~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Fixed a style variance.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 
3
 
Copyright (c) 2000, 2010, MySQL AB & Innobase Oy. All Rights Reserved.
 
3
Copyright (c) 2000, 2009, MySQL AB & Innobase Oy. All Rights Reserved.
4
4
Copyright (c) 2008, 2009 Google Inc.
5
 
Copyright (c) 2009, Percona Inc.
6
5
 
7
6
Portions of this file contain modifications contributed and copyrighted by
8
7
Google, Inc. Those modifications are gratefully acknowledged and are described
10
9
incorporated with their permission, and subject to the conditions contained in
11
10
the file COPYING.Google.
12
11
 
13
 
Portions of this file contain modifications contributed and copyrighted
14
 
by Percona Inc.. Those modifications are
15
 
gratefully acknowledged and are described briefly in the InnoDB
16
 
documentation. The contributions by Percona Inc. are incorporated with
17
 
their permission, and subject to the conditions contained in the file
18
 
COPYING.Percona.
19
 
 
20
12
This program is free software; you can redistribute it and/or modify it under
21
13
the terms of the GNU General Public License as published by the Free Software
22
14
Foundation; version 2 of the License.
26
18
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
27
19
 
28
20
You should have received a copy of the GNU General Public License along with
29
 
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
30
 
St, Fifth Floor, Boston, MA 02110-1301 USA
 
21
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
22
Place, Suite 330, Boston, MA 02111-1307 USA
31
23
 
32
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
***********************************************************************/
33
51
 
34
52
/* TODO list for the InnoDB Cursor in 5.0:
 
53
  - Remove the flag trx->active_trans and look at trx->conc_state
35
54
  - fix savepoint functions to use savepoint storage area
36
55
  - Find out what kind of problems the OS X case-insensitivity causes to
37
56
    table and database names; should we 'normalize' the names like we do
49
68
#include "drizzled/internal/m_string.h"
50
69
#include "drizzled/internal/my_sys.h"
51
70
#include "drizzled/my_hash.h"
 
71
#include "drizzled/my_error.h"
52
72
#include "drizzled/plugin.h"
53
73
#include "drizzled/show.h"
54
74
#include "drizzled/data_home.h"
61
81
#include "drizzled/field/blob.h"
62
82
#include "drizzled/field/varstring.h"
63
83
#include "drizzled/field/timestamp.h"
64
 
#include "drizzled/plugin/xa_storage_engine.h"
65
 
#include "drizzled/plugin/daemon.h"
 
84
#include "drizzled/plugin/storage_engine.h"
 
85
#include "drizzled/plugin/info_schema_table.h"
66
86
#include "drizzled/memory/multi_malloc.h"
67
87
#include "drizzled/pthread_globals.h"
68
88
#include "drizzled/named_savepoint.h"
69
89
 
70
90
#include <drizzled/transaction_services.h>
71
 
#include "drizzled/message/statement_transform.h"
72
 
 
73
 
#include <boost/algorithm/string.hpp>
74
 
#include <boost/program_options.hpp>
75
 
#include <boost/filesystem.hpp>
76
 
#include <drizzled/module/option_map.h>
77
 
#include <iostream>
78
 
 
79
 
namespace po= boost::program_options;
80
 
namespace fs=boost::filesystem;
81
 
using namespace std;
82
91
 
83
92
/** @file ha_innodb.cc */
84
93
 
85
94
/* Include necessary InnoDB headers */
86
95
extern "C" {
87
96
#include "univ.i"
88
 
#include "buf0lru.h"
89
97
#include "btr0sea.h"
90
98
#include "os0file.h"
91
99
#include "os0thread.h"
102
110
#include "log0log.h"
103
111
#include "lock0lock.h"
104
112
#include "dict0crea.h"
105
 
#include "create_replication.h"
106
113
#include "btr0cur.h"
107
114
#include "btr0btr.h"
108
115
#include "fsp0fsp.h"
115
122
#include "ha_prototypes.h"
116
123
#include "ut0mem.h"
117
124
#include "ibuf0ibuf.h"
118
 
#include "mysql_addons.h"
119
125
}
120
126
 
121
127
#include "ha_innodb.h"
122
 
#include "data_dictionary.h"
123
 
#include "replication_dictionary.h"
124
 
#include "internal_dictionary.h"
 
128
#include "i_s.h"
125
129
#include "handler0vars.h"
126
130
 
127
 
#include <iostream>
128
 
#include <sstream>
129
131
#include <string>
130
132
 
131
 
#include "plugin/innobase/handler/status_function.h"
132
 
#include "plugin/innobase/handler/replication_log.h"
133
 
 
134
 
#include <google/protobuf/io/zero_copy_stream.h>
135
 
#include <google/protobuf/io/zero_copy_stream_impl.h>
136
 
#include <google/protobuf/io/coded_stream.h>
137
 
#include <google/protobuf/text_format.h>
138
 
 
139
133
using namespace std;
140
134
using namespace drizzled;
141
135
 
 
136
#ifndef DRIZZLE_SERVER
 
137
/* This is needed because of Bug #3596.  Let us hope that pthread_mutex_t
 
138
is defined the same in both builds: the MySQL server and the InnoDB plugin. */
 
139
extern pthread_mutex_t LOCK_thread_count;
 
140
 
 
141
#endif /* DRIZZLE_SERVER */
 
142
 
142
143
/** to protect innobase_open_files */
143
144
static pthread_mutex_t innobase_share_mutex;
144
145
/** to force correct commit order in binlog */
161
162
# define EQ_CURRENT_SESSION(session) ((session) == current_session)
162
163
#endif /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
163
164
 
164
 
static plugin::XaStorageEngine* innodb_engine_ptr= NULL;
165
 
static plugin::TableFunction* status_table_function_ptr= NULL;
166
 
static plugin::TableFunction* cmp_tool= NULL;
167
 
static plugin::TableFunction* cmp_reset_tool= NULL;
168
 
static plugin::TableFunction* cmp_mem_tool= NULL;
169
 
static plugin::TableFunction* cmp_mem_reset_tool= NULL;
170
 
static plugin::TableFunction* innodb_trx_tool= NULL;
171
 
static plugin::TableFunction* innodb_locks_tool= NULL;
172
 
static plugin::TableFunction* innodb_lock_waits_tool= NULL;
173
 
static plugin::TableFunction* innodb_sys_tables_tool= NULL;
174
 
static plugin::TableFunction* innodb_sys_tablestats_tool= NULL;
175
 
 
176
 
static plugin::TableFunction* innodb_sys_indexes_tool= NULL;
177
 
static plugin::TableFunction* innodb_sys_columns_tool= NULL;
178
 
static plugin::TableFunction* innodb_sys_fields_tool= NULL;
179
 
static plugin::TableFunction* innodb_sys_foreign_tool= NULL;
180
 
static plugin::TableFunction* innodb_sys_foreign_cols_tool= NULL;
181
 
 
182
 
static ReplicationLog *replication_logger= NULL;
183
 
typedef constrained_check<uint32_t, UINT32_MAX, 10> open_files_constraint;
184
 
static open_files_constraint innobase_open_files;
185
 
typedef constrained_check<uint32_t, 10, 1> mirrored_log_groups_constraint;
186
 
static mirrored_log_groups_constraint innobase_mirrored_log_groups;
187
 
typedef constrained_check<uint32_t, 100, 2> log_files_in_group_constraint;
188
 
static log_files_in_group_constraint innobase_log_files_in_group;
189
 
typedef constrained_check<uint32_t, 6, 0> force_recovery_constraint;
190
 
force_recovery_constraint innobase_force_recovery;
191
 
typedef constrained_check<size_t, SIZE_MAX, 256*1024, 1024> log_buffer_constraint;
192
 
static log_buffer_constraint innobase_log_buffer_size;
193
 
typedef constrained_check<size_t, SIZE_MAX, 512*1024, 1024> additional_mem_pool_constraint;
194
 
static additional_mem_pool_constraint innobase_additional_mem_pool_size;
195
 
typedef constrained_check<unsigned int, 1000, 1> autoextend_constraint;
196
 
static autoextend_constraint innodb_auto_extend_increment;
197
 
typedef constrained_check<size_t, SIZE_MAX, 5242880, 1048576> buffer_pool_constraint;
198
 
static buffer_pool_constraint innobase_buffer_pool_size;
199
 
typedef constrained_check<uint32_t, MAX_BUFFER_POOLS, 1> buffer_pool_instances_constraint;
200
 
static buffer_pool_instances_constraint innobase_buffer_pool_instances;
201
 
typedef constrained_check<uint32_t, UINT32_MAX, 100> io_capacity_constraint;
202
 
static io_capacity_constraint innodb_io_capacity;
203
 
typedef constrained_check<uint32_t, 5000, 1> purge_batch_constraint;
204
 
static purge_batch_constraint innodb_purge_batch_size;
205
 
typedef constrained_check<uint32_t, 1, 0> purge_threads_constraint;
206
 
static purge_threads_constraint innodb_n_purge_threads;
207
 
typedef constrained_check<uint16_t, 2, 0> trinary_constraint;
208
 
static trinary_constraint innodb_flush_log_at_trx_commit;
209
 
typedef constrained_check<unsigned int, 99, 0> max_dirty_pages_constraint;
210
 
static max_dirty_pages_constraint innodb_max_dirty_pages_pct;
211
 
static uint64_constraint innodb_max_purge_lag;
212
 
static uint64_nonzero_constraint innodb_stats_sample_pages;
213
 
typedef constrained_check<uint32_t, 64, 1> io_threads_constraint;
214
 
static io_threads_constraint innobase_read_io_threads;
215
 
static io_threads_constraint innobase_write_io_threads;
216
 
 
217
 
typedef constrained_check<uint32_t, 1000, 0> concurrency_constraint;
218
 
static concurrency_constraint innobase_commit_concurrency;
219
 
static concurrency_constraint innobase_thread_concurrency;
220
 
static uint32_nonzero_constraint innodb_concurrency_tickets;
221
 
 
222
 
typedef constrained_check<int64_t, INT64_MAX, 1024*1024, 1024*1024> log_file_constraint;
223
 
static log_file_constraint innobase_log_file_size;
224
 
 
225
 
static uint64_constraint innodb_replication_delay;
226
 
 
227
 
/** Percentage of the buffer pool to reserve for 'old' blocks.
228
 
Connected to buf_LRU_old_ratio. */
229
 
typedef constrained_check<uint32_t, 95, 5> old_blocks_constraint;
230
 
static old_blocks_constraint innobase_old_blocks_pct;
231
 
 
232
 
static uint32_constraint innodb_sync_spin_loops;
233
 
static uint32_constraint innodb_spin_wait_delay;
234
 
static uint32_constraint innodb_thread_sleep_delay;
235
 
 
236
 
typedef constrained_check<uint32_t, 64, 0> read_ahead_threshold_constraint;
237
 
static read_ahead_threshold_constraint innodb_read_ahead_threshold;
 
165
static plugin::StorageEngine* innodb_engine_ptr= NULL;
 
166
 
 
167
static const long AUTOINC_OLD_STYLE_LOCKING = 0;
 
168
static const long AUTOINC_NEW_STYLE_LOCKING = 1;
 
169
static const long AUTOINC_NO_LOCKING = 2;
 
170
 
 
171
static long innobase_mirrored_log_groups, innobase_log_files_in_group,
 
172
        innobase_log_buffer_size,
 
173
        innobase_additional_mem_pool_size, innobase_file_io_threads,
 
174
        innobase_force_recovery, innobase_open_files,
 
175
        innobase_autoinc_lock_mode;
 
176
static ulong innobase_commit_concurrency = 0;
 
177
static ulong innobase_read_io_threads;
 
178
static ulong innobase_write_io_threads;
 
179
 
 
180
/**
 
181
 * @TODO: Turn this into size_t as soon as we have a Variable<size_t>
 
182
 */
 
183
static int64_t innobase_buffer_pool_size, innobase_log_file_size;
238
184
 
239
185
/* The default values for the following char* start-up parameters
240
186
are determined in innobase_init below: */
241
187
 
242
 
std::string innobase_data_home_dir;
243
 
std::string innobase_data_file_path;
244
 
std::string innobase_log_group_home_dir;
245
 
static string innobase_file_format_name;
246
 
static string innobase_change_buffering;
247
 
 
248
 
/* The highest file format being used in the database. The value can be
249
 
set by user, however, it will be adjusted to the newer file format if
250
 
a table of such format is created/opened. */
251
 
static string innobase_file_format_max;
 
188
static char*    innobase_data_home_dir                  = NULL;
 
189
static char*    innobase_data_file_path                 = NULL;
 
190
static char*    innobase_log_group_home_dir             = NULL;
 
191
static char*    innobase_file_format_name               = NULL;
 
192
static char*    innobase_change_buffering               = NULL;
 
193
 
 
194
/* Note: This variable can be set to on/off and any of the supported
 
195
file formats in the configuration file, but can only be set to any
 
196
of the supported file formats during runtime. */
 
197
static char*    innobase_file_format_check              = NULL;
 
198
 
 
199
/* The following has a misleading name: starting from 4.0.5, this also
 
200
affects Windows: */
 
201
static char*    innobase_unix_file_flush_method         = NULL;
252
202
 
253
203
/* Below we have boolean-valued start-up parameters, and their default
254
204
values */
255
205
 
256
 
typedef constrained_check<uint16_t, 2, 0> trinary_constraint;
257
 
static trinary_constraint innobase_fast_shutdown;
258
 
 
259
 
/* "innobase_file_format_check" decides whether we would continue
260
 
booting the server if the file format stamped on the system
261
 
table space exceeds the maximum file format supported
262
 
by the server. Can be set during server startup at command
263
 
line or configure file, and a read only variable after
264
 
server startup */
265
 
 
266
 
/* If a new file format is introduced, the file format
267
 
name needs to be updated accordingly. Please refer to
268
 
file_format_name_map[] defined in trx0sys.c for the next
269
 
file format name. */
270
 
 
271
 
static my_bool  innobase_file_format_check = TRUE;
272
 
static my_bool  innobase_use_doublewrite    = TRUE;
273
 
static my_bool  innobase_use_checksums      = TRUE;
274
 
static my_bool  innobase_rollback_on_timeout    = FALSE;
275
 
static my_bool  innobase_create_status_file   = FALSE;
276
 
static bool innobase_use_replication_log;
277
 
static bool support_xa;
278
 
static bool strict_mode;
279
 
typedef constrained_check<uint32_t, 1024*1024*1024, 1> lock_wait_constraint;
280
 
static lock_wait_constraint lock_wait_timeout;
281
 
 
282
 
static char*  internal_innobase_data_file_path  = NULL;
 
206
static ulong    innobase_fast_shutdown                  = 1;
 
207
#ifdef UNIV_LOG_ARCHIVE
 
208
static my_bool  innobase_log_archive                    = FALSE;
 
209
static char*    innobase_log_arch_dir                   = NULL;
 
210
#endif /* UNIV_LOG_ARCHIVE */
 
211
static my_bool  innobase_use_doublewrite                = TRUE;
 
212
static my_bool  innobase_use_checksums                  = TRUE;
 
213
static my_bool  innobase_locks_unsafe_for_binlog        = TRUE;
 
214
static my_bool  innobase_rollback_on_timeout            = FALSE;
 
215
static my_bool  innobase_create_status_file             = FALSE;
 
216
static my_bool  innobase_stats_on_metadata              = TRUE;
 
217
 
 
218
static char*    internal_innobase_data_file_path        = NULL;
 
219
 
 
220
static char*    innodb_version_str = (char*) INNODB_VERSION_STR;
283
221
 
284
222
/* The following counter is used to convey information to InnoDB
285
223
about server activity: in selects it is not sensible to call
286
224
srv_active_wake_master_thread after each fetch or search, we only do
287
225
it every INNOBASE_WAKE_INTERVAL'th step. */
288
226
 
289
 
#define INNOBASE_WAKE_INTERVAL  32
290
 
static ulong  innobase_active_counter = 0;
291
 
 
292
 
static hash_table_t*  innobase_open_tables;
293
 
 
294
 
#ifdef __NETWARE__  /* some special cleanup for NetWare */
 
227
#define INNOBASE_WAKE_INTERVAL  32
 
228
static ulong    innobase_active_counter = 0;
 
229
 
 
230
static hash_table_t*    innobase_open_tables;
 
231
 
 
232
#ifdef __NETWARE__      /* some special cleanup for NetWare */
295
233
bool nw_panic = FALSE;
296
234
#endif
297
235
 
298
236
/** Allowed values of innodb_change_buffering */
299
237
static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
300
 
  "none",   /* IBUF_USE_NONE */
301
 
  "inserts",    /* IBUF_USE_INSERT */
302
 
  "deletes",    /* IBUF_USE_DELETE_MARK */
303
 
  "changes",    /* IBUF_USE_INSERT_DELETE_MARK */
304
 
  "purges",     /* IBUF_USE_DELETE */
305
 
  "all"         /* IBUF_USE_ALL */
 
238
        "none",         /* IBUF_USE_NONE */
 
239
        "inserts"       /* IBUF_USE_INSERT */
306
240
};
307
241
 
308
 
/* "GEN_CLUST_INDEX" is the name reserved for Innodb default
309
 
system primary index. */
310
 
static const char innobase_index_reserve_name[]= "GEN_CLUST_INDEX";
311
 
 
312
242
/********************************************************************
313
243
Gives the file extension of an InnoDB single-table tablespace. */
314
244
static const char* ha_innobase_exts[] = {
316
246
  NULL
317
247
};
318
248
 
319
 
#define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
320
 
 
321
249
static INNOBASE_SHARE *get_share(const char *table_name);
322
250
static void free_share(INNOBASE_SHARE *share);
323
251
 
324
 
class InnobaseEngine : public plugin::XaStorageEngine
 
252
class InnobaseEngine : public plugin::StorageEngine
325
253
{
326
254
public:
327
 
  explicit InnobaseEngine(string name_arg) :
328
 
    plugin::XaStorageEngine(name_arg,
329
 
                            HTON_NULL_IN_KEY |
330
 
                            HTON_CAN_INDEX_BLOBS |
331
 
                            HTON_PRIMARY_KEY_IN_READ_INDEX |
332
 
                            HTON_PARTIAL_COLUMN_READ |
333
 
                            HTON_TABLE_SCAN_ON_INDEX |
334
 
                            HTON_HAS_FOREIGN_KEYS |
335
 
                            HTON_HAS_DOES_TRANSACTIONS)
 
255
  InnobaseEngine(string name_arg) :
 
256
    plugin::StorageEngine(name_arg,
 
257
                          HTON_NULL_IN_KEY |
 
258
                          HTON_CAN_INDEX_BLOBS |
 
259
                          HTON_PRIMARY_KEY_REQUIRED_FOR_POSITION |
 
260
                          HTON_PRIMARY_KEY_IN_READ_INDEX |
 
261
                          HTON_PARTIAL_COLUMN_READ |
 
262
                          HTON_TABLE_SCAN_ON_INDEX |
 
263
                          HTON_HAS_DOES_TRANSACTIONS)
336
264
  {
337
265
    table_definition_ext= plugin::DEFAULT_DEFINITION_FILE_EXT;
338
266
    addAlias("INNOBASE");
339
267
  }
340
268
 
341
 
  virtual ~InnobaseEngine()
342
 
  {
343
 
    int err= 0;
344
 
    if (innodb_inited) {
345
 
      srv_fast_shutdown = (ulint) innobase_fast_shutdown;
346
 
      innodb_inited = 0;
347
 
      hash_table_free(innobase_open_tables);
348
 
      innobase_open_tables = NULL;
349
 
      if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
350
 
        err = 1;
351
 
      }
352
 
      srv_free_paths_and_sizes();
353
 
      if (internal_innobase_data_file_path)
354
 
        free(internal_innobase_data_file_path);
355
 
      pthread_mutex_destroy(&innobase_share_mutex);
356
 
      pthread_mutex_destroy(&prepare_commit_mutex);
357
 
      pthread_mutex_destroy(&commit_threads_m);
358
 
      pthread_mutex_destroy(&commit_cond_m);
359
 
      pthread_cond_destroy(&commit_cond);
360
 
    }
361
 
    
362
 
    /* These get strdup'd from vm variables */
363
 
 
364
 
  }
365
 
 
366
 
private:
367
 
  virtual int doStartTransaction(Session *session, start_transaction_option_t options);
368
 
  virtual void doStartStatement(Session *session);
369
 
  virtual void doEndStatement(Session *session);
370
 
public:
371
269
  virtual
372
270
  int
373
271
  close_connection(
374
272
/*======================*/
375
 
      /* out: 0 or error number */
376
 
  Session*  session); /* in: handle to the MySQL thread of the user
377
 
      whose resources should be free'd */
 
273
                        /* out: 0 or error number */
 
274
        Session*        session);       /* in: handle to the MySQL thread of the user
 
275
                        whose resources should be free'd */
378
276
 
379
 
  virtual int doSetSavepoint(Session* session,
 
277
  virtual int savepoint_set_hook(Session* session,
380
278
                                 drizzled::NamedSavepoint &savepoint);
381
 
  virtual int doRollbackToSavepoint(Session* session,
382
 
                                     drizzled::NamedSavepoint &savepoint);
383
 
  virtual int doReleaseSavepoint(Session* session,
384
 
                                     drizzled::NamedSavepoint &savepoint);
385
 
  virtual int doXaCommit(Session* session, bool all)
386
 
  {
387
 
    return doCommit(session, all); /* XA commit just does a SQL COMMIT */
388
 
  }
389
 
  virtual int doXaRollback(Session *session, bool all)
390
 
  {
391
 
    return doRollback(session, all); /* XA rollback just does a SQL ROLLBACK */
392
 
  }
393
 
  virtual uint64_t doGetCurrentTransactionId(Session *session);
394
 
  virtual uint64_t doGetNewTransactionId(Session *session);
395
 
  virtual int doCommit(Session* session, bool all);
396
 
  virtual int doRollback(Session* session, bool all);
 
279
  virtual int savepoint_rollback_hook(Session* session,
 
280
                                     drizzled::NamedSavepoint &savepoint);
 
281
  virtual int savepoint_release_hook(Session* session,
 
282
                                     drizzled::NamedSavepoint &savepoint);
 
283
  virtual int commit(Session* session, bool all);
 
284
  virtual int rollback(Session* session, bool all);
397
285
 
398
286
  /***********************************************************************
399
287
  This function is used to prepare X/Open XA distributed transaction   */
400
288
  virtual
401
289
  int
402
 
  doXaPrepare(
 
290
  prepare(
403
291
  /*================*/
404
 
        /* out: 0 or error number */
405
 
    Session*  session,  /* in: handle to the MySQL thread of the user
406
 
        whose XA transaction should be prepared */
407
 
    bool  all); /* in: TRUE - commit transaction
408
 
        FALSE - the current SQL statement ended */
 
292
                        /* out: 0 or error number */
 
293
        Session*        session,        /* in: handle to the MySQL thread of the user
 
294
                        whose XA transaction should be prepared */
 
295
        bool    all);   /* in: TRUE - commit transaction
 
296
                        FALSE - the current SQL statement ended */
409
297
  /***********************************************************************
410
298
  This function is used to recover X/Open XA distributed transactions   */
411
299
  virtual
412
300
  int
413
 
  doXaRecover(
 
301
  recover(
414
302
  /*================*/
415
 
          /* out: number of prepared transactions
416
 
          stored in xid_list */
417
 
    ::drizzled::XID*  xid_list, /* in/out: prepared transactions */
418
 
    size_t len);    /* in: number of slots in xid_list */
 
303
                                /* out: number of prepared transactions
 
304
                                stored in xid_list */
 
305
        ::drizzled::XID*        xid_list,       /* in/out: prepared transactions */
 
306
        uint    len);           /* in: number of slots in xid_list */
419
307
  /***********************************************************************
420
308
  This function is used to commit one X/Open XA distributed transaction
421
309
  which is in the prepared state */
422
310
  virtual
423
311
  int
424
 
  doXaCommitXid(
 
312
  commit_by_xid(
425
313
  /*===================*/
426
 
        /* out: 0 or error number */
427
 
    ::drizzled::XID*  xid); /* in: X/Open XA transaction identification */
 
314
                        /* out: 0 or error number */
 
315
        ::drizzled::XID*        xid);   /* in: X/Open XA transaction identification */
428
316
  /***********************************************************************
429
317
  This function is used to rollback one X/Open XA distributed transaction
430
318
  which is in the prepared state */
431
319
  virtual
432
320
  int
433
 
  doXaRollbackXid(
 
321
  rollback_by_xid(
434
322
  /*=====================*/
435
 
        /* out: 0 or error number */
436
 
    ::drizzled::XID *xid);  /* in: X/Open XA transaction identification */
 
323
                        /* out: 0 or error number */
 
324
        ::drizzled::XID *xid);  /* in: X/Open XA transaction identification */
437
325
 
438
 
  virtual Cursor *create(Table &table)
 
326
  virtual Cursor *create(TableShare &table,
 
327
                         memory::Root *mem_root)
439
328
  {
440
 
    return new ha_innobase(*this, table);
 
329
    return new (mem_root) ha_innobase(*this, table);
441
330
  }
442
331
 
443
332
  /*********************************************************************
444
333
  Removes all tables in the named database inside InnoDB. */
445
 
  bool
446
 
  doDropSchema(
 
334
  virtual
 
335
  void
 
336
  drop_database(
447
337
  /*===================*/
448
 
        /* out: error number */
449
 
    const SchemaIdentifier  &identifier); /* in: database path; inside InnoDB the name
450
 
        of the last directory in the path is used as
451
 
        the database name: for example, in 'mysql/data/test'
452
 
        the database name is 'test' */
 
338
                        /* out: error number */
 
339
        char*   path);  /* in: database path; inside InnoDB the name
 
340
                        of the last directory in the path is used as
 
341
                        the database name: for example, in 'mysql/data/test'
 
342
                        the database name is 'test' */
453
343
 
 
344
  /*********************************************************************
 
345
  Creates an InnoDB transaction struct for the session if it does not yet have one.
 
346
  Starts a new InnoDB transaction if a transaction is not yet started. And
 
347
  assigns a new snapshot for a consistent read if the transaction does not yet
 
348
  have one. */
 
349
  virtual
 
350
  int
 
351
  start_consistent_snapshot(
 
352
  /*====================================*/
 
353
                        /* out: 0 */
 
354
        Session*        session);       /* in: MySQL thread handle of the user for whom
 
355
                        the transaction should be committed */
454
356
  /********************************************************************
455
357
  Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
456
358
  the logs, and the name of this function should be innobase_checkpoint. */
458
360
  bool
459
361
  flush_logs();
460
362
  /*================*/
461
 
          /* out: TRUE if error */
 
363
                                /* out: TRUE if error */
462
364
  
463
365
  /****************************************************************************
464
366
  Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
467
369
  bool
468
370
  show_status(
469
371
  /*===============*/
470
 
    Session*  session,  /* in: the MySQL query thread of the caller */
471
 
    stat_print_fn *stat_print,
472
 
  enum ha_stat_type stat_type);
 
372
        Session*        session,        /* in: the MySQL query thread of the caller */
 
373
        stat_print_fn *stat_print,
 
374
        enum ha_stat_type stat_type);
473
375
 
474
376
  virtual
475
377
  int
476
 
  doReleaseTemporaryLatches(
 
378
  release_temporary_latches(
477
379
  /*===============================*/
478
 
        /* out: 0 */
479
 
  Session*    session); /* in: MySQL thread */
 
380
                                /* out: 0 */
 
381
        Session*                session);       /* in: MySQL thread */
480
382
 
481
383
 
482
384
  const char** bas_ext() const {
483
 
  return(ha_innobase_exts);
 
385
        return(ha_innobase_exts);
484
386
  }
485
387
 
486
 
  UNIV_INTERN int doCreateTable(Session &session,
487
 
                                Table &form,
488
 
                                const TableIdentifier &identifier,
 
388
  UNIV_INTERN int doCreateTable(Session *session,
 
389
                                const char *table_name,
 
390
                                Table& form,
489
391
                                message::Table&);
490
 
  UNIV_INTERN int doRenameTable(Session&, const TableIdentifier &from, const TableIdentifier &to);
491
 
  UNIV_INTERN int doDropTable(Session &session, const TableIdentifier &identifier);
 
392
  UNIV_INTERN int doRenameTable(Session* session,
 
393
                                const char* from,
 
394
                                const char* to);
 
395
  UNIV_INTERN int doDropTable(Session& session, const string table_path);
492
396
 
493
397
  UNIV_INTERN virtual bool get_error_message(int error, String *buf);
494
398
 
505
409
            HA_READ_RANGE |
506
410
            HA_KEYREAD_ONLY);
507
411
  }
508
 
 
509
 
  int doGetTableDefinition(drizzled::Session& session,
510
 
                           const TableIdentifier &identifier,
511
 
                           drizzled::message::Table &table_proto);
512
 
 
513
 
  bool doDoesTableExist(drizzled::Session& session, const TableIdentifier &identifier);
514
 
 
515
 
  void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
516
 
                             const drizzled::SchemaIdentifier &schema_identifier,
517
 
                             drizzled::TableIdentifier::vector &set_of_identifiers);
518
 
  bool validateCreateTableOption(const std::string &key, const std::string &state);
519
 
  void dropTemporarySchema();
520
 
 
521
412
};
522
413
 
523
 
 
524
 
bool InnobaseEngine::validateCreateTableOption(const std::string &key, const std::string &state)
525
 
{
526
 
  if (boost::iequals(key, "ROW_FORMAT"))
527
 
  {
528
 
    if (boost::iequals(state, "COMPRESSED"))
529
 
      return true;
530
 
 
531
 
    if (boost::iequals(state, "COMPACT"))
532
 
      return true;
533
 
 
534
 
    if (boost::iequals(state, "DYNAMIC"))
535
 
      return true;
536
 
 
537
 
    if (boost::iequals(state, "REDUNDANT"))
538
 
      return true;
539
 
  }
540
 
 
541
 
  return false;
542
 
}
543
 
 
544
 
void InnobaseEngine::doGetTableIdentifiers(drizzled::CachedDirectory &directory,
545
 
                                           const drizzled::SchemaIdentifier &schema_identifier,
546
 
                                           drizzled::TableIdentifier::vector &set_of_identifiers)
547
 
{
548
 
  CachedDirectory::Entries entries= directory.getEntries();
549
 
 
550
 
  for (CachedDirectory::Entries::iterator entry_iter= entries.begin(); 
551
 
       entry_iter != entries.end(); ++entry_iter)
552
 
  {
553
 
    CachedDirectory::Entry *entry= *entry_iter;
554
 
    const string *filename= &entry->filename;
555
 
 
556
 
    assert(filename->size());
557
 
 
558
 
    const char *ext= strchr(filename->c_str(), '.');
559
 
 
560
 
    if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_FILE_EXTENSION) ||
561
 
        (filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
562
 
    { }
563
 
    else
564
 
    {
565
 
      std::string path;
566
 
      path+= directory.getPath();
567
 
      path+= FN_LIBCHAR;
568
 
      path+= entry->filename;
569
 
 
570
 
      message::Table definition;
571
 
      if (StorageEngine::readTableFile(path, definition))
572
 
      {
573
 
        /* 
574
 
           Using schema_identifier here to stop unused warning, could use
575
 
           definition.schema() instead
576
 
        */
577
 
        TableIdentifier identifier(schema_identifier.getSchemaName(), definition.name());
578
 
        set_of_identifiers.push_back(identifier);
579
 
      }
580
 
    }
581
 
  }
582
 
}
583
 
 
584
 
bool InnobaseEngine::doDoesTableExist(Session &session, const TableIdentifier &identifier)
585
 
{
586
 
  string proto_path(identifier.getPath());
587
 
  proto_path.append(DEFAULT_FILE_EXTENSION);
588
 
 
589
 
  if (session.getMessageCache().doesTableMessageExist(identifier))
590
 
    return true;
591
 
 
592
 
  if (access(proto_path.c_str(), F_OK))
593
 
  {
594
 
    return false;
595
 
  }
596
 
 
597
 
  return true;
598
 
}
599
 
 
600
 
int InnobaseEngine::doGetTableDefinition(Session &session,
601
 
                                         const TableIdentifier &identifier,
602
 
                                         message::Table &table_proto)
603
 
{
604
 
  string proto_path(identifier.getPath());
605
 
  proto_path.append(DEFAULT_FILE_EXTENSION);
606
 
 
607
 
  // First we check the temporary tables.
608
 
  if (session.getMessageCache().getTableMessage(identifier, table_proto))
609
 
    return EEXIST;
610
 
 
611
 
  if (access(proto_path.c_str(), F_OK))
612
 
  {
613
 
    return errno;
614
 
  }
615
 
 
616
 
  if (StorageEngine::readTableFile(proto_path, table_proto))
617
 
    return EEXIST;
618
 
 
619
 
  return ENOENT;
620
 
}
621
 
 
 
414
/** @brief Initialize the default value of innodb_commit_concurrency.
 
415
 
 
416
Once InnoDB is running, the innodb_commit_concurrency must not change
 
417
from zero to nonzero. (Bug #42101)
 
418
 
 
419
The initial default value is 0, and without this extra initialization,
 
420
SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
 
421
to 0, even if it was initially set to nonzero at the command line
 
422
or configuration file. */
 
423
static
 
424
void
 
425
innobase_commit_concurrency_init_default(void);
 
426
/*==========================================*/
622
427
 
623
428
/************************************************************//**
624
429
Validate the file format name and return its corresponding id.
625
 
@return valid file format id */
 
430
@return valid file format id */
626
431
static
627
432
uint
628
433
innobase_file_format_name_lookup(
629
434
/*=============================*/
630
 
  const char* format_name);   /*!< in: pointer to file format
631
 
            name */
632
 
/************************************************************//**
633
 
Validate the file format check config parameters, as a side effect it
634
 
sets the srv_max_file_format_at_startup variable.
635
 
@return the format_id if valid config value, otherwise, return -1 */
636
 
static
637
 
int
638
 
innobase_file_format_validate_and_set(
 
435
        const char*     format_name);           /*!< in: pointer to file format
 
436
                                                name */
 
437
/************************************************************//**
 
438
Validate the file format check config parameters, as a side effect it
 
439
sets the srv_check_file_format_at_startup variable.
 
440
@return true if one of  "on" or "off" */
 
441
static
 
442
bool
 
443
innobase_file_format_check_on_off(
 
444
/*==============================*/
 
445
        const char*     format_check);          /*!< in: parameter value */
 
446
/************************************************************//**
 
447
Validate the file format check config parameters, as a side effect it
 
448
sets the srv_check_file_format_at_startup variable.
 
449
@return true if valid config value */
 
450
static
 
451
bool
 
452
innobase_file_format_check_validate(
639
453
/*================================*/
640
 
  const char* format_max);    /*!< in: parameter value */
 
454
        const char*     format_check);          /*!< in: parameter value */
641
455
 
642
456
static const char innobase_engine_name[]= "InnoDB";
643
457
 
 
458
/*************************************************************//**
 
459
Check for a valid value of innobase_commit_concurrency.
 
460
@return 0 for valid innodb_commit_concurrency */
 
461
static
 
462
int
 
463
innobase_commit_concurrency_validate(
 
464
/*=================================*/
 
465
        Session*                        ,       /*!< in: thread handle */
 
466
        drizzle_sys_var*        ,       /*!< in: pointer to system
 
467
                                                variable */
 
468
        void*                           save,   /*!< out: immediate result
 
469
                                                for update function */
 
470
        drizzle_value*          value)  /*!< in: incoming string */
 
471
{
 
472
        int64_t         intbuf;
 
473
        ulong           commit_concurrency;
 
474
 
 
475
        if (value->val_int(value, &intbuf)) {
 
476
                /* The value is NULL. That is invalid. */
 
477
                return(1);
 
478
        }
 
479
 
 
480
        *reinterpret_cast<ulong*>(save) = commit_concurrency
 
481
                = static_cast<ulong>(intbuf);
 
482
 
 
483
        /* Allow the value to be updated, as long as it remains zero
 
484
        or nonzero. */
 
485
        return(!(!commit_concurrency == !innobase_commit_concurrency));
 
486
}
 
487
 
 
488
static DRIZZLE_SessionVAR_BOOL(support_xa, PLUGIN_VAR_OPCMDARG,
 
489
  "Enable InnoDB support for the XA two-phase commit",
 
490
  /* check_func */ NULL, /* update_func */ NULL,
 
491
  /* default */ TRUE);
 
492
 
 
493
static DRIZZLE_SessionVAR_BOOL(table_locks, PLUGIN_VAR_OPCMDARG,
 
494
  "Enable InnoDB locking in LOCK TABLES",
 
495
  /* check_func */ NULL, /* update_func */ NULL,
 
496
  /* default */ TRUE);
 
497
 
 
498
static DRIZZLE_SessionVAR_BOOL(strict_mode, PLUGIN_VAR_OPCMDARG,
 
499
  "Use strict mode when evaluating create options.",
 
500
  NULL, NULL, FALSE);
 
501
 
 
502
static DRIZZLE_SessionVAR_ULONG(lock_wait_timeout, PLUGIN_VAR_RQCMDARG,
 
503
  "Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout.",
 
504
  NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0);
 
505
 
 
506
 
 
507
/***********************************************************************
 
508
Closes an InnoDB database. */
 
509
static
 
510
int
 
511
innobase_deinit(plugin::Registry &registry);
644
512
 
645
513
/*****************************************************************//**
646
514
Commits a transaction in an InnoDB database. */
648
516
void
649
517
innobase_commit_low(
650
518
/*================*/
651
 
  trx_t*  trx); /*!< in: transaction handle */
 
519
        trx_t*  trx);   /*!< in: transaction handle */
652
520
 
653
 
static drizzle_show_var innodb_status_variables[]= {
 
521
static SHOW_VAR innodb_status_variables[]= {
654
522
  {"buffer_pool_pages_data",
655
 
  (char*) &export_vars.innodb_buffer_pool_pages_data,   SHOW_LONG},
 
523
  (char*) &export_vars.innodb_buffer_pool_pages_data,     SHOW_LONG},
656
524
  {"buffer_pool_pages_dirty",
657
 
  (char*) &export_vars.innodb_buffer_pool_pages_dirty,    SHOW_LONG},
 
525
  (char*) &export_vars.innodb_buffer_pool_pages_dirty,    SHOW_LONG},
658
526
  {"buffer_pool_pages_flushed",
659
527
  (char*) &export_vars.innodb_buffer_pool_pages_flushed,  SHOW_LONG},
660
528
  {"buffer_pool_pages_free",
661
 
  (char*) &export_vars.innodb_buffer_pool_pages_free,   SHOW_LONG},
 
529
  (char*) &export_vars.innodb_buffer_pool_pages_free,     SHOW_LONG},
662
530
#ifdef UNIV_DEBUG
663
531
  {"buffer_pool_pages_latched",
664
532
  (char*) &export_vars.innodb_buffer_pool_pages_latched,  SHOW_LONG},
665
533
#endif /* UNIV_DEBUG */
666
534
  {"buffer_pool_pages_misc",
667
 
  (char*) &export_vars.innodb_buffer_pool_pages_misc,   SHOW_LONG},
 
535
  (char*) &export_vars.innodb_buffer_pool_pages_misc,     SHOW_LONG},
668
536
  {"buffer_pool_pages_total",
669
 
  (char*) &export_vars.innodb_buffer_pool_pages_total,    SHOW_LONG},
670
 
  {"buffer_pool_read_ahead",
671
 
  (char*) &export_vars.innodb_buffer_pool_read_ahead, SHOW_LONG},
672
 
  {"buffer_pool_read_ahead_evicted",
673
 
  (char*) &export_vars.innodb_buffer_pool_read_ahead_evicted, SHOW_LONG},
 
537
  (char*) &export_vars.innodb_buffer_pool_pages_total,    SHOW_LONG},
 
538
  {"buffer_pool_read_ahead_rnd",
 
539
  (char*) &export_vars.innodb_buffer_pool_read_ahead_rnd, SHOW_LONG},
 
540
  {"buffer_pool_read_ahead_seq",
 
541
  (char*) &export_vars.innodb_buffer_pool_read_ahead_seq, SHOW_LONG},
674
542
  {"buffer_pool_read_requests",
675
543
  (char*) &export_vars.innodb_buffer_pool_read_requests,  SHOW_LONG},
676
544
  {"buffer_pool_reads",
677
 
  (char*) &export_vars.innodb_buffer_pool_reads,    SHOW_LONG},
 
545
  (char*) &export_vars.innodb_buffer_pool_reads,          SHOW_LONG},
678
546
  {"buffer_pool_wait_free",
679
 
  (char*) &export_vars.innodb_buffer_pool_wait_free,    SHOW_LONG},
 
547
  (char*) &export_vars.innodb_buffer_pool_wait_free,      SHOW_LONG},
680
548
  {"buffer_pool_write_requests",
681
549
  (char*) &export_vars.innodb_buffer_pool_write_requests, SHOW_LONG},
682
550
  {"data_fsyncs",
683
 
  (char*) &export_vars.innodb_data_fsyncs,      SHOW_LONG},
 
551
  (char*) &export_vars.innodb_data_fsyncs,                SHOW_LONG},
684
552
  {"data_pending_fsyncs",
685
 
  (char*) &export_vars.innodb_data_pending_fsyncs,    SHOW_LONG},
 
553
  (char*) &export_vars.innodb_data_pending_fsyncs,        SHOW_LONG},
686
554
  {"data_pending_reads",
687
 
  (char*) &export_vars.innodb_data_pending_reads,   SHOW_LONG},
 
555
  (char*) &export_vars.innodb_data_pending_reads,         SHOW_LONG},
688
556
  {"data_pending_writes",
689
 
  (char*) &export_vars.innodb_data_pending_writes,    SHOW_LONG},
 
557
  (char*) &export_vars.innodb_data_pending_writes,        SHOW_LONG},
690
558
  {"data_read",
691
 
  (char*) &export_vars.innodb_data_read,      SHOW_LONG},
 
559
  (char*) &export_vars.innodb_data_read,                  SHOW_LONG},
692
560
  {"data_reads",
693
 
  (char*) &export_vars.innodb_data_reads,     SHOW_LONG},
 
561
  (char*) &export_vars.innodb_data_reads,                 SHOW_LONG},
694
562
  {"data_writes",
695
 
  (char*) &export_vars.innodb_data_writes,      SHOW_LONG},
 
563
  (char*) &export_vars.innodb_data_writes,                SHOW_LONG},
696
564
  {"data_written",
697
 
  (char*) &export_vars.innodb_data_written,     SHOW_LONG},
 
565
  (char*) &export_vars.innodb_data_written,               SHOW_LONG},
698
566
  {"dblwr_pages_written",
699
 
  (char*) &export_vars.innodb_dblwr_pages_written,    SHOW_LONG},
 
567
  (char*) &export_vars.innodb_dblwr_pages_written,        SHOW_LONG},
700
568
  {"dblwr_writes",
701
 
  (char*) &export_vars.innodb_dblwr_writes,     SHOW_LONG},
 
569
  (char*) &export_vars.innodb_dblwr_writes,               SHOW_LONG},
702
570
  {"have_atomic_builtins",
703
 
  (char*) &export_vars.innodb_have_atomic_builtins,   SHOW_BOOL},
 
571
  (char*) &export_vars.innodb_have_atomic_builtins,       SHOW_BOOL},
704
572
  {"log_waits",
705
 
  (char*) &export_vars.innodb_log_waits,      SHOW_LONG},
 
573
  (char*) &export_vars.innodb_log_waits,                  SHOW_LONG},
706
574
  {"log_write_requests",
707
 
  (char*) &export_vars.innodb_log_write_requests,   SHOW_LONG},
 
575
  (char*) &export_vars.innodb_log_write_requests,         SHOW_LONG},
708
576
  {"log_writes",
709
 
  (char*) &export_vars.innodb_log_writes,     SHOW_LONG},
 
577
  (char*) &export_vars.innodb_log_writes,                 SHOW_LONG},
710
578
  {"os_log_fsyncs",
711
 
  (char*) &export_vars.innodb_os_log_fsyncs,      SHOW_LONG},
 
579
  (char*) &export_vars.innodb_os_log_fsyncs,              SHOW_LONG},
712
580
  {"os_log_pending_fsyncs",
713
 
  (char*) &export_vars.innodb_os_log_pending_fsyncs,    SHOW_LONG},
 
581
  (char*) &export_vars.innodb_os_log_pending_fsyncs,      SHOW_LONG},
714
582
  {"os_log_pending_writes",
715
 
  (char*) &export_vars.innodb_os_log_pending_writes,    SHOW_LONG},
 
583
  (char*) &export_vars.innodb_os_log_pending_writes,      SHOW_LONG},
716
584
  {"os_log_written",
717
 
  (char*) &export_vars.innodb_os_log_written,     SHOW_LONG},
 
585
  (char*) &export_vars.innodb_os_log_written,             SHOW_LONG},
718
586
  {"page_size",
719
 
  (char*) &export_vars.innodb_page_size,      SHOW_LONG},
 
587
  (char*) &export_vars.innodb_page_size,                  SHOW_LONG},
720
588
  {"pages_created",
721
 
  (char*) &export_vars.innodb_pages_created,      SHOW_LONG},
 
589
  (char*) &export_vars.innodb_pages_created,              SHOW_LONG},
722
590
  {"pages_read",
723
 
  (char*) &export_vars.innodb_pages_read,     SHOW_LONG},
 
591
  (char*) &export_vars.innodb_pages_read,                 SHOW_LONG},
724
592
  {"pages_written",
725
 
  (char*) &export_vars.innodb_pages_written,      SHOW_LONG},
 
593
  (char*) &export_vars.innodb_pages_written,              SHOW_LONG},
726
594
  {"row_lock_current_waits",
727
 
  (char*) &export_vars.innodb_row_lock_current_waits,   SHOW_LONG},
 
595
  (char*) &export_vars.innodb_row_lock_current_waits,     SHOW_LONG},
728
596
  {"row_lock_time",
729
 
  (char*) &export_vars.innodb_row_lock_time,      SHOW_LONGLONG},
 
597
  (char*) &export_vars.innodb_row_lock_time,              SHOW_LONGLONG},
730
598
  {"row_lock_time_avg",
731
 
  (char*) &export_vars.innodb_row_lock_time_avg,    SHOW_LONG},
 
599
  (char*) &export_vars.innodb_row_lock_time_avg,          SHOW_LONG},
732
600
  {"row_lock_time_max",
733
 
  (char*) &export_vars.innodb_row_lock_time_max,    SHOW_LONG},
 
601
  (char*) &export_vars.innodb_row_lock_time_max,          SHOW_LONG},
734
602
  {"row_lock_waits",
735
 
  (char*) &export_vars.innodb_row_lock_waits,     SHOW_LONG},
 
603
  (char*) &export_vars.innodb_row_lock_waits,             SHOW_LONG},
736
604
  {"rows_deleted",
737
 
  (char*) &export_vars.innodb_rows_deleted,     SHOW_LONG},
 
605
  (char*) &export_vars.innodb_rows_deleted,               SHOW_LONG},
738
606
  {"rows_inserted",
739
 
  (char*) &export_vars.innodb_rows_inserted,      SHOW_LONG},
 
607
  (char*) &export_vars.innodb_rows_inserted,              SHOW_LONG},
740
608
  {"rows_read",
741
 
  (char*) &export_vars.innodb_rows_read,      SHOW_LONG},
 
609
  (char*) &export_vars.innodb_rows_read,                  SHOW_LONG},
742
610
  {"rows_updated",
743
 
  (char*) &export_vars.innodb_rows_updated,     SHOW_LONG},
 
611
  (char*) &export_vars.innodb_rows_updated,               SHOW_LONG},
744
612
  {NULL, NULL, SHOW_LONG}
745
613
};
746
614
 
747
 
InnodbStatusTool::Generator::Generator(drizzled::Field **fields) :
748
 
  plugin::TableFunction::Generator(fields)
749
 
750
 
  srv_export_innodb_status();
751
 
  status_var_ptr= innodb_status_variables;
752
 
}
753
 
 
754
 
bool InnodbStatusTool::Generator::populate()
755
 
{
756
 
  if (status_var_ptr->name)
757
 
  {
758
 
    std::ostringstream oss;
759
 
    string return_value;
760
 
    const char *value= status_var_ptr->value;
761
 
 
762
 
    /* VARIABLE_NAME */
763
 
    push(status_var_ptr->name);
764
 
 
765
 
    switch (status_var_ptr->type)
766
 
    {
767
 
    case SHOW_LONG:
768
 
      oss << *(int64_t*) value;
769
 
      return_value= oss.str();
770
 
      break;
771
 
    case SHOW_LONGLONG:
772
 
      oss << *(int64_t*) value;
773
 
      return_value= oss.str();
774
 
      break;
775
 
    case SHOW_BOOL:
776
 
      return_value= *(bool*) value ? "ON" : "OFF";
777
 
      break;
778
 
    default:
779
 
      assert(0);
780
 
    }
781
 
 
782
 
    /* VARIABLE_VALUE */
783
 
    if (return_value.length())
784
 
      push(return_value);
785
 
    else 
786
 
      push(" ");
787
 
 
788
 
    status_var_ptr++;
789
 
 
790
 
    return true;
791
 
  }
792
 
  return false;
793
 
}
794
 
 
795
615
/* General functions */
796
616
 
797
617
/******************************************************************//**
803
623
 
804
624
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking 
805
625
         in non-Cursor code.
806
 
@return true if session is the replication thread */
 
626
@return true if session is the replication thread */
807
627
extern "C" UNIV_INTERN
808
628
ibool
809
629
thd_is_replication_slave_thread(
810
630
/*============================*/
811
 
  void* ) /*!< in: thread handle (Session*) */
 
631
        void*   )       /*!< in: thread handle (Session*) */
812
632
{
813
 
  return false;
 
633
        return false;
814
634
}
815
635
 
816
636
/******************************************************************//**
820
640
void
821
641
innodb_srv_conc_enter_innodb(
822
642
/*=========================*/
823
 
  trx_t*  trx)  /*!< in: transaction handle */
 
643
        trx_t*  trx)    /*!< in: transaction handle */
824
644
{
825
 
  if (UNIV_LIKELY(!srv_thread_concurrency)) {
826
 
 
827
 
    return;
828
 
  }
829
 
 
830
 
  srv_conc_enter_innodb(trx);
 
645
        if (UNIV_LIKELY(!srv_thread_concurrency)) {
 
646
 
 
647
                return;
 
648
        }
 
649
 
 
650
        srv_conc_enter_innodb(trx);
831
651
}
832
652
 
833
653
/******************************************************************//**
837
657
void
838
658
innodb_srv_conc_exit_innodb(
839
659
/*========================*/
840
 
  trx_t*  trx)  /*!< in: transaction handle */
 
660
        trx_t*  trx)    /*!< in: transaction handle */
841
661
{
842
 
  if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
843
 
 
844
 
    return;
845
 
  }
846
 
 
847
 
  srv_conc_exit_innodb(trx);
 
662
        if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
 
663
 
 
664
                return;
 
665
        }
 
666
 
 
667
        srv_conc_exit_innodb(trx);
848
668
}
849
669
 
850
670
/******************************************************************//**
856
676
void
857
677
innobase_release_stat_resources(
858
678
/*============================*/
859
 
  trx_t*  trx)  /*!< in: transaction object */
 
679
        trx_t*  trx)    /*!< in: transaction object */
860
680
{
861
 
  if (trx->has_search_latch) {
862
 
    trx_search_latch_release_if_reserved(trx);
863
 
  }
864
 
 
865
 
  if (trx->declared_to_be_inside_innodb) {
866
 
    /* Release our possible ticket in the FIFO */
867
 
 
868
 
    srv_conc_force_exit_innodb(trx);
869
 
  }
 
681
        if (trx->has_search_latch) {
 
682
                trx_search_latch_release_if_reserved(trx);
 
683
        }
 
684
 
 
685
        if (trx->declared_to_be_inside_innodb) {
 
686
                /* Release our possible ticket in the FIFO */
 
687
 
 
688
                srv_conc_force_exit_innodb(trx);
 
689
        }
870
690
}
871
691
 
872
692
/******************************************************************//**
877
697
 
878
698
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking 
879
699
         in non-Cursor code.
880
 
@return true if non-transactional tables have been edited */
 
700
@return true if non-transactional tables have been edited */
881
701
extern "C" UNIV_INTERN
882
702
ibool
883
703
thd_has_edited_nontrans_tables(
884
704
/*===========================*/
885
 
  void*   session)  /*!< in: thread handle (Session*) */
 
705
        void*           session)        /*!< in: thread handle (Session*) */
886
706
{
887
 
  return((ibool)((Session *)session)->transaction.all.hasModifiedNonTransData());
 
707
        return((ibool) session_non_transactional_update((Session*) session));
888
708
}
889
709
 
890
710
/******************************************************************//**
891
711
Returns true if the thread is executing a SELECT statement.
892
 
@return true if session is executing SELECT */
 
712
@return true if session is executing SELECT */
893
713
extern "C" UNIV_INTERN
894
714
ibool
895
715
thd_is_select(
896
716
/*==========*/
897
 
  const void* session)  /*!< in: thread handle (Session*) */
 
717
        const void*     session)        /*!< in: thread handle (Session*) */
898
718
{
899
 
  return(session_sql_command((const Session*) session) == SQLCOM_SELECT);
 
719
        return(session_sql_command((const Session*) session) == SQLCOM_SELECT);
900
720
}
901
721
 
902
722
/******************************************************************//**
903
723
Returns true if the thread supports XA,
904
724
global value of innodb_supports_xa if session is NULL.
905
 
@return true if session has XA support */
 
725
@return true if session has XA support */
906
726
extern "C" UNIV_INTERN
907
727
ibool
908
728
thd_supports_xa(
909
729
/*============*/
910
 
  void* )  /*!< in: thread handle (Session*), or NULL to query
911
 
        the global innodb_supports_xa */
 
730
        void*   session)        /*!< in: thread handle (Session*), or NULL to query
 
731
                                the global innodb_supports_xa */
912
732
{
913
 
  /* TODO: Add support here for per-session value */
914
 
  return(support_xa);
 
733
        return(SessionVAR((Session*) session, support_xa));
915
734
}
916
735
 
917
736
/******************************************************************//**
918
737
Returns the lock wait timeout for the current connection.
919
 
@return the lock wait timeout, in seconds */
 
738
@return the lock wait timeout, in seconds */
920
739
extern "C" UNIV_INTERN
921
740
ulong
922
741
thd_lock_wait_timeout(
923
742
/*==================*/
924
 
  void*)  /*!< in: thread handle (Session*), or NULL to query
925
 
      the global innodb_lock_wait_timeout */
926
 
{
927
 
  /* TODO: Add support here for per-session value */
928
 
  /* According to <drizzle/plugin.h>, passing session == NULL
929
 
  returns the global value of the session variable. */
930
 
  return((ulong)lock_wait_timeout.get());
931
 
}
932
 
 
933
 
/******************************************************************//**
934
 
Set the time waited for the lock for the current query. */
935
 
extern "C" UNIV_INTERN
936
 
void
937
 
thd_set_lock_wait_time(
938
 
/*===================*/
939
 
        void*   thd,    /*!< in: thread handle (THD*) */
940
 
        ulint   value)  /*!< in: time waited for the lock */
941
 
{
942
 
        if (thd) {
943
 
          static_cast<Session*>(thd)->utime_after_lock+= value;
944
 
        }
 
743
        void*   session)        /*!< in: thread handle (Session*), or NULL to query
 
744
                        the global innodb_lock_wait_timeout */
 
745
{
 
746
        /* According to <drizzle/plugin.h>, passing session == NULL
 
747
        returns the global value of the session variable. */
 
748
        return(SessionVAR((Session*) session, lock_wait_timeout));
945
749
}
946
750
 
947
751
/********************************************************************//**
948
752
Obtain the InnoDB transaction of a MySQL thread.
949
 
@return reference to transaction pointer */
 
753
@return reference to transaction pointer */
950
754
static inline
951
755
trx_t*&
952
756
session_to_trx(
953
757
/*=======*/
954
 
  Session*  session)  /*!< in: Drizzle Session */
955
 
{
956
 
  return *(trx_t**) session->getEngineData(innodb_engine_ptr);
957
 
}
958
 
 
959
 
 
960
 
plugin::ReplicationReturnCode ReplicationLog::apply(Session &session,
961
 
                                                    const message::Transaction &message)
962
 
{
963
 
  char *data= new char[message.ByteSize()];
964
 
 
965
 
  message.SerializeToArray(data, message.ByteSize());
966
 
 
967
 
  trx_t *trx= session_to_trx(&session);
968
 
 
969
 
  uint64_t trx_id= message.transaction_context().transaction_id();
970
 
  ulint error= insert_replication_message(data, message.ByteSize(), trx, trx_id);
971
 
  (void)error;
972
 
 
973
 
  delete[] data;
974
 
 
975
 
  return plugin::SUCCESS;
 
758
        Session*        session)        /*!< in: Drizzle Session */
 
759
{
 
760
        return *(trx_t**) session->getEngineData(innodb_engine_ptr);
976
761
}
977
762
 
978
763
/********************************************************************//**
979
764
Call this function when mysqld passes control to the client. That is to
980
765
avoid deadlocks on the adaptive hash S-latch possibly held by session. For more
981
766
documentation, see Cursor.cc.
982
 
@return 0 */
 
767
@return 0 */
983
768
int
984
 
InnobaseEngine::doReleaseTemporaryLatches(
 
769
InnobaseEngine::release_temporary_latches(
985
770
/*===============================*/
986
 
  Session*    session)  /*!< in: MySQL thread */
 
771
        Session*                session)        /*!< in: MySQL thread */
987
772
{
988
 
  trx_t*  trx;
989
 
 
990
 
  assert(this == innodb_engine_ptr);
991
 
 
992
 
  if (!innodb_inited) {
993
 
 
994
 
    return(0);
995
 
  }
996
 
 
997
 
  trx = session_to_trx(session);
998
 
 
999
 
  if (trx) {
1000
 
    innobase_release_stat_resources(trx);
1001
 
  }
1002
 
  return(0);
 
773
        trx_t*  trx;
 
774
 
 
775
        assert(this == innodb_engine_ptr);
 
776
 
 
777
        if (!innodb_inited) {
 
778
 
 
779
                return(0);
 
780
        }
 
781
 
 
782
        trx = session_to_trx(session);
 
783
 
 
784
        if (trx) {
 
785
                innobase_release_stat_resources(trx);
 
786
        }
 
787
        return(0);
1003
788
}
1004
789
 
1005
790
/********************************************************************//**
1012
797
innobase_active_small(void)
1013
798
/*=======================*/
1014
799
{
1015
 
  innobase_active_counter++;
 
800
        innobase_active_counter++;
1016
801
 
1017
 
  if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
1018
 
    srv_active_wake_master_thread();
1019
 
  }
 
802
        if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
 
803
                srv_active_wake_master_thread();
 
804
        }
1020
805
}
1021
806
 
1022
807
/********************************************************************//**
1023
808
Converts an InnoDB error code to a MySQL error code and also tells to MySQL
1024
809
about a possible transaction rollback inside InnoDB caused by a lock wait
1025
810
timeout or a deadlock.
1026
 
@return MySQL error code */
 
811
@return MySQL error code */
1027
812
extern "C" UNIV_INTERN
1028
813
int
1029
814
convert_error_code_to_mysql(
1030
815
/*========================*/
1031
 
  int   error,  /*!< in: InnoDB error code */
1032
 
  ulint   flags,  /*!< in: InnoDB table flags, or 0 */
1033
 
  Session*  session)/*!< in: user thread handle or NULL */
1034
 
{
1035
 
  switch (error) {
1036
 
  case DB_SUCCESS:
1037
 
    return(0);
1038
 
 
1039
 
  case DB_INTERRUPTED:
1040
 
    my_error(ER_QUERY_INTERRUPTED, MYF(0));
1041
 
    /* fall through */
1042
 
 
1043
 
  case DB_FOREIGN_EXCEED_MAX_CASCADE:
1044
 
    push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1045
 
                        HA_ERR_ROW_IS_REFERENCED,
1046
 
                        "InnoDB: Cannot delete/update "
1047
 
                        "rows with cascading foreign key "
1048
 
                        "constraints that exceed max "
1049
 
                        "depth of %d. Please "
1050
 
                        "drop extra constraints and try "
1051
 
                        "again", DICT_FK_MAX_RECURSIVE_LOAD);
1052
 
    /* fall through */
1053
 
 
1054
 
  case DB_ERROR:
1055
 
  default:
1056
 
    return(-1); /* unspecified error */
1057
 
 
1058
 
  case DB_DUPLICATE_KEY:
1059
 
    /* Be cautious with returning this error, since
1060
 
       mysql could re-enter the storage layer to get
1061
 
       duplicated key info, the operation requires a
1062
 
       valid table handle and/or transaction information,
1063
 
       which might not always be available in the error
1064
 
       handling stage. */
1065
 
    return(HA_ERR_FOUND_DUPP_KEY);
1066
 
 
1067
 
  case DB_FOREIGN_DUPLICATE_KEY:
1068
 
    return(HA_ERR_FOREIGN_DUPLICATE_KEY);
1069
 
 
1070
 
  case DB_MISSING_HISTORY:
1071
 
    return(HA_ERR_TABLE_DEF_CHANGED);
1072
 
 
1073
 
  case DB_RECORD_NOT_FOUND:
1074
 
    return(HA_ERR_NO_ACTIVE_RECORD);
1075
 
 
1076
 
  case DB_DEADLOCK:
1077
 
    /* Since we rolled back the whole transaction, we must
1078
 
    tell it also to MySQL so that MySQL knows to empty the
1079
 
    cached binlog for this transaction */
1080
 
 
1081
 
    mark_transaction_to_rollback(session, TRUE);
1082
 
 
1083
 
    return(HA_ERR_LOCK_DEADLOCK);
1084
 
 
1085
 
  case DB_LOCK_WAIT_TIMEOUT:
1086
 
    /* Starting from 5.0.13, we let MySQL just roll back the
1087
 
    latest SQL statement in a lock wait timeout. Previously, we
1088
 
    rolled back the whole transaction. */
1089
 
 
1090
 
    mark_transaction_to_rollback(session, (bool)row_rollback_on_timeout);
1091
 
 
1092
 
    return(HA_ERR_LOCK_WAIT_TIMEOUT);
1093
 
 
1094
 
  case DB_NO_REFERENCED_ROW:
1095
 
    return(HA_ERR_NO_REFERENCED_ROW);
1096
 
 
1097
 
  case DB_ROW_IS_REFERENCED:
1098
 
    return(HA_ERR_ROW_IS_REFERENCED);
1099
 
 
1100
 
  case DB_CANNOT_ADD_CONSTRAINT:
1101
 
    return(HA_ERR_CANNOT_ADD_FOREIGN);
1102
 
 
1103
 
  case DB_CANNOT_DROP_CONSTRAINT:
1104
 
 
1105
 
    return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
1106
 
            misleading, a new MySQL error
1107
 
            code should be introduced */
1108
 
 
1109
 
  case DB_COL_APPEARS_TWICE_IN_INDEX:
1110
 
  case DB_CORRUPTION:
1111
 
    return(HA_ERR_CRASHED);
1112
 
 
1113
 
  case DB_OUT_OF_FILE_SPACE:
1114
 
    return(HA_ERR_RECORD_FILE_FULL);
1115
 
 
1116
 
  case DB_TABLE_IS_BEING_USED:
1117
 
    return(HA_ERR_WRONG_COMMAND);
1118
 
 
1119
 
  case DB_TABLE_NOT_FOUND:
1120
 
    return(HA_ERR_NO_SUCH_TABLE);
1121
 
 
1122
 
  case DB_TOO_BIG_RECORD:
1123
 
    my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
1124
 
       page_get_free_space_of_empty(flags
1125
 
                  & DICT_TF_COMPACT) / 2);
1126
 
    return(HA_ERR_TO_BIG_ROW);
1127
 
 
1128
 
  case DB_NO_SAVEPOINT:
1129
 
    return(HA_ERR_NO_SAVEPOINT);
1130
 
 
1131
 
  case DB_LOCK_TABLE_FULL:
1132
 
    /* Since we rolled back the whole transaction, we must
1133
 
    tell it also to MySQL so that MySQL knows to empty the
1134
 
    cached binlog for this transaction */
1135
 
 
1136
 
    mark_transaction_to_rollback(session, TRUE);
1137
 
 
1138
 
    return(HA_ERR_LOCK_TABLE_FULL);
1139
 
 
1140
 
  case DB_PRIMARY_KEY_IS_NULL:
1141
 
    return(ER_PRIMARY_CANT_HAVE_NULL);
1142
 
 
1143
 
  case DB_TOO_MANY_CONCURRENT_TRXS:
1144
 
 
1145
 
    /* Once MySQL add the appropriate code to errmsg.txt then
1146
 
    we can get rid of this #ifdef. NOTE: The code checked by
1147
 
    the #ifdef is the suggested name for the error condition
1148
 
    and the actual error code name could very well be different.
1149
 
    This will require some monitoring, ie. the status
1150
 
    of this request on our part.*/
1151
 
 
1152
 
    /* New error code HA_ERR_TOO_MANY_CONCURRENT_TRXS is only
1153
 
       available in 5.1.38 and later, but the plugin should still
1154
 
       work with previous versions of MySQL.
1155
 
       In Drizzle we seem to not have this yet.
1156
 
    */
1157
 
#ifdef HA_ERR_TOO_MANY_CONCURRENT_TRXS
1158
 
    return(HA_ERR_TOO_MANY_CONCURRENT_TRXS);
1159
 
#else /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */
1160
 
    return(HA_ERR_RECORD_FILE_FULL);
1161
 
#endif /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */
1162
 
  case DB_UNSUPPORTED:
1163
 
    return(HA_ERR_UNSUPPORTED);
1164
 
  }
1165
 
}
1166
 
 
 
816
        int             error,  /*!< in: InnoDB error code */
 
817
        ulint           flags,  /*!< in: InnoDB table flags, or 0 */
 
818
        Session*        session)/*!< in: user thread handle or NULL */
 
819
{
 
820
        switch (error) {
 
821
        case DB_SUCCESS:
 
822
                return(0);
 
823
 
 
824
        case DB_ERROR:
 
825
        default:
 
826
                return(-1); /* unspecified error */
 
827
 
 
828
        case DB_DUPLICATE_KEY:
 
829
                return(HA_ERR_FOUND_DUPP_KEY);
 
830
 
 
831
        case DB_FOREIGN_DUPLICATE_KEY:
 
832
                return(HA_ERR_FOREIGN_DUPLICATE_KEY);
 
833
 
 
834
        case DB_MISSING_HISTORY:
 
835
                return(HA_ERR_TABLE_DEF_CHANGED);
 
836
 
 
837
        case DB_RECORD_NOT_FOUND:
 
838
                return(HA_ERR_NO_ACTIVE_RECORD);
 
839
 
 
840
        case DB_DEADLOCK:
 
841
                /* Since we rolled back the whole transaction, we must
 
842
                tell it also to MySQL so that MySQL knows to empty the
 
843
                cached binlog for this transaction */
 
844
 
 
845
                session_mark_transaction_to_rollback(session, TRUE);
 
846
 
 
847
                return(HA_ERR_LOCK_DEADLOCK);
 
848
 
 
849
        case DB_LOCK_WAIT_TIMEOUT:
 
850
                /* Starting from 5.0.13, we let MySQL just roll back the
 
851
                latest SQL statement in a lock wait timeout. Previously, we
 
852
                rolled back the whole transaction. */
 
853
 
 
854
                session_mark_transaction_to_rollback(session,
 
855
                                             (bool)row_rollback_on_timeout);
 
856
 
 
857
                return(HA_ERR_LOCK_WAIT_TIMEOUT);
 
858
 
 
859
        case DB_NO_REFERENCED_ROW:
 
860
                return(HA_ERR_NO_REFERENCED_ROW);
 
861
 
 
862
        case DB_ROW_IS_REFERENCED:
 
863
                return(HA_ERR_ROW_IS_REFERENCED);
 
864
 
 
865
        case DB_CANNOT_ADD_CONSTRAINT:
 
866
                return(HA_ERR_CANNOT_ADD_FOREIGN);
 
867
 
 
868
        case DB_CANNOT_DROP_CONSTRAINT:
 
869
 
 
870
                return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
 
871
                                                misleading, a new MySQL error
 
872
                                                code should be introduced */
 
873
 
 
874
        case DB_COL_APPEARS_TWICE_IN_INDEX:
 
875
        case DB_CORRUPTION:
 
876
                return(HA_ERR_CRASHED);
 
877
 
 
878
        case DB_OUT_OF_FILE_SPACE:
 
879
                return(HA_ERR_RECORD_FILE_FULL);
 
880
 
 
881
        case DB_TABLE_IS_BEING_USED:
 
882
                return(HA_ERR_WRONG_COMMAND);
 
883
 
 
884
        case DB_TABLE_NOT_FOUND:
 
885
                return(HA_ERR_NO_SUCH_TABLE);
 
886
 
 
887
        case DB_TOO_BIG_RECORD:
 
888
                my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
 
889
                         page_get_free_space_of_empty(flags
 
890
                                                      & DICT_TF_COMPACT) / 2);
 
891
                return(HA_ERR_TO_BIG_ROW);
 
892
 
 
893
        case DB_NO_SAVEPOINT:
 
894
                return(HA_ERR_NO_SAVEPOINT);
 
895
 
 
896
        case DB_LOCK_TABLE_FULL:
 
897
                /* Since we rolled back the whole transaction, we must
 
898
                tell it also to MySQL so that MySQL knows to empty the
 
899
                cached binlog for this transaction */
 
900
 
 
901
                session_mark_transaction_to_rollback(session, TRUE);
 
902
 
 
903
                return(HA_ERR_LOCK_TABLE_FULL);
 
904
 
 
905
        case DB_PRIMARY_KEY_IS_NULL:
 
906
                return(ER_PRIMARY_CANT_HAVE_NULL);
 
907
 
 
908
        case DB_TOO_MANY_CONCURRENT_TRXS:
 
909
 
 
910
                /* Once MySQL add the appropriate code to errmsg.txt then
 
911
                we can get rid of this #ifdef. NOTE: The code checked by
 
912
                the #ifdef is the suggested name for the error condition
 
913
                and the actual error code name could very well be different.
 
914
                This will require some monitoring, ie. the status
 
915
                of this request on our part.*/
 
916
#ifdef ER_TOO_MANY_CONCURRENT_TRXS
 
917
                return(ER_TOO_MANY_CONCURRENT_TRXS);
 
918
#else
 
919
                return(HA_ERR_RECORD_FILE_FULL);
 
920
#endif
 
921
        case DB_UNSUPPORTED:
 
922
                return(HA_ERR_UNSUPPORTED);
 
923
        }
 
924
}
 
925
 
 
926
/*************************************************************//**
 
927
If you want to print a session that is not associated with the current thread,
 
928
you must call this function before reserving the InnoDB kernel_mutex, to
 
929
protect Drizzle from setting session->query NULL. If you print a session of the
 
930
current thread, we know that Drizzle cannot modify sesion->query, and it is
 
931
not necessary to call this. Call innobase_mysql_end_print_arbitrary_thd()
 
932
after you release the kernel_mutex.
 
933
 
 
934
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking 
 
935
         in non-Cursor code.
 
936
 */
 
937
extern "C" UNIV_INTERN
 
938
void
 
939
innobase_mysql_prepare_print_arbitrary_thd(void)
 
940
/*============================================*/
 
941
{
 
942
        ut_ad(!mutex_own(&kernel_mutex));
 
943
        pthread_mutex_lock(&LOCK_thread_count);
 
944
}
 
945
 
 
946
/*************************************************************//**
 
947
Releases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd().
 
948
In the InnoDB latching order, the mutex sits right above the
 
949
kernel_mutex.  In debug builds, we assert that the kernel_mutex is
 
950
released before this function is invoked. 
 
951
 
 
952
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking 
 
953
         in non-Cursor code.
 
954
*/
 
955
extern "C" UNIV_INTERN
 
956
void
 
957
innobase_mysql_end_print_arbitrary_thd(void)
 
958
/*========================================*/
 
959
{
 
960
        ut_ad(!mutex_own(&kernel_mutex));
 
961
        pthread_mutex_unlock(&LOCK_thread_count);
 
962
}
1167
963
 
1168
964
/*************************************************************//**
1169
965
Prints info of a Session object (== user session thread) to the given file. */
1171
967
void
1172
968
innobase_mysql_print_thd(
1173
969
/*=====================*/
1174
 
  FILE* f,    /*!< in: output stream */
1175
 
  void * in_session,  /*!< in: pointer to a Drizzle Session object */
1176
 
  uint  )   /*!< in: max query length to print, or 0 to
1177
 
           use the default max length */
 
970
        FILE*   f,              /*!< in: output stream */
 
971
        void * in_session,      /*!< in: pointer to a Drizzle Session object */
 
972
        uint    )               /*!< in: max query length to print, or 0 to
 
973
                                   use the default max length */
1178
974
{
1179
975
  Session *session= reinterpret_cast<Session *>(in_session);
1180
976
  fprintf(f,
1181
977
          "Drizzle thread %"PRIu64", query id %"PRIu64", %s, %s, %s ",
1182
 
          static_cast<uint64_t>(session->getSessionId()),
 
978
          static_cast<uint64_t>(session_get_thread_id( session)),
1183
979
          static_cast<uint64_t>(session->getQueryId()),
1184
980
          glob_hostname,
1185
 
          session->getSecurityContext().getIp().c_str(),
1186
 
          session->getSecurityContext().getUser().c_str()
1187
 
  );
1188
 
  fprintf(f, "\n%s", session->getQueryString()->c_str());
1189
 
  putc('\n', f);
 
981
          session->security_ctx.ip.c_str(),
 
982
          session->security_ctx.user.c_str()
 
983
  );
 
984
  fprintf(f,
 
985
          "\n%s", session->getQueryString()
 
986
  );
 
987
        putc('\n', f);
1190
988
}
1191
989
 
1192
990
/******************************************************************//**
1195
993
void
1196
994
innobase_get_cset_width(
1197
995
/*====================*/
1198
 
  ulint cset,   /*!< in: MySQL charset-collation code */
1199
 
  ulint*  mbminlen, /*!< out: minimum length of a char (in bytes) */
1200
 
  ulint*  mbmaxlen) /*!< out: maximum length of a char (in bytes) */
 
996
        ulint   cset,           /*!< in: MySQL charset-collation code */
 
997
        ulint*  mbminlen,       /*!< out: minimum length of a char (in bytes) */
 
998
        ulint*  mbmaxlen)       /*!< out: maximum length of a char (in bytes) */
1201
999
{
1202
 
  CHARSET_INFO* cs;
1203
 
  ut_ad(cset < 256);
1204
 
  ut_ad(mbminlen);
1205
 
  ut_ad(mbmaxlen);
 
1000
        CHARSET_INFO*   cs;
 
1001
        ut_ad(cset < 256);
 
1002
        ut_ad(mbminlen);
 
1003
        ut_ad(mbmaxlen);
1206
1004
 
1207
 
  cs = all_charsets[cset];
1208
 
  if (cs) {
1209
 
    *mbminlen = cs->mbminlen;
1210
 
    *mbmaxlen = cs->mbmaxlen;
1211
 
    ut_ad(*mbminlen < DATA_MBMAX);
1212
 
    ut_ad(*mbmaxlen < DATA_MBMAX);
1213
 
  } else {
1214
 
    ut_a(cset == 0);
1215
 
    *mbminlen = *mbmaxlen = 0;
1216
 
  }
 
1005
        cs = all_charsets[cset];
 
1006
        if (cs) {
 
1007
                *mbminlen = cs->mbminlen;
 
1008
                *mbmaxlen = cs->mbmaxlen;
 
1009
        } else {
 
1010
                ut_a(cset == 0);
 
1011
                *mbminlen = *mbmaxlen = 0;
 
1012
        }
1217
1013
}
1218
1014
 
1219
1015
/******************************************************************//**
1222
1018
void
1223
1019
innobase_convert_from_table_id(
1224
1020
/*===========================*/
1225
 
  const void*,      /*!< in: the 'from' character set */
1226
 
  char*     to, /*!< out: converted identifier */
1227
 
  const char*   from, /*!< in: identifier to convert */
1228
 
  ulint     len)  /*!< in: length of 'to', in bytes */
 
1021
        const void*,                    /*!< in: the 'from' character set */
 
1022
        char*                   to,     /*!< out: converted identifier */
 
1023
        const char*             from,   /*!< in: identifier to convert */
 
1024
        ulint                   len)    /*!< in: length of 'to', in bytes */
1229
1025
{
1230
 
  strncpy(to, from, len);
 
1026
        strncpy(to, from, len);
1231
1027
}
1232
1028
 
1233
1029
/******************************************************************//**
1236
1032
void
1237
1033
innobase_convert_from_id(
1238
1034
/*=====================*/
1239
 
  const void*,      /*!< in: the 'from' character set */
1240
 
  char*     to, /*!< out: converted identifier */
1241
 
  const char*   from, /*!< in: identifier to convert */
1242
 
  ulint     len)  /*!< in: length of 'to', in bytes */
 
1035
        const void*,                    /*!< in: the 'from' character set */
 
1036
        char*                   to,     /*!< out: converted identifier */
 
1037
        const char*             from,   /*!< in: identifier to convert */
 
1038
        ulint                   len)    /*!< in: length of 'to', in bytes */
1243
1039
{
1244
 
  strncpy(to, from, len);
 
1040
        strncpy(to, from, len);
1245
1041
}
1246
1042
 
1247
1043
/******************************************************************//**
1248
1044
Compares NUL-terminated UTF-8 strings case insensitively.
1249
 
@return 0 if a=b, <0 if a<b, >1 if a>b */
 
1045
@return 0 if a=b, <0 if a<b, >1 if a>b */
1250
1046
extern "C" UNIV_INTERN
1251
1047
int
1252
1048
innobase_strcasecmp(
1253
1049
/*================*/
1254
 
  const char* a,  /*!< in: first string to compare */
1255
 
  const char* b)  /*!< in: second string to compare */
 
1050
        const char*     a,      /*!< in: first string to compare */
 
1051
        const char*     b)      /*!< in: second string to compare */
1256
1052
{
1257
 
  return(my_strcasecmp(system_charset_info, a, b));
 
1053
        return(my_strcasecmp(system_charset_info, a, b));
1258
1054
}
1259
1055
 
1260
1056
/******************************************************************//**
1263
1059
void
1264
1060
innobase_casedn_str(
1265
1061
/*================*/
1266
 
  char* a)  /*!< in/out: string to put in lower case */
 
1062
        char*   a)      /*!< in/out: string to put in lower case */
1267
1063
{
1268
 
  my_casedn_str(system_charset_info, a);
 
1064
        my_casedn_str(system_charset_info, a);
1269
1065
}
1270
1066
 
1271
1067
/**********************************************************************//**
1272
1068
Determines the connection character set.
1273
 
@return connection character set */
 
1069
@return connection character set */
1274
1070
extern "C" UNIV_INTERN
1275
1071
const void*
1276
1072
innobase_get_charset(
1277
1073
/*=================*/
1278
 
  void* mysql_session)  /*!< in: MySQL thread handle */
 
1074
        void*   mysql_session)  /*!< in: MySQL thread handle */
1279
1075
{
1280
 
  return static_cast<Session*>(mysql_session)->charset();
 
1076
        return session_charset(static_cast<Session*>(mysql_session));
1281
1077
}
1282
1078
 
1283
1079
extern "C" UNIV_INTERN
1284
1080
bool
1285
1081
innobase_isspace(
1286
 
  const void *cs,
1287
 
  char char_to_test)
 
1082
        const void *cs,
 
1083
        char char_to_test)
1288
1084
{
1289
 
  return my_isspace(static_cast<const CHARSET_INFO *>(cs), char_to_test);
 
1085
        return my_isspace(static_cast<const CHARSET_INFO *>(cs), char_to_test);
1290
1086
}
1291
1087
 
1292
1088
UNIV_INTERN
1294
1090
innobase_fast_mutex_init(
1295
1091
        os_fast_mutex_t*        fast_mutex)
1296
1092
{
1297
 
  return pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST);
1298
 
}
1299
 
 
1300
 
/**********************************************************************//**
1301
 
Determines the current SQL statement.
1302
 
@return        SQL statement string */
1303
 
extern "C" UNIV_INTERN
1304
 
const char*
1305
 
innobase_get_stmt(
1306
 
/*==============*/
1307
 
       void*   session,        /*!< in: MySQL thread handle */
1308
 
       size_t* length)         /*!< out: length of the SQL statement */
1309
 
{
1310
 
  return static_cast<Session*>(session)->getQueryStringCopy(*length);
 
1093
        return pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST);
1311
1094
}
1312
1095
 
1313
1096
#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
1317
1100
extern "C"
1318
1101
void __cdecl
1319
1102
_dosmaperr(
1320
 
  unsigned long); /*!< in: OS error value */
 
1103
        unsigned long); /*!< in: OS error value */
1321
1104
 
1322
1105
/*********************************************************************//**
1323
1106
Creates a temporary file.
1324
 
@return temporary file descriptor, or < 0 on error */
 
1107
@return temporary file descriptor, or < 0 on error */
1325
1108
extern "C" UNIV_INTERN
1326
1109
int
1327
1110
innobase_mysql_tmpfile(void)
1328
1111
/*========================*/
1329
1112
{
1330
 
  int fd;       /* handle of opened file */
1331
 
  HANDLE  osfh;       /* OS handle of opened file */
1332
 
  char* tmpdir;       /* point to the directory
1333
 
            where to create file */
1334
 
  TCHAR path_buf[MAX_PATH - 14];  /* buffer for tmp file path.
1335
 
            The length cannot be longer
1336
 
            than MAX_PATH - 14, or
1337
 
            GetTempFileName will fail. */
1338
 
  char  filename[MAX_PATH];   /* name of the tmpfile */
1339
 
  DWORD fileaccess = GENERIC_READ /* OS file access */
1340
 
           | GENERIC_WRITE
1341
 
           | DELETE;
1342
 
  DWORD fileshare = FILE_SHARE_READ /* OS file sharing mode */
1343
 
          | FILE_SHARE_WRITE
1344
 
          | FILE_SHARE_DELETE;
1345
 
  DWORD filecreate = CREATE_ALWAYS; /* OS method of open/create */
1346
 
  DWORD fileattrib =      /* OS file attribute flags */
1347
 
           FILE_ATTRIBUTE_NORMAL
1348
 
           | FILE_FLAG_DELETE_ON_CLOSE
1349
 
           | FILE_ATTRIBUTE_TEMPORARY
1350
 
           | FILE_FLAG_SEQUENTIAL_SCAN;
1351
 
 
1352
 
  tmpdir = my_tmpdir(&mysql_tmpdir_list);
1353
 
 
1354
 
  /* The tmpdir parameter can not be NULL for GetTempFileName. */
1355
 
  if (!tmpdir) {
1356
 
    uint  ret;
1357
 
 
1358
 
    /* Use GetTempPath to determine path for temporary files. */
1359
 
    ret = GetTempPath(sizeof(path_buf), path_buf);
1360
 
    if (ret > sizeof(path_buf) || (ret == 0)) {
1361
 
 
1362
 
      _dosmaperr(GetLastError()); /* map error */
1363
 
      return(-1);
1364
 
    }
1365
 
 
1366
 
    tmpdir = path_buf;
1367
 
  }
1368
 
 
1369
 
  /* Use GetTempFileName to generate a unique filename. */
1370
 
  if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
1371
 
 
1372
 
    _dosmaperr(GetLastError()); /* map error */
1373
 
    return(-1);
1374
 
  }
1375
 
 
1376
 
  /* Open/Create the file. */
1377
 
  osfh = CreateFile(filename, fileaccess, fileshare, NULL,
1378
 
        filecreate, fileattrib, NULL);
1379
 
  if (osfh == INVALID_HANDLE_VALUE) {
1380
 
 
1381
 
    /* open/create file failed! */
1382
 
    _dosmaperr(GetLastError()); /* map error */
1383
 
    return(-1);
1384
 
  }
1385
 
 
1386
 
  do {
1387
 
    /* Associates a CRT file descriptor with the OS file handle. */
1388
 
    fd = _open_osfhandle((intptr_t) osfh, 0);
1389
 
  } while (fd == -1 && errno == EINTR);
1390
 
 
1391
 
  if (fd == -1) {
1392
 
    /* Open failed, close the file handle. */
1393
 
 
1394
 
    _dosmaperr(GetLastError()); /* map error */
1395
 
    CloseHandle(osfh);    /* no need to check if
1396
 
            CloseHandle fails */
1397
 
  }
1398
 
 
1399
 
  return(fd);
 
1113
        int     fd;                             /* handle of opened file */
 
1114
        HANDLE  osfh;                           /* OS handle of opened file */
 
1115
        char*   tmpdir;                         /* point to the directory
 
1116
                                                where to create file */
 
1117
        TCHAR   path_buf[MAX_PATH - 14];        /* buffer for tmp file path.
 
1118
                                                The length cannot be longer
 
1119
                                                than MAX_PATH - 14, or
 
1120
                                                GetTempFileName will fail. */
 
1121
        char    filename[MAX_PATH];             /* name of the tmpfile */
 
1122
        DWORD   fileaccess = GENERIC_READ       /* OS file access */
 
1123
                             | GENERIC_WRITE
 
1124
                             | DELETE;
 
1125
        DWORD   fileshare = FILE_SHARE_READ     /* OS file sharing mode */
 
1126
                            | FILE_SHARE_WRITE
 
1127
                            | FILE_SHARE_DELETE;
 
1128
        DWORD   filecreate = CREATE_ALWAYS;     /* OS method of open/create */
 
1129
        DWORD   fileattrib =                    /* OS file attribute flags */
 
1130
                             FILE_ATTRIBUTE_NORMAL
 
1131
                             | FILE_FLAG_DELETE_ON_CLOSE
 
1132
                             | FILE_ATTRIBUTE_TEMPORARY
 
1133
                             | FILE_FLAG_SEQUENTIAL_SCAN;
 
1134
 
 
1135
        tmpdir = my_tmpdir(&mysql_tmpdir_list);
 
1136
 
 
1137
        /* The tmpdir parameter can not be NULL for GetTempFileName. */
 
1138
        if (!tmpdir) {
 
1139
                uint    ret;
 
1140
 
 
1141
                /* Use GetTempPath to determine path for temporary files. */
 
1142
                ret = GetTempPath(sizeof(path_buf), path_buf);
 
1143
                if (ret > sizeof(path_buf) || (ret == 0)) {
 
1144
 
 
1145
                        _dosmaperr(GetLastError());     /* map error */
 
1146
                        return(-1);
 
1147
                }
 
1148
 
 
1149
                tmpdir = path_buf;
 
1150
        }
 
1151
 
 
1152
        /* Use GetTempFileName to generate a unique filename. */
 
1153
        if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
 
1154
 
 
1155
                _dosmaperr(GetLastError());     /* map error */
 
1156
                return(-1);
 
1157
        }
 
1158
 
 
1159
        /* Open/Create the file. */
 
1160
        osfh = CreateFile(filename, fileaccess, fileshare, NULL,
 
1161
                          filecreate, fileattrib, NULL);
 
1162
        if (osfh == INVALID_HANDLE_VALUE) {
 
1163
 
 
1164
                /* open/create file failed! */
 
1165
                _dosmaperr(GetLastError());     /* map error */
 
1166
                return(-1);
 
1167
        }
 
1168
 
 
1169
        do {
 
1170
                /* Associates a CRT file descriptor with the OS file handle. */
 
1171
                fd = _open_osfhandle((intptr_t) osfh, 0);
 
1172
        } while (fd == -1 && errno == EINTR);
 
1173
 
 
1174
        if (fd == -1) {
 
1175
                /* Open failed, close the file handle. */
 
1176
 
 
1177
                _dosmaperr(GetLastError());     /* map error */
 
1178
                CloseHandle(osfh);              /* no need to check if
 
1179
                                                CloseHandle fails */
 
1180
        }
 
1181
 
 
1182
        return(fd);
1400
1183
}
1401
1184
#else
1402
1185
/*********************************************************************//**
1403
1186
Creates a temporary file.
1404
 
@return temporary file descriptor, or < 0 on error */
 
1187
@return temporary file descriptor, or < 0 on error */
1405
1188
extern "C" UNIV_INTERN
1406
1189
int
1407
1190
innobase_mysql_tmpfile(void)
1408
1191
/*========================*/
1409
1192
{
1410
 
  int fd2 = -1;
1411
 
  int fd = mysql_tmpfile("ib");
1412
 
  if (fd >= 0) {
1413
 
    /* Copy the file descriptor, so that the additional resources
1414
 
    allocated by create_temp_file() can be freed by invoking
1415
 
    internal::my_close().
 
1193
        int     fd2 = -1;
 
1194
        int     fd = mysql_tmpfile("ib");
 
1195
        if (fd >= 0) {
 
1196
                /* Copy the file descriptor, so that the additional resources
 
1197
                allocated by create_temp_file() can be freed by invoking
 
1198
                internal::my_close().
1416
1199
 
1417
 
    Because the file descriptor returned by this function
1418
 
    will be passed to fdopen(), it will be closed by invoking
1419
 
    fclose(), which in turn will invoke close() instead of
1420
 
    internal::my_close(). */
1421
 
    fd2 = dup(fd);
1422
 
    if (fd2 < 0) {
1423
 
      errno=errno;
1424
 
      my_error(EE_OUT_OF_FILERESOURCES,
1425
 
         MYF(ME_BELL+ME_WAITTANG),
1426
 
         "ib*", errno);
1427
 
    }
1428
 
    internal::my_close(fd, MYF(MY_WME));
1429
 
  }
1430
 
  return(fd2);
 
1200
                Because the file descriptor returned by this function
 
1201
                will be passed to fdopen(), it will be closed by invoking
 
1202
                fclose(), which in turn will invoke close() instead of
 
1203
                internal::my_close(). */
 
1204
                fd2 = dup(fd);
 
1205
                if (fd2 < 0) {
 
1206
                        errno=errno;
 
1207
                        my_error(EE_OUT_OF_FILERESOURCES,
 
1208
                                 MYF(ME_BELL+ME_WAITTANG),
 
1209
                                 "ib*", errno);
 
1210
                }
 
1211
                internal::my_close(fd, MYF(MY_WME));
 
1212
        }
 
1213
        return(fd2);
1431
1214
}
1432
1215
#endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */
1433
1216
 
1440
1223
The result is always NUL-terminated (provided buf_size > 0) and the
1441
1224
number of bytes that were written to "buf" is returned (including the
1442
1225
terminating NUL).
1443
 
@return number of bytes that were written */
 
1226
@return number of bytes that were written */
1444
1227
extern "C" UNIV_INTERN
1445
1228
ulint
1446
1229
innobase_raw_format(
1447
1230
/*================*/
1448
 
  const char* data,   /*!< in: raw data */
1449
 
  ulint   data_len, /*!< in: raw data length
1450
 
          in bytes */
1451
 
  ulint   ,   /*!< in: charset collation */
1452
 
  char*   buf,    /*!< out: output buffer */
1453
 
  ulint   buf_size) /*!< in: output buffer size
1454
 
          in bytes */
 
1231
        const char*     data,           /*!< in: raw data */
 
1232
        ulint           data_len,       /*!< in: raw data length
 
1233
                                        in bytes */
 
1234
        ulint           ,               /*!< in: charset collation */
 
1235
        char*           buf,            /*!< out: output buffer */
 
1236
        ulint           buf_size)       /*!< in: output buffer size
 
1237
                                        in bytes */
1455
1238
{
1456
 
  return(ut_str_sql_format(data, data_len, buf, buf_size));
 
1239
        return(ut_str_sql_format(data, data_len, buf, buf_size));
1457
1240
}
1458
1241
 
1459
1242
/*********************************************************************//**
1468
1251
Note: This function is also called with increment set to the number of
1469
1252
values we want to reserve for multi-value inserts e.g.,
1470
1253
 
1471
 
  INSERT INTO T VALUES(), (), ();
 
1254
        INSERT INTO T VALUES(), (), ();
1472
1255
 
1473
1256
innobase_next_autoinc() will be called with increment set to
 
1257
n * 3 where autoinc_lock_mode != TRADITIONAL because we want
1474
1258
to reserve 3 values for the multi-value INSERT above.
1475
 
@return the next value */
 
1259
@return the next value */
1476
1260
static
1477
1261
uint64_t
1478
1262
innobase_next_autoinc(
1479
1263
/*==================*/
1480
 
  uint64_t  current,  /*!< in: Current value */
1481
 
  uint64_t  increment,  /*!< in: increment current by */
1482
 
  uint64_t  offset,   /*!< in: AUTOINC offset */
1483
 
  uint64_t  max_value)  /*!< in: max value for type */
 
1264
        uint64_t        current,        /*!< in: Current value */
 
1265
        uint64_t        increment,      /*!< in: increment current by */
 
1266
        uint64_t        offset,         /*!< in: AUTOINC offset */
 
1267
        uint64_t        max_value)      /*!< in: max value for type */
1484
1268
{
1485
 
  uint64_t  next_value;
1486
 
 
1487
 
  /* Should never be 0. */
1488
 
  ut_a(increment > 0);
1489
 
 
1490
 
  /* According to MySQL documentation, if the offset is greater than
1491
 
  the increment then the offset is ignored. */
1492
 
  if (offset > increment) {
1493
 
    offset = 0;
1494
 
  }
1495
 
 
1496
 
  if (max_value <= current) {
1497
 
    next_value = max_value;
1498
 
  } else if (offset <= 1) {
1499
 
    /* Offset 0 and 1 are the same, because there must be at
1500
 
    least one node in the system. */
1501
 
    if (max_value - current <= increment) {
1502
 
      next_value = max_value;
1503
 
    } else {
1504
 
      next_value = current + increment;
1505
 
    }
1506
 
  } else if (max_value > current) {
1507
 
    if (current > offset) {
1508
 
      next_value = ((current - offset) / increment) + 1;
1509
 
    } else {
1510
 
      next_value = ((offset - current) / increment) + 1;
1511
 
    }
1512
 
 
1513
 
    ut_a(increment > 0);
1514
 
    ut_a(next_value > 0);
1515
 
 
1516
 
    /* Check for multiplication overflow. */
1517
 
    if (increment > (max_value / next_value)) {
1518
 
 
1519
 
      next_value = max_value;
1520
 
    } else {
1521
 
      next_value *= increment;
1522
 
 
1523
 
      ut_a(max_value >= next_value);
1524
 
 
1525
 
      /* Check for overflow. */
1526
 
      if (max_value - next_value <= offset) {
1527
 
        next_value = max_value;
1528
 
      } else {
1529
 
        next_value += offset;
1530
 
      }
1531
 
    }
1532
 
  } else {
1533
 
    next_value = max_value;
1534
 
  }
1535
 
 
1536
 
  ut_a(next_value <= max_value);
1537
 
 
1538
 
  return(next_value);
 
1269
        uint64_t        next_value;
 
1270
 
 
1271
        /* Should never be 0. */
 
1272
        ut_a(increment > 0);
 
1273
 
 
1274
        /* According to MySQL documentation, if the offset is greater than
 
1275
        the increment then the offset is ignored. */
 
1276
        if (offset > increment) {
 
1277
                offset = 0;
 
1278
        }
 
1279
 
 
1280
        if (max_value <= current) {
 
1281
                next_value = max_value;
 
1282
        } else if (offset <= 1) {
 
1283
                /* Offset 0 and 1 are the same, because there must be at
 
1284
                least one node in the system. */
 
1285
                if (max_value - current <= increment) {
 
1286
                        next_value = max_value;
 
1287
                } else {
 
1288
                        next_value = current + increment;
 
1289
                }
 
1290
        } else if (max_value > current) {
 
1291
                if (current > offset) {
 
1292
                        next_value = ((current - offset) / increment) + 1;
 
1293
                } else {
 
1294
                        next_value = ((offset - current) / increment) + 1;
 
1295
                }
 
1296
 
 
1297
                ut_a(increment > 0);
 
1298
                ut_a(next_value > 0);
 
1299
 
 
1300
                /* Check for multiplication overflow. */
 
1301
                if (increment > (max_value / next_value)) {
 
1302
 
 
1303
                        next_value = max_value;
 
1304
                } else {
 
1305
                        next_value *= increment;
 
1306
 
 
1307
                        ut_a(max_value >= next_value);
 
1308
 
 
1309
                        /* Check for overflow. */
 
1310
                        if (max_value - next_value <= offset) {
 
1311
                                next_value = max_value;
 
1312
                        } else {
 
1313
                                next_value += offset;
 
1314
                        }
 
1315
                }
 
1316
        } else {
 
1317
                next_value = max_value;
 
1318
        }
 
1319
 
 
1320
        ut_a(next_value <= max_value);
 
1321
 
 
1322
        return(next_value);
1539
1323
}
1540
1324
 
1541
1325
/*********************************************************************//**
1544
1328
void
1545
1329
innobase_trx_init(
1546
1330
/*==============*/
1547
 
  Session*  session,  /*!< in: user thread handle */
1548
 
  trx_t*  trx)  /*!< in/out: InnoDB transaction handle */
 
1331
        Session*        session,        /*!< in: user thread handle */
 
1332
        trx_t*  trx)    /*!< in/out: InnoDB transaction handle */
1549
1333
{
1550
 
  assert(session == trx->mysql_thd);
1551
 
 
1552
 
  trx->check_foreigns = !session_test_options(
1553
 
    session, OPTION_NO_FOREIGN_KEY_CHECKS);
1554
 
 
1555
 
  trx->check_unique_secondary = !session_test_options(
1556
 
    session, OPTION_RELAXED_UNIQUE_CHECKS);
1557
 
 
1558
 
  return;
 
1334
        assert(session == trx->mysql_thd);
 
1335
 
 
1336
        trx->check_foreigns = !session_test_options(
 
1337
                session, OPTION_NO_FOREIGN_KEY_CHECKS);
 
1338
 
 
1339
        trx->check_unique_secondary = !session_test_options(
 
1340
                session, OPTION_RELAXED_UNIQUE_CHECKS);
 
1341
 
 
1342
        return;
1559
1343
}
1560
1344
 
1561
1345
/*********************************************************************//**
1562
1346
Allocates an InnoDB transaction for a MySQL Cursor object.
1563
 
@return InnoDB transaction handle */
 
1347
@return InnoDB transaction handle */
1564
1348
extern "C" UNIV_INTERN
1565
1349
trx_t*
1566
1350
innobase_trx_allocate(
1567
1351
/*==================*/
1568
 
  Session*  session)  /*!< in: user thread handle */
 
1352
        Session*        session)        /*!< in: user thread handle */
1569
1353
{
1570
 
  trx_t*  trx;
1571
 
 
1572
 
  assert(session != NULL);
1573
 
  assert(EQ_CURRENT_SESSION(session));
1574
 
 
1575
 
  trx = trx_allocate_for_mysql();
1576
 
 
1577
 
  trx->mysql_thd = session;
1578
 
 
1579
 
  innobase_trx_init(session, trx);
1580
 
 
1581
 
  return(trx);
 
1354
        trx_t*  trx;
 
1355
 
 
1356
        assert(session != NULL);
 
1357
        assert(EQ_CURRENT_SESSION(session));
 
1358
 
 
1359
        trx = trx_allocate_for_mysql();
 
1360
 
 
1361
        trx->mysql_thd = session;
 
1362
        trx->mysql_query_str = session_query(session);
 
1363
 
 
1364
        innobase_trx_init(session, trx);
 
1365
 
 
1366
        return(trx);
1582
1367
}
1583
1368
 
1584
1369
/*********************************************************************//**
1585
1370
Gets the InnoDB transaction handle for a MySQL Cursor object, creates
1586
1371
an InnoDB transaction struct if the corresponding MySQL thread struct still
1587
1372
lacks one.
1588
 
@return InnoDB transaction handle */
 
1373
@return InnoDB transaction handle */
1589
1374
static
1590
1375
trx_t*
1591
1376
check_trx_exists(
1592
1377
/*=============*/
1593
 
  Session*  session)  /*!< in: user thread handle */
 
1378
        Session*        session)        /*!< in: user thread handle */
1594
1379
{
1595
 
  trx_t*& trx = session_to_trx(session);
1596
 
 
1597
 
  ut_ad(EQ_CURRENT_SESSION(session));
1598
 
 
1599
 
  if (trx == NULL) {
1600
 
    trx = innobase_trx_allocate(session);
1601
 
  } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
1602
 
    mem_analyze_corruption(trx);
1603
 
    ut_error;
1604
 
  }
1605
 
 
1606
 
  innobase_trx_init(session, trx);
1607
 
 
1608
 
  return(trx);
 
1380
        trx_t*& trx = session_to_trx(session);
 
1381
 
 
1382
        ut_ad(EQ_CURRENT_SESSION(session));
 
1383
 
 
1384
        if (trx == NULL) {
 
1385
                trx = innobase_trx_allocate(session);
 
1386
        } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
 
1387
                mem_analyze_corruption(trx);
 
1388
                ut_error;
 
1389
        }
 
1390
 
 
1391
        innobase_trx_init(session, trx);
 
1392
 
 
1393
        return(trx);
1609
1394
}
1610
1395
 
1611
1396
 
1613
1398
Construct ha_innobase Cursor. */
1614
1399
UNIV_INTERN
1615
1400
ha_innobase::ha_innobase(plugin::StorageEngine &engine_arg,
1616
 
                         Table &table_arg)
 
1401
                         TableShare &table_arg)
1617
1402
  :Cursor(engine_arg, table_arg),
1618
1403
  primary_key(0), /* needs initialization because index_flags() may be called 
1619
1404
                     before this is set to the real value. It's ok to have any 
1638
1423
void
1639
1424
ha_innobase::update_session(
1640
1425
/*====================*/
1641
 
  Session*  session)  /*!< in: thd to use the handle */
1642
 
{
1643
 
  trx_t*    trx;
1644
 
 
1645
 
  assert(session);
1646
 
  trx = check_trx_exists(session);
1647
 
 
1648
 
  if (prebuilt->trx != trx) {
1649
 
 
1650
 
    row_update_prebuilt_trx(prebuilt, trx);
1651
 
  }
1652
 
 
1653
 
  user_session = session;
 
1426
        Session*        session)        /*!< in: thd to use the handle */
 
1427
{
 
1428
        trx_t*          trx;
 
1429
 
 
1430
        trx = check_trx_exists(session);
 
1431
 
 
1432
        if (prebuilt->trx != trx) {
 
1433
 
 
1434
                row_update_prebuilt_trx(prebuilt, trx);
 
1435
        }
 
1436
 
 
1437
        user_session = session;
 
1438
}
 
1439
 
 
1440
/*********************************************************************//**
 
1441
Updates the user_thd field in a handle and also allocates a new InnoDB
 
1442
transaction handle if needed, and updates the transaction fields in the
 
1443
prebuilt struct. */
 
1444
UNIV_INTERN
 
1445
void
 
1446
ha_innobase::update_session()
 
1447
/*=====================*/
 
1448
{
 
1449
        Session*        session = ha_session();
 
1450
        ut_ad(EQ_CURRENT_SESSION(session));
 
1451
        update_session(session);
 
1452
}
 
1453
 
 
1454
/*********************************************************************//**
 
1455
Registers that InnoDB takes part in an SQL statement, so that MySQL knows to
 
1456
roll back the statement if the statement results in an error. This MUST be
 
1457
called for every SQL statement that may be rolled back by MySQL. Calling this
 
1458
several times to register the same statement is allowed, too. */
 
1459
static inline
 
1460
void
 
1461
innobase_register_stmt(
 
1462
/*===================*/
 
1463
        plugin::StorageEngine*  engine, /*!< in: Innobase hton */
 
1464
        Session*        session)        /*!< in: MySQL thd (connection) object */
 
1465
{
 
1466
        assert(engine == innodb_engine_ptr);
 
1467
        /* Register the statement */
 
1468
  TransactionServices &transaction_services= TransactionServices::singleton();
 
1469
        transaction_services.trans_register_ha(session, FALSE, engine);
 
1470
}
 
1471
 
 
1472
/*********************************************************************//**
 
1473
Registers an InnoDB transaction in MySQL, so that the MySQL XA code knows
 
1474
to call the InnoDB prepare and commit, or rollback for the transaction. This
 
1475
MUST be called for every transaction for which the user may call commit or
 
1476
rollback. Calling this several times to register the same transaction is
 
1477
allowed, too.
 
1478
This function also registers the current SQL statement. */
 
1479
static inline
 
1480
void
 
1481
innobase_register_trx_and_stmt(
 
1482
/*===========================*/
 
1483
        plugin::StorageEngine *engine, /*!< in: Innobase StorageEngine */
 
1484
        Session*        session)        /*!< in: MySQL thd (connection) object */
 
1485
{
 
1486
        /* NOTE that actually innobase_register_stmt() registers also
 
1487
        the transaction in the AUTOCOMMIT=1 mode. */
 
1488
 
 
1489
        innobase_register_stmt(engine, session);
 
1490
 
 
1491
        if (session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
 
1492
 
 
1493
                /* No autocommit mode, register for a transaction */
 
1494
    TransactionServices &transaction_services= TransactionServices::singleton();
 
1495
    transaction_services.trans_register_ha(session, TRUE, engine);
 
1496
        }
1654
1497
}
1655
1498
 
1656
1499
/*****************************************************************//**
1657
1500
Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
1658
1501
and quote it if needed.
1659
 
@return pointer to the end of buf */
 
1502
@return pointer to the end of buf */
1660
1503
static
1661
1504
char*
1662
1505
innobase_convert_identifier(
1663
1506
/*========================*/
1664
 
  char*   buf,  /*!< out: buffer for converted identifier */
1665
 
  ulint   buflen, /*!< in: length of buf, in bytes */
1666
 
  const char* id, /*!< in: identifier to convert */
1667
 
  ulint   idlen,  /*!< in: length of id, in bytes */
1668
 
  void*   session,/*!< in: MySQL connection thread, or NULL */
1669
 
  ibool   file_id)/*!< in: TRUE=id is a table or database name;
1670
 
        FALSE=id is an UTF-8 string */
 
1507
        char*           buf,    /*!< out: buffer for converted identifier */
 
1508
        ulint           buflen, /*!< in: length of buf, in bytes */
 
1509
        const char*     id,     /*!< in: identifier to convert */
 
1510
        ulint           idlen,  /*!< in: length of id, in bytes */
 
1511
        void*           session,/*!< in: MySQL connection thread, or NULL */
 
1512
        ibool           file_id)/*!< in: TRUE=id is a table or database name;
 
1513
                                FALSE=id is an UTF-8 string */
1671
1514
{
1672
 
  char nz[NAME_LEN + 1];
1673
 
  char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix];
1674
 
 
1675
 
  const char* s = id;
1676
 
  int   q;
1677
 
 
1678
 
  if (file_id) {
1679
 
    /* Decode the table name.  The filename_to_tablename()
1680
 
    function expects a NUL-terminated string.  The input and
1681
 
    output strings buffers must not be shared. */
1682
 
 
1683
 
    if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
1684
 
      idlen = (sizeof nz) - 1;
1685
 
    }
1686
 
 
1687
 
    memcpy(nz, id, idlen);
1688
 
    nz[idlen] = 0;
1689
 
 
1690
 
    s = nz2;
1691
 
    idlen = TableIdentifier::filename_to_tablename(nz, nz2, sizeof nz2);
1692
 
  }
1693
 
 
1694
 
  /* See if the identifier needs to be quoted. */
1695
 
  if (UNIV_UNLIKELY(!session)) {
1696
 
    q = '"';
1697
 
  } else {
1698
 
    q = get_quote_char_for_identifier();
1699
 
  }
1700
 
 
1701
 
  if (q == EOF) {
1702
 
    if (UNIV_UNLIKELY(idlen > buflen)) {
1703
 
      idlen = buflen;
1704
 
    }
1705
 
    memcpy(buf, s, idlen);
1706
 
    return(buf + idlen);
1707
 
  }
1708
 
 
1709
 
  /* Quote the identifier. */
1710
 
  if (buflen < 2) {
1711
 
    return(buf);
1712
 
  }
1713
 
 
1714
 
  *buf++ = q;
1715
 
  buflen--;
1716
 
 
1717
 
  for (; idlen; idlen--) {
1718
 
    int c = *s++;
1719
 
    if (UNIV_UNLIKELY(c == q)) {
1720
 
      if (UNIV_UNLIKELY(buflen < 3)) {
1721
 
        break;
1722
 
      }
1723
 
 
1724
 
      *buf++ = c;
1725
 
      *buf++ = c;
1726
 
      buflen -= 2;
1727
 
    } else {
1728
 
      if (UNIV_UNLIKELY(buflen < 2)) {
1729
 
        break;
1730
 
      }
1731
 
 
1732
 
      *buf++ = c;
1733
 
      buflen--;
1734
 
    }
1735
 
  }
1736
 
 
1737
 
  *buf++ = q;
1738
 
  return(buf);
 
1515
        char nz[NAME_LEN + 1];
 
1516
        char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix];
 
1517
 
 
1518
        const char*     s       = id;
 
1519
        int             q;
 
1520
 
 
1521
        if (file_id) {
 
1522
                /* Decode the table name.  The filename_to_tablename()
 
1523
                function expects a NUL-terminated string.  The input and
 
1524
                output strings buffers must not be shared. */
 
1525
 
 
1526
                if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
 
1527
                        idlen = (sizeof nz) - 1;
 
1528
                }
 
1529
 
 
1530
                memcpy(nz, id, idlen);
 
1531
                nz[idlen] = 0;
 
1532
 
 
1533
                s = nz2;
 
1534
                idlen = filename_to_tablename(nz, nz2, sizeof nz2);
 
1535
        }
 
1536
 
 
1537
        /* See if the identifier needs to be quoted. */
 
1538
        if (UNIV_UNLIKELY(!session)) {
 
1539
                q = '"';
 
1540
        } else {
 
1541
                q = get_quote_char_for_identifier();
 
1542
        }
 
1543
 
 
1544
        if (q == EOF) {
 
1545
                if (UNIV_UNLIKELY(idlen > buflen)) {
 
1546
                        idlen = buflen;
 
1547
                }
 
1548
                memcpy(buf, s, idlen);
 
1549
                return(buf + idlen);
 
1550
        }
 
1551
 
 
1552
        /* Quote the identifier. */
 
1553
        if (buflen < 2) {
 
1554
                return(buf);
 
1555
        }
 
1556
 
 
1557
        *buf++ = q;
 
1558
        buflen--;
 
1559
 
 
1560
        for (; idlen; idlen--) {
 
1561
                int     c = *s++;
 
1562
                if (UNIV_UNLIKELY(c == q)) {
 
1563
                        if (UNIV_UNLIKELY(buflen < 3)) {
 
1564
                                break;
 
1565
                        }
 
1566
 
 
1567
                        *buf++ = c;
 
1568
                        *buf++ = c;
 
1569
                        buflen -= 2;
 
1570
                } else {
 
1571
                        if (UNIV_UNLIKELY(buflen < 2)) {
 
1572
                                break;
 
1573
                        }
 
1574
 
 
1575
                        *buf++ = c;
 
1576
                        buflen--;
 
1577
                }
 
1578
        }
 
1579
 
 
1580
        *buf++ = q;
 
1581
        return(buf);
1739
1582
}
1740
1583
 
1741
1584
/*****************************************************************//**
1742
1585
Convert a table or index name to the MySQL system_charset_info (UTF-8)
1743
1586
and quote it if needed.
1744
 
@return pointer to the end of buf */
 
1587
@return pointer to the end of buf */
1745
1588
extern "C" UNIV_INTERN
1746
1589
char*
1747
1590
innobase_convert_name(
1748
1591
/*==================*/
1749
 
  char*   buf,  /*!< out: buffer for converted identifier */
1750
 
  ulint   buflen, /*!< in: length of buf, in bytes */
1751
 
  const char* id, /*!< in: identifier to convert */
1752
 
  ulint   idlen,  /*!< in: length of id, in bytes */
1753
 
  void*   session,/*!< in: MySQL connection thread, or NULL */
1754
 
  ibool   table_id)/*!< in: TRUE=id is a table or database name;
1755
 
        FALSE=id is an index name */
 
1592
        char*           buf,    /*!< out: buffer for converted identifier */
 
1593
        ulint           buflen, /*!< in: length of buf, in bytes */
 
1594
        const char*     id,     /*!< in: identifier to convert */
 
1595
        ulint           idlen,  /*!< in: length of id, in bytes */
 
1596
        void*           session,/*!< in: MySQL connection thread, or NULL */
 
1597
        ibool           table_id)/*!< in: TRUE=id is a table or database name;
 
1598
                                FALSE=id is an index name */
1756
1599
{
1757
 
  char*   s = buf;
1758
 
  const char* bufend  = buf + buflen;
1759
 
 
1760
 
  if (table_id) {
1761
 
    const char* slash = (const char*) memchr(id, '/', idlen);
1762
 
    if (!slash) {
1763
 
 
1764
 
      goto no_db_name;
1765
 
    }
1766
 
 
1767
 
    /* Print the database name and table name separately. */
1768
 
    s = innobase_convert_identifier(s, bufend - s, id, slash - id,
1769
 
            session, TRUE);
1770
 
    if (UNIV_LIKELY(s < bufend)) {
1771
 
      *s++ = '.';
1772
 
      s = innobase_convert_identifier(s, bufend - s,
1773
 
              slash + 1, idlen
1774
 
              - (slash - id) - 1,
1775
 
              session, TRUE);
1776
 
    }
1777
 
  } else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
1778
 
    /* Temporary index name (smart ALTER TABLE) */
1779
 
    const char temp_index_suffix[]= "--temporary--";
1780
 
 
1781
 
    s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
1782
 
            session, FALSE);
1783
 
    if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
1784
 
      memcpy(s, temp_index_suffix,
1785
 
             sizeof temp_index_suffix - 1);
1786
 
      s += sizeof temp_index_suffix - 1;
1787
 
    }
1788
 
  } else {
 
1600
        char*           s       = buf;
 
1601
        const char*     bufend  = buf + buflen;
 
1602
 
 
1603
        if (table_id) {
 
1604
                const char*     slash = (const char*) memchr(id, '/', idlen);
 
1605
                if (!slash) {
 
1606
 
 
1607
                        goto no_db_name;
 
1608
                }
 
1609
 
 
1610
                /* Print the database name and table name separately. */
 
1611
                s = innobase_convert_identifier(s, bufend - s, id, slash - id,
 
1612
                                                session, TRUE);
 
1613
                if (UNIV_LIKELY(s < bufend)) {
 
1614
                        *s++ = '.';
 
1615
                        s = innobase_convert_identifier(s, bufend - s,
 
1616
                                                        slash + 1, idlen
 
1617
                                                        - (slash - id) - 1,
 
1618
                                                        session, TRUE);
 
1619
                }
 
1620
        } else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
 
1621
                /* Temporary index name (smart ALTER TABLE) */
 
1622
                const char temp_index_suffix[]= "--temporary--";
 
1623
 
 
1624
                s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
 
1625
                                                session, FALSE);
 
1626
                if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
 
1627
                        memcpy(s, temp_index_suffix,
 
1628
                               sizeof temp_index_suffix - 1);
 
1629
                        s += sizeof temp_index_suffix - 1;
 
1630
                }
 
1631
        } else {
1789
1632
no_db_name:
1790
 
    s = innobase_convert_identifier(buf, buflen, id, idlen,
1791
 
            session, table_id);
1792
 
  }
 
1633
                s = innobase_convert_identifier(buf, buflen, id, idlen,
 
1634
                                                session, table_id);
 
1635
        }
1793
1636
 
1794
 
  return(s);
 
1637
        return(s);
1795
1638
 
1796
1639
}
1797
1640
 
1798
1641
/**********************************************************************//**
1799
1642
Determines if the currently running transaction has been interrupted.
1800
 
@return TRUE if interrupted */
 
1643
@return TRUE if interrupted */
1801
1644
extern "C" UNIV_INTERN
1802
1645
ibool
1803
1646
trx_is_interrupted(
1804
1647
/*===============*/
1805
 
  trx_t*  trx)  /*!< in: transaction */
1806
 
{
1807
 
  return(trx && trx->mysql_thd && static_cast<Session*>(trx->mysql_thd)->getKilled());
1808
 
}
1809
 
 
1810
 
/**********************************************************************//**
1811
 
Determines if the currently running transaction is in strict mode.
1812
 
@return TRUE if strict */
1813
 
extern "C" UNIV_INTERN
1814
 
ibool
1815
 
trx_is_strict(
1816
 
/*==========*/
1817
1648
        trx_t*  trx)    /*!< in: transaction */
1818
1649
{
1819
 
        return(trx && trx->mysql_thd
1820
 
               && true);
 
1650
        return(trx && trx->mysql_thd && session_killed((Session*) trx->mysql_thd));
1821
1651
}
1822
1652
 
1823
1653
/**************************************************************//**
1827
1657
void
1828
1658
reset_template(
1829
1659
/*===========*/
1830
 
  row_prebuilt_t* prebuilt) /*!< in/out: prebuilt struct */
1831
 
{
1832
 
  prebuilt->keep_other_fields_on_keyread = 0;
1833
 
  prebuilt->read_just_key = 0;
1834
 
}
1835
 
 
1836
 
template<class T>
1837
 
void align_value(T& value, size_t align_val= 1024)
1838
 
{
1839
 
  value= value - (value % align_val);
1840
 
}
1841
 
 
1842
 
static void auto_extend_update(Session *, sql_var_t)
1843
 
{
1844
 
  srv_auto_extend_increment= innodb_auto_extend_increment.get();
1845
 
}
1846
 
 
1847
 
static void io_capacity_update(Session *, sql_var_t)
1848
 
{
1849
 
  srv_io_capacity= innodb_io_capacity.get();
1850
 
}
1851
 
 
1852
 
static void purge_batch_update(Session *, sql_var_t)
1853
 
{
1854
 
  srv_purge_batch_size= innodb_purge_batch_size.get();
1855
 
}
1856
 
 
1857
 
static void purge_threads_update(Session *, sql_var_t)
1858
 
{
1859
 
  srv_n_purge_threads= innodb_n_purge_threads.get();
1860
 
}
1861
 
 
1862
 
static void innodb_adaptive_hash_index_update(Session *, sql_var_t)
1863
 
{
1864
 
  if (btr_search_enabled)
1865
 
  {
1866
 
    btr_search_enable();
1867
 
  } else {
1868
 
    btr_search_disable();
1869
 
  }
1870
 
}
1871
 
 
1872
 
static void innodb_old_blocks_pct_update(Session *, sql_var_t)
1873
 
{
1874
 
  innobase_old_blocks_pct= buf_LRU_old_ratio_update(innobase_old_blocks_pct.get(), TRUE);
1875
 
}
1876
 
 
1877
 
static void innodb_thread_concurrency_update(Session *, sql_var_t)
1878
 
{
1879
 
  srv_thread_concurrency= innobase_thread_concurrency.get();
1880
 
}
1881
 
 
1882
 
static void innodb_sync_spin_loops_update(Session *, sql_var_t)
1883
 
{
1884
 
  srv_n_spin_wait_rounds= innodb_sync_spin_loops.get();
1885
 
}
1886
 
 
1887
 
static void innodb_spin_wait_delay_update(Session *, sql_var_t)
1888
 
{
1889
 
  srv_spin_wait_delay= innodb_spin_wait_delay.get();
1890
 
}
1891
 
 
1892
 
static void innodb_thread_sleep_delay_update(Session *, sql_var_t)
1893
 
{
1894
 
  srv_thread_sleep_delay= innodb_thread_sleep_delay.get();
1895
 
}
1896
 
 
1897
 
static void innodb_read_ahead_threshold_update(Session *, sql_var_t)
1898
 
{
1899
 
  srv_read_ahead_threshold= innodb_read_ahead_threshold.get();
1900
 
}
1901
 
 
1902
 
 
1903
 
static int innodb_commit_concurrency_validate(Session *session, set_var *var)
1904
 
{
1905
 
   uint32_t new_value= var->save_result.uint32_t_value;
1906
 
 
1907
 
   if ((innobase_commit_concurrency.get() == 0 && new_value != 0) ||
1908
 
       (innobase_commit_concurrency.get() != 0 && new_value == 0))
1909
 
   {
1910
 
     push_warning_printf(session,
1911
 
                         DRIZZLE_ERROR::WARN_LEVEL_WARN,
1912
 
                         ER_WRONG_ARGUMENTS,
1913
 
                         _("Once InnoDB is running, innodb_commit_concurrency "
1914
 
                           "must not change between zero and nonzero."));
1915
 
     return 1;
1916
 
   }
1917
 
   return 0;
1918
 
}
1919
 
 
1920
 
/*************************************************************//**
1921
 
Check if it is a valid file format. This function is registered as
1922
 
a callback with MySQL.
1923
 
@return 0 for valid file format */
1924
 
static
1925
 
int
1926
 
innodb_file_format_name_validate(
1927
 
/*=============================*/
1928
 
  Session*      , /*!< in: thread handle */
1929
 
  set_var *var)
1930
 
{
1931
 
  const char *file_format_input = var->value->str_value.ptr();
1932
 
  if (file_format_input == NULL)
1933
 
    return 1;
1934
 
 
1935
 
  if (file_format_input != NULL) {
1936
 
    uint  format_id;
1937
 
 
1938
 
    format_id = innobase_file_format_name_lookup(
1939
 
      file_format_input);
1940
 
 
1941
 
    if (format_id <= DICT_TF_FORMAT_MAX) {
1942
 
      innobase_file_format_name =
1943
 
        trx_sys_file_format_id_to_name(format_id);
1944
 
 
1945
 
      return(0);
1946
 
    }
1947
 
  }
1948
 
 
1949
 
  return(1);
1950
 
}
1951
 
 
1952
 
/*************************************************************//**
1953
 
Check if it is a valid value of innodb_change_buffering. This function is
1954
 
registered as a callback with MySQL.
1955
 
@return 0 for valid innodb_change_buffering */
1956
 
static
1957
 
int
1958
 
innodb_change_buffering_validate(
1959
 
/*=============================*/
1960
 
  Session*      , /*!< in: thread handle */
1961
 
  set_var *var)
1962
 
{
1963
 
  const char *change_buffering_input = var->value->str_value.ptr();
1964
 
 
1965
 
  if (change_buffering_input == NULL)
1966
 
    return 1;
1967
 
 
1968
 
  ulint use;
1969
 
 
1970
 
  for (use = 0;
1971
 
       use < UT_ARR_SIZE(innobase_change_buffering_values);
1972
 
       ++use) {
1973
 
    if (!innobase_strcasecmp(change_buffering_input,
1974
 
                             innobase_change_buffering_values[use]))
1975
 
    {
1976
 
      ibuf_use= static_cast<ibuf_use_t>(use); 
1977
 
      return 0;
1978
 
    }
1979
 
  }
1980
 
 
1981
 
  return 1;
1982
 
}
1983
 
 
1984
 
 
1985
 
/*************************************************************//**
1986
 
Check if valid argument to innodb_file_format_max. This function
1987
 
is registered as a callback with MySQL.
1988
 
@return 0 for valid file format */
1989
 
static
1990
 
int
1991
 
innodb_file_format_max_validate(
1992
 
/*==============================*/
1993
 
  Session*   session, /*!< in: thread handle */
1994
 
  set_var *var)
1995
 
{
1996
 
  const char *file_format_input = var->value->str_value.ptr();
1997
 
  if (file_format_input == NULL)
1998
 
    return 1;
1999
 
 
2000
 
  if (file_format_input != NULL) {
2001
 
    int format_id = innobase_file_format_validate_and_set(file_format_input);
2002
 
 
2003
 
    if (format_id > DICT_TF_FORMAT_MAX) {
2004
 
      /* DEFAULT is "on", which is invalid at runtime. */
2005
 
      return 1;
2006
 
    }
2007
 
 
2008
 
    if (format_id >= 0) {
2009
 
      innobase_file_format_max= 
2010
 
        trx_sys_file_format_id_to_name((uint)format_id);
2011
 
 
2012
 
      /* Update the max format id in the system tablespace. */
2013
 
      char name_buff[100];
2014
 
      strcpy(name_buff, innobase_file_format_max.c_str());
2015
 
      if (trx_sys_file_format_max_set(format_id, (const char **)&name_buff))
2016
 
      {
2017
 
        errmsg_printf(ERRMSG_LVL_WARN,
2018
 
                      " [Info] InnoDB: the file format in the system "
2019
 
                      "tablespace is now set to %s.\n", name_buff);
2020
 
        innobase_file_format_max= name_buff;
2021
 
      }
2022
 
      return(0);
2023
 
 
2024
 
    } else {
2025
 
      push_warning_printf(session,
2026
 
                          DRIZZLE_ERROR::WARN_LEVEL_WARN,
2027
 
                          ER_WRONG_ARGUMENTS,
2028
 
                          "InnoDB: invalid innodb_file_format_max "
2029
 
                          "value; can be any format up to %s "
2030
 
                          "or equivalent id of %d",
2031
 
                          trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX),
2032
 
                          DICT_TF_FORMAT_MAX);
2033
 
    }
2034
 
  }
2035
 
 
2036
 
  return(1);
2037
 
}
2038
 
 
 
1660
        row_prebuilt_t* prebuilt)       /*!< in/out: prebuilt struct */
 
1661
{
 
1662
        prebuilt->keep_other_fields_on_keyread = 0;
 
1663
        prebuilt->read_just_key = 0;
 
1664
}
 
1665
 
 
1666
/*****************************************************************//**
 
1667
Call this when you have opened a new table handle in HANDLER, before you
 
1668
call index_read_idx() etc. Actually, we can let the cursor stay open even
 
1669
over a transaction commit! Then you should call this before every operation,
 
1670
fetch next etc. This function inits the necessary things even after a
 
1671
transaction commit. */
 
1672
UNIV_INTERN
 
1673
void
 
1674
ha_innobase::init_table_handle_for_HANDLER(void)
 
1675
/*============================================*/
 
1676
{
 
1677
        /* If current session does not yet have a trx struct, create one.
 
1678
        If the current handle does not yet have a prebuilt struct, create
 
1679
        one. Update the trx pointers in the prebuilt struct. Normally
 
1680
        this operation is done in external_lock. */
 
1681
 
 
1682
        update_session(ha_session());
 
1683
 
 
1684
        /* Initialize the prebuilt struct much like it would be inited in
 
1685
        external_lock */
 
1686
 
 
1687
        innobase_release_stat_resources(prebuilt->trx);
 
1688
 
 
1689
        /* If the transaction is not started yet, start it */
 
1690
 
 
1691
        trx_start_if_not_started(prebuilt->trx);
 
1692
 
 
1693
        /* Assign a read view if the transaction does not have it yet */
 
1694
 
 
1695
        trx_assign_read_view(prebuilt->trx);
 
1696
 
 
1697
        /* Set the MySQL flag to mark that there is an active transaction */
 
1698
 
 
1699
        if (prebuilt->trx->active_trans == 0) {
 
1700
 
 
1701
                innobase_register_trx_and_stmt(engine, user_session);
 
1702
 
 
1703
                prebuilt->trx->active_trans = 1;
 
1704
        }
 
1705
 
 
1706
        /* We did the necessary inits in this function, no need to repeat them
 
1707
        in row_search_for_mysql */
 
1708
 
 
1709
        prebuilt->sql_stat_start = FALSE;
 
1710
 
 
1711
        /* We let HANDLER always to do the reads as consistent reads, even
 
1712
        if the trx isolation level would have been specified as SERIALIZABLE */
 
1713
 
 
1714
        prebuilt->select_lock_type = LOCK_NONE;
 
1715
        prebuilt->stored_select_lock_type = LOCK_NONE;
 
1716
 
 
1717
        /* Always fetch all columns in the index record */
 
1718
 
 
1719
        prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS;
 
1720
 
 
1721
        /* We want always to fetch all columns in the whole row? Or do
 
1722
        we???? */
 
1723
 
 
1724
        prebuilt->used_in_HANDLER = TRUE;
 
1725
        reset_template(prebuilt);
 
1726
}
2039
1727
 
2040
1728
/*********************************************************************//**
2041
1729
Opens an InnoDB database.
2042
 
@return 0 on success, error code on failure */
 
1730
@return 0 on success, error code on failure */
2043
1731
static
2044
1732
int
2045
1733
innobase_init(
2046
1734
/*==========*/
2047
 
  module::Context &context) /*!< in: Drizzle Plugin Context */
 
1735
        plugin::Registry        &registry)      /*!< in: Drizzle Plugin Registry */
2048
1736
{
2049
 
  int   err;
2050
 
  bool    ret;
2051
 
  uint    format_id;
2052
 
  InnobaseEngine *actuall_engine_ptr;
2053
 
  const module::option_map &vm= context.getOptions();
2054
 
 
2055
 
  srv_auto_extend_increment= innodb_auto_extend_increment.get();
2056
 
  srv_io_capacity= innodb_io_capacity.get();
2057
 
  srv_purge_batch_size= innodb_purge_batch_size.get();
2058
 
  srv_n_purge_threads= innodb_n_purge_threads.get();
2059
 
  srv_flush_log_at_trx_commit= innodb_flush_log_at_trx_commit.get();
2060
 
  srv_max_buf_pool_modified_pct= innodb_max_dirty_pages_pct.get();
2061
 
  srv_max_purge_lag= innodb_max_purge_lag.get();
2062
 
  srv_stats_sample_pages= innodb_stats_sample_pages.get();
2063
 
  srv_n_free_tickets_to_enter= innodb_concurrency_tickets.get();
2064
 
  srv_replication_delay= innodb_replication_delay.get();
2065
 
  srv_thread_concurrency= innobase_thread_concurrency.get();
2066
 
  srv_n_spin_wait_rounds= innodb_sync_spin_loops.get();
2067
 
  srv_spin_wait_delay= innodb_spin_wait_delay.get();
2068
 
  srv_thread_sleep_delay= innodb_thread_sleep_delay.get();
2069
 
  srv_read_ahead_threshold= innodb_read_ahead_threshold.get();
2070
 
 
2071
 
  /* Inverted Booleans */
2072
 
 
2073
 
  innobase_use_checksums= (vm.count("disable-checksums")) ? false : true;
2074
 
  innobase_use_doublewrite= (vm.count("disable-doublewrite")) ? false : true;
2075
 
  srv_adaptive_flushing= (vm.count("disable-adaptive-flushing")) ? false : true;
2076
 
  srv_use_sys_malloc= (vm.count("use-internal-malloc")) ? false : true;
2077
 
  support_xa= (vm.count("disable-xa")) ? false : true;
2078
 
  btr_search_enabled= (vm.count("disable-adaptive-hash-index")) ? false : true;
2079
 
 
2080
 
 
2081
 
  /* Hafta do this here because we need to late-bind the default value */
2082
 
  if (vm.count("data-home-dir"))
2083
 
  {
2084
 
    innobase_data_home_dir= vm["data-home-dir"].as<string>();
2085
 
  }
2086
 
  else
2087
 
  {
2088
 
    innobase_data_home_dir= getDataHome().file_string();
2089
 
  }
2090
 
 
2091
 
 
2092
 
  if (vm.count("data-file-path"))
2093
 
  {
2094
 
    innobase_data_file_path= vm["data-file-path"].as<string>();
2095
 
  }
2096
 
 
2097
 
 
2098
 
  innodb_engine_ptr= actuall_engine_ptr= new InnobaseEngine(innobase_engine_name);
2099
 
 
2100
 
  ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)DRIZZLE_TYPE_VARCHAR);
 
1737
        static char     current_dir[3];         /*!< Set if using current lib */
 
1738
        int             err;
 
1739
        bool            ret;
 
1740
        char            *default_path;
 
1741
        uint            format_id;
 
1742
 
 
1743
        innodb_engine_ptr= new InnobaseEngine(innobase_engine_name);
 
1744
 
 
1745
 
 
1746
        ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)DRIZZLE_TYPE_VARCHAR);
2101
1747
 
2102
1748
#ifdef UNIV_DEBUG
2103
 
  static const char test_filename[] = "-@";
2104
 
  char      test_tablename[sizeof test_filename
2105
 
    + sizeof srv_mysql50_table_name_prefix];
2106
 
  if ((sizeof test_tablename) - 1
2107
 
      != filename_to_tablename(test_filename, test_tablename,
2108
 
                               sizeof test_tablename)
2109
 
      || strncmp(test_tablename,
2110
 
                 srv_mysql50_table_name_prefix,
2111
 
                 sizeof srv_mysql50_table_name_prefix)
2112
 
      || strcmp(test_tablename
2113
 
                + sizeof srv_mysql50_table_name_prefix,
2114
 
                test_filename)) {
2115
 
    errmsg_printf(ERRMSG_LVL_ERROR, "tablename encoding has been changed");
2116
 
    goto error;
2117
 
  }
 
1749
        static const char       test_filename[] = "-@";
 
1750
        char                    test_tablename[sizeof test_filename
 
1751
                                + sizeof srv_mysql50_table_name_prefix];
 
1752
        if ((sizeof test_tablename) - 1
 
1753
                        != filename_to_tablename(test_filename, test_tablename,
 
1754
                        sizeof test_tablename)
 
1755
                        || strncmp(test_tablename,
 
1756
                        srv_mysql50_table_name_prefix,
 
1757
                        sizeof srv_mysql50_table_name_prefix)
 
1758
                        || strcmp(test_tablename
 
1759
                        + sizeof srv_mysql50_table_name_prefix,
 
1760
                        test_filename)) {
 
1761
                errmsg_printf(ERRMSG_LVL_ERROR, "tablename encoding has been changed");
 
1762
                goto error;
 
1763
        }
2118
1764
#endif /* UNIV_DEBUG */
2119
1765
 
2120
 
  os_innodb_umask = (ulint)internal::my_umask;
2121
 
 
2122
 
 
2123
 
  /* Set InnoDB initialization parameters according to the values
2124
 
    read from MySQL .cnf file */
2125
 
 
2126
 
  /*--------------- Data files -------------------------*/
2127
 
 
2128
 
  /* The default dir for data files is the datadir of MySQL */
2129
 
 
2130
 
  srv_data_home = (char *)innobase_data_home_dir.c_str();
2131
 
 
2132
 
  /* Set default InnoDB data file size to 10 MB and let it be
2133
 
    auto-extending. Thus users can use InnoDB in >= 4.0 without having
2134
 
    to specify any startup options. */
2135
 
 
2136
 
  if (innobase_data_file_path.empty()) 
2137
 
  {
2138
 
    innobase_data_file_path= std::string("ibdata1:10M:autoextend");
2139
 
  }
2140
 
 
2141
 
  /* Since InnoDB edits the argument in the next call, we make another
2142
 
    copy of it: */
2143
 
 
2144
 
  internal_innobase_data_file_path = strdup(innobase_data_file_path.c_str());
2145
 
 
2146
 
  ret = (bool) srv_parse_data_file_paths_and_sizes(
2147
 
                                                   internal_innobase_data_file_path);
2148
 
  if (ret == FALSE) {
2149
 
    errmsg_printf(ERRMSG_LVL_ERROR, 
2150
 
                  "InnoDB: syntax error in innodb_data_file_path");
 
1766
        /* Check that values don't overflow on 32-bit systems. */
 
1767
        if (sizeof(ulint) == 4) {
 
1768
                if (innobase_buffer_pool_size > UINT32_MAX) {
 
1769
                        errmsg_printf(ERRMSG_LVL_ERROR, 
 
1770
                                "innobase_buffer_pool_size can't be over 4GB"
 
1771
                                " on 32-bit systems");
 
1772
 
 
1773
                        goto error;
 
1774
                }
 
1775
 
 
1776
                if (innobase_log_file_size > UINT32_MAX) {
 
1777
                        errmsg_printf(ERRMSG_LVL_ERROR, 
 
1778
                                "innobase_log_file_size can't be over 4GB"
 
1779
                                " on 32-bit systems");
 
1780
 
 
1781
                        goto error;
 
1782
                }
 
1783
        }
 
1784
 
 
1785
        os_innodb_umask = (ulint)internal::my_umask;
 
1786
 
 
1787
        /* First calculate the default path for innodb_data_home_dir etc.,
 
1788
        in case the user has not given any value.
 
1789
 
 
1790
        Note that when using the embedded server, the datadirectory is not
 
1791
        necessarily the current directory of this program. */
 
1792
 
 
1793
        /* It's better to use current lib, to keep paths short */
 
1794
        current_dir[0] = FN_CURLIB;
 
1795
        current_dir[1] = FN_LIBCHAR;
 
1796
        current_dir[2] = 0;
 
1797
        default_path = current_dir;
 
1798
 
 
1799
        ut_a(default_path);
 
1800
 
 
1801
        srv_set_thread_priorities = TRUE;
 
1802
        srv_query_thread_priority = QUERY_PRIOR;
 
1803
 
 
1804
        /* Set InnoDB initialization parameters according to the values
 
1805
        read from MySQL .cnf file */
 
1806
 
 
1807
        /*--------------- Data files -------------------------*/
 
1808
 
 
1809
        /* The default dir for data files is the datadir of MySQL */
 
1810
 
 
1811
        srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
 
1812
                         default_path);
 
1813
 
 
1814
        /* Set default InnoDB data file size to 10 MB and let it be
 
1815
        auto-extending. Thus users can use InnoDB in >= 4.0 without having
 
1816
        to specify any startup options. */
 
1817
 
 
1818
        if (!innobase_data_file_path) {
 
1819
                innobase_data_file_path = (char*) "ibdata1:10M:autoextend";
 
1820
        }
 
1821
 
 
1822
        /* Since InnoDB edits the argument in the next call, we make another
 
1823
        copy of it: */
 
1824
 
 
1825
        internal_innobase_data_file_path = strdup(innobase_data_file_path);
 
1826
 
 
1827
        ret = (bool) srv_parse_data_file_paths_and_sizes(
 
1828
                internal_innobase_data_file_path);
 
1829
        if (ret == FALSE) {
 
1830
                errmsg_printf(ERRMSG_LVL_ERROR, 
 
1831
                        "InnoDB: syntax error in innodb_data_file_path");
2151
1832
mem_free_and_error:
2152
 
    srv_free_paths_and_sizes();
2153
 
    if (internal_innobase_data_file_path)
2154
 
      free(internal_innobase_data_file_path);
2155
 
    goto error;
2156
 
  }
2157
 
 
2158
 
  /* -------------- Log files ---------------------------*/
2159
 
 
2160
 
  /* The default dir for log files is the datadir of MySQL */
2161
 
 
2162
 
  if (vm.count("log-group-home-dir"))
2163
 
  {
2164
 
    innobase_log_group_home_dir= vm["log-group-home-dir"].as<string>();
2165
 
  }
2166
 
  else
2167
 
  {
2168
 
    innobase_log_group_home_dir= getDataHome().file_string();
2169
 
  }
2170
 
 
2171
 
  ret = (bool)
2172
 
    srv_parse_log_group_home_dirs((char *)innobase_log_group_home_dir.c_str());
2173
 
 
2174
 
  if (ret == FALSE || innobase_mirrored_log_groups.get() != 1) {
2175
 
    errmsg_printf(ERRMSG_LVL_ERROR,
2176
 
                  _("syntax error in innodb_log_group_home_dir, or a "
2177
 
                  "wrong number of mirrored log groups"));
2178
 
 
2179
 
    goto mem_free_and_error;
2180
 
  }
2181
 
 
2182
 
 
2183
 
  /* Validate the file format by animal name */
2184
 
  if (vm.count("file-format"))
2185
 
  {
2186
 
    format_id = innobase_file_format_name_lookup(
2187
 
                                                 vm["file-format"].as<string>().c_str());
2188
 
 
2189
 
    if (format_id > DICT_TF_FORMAT_MAX) {
2190
 
 
2191
 
      errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: wrong innodb_file_format.");
2192
 
 
2193
 
      goto mem_free_and_error;
2194
 
    }
2195
 
  } else {
2196
 
    /* Set it to the default file format id.*/
2197
 
    format_id = 0;
2198
 
  }
2199
 
 
2200
 
  srv_file_format = format_id;
2201
 
 
2202
 
  innobase_file_format_name =
2203
 
    trx_sys_file_format_id_to_name(format_id);
2204
 
 
2205
 
  /* Check innobase_file_format_check variable */
2206
 
  if (!innobase_file_format_check)
2207
 
  {
2208
 
    /* Set the value to disable checking. */
2209
 
    srv_max_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
2210
 
  } else {
2211
 
    /* Set the value to the lowest supported format. */
2212
 
    srv_max_file_format_at_startup = DICT_TF_FORMAT_MIN;
2213
 
  }
2214
 
 
2215
 
  /* Did the user specify a format name that we support?
2216
 
     As a side effect it will update the variable
2217
 
     srv_max_file_format_at_startup */
2218
 
  if (innobase_file_format_validate_and_set(innobase_file_format_max.c_str()) < 0)
2219
 
  {
2220
 
    errmsg_printf(ERRMSG_LVL_ERROR, _("InnoDB: invalid "
2221
 
                    "innodb_file_format_max value: "
2222
 
                    "should be any value up to %s or its "
2223
 
                    "equivalent numeric id"),
2224
 
                    trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX));
2225
 
    goto mem_free_and_error;
2226
 
  }
2227
 
 
2228
 
  if (vm.count("change-buffering"))
2229
 
  {
2230
 
    ulint use;
2231
 
 
2232
 
    for (use = 0;
2233
 
         use < UT_ARR_SIZE(innobase_change_buffering_values);
2234
 
         use++) {
2235
 
      if (!innobase_strcasecmp(
2236
 
                               innobase_change_buffering.c_str(),
2237
 
                               innobase_change_buffering_values[use])) {
2238
 
        ibuf_use = static_cast<ibuf_use_t>(use);
2239
 
        goto innobase_change_buffering_inited_ok;
2240
 
      }
2241
 
    }
2242
 
 
2243
 
    errmsg_printf(ERRMSG_LVL_ERROR,
2244
 
                  "InnoDB: invalid value "
2245
 
                  "innodb_change_buffering=%s",
2246
 
                  vm["change-buffering"].as<string>().c_str());
2247
 
    goto mem_free_and_error;
2248
 
  }
 
1833
                srv_free_paths_and_sizes();
 
1834
                if (internal_innobase_data_file_path)
 
1835
                  free(internal_innobase_data_file_path);
 
1836
                goto error;
 
1837
        }
 
1838
 
 
1839
        /* -------------- Log files ---------------------------*/
 
1840
 
 
1841
        /* The default dir for log files is the datadir of MySQL */
 
1842
 
 
1843
        if (!innobase_log_group_home_dir) {
 
1844
                innobase_log_group_home_dir = default_path;
 
1845
        }
 
1846
 
 
1847
#ifdef UNIV_LOG_ARCHIVE
 
1848
        /* Since innodb_log_arch_dir has no relevance under MySQL,
 
1849
        starting from 4.0.6 we always set it the same as
 
1850
        innodb_log_group_home_dir: */
 
1851
 
 
1852
        innobase_log_arch_dir = innobase_log_group_home_dir;
 
1853
 
 
1854
        srv_arch_dir = innobase_log_arch_dir;
 
1855
#endif /* UNIG_LOG_ARCHIVE */
 
1856
 
 
1857
        ret = (bool)
 
1858
                srv_parse_log_group_home_dirs(innobase_log_group_home_dir);
 
1859
 
 
1860
        if (ret == FALSE || innobase_mirrored_log_groups != 1) {
 
1861
          errmsg_printf(ERRMSG_LVL_ERROR, "syntax error in innodb_log_group_home_dir, or a "
 
1862
                          "wrong number of mirrored log groups");
 
1863
 
 
1864
                goto mem_free_and_error;
 
1865
        }
 
1866
 
 
1867
        /* Validate the file format by animal name */
 
1868
        if (innobase_file_format_name != NULL) {
 
1869
 
 
1870
                format_id = innobase_file_format_name_lookup(
 
1871
                        innobase_file_format_name);
 
1872
 
 
1873
                if (format_id > DICT_TF_FORMAT_MAX) {
 
1874
 
 
1875
                        errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: wrong innodb_file_format.");
 
1876
 
 
1877
                        goto mem_free_and_error;
 
1878
                }
 
1879
        } else {
 
1880
                /* Set it to the default file format id. Though this
 
1881
                should never happen. */
 
1882
                format_id = 0;
 
1883
        }
 
1884
 
 
1885
        srv_file_format = format_id;
 
1886
 
 
1887
        /* Given the type of innobase_file_format_name we have little
 
1888
        choice but to cast away the constness from the returned name.
 
1889
        innobase_file_format_name is used in the MySQL set variable
 
1890
        interface and so can't be const. */
 
1891
 
 
1892
        innobase_file_format_name = 
 
1893
                (char*) trx_sys_file_format_id_to_name(format_id);
 
1894
 
 
1895
        /* Process innobase_file_format_check variable */
 
1896
        ut_a(innobase_file_format_check != NULL);
 
1897
 
 
1898
        /* As a side effect it will set srv_check_file_format_at_startup
 
1899
        on valid input. First we check for "on"/"off". */
 
1900
        if (!innobase_file_format_check_on_off(innobase_file_format_check)) {
 
1901
 
 
1902
                /* Did the user specify a format name that we support ?
 
1903
                As a side effect it will update the variable
 
1904
                srv_check_file_format_at_startup */
 
1905
                if (!innobase_file_format_check_validate(
 
1906
                        innobase_file_format_check)) {
 
1907
 
 
1908
                        errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: invalid "
 
1909
                                        "innodb_file_format_check value: "
 
1910
                                        "should be either 'on' or 'off' or "
 
1911
                                        "any value up to %s or its "
 
1912
                                        "equivalent numeric id",
 
1913
                                        trx_sys_file_format_id_to_name(
 
1914
                                                DICT_TF_FORMAT_MAX));
 
1915
 
 
1916
                        goto mem_free_and_error;
 
1917
                }
 
1918
        }
 
1919
 
 
1920
        if (innobase_change_buffering) {
 
1921
                ulint   use;
 
1922
 
 
1923
                for (use = 0;
 
1924
                     use < UT_ARR_SIZE(innobase_change_buffering_values);
 
1925
                     use++) {
 
1926
                        if (!innobase_strcasecmp(
 
1927
                                    innobase_change_buffering,
 
1928
                                    innobase_change_buffering_values[use])) {
 
1929
                                ibuf_use = (ibuf_use_t) use;
 
1930
                                goto innobase_change_buffering_inited_ok;
 
1931
                        }
 
1932
                }
 
1933
 
 
1934
                errmsg_printf(ERRMSG_LVL_ERROR,
 
1935
                                "InnoDB: invalid value "
 
1936
                                "innodb_file_format_check=%s",
 
1937
                                innobase_change_buffering);
 
1938
                goto mem_free_and_error;
 
1939
        }
2249
1940
 
2250
1941
innobase_change_buffering_inited_ok:
2251
 
  ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
2252
 
  innobase_change_buffering = innobase_change_buffering_values[ibuf_use];
2253
 
 
2254
 
  /* --------------------------------------------------*/
2255
 
 
2256
 
  if (vm.count("flush-method") != 0)
2257
 
  {
2258
 
    srv_file_flush_method_str = (char *)vm["flush-method"].as<string>().c_str();
2259
 
  }
2260
 
 
2261
 
  srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
2262
 
  srv_n_log_files = (ulint) innobase_log_files_in_group;
2263
 
  srv_log_file_size = (ulint) innobase_log_file_size;
2264
 
 
2265
 
  srv_log_buffer_size = (ulint) innobase_log_buffer_size;
2266
 
 
2267
 
  srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
2268
 
  srv_buf_pool_instances = (ulint) innobase_buffer_pool_instances;
2269
 
 
2270
 
  srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
2271
 
 
2272
 
  srv_n_read_io_threads = (ulint) innobase_read_io_threads;
2273
 
  srv_n_write_io_threads = (ulint) innobase_write_io_threads;
2274
 
 
2275
 
  srv_force_recovery = (ulint) innobase_force_recovery;
2276
 
 
2277
 
  srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
2278
 
  srv_use_checksums = (ibool) innobase_use_checksums;
 
1942
        ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
 
1943
        innobase_change_buffering = (char*)
 
1944
                innobase_change_buffering_values[ibuf_use];
 
1945
 
 
1946
        /* --------------------------------------------------*/
 
1947
 
 
1948
        srv_file_flush_method_str = innobase_unix_file_flush_method;
 
1949
 
 
1950
        srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
 
1951
        srv_n_log_files = (ulint) innobase_log_files_in_group;
 
1952
        srv_log_file_size = (ulint) innobase_log_file_size;
 
1953
 
 
1954
#ifdef UNIV_LOG_ARCHIVE
 
1955
        srv_log_archive_on = (ulint) innobase_log_archive;
 
1956
#endif /* UNIV_LOG_ARCHIVE */
 
1957
        srv_log_buffer_size = (ulint) innobase_log_buffer_size;
 
1958
 
 
1959
        srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
 
1960
 
 
1961
        srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
 
1962
 
 
1963
        srv_n_file_io_threads = (ulint) innobase_file_io_threads;
 
1964
        srv_n_read_io_threads = (ulint) innobase_read_io_threads;
 
1965
        srv_n_write_io_threads = (ulint) innobase_write_io_threads;
 
1966
 
 
1967
        srv_force_recovery = (ulint) innobase_force_recovery;
 
1968
 
 
1969
        srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
 
1970
        srv_use_checksums = (ibool) innobase_use_checksums;
2279
1971
 
2280
1972
#ifdef HAVE_LARGE_PAGES
2281
 
  if ((os_use_large_pages = (ibool) my_use_large_pages))
2282
 
    os_large_page_size = (ulint) opt_large_page_size;
 
1973
        if ((os_use_large_pages = (ibool) my_use_large_pages))
 
1974
                os_large_page_size = (ulint) opt_large_page_size;
2283
1975
#endif
2284
1976
 
2285
 
  row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
2286
 
 
2287
 
  srv_locks_unsafe_for_binlog = (ibool) TRUE;
2288
 
 
2289
 
  srv_max_n_open_files = (ulint) innobase_open_files;
2290
 
  srv_innodb_status = (ibool) innobase_create_status_file;
2291
 
 
2292
 
  srv_print_verbose_log = true;
2293
 
 
2294
 
  /* Store the default charset-collation number of this MySQL
2295
 
    installation */
2296
 
 
2297
 
  data_mysql_default_charset_coll = (ulint)default_charset_info->number;
2298
 
 
2299
 
  /* Since we in this module access directly the fields of a trx
2300
 
    struct, and due to different headers and flags it might happen that
2301
 
    mutex_t has a different size in this module and in InnoDB
2302
 
    modules, we check at run time that the size is the same in
2303
 
    these compilation modules. */
2304
 
 
2305
 
  err = innobase_start_or_create_for_mysql();
2306
 
 
2307
 
  if (err != DB_SUCCESS)
2308
 
  {
2309
 
    goto mem_free_and_error;
2310
 
  }
2311
 
 
2312
 
  err = dict_create_sys_replication_log();
2313
 
 
2314
 
  if (err != DB_SUCCESS) {
2315
 
    goto mem_free_and_error;
2316
 
  }
2317
 
 
2318
 
 
2319
 
  innobase_old_blocks_pct = buf_LRU_old_ratio_update(innobase_old_blocks_pct.get(),
2320
 
                                                     TRUE);
2321
 
 
2322
 
  innobase_open_tables = hash_create(200);
2323
 
  pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
2324
 
  pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
2325
 
  pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
2326
 
  pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
2327
 
  pthread_cond_init(&commit_cond, NULL);
2328
 
  innodb_inited= 1;
2329
 
 
2330
 
  actuall_engine_ptr->dropTemporarySchema();
2331
 
 
2332
 
  status_table_function_ptr= new InnodbStatusTool;
2333
 
 
2334
 
  context.add(innodb_engine_ptr);
2335
 
 
2336
 
  context.add(status_table_function_ptr);
2337
 
 
2338
 
  cmp_tool= new(std::nothrow)CmpTool(false);
2339
 
  context.add(cmp_tool);
2340
 
 
2341
 
  cmp_reset_tool= new(std::nothrow)CmpTool(true);
2342
 
  context.add(cmp_reset_tool);
2343
 
 
2344
 
  cmp_mem_tool= new(std::nothrow)CmpmemTool(false);
2345
 
  context.add(cmp_mem_tool);
2346
 
 
2347
 
  cmp_mem_reset_tool= new(std::nothrow)CmpmemTool(true);
2348
 
  context.add(cmp_mem_reset_tool);
2349
 
 
2350
 
  innodb_trx_tool= new(std::nothrow)InnodbTrxTool("INNODB_TRX");
2351
 
  context.add(innodb_trx_tool);
2352
 
 
2353
 
  innodb_locks_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCKS");
2354
 
  context.add(innodb_locks_tool);
2355
 
 
2356
 
  innodb_lock_waits_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCK_WAITS");
2357
 
  context.add(innodb_lock_waits_tool);
2358
 
 
2359
 
  innodb_sys_tables_tool= new(std::nothrow)InnodbSysTablesTool();
2360
 
  context.add(innodb_sys_tables_tool);
2361
 
 
2362
 
  innodb_sys_tablestats_tool= new(std::nothrow)InnodbSysTableStatsTool();
2363
 
  context.add(innodb_sys_tablestats_tool);
2364
 
 
2365
 
  innodb_sys_indexes_tool= new(std::nothrow)InnodbSysIndexesTool();
2366
 
  context.add(innodb_sys_indexes_tool);
2367
 
 
2368
 
  innodb_sys_columns_tool= new(std::nothrow)InnodbSysColumnsTool();
2369
 
  context.add(innodb_sys_columns_tool);
2370
 
 
2371
 
  innodb_sys_fields_tool= new(std::nothrow)InnodbSysFieldsTool();
2372
 
  context.add(innodb_sys_fields_tool);
2373
 
 
2374
 
  innodb_sys_foreign_tool= new(std::nothrow)InnodbSysForeignTool();
2375
 
  context.add(innodb_sys_foreign_tool);
2376
 
 
2377
 
  innodb_sys_foreign_cols_tool= new(std::nothrow)InnodbSysForeignColsTool();
2378
 
  context.add(innodb_sys_foreign_cols_tool);
2379
 
 
2380
 
  context.add(new(std::nothrow)InnodbInternalTables());
2381
 
  context.add(new(std::nothrow)InnodbReplicationTable());
2382
 
 
2383
 
  if (innobase_use_replication_log)
2384
 
  {
2385
 
    replication_logger= new(std::nothrow)ReplicationLog();
2386
 
    context.add(replication_logger);
2387
 
    ReplicationLog::setup(replication_logger);
2388
 
  }
2389
 
 
2390
 
  context.registerVariable(new sys_var_const_string_val("data-home-dir", innobase_data_home_dir));
2391
 
  context.registerVariable(new sys_var_const_string_val("flush-method", 
2392
 
                                                        vm.count("flush-method") ?  vm["flush-method"].as<string>() : ""));
2393
 
  context.registerVariable(new sys_var_const_string_val("log-group-home-dir", innobase_log_group_home_dir));
2394
 
  context.registerVariable(new sys_var_const_string_val("data-file-path", innobase_data_file_path));
2395
 
  context.registerVariable(new sys_var_const_string_val("version", vm["version"].as<string>()));
2396
 
 
2397
 
 
2398
 
  context.registerVariable(new sys_var_bool_ptr_readonly("replication_log", &innobase_use_replication_log));
2399
 
  context.registerVariable(new sys_var_bool_ptr_readonly("checksums", &innobase_use_checksums));
2400
 
  context.registerVariable(new sys_var_bool_ptr_readonly("doublewrite", &innobase_use_doublewrite));
2401
 
  context.registerVariable(new sys_var_bool_ptr("file-per-table", &srv_file_per_table));
2402
 
  context.registerVariable(new sys_var_bool_ptr_readonly("file-format-check", &innobase_file_format_check));
2403
 
  context.registerVariable(new sys_var_bool_ptr("adaptive-flushing", &srv_adaptive_flushing));
2404
 
  context.registerVariable(new sys_var_bool_ptr("status-file", &innobase_create_status_file));
2405
 
  context.registerVariable(new sys_var_bool_ptr_readonly("use-sys-malloc", &srv_use_sys_malloc));
2406
 
  context.registerVariable(new sys_var_bool_ptr_readonly("use-native-aio", &srv_use_native_aio));
2407
 
 
2408
 
  context.registerVariable(new sys_var_bool_ptr("support-xa", &support_xa));
2409
 
  context.registerVariable(new sys_var_bool_ptr("strict_mode", &strict_mode));
2410
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("lock_wait_timeout", lock_wait_timeout));
2411
 
 
2412
 
  context.registerVariable(new sys_var_constrained_value_readonly<size_t>("additional_mem_pool_size",innobase_additional_mem_pool_size));
2413
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("autoextend_increment",
2414
 
                                                                   innodb_auto_extend_increment,
2415
 
                                                                   auto_extend_update));
2416
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("io_capacity",
2417
 
                                                                   innodb_io_capacity,
2418
 
                                                                   io_capacity_update));
2419
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("purge_batch_size",
2420
 
                                                                   innodb_purge_batch_size,
2421
 
                                                                   purge_batch_update));
2422
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("purge_threads",
2423
 
                                                                   innodb_n_purge_threads,
2424
 
                                                                   purge_threads_update));
2425
 
  context.registerVariable(new sys_var_constrained_value<uint16_t>("fast_shutdown", innobase_fast_shutdown));
2426
 
  context.registerVariable(new sys_var_std_string("file_format",
2427
 
                                                  innobase_file_format_name,
2428
 
                                                  innodb_file_format_name_validate));
2429
 
  context.registerVariable(new sys_var_std_string("change_buffering",
2430
 
                                                  innobase_change_buffering,
2431
 
                                                  innodb_change_buffering_validate));
2432
 
  context.registerVariable(new sys_var_std_string("file_format_max",
2433
 
                                                  innobase_file_format_max,
2434
 
                                                  innodb_file_format_max_validate));
2435
 
  context.registerVariable(new sys_var_constrained_value_readonly<size_t>("buffer_pool_size", innobase_buffer_pool_size));
2436
 
  context.registerVariable(new sys_var_constrained_value_readonly<int64_t>("log_file_size", innobase_log_file_size));
2437
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint16_t>("flush_log_at_trx_commit",
2438
 
                                                  innodb_flush_log_at_trx_commit));
2439
 
  context.registerVariable(new sys_var_constrained_value_readonly<unsigned int>("max_dirty_pages_pct",
2440
 
                                                  innodb_max_dirty_pages_pct));
2441
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("max_purge_lag", innodb_max_purge_lag));
2442
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("stats_sample_pages", innodb_stats_sample_pages));
2443
 
  context.registerVariable(new sys_var_bool_ptr("adaptive_hash_index", &btr_search_enabled, innodb_adaptive_hash_index_update));
2444
 
 
2445
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("commit_concurrency",
2446
 
                                                                   innobase_commit_concurrency,
2447
 
                                                                   innodb_commit_concurrency_validate));
2448
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("concurrency_tickets",
2449
 
                                                                   innodb_concurrency_tickets));
2450
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("read_io_threads", innobase_read_io_threads));
2451
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("write_io_threads", innobase_write_io_threads));
2452
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("replication_delay", innodb_replication_delay));
2453
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("force_recovery", innobase_force_recovery));
2454
 
  context.registerVariable(new sys_var_constrained_value_readonly<size_t>("log_buffer_size", innobase_log_buffer_size));
2455
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("log_files_in_group", innobase_log_files_in_group));
2456
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("mirrored_log_groups", innobase_mirrored_log_groups));
2457
 
  context.registerVariable(new sys_var_constrained_value_readonly<uint32_t>("open_files", innobase_open_files));
2458
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("old_blocks_pct",
2459
 
                                                                   innobase_old_blocks_pct,
2460
 
                                                                   innodb_old_blocks_pct_update));
2461
 
  context.registerVariable(new sys_var_uint32_t_ptr("old_blocks_time", &buf_LRU_old_threshold_ms));
2462
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("sync_spin_loops", innodb_sync_spin_loops, innodb_sync_spin_loops_update));
2463
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("spin_wait_delay", innodb_spin_wait_delay, innodb_spin_wait_delay_update));
2464
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("thread_sleep_delay", innodb_thread_sleep_delay, innodb_thread_sleep_delay_update));
2465
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("thread_concurrency",
2466
 
                                                                   innobase_thread_concurrency,
2467
 
                                                                   innodb_thread_concurrency_update));
2468
 
  context.registerVariable(new sys_var_constrained_value<uint32_t>("read_ahead_threshold",
2469
 
                                                                   innodb_read_ahead_threshold,
2470
 
                                                                   innodb_read_ahead_threshold_update));
2471
 
  /* Get the current high water mark format. */
2472
 
  innobase_file_format_max = trx_sys_file_format_max_get();
2473
 
  btr_search_fully_disabled = (!btr_search_enabled);
2474
 
 
2475
 
  return(FALSE);
 
1977
        row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
 
1978
 
 
1979
        srv_locks_unsafe_for_binlog = (ibool) innobase_locks_unsafe_for_binlog;
 
1980
 
 
1981
        srv_max_n_open_files = (ulint) innobase_open_files;
 
1982
        srv_innodb_status = (ibool) innobase_create_status_file;
 
1983
 
 
1984
        srv_print_verbose_log = true;
 
1985
 
 
1986
        /* Store the default charset-collation number of this MySQL
 
1987
        installation */
 
1988
 
 
1989
        data_mysql_default_charset_coll = (ulint)default_charset_info->number;
 
1990
 
 
1991
 
 
1992
        innobase_commit_concurrency_init_default();
 
1993
 
 
1994
        /* Since we in this module access directly the fields of a trx
 
1995
        struct, and due to different headers and flags it might happen that
 
1996
        mutex_t has a different size in this module and in InnoDB
 
1997
        modules, we check at run time that the size is the same in
 
1998
        these compilation modules. */
 
1999
 
 
2000
        err = innobase_start_or_create_for_mysql();
 
2001
 
 
2002
        if (err != DB_SUCCESS) {
 
2003
                goto mem_free_and_error;
 
2004
        }
 
2005
 
 
2006
        innobase_open_tables = hash_create(200);
 
2007
        pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
 
2008
        pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
 
2009
        pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
 
2010
        pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
 
2011
        pthread_cond_init(&commit_cond, NULL);
 
2012
        innodb_inited= 1;
 
2013
 
 
2014
        if (innodb_locks_init() ||
 
2015
                innodb_trx_init() ||
 
2016
                innodb_lock_waits_init() ||
 
2017
                i_s_cmp_init() ||
 
2018
                i_s_cmp_reset_init() ||
 
2019
                i_s_cmpmem_init() ||
 
2020
                i_s_cmpmem_reset_init())
 
2021
                goto error;
 
2022
 
 
2023
        registry.add(innodb_engine_ptr);
 
2024
 
 
2025
        registry.add(innodb_trx_schema_table);
 
2026
        registry.add(innodb_locks_schema_table);
 
2027
        registry.add(innodb_lock_waits_schema_table);   
 
2028
        registry.add(innodb_cmp_schema_table);
 
2029
        registry.add(innodb_cmp_reset_schema_table);
 
2030
        registry.add(innodb_cmpmem_schema_table);
 
2031
        registry.add(innodb_cmpmem_reset_schema_table);
 
2032
 
 
2033
        /* Get the current high water mark format. */
 
2034
        innobase_file_format_check = (char*) trx_sys_file_format_max_get();
 
2035
 
 
2036
        return(FALSE);
2476
2037
error:
2477
 
  return(TRUE);
2478
 
}
2479
 
 
 
2038
        return(TRUE);
 
2039
}
 
2040
 
 
2041
/*******************************************************************//**
 
2042
Closes an InnoDB database.
 
2043
@return TRUE if error */
 
2044
static
 
2045
int
 
2046
innobase_deinit(plugin::Registry &registry)
 
2047
{
 
2048
        int     err= 0;
 
2049
        i_s_common_deinit(registry);
 
2050
        registry.remove(innodb_engine_ptr);
 
2051
        delete innodb_engine_ptr;
 
2052
 
 
2053
        if (innodb_inited) {
 
2054
 
 
2055
                srv_fast_shutdown = (ulint) innobase_fast_shutdown;
 
2056
                innodb_inited = 0;
 
2057
                hash_table_free(innobase_open_tables);
 
2058
                innobase_open_tables = NULL;
 
2059
                if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
 
2060
                        err = 1;
 
2061
                }
 
2062
                srv_free_paths_and_sizes();
 
2063
                if (internal_innobase_data_file_path)
 
2064
                  free(internal_innobase_data_file_path);
 
2065
                pthread_mutex_destroy(&innobase_share_mutex);
 
2066
                pthread_mutex_destroy(&prepare_commit_mutex);
 
2067
                pthread_mutex_destroy(&commit_threads_m);
 
2068
                pthread_mutex_destroy(&commit_cond_m);
 
2069
                pthread_cond_destroy(&commit_cond);
 
2070
        }
 
2071
 
 
2072
        return(err);
 
2073
}
2480
2074
 
2481
2075
/****************************************************************//**
2482
2076
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
2483
2077
the logs, and the name of this function should be innobase_checkpoint.
2484
 
@return TRUE if error */
 
2078
@return TRUE if error */
2485
2079
bool
2486
2080
InnobaseEngine::flush_logs()
2487
2081
/*=====================*/
2488
2082
{
2489
 
  bool  result = 0;
2490
 
 
2491
 
  assert(this == innodb_engine_ptr);
2492
 
 
2493
 
  log_buffer_flush_to_disk();
2494
 
 
2495
 
  return(result);
 
2083
        bool    result = 0;
 
2084
 
 
2085
        assert(this == innodb_engine_ptr);
 
2086
 
 
2087
        log_buffer_flush_to_disk();
 
2088
 
 
2089
        return(result);
2496
2090
}
2497
2091
 
2498
2092
/*****************************************************************//**
2501
2095
void
2502
2096
innobase_commit_low(
2503
2097
/*================*/
2504
 
  trx_t*  trx)  /*!< in: transaction handle */
 
2098
        trx_t*  trx)    /*!< in: transaction handle */
2505
2099
{
2506
 
  if (trx->conc_state == TRX_NOT_STARTED) {
2507
 
 
2508
 
    return;
2509
 
  }
2510
 
 
2511
 
  trx_commit_for_mysql(trx);
 
2100
        if (trx->conc_state == TRX_NOT_STARTED) {
 
2101
 
 
2102
                return;
 
2103
        }
 
2104
 
 
2105
        trx_commit_for_mysql(trx);
2512
2106
}
2513
2107
 
2514
2108
/*****************************************************************//**
2516
2110
Starts a new InnoDB transaction if a transaction is not yet started. And
2517
2111
assigns a new snapshot for a consistent read if the transaction does not yet
2518
2112
have one.
2519
 
@return 0 */
 
2113
@return 0 */
2520
2114
int
2521
 
InnobaseEngine::doStartTransaction(
 
2115
InnobaseEngine::start_consistent_snapshot(
2522
2116
/*====================================*/
2523
 
  Session*  session,  /*!< in: MySQL thread handle of the user for whom
2524
 
                               the transaction should be committed */
2525
 
  start_transaction_option_t options)
 
2117
        Session*        session)        /*!< in: MySQL thread handle of the user for whom
 
2118
                        the transaction should be committed */
2526
2119
{
2527
 
  assert(this == innodb_engine_ptr);
2528
 
 
2529
 
  /* Create a new trx struct for session, if it does not yet have one */
2530
 
  trx_t *trx = check_trx_exists(session);
2531
 
 
2532
 
  /* This is just to play safe: release a possible FIFO ticket and
2533
 
  search latch. Since we will reserve the kernel mutex, we have to
2534
 
  release the search system latch first to obey the latching order. */
2535
 
  innobase_release_stat_resources(trx);
2536
 
 
2537
 
  /* If the transaction is not started yet, start it */
2538
 
  trx_start_if_not_started(trx);
2539
 
 
2540
 
  /* Assign a read view if the transaction does not have it yet */
2541
 
  if (options == START_TRANS_OPT_WITH_CONS_SNAPSHOT)
2542
 
    trx_assign_read_view(trx);
2543
 
 
2544
 
  return 0;
 
2120
        trx_t*  trx;
 
2121
 
 
2122
        assert(this == innodb_engine_ptr);
 
2123
 
 
2124
        /* Create a new trx struct for session, if it does not yet have one */
 
2125
 
 
2126
        trx = check_trx_exists(session);
 
2127
 
 
2128
        /* This is just to play safe: release a possible FIFO ticket and
 
2129
        search latch. Since we will reserve the kernel mutex, we have to
 
2130
        release the search system latch first to obey the latching order. */
 
2131
 
 
2132
        innobase_release_stat_resources(trx);
 
2133
 
 
2134
        /* If the transaction is not started yet, start it */
 
2135
 
 
2136
        trx_start_if_not_started(trx);
 
2137
 
 
2138
        /* Assign a read view if the transaction does not have it yet */
 
2139
 
 
2140
        trx_assign_read_view(trx);
 
2141
 
 
2142
        /* Set the MySQL flag to mark that there is an active transaction */
 
2143
 
 
2144
        if (trx->active_trans == 0) {
 
2145
                innobase_register_trx_and_stmt(this, current_session);
 
2146
                trx->active_trans = 1;
 
2147
        }
 
2148
 
 
2149
        return(0);
2545
2150
}
2546
2151
 
2547
2152
/*****************************************************************//**
2548
2153
Commits a transaction in an InnoDB database or marks an SQL statement
2549
2154
ended.
2550
 
@return 0 */
 
2155
@return 0 */
2551
2156
int
2552
 
InnobaseEngine::doCommit(
 
2157
InnobaseEngine::commit(
2553
2158
/*============*/
2554
 
  Session*  session,  /*!< in: MySQL thread handle of the user for whom
2555
 
      the transaction should be committed */
2556
 
  bool  all)  /*!< in:  TRUE - commit transaction
2557
 
        FALSE - the current SQL statement ended */
 
2159
        Session*        session,        /*!< in: MySQL thread handle of the user for whom
 
2160
                        the transaction should be committed */
 
2161
        bool    all)    /*!< in:        TRUE - commit transaction
 
2162
                                FALSE - the current SQL statement ended */
2558
2163
{
2559
 
  trx_t*    trx;
2560
 
 
2561
 
  assert(this == innodb_engine_ptr);
2562
 
 
2563
 
  trx = check_trx_exists(session);
2564
 
 
2565
 
  /* Since we will reserve the kernel mutex, we have to release
2566
 
  the search system latch first to obey the latching order. */
2567
 
 
2568
 
  if (trx->has_search_latch) {
2569
 
    trx_search_latch_release_if_reserved(trx);
2570
 
  }
2571
 
 
2572
 
  if (all
2573
 
    || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
2574
 
 
2575
 
    /* We were instructed to commit the whole transaction, or
2576
 
    this is an SQL statement end and autocommit is on */
2577
 
 
2578
 
    /* We need current binlog position for ibbackup to work.
2579
 
    Note, the position is current because of
2580
 
    prepare_commit_mutex */
 
2164
        trx_t*          trx;
 
2165
 
 
2166
        assert(this == innodb_engine_ptr);
 
2167
 
 
2168
        trx = check_trx_exists(session);
 
2169
 
 
2170
        /* Since we will reserve the kernel mutex, we have to release
 
2171
        the search system latch first to obey the latching order. */
 
2172
 
 
2173
        if (trx->has_search_latch) {
 
2174
                trx_search_latch_release_if_reserved(trx);
 
2175
        }
 
2176
 
 
2177
        /* The flag trx->active_trans is set to 1 in
 
2178
 
 
2179
        1. ::external_lock(),
 
2180
        2. ::start_stmt(),
 
2181
        3. innobase_query_caching_of_table_permitted(),
 
2182
        4. InnobaseEngine::savepoint_set(),
 
2183
        5. ::init_table_handle_for_HANDLER(),
 
2184
        6. InnobaseEngine::start_consistent_snapshot(),
 
2185
 
 
2186
        and it is only set to 0 in a commit or a rollback. If it is 0 we know
 
2187
        there cannot be resources to be freed and we could return immediately.
 
2188
        For the time being, we play safe and do the cleanup though there should
 
2189
        be nothing to clean up. */
 
2190
 
 
2191
        if (trx->active_trans == 0
 
2192
                && trx->conc_state != TRX_NOT_STARTED) {
 
2193
 
 
2194
                errmsg_printf(ERRMSG_LVL_ERROR, "trx->active_trans == 0, but"
 
2195
                        " trx->conc_state != TRX_NOT_STARTED");
 
2196
        }
 
2197
        if (all
 
2198
                || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
 
2199
 
 
2200
                /* We were instructed to commit the whole transaction, or
 
2201
                this is an SQL statement end and autocommit is on */
 
2202
 
 
2203
                /* We need current binlog position for ibbackup to work.
 
2204
                Note, the position is current because of
 
2205
                prepare_commit_mutex */
2581
2206
retry:
2582
 
    if (innobase_commit_concurrency.get() > 0) {
2583
 
      pthread_mutex_lock(&commit_cond_m);
2584
 
      commit_threads++;
 
2207
                if (innobase_commit_concurrency > 0) {
 
2208
                        pthread_mutex_lock(&commit_cond_m);
 
2209
                        commit_threads++;
2585
2210
 
2586
 
      if (commit_threads > innobase_commit_concurrency.get()) {
2587
 
        commit_threads--;
2588
 
        pthread_cond_wait(&commit_cond,
2589
 
          &commit_cond_m);
2590
 
        pthread_mutex_unlock(&commit_cond_m);
2591
 
        goto retry;
2592
 
      }
2593
 
      else {
2594
 
        pthread_mutex_unlock(&commit_cond_m);
2595
 
      }
2596
 
    }
 
2211
                        if (commit_threads > innobase_commit_concurrency) {
 
2212
                                commit_threads--;
 
2213
                                pthread_cond_wait(&commit_cond,
 
2214
                                        &commit_cond_m);
 
2215
                                pthread_mutex_unlock(&commit_cond_m);
 
2216
                                goto retry;
 
2217
                        }
 
2218
                        else {
 
2219
                                pthread_mutex_unlock(&commit_cond_m);
 
2220
                        }
 
2221
                }
2597
2222
 
2598
2223
                /* Store transaction point for binlog
2599
 
    Later logic tests that this is set to _something_. We need
2600
 
    that logic to fire, even though we do not have a real name. */
2601
 
    trx->mysql_log_file_name = "UNUSED";
2602
 
    trx->mysql_log_offset = 0;
2603
 
 
2604
 
    /* Don't do write + flush right now. For group commit
2605
 
    to work we want to do the flush after releasing the
2606
 
    prepare_commit_mutex. */
2607
 
    trx->flush_log_later = TRUE;
2608
 
    innobase_commit_low(trx);
2609
 
    trx->flush_log_later = FALSE;
2610
 
 
2611
 
    if (innobase_commit_concurrency.get() > 0) {
2612
 
      pthread_mutex_lock(&commit_cond_m);
2613
 
      commit_threads--;
2614
 
      pthread_cond_signal(&commit_cond);
2615
 
      pthread_mutex_unlock(&commit_cond_m);
2616
 
    }
2617
 
 
2618
 
    /* Now do a write + flush of logs. */
2619
 
    trx_commit_complete_for_mysql(trx);
2620
 
 
2621
 
  } else {
2622
 
    /* We just mark the SQL statement ended and do not do a
2623
 
    transaction commit */
2624
 
 
2625
 
    /* If we had reserved the auto-inc lock for some
2626
 
    table in this SQL statement we release it now */
2627
 
 
2628
 
    row_unlock_table_autoinc_for_mysql(trx);
2629
 
 
2630
 
    /* Store the current undo_no of the transaction so that we
2631
 
    know where to roll back if we have to roll back the next
2632
 
    SQL statement */
2633
 
 
2634
 
    trx_mark_sql_stat_end(trx);
2635
 
 
2636
 
    if (! session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
2637
 
    {
2638
 
      if (trx->conc_state != TRX_NOT_STARTED)
2639
 
      {
2640
 
        commit(session, TRUE);
2641
 
      }
2642
 
    }
2643
 
  }
2644
 
 
2645
 
  trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
2646
 
 
2647
 
  if (trx->declared_to_be_inside_innodb) {
2648
 
    /* Release our possible ticket in the FIFO */
2649
 
 
2650
 
    srv_conc_force_exit_innodb(trx);
2651
 
  }
2652
 
 
2653
 
  /* Tell the InnoDB server that there might be work for utility
2654
 
  threads: */
2655
 
  srv_active_wake_master_thread();
2656
 
 
2657
 
  if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
2658
 
      trx->global_read_view)
2659
 
  {
2660
 
    /* At low transaction isolation levels we let
2661
 
       each consistent read set its own snapshot */
2662
 
    read_view_close_for_mysql(trx);
2663
 
  }
2664
 
 
2665
 
  return(0);
 
2224
                Later logic tests that this is set to _something_. We need
 
2225
                that logic to fire, even though we do not have a real name. */
 
2226
                trx->mysql_log_file_name = "UNUSED";
 
2227
                trx->mysql_log_offset = 0;
 
2228
 
 
2229
                /* Don't do write + flush right now. For group commit
 
2230
                to work we want to do the flush after releasing the
 
2231
                prepare_commit_mutex. */
 
2232
                trx->flush_log_later = TRUE;
 
2233
                innobase_commit_low(trx);
 
2234
                trx->flush_log_later = FALSE;
 
2235
 
 
2236
                if (innobase_commit_concurrency > 0) {
 
2237
                        pthread_mutex_lock(&commit_cond_m);
 
2238
                        commit_threads--;
 
2239
                        pthread_cond_signal(&commit_cond);
 
2240
                        pthread_mutex_unlock(&commit_cond_m);
 
2241
                }
 
2242
 
 
2243
                if (trx->active_trans == 2) {
 
2244
 
 
2245
                        pthread_mutex_unlock(&prepare_commit_mutex);
 
2246
                }
 
2247
 
 
2248
                /* Now do a write + flush of logs. */
 
2249
                trx_commit_complete_for_mysql(trx);
 
2250
                trx->active_trans = 0;
 
2251
 
 
2252
        } else {
 
2253
                /* We just mark the SQL statement ended and do not do a
 
2254
                transaction commit */
 
2255
 
 
2256
                /* If we had reserved the auto-inc lock for some
 
2257
                table in this SQL statement we release it now */
 
2258
 
 
2259
                row_unlock_table_autoinc_for_mysql(trx);
 
2260
 
 
2261
                /* Store the current undo_no of the transaction so that we
 
2262
                know where to roll back if we have to roll back the next
 
2263
                SQL statement */
 
2264
 
 
2265
                trx_mark_sql_stat_end(trx);
 
2266
        }
 
2267
 
 
2268
        trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
 
2269
 
 
2270
        if (trx->declared_to_be_inside_innodb) {
 
2271
                /* Release our possible ticket in the FIFO */
 
2272
 
 
2273
                srv_conc_force_exit_innodb(trx);
 
2274
        }
 
2275
 
 
2276
        /* Tell the InnoDB server that there might be work for utility
 
2277
        threads: */
 
2278
        srv_active_wake_master_thread();
 
2279
 
 
2280
        return(0);
2666
2281
}
2667
2282
 
2668
2283
/*****************************************************************//**
2669
2284
Rolls back a transaction or the latest SQL statement.
2670
 
@return 0 or error number */
 
2285
@return 0 or error number */
2671
2286
int
2672
 
InnobaseEngine::doRollback(
 
2287
InnobaseEngine::rollback(
2673
2288
/*==============*/
2674
 
  Session*  session,/*!< in: handle to the MySQL thread of the user
2675
 
      whose transaction should be rolled back */
2676
 
  bool  all)  /*!< in:  TRUE - commit transaction
2677
 
        FALSE - the current SQL statement ended */
 
2289
        Session*        session,/*!< in: handle to the MySQL thread of the user
 
2290
                        whose transaction should be rolled back */
 
2291
        bool    all)    /*!< in:        TRUE - commit transaction
 
2292
                                FALSE - the current SQL statement ended */
2678
2293
{
2679
 
  int error = 0;
2680
 
  trx_t*  trx;
2681
 
 
2682
 
  assert(this == innodb_engine_ptr);
2683
 
 
2684
 
  trx = check_trx_exists(session);
2685
 
 
2686
 
  /* Release a possible FIFO ticket and search latch. Since we will
2687
 
  reserve the kernel mutex, we have to release the search system latch
2688
 
  first to obey the latching order. */
2689
 
 
2690
 
  innobase_release_stat_resources(trx);
2691
 
 
2692
 
  trx->n_autoinc_rows = 0;
2693
 
 
2694
 
  /* If we had reserved the auto-inc lock for some table (if
2695
 
  we come here to roll back the latest SQL statement) we
2696
 
  release it now before a possibly lengthy rollback */
2697
 
 
2698
 
  row_unlock_table_autoinc_for_mysql(trx);
2699
 
 
2700
 
  if (all
2701
 
    || !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
2702
 
 
2703
 
    error = trx_rollback_for_mysql(trx);
2704
 
  } else {
2705
 
    error = trx_rollback_last_sql_stat_for_mysql(trx);
2706
 
  }
2707
 
 
2708
 
  if (trx->isolation_level <= TRX_ISO_READ_COMMITTED &&
2709
 
      trx->global_read_view)
2710
 
  {
2711
 
    /* At low transaction isolation levels we let
2712
 
       each consistent read set its own snapshot */
2713
 
    read_view_close_for_mysql(trx);
2714
 
  }
2715
 
 
2716
 
  return(convert_error_code_to_mysql(error, 0, NULL));
 
2294
        int     error = 0;
 
2295
        trx_t*  trx;
 
2296
 
 
2297
        assert(this == innodb_engine_ptr);
 
2298
 
 
2299
        trx = check_trx_exists(session);
 
2300
 
 
2301
        /* Release a possible FIFO ticket and search latch. Since we will
 
2302
        reserve the kernel mutex, we have to release the search system latch
 
2303
        first to obey the latching order. */
 
2304
 
 
2305
        innobase_release_stat_resources(trx);
 
2306
 
 
2307
        /* If we had reserved the auto-inc lock for some table (if
 
2308
        we come here to roll back the latest SQL statement) we
 
2309
        release it now before a possibly lengthy rollback */
 
2310
 
 
2311
        row_unlock_table_autoinc_for_mysql(trx);
 
2312
 
 
2313
        if (all
 
2314
                || !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
 
2315
 
 
2316
                error = trx_rollback_for_mysql(trx);
 
2317
                trx->active_trans = 0;
 
2318
        } else {
 
2319
                error = trx_rollback_last_sql_stat_for_mysql(trx);
 
2320
        }
 
2321
 
 
2322
        return(convert_error_code_to_mysql(error, 0, NULL));
2717
2323
}
2718
2324
 
2719
2325
/*****************************************************************//**
2720
2326
Rolls back a transaction
2721
 
@return 0 or error number */
 
2327
@return 0 or error number */
2722
2328
static
2723
2329
int
2724
2330
innobase_rollback_trx(
2725
2331
/*==================*/
2726
 
  trx_t*  trx)  /*!< in: transaction */
 
2332
        trx_t*  trx)    /*!< in: transaction */
2727
2333
{
2728
 
  int error = 0;
2729
 
 
2730
 
  /* Release a possible FIFO ticket and search latch. Since we will
2731
 
  reserve the kernel mutex, we have to release the search system latch
2732
 
  first to obey the latching order. */
2733
 
 
2734
 
  innobase_release_stat_resources(trx);
2735
 
 
2736
 
  /* If we had reserved the auto-inc lock for some table (if
2737
 
  we come here to roll back the latest SQL statement) we
2738
 
  release it now before a possibly lengthy rollback */
2739
 
 
2740
 
  row_unlock_table_autoinc_for_mysql(trx);
2741
 
 
2742
 
  error = trx_rollback_for_mysql(trx);
2743
 
 
2744
 
  return(convert_error_code_to_mysql(error, 0, NULL));
 
2334
        int     error = 0;
 
2335
 
 
2336
        /* Release a possible FIFO ticket and search latch. Since we will
 
2337
        reserve the kernel mutex, we have to release the search system latch
 
2338
        first to obey the latching order. */
 
2339
 
 
2340
        innobase_release_stat_resources(trx);
 
2341
 
 
2342
        /* If we had reserved the auto-inc lock for some table (if
 
2343
        we come here to roll back the latest SQL statement) we
 
2344
        release it now before a possibly lengthy rollback */
 
2345
 
 
2346
        row_unlock_table_autoinc_for_mysql(trx);
 
2347
 
 
2348
        error = trx_rollback_for_mysql(trx);
 
2349
 
 
2350
        return(convert_error_code_to_mysql(error, 0, NULL));
2745
2351
}
2746
2352
 
2747
2353
/*****************************************************************//**
2749
2355
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2750
2356
given name */
2751
2357
int
2752
 
InnobaseEngine::doRollbackToSavepoint(
 
2358
InnobaseEngine::savepoint_rollback_hook(
2753
2359
/*===========================*/
2754
 
  Session*  session,    /*!< in: handle to the MySQL thread of the user
2755
 
        whose transaction should be rolled back */
2756
 
  drizzled::NamedSavepoint &named_savepoint)  /*!< in: savepoint data */
 
2360
        Session*        session,                /*!< in: handle to the MySQL thread of the user
 
2361
                                whose transaction should be rolled back */
 
2362
        drizzled::NamedSavepoint &named_savepoint)      /*!< in: savepoint data */
2757
2363
{
2758
 
  ib_int64_t  mysql_binlog_cache_pos;
2759
 
  int   error = 0;
2760
 
  trx_t*    trx;
2761
 
 
2762
 
  assert(this == innodb_engine_ptr);
2763
 
 
2764
 
  trx = check_trx_exists(session);
2765
 
 
2766
 
  /* Release a possible FIFO ticket and search latch. Since we will
2767
 
  reserve the kernel mutex, we have to release the search system latch
2768
 
  first to obey the latching order. */
2769
 
 
2770
 
  innobase_release_stat_resources(trx);
2771
 
 
2772
 
  error= (int)trx_rollback_to_savepoint_for_mysql(trx, named_savepoint.getName().c_str(),
 
2364
        ib_int64_t      mysql_binlog_cache_pos;
 
2365
        int             error = 0;
 
2366
        trx_t*          trx;
 
2367
 
 
2368
        assert(this == innodb_engine_ptr);
 
2369
 
 
2370
        trx = check_trx_exists(session);
 
2371
 
 
2372
        /* Release a possible FIFO ticket and search latch. Since we will
 
2373
        reserve the kernel mutex, we have to release the search system latch
 
2374
        first to obey the latching order. */
 
2375
 
 
2376
        innobase_release_stat_resources(trx);
 
2377
 
 
2378
        /* TODO: use provided savepoint data area to store savepoint data */
 
2379
        error= (int)trx_rollback_to_savepoint_for_mysql(trx, named_savepoint.getName().c_str(),
2773
2380
                                                        &mysql_binlog_cache_pos);
2774
 
  return(convert_error_code_to_mysql(error, 0, NULL));
 
2381
        return(convert_error_code_to_mysql(error, 0, NULL));
2775
2382
}
2776
2383
 
2777
2384
/*****************************************************************//**
2779
2386
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
2780
2387
given name */
2781
2388
int
2782
 
InnobaseEngine::doReleaseSavepoint(
 
2389
InnobaseEngine::savepoint_release_hook(
2783
2390
/*=======================*/
2784
 
  Session*  session,    /*!< in: handle to the MySQL thread of the user
2785
 
        whose transaction should be rolled back */
2786
 
  drizzled::NamedSavepoint &named_savepoint)  /*!< in: savepoint data */
 
2391
        Session*        session,                /*!< in: handle to the MySQL thread of the user
 
2392
                                whose transaction should be rolled back */
 
2393
        drizzled::NamedSavepoint &named_savepoint)      /*!< in: savepoint data */
2787
2394
{
2788
 
  int   error = 0;
2789
 
  trx_t*    trx;
2790
 
 
2791
 
  assert(this == innodb_engine_ptr);
2792
 
 
2793
 
  trx = check_trx_exists(session);
2794
 
 
2795
 
  error = (int) trx_release_savepoint_for_mysql(trx, named_savepoint.getName().c_str());
2796
 
 
2797
 
  return(convert_error_code_to_mysql(error, 0, NULL));
 
2395
        int             error = 0;
 
2396
        trx_t*          trx;
 
2397
 
 
2398
        assert(this == innodb_engine_ptr);
 
2399
 
 
2400
        trx = check_trx_exists(session);
 
2401
 
 
2402
        /* TODO: use provided savepoint data area to store savepoint data */
 
2403
        error = (int) trx_release_savepoint_for_mysql(trx, named_savepoint.getName().c_str());
 
2404
 
 
2405
        return(convert_error_code_to_mysql(error, 0, NULL));
2798
2406
}
2799
2407
 
2800
2408
/*****************************************************************//**
2801
2409
Sets a transaction savepoint.
2802
 
@return always 0, that is, always succeeds */
 
2410
@return always 0, that is, always succeeds */
2803
2411
int
2804
 
InnobaseEngine::doSetSavepoint(
 
2412
InnobaseEngine::savepoint_set_hook(
2805
2413
/*===============*/
2806
 
  Session*  session,/*!< in: handle to the MySQL thread */
2807
 
  drizzled::NamedSavepoint &named_savepoint)  /*!< in: savepoint data */
 
2414
        Session*        session,/*!< in: handle to the MySQL thread */
 
2415
        drizzled::NamedSavepoint &named_savepoint)      /*!< in: savepoint data */
2808
2416
{
2809
 
  int error = 0;
2810
 
  trx_t*  trx;
2811
 
 
2812
 
  assert(this == innodb_engine_ptr);
2813
 
 
2814
 
  /*
2815
 
    In the autocommit mode there is no sense to set a savepoint
2816
 
    (unless we are in sub-statement), so SQL layer ensures that
2817
 
    this method is never called in such situation.
2818
 
  */
2819
 
 
2820
 
  trx = check_trx_exists(session);
2821
 
 
2822
 
  /* Release a possible FIFO ticket and search latch. Since we will
2823
 
  reserve the kernel mutex, we have to release the search system latch
2824
 
  first to obey the latching order. */
2825
 
 
2826
 
  innobase_release_stat_resources(trx);
2827
 
 
2828
 
  /* cannot happen outside of transaction */
2829
 
  assert(trx->conc_state != TRX_NOT_STARTED);
2830
 
 
2831
 
  error = (int) trx_savepoint_for_mysql(trx, named_savepoint.getName().c_str(), (ib_int64_t)0);
2832
 
 
2833
 
  return(convert_error_code_to_mysql(error, 0, NULL));
 
2417
        int     error = 0;
 
2418
        trx_t*  trx;
 
2419
 
 
2420
        assert(this == innodb_engine_ptr);
 
2421
 
 
2422
        /*
 
2423
          In the autocommit mode there is no sense to set a savepoint
 
2424
          (unless we are in sub-statement), so SQL layer ensures that
 
2425
          this method is never called in such situation.
 
2426
        */
 
2427
 
 
2428
        trx = check_trx_exists(session);
 
2429
 
 
2430
        /* Release a possible FIFO ticket and search latch. Since we will
 
2431
        reserve the kernel mutex, we have to release the search system latch
 
2432
        first to obey the latching order. */
 
2433
 
 
2434
        innobase_release_stat_resources(trx);
 
2435
 
 
2436
        /* cannot happen outside of transaction */
 
2437
        assert(trx->active_trans);
 
2438
 
 
2439
        /* TODO: use provided savepoint data area to store savepoint data */
 
2440
        error = (int) trx_savepoint_for_mysql(trx, named_savepoint.getName().c_str(), (ib_int64_t)0);
 
2441
 
 
2442
        return(convert_error_code_to_mysql(error, 0, NULL));
2834
2443
}
2835
2444
 
2836
2445
/*****************************************************************//**
2837
2446
Frees a possible InnoDB trx object associated with the current Session.
2838
 
@return 0 or error number */
 
2447
@return 0 or error number */
2839
2448
int
2840
2449
InnobaseEngine::close_connection(
2841
2450
/*======================*/
2842
 
  Session*  session)/*!< in: handle to the MySQL thread of the user
2843
 
      whose resources should be free'd */
 
2451
        Session*        session)/*!< in: handle to the MySQL thread of the user
 
2452
                        whose resources should be free'd */
2844
2453
{
2845
 
  trx_t*  trx;
2846
 
 
2847
 
  assert(this == innodb_engine_ptr);
2848
 
  trx = session_to_trx(session);
2849
 
 
2850
 
  ut_a(trx);
2851
 
 
2852
 
  assert(session->getKilled() != Session::NOT_KILLED ||
2853
 
         trx->conc_state == TRX_NOT_STARTED);
2854
 
 
2855
 
  /* Warn if rolling back some things... */
2856
 
  if (session->getKilled() != Session::NOT_KILLED &&
2857
 
      trx->conc_state != TRX_NOT_STARTED &&
2858
 
      trx->undo_no > 0 &&
2859
 
      global_system_variables.log_warnings)
2860
 
  {
2861
 
      errmsg_printf(ERRMSG_LVL_WARN,
2862
 
      "Drizzle is closing a connection during a KILL operation\n"
2863
 
      "that has an active InnoDB transaction.  %llu row modifications will "
2864
 
      "roll back.\n",
2865
 
      (ullint) trx->undo_no);
2866
 
  }
2867
 
 
2868
 
  innobase_rollback_trx(trx);
2869
 
 
2870
 
  thr_local_free(trx->mysql_thread_id);
2871
 
  trx_free_for_mysql(trx);
2872
 
 
2873
 
  return(0);
 
2454
        trx_t*  trx;
 
2455
 
 
2456
        assert(this == innodb_engine_ptr);
 
2457
        trx = session_to_trx(session);
 
2458
 
 
2459
        ut_a(trx);
 
2460
 
 
2461
        if (trx->active_trans == 0
 
2462
                && trx->conc_state != TRX_NOT_STARTED) {
 
2463
 
 
2464
                errmsg_printf(ERRMSG_LVL_ERROR, "trx->active_trans == 0, but"
 
2465
                        " trx->conc_state != TRX_NOT_STARTED");
 
2466
        }
 
2467
 
 
2468
 
 
2469
        if (trx->conc_state != TRX_NOT_STARTED &&
 
2470
                global_system_variables.log_warnings) {
 
2471
                errmsg_printf(ERRMSG_LVL_WARN, 
 
2472
                        "MySQL is closing a connection that has an active "
 
2473
                        "InnoDB transaction.  %lu row modifications will "
 
2474
                        "roll back.",
 
2475
                        (ulong) trx->undo_no.low);
 
2476
        }
 
2477
 
 
2478
        innobase_rollback_trx(trx);
 
2479
 
 
2480
        thr_local_free(trx->mysql_thread_id);
 
2481
        trx_free_for_mysql(trx);
 
2482
 
 
2483
        return(0);
2874
2484
}
2875
2485
 
2876
2486
 
2879
2489
*****************************************************************************/
2880
2490
 
2881
2491
/****************************************************************//**
 
2492
Get the record format from the data dictionary.
 
2493
@return one of ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT,
 
2494
ROW_TYPE_COMPRESSED, ROW_TYPE_DYNAMIC */
 
2495
UNIV_INTERN
 
2496
enum row_type
 
2497
ha_innobase::get_row_type() const
 
2498
/*=============================*/
 
2499
{
 
2500
        if (prebuilt && prebuilt->table) {
 
2501
                const ulint     flags = prebuilt->table->flags;
 
2502
 
 
2503
                if (UNIV_UNLIKELY(!flags)) {
 
2504
                        return(ROW_TYPE_REDUNDANT);
 
2505
                }
 
2506
 
 
2507
                ut_ad(flags & DICT_TF_COMPACT);
 
2508
 
 
2509
                switch (flags & DICT_TF_FORMAT_MASK) {
 
2510
                case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT:
 
2511
                        return(ROW_TYPE_COMPACT);
 
2512
                case DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT:
 
2513
                        if (flags & DICT_TF_ZSSIZE_MASK) {
 
2514
                                return(ROW_TYPE_COMPRESSED);
 
2515
                        } else {
 
2516
                                return(ROW_TYPE_DYNAMIC);
 
2517
                        }
 
2518
#if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
 
2519
# error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
 
2520
#endif
 
2521
                }
 
2522
        }
 
2523
        ut_ad(0);
 
2524
        return(ROW_TYPE_NOT_USED);
 
2525
}
 
2526
 
 
2527
 
 
2528
/****************************************************************//**
2882
2529
Returns the index type. */
2883
2530
UNIV_INTERN
2884
2531
const char*
2885
2532
ha_innobase::index_type(
2886
2533
/*====================*/
2887
 
  uint)
2888
 
        /*!< out: index type */
 
2534
        uint)
 
2535
                                /*!< out: index type */
2889
2536
{
2890
 
  return("BTREE");
 
2537
        return("BTREE");
2891
2538
}
2892
2539
 
2893
2540
/****************************************************************//**
2894
2541
Returns the maximum number of keys.
2895
 
@return MAX_KEY */
 
2542
@return MAX_KEY */
2896
2543
UNIV_INTERN
2897
2544
uint
2898
2545
InnobaseEngine::max_supported_keys() const
2899
2546
/*===================================*/
2900
2547
{
2901
 
  return(MAX_KEY);
 
2548
        return(MAX_KEY);
2902
2549
}
2903
2550
 
2904
2551
/****************************************************************//**
2905
2552
Returns the maximum key length.
2906
 
@return maximum supported key length, in bytes */
 
2553
@return maximum supported key length, in bytes */
2907
2554
UNIV_INTERN
2908
2555
uint32_t
2909
2556
InnobaseEngine::max_supported_key_length() const
2910
2557
/*=========================================*/
2911
2558
{
2912
 
  /* An InnoDB page must store >= 2 keys; a secondary key record
2913
 
  must also contain the primary key value: max key length is
2914
 
  therefore set to slightly less than 1 / 4 of page size which
2915
 
  is 16 kB; but currently MySQL does not work with keys whose
2916
 
  size is > MAX_KEY_LENGTH */
2917
 
  return(3500);
 
2559
        /* An InnoDB page must store >= 2 keys; a secondary key record
 
2560
        must also contain the primary key value: max key length is
 
2561
        therefore set to slightly less than 1 / 4 of page size which
 
2562
        is 16 kB; but currently MySQL does not work with keys whose
 
2563
        size is > MAX_KEY_LENGTH */
 
2564
        return(3500);
2918
2565
}
2919
2566
 
2920
2567
/****************************************************************//**
2921
2568
Returns the key map of keys that are usable for scanning.
2922
 
@return key_map_full */
 
2569
@return key_map_full */
2923
2570
UNIV_INTERN
2924
2571
const key_map*
2925
2572
ha_innobase::keys_to_use_for_scanning()
2926
2573
{
2927
 
  return(&key_map_full);
 
2574
        return(&key_map_full);
2928
2575
}
2929
2576
 
2930
2577
 
2931
2578
/****************************************************************//**
2932
2579
Determines if the primary key is clustered index.
2933
 
@return true */
 
2580
@return true */
2934
2581
UNIV_INTERN
2935
2582
bool
2936
2583
ha_innobase::primary_key_is_clustered()
2937
2584
{
2938
 
  return(true);
 
2585
        return(true);
2939
2586
}
2940
2587
 
2941
2588
/*****************************************************************//**
2947
2594
void
2948
2595
normalize_table_name(
2949
2596
/*=================*/
2950
 
  char*   norm_name,  /*!< out: normalized name as a
2951
 
          null-terminated string */
2952
 
  const char* name)   /*!< in: table name string */
 
2597
        char*           norm_name,      /*!< out: normalized name as a
 
2598
                                        null-terminated string */
 
2599
        const char*     name)           /*!< in: table name string */
2953
2600
{
2954
 
  const char* name_ptr;
2955
 
  const char* db_ptr;
2956
 
  const char* ptr;
2957
 
 
2958
 
  /* Scan name from the end */
2959
 
 
2960
 
  ptr = strchr(name, '\0')-1;
2961
 
 
2962
 
  while (ptr >= name && *ptr != '\\' && *ptr != '/') {
2963
 
    ptr--;
2964
 
  }
2965
 
 
2966
 
  name_ptr = ptr + 1;
2967
 
 
2968
 
  assert(ptr > name);
2969
 
 
2970
 
  ptr--;
2971
 
 
2972
 
  while (ptr >= name && *ptr != '\\' && *ptr != '/') {
2973
 
    ptr--;
2974
 
  }
2975
 
 
2976
 
  db_ptr = ptr + 1;
2977
 
 
2978
 
  memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
2979
 
 
2980
 
  norm_name[name_ptr - db_ptr - 1] = '/';
 
2601
        const char*     name_ptr;
 
2602
        const char*     db_ptr;
 
2603
        const char*     ptr;
 
2604
 
 
2605
        /* Scan name from the end */
 
2606
 
 
2607
        ptr = strchr(name, '\0')-1;
 
2608
 
 
2609
        while (ptr >= name && *ptr != '\\' && *ptr != '/') {
 
2610
                ptr--;
 
2611
        }
 
2612
 
 
2613
        name_ptr = ptr + 1;
 
2614
 
 
2615
        assert(ptr > name);
 
2616
 
 
2617
        ptr--;
 
2618
 
 
2619
        while (ptr >= name && *ptr != '\\' && *ptr != '/') {
 
2620
                ptr--;
 
2621
        }
 
2622
 
 
2623
        db_ptr = ptr + 1;
 
2624
 
 
2625
        memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
 
2626
 
 
2627
        norm_name[name_ptr - db_ptr - 1] = '/';
2981
2628
 
2982
2629
#ifdef __WIN__
2983
 
  innobase_casedn_str(norm_name);
 
2630
        innobase_casedn_str(norm_name);
2984
2631
#endif
2985
2632
}
2986
2633
 
2987
2634
/********************************************************************//**
2988
 
Get the upper limit of the MySQL integral and floating-point type.
2989
 
@return maximum allowed value for the field */
2990
 
static
2991
 
uint64_t
2992
 
innobase_get_int_col_max_value(
2993
 
/*===========================*/
2994
 
        const Field*    field)  /*!< in: MySQL field */
2995
 
{
2996
 
        uint64_t        max_value = 0;
2997
 
 
2998
 
        switch(field->key_type()) {
2999
 
        /* TINY */
3000
 
        case HA_KEYTYPE_BINARY:
3001
 
                max_value = 0xFFULL;
3002
 
                break;
3003
 
        /* LONG */
3004
 
        case HA_KEYTYPE_ULONG_INT:
3005
 
                max_value = 0xFFFFFFFFULL;
3006
 
                break;
3007
 
        case HA_KEYTYPE_LONG_INT:
3008
 
                max_value = 0x7FFFFFFFULL;
3009
 
                break;
3010
 
        /* BIG */
3011
 
        case HA_KEYTYPE_ULONGLONG:
3012
 
                max_value = 0xFFFFFFFFFFFFFFFFULL;
3013
 
                break;
3014
 
        case HA_KEYTYPE_LONGLONG:
3015
 
                max_value = 0x7FFFFFFFFFFFFFFFULL;
3016
 
                break;
3017
 
        case HA_KEYTYPE_DOUBLE:
3018
 
                /* We use the maximum as per IEEE754-2008 standard, 2^53 */
3019
 
                max_value = 0x20000000000000ULL;
3020
 
                break;
3021
 
        default:
3022
 
                ut_error;
3023
 
        }
3024
 
 
3025
 
        return(max_value);
3026
 
}
3027
 
 
3028
 
/*******************************************************************//**
3029
 
This function checks whether the index column information
3030
 
is consistent between KEY info from mysql and that from innodb index.
3031
 
@return TRUE if all column types match. */
3032
 
static
3033
 
ibool
3034
 
innobase_match_index_columns(
3035
 
/*=========================*/
3036
 
        const KeyInfo*          key_info,       /*!< in: Index info
3037
 
                                                from mysql */
3038
 
        const dict_index_t*     index_info)     /*!< in: Index info
3039
 
                                                from Innodb */
3040
 
{
3041
 
        const KeyPartInfo*      key_part;
3042
 
        const KeyPartInfo*      key_end;
3043
 
        const dict_field_t*     innodb_idx_fld;
3044
 
        const dict_field_t*     innodb_idx_fld_end;
3045
 
 
3046
 
        /* Check whether user defined index column count matches */
3047
 
        if (key_info->key_parts != index_info->n_user_defined_cols) {
3048
 
                return(FALSE);
3049
 
        }
3050
 
 
3051
 
        key_part = key_info->key_part;
3052
 
        key_end = key_part + key_info->key_parts;
3053
 
        innodb_idx_fld = index_info->fields;
3054
 
        innodb_idx_fld_end = index_info->fields + index_info->n_fields;
3055
 
 
3056
 
        /* Check each index column's datatype. We do not check
3057
 
        column name because there exists case that index
3058
 
        column name got modified in mysql but such change does not
3059
 
        propagate to InnoDB.
3060
 
        One hidden assumption here is that the index column sequences
3061
 
        are matched up between those in mysql and Innodb. */
3062
 
        for (; key_part != key_end; ++key_part) {
3063
 
                ulint   col_type;
3064
 
                ibool   is_unsigned;
3065
 
                ulint   mtype = innodb_idx_fld->col->mtype;
3066
 
 
3067
 
                /* Need to translate to InnoDB column type before
3068
 
                comparison. */
3069
 
                col_type = get_innobase_type_from_mysql_type(&is_unsigned,
3070
 
                                                             key_part->field);
3071
 
 
3072
 
                /* Ignore Innodb specific system columns. */
3073
 
                while (mtype == DATA_SYS) {
3074
 
                        innodb_idx_fld++;
3075
 
 
3076
 
                        if (innodb_idx_fld >= innodb_idx_fld_end) {
3077
 
                                return(FALSE);
3078
 
                        }
3079
 
                }
3080
 
 
3081
 
                if (col_type != mtype) {
3082
 
                        /* Column Type mismatches */
3083
 
                        return(FALSE);
3084
 
                }
3085
 
 
3086
 
                innodb_idx_fld++;
3087
 
        }
3088
 
 
3089
 
        return(TRUE);
3090
 
}
3091
 
 
3092
 
/*******************************************************************//**
3093
 
This function builds a translation table in INNOBASE_SHARE
3094
 
structure for fast index location with mysql array number from its
3095
 
table->key_info structure. This also provides the necessary translation
3096
 
between the key order in mysql key_info and Innodb ib_table->indexes if
3097
 
they are not fully matched with each other.
3098
 
Note we do not have any mutex protecting the translation table
3099
 
building based on the assumption that there is no concurrent
3100
 
index creation/drop and DMLs that requires index lookup. All table
3101
 
handle will be closed before the index creation/drop.
3102
 
@return TRUE if index translation table built successfully */
3103
 
static
3104
 
ibool
3105
 
innobase_build_index_translation(
3106
 
/*=============================*/
3107
 
        const Table*            table,    /*!< in: table in MySQL data
3108
 
                                          dictionary */
3109
 
        dict_table_t*           ib_table, /*!< in: table in Innodb data
3110
 
                                          dictionary */
3111
 
        INNOBASE_SHARE*         share)    /*!< in/out: share structure
3112
 
                                          where index translation table
3113
 
                                          will be constructed in. */
3114
 
{
3115
 
        ulint           mysql_num_index;
3116
 
        ulint           ib_num_index;
3117
 
        dict_index_t**  index_mapping;
3118
 
        ibool           ret = TRUE;
3119
 
 
3120
 
        mutex_enter(&dict_sys->mutex);
3121
 
 
3122
 
        mysql_num_index = table->getShare()->keys;
3123
 
        ib_num_index = UT_LIST_GET_LEN(ib_table->indexes);
3124
 
 
3125
 
        index_mapping = share->idx_trans_tbl.index_mapping;
3126
 
 
3127
 
        /* If there exists inconsistency between MySQL and InnoDB dictionary
3128
 
        (metadata) information, the number of index defined in MySQL
3129
 
        could exceed that in InnoDB, do not build index translation
3130
 
        table in such case */
3131
 
        if (UNIV_UNLIKELY(ib_num_index < mysql_num_index)) {
3132
 
                ret = FALSE;
3133
 
                goto func_exit;
3134
 
        }
3135
 
 
3136
 
        /* If index entry count is non-zero, nothing has
3137
 
        changed since last update, directly return TRUE */
3138
 
        if (share->idx_trans_tbl.index_count) {
3139
 
                /* Index entry count should still match mysql_num_index */
3140
 
                ut_a(share->idx_trans_tbl.index_count == mysql_num_index);
3141
 
                goto func_exit;
3142
 
        }
3143
 
 
3144
 
        /* The number of index increased, rebuild the mapping table */
3145
 
        if (mysql_num_index > share->idx_trans_tbl.array_size) {
3146
 
                index_mapping = (dict_index_t**) realloc(index_mapping,
3147
 
                                                        mysql_num_index *
3148
 
                                                         sizeof(*index_mapping));
3149
 
 
3150
 
                if (!index_mapping) {
3151
 
                        /* Report an error if index_mapping continues to be
3152
 
                        NULL and mysql_num_index is a non-zero value */
3153
 
                        errmsg_printf(ERRMSG_LVL_ERROR,
3154
 
                                      "InnoDB: fail to allocate memory for "
3155
 
                                        "index translation table. Number of "
3156
 
                                        "Index:%lu, array size:%lu",
3157
 
                                        mysql_num_index,
3158
 
                                        share->idx_trans_tbl.array_size);
3159
 
                        ret = FALSE;
3160
 
                        goto func_exit;
3161
 
                }
3162
 
 
3163
 
                share->idx_trans_tbl.array_size = mysql_num_index;
3164
 
        }
3165
 
 
3166
 
        /* For each index in the mysql key_info array, fetch its
3167
 
        corresponding InnoDB index pointer into index_mapping
3168
 
        array. */
3169
 
        for (ulint count = 0; count < mysql_num_index; count++) {
3170
 
 
3171
 
                /* Fetch index pointers into index_mapping according to mysql
3172
 
                index sequence */
3173
 
                index_mapping[count] = dict_table_get_index_on_name(
3174
 
                        ib_table, table->key_info[count].name);
3175
 
 
3176
 
                if (!index_mapping[count]) {
3177
 
                        errmsg_printf(ERRMSG_LVL_ERROR, "Cannot find index %s in InnoDB "
3178
 
                                        "index dictionary.",
3179
 
                                        table->key_info[count].name);
3180
 
                        ret = FALSE;
3181
 
                        goto func_exit;
3182
 
                }
3183
 
 
3184
 
                /* Double check fetched index has the same
3185
 
                column info as those in mysql key_info. */
3186
 
                if (!innobase_match_index_columns(&table->key_info[count],
3187
 
                                                  index_mapping[count])) {
3188
 
                        errmsg_printf(ERRMSG_LVL_ERROR, "Found index %s whose column info "
3189
 
                                        "does not match that of MySQL.",
3190
 
                                        table->key_info[count].name);
3191
 
                        ret = FALSE;
3192
 
                        goto func_exit;
3193
 
                }
3194
 
        }
3195
 
 
3196
 
        /* Successfully built the translation table */
3197
 
        share->idx_trans_tbl.index_count = mysql_num_index;
3198
 
 
3199
 
func_exit:
3200
 
        if (!ret) {
3201
 
                /* Build translation table failed. */
3202
 
                free(index_mapping);
3203
 
 
3204
 
                share->idx_trans_tbl.array_size = 0;
3205
 
                share->idx_trans_tbl.index_count = 0;
3206
 
                index_mapping = NULL;
3207
 
        }
3208
 
 
3209
 
        share->idx_trans_tbl.index_mapping = index_mapping;
3210
 
 
3211
 
        mutex_exit(&dict_sys->mutex);
3212
 
 
3213
 
        return(ret);
3214
 
}
3215
 
 
3216
 
/*******************************************************************//**
3217
 
This function uses index translation table to quickly locate the
3218
 
requested index structure.
3219
 
Note we do not have mutex protection for the index translatoin table
3220
 
access, it is based on the assumption that there is no concurrent
3221
 
translation table rebuild (fter create/drop index) and DMLs that
3222
 
require index lookup.
3223
 
@return dict_index_t structure for requested index. NULL if
3224
 
fail to locate the index structure. */
3225
 
static
3226
 
dict_index_t*
3227
 
innobase_index_lookup(
3228
 
/*==================*/
3229
 
        INNOBASE_SHARE* share,  /*!< in: share structure for index
3230
 
                                translation table. */
3231
 
        uint            keynr)  /*!< in: index number for the requested
3232
 
                                index */
3233
 
{
3234
 
        if (!share->idx_trans_tbl.index_mapping
3235
 
            || keynr >= share->idx_trans_tbl.index_count) {
3236
 
                return(NULL);
3237
 
        }
3238
 
 
3239
 
        return(share->idx_trans_tbl.index_mapping[keynr]);
3240
 
}
3241
 
 
3242
 
/********************************************************************//**
3243
2635
Set the autoinc column max value. This should only be called once from
3244
 
ha_innobase::open(). Therefore there's no need for a covering lock. */
 
2636
ha_innobase::open(). Therefore there's no need for a covering lock.
 
2637
@return DB_SUCCESS or error code */
3245
2638
UNIV_INTERN
3246
 
void
 
2639
ulint
3247
2640
ha_innobase::innobase_initialize_autoinc()
3248
2641
/*======================================*/
3249
2642
{
3250
 
  uint64_t  auto_inc;
3251
 
  const Field*  field = getTable()->found_next_number_field;
3252
 
 
3253
 
  if (field != NULL) {
3254
 
    auto_inc = innobase_get_int_col_max_value(field);
3255
 
  } else {
3256
 
    /* We have no idea what's been passed in to us as the
3257
 
       autoinc column. We set it to the 0, effectively disabling
3258
 
       updates to the table. */
3259
 
    auto_inc = 0;
3260
 
 
3261
 
    ut_print_timestamp(stderr);
3262
 
    fprintf(stderr, "  InnoDB: Unable to determine the AUTOINC "
3263
 
            "column name\n");
3264
 
  }
3265
 
 
3266
 
  if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
3267
 
    /* If the recovery level is set so high that writes
3268
 
       are disabled we force the AUTOINC counter to 0
3269
 
       value effectively disabling writes to the table.
3270
 
       Secondly, we avoid reading the table in case the read
3271
 
       results in failure due to a corrupted table/index.
3272
 
 
3273
 
       We will not return an error to the client, so that the
3274
 
       tables can be dumped with minimal hassle.  If an error
3275
 
       were returned in this case, the first attempt to read
3276
 
       the table would fail and subsequent SELECTs would succeed. */
3277
 
    auto_inc = 0;
3278
 
  } else if (field == NULL) {
3279
 
    /* This is a far more serious error, best to avoid
3280
 
       opening the table and return failure. */
3281
 
    my_error(ER_AUTOINC_READ_FAILED, MYF(0));
3282
 
  } else {
3283
 
    dict_index_t*       index;
3284
 
    const char* col_name;
3285
 
    uint64_t    read_auto_inc;
3286
 
    ulint               err;
3287
 
 
3288
 
    update_session(getTable()->in_use);
3289
 
    col_name = field->field_name;
3290
 
 
3291
 
    ut_a(prebuilt->trx == session_to_trx(user_session));
3292
 
 
3293
 
    index = innobase_get_index(getTable()->getShare()->next_number_index);
3294
 
 
3295
 
    /* Execute SELECT MAX(col_name) FROM TABLE; */
3296
 
    err = row_search_max_autoinc(index, col_name, &read_auto_inc);
3297
 
 
3298
 
    switch (err) {
3299
 
    case DB_SUCCESS: {
3300
 
      uint64_t col_max_value;
3301
 
 
3302
 
      col_max_value = innobase_get_int_col_max_value(field);
3303
 
 
3304
 
      /* At the this stage we do not know the increment
3305
 
         nor the offset, so use a default increment of 1. */
3306
 
 
3307
 
      auto_inc = innobase_next_autoinc(read_auto_inc, 1, 1, col_max_value);
3308
 
 
3309
 
      break;
3310
 
    }
3311
 
    case DB_RECORD_NOT_FOUND:
3312
 
      ut_print_timestamp(stderr);
3313
 
      fprintf(stderr, "  InnoDB: MySQL and InnoDB data "
3314
 
              "dictionaries are out of sync.\n"
3315
 
              "InnoDB: Unable to find the AUTOINC column "
3316
 
              "%s in the InnoDB table %s.\n"
3317
 
              "InnoDB: We set the next AUTOINC column "
3318
 
              "value to 0,\n"
3319
 
              "InnoDB: in effect disabling the AUTOINC "
3320
 
              "next value generation.\n"
3321
 
              "InnoDB: You can either set the next "
3322
 
              "AUTOINC value explicitly using ALTER TABLE\n"
3323
 
              "InnoDB: or fix the data dictionary by "
3324
 
              "recreating the table.\n",
3325
 
              col_name, index->table->name);
3326
 
 
3327
 
      /* This will disable the AUTOINC generation. */
3328
 
      auto_inc = 0;
3329
 
 
3330
 
      /* We want the open to succeed, so that the user can
3331
 
         take corrective action. ie. reads should succeed but
3332
 
         updates should fail. */
3333
 
      err = DB_SUCCESS;
3334
 
      break;
3335
 
    default:
3336
 
      /* row_search_max_autoinc() should only return
3337
 
         one of DB_SUCCESS or DB_RECORD_NOT_FOUND. */
3338
 
      ut_error;
3339
 
    }
3340
 
  }
3341
 
 
3342
 
  dict_table_autoinc_initialize(prebuilt->table, auto_inc);
 
2643
        dict_index_t*   index;
 
2644
        uint64_t        auto_inc;
 
2645
        const char*     col_name;
 
2646
        ulint           error;
 
2647
 
 
2648
        col_name = table->found_next_number_field->field_name;
 
2649
        index = innobase_get_index(table->s->next_number_index);
 
2650
 
 
2651
        /* Execute SELECT MAX(col_name) FROM TABLE; */
 
2652
        error = row_search_max_autoinc(index, col_name, &auto_inc);
 
2653
 
 
2654
        switch (error) {
 
2655
        case DB_SUCCESS:
 
2656
 
 
2657
                /* At the this stage we don't know the increment
 
2658
                or the offset, so use default inrement of 1. */
 
2659
                ++auto_inc;
 
2660
                break;
 
2661
 
 
2662
        case DB_RECORD_NOT_FOUND:
 
2663
                ut_print_timestamp(stderr);
 
2664
                fprintf(stderr, "  InnoDB: MySQL and InnoDB data "
 
2665
                        "dictionaries are out of sync.\n"
 
2666
                        "InnoDB: Unable to find the AUTOINC column %s in the "
 
2667
                        "InnoDB table %s.\n"
 
2668
                        "InnoDB: We set the next AUTOINC column value to the "
 
2669
                        "maximum possible value,\n"
 
2670
                        "InnoDB: in effect disabling the AUTOINC next value "
 
2671
                        "generation.\n"
 
2672
                        "InnoDB: You can either set the next AUTOINC value "
 
2673
                        "explicitly using ALTER TABLE\n"
 
2674
                        "InnoDB: or fix the data dictionary by recreating "
 
2675
                        "the table.\n",
 
2676
                        col_name, index->table->name);
 
2677
 
 
2678
                auto_inc = 0xFFFFFFFFFFFFFFFFULL;
 
2679
                break;
 
2680
 
 
2681
        default:
 
2682
                return(error);
 
2683
        }
 
2684
 
 
2685
        dict_table_autoinc_initialize(prebuilt->table, auto_inc);
 
2686
 
 
2687
        return(DB_SUCCESS);
3343
2688
}
3344
2689
 
3345
2690
/*****************************************************************//**
3346
2691
Creates and opens a handle to a table which already exists in an InnoDB
3347
2692
database.
3348
 
@return 1 if error, 0 if success */
 
2693
@return 1 if error, 0 if success */
3349
2694
UNIV_INTERN
3350
2695
int
3351
 
ha_innobase::doOpen(const TableIdentifier &identifier,
3352
 
                    int   mode,   /*!< in: not used */
3353
 
                    uint    test_if_locked) /*!< in: not used */
 
2696
ha_innobase::open(
 
2697
/*==============*/
 
2698
        const char*     name,           /*!< in: table name */
 
2699
        int             mode,           /*!< in: not used */
 
2700
        uint            test_if_locked) /*!< in: not used */
3354
2701
{
3355
 
  dict_table_t* ib_table;
3356
 
  char    norm_name[FN_REFLEN];
3357
 
  Session*    session;
3358
 
 
3359
 
  UT_NOT_USED(mode);
3360
 
  UT_NOT_USED(test_if_locked);
3361
 
 
3362
 
  session= getTable()->in_use;
3363
 
 
3364
 
  /* Under some cases Drizzle seems to call this function while
3365
 
  holding btr_search_latch. This breaks the latching order as
3366
 
  we acquire dict_sys->mutex below and leads to a deadlock. */
3367
 
  if (session != NULL) {
3368
 
    getTransactionalEngine()->releaseTemporaryLatches(session);
3369
 
  }
3370
 
 
3371
 
  normalize_table_name(norm_name, identifier.getPath().c_str());
3372
 
 
3373
 
  user_session = NULL;
3374
 
 
3375
 
  if (!(share=get_share(identifier.getPath().c_str()))) {
3376
 
 
3377
 
    return(1);
3378
 
  }
3379
 
 
3380
 
  /* Create buffers for packing the fields of a record. Why
3381
 
  table->stored_rec_length did not work here? Obviously, because char
3382
 
  fields when packed actually became 1 byte longer, when we also
3383
 
  stored the string length as the first byte. */
3384
 
 
3385
 
  upd_and_key_val_buff_len =
3386
 
        getTable()->getShare()->stored_rec_length
3387
 
        + getTable()->getShare()->max_key_length
3388
 
        + MAX_REF_PARTS * 3;
3389
 
 
3390
 
  upd_buff.resize(upd_and_key_val_buff_len);
3391
 
 
3392
 
  if (upd_buff.size() < upd_and_key_val_buff_len)
3393
 
  {
3394
 
    free_share(share);
3395
 
  }
3396
 
 
3397
 
  key_val_buff.resize(upd_and_key_val_buff_len);
3398
 
  if (key_val_buff.size() < upd_and_key_val_buff_len)
3399
 
  {
3400
 
    return(1);
3401
 
  }
3402
 
 
3403
 
  /* Get pointer to a table object in InnoDB dictionary cache */
3404
 
  ib_table = dict_table_get(norm_name, TRUE);
3405
 
  
3406
 
  if (NULL == ib_table) {
3407
 
    errmsg_printf(ERRMSG_LVL_ERROR, "Cannot find or open table %s from\n"
3408
 
        "the internal data dictionary of InnoDB "
3409
 
        "though the .frm file for the\n"
3410
 
        "table exists. Maybe you have deleted and "
3411
 
        "recreated InnoDB data\n"
3412
 
        "files but have forgotten to delete the "
3413
 
        "corresponding .frm files\n"
3414
 
        "of InnoDB tables, or you have moved .frm "
3415
 
        "files to another database?\n"
3416
 
        "or, the table contains indexes that this "
3417
 
        "version of the engine\n"
3418
 
        "doesn't support.\n"
3419
 
        "See " REFMAN "innodb-troubleshooting.html\n"
3420
 
        "how you can resolve the problem.\n",
3421
 
        norm_name);
3422
 
    free_share(share);
3423
 
    upd_buff.resize(0);
3424
 
    key_val_buff.resize(0);
3425
 
    errno = ENOENT;
3426
 
 
3427
 
    return(HA_ERR_NO_SUCH_TABLE);
3428
 
  }
3429
 
 
3430
 
  if (ib_table->ibd_file_missing && !session_tablespace_op(session)) {
3431
 
    errmsg_printf(ERRMSG_LVL_ERROR, "MySQL is trying to open a table handle but "
3432
 
        "the .ibd file for\ntable %s does not exist.\n"
3433
 
        "Have you deleted the .ibd file from the "
3434
 
        "database directory under\nthe MySQL datadir, "
3435
 
        "or have you used DISCARD TABLESPACE?\n"
3436
 
        "See " REFMAN "innodb-troubleshooting.html\n"
3437
 
        "how you can resolve the problem.\n",
3438
 
        norm_name);
3439
 
    free_share(share);
3440
 
    upd_buff.resize(0);
3441
 
    key_val_buff.resize(0);
3442
 
    errno = ENOENT;
3443
 
 
3444
 
    dict_table_decrement_handle_count(ib_table, FALSE);
3445
 
    return(HA_ERR_NO_SUCH_TABLE);
3446
 
  }
3447
 
 
3448
 
  prebuilt = row_create_prebuilt(ib_table);
3449
 
 
3450
 
  prebuilt->mysql_row_len = getTable()->getShare()->stored_rec_length;
3451
 
  prebuilt->default_rec = getTable()->getDefaultValues();
3452
 
  ut_ad(prebuilt->default_rec);
3453
 
 
3454
 
  /* Looks like MySQL-3.23 sometimes has primary key number != 0 */
3455
 
 
3456
 
  primary_key = getTable()->getShare()->getPrimaryKey();
3457
 
  key_used_on_scan = primary_key;
3458
 
 
3459
 
  if (!innobase_build_index_translation(getTable(), ib_table, share)) {
3460
 
    errmsg_printf(ERRMSG_LVL_ERROR, "Build InnoDB index translation table for"
3461
 
                    " Table %s failed", identifier.getPath().c_str());
3462
 
  }
3463
 
 
3464
 
  /* Allocate a buffer for a 'row reference'. A row reference is
3465
 
  a string of bytes of length ref_length which uniquely specifies
3466
 
  a row in our table. Note that MySQL may also compare two row
3467
 
  references for equality by doing a simple memcmp on the strings
3468
 
  of length ref_length! */
3469
 
 
3470
 
  if (!row_table_got_default_clust_index(ib_table)) {
3471
 
 
3472
 
    prebuilt->clust_index_was_generated = FALSE;
3473
 
 
3474
 
    if (UNIV_UNLIKELY(primary_key >= MAX_KEY)) {
3475
 
      errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has a primary key in "
3476
 
                    "InnoDB data dictionary, but not "
3477
 
                    "in MySQL!", identifier.getTableName().c_str());
3478
 
 
3479
 
      /* This mismatch could cause further problems
3480
 
         if not attended, bring this to the user's attention
3481
 
         by printing a warning in addition to log a message
3482
 
         in the errorlog */
3483
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
3484
 
                          ER_NO_SUCH_INDEX,
3485
 
                          "InnoDB: Table %s has a "
3486
 
                          "primary key in InnoDB data "
3487
 
                          "dictionary, but not in "
3488
 
                          "MySQL!", identifier.getTableName().c_str());
3489
 
 
3490
 
      /* If primary_key >= MAX_KEY, its (primary_key)
3491
 
         value could be out of bound if continue to index
3492
 
         into key_info[] array. Find InnoDB primary index,
3493
 
         and assign its key_length to ref_length.
3494
 
         In addition, since MySQL indexes are sorted starting
3495
 
         with primary index, unique index etc., initialize
3496
 
         ref_length to the first index key length in
3497
 
         case we fail to find InnoDB cluster index.
3498
 
 
3499
 
         Please note, this will not resolve the primary
3500
 
         index mismatch problem, other side effects are
3501
 
         possible if users continue to use the table.
3502
 
         However, we allow this table to be opened so
3503
 
         that user can adopt necessary measures for the
3504
 
         mismatch while still being accessible to the table
3505
 
         date. */
3506
 
      ref_length = getTable()->key_info[0].key_length;
3507
 
 
3508
 
      /* Find correspoinding cluster index
3509
 
         key length in MySQL's key_info[] array */
3510
 
      for (ulint i = 0; i < getTable()->getShare()->keys; i++) {
3511
 
        dict_index_t*   index;
3512
 
        index = innobase_get_index(i);
3513
 
        if (dict_index_is_clust(index)) {
3514
 
          ref_length =
3515
 
            getTable()->key_info[i].key_length;
3516
 
        }
3517
 
      }
3518
 
    } else {
3519
 
      /* MySQL allocates the buffer for ref.
3520
 
         key_info->key_length includes space for all key
3521
 
         columns + one byte for each column that may be
3522
 
         NULL. ref_length must be as exact as possible to
3523
 
         save space, because all row reference buffers are
3524
 
         allocated based on ref_length. */
3525
 
 
3526
 
      ref_length = getTable()->key_info[primary_key].key_length;
3527
 
    }
3528
 
  } else {
3529
 
    if (primary_key != MAX_KEY) {
3530
 
      errmsg_printf(ERRMSG_LVL_ERROR,
3531
 
                    "Table %s has no primary key in InnoDB data "
3532
 
                    "dictionary, but has one in MySQL! If you "
3533
 
                    "created the table with a MySQL version < "
3534
 
                    "3.23.54 and did not define a primary key, "
3535
 
                    "but defined a unique key with all non-NULL "
3536
 
                    "columns, then MySQL internally treats that "
3537
 
                    "key as the primary key. You can fix this "
3538
 
                    "error by dump + DROP + CREATE + reimport "
3539
 
                    "of the table.", identifier.getTableName().c_str());
3540
 
 
3541
 
      /* This mismatch could cause further problems
3542
 
         if not attended, bring this to the user attention
3543
 
         by printing a warning in addition to log a message
3544
 
         in the errorlog */
3545
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
3546
 
                          ER_NO_SUCH_INDEX,
3547
 
                          "InnoDB: Table %s has no "
3548
 
                          "primary key in InnoDB data "
3549
 
                          "dictionary, but has one in "
3550
 
                          "MySQL!", identifier.getTableName().c_str());
3551
 
    }
3552
 
 
3553
 
    prebuilt->clust_index_was_generated = TRUE;
3554
 
 
3555
 
    ref_length = DATA_ROW_ID_LEN;
3556
 
 
3557
 
    /* If we automatically created the clustered index, then
3558
 
    MySQL does not know about it, and MySQL must NOT be aware
3559
 
    of the index used on scan, to make it avoid checking if we
3560
 
    update the column of the index. That is why we assert below
3561
 
    that key_used_on_scan is the undefined value MAX_KEY.
3562
 
    The column is the row id in the automatical generation case,
3563
 
    and it will never be updated anyway. */
3564
 
 
3565
 
    if (key_used_on_scan != MAX_KEY) {
3566
 
      errmsg_printf(ERRMSG_LVL_WARN, 
3567
 
        "Table %s key_used_on_scan is %lu even "
3568
 
        "though there is no primary key inside "
3569
 
        "InnoDB.", identifier.getTableName().c_str(), (ulong) key_used_on_scan);
3570
 
    }
3571
 
  }
3572
 
 
3573
 
  /* Index block size in InnoDB: used by MySQL in query optimization */
3574
 
  stats.block_size = 16 * 1024;
3575
 
 
3576
 
  /* Init table lock structure */
3577
 
  lock.init(&share->lock);
3578
 
 
3579
 
  if (prebuilt->table) {
3580
 
    /* We update the highest file format in the system table
3581
 
    space, if this table has higher file format setting. */
3582
 
 
3583
 
    char changed_file_format_max[100];
3584
 
    strcpy(changed_file_format_max, innobase_file_format_max.c_str());
3585
 
    trx_sys_file_format_max_upgrade((const char **)&changed_file_format_max,
3586
 
      dict_table_get_format(prebuilt->table));
3587
 
    innobase_file_format_max= changed_file_format_max;
3588
 
  }
3589
 
 
3590
 
  /* Only if the table has an AUTOINC column. */
3591
 
  if (prebuilt->table != NULL && getTable()->found_next_number_field != NULL) {
3592
 
 
3593
 
    dict_table_autoinc_lock(prebuilt->table);
3594
 
 
3595
 
    /* Since a table can already be "open" in InnoDB's internal
3596
 
    data dictionary, we only init the autoinc counter once, the
3597
 
    first time the table is loaded. We can safely reuse the
3598
 
    autoinc value from a previous Drizzle open. */
3599
 
    if (dict_table_autoinc_read(prebuilt->table) == 0) {
3600
 
 
3601
 
      innobase_initialize_autoinc();
3602
 
    }
3603
 
 
3604
 
    dict_table_autoinc_unlock(prebuilt->table);
3605
 
  }
3606
 
 
3607
 
  info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
3608
 
 
3609
 
  return(0);
 
2702
        dict_table_t*   ib_table;
 
2703
        char            norm_name[1000];
 
2704
        Session*                session;
 
2705
        ulint           retries = 0;
 
2706
        char*           is_part = NULL;
 
2707
 
 
2708
        UT_NOT_USED(mode);
 
2709
        UT_NOT_USED(test_if_locked);
 
2710
 
 
2711
        session = ha_session();
 
2712
 
 
2713
        /* Under some cases Drizzle seems to call this function while
 
2714
        holding btr_search_latch. This breaks the latching order as
 
2715
        we acquire dict_sys->mutex below and leads to a deadlock. */
 
2716
        if (session != NULL) {
 
2717
                engine->release_temporary_latches(session);
 
2718
        }
 
2719
 
 
2720
        normalize_table_name(norm_name, name);
 
2721
 
 
2722
        user_session = NULL;
 
2723
 
 
2724
        if (!(share=get_share(name))) {
 
2725
 
 
2726
                return(1);
 
2727
        }
 
2728
 
 
2729
        /* Create buffers for packing the fields of a record. Why
 
2730
        table->stored_rec_length did not work here? Obviously, because char
 
2731
        fields when packed actually became 1 byte longer, when we also
 
2732
        stored the string length as the first byte. */
 
2733
 
 
2734
        upd_and_key_val_buff_len =
 
2735
                                table->s->stored_rec_length
 
2736
                                + table->s->max_key_length
 
2737
                                + MAX_REF_PARTS * 3;
 
2738
        if (!(unsigned char*) memory::multi_malloc(false,
 
2739
                        &upd_buff, upd_and_key_val_buff_len,
 
2740
                        &key_val_buff, upd_and_key_val_buff_len,
 
2741
                        NULL)) {
 
2742
                free_share(share);
 
2743
 
 
2744
                return(1);
 
2745
        }
 
2746
 
 
2747
        /* We look for pattern #P# to see if the table is partitioned
 
2748
        MySQL table. The retry logic for partitioned tables is a
 
2749
        workaround for http://bugs.mysql.com/bug.php?id=33349. Look
 
2750
        at support issue https://support.mysql.com/view.php?id=21080
 
2751
        for more details. */
 
2752
        is_part = strstr(norm_name, "#P#");
 
2753
retry:
 
2754
        /* Get pointer to a table object in InnoDB dictionary cache */
 
2755
        ib_table = dict_table_get(norm_name, TRUE);
 
2756
        
 
2757
        if (NULL == ib_table) {
 
2758
                if (is_part && retries < 10) {
 
2759
                        ++retries;
 
2760
                        os_thread_sleep(100000);
 
2761
                        goto retry;
 
2762
                }
 
2763
 
 
2764
                if (is_part) {
 
2765
                        errmsg_printf(ERRMSG_LVL_ERROR, "Failed to open table %s after "
 
2766
                                        "%lu attemtps.\n", norm_name,
 
2767
                                        retries);
 
2768
                }
 
2769
 
 
2770
                errmsg_printf(ERRMSG_LVL_ERROR, "Cannot find or open table %s from\n"
 
2771
                                "the internal data dictionary of InnoDB "
 
2772
                                "though the .frm file for the\n"
 
2773
                                "table exists. Maybe you have deleted and "
 
2774
                                "recreated InnoDB data\n"
 
2775
                                "files but have forgotten to delete the "
 
2776
                                "corresponding .frm files\n"
 
2777
                                "of InnoDB tables, or you have moved .frm "
 
2778
                                "files to another database?\n"
 
2779
                                "or, the table contains indexes that this "
 
2780
                                "version of the engine\n"
 
2781
                                "doesn't support.\n"
 
2782
                                "See " REFMAN "innodb-troubleshooting.html\n"
 
2783
                                "how you can resolve the problem.\n",
 
2784
                                norm_name);
 
2785
                free_share(share);
 
2786
                free(upd_buff);
 
2787
                errno = ENOENT;
 
2788
 
 
2789
                return(HA_ERR_NO_SUCH_TABLE);
 
2790
        }
 
2791
 
 
2792
        if (ib_table->ibd_file_missing && !session_tablespace_op(session)) {
 
2793
                errmsg_printf(ERRMSG_LVL_ERROR, "MySQL is trying to open a table handle but "
 
2794
                                "the .ibd file for\ntable %s does not exist.\n"
 
2795
                                "Have you deleted the .ibd file from the "
 
2796
                                "database directory under\nthe MySQL datadir, "
 
2797
                                "or have you used DISCARD TABLESPACE?\n"
 
2798
                                "See " REFMAN "innodb-troubleshooting.html\n"
 
2799
                                "how you can resolve the problem.\n",
 
2800
                                norm_name);
 
2801
                free_share(share);
 
2802
                free(upd_buff);
 
2803
                errno = ENOENT;
 
2804
 
 
2805
                dict_table_decrement_handle_count(ib_table, FALSE);
 
2806
                return(HA_ERR_NO_SUCH_TABLE);
 
2807
        }
 
2808
 
 
2809
        prebuilt = row_create_prebuilt(ib_table);
 
2810
 
 
2811
        prebuilt->mysql_row_len = table->s->stored_rec_length;
 
2812
        prebuilt->default_rec = table->s->default_values;
 
2813
        ut_ad(prebuilt->default_rec);
 
2814
 
 
2815
        /* Looks like MySQL-3.23 sometimes has primary key number != 0 */
 
2816
 
 
2817
        primary_key = table->s->primary_key;
 
2818
        key_used_on_scan = primary_key;
 
2819
 
 
2820
        /* Allocate a buffer for a 'row reference'. A row reference is
 
2821
        a string of bytes of length ref_length which uniquely specifies
 
2822
        a row in our table. Note that MySQL may also compare two row
 
2823
        references for equality by doing a simple memcmp on the strings
 
2824
        of length ref_length! */
 
2825
 
 
2826
        if (!row_table_got_default_clust_index(ib_table)) {
 
2827
                if (primary_key >= MAX_KEY) {
 
2828
                  errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has a primary key in InnoDB data "
 
2829
                                  "dictionary, but not in MySQL!", name);
 
2830
                }
 
2831
 
 
2832
                prebuilt->clust_index_was_generated = FALSE;
 
2833
 
 
2834
                /* MySQL allocates the buffer for ref. key_info->key_length
 
2835
                includes space for all key columns + one byte for each column
 
2836
                that may be NULL. ref_length must be as exact as possible to
 
2837
                save space, because all row reference buffers are allocated
 
2838
                based on ref_length. */
 
2839
 
 
2840
                ref_length = table->key_info[primary_key].key_length;
 
2841
        } else {
 
2842
                if (primary_key != MAX_KEY) {
 
2843
                  errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has no primary key in InnoDB data "
 
2844
                                  "dictionary, but has one in MySQL! If you "
 
2845
                                  "created the table with a MySQL version < "
 
2846
                                  "3.23.54 and did not define a primary key, "
 
2847
                                  "but defined a unique key with all non-NULL "
 
2848
                                  "columns, then MySQL internally treats that "
 
2849
                                  "key as the primary key. You can fix this "
 
2850
                                  "error by dump + DROP + CREATE + reimport "
 
2851
                                  "of the table.", name);
 
2852
                }
 
2853
 
 
2854
                prebuilt->clust_index_was_generated = TRUE;
 
2855
 
 
2856
                ref_length = DATA_ROW_ID_LEN;
 
2857
 
 
2858
                /* If we automatically created the clustered index, then
 
2859
                MySQL does not know about it, and MySQL must NOT be aware
 
2860
                of the index used on scan, to make it avoid checking if we
 
2861
                update the column of the index. That is why we assert below
 
2862
                that key_used_on_scan is the undefined value MAX_KEY.
 
2863
                The column is the row id in the automatical generation case,
 
2864
                and it will never be updated anyway. */
 
2865
 
 
2866
                if (key_used_on_scan != MAX_KEY) {
 
2867
                        errmsg_printf(ERRMSG_LVL_WARN, 
 
2868
                                "Table %s key_used_on_scan is %lu even "
 
2869
                                "though there is no primary key inside "
 
2870
                                "InnoDB.", name, (ulong) key_used_on_scan);
 
2871
                }
 
2872
        }
 
2873
 
 
2874
        /* Index block size in InnoDB: used by MySQL in query optimization */
 
2875
        stats.block_size = 16 * 1024;
 
2876
 
 
2877
        /* Init table lock structure */
 
2878
        thr_lock_data_init(&share->lock,&lock,(void*) 0);
 
2879
 
 
2880
        if (prebuilt->table) {
 
2881
                /* We update the highest file format in the system table
 
2882
                space, if this table has higher file format setting. */
 
2883
 
 
2884
                trx_sys_file_format_max_upgrade(
 
2885
                        (const char**) &innobase_file_format_check,
 
2886
                        dict_table_get_format(prebuilt->table));
 
2887
        }
 
2888
 
 
2889
        info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
 
2890
 
 
2891
        /* Only if the table has an AUTOINC column. */
 
2892
        if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
 
2893
                ulint   error;
 
2894
 
 
2895
                dict_table_autoinc_lock(prebuilt->table);
 
2896
 
 
2897
                /* Since a table can already be "open" in InnoDB's internal
 
2898
                data dictionary, we only init the autoinc counter once, the
 
2899
                first time the table is loaded. We can safely reuse the
 
2900
                autoinc value from a previous Drizzle open. */
 
2901
                if (dict_table_autoinc_read(prebuilt->table) == 0) {
 
2902
 
 
2903
                        error = innobase_initialize_autoinc();
 
2904
                        ut_a(error == DB_SUCCESS);
 
2905
                }
 
2906
 
 
2907
                dict_table_autoinc_unlock(prebuilt->table);
 
2908
        }
 
2909
 
 
2910
        return(0);
3610
2911
}
3611
2912
 
3612
2913
UNIV_INTERN
3613
2914
uint32_t
3614
2915
InnobaseEngine::max_supported_key_part_length() const
3615
2916
{
3616
 
  return(DICT_MAX_INDEX_COL_LEN - 1);
 
2917
        return(DICT_MAX_INDEX_COL_LEN - 1);
3617
2918
}
3618
2919
 
3619
2920
/******************************************************************//**
3620
2921
Closes a handle to an InnoDB table.
3621
 
@return 0 */
 
2922
@return 0 */
3622
2923
UNIV_INTERN
3623
2924
int
3624
2925
ha_innobase::close(void)
3625
2926
/*====================*/
3626
2927
{
3627
 
  Session*  session;
3628
 
 
3629
 
  session= getTable()->in_use;
3630
 
  if (session != NULL) {
3631
 
    getTransactionalEngine()->releaseTemporaryLatches(session);
3632
 
  }
3633
 
 
3634
 
  row_prebuilt_free(prebuilt, FALSE);
3635
 
 
3636
 
  upd_buff.clear();
3637
 
  key_val_buff.clear();
3638
 
  free_share(share);
3639
 
 
3640
 
  /* Tell InnoDB server that there might be work for
3641
 
  utility threads: */
3642
 
 
3643
 
  srv_active_wake_master_thread();
3644
 
 
3645
 
  return(0);
 
2928
        Session*        session;
 
2929
 
 
2930
        session = ha_session();
 
2931
        if (session != NULL) {
 
2932
                engine->release_temporary_latches(session);
 
2933
        }
 
2934
 
 
2935
        row_prebuilt_free(prebuilt, FALSE);
 
2936
 
 
2937
        free(upd_buff);
 
2938
        free_share(share);
 
2939
 
 
2940
        /* Tell InnoDB server that there might be work for
 
2941
        utility threads: */
 
2942
 
 
2943
        srv_active_wake_master_thread();
 
2944
 
 
2945
        return(0);
3646
2946
}
3647
2947
 
3648
2948
/* The following accessor functions should really be inside MySQL code! */
3649
2949
 
3650
2950
/**************************************************************//**
3651
2951
Gets field offset for a field in a table.
3652
 
@return offset */
 
2952
@return offset */
3653
2953
static inline
3654
2954
uint
3655
2955
get_field_offset(
3656
2956
/*=============*/
3657
 
  Table*  table,  /*!< in: MySQL table object */
3658
 
  Field*  field)  /*!< in: MySQL field object */
 
2957
        Table*  table,  /*!< in: MySQL table object */
 
2958
        Field*  field)  /*!< in: MySQL field object */
3659
2959
{
3660
 
  return((uint) (field->ptr - table->getInsertRecord()));
 
2960
        return((uint) (field->ptr - table->record[0]));
3661
2961
}
3662
2962
 
3663
2963
/**************************************************************//**
3664
2964
Checks if a field in a record is SQL NULL. Uses the record format
3665
2965
information in table to track the null bit in record.
3666
 
@return 1 if NULL, 0 otherwise */
 
2966
@return 1 if NULL, 0 otherwise */
3667
2967
static inline
3668
2968
uint
3669
2969
field_in_record_is_null(
3670
2970
/*====================*/
3671
 
  Table*  table,  /*!< in: MySQL table object */
3672
 
  Field*  field,  /*!< in: MySQL field object */
3673
 
  char* record) /*!< in: a row in MySQL format */
 
2971
        Table*  table,  /*!< in: MySQL table object */
 
2972
        Field*  field,  /*!< in: MySQL field object */
 
2973
        char*   record) /*!< in: a row in MySQL format */
3674
2974
{
3675
 
  int null_offset;
3676
 
 
3677
 
  if (!field->null_ptr) {
3678
 
 
3679
 
    return(0);
3680
 
  }
3681
 
 
3682
 
  null_offset = (uint) ((char*) field->null_ptr
3683
 
          - (char*) table->getInsertRecord());
3684
 
 
3685
 
  if (record[null_offset] & field->null_bit) {
3686
 
 
3687
 
    return(1);
3688
 
  }
3689
 
 
3690
 
  return(0);
 
2975
        int     null_offset;
 
2976
 
 
2977
        if (!field->null_ptr) {
 
2978
 
 
2979
                return(0);
 
2980
        }
 
2981
 
 
2982
        null_offset = (uint) ((char*) field->null_ptr
 
2983
                                        - (char*) table->record[0]);
 
2984
 
 
2985
        if (record[null_offset] & field->null_bit) {
 
2986
 
 
2987
                return(1);
 
2988
        }
 
2989
 
 
2990
        return(0);
3691
2991
}
3692
2992
 
3693
2993
/**************************************************************//**
3697
2997
void
3698
2998
set_field_in_record_to_null(
3699
2999
/*========================*/
3700
 
  Table*  table,  /*!< in: MySQL table object */
3701
 
  Field*  field,  /*!< in: MySQL field object */
3702
 
  char* record) /*!< in: a row in MySQL format */
 
3000
        Table*  table,  /*!< in: MySQL table object */
 
3001
        Field*  field,  /*!< in: MySQL field object */
 
3002
        char*   record) /*!< in: a row in MySQL format */
3703
3003
{
3704
 
  int null_offset;
3705
 
 
3706
 
  null_offset = (uint) ((char*) field->null_ptr
3707
 
          - (char*) table->getInsertRecord());
3708
 
 
3709
 
  record[null_offset] = record[null_offset] | field->null_bit;
 
3004
        int     null_offset;
 
3005
 
 
3006
        null_offset = (uint) ((char*) field->null_ptr
 
3007
                                        - (char*) table->record[0]);
 
3008
 
 
3009
        record[null_offset] = record[null_offset] | field->null_bit;
3710
3010
}
3711
3011
 
3712
3012
/*************************************************************//**
3714
3014
is such that we must use MySQL code to compare them. NOTE that the prototype
3715
3015
of this function is in rem0cmp.c in InnoDB source code! If you change this
3716
3016
function, remember to update the prototype there!
3717
 
@return 1, 0, -1, if a is greater, equal, less than b, respectively */
 
3017
@return 1, 0, -1, if a is greater, equal, less than b, respectively */
3718
3018
extern "C" UNIV_INTERN
3719
3019
int
3720
3020
innobase_mysql_cmp(
3721
3021
/*===============*/
3722
 
  int   mysql_type, /*!< in: MySQL type */
3723
 
  uint    charset_number, /*!< in: number of the charset */
3724
 
  const unsigned char* a,   /*!< in: data field */
3725
 
  unsigned int  a_length, /*!< in: data field length,
3726
 
          not UNIV_SQL_NULL */
3727
 
  const unsigned char* b,   /* in: data field */
3728
 
  unsigned int  b_length);  /* in: data field length,
3729
 
          not UNIV_SQL_NULL */
 
3022
        int             mysql_type,     /*!< in: MySQL type */
 
3023
        uint            charset_number, /*!< in: number of the charset */
 
3024
        const unsigned char* a,         /*!< in: data field */
 
3025
        unsigned int    a_length,       /*!< in: data field length,
 
3026
                                        not UNIV_SQL_NULL */
 
3027
        const unsigned char* b,         /* in: data field */
 
3028
        unsigned int    b_length);      /* in: data field length,
 
3029
                                        not UNIV_SQL_NULL */
3730
3030
 
3731
3031
int
3732
3032
innobase_mysql_cmp(
3733
3033
/*===============*/
3734
 
          /* out: 1, 0, -1, if a is greater, equal, less than b, respectively */
3735
 
  int   mysql_type, /* in: MySQL type */
3736
 
  uint    charset_number, /* in: number of the charset */
3737
 
  const unsigned char* a,   /* in: data field */
3738
 
  unsigned int  a_length, /* in: data field length, not UNIV_SQL_NULL */
3739
 
  const unsigned char* b,   /* in: data field */
3740
 
  unsigned int  b_length) /* in: data field length, not UNIV_SQL_NULL */
 
3034
                                        /* out: 1, 0, -1, if a is greater,
 
3035
                                        equal, less than b, respectively */
 
3036
        int             mysql_type,     /* in: MySQL type */
 
3037
        uint            charset_number, /* in: number of the charset */
 
3038
        const unsigned char* a,         /* in: data field */
 
3039
        unsigned int    a_length,       /* in: data field length,
 
3040
                                        not UNIV_SQL_NULL */
 
3041
        const unsigned char* b,         /* in: data field */
 
3042
        unsigned int    b_length)       /* in: data field length,
 
3043
                                        not UNIV_SQL_NULL */
3741
3044
{
3742
 
  const CHARSET_INFO* charset;
3743
 
  enum_field_types  mysql_tp;
3744
 
  int     ret;
3745
 
 
3746
 
  assert(a_length != UNIV_SQL_NULL);
3747
 
  assert(b_length != UNIV_SQL_NULL);
3748
 
 
3749
 
  mysql_tp = (enum_field_types) mysql_type;
3750
 
 
3751
 
  switch (mysql_tp) {
3752
 
 
3753
 
  case DRIZZLE_TYPE_BLOB:
3754
 
  case DRIZZLE_TYPE_VARCHAR:
3755
 
    /* Use the charset number to pick the right charset struct for
3756
 
      the comparison. Since the MySQL function get_charset may be
3757
 
      slow before Bar removes the mutex operation there, we first
3758
 
      look at 2 common charsets directly. */
3759
 
 
3760
 
    if (charset_number == default_charset_info->number) {
3761
 
      charset = default_charset_info;
3762
 
    } else {
3763
 
      charset = get_charset(charset_number);
3764
 
 
3765
 
      if (charset == NULL) {
3766
 
        errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB needs charset %lu for doing "
3767
 
                      "a comparison, but MySQL cannot "
3768
 
                      "find that charset.",
3769
 
                      (ulong) charset_number);
3770
 
        ut_a(0);
3771
 
      }
3772
 
    }
3773
 
 
3774
 
    /* Starting from 4.1.3, we use strnncollsp() in comparisons of
3775
 
      non-latin1_swedish_ci strings. NOTE that the collation order
3776
 
      changes then: 'b\0\0...' is ordered BEFORE 'b  ...'. Users
3777
 
      having indexes on such data need to rebuild their tables! */
3778
 
 
3779
 
    ret = charset->coll->strnncollsp(charset,
3780
 
                                     a, a_length,
3781
 
                                     b, b_length, 0);
3782
 
    if (ret < 0) {
3783
 
      return(-1);
3784
 
    } else if (ret > 0) {
3785
 
      return(1);
3786
 
    } else {
3787
 
      return(0);
3788
 
    }
3789
 
  default:
3790
 
    ut_error;
3791
 
  }
3792
 
 
3793
 
  return(0);
 
3045
        const CHARSET_INFO*     charset;
 
3046
        enum_field_types        mysql_tp;
 
3047
        int                     ret;
 
3048
 
 
3049
        assert(a_length != UNIV_SQL_NULL);
 
3050
        assert(b_length != UNIV_SQL_NULL);
 
3051
 
 
3052
        mysql_tp = (enum_field_types) mysql_type;
 
3053
 
 
3054
        switch (mysql_tp) {
 
3055
 
 
3056
        case DRIZZLE_TYPE_BLOB:
 
3057
        case DRIZZLE_TYPE_VARCHAR:
 
3058
                /* Use the charset number to pick the right charset struct for
 
3059
                the comparison. Since the MySQL function get_charset may be
 
3060
                slow before Bar removes the mutex operation there, we first
 
3061
                look at 2 common charsets directly. */
 
3062
 
 
3063
                if (charset_number == default_charset_info->number) {
 
3064
                        charset = default_charset_info;
 
3065
                } else {
 
3066
                        charset = get_charset(charset_number);
 
3067
 
 
3068
                        if (charset == NULL) {
 
3069
                          errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB needs charset %lu for doing "
 
3070
                                          "a comparison, but MySQL cannot "
 
3071
                                          "find that charset.",
 
3072
                                          (ulong) charset_number);
 
3073
                                ut_a(0);
 
3074
                        }
 
3075
                }
 
3076
 
 
3077
                /* Starting from 4.1.3, we use strnncollsp() in comparisons of
 
3078
                non-latin1_swedish_ci strings. NOTE that the collation order
 
3079
                changes then: 'b\0\0...' is ordered BEFORE 'b  ...'. Users
 
3080
                having indexes on such data need to rebuild their tables! */
 
3081
 
 
3082
                ret = charset->coll->strnncollsp(charset,
 
3083
                                  a, a_length,
 
3084
                                                 b, b_length, 0);
 
3085
                if (ret < 0) {
 
3086
                        return(-1);
 
3087
                } else if (ret > 0) {
 
3088
                        return(1);
 
3089
                } else {
 
3090
                        return(0);
 
3091
                }
 
3092
        default:
 
3093
                ut_error;
 
3094
        }
 
3095
 
 
3096
        return(0);
3794
3097
}
3795
3098
 
3796
3099
/**************************************************************//**
3797
3100
Converts a MySQL type to an InnoDB type. Note that this function returns
3798
3101
the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
3799
3102
VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'.
3800
 
@return DATA_BINARY, DATA_VARCHAR, ... */
 
3103
@return DATA_BINARY, DATA_VARCHAR, ... */
3801
3104
extern "C" UNIV_INTERN
3802
3105
ulint
3803
3106
get_innobase_type_from_mysql_type(
3804
3107
/*==============================*/
3805
 
  ulint*    unsigned_flag,  /*!< out: DATA_UNSIGNED if an
3806
 
          'unsigned type';
3807
 
          at least ENUM and SET,
3808
 
          and unsigned integer
3809
 
          types are 'unsigned types' */
3810
 
  const void* f)    /*!< in: MySQL Field */
 
3108
        ulint*          unsigned_flag,  /*!< out: DATA_UNSIGNED if an
 
3109
                                        'unsigned type';
 
3110
                                        at least ENUM and SET,
 
3111
                                        and unsigned integer
 
3112
                                        types are 'unsigned types' */
 
3113
        const void*     f)              /*!< in: MySQL Field */
3811
3114
{
3812
 
  const class Field* field = reinterpret_cast<const class Field*>(f);
3813
 
 
3814
 
  /* The following asserts try to check that the MySQL type code fits in
3815
 
  8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
3816
 
  the type */
3817
 
 
3818
 
  assert((ulint)DRIZZLE_TYPE_DOUBLE < 256);
3819
 
 
3820
 
  if (field->flags & UNSIGNED_FLAG) {
3821
 
 
3822
 
    *unsigned_flag = DATA_UNSIGNED;
3823
 
  } else {
3824
 
    *unsigned_flag = 0;
3825
 
  }
3826
 
 
3827
 
  if (field->real_type() == DRIZZLE_TYPE_ENUM)
3828
 
  {
3829
 
    /* MySQL has field->type() a string type for these, but the
3830
 
    data is actually internally stored as an unsigned integer
3831
 
    code! */
3832
 
 
3833
 
    *unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
3834
 
            flag set to zero, even though
3835
 
            internally this is an unsigned
3836
 
            integer type */
3837
 
    return(DATA_INT);
3838
 
  }
3839
 
 
3840
 
  switch (field->type()) {
3841
 
    /* NOTE that we only allow string types in DATA_DRIZZLE and
3842
 
    DATA_VARDRIZZLE */
3843
 
  case DRIZZLE_TYPE_VARCHAR:    /* new >= 5.0.3 true VARCHAR */
3844
 
    if (field->binary()) {
3845
 
      return(DATA_BINARY);
3846
 
    } else {
3847
 
      return(DATA_VARMYSQL);
3848
 
    }
3849
 
  case DRIZZLE_TYPE_DECIMAL:
3850
 
    return(DATA_FIXBINARY);
3851
 
  case DRIZZLE_TYPE_LONG:
3852
 
  case DRIZZLE_TYPE_LONGLONG:
3853
 
  case DRIZZLE_TYPE_DATETIME:
3854
 
  case DRIZZLE_TYPE_DATE:
3855
 
  case DRIZZLE_TYPE_TIMESTAMP:
3856
 
  case DRIZZLE_TYPE_ENUM:
3857
 
    return(DATA_INT);
3858
 
  case DRIZZLE_TYPE_DOUBLE:
3859
 
    return(DATA_DOUBLE);
3860
 
  case DRIZZLE_TYPE_BLOB:
3861
 
    return(DATA_BLOB);
3862
 
  case DRIZZLE_TYPE_UUID:
3863
 
    return(DATA_FIXBINARY);
3864
 
  case DRIZZLE_TYPE_NULL:
3865
 
    ut_error;
3866
 
  }
3867
 
 
3868
 
  return(0);
 
3115
        const class Field* field = reinterpret_cast<const class Field*>(f);
 
3116
 
 
3117
        /* The following asserts try to check that the MySQL type code fits in
 
3118
        8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
 
3119
        the type */
 
3120
 
 
3121
        assert((ulint)DRIZZLE_TYPE_DOUBLE < 256);
 
3122
 
 
3123
        if (field->flags & UNSIGNED_FLAG) {
 
3124
 
 
3125
                *unsigned_flag = DATA_UNSIGNED;
 
3126
        } else {
 
3127
                *unsigned_flag = 0;
 
3128
        }
 
3129
 
 
3130
        if (field->real_type() == DRIZZLE_TYPE_ENUM)
 
3131
        {
 
3132
                /* MySQL has field->type() a string type for these, but the
 
3133
                data is actually internally stored as an unsigned integer
 
3134
                code! */
 
3135
 
 
3136
                *unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
 
3137
                                                flag set to zero, even though
 
3138
                                                internally this is an unsigned
 
3139
                                                integer type */
 
3140
                return(DATA_INT);
 
3141
        }
 
3142
 
 
3143
        switch (field->type()) {
 
3144
                /* NOTE that we only allow string types in DATA_DRIZZLE and
 
3145
                DATA_VARDRIZZLE */
 
3146
        case DRIZZLE_TYPE_VARCHAR:    /* new >= 5.0.3 true VARCHAR */
 
3147
                if (field->binary()) {
 
3148
                        return(DATA_BINARY);
 
3149
                } else {
 
3150
                        return(DATA_VARMYSQL);
 
3151
                }
 
3152
        case DRIZZLE_TYPE_DECIMAL:
 
3153
                return(DATA_FIXBINARY);
 
3154
        case DRIZZLE_TYPE_LONG:
 
3155
        case DRIZZLE_TYPE_LONGLONG:
 
3156
        case DRIZZLE_TYPE_DATETIME:
 
3157
        case DRIZZLE_TYPE_DATE:
 
3158
        case DRIZZLE_TYPE_TIMESTAMP:
 
3159
                return(DATA_INT);
 
3160
        case DRIZZLE_TYPE_DOUBLE:
 
3161
                return(DATA_DOUBLE);
 
3162
        case DRIZZLE_TYPE_BLOB:
 
3163
                return(DATA_BLOB);
 
3164
        default:
 
3165
                ut_error;
 
3166
        }
 
3167
 
 
3168
        return(0);
3869
3169
}
3870
3170
 
3871
3171
/*******************************************************************//**
3875
3175
void
3876
3176
innobase_write_to_2_little_endian(
3877
3177
/*==============================*/
3878
 
  byte* buf,  /*!< in: where to store */
3879
 
  ulint val)  /*!< in: value to write, must be < 64k */
 
3178
        byte*   buf,    /*!< in: where to store */
 
3179
        ulint   val)    /*!< in: value to write, must be < 64k */
3880
3180
{
3881
 
  ut_a(val < 256 * 256);
 
3181
        ut_a(val < 256 * 256);
3882
3182
 
3883
 
  buf[0] = (byte)(val & 0xFF);
3884
 
  buf[1] = (byte)(val / 256);
 
3183
        buf[0] = (byte)(val & 0xFF);
 
3184
        buf[1] = (byte)(val / 256);
3885
3185
}
3886
3186
 
3887
3187
/*******************************************************************//**
3888
3188
Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
3889
3189
storage format.
3890
 
@return value */
 
3190
@return value */
3891
3191
static inline
3892
3192
uint
3893
3193
innobase_read_from_2_little_endian(
3894
3194
/*===============================*/
3895
 
  const unsigned char*  buf)  /*!< in: from where to read */
 
3195
        const unsigned char*    buf)    /*!< in: from where to read */
3896
3196
{
3897
 
  return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
 
3197
        return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
3898
3198
}
3899
3199
 
3900
3200
/*******************************************************************//**
3901
3201
Stores a key value for a row to a buffer.
3902
 
@return key value length as stored in buff */
 
3202
@return key value length as stored in buff */
3903
3203
UNIV_INTERN
3904
3204
uint
3905
3205
ha_innobase::store_key_val_for_row(
3906
3206
/*===============================*/
3907
 
  uint    keynr,  /*!< in: key number */
3908
 
  char*   buff, /*!< in/out: buffer for the key value (in MySQL
3909
 
        format) */
3910
 
  uint    buff_len,/*!< in: buffer length */
3911
 
  const unsigned char*  record)/*!< in: row in MySQL format */
 
3207
        uint            keynr,  /*!< in: key number */
 
3208
        char*           buff,   /*!< in/out: buffer for the key value (in MySQL
 
3209
                                format) */
 
3210
        uint            buff_len,/*!< in: buffer length */
 
3211
        const unsigned char*    record)/*!< in: row in MySQL format */
3912
3212
{
3913
 
  KeyInfo*    key_info  = &getTable()->key_info[keynr];
3914
 
  KeyPartInfo*  key_part  = key_info->key_part;
3915
 
  KeyPartInfo*  end   = key_part + key_info->key_parts;
3916
 
  char*   buff_start  = buff;
3917
 
  enum_field_types mysql_type;
3918
 
  Field*    field;
3919
 
  ibool   is_null;
3920
 
 
3921
 
  /* The format for storing a key field in MySQL is the following:
3922
 
 
3923
 
  1. If the column can be NULL, then in the first byte we put 1 if the
3924
 
  field value is NULL, 0 otherwise.
3925
 
 
3926
 
  2. If the column is of a BLOB type (it must be a column prefix field
3927
 
  in this case), then we put the length of the data in the field to the
3928
 
  next 2 bytes, in the little-endian format. If the field is SQL NULL,
3929
 
  then these 2 bytes are set to 0. Note that the length of data in the
3930
 
  field is <= column prefix length.
3931
 
 
3932
 
  3. In a column prefix field, prefix_len next bytes are reserved for
3933
 
  data. In a normal field the max field length next bytes are reserved
3934
 
  for data. For a VARCHAR(n) the max field length is n. If the stored
3935
 
  value is the SQL NULL then these data bytes are set to 0.
3936
 
 
3937
 
  4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
3938
 
  in the MySQL row format, the length is stored in 1 or 2 bytes,
3939
 
  depending on the maximum allowed length. But in the MySQL key value
3940
 
  format, the length always takes 2 bytes.
3941
 
 
3942
 
  We have to zero-fill the buffer so that MySQL is able to use a
3943
 
  simple memcmp to compare two key values to determine if they are
3944
 
  equal. MySQL does this to compare contents of two 'ref' values. */
3945
 
 
3946
 
  bzero(buff, buff_len);
3947
 
 
3948
 
  for (; key_part != end; key_part++) {
3949
 
    is_null = FALSE;
3950
 
 
3951
 
    if (key_part->null_bit) {
3952
 
      if (record[key_part->null_offset]
3953
 
            & key_part->null_bit) {
3954
 
        *buff = 1;
3955
 
        is_null = TRUE;
3956
 
      } else {
3957
 
        *buff = 0;
3958
 
      }
3959
 
      buff++;
3960
 
    }
3961
 
 
3962
 
    field = key_part->field;
3963
 
    mysql_type = field->type();
3964
 
 
3965
 
    if (mysql_type == DRIZZLE_TYPE_VARCHAR) {
3966
 
            /* >= 5.0.3 true VARCHAR */
3967
 
      ulint   lenlen;
3968
 
      ulint   len;
3969
 
      const byte* data;
3970
 
      ulint   key_len;
3971
 
      ulint   true_len;
3972
 
      const CHARSET_INFO* cs;
3973
 
      int   error=0;
3974
 
 
3975
 
      key_len = key_part->length;
3976
 
 
3977
 
      if (is_null) {
3978
 
        buff += key_len + 2;
3979
 
 
3980
 
        continue;
3981
 
      }
3982
 
      cs = field->charset();
3983
 
 
3984
 
      lenlen = (ulint)
3985
 
        (((Field_varstring*)field)->pack_length_no_ptr());
3986
 
 
3987
 
      data = row_mysql_read_true_varchar(&len,
3988
 
        (byte*) (record
3989
 
        + (ulint)get_field_offset(getTable(), field)),
3990
 
        lenlen);
3991
 
 
3992
 
      true_len = len;
3993
 
 
3994
 
      /* For multi byte character sets we need to calculate
3995
 
      the true length of the key */
3996
 
 
3997
 
      if (len > 0 && cs->mbmaxlen > 1) {
3998
 
        true_len = (ulint) cs->cset->well_formed_len(cs,
3999
 
            (const char *) data,
4000
 
            (const char *) data + len,
4001
 
                                                (uint) (key_len /
4002
 
                                                        cs->mbmaxlen),
4003
 
            &error);
4004
 
      }
4005
 
 
4006
 
      /* In a column prefix index, we may need to truncate
4007
 
      the stored value: */
4008
 
 
4009
 
      if (true_len > key_len) {
4010
 
        true_len = key_len;
4011
 
      }
4012
 
 
4013
 
      /* The length in a key value is always stored in 2
4014
 
      bytes */
4015
 
 
4016
 
      row_mysql_store_true_var_len((byte*)buff, true_len, 2);
4017
 
      buff += 2;
4018
 
 
4019
 
      memcpy(buff, data, true_len);
4020
 
 
4021
 
      /* Note that we always reserve the maximum possible
4022
 
      length of the true VARCHAR in the key value, though
4023
 
      only len first bytes after the 2 length bytes contain
4024
 
      actual data. The rest of the space was reset to zero
4025
 
      in the bzero() call above. */
4026
 
 
4027
 
      buff += key_len;
4028
 
 
4029
 
    } else if (mysql_type == DRIZZLE_TYPE_BLOB) {
4030
 
 
4031
 
      const CHARSET_INFO* cs;
4032
 
      ulint   key_len;
4033
 
      ulint   true_len;
4034
 
      int   error=0;
4035
 
      ulint   blob_len;
4036
 
      const byte* blob_data;
4037
 
 
4038
 
      ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
4039
 
 
4040
 
      key_len = key_part->length;
4041
 
 
4042
 
      if (is_null) {
4043
 
        buff += key_len + 2;
4044
 
 
4045
 
        continue;
4046
 
      }
4047
 
 
4048
 
      cs = field->charset();
4049
 
 
4050
 
      blob_data = row_mysql_read_blob_ref(&blob_len,
4051
 
        (byte*) (record
4052
 
        + (ulint)get_field_offset(getTable(), field)),
4053
 
          (ulint) field->pack_length());
4054
 
 
4055
 
      true_len = blob_len;
4056
 
 
4057
 
      ut_a(get_field_offset(getTable(), field)
4058
 
        == key_part->offset);
4059
 
 
4060
 
      /* For multi byte character sets we need to calculate
4061
 
      the true length of the key */
4062
 
 
4063
 
      if (blob_len > 0 && cs->mbmaxlen > 1) {
4064
 
        true_len = (ulint) cs->cset->well_formed_len(cs,
4065
 
                                                     (const char *) blob_data,
4066
 
                                                     (const char *) blob_data
4067
 
                                                     + blob_len,
4068
 
                                                     (uint) (key_len /
4069
 
                                                             cs->mbmaxlen),
4070
 
                                                     &error);
4071
 
      }
4072
 
 
4073
 
      /* All indexes on BLOB and TEXT are column prefix
4074
 
      indexes, and we may need to truncate the data to be
4075
 
      stored in the key value: */
4076
 
 
4077
 
      if (true_len > key_len) {
4078
 
        true_len = key_len;
4079
 
      }
4080
 
 
4081
 
      /* MySQL reserves 2 bytes for the length and the
4082
 
      storage of the number is little-endian */
4083
 
 
4084
 
      innobase_write_to_2_little_endian(
4085
 
          (byte*)buff, true_len);
4086
 
      buff += 2;
4087
 
 
4088
 
      memcpy(buff, blob_data, true_len);
4089
 
 
4090
 
      /* Note that we always reserve the maximum possible
4091
 
      length of the BLOB prefix in the key value. */
4092
 
 
4093
 
      buff += key_len;
4094
 
    } else {
4095
 
      /* Here we handle all other data types except the
4096
 
      true VARCHAR, BLOB and TEXT. Note that the column
4097
 
      value we store may be also in a column prefix
4098
 
      index. */
4099
 
 
4100
 
      ulint     true_len;
4101
 
      ulint     key_len;
4102
 
      const unsigned char*    src_start;
4103
 
      enum_field_types  real_type;
4104
 
      const CHARSET_INFO* cs= field->charset();
4105
 
 
4106
 
      key_len = key_part->length;
4107
 
 
4108
 
      if (is_null) {
4109
 
         buff += key_len;
4110
 
 
4111
 
         continue;
4112
 
      }
4113
 
 
4114
 
      src_start = record + key_part->offset;
4115
 
      real_type = field->real_type();
4116
 
      true_len = key_len;
4117
 
 
4118
 
      /* Character set for the field is defined only
4119
 
      to fields whose type is string and real field
4120
 
      type is not enum or set. For these fields check
4121
 
      if character set is multi byte. */
4122
 
 
4123
 
      memcpy(buff, src_start, true_len);
4124
 
      buff += true_len;
4125
 
 
4126
 
      /* Pad the unused space with spaces. */
4127
 
 
4128
 
      if (true_len < key_len) {
4129
 
        ulint   pad_len = key_len - true_len;
4130
 
        ut_a(!(pad_len % cs->mbminlen));
4131
 
 
4132
 
        cs->cset->fill(cs, buff, pad_len,
4133
 
                       0x20 /* space */);
4134
 
        buff += pad_len;
4135
 
      }
4136
 
    }
4137
 
  }
4138
 
 
4139
 
  ut_a(buff <= buff_start + buff_len);
4140
 
 
4141
 
  return((uint)(buff - buff_start));
 
3213
        KEY*            key_info        = table->key_info + keynr;
 
3214
        KEY_PART_INFO*  key_part        = key_info->key_part;
 
3215
        KEY_PART_INFO*  end             = key_part + key_info->key_parts;
 
3216
        char*           buff_start      = buff;
 
3217
        enum_field_types mysql_type;
 
3218
        Field*          field;
 
3219
        ibool           is_null;
 
3220
 
 
3221
        /* The format for storing a key field in MySQL is the following:
 
3222
 
 
3223
        1. If the column can be NULL, then in the first byte we put 1 if the
 
3224
        field value is NULL, 0 otherwise.
 
3225
 
 
3226
        2. If the column is of a BLOB type (it must be a column prefix field
 
3227
        in this case), then we put the length of the data in the field to the
 
3228
        next 2 bytes, in the little-endian format. If the field is SQL NULL,
 
3229
        then these 2 bytes are set to 0. Note that the length of data in the
 
3230
        field is <= column prefix length.
 
3231
 
 
3232
        3. In a column prefix field, prefix_len next bytes are reserved for
 
3233
        data. In a normal field the max field length next bytes are reserved
 
3234
        for data. For a VARCHAR(n) the max field length is n. If the stored
 
3235
        value is the SQL NULL then these data bytes are set to 0.
 
3236
 
 
3237
        4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
 
3238
        in the MySQL row format, the length is stored in 1 or 2 bytes,
 
3239
        depending on the maximum allowed length. But in the MySQL key value
 
3240
        format, the length always takes 2 bytes.
 
3241
 
 
3242
        We have to zero-fill the buffer so that MySQL is able to use a
 
3243
        simple memcmp to compare two key values to determine if they are
 
3244
        equal. MySQL does this to compare contents of two 'ref' values. */
 
3245
 
 
3246
        bzero(buff, buff_len);
 
3247
 
 
3248
        for (; key_part != end; key_part++) {
 
3249
                is_null = FALSE;
 
3250
 
 
3251
                if (key_part->null_bit) {
 
3252
                        if (record[key_part->null_offset]
 
3253
                                                & key_part->null_bit) {
 
3254
                                *buff = 1;
 
3255
                                is_null = TRUE;
 
3256
                        } else {
 
3257
                                *buff = 0;
 
3258
                        }
 
3259
                        buff++;
 
3260
                }
 
3261
 
 
3262
                field = key_part->field;
 
3263
                mysql_type = field->type();
 
3264
 
 
3265
                if (mysql_type == DRIZZLE_TYPE_VARCHAR) {
 
3266
                                                /* >= 5.0.3 true VARCHAR */
 
3267
                        ulint           lenlen;
 
3268
                        ulint           len;
 
3269
                        const byte*     data;
 
3270
                        ulint           key_len;
 
3271
                        ulint           true_len;
 
3272
                        const CHARSET_INFO*     cs;
 
3273
                        int             error=0;
 
3274
 
 
3275
                        key_len = key_part->length;
 
3276
 
 
3277
                        if (is_null) {
 
3278
                                buff += key_len + 2;
 
3279
 
 
3280
                                continue;
 
3281
                        }
 
3282
                        cs = field->charset();
 
3283
 
 
3284
                        lenlen = (ulint)
 
3285
                                (((Field_varstring*)field)->length_bytes);
 
3286
 
 
3287
                        data = row_mysql_read_true_varchar(&len,
 
3288
                                (byte*) (record
 
3289
                                + (ulint)get_field_offset(table, field)),
 
3290
                                lenlen);
 
3291
 
 
3292
                        true_len = len;
 
3293
 
 
3294
                        /* For multi byte character sets we need to calculate
 
3295
                        the true length of the key */
 
3296
 
 
3297
                        if (len > 0 && cs->mbmaxlen > 1) {
 
3298
                                true_len = (ulint) cs->cset->well_formed_len(cs,
 
3299
                                                (const char *) data,
 
3300
                                                (const char *) data + len,
 
3301
                                                (uint) (key_len /
 
3302
                                                        cs->mbmaxlen),
 
3303
                                                &error);
 
3304
                        }
 
3305
 
 
3306
                        /* In a column prefix index, we may need to truncate
 
3307
                        the stored value: */
 
3308
 
 
3309
                        if (true_len > key_len) {
 
3310
                                true_len = key_len;
 
3311
                        }
 
3312
 
 
3313
                        /* The length in a key value is always stored in 2
 
3314
                        bytes */
 
3315
 
 
3316
                        row_mysql_store_true_var_len((byte*)buff, true_len, 2);
 
3317
                        buff += 2;
 
3318
 
 
3319
                        memcpy(buff, data, true_len);
 
3320
 
 
3321
                        /* Note that we always reserve the maximum possible
 
3322
                        length of the true VARCHAR in the key value, though
 
3323
                        only len first bytes after the 2 length bytes contain
 
3324
                        actual data. The rest of the space was reset to zero
 
3325
                        in the bzero() call above. */
 
3326
 
 
3327
                        buff += key_len;
 
3328
 
 
3329
                } else if (mysql_type == DRIZZLE_TYPE_BLOB) {
 
3330
 
 
3331
                        const CHARSET_INFO*     cs;
 
3332
                        ulint           key_len;
 
3333
                        ulint           true_len;
 
3334
                        int             error=0;
 
3335
                        ulint           blob_len;
 
3336
                        const byte*     blob_data;
 
3337
 
 
3338
                        ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
 
3339
 
 
3340
                        key_len = key_part->length;
 
3341
 
 
3342
                        if (is_null) {
 
3343
                                buff += key_len + 2;
 
3344
 
 
3345
                                continue;
 
3346
                        }
 
3347
 
 
3348
                        cs = field->charset();
 
3349
 
 
3350
                        blob_data = row_mysql_read_blob_ref(&blob_len,
 
3351
                                (byte*) (record
 
3352
                                + (ulint)get_field_offset(table, field)),
 
3353
                                        (ulint) field->pack_length());
 
3354
 
 
3355
                        true_len = blob_len;
 
3356
 
 
3357
                        ut_a(get_field_offset(table, field)
 
3358
                                == key_part->offset);
 
3359
 
 
3360
                        /* For multi byte character sets we need to calculate
 
3361
                        the true length of the key */
 
3362
 
 
3363
                        if (blob_len > 0 && cs->mbmaxlen > 1) {
 
3364
                                true_len = (ulint) cs->cset->well_formed_len(cs,
 
3365
                                                (const char *) blob_data,
 
3366
                                                (const char *) blob_data
 
3367
                                                        + blob_len,
 
3368
                                                (uint) (key_len /
 
3369
                                                        cs->mbmaxlen),
 
3370
                                                &error);
 
3371
                        }
 
3372
 
 
3373
                        /* All indexes on BLOB and TEXT are column prefix
 
3374
                        indexes, and we may need to truncate the data to be
 
3375
                        stored in the key value: */
 
3376
 
 
3377
                        if (true_len > key_len) {
 
3378
                                true_len = key_len;
 
3379
                        }
 
3380
 
 
3381
                        /* MySQL reserves 2 bytes for the length and the
 
3382
                        storage of the number is little-endian */
 
3383
 
 
3384
                        innobase_write_to_2_little_endian(
 
3385
                                        (byte*)buff, true_len);
 
3386
                        buff += 2;
 
3387
 
 
3388
                        memcpy(buff, blob_data, true_len);
 
3389
 
 
3390
                        /* Note that we always reserve the maximum possible
 
3391
                        length of the BLOB prefix in the key value. */
 
3392
 
 
3393
                        buff += key_len;
 
3394
                } else {
 
3395
                        /* Here we handle all other data types except the
 
3396
                        true VARCHAR, BLOB and TEXT. Note that the column
 
3397
                        value we store may be also in a column prefix
 
3398
                        index. */
 
3399
 
 
3400
                        ulint                   true_len;
 
3401
                        ulint                   key_len;
 
3402
                        const unsigned char*            src_start;
 
3403
                        enum_field_types        real_type;
 
3404
 
 
3405
                        key_len = key_part->length;
 
3406
 
 
3407
                        if (is_null) {
 
3408
                                 buff += key_len;
 
3409
 
 
3410
                                 continue;
 
3411
                        }
 
3412
 
 
3413
                        src_start = record + key_part->offset;
 
3414
                        real_type = field->real_type();
 
3415
                        true_len = key_len;
 
3416
 
 
3417
                        /* Character set for the field is defined only
 
3418
                        to fields whose type is string and real field
 
3419
                        type is not enum or set. For these fields check
 
3420
                        if character set is multi byte. */
 
3421
 
 
3422
                        memcpy(buff, src_start, true_len);
 
3423
                        buff += true_len;
 
3424
 
 
3425
                        /* Pad the unused space with spaces. Note that no
 
3426
                        padding is ever needed for UCS-2 because in MySQL,
 
3427
                        all UCS2 characters are 2 bytes, as MySQL does not
 
3428
                        support surrogate pairs, which are needed to represent
 
3429
                        characters in the range U+10000 to U+10FFFF. */
 
3430
 
 
3431
                        if (true_len < key_len) {
 
3432
                                ulint pad_len = key_len - true_len;
 
3433
                                memset(buff, ' ', pad_len);
 
3434
                                buff += pad_len;
 
3435
                        }
 
3436
                }
 
3437
        }
 
3438
 
 
3439
        ut_a(buff <= buff_start + buff_len);
 
3440
 
 
3441
        return((uint)(buff - buff_start));
4142
3442
}
4143
3443
 
4144
3444
/**************************************************************//**
4148
3448
void
4149
3449
build_template(
4150
3450
/*===========*/
4151
 
  row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct */
4152
 
  Session*  ,   /*!< in: current user thread, used
4153
 
          only if templ_type is
4154
 
          ROW_DRIZZLE_REC_FIELDS */
4155
 
  Table*    table,    /*!< in: MySQL table */
4156
 
  uint    templ_type) /*!< in: ROW_MYSQL_WHOLE_ROW or
4157
 
          ROW_DRIZZLE_REC_FIELDS */
 
3451
        row_prebuilt_t* prebuilt,       /*!< in/out: prebuilt struct */
 
3452
        Session*        ,               /*!< in: current user thread, used
 
3453
                                        only if templ_type is
 
3454
                                        ROW_DRIZZLE_REC_FIELDS */
 
3455
        Table*          table,          /*!< in: MySQL table */
 
3456
        uint            templ_type)     /*!< in: ROW_MYSQL_WHOLE_ROW or
 
3457
                                        ROW_DRIZZLE_REC_FIELDS */
4158
3458
{
4159
 
  dict_index_t* index;
4160
 
  dict_index_t* clust_index;
4161
 
  mysql_row_templ_t* templ;
4162
 
  Field*    field;
4163
 
  ulint   n_fields;
4164
 
  ulint   n_requested_fields  = 0;
4165
 
  ibool   fetch_all_in_key  = FALSE;
4166
 
  ibool   fetch_primary_key_cols  = FALSE;
4167
 
  ulint   i= 0;
4168
 
  /* byte offset of the end of last requested column */
4169
 
  ulint   mysql_prefix_len  = 0;
4170
 
 
4171
 
  if (prebuilt->select_lock_type == LOCK_X) {
4172
 
    /* We always retrieve the whole clustered index record if we
4173
 
    use exclusive row level locks, for example, if the read is
4174
 
    done in an UPDATE statement. */
4175
 
 
4176
 
    templ_type = ROW_MYSQL_WHOLE_ROW;
4177
 
  }
4178
 
 
4179
 
  if (templ_type == ROW_MYSQL_REC_FIELDS) {
4180
 
    if (prebuilt->hint_need_to_fetch_extra_cols
4181
 
      == ROW_RETRIEVE_ALL_COLS) {
4182
 
 
4183
 
      /* We know we must at least fetch all columns in the
4184
 
      key, or all columns in the table */
4185
 
 
4186
 
      if (prebuilt->read_just_key) {
4187
 
        /* MySQL has instructed us that it is enough
4188
 
        to fetch the columns in the key; looks like
4189
 
        MySQL can set this flag also when there is
4190
 
        only a prefix of the column in the key: in
4191
 
        that case we retrieve the whole column from
4192
 
        the clustered index */
4193
 
 
4194
 
        fetch_all_in_key = TRUE;
4195
 
      } else {
4196
 
        templ_type = ROW_MYSQL_WHOLE_ROW;
4197
 
      }
4198
 
    } else if (prebuilt->hint_need_to_fetch_extra_cols
4199
 
      == ROW_RETRIEVE_PRIMARY_KEY) {
4200
 
      /* We must at least fetch all primary key cols. Note
4201
 
         that if the clustered index was internally generated
4202
 
         by InnoDB on the row id (no primary key was
4203
 
         defined), then row_search_for_mysql() will always
4204
 
         retrieve the row id to a special buffer in the
4205
 
         prebuilt struct. */
4206
 
 
4207
 
      fetch_primary_key_cols = TRUE;
4208
 
    }
4209
 
  }
4210
 
 
4211
 
  clust_index = dict_table_get_first_index(prebuilt->table);
4212
 
 
4213
 
  if (templ_type == ROW_MYSQL_REC_FIELDS) {
4214
 
    index = prebuilt->index;
4215
 
  } else {
4216
 
    index = clust_index;
4217
 
  }
4218
 
 
4219
 
  if (index == clust_index) {
4220
 
    prebuilt->need_to_access_clustered = TRUE;
4221
 
  } else {
4222
 
    prebuilt->need_to_access_clustered = FALSE;
4223
 
    /* Below we check column by column if we need to access
4224
 
    the clustered index */
4225
 
  }
4226
 
 
4227
 
  n_fields = (ulint)table->getShare()->sizeFields(); /* number of columns */
4228
 
 
4229
 
  if (!prebuilt->mysql_template) {
4230
 
    prebuilt->mysql_template = (mysql_row_templ_t*)
4231
 
      mem_alloc(n_fields * sizeof(mysql_row_templ_t));
4232
 
  }
4233
 
 
4234
 
  prebuilt->template_type = templ_type;
4235
 
  prebuilt->null_bitmap_len = table->getShare()->null_bytes;
4236
 
 
4237
 
  prebuilt->templ_contains_blob = FALSE;
4238
 
 
4239
 
  /* Note that in InnoDB, i is the column number. MySQL calls columns
4240
 
  'fields'. */
4241
 
  for (i = 0; i < n_fields; i++)
4242
 
  {
4243
 
    const dict_col_t *col= &index->table->cols[i];
4244
 
    templ = prebuilt->mysql_template + n_requested_fields;
4245
 
    field = table->getField(i);
4246
 
 
4247
 
    if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
4248
 
      /* Decide which columns we should fetch
4249
 
      and which we can skip. */
4250
 
      register const ibool  index_contains_field =
4251
 
        dict_index_contains_col_or_prefix(index, i);
4252
 
 
4253
 
      if (!index_contains_field && prebuilt->read_just_key) {
4254
 
        /* If this is a 'key read', we do not need
4255
 
        columns that are not in the key */
4256
 
 
4257
 
        goto skip_field;
4258
 
      }
4259
 
 
4260
 
      if (index_contains_field && fetch_all_in_key) {
4261
 
        /* This field is needed in the query */
4262
 
 
4263
 
        goto include_field;
4264
 
      }
 
3459
        dict_index_t*   index;
 
3460
        dict_index_t*   clust_index;
 
3461
        mysql_row_templ_t* templ;
 
3462
        Field*          field;
 
3463
        ulint           n_fields;
 
3464
        ulint           n_requested_fields      = 0;
 
3465
        ibool           fetch_all_in_key        = FALSE;
 
3466
        ibool           fetch_primary_key_cols  = FALSE;
 
3467
        ulint           i= 0;
 
3468
        /* byte offset of the end of last requested column */
 
3469
        ulint           mysql_prefix_len        = 0;
 
3470
 
 
3471
        if (prebuilt->select_lock_type == LOCK_X) {
 
3472
                /* We always retrieve the whole clustered index record if we
 
3473
                use exclusive row level locks, for example, if the read is
 
3474
                done in an UPDATE statement. */
 
3475
 
 
3476
                templ_type = ROW_MYSQL_WHOLE_ROW;
 
3477
        }
 
3478
 
 
3479
        if (templ_type == ROW_MYSQL_REC_FIELDS) {
 
3480
                if (prebuilt->hint_need_to_fetch_extra_cols
 
3481
                        == ROW_RETRIEVE_ALL_COLS) {
 
3482
 
 
3483
                        /* We know we must at least fetch all columns in the
 
3484
                        key, or all columns in the table */
 
3485
 
 
3486
                        if (prebuilt->read_just_key) {
 
3487
                                /* MySQL has instructed us that it is enough
 
3488
                                to fetch the columns in the key; looks like
 
3489
                                MySQL can set this flag also when there is
 
3490
                                only a prefix of the column in the key: in
 
3491
                                that case we retrieve the whole column from
 
3492
                                the clustered index */
 
3493
 
 
3494
                                fetch_all_in_key = TRUE;
 
3495
                        } else {
 
3496
                                templ_type = ROW_MYSQL_WHOLE_ROW;
 
3497
                        }
 
3498
                } else if (prebuilt->hint_need_to_fetch_extra_cols
 
3499
                        == ROW_RETRIEVE_PRIMARY_KEY) {
 
3500
                        /* We must at least fetch all primary key cols. Note
 
3501
                           that if the clustered index was internally generated
 
3502
                           by InnoDB on the row id (no primary key was
 
3503
                           defined), then row_search_for_mysql() will always
 
3504
                           retrieve the row id to a special buffer in the
 
3505
                           prebuilt struct. */
 
3506
 
 
3507
                        fetch_primary_key_cols = TRUE;
 
3508
                }
 
3509
        }
 
3510
 
 
3511
        clust_index = dict_table_get_first_index(prebuilt->table);
 
3512
 
 
3513
        if (templ_type == ROW_MYSQL_REC_FIELDS) {
 
3514
                index = prebuilt->index;
 
3515
        } else {
 
3516
                index = clust_index;
 
3517
        }
 
3518
 
 
3519
        if (index == clust_index) {
 
3520
                prebuilt->need_to_access_clustered = TRUE;
 
3521
        } else {
 
3522
                prebuilt->need_to_access_clustered = FALSE;
 
3523
                /* Below we check column by column if we need to access
 
3524
                the clustered index */
 
3525
        }
 
3526
 
 
3527
        n_fields = (ulint)table->s->fields; /* number of columns */
 
3528
 
 
3529
        if (!prebuilt->mysql_template) {
 
3530
                prebuilt->mysql_template = (mysql_row_templ_t*)
 
3531
                        mem_alloc(n_fields * sizeof(mysql_row_templ_t));
 
3532
        }
 
3533
 
 
3534
        prebuilt->template_type = templ_type;
 
3535
        prebuilt->null_bitmap_len = table->s->null_bytes;
 
3536
 
 
3537
        prebuilt->templ_contains_blob = FALSE;
 
3538
 
 
3539
        /* Note that in InnoDB, i is the column number. MySQL calls columns
 
3540
        'fields'. */
 
3541
        for (i = 0; i < n_fields; i++) {
 
3542
                templ = prebuilt->mysql_template + n_requested_fields;
 
3543
                field = table->field[i];
 
3544
 
 
3545
                if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
 
3546
                        /* Decide which columns we should fetch
 
3547
                        and which we can skip. */
 
3548
                        register const ibool    index_contains_field =
 
3549
                                dict_index_contains_col_or_prefix(index, i);
 
3550
 
 
3551
                        if (!index_contains_field && prebuilt->read_just_key) {
 
3552
                                /* If this is a 'key read', we do not need
 
3553
                                columns that are not in the key */
 
3554
 
 
3555
                                goto skip_field;
 
3556
                        }
 
3557
 
 
3558
                        if (index_contains_field && fetch_all_in_key) {
 
3559
                                /* This field is needed in the query */
 
3560
 
 
3561
                                goto include_field;
 
3562
                        }
4265
3563
 
4266
3564
                        if (field->isReadSet() || field->isWriteSet())
4267
 
        /* This field is needed in the query */
4268
 
        goto include_field;
 
3565
                                /* This field is needed in the query */
 
3566
                                goto include_field;
4269
3567
 
4270
3568
                        assert(table->isReadSet(i) == field->isReadSet());
4271
3569
                        assert(table->isWriteSet(i) == field->isWriteSet());
4272
3570
 
4273
 
      if (fetch_primary_key_cols
4274
 
        && dict_table_col_in_clustered_key(
4275
 
          index->table, i)) {
4276
 
        /* This field is needed in the query */
4277
 
 
4278
 
        goto include_field;
4279
 
      }
4280
 
 
4281
 
      /* This field is not needed in the query, skip it */
4282
 
 
4283
 
      goto skip_field;
4284
 
    }
 
3571
                        if (fetch_primary_key_cols
 
3572
                                && dict_table_col_in_clustered_key(
 
3573
                                        index->table, i)) {
 
3574
                                /* This field is needed in the query */
 
3575
 
 
3576
                                goto include_field;
 
3577
                        }
 
3578
 
 
3579
                        /* This field is not needed in the query, skip it */
 
3580
 
 
3581
                        goto skip_field;
 
3582
                }
4285
3583
include_field:
4286
 
    n_requested_fields++;
4287
 
 
4288
 
    templ->col_no = i;
4289
 
 
4290
 
    if (index == clust_index) {
4291
 
      templ->rec_field_no = dict_col_get_clust_pos(col, index);
4292
 
    } else {
4293
 
      templ->rec_field_no = dict_index_get_nth_col_pos(
4294
 
                index, i);
4295
 
    }
4296
 
 
4297
 
    if (templ->rec_field_no == ULINT_UNDEFINED) {
4298
 
      prebuilt->need_to_access_clustered = TRUE;
4299
 
    }
4300
 
 
4301
 
    if (field->null_ptr) {
4302
 
      templ->mysql_null_byte_offset =
4303
 
        (ulint) ((char*) field->null_ptr
4304
 
          - (char*) table->getInsertRecord());
4305
 
 
4306
 
      templ->mysql_null_bit_mask = (ulint) field->null_bit;
4307
 
    } else {
4308
 
      templ->mysql_null_bit_mask = 0;
4309
 
    }
4310
 
 
4311
 
    templ->mysql_col_offset = (ulint)
4312
 
          get_field_offset(table, field);
4313
 
 
4314
 
    templ->mysql_col_len = (ulint) field->pack_length();
4315
 
    if (mysql_prefix_len < templ->mysql_col_offset
4316
 
        + templ->mysql_col_len) {
4317
 
      mysql_prefix_len = templ->mysql_col_offset
4318
 
        + templ->mysql_col_len;
4319
 
    }
4320
 
    templ->type = col->mtype;
4321
 
    templ->mysql_type = (ulint)field->type();
4322
 
 
4323
 
    if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
4324
 
      templ->mysql_length_bytes = (ulint)
4325
 
        (((Field_varstring*)field)->pack_length_no_ptr());
4326
 
    }
4327
 
 
4328
 
    templ->charset = dtype_get_charset_coll(col->prtype);
4329
 
    templ->mbminlen = dict_col_get_mbminlen(col);
4330
 
    templ->mbmaxlen = dict_col_get_mbmaxlen(col);
4331
 
    templ->is_unsigned = col->prtype & DATA_UNSIGNED;
4332
 
    if (templ->type == DATA_BLOB) {
4333
 
      prebuilt->templ_contains_blob = TRUE;
4334
 
    }
 
3584
                n_requested_fields++;
 
3585
 
 
3586
                templ->col_no = i;
 
3587
 
 
3588
                if (index == clust_index) {
 
3589
                        templ->rec_field_no = dict_col_get_clust_pos(
 
3590
                                &index->table->cols[i], index);
 
3591
                } else {
 
3592
                        templ->rec_field_no = dict_index_get_nth_col_pos(
 
3593
                                                                index, i);
 
3594
                }
 
3595
 
 
3596
                if (templ->rec_field_no == ULINT_UNDEFINED) {
 
3597
                        prebuilt->need_to_access_clustered = TRUE;
 
3598
                }
 
3599
 
 
3600
                if (field->null_ptr) {
 
3601
                        templ->mysql_null_byte_offset =
 
3602
                                (ulint) ((char*) field->null_ptr
 
3603
                                        - (char*) table->record[0]);
 
3604
 
 
3605
                        templ->mysql_null_bit_mask = (ulint) field->null_bit;
 
3606
                } else {
 
3607
                        templ->mysql_null_bit_mask = 0;
 
3608
                }
 
3609
 
 
3610
                templ->mysql_col_offset = (ulint)
 
3611
                                        get_field_offset(table, field);
 
3612
 
 
3613
                templ->mysql_col_len = (ulint) field->pack_length();
 
3614
                if (mysql_prefix_len < templ->mysql_col_offset
 
3615
                                + templ->mysql_col_len) {
 
3616
                        mysql_prefix_len = templ->mysql_col_offset
 
3617
                                + templ->mysql_col_len;
 
3618
                }
 
3619
                templ->type = index->table->cols[i].mtype;
 
3620
                templ->mysql_type = (ulint)field->type();
 
3621
 
 
3622
                if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
 
3623
                        templ->mysql_length_bytes = (ulint)
 
3624
                                (((Field_varstring*)field)->length_bytes);
 
3625
                }
 
3626
 
 
3627
                templ->charset = dtype_get_charset_coll(
 
3628
                        index->table->cols[i].prtype);
 
3629
                templ->mbminlen = index->table->cols[i].mbminlen;
 
3630
                templ->mbmaxlen = index->table->cols[i].mbmaxlen;
 
3631
                templ->is_unsigned = index->table->cols[i].prtype
 
3632
                                                        & DATA_UNSIGNED;
 
3633
                if (templ->type == DATA_BLOB) {
 
3634
                        prebuilt->templ_contains_blob = TRUE;
 
3635
                }
4335
3636
skip_field:
4336
 
    ;
4337
 
  }
4338
 
 
4339
 
  prebuilt->n_template = n_requested_fields;
4340
 
  prebuilt->mysql_prefix_len = mysql_prefix_len;
4341
 
 
4342
 
  if (index != clust_index && prebuilt->need_to_access_clustered) {
4343
 
    /* Change rec_field_no's to correspond to the clustered index
4344
 
    record */
4345
 
    for (i = 0; i < n_requested_fields; i++) {
4346
 
      templ = prebuilt->mysql_template + i;
4347
 
 
4348
 
      templ->rec_field_no = dict_col_get_clust_pos(
4349
 
        &index->table->cols[templ->col_no],
4350
 
        clust_index);
4351
 
    }
4352
 
  }
 
3637
                ;
 
3638
        }
 
3639
 
 
3640
        prebuilt->n_template = n_requested_fields;
 
3641
        prebuilt->mysql_prefix_len = mysql_prefix_len;
 
3642
 
 
3643
        if (index != clust_index && prebuilt->need_to_access_clustered) {
 
3644
                /* Change rec_field_no's to correspond to the clustered index
 
3645
                record */
 
3646
                for (i = 0; i < n_requested_fields; i++) {
 
3647
                        templ = prebuilt->mysql_template + i;
 
3648
 
 
3649
                        templ->rec_field_no = dict_col_get_clust_pos(
 
3650
                                &index->table->cols[templ->col_no],
 
3651
                                clust_index);
 
3652
                }
 
3653
        }
 
3654
}
 
3655
 
 
3656
/********************************************************************//**
 
3657
Get the upper limit of the MySQL integral and floating-point type. */
 
3658
UNIV_INTERN
 
3659
uint64_t
 
3660
ha_innobase::innobase_get_int_col_max_value(
 
3661
/*========================================*/
 
3662
        const Field*    field)
 
3663
{
 
3664
        uint64_t        max_value = 0;
 
3665
 
 
3666
        switch(field->key_type()) {
 
3667
        /* TINY */
 
3668
        case HA_KEYTYPE_BINARY:
 
3669
                max_value = 0xFFULL;
 
3670
                break;
 
3671
        /* MEDIUM */
 
3672
        case HA_KEYTYPE_UINT24:
 
3673
                max_value = 0xFFFFFFULL;
 
3674
                break;
 
3675
        /* LONG */
 
3676
        case HA_KEYTYPE_ULONG_INT:
 
3677
                max_value = 0xFFFFFFFFULL;
 
3678
                break;
 
3679
        case HA_KEYTYPE_LONG_INT:
 
3680
                max_value = 0x7FFFFFFFULL;
 
3681
                break;
 
3682
        /* BIG */
 
3683
        case HA_KEYTYPE_ULONGLONG:
 
3684
                max_value = 0xFFFFFFFFFFFFFFFFULL;
 
3685
                break;
 
3686
        case HA_KEYTYPE_LONGLONG:
 
3687
                max_value = 0x7FFFFFFFFFFFFFFFULL;
 
3688
                break;
 
3689
        case HA_KEYTYPE_DOUBLE:
 
3690
                /* We use the maximum as per IEEE754-2008 standard, 2^53 */
 
3691
                max_value = 0x20000000000000ULL;
 
3692
                break;
 
3693
        default:
 
3694
                ut_error;
 
3695
        }
 
3696
 
 
3697
        return(max_value);
4353
3698
}
4354
3699
 
4355
3700
/********************************************************************//**
4358
3703
INSERT ... SELECT type of statements, since MySQL binlog only stores the
4359
3704
min value of the autoinc interval. Once that is fixed we can get rid of
4360
3705
the special lock handling.
4361
 
@return DB_SUCCESS if all OK else error code */
 
3706
@return DB_SUCCESS if all OK else error code */
4362
3707
UNIV_INTERN
4363
3708
ulint
4364
3709
ha_innobase::innobase_lock_autoinc(void)
4365
3710
/*====================================*/
4366
3711
{
4367
 
  ulint   error = DB_SUCCESS;
4368
 
 
4369
 
  dict_table_autoinc_lock(prebuilt->table);
4370
 
 
4371
 
  return(ulong(error));
 
3712
        ulint           error = DB_SUCCESS;
 
3713
 
 
3714
        switch (innobase_autoinc_lock_mode) {
 
3715
        case AUTOINC_NO_LOCKING:
 
3716
                /* Acquire only the AUTOINC mutex. */
 
3717
                dict_table_autoinc_lock(prebuilt->table);
 
3718
                break;
 
3719
 
 
3720
        case AUTOINC_NEW_STYLE_LOCKING:
 
3721
                /* For simple (single/multi) row INSERTs, we fallback to the
 
3722
                old style only if another transaction has already acquired
 
3723
                the AUTOINC lock on behalf of a LOAD FILE or INSERT ... SELECT
 
3724
                etc. type of statement. */
 
3725
                if (session_sql_command(user_session) == SQLCOM_INSERT
 
3726
                    || session_sql_command(user_session) == SQLCOM_REPLACE) {
 
3727
                        dict_table_t*   d_table = prebuilt->table;
 
3728
 
 
3729
                        /* Acquire the AUTOINC mutex. */
 
3730
                        dict_table_autoinc_lock(d_table);
 
3731
 
 
3732
                        /* We need to check that another transaction isn't
 
3733
                        already holding the AUTOINC lock on the table. */
 
3734
                        if (d_table->n_waiting_or_granted_auto_inc_locks) {
 
3735
                                /* Release the mutex to avoid deadlocks. */
 
3736
                                dict_table_autoinc_unlock(d_table);
 
3737
                        } else {
 
3738
                                break;
 
3739
                        }
 
3740
                }
 
3741
                /* Fall through to old style locking. */
 
3742
 
 
3743
        case AUTOINC_OLD_STYLE_LOCKING:
 
3744
                error = row_lock_table_autoinc_for_mysql(prebuilt);
 
3745
 
 
3746
                if (error == DB_SUCCESS) {
 
3747
 
 
3748
                        /* Acquire the AUTOINC mutex. */
 
3749
                        dict_table_autoinc_lock(prebuilt->table);
 
3750
                }
 
3751
                break;
 
3752
 
 
3753
        default:
 
3754
                ut_error;
 
3755
        }
 
3756
 
 
3757
        return(ulong(error));
4372
3758
}
4373
3759
 
4374
3760
/********************************************************************//**
4375
3761
Reset the autoinc value in the table.
4376
 
@return DB_SUCCESS if all went well else error code */
 
3762
@return DB_SUCCESS if all went well else error code */
4377
3763
UNIV_INTERN
4378
3764
ulint
4379
3765
ha_innobase::innobase_reset_autoinc(
4380
3766
/*================================*/
4381
 
  uint64_t  autoinc)  /*!< in: value to store */
 
3767
        uint64_t        autoinc)        /*!< in: value to store */
4382
3768
{
4383
 
  dict_table_autoinc_lock(prebuilt->table);
4384
 
  dict_table_autoinc_initialize(prebuilt->table, autoinc);
4385
 
  dict_table_autoinc_unlock(prebuilt->table);
4386
 
 
4387
 
  return(ulong(DB_SUCCESS));
 
3769
        ulint           error;
 
3770
 
 
3771
        error = innobase_lock_autoinc();
 
3772
 
 
3773
        if (error == DB_SUCCESS) {
 
3774
 
 
3775
                dict_table_autoinc_initialize(prebuilt->table, autoinc);
 
3776
 
 
3777
                dict_table_autoinc_unlock(prebuilt->table);
 
3778
        }
 
3779
 
 
3780
        return(ulong(error));
4388
3781
}
4389
3782
 
4390
3783
/********************************************************************//**
4391
3784
Store the autoinc value in the table. The autoinc value is only set if
4392
3785
it's greater than the existing autoinc value in the table.
4393
 
@return DB_SUCCESS if all went well else error code */
 
3786
@return DB_SUCCESS if all went well else error code */
4394
3787
UNIV_INTERN
4395
3788
ulint
4396
3789
ha_innobase::innobase_set_max_autoinc(
4397
3790
/*==================================*/
4398
 
  uint64_t  auto_inc) /*!< in: value to store */
 
3791
        uint64_t        auto_inc)       /*!< in: value to store */
4399
3792
{
4400
 
  dict_table_autoinc_lock(prebuilt->table);
4401
 
  dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
4402
 
  dict_table_autoinc_unlock(prebuilt->table);
4403
 
 
4404
 
  return(ulong(DB_SUCCESS));
 
3793
        ulint           error;
 
3794
 
 
3795
        error = innobase_lock_autoinc();
 
3796
 
 
3797
        if (error == DB_SUCCESS) {
 
3798
 
 
3799
                dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
 
3800
 
 
3801
                dict_table_autoinc_unlock(prebuilt->table);
 
3802
        }
 
3803
 
 
3804
        return(ulong(error));
4405
3805
}
4406
3806
 
4407
3807
/********************************************************************//**
4408
3808
Stores a row in an InnoDB database, to the table specified in this
4409
3809
handle.
4410
 
@return error code */
 
3810
@return error code */
4411
3811
UNIV_INTERN
4412
3812
int
4413
 
ha_innobase::doInsertRecord(
 
3813
ha_innobase::write_row(
4414
3814
/*===================*/
4415
 
  unsigned char*  record) /*!< in: a row in MySQL format */
 
3815
        unsigned char*  record) /*!< in: a row in MySQL format */
4416
3816
{
4417
 
  ulint   error = 0;
 
3817
        ulint           error = 0;
4418
3818
        int             error_result= 0;
4419
 
  ibool   auto_inc_used= FALSE;
4420
 
  ulint   sql_command;
4421
 
  trx_t*    trx = session_to_trx(user_session);
4422
 
 
4423
 
  if (prebuilt->trx != trx) {
4424
 
    errmsg_printf(ERRMSG_LVL_ERROR, "The transaction object for the table handle is at "
4425
 
        "%p, but for the current thread it is at %p",
4426
 
        (const void*) prebuilt->trx, (const void*) trx);
4427
 
 
4428
 
    fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
4429
 
    ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
4430
 
    fputs("\n"
4431
 
      "InnoDB: Dump of 200 bytes around ha_data: ",
4432
 
      stderr);
4433
 
    ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
4434
 
    putc('\n', stderr);
4435
 
    ut_error;
4436
 
  }
4437
 
 
4438
 
  sql_command = session_sql_command(user_session);
4439
 
 
4440
 
  if ((sql_command == SQLCOM_ALTER_TABLE
4441
 
       || sql_command == SQLCOM_CREATE_INDEX
4442
 
       || sql_command == SQLCOM_DROP_INDEX)
4443
 
      && num_write_row >= 10000) {
4444
 
    /* ALTER TABLE is COMMITted at every 10000 copied rows.
4445
 
    The IX table lock for the original table has to be re-issued.
4446
 
    As this method will be called on a temporary table where the
4447
 
    contents of the original table is being copied to, it is
4448
 
    a bit tricky to determine the source table.  The cursor
4449
 
    position in the source table need not be adjusted after the
4450
 
    intermediate COMMIT, since writes by other transactions are
4451
 
    being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
4452
 
 
4453
 
    dict_table_t* src_table;
4454
 
    enum lock_mode  mode;
4455
 
 
4456
 
    num_write_row = 0;
4457
 
 
4458
 
    /* Commit the transaction.  This will release the table
4459
 
    locks, so they have to be acquired again. */
4460
 
 
4461
 
    /* Altering an InnoDB table */
4462
 
    /* Get the source table. */
4463
 
    src_table = lock_get_src_table(
4464
 
        prebuilt->trx, prebuilt->table, &mode);
4465
 
    if (!src_table) {
 
3819
        ibool           auto_inc_used= FALSE;
 
3820
        ulint           sql_command;
 
3821
        trx_t*          trx = session_to_trx(user_session);
 
3822
 
 
3823
        if (prebuilt->trx != trx) {
 
3824
          errmsg_printf(ERRMSG_LVL_ERROR, "The transaction object for the table handle is at "
 
3825
                          "%p, but for the current thread it is at %p",
 
3826
                          (const void*) prebuilt->trx, (const void*) trx);
 
3827
 
 
3828
                fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
 
3829
                ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
 
3830
                fputs("\n"
 
3831
                        "InnoDB: Dump of 200 bytes around ha_data: ",
 
3832
                        stderr);
 
3833
                ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
 
3834
                putc('\n', stderr);
 
3835
                ut_error;
 
3836
        }
 
3837
 
 
3838
        ha_statistic_increment(&SSV::ha_write_count);
 
3839
 
 
3840
        sql_command = session_sql_command(user_session);
 
3841
 
 
3842
        if ((sql_command == SQLCOM_ALTER_TABLE
 
3843
             || sql_command == SQLCOM_CREATE_INDEX
 
3844
             || sql_command == SQLCOM_DROP_INDEX)
 
3845
            && num_write_row >= 10000) {
 
3846
                /* ALTER TABLE is COMMITted at every 10000 copied rows.
 
3847
                The IX table lock for the original table has to be re-issued.
 
3848
                As this method will be called on a temporary table where the
 
3849
                contents of the original table is being copied to, it is
 
3850
                a bit tricky to determine the source table.  The cursor
 
3851
                position in the source table need not be adjusted after the
 
3852
                intermediate COMMIT, since writes by other transactions are
 
3853
                being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
 
3854
 
 
3855
                dict_table_t*   src_table;
 
3856
                enum lock_mode  mode;
 
3857
 
 
3858
                num_write_row = 0;
 
3859
 
 
3860
                /* Commit the transaction.  This will release the table
 
3861
                locks, so they have to be acquired again. */
 
3862
 
 
3863
                /* Altering an InnoDB table */
 
3864
                /* Get the source table. */
 
3865
                src_table = lock_get_src_table(
 
3866
                                prebuilt->trx, prebuilt->table, &mode);
 
3867
                if (!src_table) {
4466
3868
no_commit:
4467
 
      /* Unknown situation: do not commit */
4468
 
      /*
4469
 
      ut_print_timestamp(stderr);
4470
 
      fprintf(stderr,
4471
 
        "  InnoDB: ALTER TABLE is holding lock"
4472
 
        " on %lu tables!\n",
4473
 
        prebuilt->trx->mysql_n_tables_locked);
4474
 
      */
4475
 
      ;
4476
 
    } else if (src_table == prebuilt->table) {
4477
 
      /* Source table is not in InnoDB format:
4478
 
      no need to re-acquire locks on it. */
4479
 
 
4480
 
      /* Altering to InnoDB format */
4481
 
      getTransactionalEngine()->commit(user_session, 1);
4482
 
      /* We will need an IX lock on the destination table. */
4483
 
      prebuilt->sql_stat_start = TRUE;
4484
 
    } else {
4485
 
      /* Ensure that there are no other table locks than
4486
 
      LOCK_IX and LOCK_AUTO_INC on the destination table. */
4487
 
 
4488
 
      if (!lock_is_table_exclusive(prebuilt->table,
4489
 
              prebuilt->trx)) {
4490
 
        goto no_commit;
4491
 
      }
4492
 
 
4493
 
      /* Commit the transaction.  This will release the table
4494
 
      locks, so they have to be acquired again. */
4495
 
      getTransactionalEngine()->commit(user_session, 1);
4496
 
      /* Re-acquire the table lock on the source table. */
4497
 
      row_lock_table_for_mysql(prebuilt, src_table, mode);
4498
 
      /* We will need an IX lock on the destination table. */
4499
 
      prebuilt->sql_stat_start = TRUE;
4500
 
    }
4501
 
  }
4502
 
 
4503
 
  num_write_row++;
4504
 
 
4505
 
  /* This is the case where the table has an auto-increment column */
4506
 
  if (getTable()->next_number_field && record == getTable()->getInsertRecord()) {
4507
 
 
4508
 
    /* Reset the error code before calling
4509
 
    innobase_get_auto_increment(). */
4510
 
    prebuilt->autoinc_error = DB_SUCCESS;
4511
 
 
4512
 
    if ((error = update_auto_increment())) {
4513
 
      /* We don't want to mask autoinc overflow errors. */
4514
 
 
4515
 
      /* Handle the case where the AUTOINC sub-system
4516
 
         failed during initialization. */
4517
 
      if (prebuilt->autoinc_error == DB_UNSUPPORTED) {
4518
 
        error_result = ER_AUTOINC_READ_FAILED;
4519
 
        /* Set the error message to report too. */
4520
 
        my_error(ER_AUTOINC_READ_FAILED, MYF(0));
4521
 
        goto func_exit;
4522
 
      } else if (prebuilt->autoinc_error != DB_SUCCESS) {
4523
 
        error = (int) prebuilt->autoinc_error;
4524
 
 
4525
 
        goto report_error;
4526
 
      }
4527
 
 
4528
 
      /* MySQL errors are passed straight back. */
4529
 
      error_result = (int) error;
4530
 
      goto func_exit;
4531
 
    }
4532
 
 
4533
 
    auto_inc_used = TRUE;
4534
 
  }
4535
 
 
4536
 
  if (prebuilt->mysql_template == NULL
4537
 
      || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
4538
 
 
4539
 
    /* Build the template used in converting quickly between
4540
 
    the two database formats */
4541
 
 
4542
 
    build_template(prebuilt, NULL, getTable(), ROW_MYSQL_WHOLE_ROW);
4543
 
  }
4544
 
 
4545
 
  innodb_srv_conc_enter_innodb(prebuilt->trx);
4546
 
 
4547
 
  error = row_insert_for_mysql((byte*) record, prebuilt);
4548
 
 
4549
 
  user_session->setXaId(trx->id);
4550
 
 
4551
 
  /* Handle duplicate key errors */
4552
 
  if (auto_inc_used) {
4553
 
    ulint   err;
4554
 
    uint64_t  auto_inc;
4555
 
    uint64_t  col_max_value;
4556
 
 
4557
 
    /* Note the number of rows processed for this statement, used
4558
 
    by get_auto_increment() to determine the number of AUTO-INC
4559
 
    values to reserve. This is only useful for a mult-value INSERT
4560
 
    and is a statement level counter.*/
4561
 
    if (trx->n_autoinc_rows > 0) {
4562
 
      --trx->n_autoinc_rows;
4563
 
    }
4564
 
 
4565
 
    /* We need the upper limit of the col type to check for
4566
 
    whether we update the table autoinc counter or not. */
4567
 
    col_max_value = innobase_get_int_col_max_value(
4568
 
      getTable()->next_number_field); 
4569
 
    /* Get the value that MySQL attempted to store in the table.*/
4570
 
    auto_inc = getTable()->next_number_field->val_int();
4571
 
 
4572
 
    switch (error) {
4573
 
    case DB_DUPLICATE_KEY:
4574
 
 
4575
 
      /* A REPLACE command and LOAD DATA INFILE REPLACE
4576
 
      handle a duplicate key error themselves, but we
4577
 
      must update the autoinc counter if we are performing
4578
 
      those statements. */
4579
 
 
4580
 
      switch (sql_command) {
4581
 
      case SQLCOM_LOAD:
4582
 
        if ((trx->duplicates
4583
 
            & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
4584
 
 
4585
 
          goto set_max_autoinc;
4586
 
        }
4587
 
        break;
4588
 
 
4589
 
      case SQLCOM_REPLACE:
4590
 
      case SQLCOM_INSERT_SELECT:
4591
 
      case SQLCOM_REPLACE_SELECT:
4592
 
        goto set_max_autoinc;
4593
 
 
4594
 
      default:
4595
 
        break;
4596
 
      }
4597
 
 
4598
 
      break;
4599
 
 
4600
 
    case DB_SUCCESS:
4601
 
      /* If the actual value inserted is greater than
4602
 
      the upper limit of the interval, then we try and
4603
 
      update the table upper limit. Note: last_value
4604
 
      will be 0 if get_auto_increment() was not called.*/
4605
 
 
4606
 
      if (auto_inc >= prebuilt->autoinc_last_value) {
 
3869
                        /* Unknown situation: do not commit */
 
3870
                        /*
 
3871
                        ut_print_timestamp(stderr);
 
3872
                        fprintf(stderr,
 
3873
                                "  InnoDB: ALTER TABLE is holding lock"
 
3874
                                " on %lu tables!\n",
 
3875
                                prebuilt->trx->mysql_n_tables_locked);
 
3876
                        */
 
3877
                        ;
 
3878
                } else if (src_table == prebuilt->table) {
 
3879
                        /* Source table is not in InnoDB format:
 
3880
                        no need to re-acquire locks on it. */
 
3881
 
 
3882
                        /* Altering to InnoDB format */
 
3883
                        engine->commit(user_session, 1);
 
3884
                        /* Note that this transaction is still active. */
 
3885
                        prebuilt->trx->active_trans = 1;
 
3886
                        /* We will need an IX lock on the destination table. */
 
3887
                        prebuilt->sql_stat_start = TRUE;
 
3888
                } else {
 
3889
                        /* Ensure that there are no other table locks than
 
3890
                        LOCK_IX and LOCK_AUTO_INC on the destination table. */
 
3891
 
 
3892
                        if (!lock_is_table_exclusive(prebuilt->table,
 
3893
                                                        prebuilt->trx)) {
 
3894
                                goto no_commit;
 
3895
                        }
 
3896
 
 
3897
                        /* Commit the transaction.  This will release the table
 
3898
                        locks, so they have to be acquired again. */
 
3899
                        engine->commit(user_session, 1);
 
3900
                        /* Note that this transaction is still active. */
 
3901
                        prebuilt->trx->active_trans = 1;
 
3902
                        /* Re-acquire the table lock on the source table. */
 
3903
                        row_lock_table_for_mysql(prebuilt, src_table, mode);
 
3904
                        /* We will need an IX lock on the destination table. */
 
3905
                        prebuilt->sql_stat_start = TRUE;
 
3906
                }
 
3907
        }
 
3908
 
 
3909
        num_write_row++;
 
3910
 
 
3911
        /* This is the case where the table has an auto-increment column */
 
3912
        if (table->next_number_field && record == table->record[0]) {
 
3913
 
 
3914
                /* Reset the error code before calling
 
3915
                innobase_get_auto_increment(). */
 
3916
                prebuilt->autoinc_error = DB_SUCCESS;
 
3917
 
 
3918
                if ((error = update_auto_increment())) {
 
3919
 
 
3920
                        /* We don't want to mask autoinc overflow errors. */
 
3921
                        if (prebuilt->autoinc_error != DB_SUCCESS) {
 
3922
                                error = (int) prebuilt->autoinc_error;
 
3923
 
 
3924
                                goto report_error;
 
3925
                        }
 
3926
 
 
3927
                        /* MySQL errors are passed straight back. */
 
3928
                        error_result = (int) error;
 
3929
                        goto func_exit;
 
3930
                }
 
3931
 
 
3932
                auto_inc_used = TRUE;
 
3933
        }
 
3934
 
 
3935
        if (prebuilt->mysql_template == NULL
 
3936
            || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
 
3937
 
 
3938
                /* Build the template used in converting quickly between
 
3939
                the two database formats */
 
3940
 
 
3941
                build_template(prebuilt, NULL, table,
 
3942
                               ROW_MYSQL_WHOLE_ROW);
 
3943
        }
 
3944
 
 
3945
        innodb_srv_conc_enter_innodb(prebuilt->trx);
 
3946
 
 
3947
        error = row_insert_for_mysql((byte*) record, prebuilt);
 
3948
 
 
3949
        /* Handle duplicate key errors */
 
3950
        if (auto_inc_used) {
 
3951
                ulint           err;
 
3952
                uint64_t        auto_inc;
 
3953
                uint64_t        col_max_value;
 
3954
 
 
3955
                /* Note the number of rows processed for this statement, used
 
3956
                by get_auto_increment() to determine the number of AUTO-INC
 
3957
                values to reserve. This is only useful for a mult-value INSERT
 
3958
                and is a statement level counter.*/
 
3959
                if (trx->n_autoinc_rows > 0) {
 
3960
                        --trx->n_autoinc_rows;
 
3961
                }
 
3962
 
 
3963
                /* We need the upper limit of the col type to check for
 
3964
                whether we update the table autoinc counter or not. */
 
3965
                col_max_value = innobase_get_int_col_max_value(
 
3966
                        table->next_number_field);
 
3967
 
 
3968
                /* Get the value that MySQL attempted to store in the table.*/
 
3969
                auto_inc = table->next_number_field->val_int();
 
3970
 
 
3971
                switch (error) {
 
3972
                case DB_DUPLICATE_KEY:
 
3973
 
 
3974
                        /* A REPLACE command and LOAD DATA INFILE REPLACE
 
3975
                        handle a duplicate key error themselves, but we
 
3976
                        must update the autoinc counter if we are performing
 
3977
                        those statements. */
 
3978
 
 
3979
                        switch (sql_command) {
 
3980
                        case SQLCOM_LOAD:
 
3981
                                if ((trx->duplicates
 
3982
                                    & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
 
3983
 
 
3984
                                        goto set_max_autoinc;
 
3985
                                }
 
3986
                                break;
 
3987
 
 
3988
                        case SQLCOM_REPLACE:
 
3989
                        case SQLCOM_INSERT_SELECT:
 
3990
                        case SQLCOM_REPLACE_SELECT:
 
3991
                                goto set_max_autoinc;
 
3992
 
 
3993
                        default:
 
3994
                                break;
 
3995
                        }
 
3996
 
 
3997
                        break;
 
3998
 
 
3999
                case DB_SUCCESS:
 
4000
                        /* If the actual value inserted is greater than
 
4001
                        the upper limit of the interval, then we try and
 
4002
                        update the table upper limit. Note: last_value
 
4003
                        will be 0 if get_auto_increment() was not called.*/
 
4004
 
 
4005
                        if (auto_inc <= col_max_value
 
4006
                            && auto_inc >= prebuilt->autoinc_last_value) {
4607
4007
set_max_autoinc:
4608
 
        /* This should filter out the negative
4609
 
           values set explicitly by the user. */
4610
 
        if (auto_inc <= col_max_value) {
4611
 
          ut_a(prebuilt->autoinc_increment > 0);
4612
 
 
4613
 
          uint64_t      need;
4614
 
          uint64_t      offset;
4615
 
 
4616
 
          offset = prebuilt->autoinc_offset;
4617
 
          need = prebuilt->autoinc_increment;
4618
 
 
4619
 
          auto_inc = innobase_next_autoinc(
4620
 
                                           auto_inc,
4621
 
                                           need, offset, col_max_value);
4622
 
 
4623
 
          err = innobase_set_max_autoinc(
4624
 
                                         auto_inc);
4625
 
 
4626
 
          if (err != DB_SUCCESS) {
4627
 
            error = err;
4628
 
          }
4629
 
        }
4630
 
      }
4631
 
      break;
4632
 
    }
4633
 
  }
4634
 
 
4635
 
  innodb_srv_conc_exit_innodb(prebuilt->trx);
 
4008
                                ut_a(prebuilt->autoinc_increment > 0);
 
4009
 
 
4010
                                uint64_t        need;
 
4011
                                uint64_t        offset;
 
4012
 
 
4013
                                offset = prebuilt->autoinc_offset;
 
4014
                                need = prebuilt->autoinc_increment;
 
4015
 
 
4016
                                auto_inc = innobase_next_autoinc(
 
4017
                                        auto_inc, need, offset, col_max_value);
 
4018
 
 
4019
                                err = innobase_set_max_autoinc(auto_inc);
 
4020
 
 
4021
                                if (err != DB_SUCCESS) {
 
4022
                                        error = err;
 
4023
                                }
 
4024
                        }
 
4025
                        break;
 
4026
                }
 
4027
        }
 
4028
 
 
4029
        innodb_srv_conc_exit_innodb(prebuilt->trx);
4636
4030
 
4637
4031
report_error:
4638
 
  error_result = convert_error_code_to_mysql((int) error,
4639
 
               prebuilt->table->flags,
4640
 
               user_session);
 
4032
        error_result = convert_error_code_to_mysql((int) error,
 
4033
                                                   prebuilt->table->flags,
 
4034
                                                   user_session);
4641
4035
 
4642
4036
func_exit:
4643
 
  innobase_active_small();
 
4037
        innobase_active_small();
4644
4038
 
4645
 
  return(error_result);
 
4039
        return(error_result);
4646
4040
}
4647
4041
 
4648
4042
/**********************************************************************//**
4649
4043
Checks which fields have changed in a row and stores information
4650
4044
of them to an update vector.
4651
 
@return error number or 0 */
 
4045
@return error number or 0 */
4652
4046
static
4653
4047
int
4654
4048
calc_row_difference(
4655
4049
/*================*/
4656
 
  upd_t*    uvect,    /*!< in/out: update vector */
4657
 
  unsigned char*    old_row,  /*!< in: old row in MySQL format */
4658
 
  unsigned char*    new_row,  /*!< in: new row in MySQL format */
4659
 
  Table* table,   /*!< in: table in MySQL data
4660
 
          dictionary */
4661
 
  unsigned char*  upd_buff, /*!< in: buffer to use */
4662
 
  ulint   buff_len, /*!< in: buffer length */
4663
 
  row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */
4664
 
  Session*  )   /*!< in: user thread */
 
4050
        upd_t*          uvect,          /*!< in/out: update vector */
 
4051
        unsigned char*          old_row,        /*!< in: old row in MySQL format */
 
4052
        unsigned char*          new_row,        /*!< in: new row in MySQL format */
 
4053
        Table* table,           /*!< in: table in MySQL data
 
4054
                                        dictionary */
 
4055
        unsigned char*  upd_buff,       /*!< in: buffer to use */
 
4056
        ulint           buff_len,       /*!< in: buffer length */
 
4057
        row_prebuilt_t* prebuilt,       /*!< in: InnoDB prebuilt struct */
 
4058
        Session*        )               /*!< in: user thread */
4665
4059
{
4666
 
  unsigned char*    original_upd_buff = upd_buff;
4667
 
  enum_field_types field_mysql_type;
4668
 
  uint    n_fields;
4669
 
  ulint   o_len;
4670
 
  ulint   n_len;
4671
 
  ulint   col_pack_len;
4672
 
  const byte* new_mysql_row_col;
4673
 
  const byte* o_ptr;
4674
 
  const byte* n_ptr;
4675
 
  byte*   buf;
4676
 
  upd_field_t*  ufield;
4677
 
  ulint   col_type;
4678
 
  ulint   n_changed = 0;
4679
 
  dfield_t  dfield;
4680
 
  dict_index_t* clust_index;
4681
 
  uint    i= 0;
4682
 
 
4683
 
  n_fields = table->getShare()->sizeFields();
4684
 
  clust_index = dict_table_get_first_index(prebuilt->table);
4685
 
 
4686
 
  /* We use upd_buff to convert changed fields */
4687
 
  buf = (byte*) upd_buff;
4688
 
 
4689
 
  for (i = 0; i < n_fields; i++) {
4690
 
    Field *field= table->getField(i);
4691
 
 
4692
 
    o_ptr = (const byte*) old_row + get_field_offset(table, field);
4693
 
    n_ptr = (const byte*) new_row + get_field_offset(table, field);
4694
 
 
4695
 
    /* Use new_mysql_row_col and col_pack_len save the values */
4696
 
 
4697
 
    new_mysql_row_col = n_ptr;
4698
 
    col_pack_len = field->pack_length();
4699
 
 
4700
 
    o_len = col_pack_len;
4701
 
    n_len = col_pack_len;
4702
 
 
4703
 
    /* We use o_ptr and n_ptr to dig up the actual data for
4704
 
    comparison. */
4705
 
 
4706
 
    field_mysql_type = field->type();
4707
 
 
4708
 
    col_type = prebuilt->table->cols[i].mtype;
4709
 
 
4710
 
    switch (col_type) {
4711
 
 
4712
 
    case DATA_BLOB:
4713
 
      o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
4714
 
      n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
4715
 
 
4716
 
      break;
4717
 
 
4718
 
    case DATA_VARCHAR:
4719
 
    case DATA_BINARY:
4720
 
    case DATA_VARMYSQL:
4721
 
      if (field_mysql_type == DRIZZLE_TYPE_VARCHAR) {
4722
 
        /* This is a >= 5.0.3 type true VARCHAR where
4723
 
        the real payload data length is stored in
4724
 
        1 or 2 bytes */
4725
 
 
4726
 
        o_ptr = row_mysql_read_true_varchar(
4727
 
          &o_len, o_ptr,
4728
 
          (ulint)
4729
 
          (((Field_varstring*)field)->pack_length_no_ptr()));
4730
 
 
4731
 
        n_ptr = row_mysql_read_true_varchar(
4732
 
          &n_len, n_ptr,
4733
 
          (ulint)
4734
 
          (((Field_varstring*)field)->pack_length_no_ptr()));
4735
 
      }
4736
 
 
4737
 
      break;
4738
 
    default:
4739
 
      ;
4740
 
    }
4741
 
 
4742
 
    if (field->null_ptr) {
4743
 
      if (field_in_record_is_null(table, field,
4744
 
              (char*) old_row)) {
4745
 
        o_len = UNIV_SQL_NULL;
4746
 
      }
4747
 
 
4748
 
      if (field_in_record_is_null(table, field,
4749
 
              (char*) new_row)) {
4750
 
        n_len = UNIV_SQL_NULL;
4751
 
      }
4752
 
    }
4753
 
 
4754
 
    if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
4755
 
          0 != memcmp(o_ptr, n_ptr, o_len))) {
4756
 
      /* The field has changed */
4757
 
 
4758
 
      ufield = uvect->fields + n_changed;
4759
 
 
4760
 
      /* Let us use a dummy dfield to make the conversion
4761
 
      from the MySQL column format to the InnoDB format */
4762
 
 
4763
 
      dict_col_copy_type(prebuilt->table->cols + i,
4764
 
                 &dfield.type);
4765
 
 
4766
 
      if (n_len != UNIV_SQL_NULL) {
4767
 
        buf = row_mysql_store_col_in_innobase_format(
4768
 
          &dfield,
4769
 
          (byte*)buf,
4770
 
          TRUE,
4771
 
          new_mysql_row_col,
4772
 
          col_pack_len,
4773
 
          dict_table_is_comp(prebuilt->table));
4774
 
        dfield_copy_data(&ufield->new_val, &dfield);
4775
 
      } else {
4776
 
        dfield_set_null(&ufield->new_val);
4777
 
      }
4778
 
 
4779
 
      ufield->exp = NULL;
4780
 
      ufield->orig_len = 0;
4781
 
      ufield->field_no = dict_col_get_clust_pos(
4782
 
        &prebuilt->table->cols[i], clust_index);
4783
 
      n_changed++;
4784
 
    }
4785
 
  }
4786
 
 
4787
 
  uvect->n_fields = n_changed;
4788
 
  uvect->info_bits = 0;
4789
 
 
4790
 
  ut_a(buf <= (byte*)original_upd_buff + buff_len);
4791
 
 
4792
 
  return(0);
 
4060
        unsigned char*          original_upd_buff = upd_buff;
 
4061
        Field*          field;
 
4062
        enum_field_types field_mysql_type;
 
4063
        uint            n_fields;
 
4064
        ulint           o_len;
 
4065
        ulint           n_len;
 
4066
        ulint           col_pack_len;
 
4067
        const byte*     new_mysql_row_col;
 
4068
        const byte*     o_ptr;
 
4069
        const byte*     n_ptr;
 
4070
        byte*           buf;
 
4071
        upd_field_t*    ufield;
 
4072
        ulint           col_type;
 
4073
        ulint           n_changed = 0;
 
4074
        dfield_t        dfield;
 
4075
        dict_index_t*   clust_index;
 
4076
        uint            i= 0;
 
4077
 
 
4078
        n_fields = table->s->fields;
 
4079
        clust_index = dict_table_get_first_index(prebuilt->table);
 
4080
 
 
4081
        /* We use upd_buff to convert changed fields */
 
4082
        buf = (byte*) upd_buff;
 
4083
 
 
4084
        for (i = 0; i < n_fields; i++) {
 
4085
                field = table->field[i];
 
4086
 
 
4087
                o_ptr = (const byte*) old_row + get_field_offset(table, field);
 
4088
                n_ptr = (const byte*) new_row + get_field_offset(table, field);
 
4089
 
 
4090
                /* Use new_mysql_row_col and col_pack_len save the values */
 
4091
 
 
4092
                new_mysql_row_col = n_ptr;
 
4093
                col_pack_len = field->pack_length();
 
4094
 
 
4095
                o_len = col_pack_len;
 
4096
                n_len = col_pack_len;
 
4097
 
 
4098
                /* We use o_ptr and n_ptr to dig up the actual data for
 
4099
                comparison. */
 
4100
 
 
4101
                field_mysql_type = field->type();
 
4102
 
 
4103
                col_type = prebuilt->table->cols[i].mtype;
 
4104
 
 
4105
                switch (col_type) {
 
4106
 
 
4107
                case DATA_BLOB:
 
4108
                        o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
 
4109
                        n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
 
4110
 
 
4111
                        break;
 
4112
 
 
4113
                case DATA_VARCHAR:
 
4114
                case DATA_BINARY:
 
4115
                case DATA_VARMYSQL:
 
4116
                        if (field_mysql_type == DRIZZLE_TYPE_VARCHAR) {
 
4117
                                /* This is a >= 5.0.3 type true VARCHAR where
 
4118
                                the real payload data length is stored in
 
4119
                                1 or 2 bytes */
 
4120
 
 
4121
                                o_ptr = row_mysql_read_true_varchar(
 
4122
                                        &o_len, o_ptr,
 
4123
                                        (ulint)
 
4124
                                        (((Field_varstring*)field)->length_bytes));
 
4125
 
 
4126
                                n_ptr = row_mysql_read_true_varchar(
 
4127
                                        &n_len, n_ptr,
 
4128
                                        (ulint)
 
4129
                                        (((Field_varstring*)field)->length_bytes));
 
4130
                        }
 
4131
 
 
4132
                        break;
 
4133
                default:
 
4134
                        ;
 
4135
                }
 
4136
 
 
4137
                if (field->null_ptr) {
 
4138
                        if (field_in_record_is_null(table, field,
 
4139
                                                        (char*) old_row)) {
 
4140
                                o_len = UNIV_SQL_NULL;
 
4141
                        }
 
4142
 
 
4143
                        if (field_in_record_is_null(table, field,
 
4144
                                                        (char*) new_row)) {
 
4145
                                n_len = UNIV_SQL_NULL;
 
4146
                        }
 
4147
                }
 
4148
 
 
4149
                if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
 
4150
                                        0 != memcmp(o_ptr, n_ptr, o_len))) {
 
4151
                        /* The field has changed */
 
4152
 
 
4153
                        ufield = uvect->fields + n_changed;
 
4154
 
 
4155
                        /* Let us use a dummy dfield to make the conversion
 
4156
                        from the MySQL column format to the InnoDB format */
 
4157
 
 
4158
                        dict_col_copy_type(prebuilt->table->cols + i,
 
4159
                                                     &dfield.type);
 
4160
 
 
4161
                        if (n_len != UNIV_SQL_NULL) {
 
4162
                                buf = row_mysql_store_col_in_innobase_format(
 
4163
                                        &dfield,
 
4164
                                        (byte*)buf,
 
4165
                                        TRUE,
 
4166
                                        new_mysql_row_col,
 
4167
                                        col_pack_len,
 
4168
                                        dict_table_is_comp(prebuilt->table));
 
4169
                                dfield_copy_data(&ufield->new_val, &dfield);
 
4170
                        } else {
 
4171
                                dfield_set_null(&ufield->new_val);
 
4172
                        }
 
4173
 
 
4174
                        ufield->exp = NULL;
 
4175
                        ufield->orig_len = 0;
 
4176
                        ufield->field_no = dict_col_get_clust_pos(
 
4177
                                &prebuilt->table->cols[i], clust_index);
 
4178
                        n_changed++;
 
4179
                }
 
4180
        }
 
4181
 
 
4182
        uvect->n_fields = n_changed;
 
4183
        uvect->info_bits = 0;
 
4184
 
 
4185
        ut_a(buf <= (byte*)original_upd_buff + buff_len);
 
4186
 
 
4187
        return(0);
4793
4188
}
4794
4189
 
4795
4190
/**********************************************************************//**
4799
4194
TODO: currently InnoDB does not prevent the 'Halloween problem':
4800
4195
in a searched update a single row can get updated several times
4801
4196
if its index columns are updated!
4802
 
@return error number or 0 */
 
4197
@return error number or 0 */
4803
4198
UNIV_INTERN
4804
4199
int
4805
 
ha_innobase::doUpdateRecord(
 
4200
ha_innobase::update_row(
4806
4201
/*====================*/
4807
 
  const unsigned char*  old_row,/*!< in: old row in MySQL format */
4808
 
  unsigned char*    new_row)/*!< in: new row in MySQL format */
 
4202
        const unsigned char*    old_row,/*!< in: old row in MySQL format */
 
4203
        unsigned char*          new_row)/*!< in: new row in MySQL format */
4809
4204
{
4810
 
  upd_t*    uvect;
4811
 
  int   error = 0;
4812
 
  trx_t*    trx = session_to_trx(user_session);
4813
 
 
4814
 
  ut_a(prebuilt->trx == trx);
4815
 
 
4816
 
  if (prebuilt->upd_node) {
4817
 
    uvect = prebuilt->upd_node->update;
4818
 
  } else {
4819
 
    uvect = row_get_prebuilt_update_vector(prebuilt);
4820
 
  }
4821
 
 
4822
 
  /* Build an update vector from the modified fields in the rows
4823
 
  (uses upd_buff of the handle) */
4824
 
 
4825
 
  calc_row_difference(uvect, (unsigned char*) old_row, new_row, getTable(),
4826
 
      &upd_buff[0], (ulint)upd_and_key_val_buff_len,
4827
 
      prebuilt, user_session);
4828
 
 
4829
 
  /* This is not a delete */
4830
 
  prebuilt->upd_node->is_delete = FALSE;
4831
 
 
4832
 
  ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
4833
 
 
4834
 
  if (getTable()->found_next_number_field)
4835
 
  {
4836
 
    uint64_t  auto_inc;
4837
 
    uint64_t  col_max_value;
4838
 
 
4839
 
    auto_inc = getTable()->found_next_number_field->val_int();
4840
 
 
4841
 
    /* We need the upper limit of the col type to check for
4842
 
    whether we update the table autoinc counter or not. */
4843
 
    col_max_value = innobase_get_int_col_max_value(
4844
 
      getTable()->found_next_number_field);
4845
 
 
4846
 
    uint64_t current_autoinc;
4847
 
    ulint autoinc_error= innobase_get_autoinc(&current_autoinc);
4848
 
    if (autoinc_error == DB_SUCCESS
4849
 
        && auto_inc <= col_max_value && auto_inc != 0
4850
 
        && auto_inc >= current_autoinc)
4851
 
    {
4852
 
 
4853
 
      uint64_t  need;
4854
 
      uint64_t  offset;
4855
 
 
4856
 
      offset = prebuilt->autoinc_offset;
4857
 
      need = prebuilt->autoinc_increment;
4858
 
 
4859
 
      auto_inc = innobase_next_autoinc(
4860
 
        auto_inc, need, offset, col_max_value);
4861
 
 
4862
 
      dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
4863
 
    }
4864
 
 
4865
 
    dict_table_autoinc_unlock(prebuilt->table);
4866
 
  }
4867
 
 
4868
 
  innodb_srv_conc_enter_innodb(trx);
4869
 
 
4870
 
  error = row_update_for_mysql((byte*) old_row, prebuilt);
4871
 
 
4872
 
  user_session->setXaId(trx->id);
4873
 
 
4874
 
  /* We need to do some special AUTOINC handling for the following case:
4875
 
 
4876
 
  INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
4877
 
 
4878
 
  We need to use the AUTOINC counter that was actually used by
4879
 
  MySQL in the UPDATE statement, which can be different from the
4880
 
  value used in the INSERT statement.*/
4881
 
 
4882
 
  if (error == DB_SUCCESS
4883
 
      && getTable()->next_number_field
4884
 
      && new_row == getTable()->getInsertRecord()
4885
 
      && session_sql_command(user_session) == SQLCOM_INSERT
4886
 
      && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
4887
 
    == TRX_DUP_IGNORE)  {
4888
 
 
4889
 
    uint64_t  auto_inc;
4890
 
    uint64_t  col_max_value;
4891
 
 
4892
 
    auto_inc = getTable()->next_number_field->val_int();
4893
 
 
4894
 
    /* We need the upper limit of the col type to check for
4895
 
    whether we update the table autoinc counter or not. */
4896
 
    col_max_value = innobase_get_int_col_max_value(
4897
 
      getTable()->next_number_field);
4898
 
 
4899
 
    if (auto_inc <= col_max_value && auto_inc != 0) {
4900
 
 
4901
 
      uint64_t  need;
4902
 
      uint64_t  offset;
4903
 
 
4904
 
      offset = prebuilt->autoinc_offset;
4905
 
      need = prebuilt->autoinc_increment;
4906
 
 
4907
 
      auto_inc = innobase_next_autoinc(
4908
 
        auto_inc, need, offset, col_max_value);
4909
 
 
4910
 
      error = innobase_set_max_autoinc(auto_inc);
4911
 
    }
4912
 
  }
4913
 
 
4914
 
  innodb_srv_conc_exit_innodb(trx);
4915
 
 
4916
 
  error = convert_error_code_to_mysql(error,
4917
 
              prebuilt->table->flags,
 
4205
        upd_t*          uvect;
 
4206
        int             error = 0;
 
4207
        trx_t*          trx = session_to_trx(user_session);
 
4208
 
 
4209
        ut_a(prebuilt->trx == trx);
 
4210
 
 
4211
        ha_statistic_increment(&SSV::ha_update_count);
 
4212
 
 
4213
        if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
 
4214
                table->timestamp_field->set_time();
 
4215
 
 
4216
        if (prebuilt->upd_node) {
 
4217
                uvect = prebuilt->upd_node->update;
 
4218
        } else {
 
4219
                uvect = row_get_prebuilt_update_vector(prebuilt);
 
4220
        }
 
4221
 
 
4222
        /* Build an update vector from the modified fields in the rows
 
4223
        (uses upd_buff of the handle) */
 
4224
 
 
4225
        calc_row_difference(uvect, (unsigned char*) old_row, new_row, table,
 
4226
                        upd_buff, (ulint)upd_and_key_val_buff_len,
 
4227
                        prebuilt, user_session);
 
4228
 
 
4229
        /* This is not a delete */
 
4230
        prebuilt->upd_node->is_delete = FALSE;
 
4231
 
 
4232
        ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
 
4233
 
 
4234
        innodb_srv_conc_enter_innodb(trx);
 
4235
 
 
4236
        error = row_update_for_mysql((byte*) old_row, prebuilt);
 
4237
 
 
4238
        /* We need to do some special AUTOINC handling for the following case:
 
4239
 
 
4240
        INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
 
4241
 
 
4242
        We need to use the AUTOINC counter that was actually used by
 
4243
        MySQL in the UPDATE statement, which can be different from the
 
4244
        value used in the INSERT statement.*/
 
4245
 
 
4246
        if (error == DB_SUCCESS
 
4247
            && table->next_number_field
 
4248
            && new_row == table->record[0]
 
4249
            && session_sql_command(user_session) == SQLCOM_INSERT
 
4250
            && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
 
4251
                == TRX_DUP_IGNORE)  {
 
4252
 
 
4253
                uint64_t        auto_inc;
 
4254
                uint64_t        col_max_value;
 
4255
 
 
4256
                auto_inc = table->next_number_field->val_int();
 
4257
 
 
4258
                /* We need the upper limit of the col type to check for
 
4259
                whether we update the table autoinc counter or not. */
 
4260
                col_max_value = innobase_get_int_col_max_value(
 
4261
                        table->next_number_field);
 
4262
 
 
4263
                if (auto_inc <= col_max_value && auto_inc != 0) {
 
4264
 
 
4265
                        uint64_t        need;
 
4266
                        uint64_t        offset;
 
4267
 
 
4268
                        offset = prebuilt->autoinc_offset;
 
4269
                        need = prebuilt->autoinc_increment;
 
4270
 
 
4271
                        auto_inc = innobase_next_autoinc(
 
4272
                                auto_inc, need, offset, col_max_value);
 
4273
 
 
4274
                        error = innobase_set_max_autoinc(auto_inc);
 
4275
                }
 
4276
        }
 
4277
 
 
4278
        innodb_srv_conc_exit_innodb(trx);
 
4279
 
 
4280
        error = convert_error_code_to_mysql(error,
 
4281
                                            prebuilt->table->flags,
4918
4282
                                            user_session);
4919
4283
 
4920
 
  if (error == 0 /* success */
4921
 
      && uvect->n_fields == 0 /* no columns were updated */) {
4922
 
 
4923
 
    /* This is the same as success, but instructs
4924
 
    MySQL that the row is not really updated and it
4925
 
    should not increase the count of updated rows.
4926
 
    This is fix for http://bugs.mysql.com/29157 */
4927
 
    error = HA_ERR_RECORD_IS_THE_SAME;
4928
 
  }
4929
 
 
4930
 
  /* Tell InnoDB server that there might be work for
4931
 
  utility threads: */
4932
 
 
4933
 
  innobase_active_small();
4934
 
 
4935
 
  return(error);
 
4284
        if (error == 0 /* success */
 
4285
            && uvect->n_fields == 0 /* no columns were updated */) {
 
4286
 
 
4287
                /* This is the same as success, but instructs
 
4288
                MySQL that the row is not really updated and it
 
4289
                should not increase the count of updated rows.
 
4290
                This is fix for http://bugs.mysql.com/29157 */
 
4291
                error = HA_ERR_RECORD_IS_THE_SAME;
 
4292
        }
 
4293
 
 
4294
        /* Tell InnoDB server that there might be work for
 
4295
        utility threads: */
 
4296
 
 
4297
        innobase_active_small();
 
4298
 
 
4299
        return(error);
4936
4300
}
4937
4301
 
4938
4302
/**********************************************************************//**
4939
4303
Deletes a row given as the parameter.
4940
 
@return error number or 0 */
 
4304
@return error number or 0 */
4941
4305
UNIV_INTERN
4942
4306
int
4943
 
ha_innobase::doDeleteRecord(
 
4307
ha_innobase::delete_row(
4944
4308
/*====================*/
4945
 
  const unsigned char*  record) /*!< in: a row in MySQL format */
 
4309
        const unsigned char*    record) /*!< in: a row in MySQL format */
4946
4310
{
4947
 
  int   error = 0;
4948
 
  trx_t*    trx = session_to_trx(user_session);
4949
 
 
4950
 
  ut_a(prebuilt->trx == trx);
4951
 
 
4952
 
  if (!prebuilt->upd_node) {
4953
 
    row_get_prebuilt_update_vector(prebuilt);
4954
 
  }
4955
 
 
4956
 
  /* This is a delete */
4957
 
 
4958
 
  prebuilt->upd_node->is_delete = TRUE;
4959
 
 
4960
 
  innodb_srv_conc_enter_innodb(trx);
4961
 
 
4962
 
  error = row_update_for_mysql((byte*) record, prebuilt);
4963
 
 
4964
 
  user_session->setXaId(trx->id);
4965
 
 
4966
 
  innodb_srv_conc_exit_innodb(trx);
4967
 
 
4968
 
  error = convert_error_code_to_mysql(
4969
 
    error, prebuilt->table->flags, user_session);
4970
 
 
4971
 
  /* Tell the InnoDB server that there might be work for
4972
 
  utility threads: */
4973
 
 
4974
 
  innobase_active_small();
4975
 
 
4976
 
  return(error);
 
4311
        int             error = 0;
 
4312
        trx_t*          trx = session_to_trx(user_session);
 
4313
 
 
4314
        ut_a(prebuilt->trx == trx);
 
4315
 
 
4316
        ha_statistic_increment(&SSV::ha_delete_count);
 
4317
 
 
4318
        if (!prebuilt->upd_node) {
 
4319
                row_get_prebuilt_update_vector(prebuilt);
 
4320
        }
 
4321
 
 
4322
        /* This is a delete */
 
4323
 
 
4324
        prebuilt->upd_node->is_delete = TRUE;
 
4325
 
 
4326
        innodb_srv_conc_enter_innodb(trx);
 
4327
 
 
4328
        error = row_update_for_mysql((byte*) record, prebuilt);
 
4329
 
 
4330
        innodb_srv_conc_exit_innodb(trx);
 
4331
 
 
4332
        error = convert_error_code_to_mysql(
 
4333
                error, prebuilt->table->flags, user_session);
 
4334
 
 
4335
        /* Tell the InnoDB server that there might be work for
 
4336
        utility threads: */
 
4337
 
 
4338
        innobase_active_small();
 
4339
 
 
4340
        return(error);
4977
4341
}
4978
4342
 
4979
4343
/**********************************************************************//**
4985
4349
ha_innobase::unlock_row(void)
4986
4350
/*=========================*/
4987
4351
{
4988
 
  /* Consistent read does not take any locks, thus there is
4989
 
  nothing to unlock. */
4990
 
 
4991
 
  if (prebuilt->select_lock_type == LOCK_NONE) {
4992
 
    return;
4993
 
  }
4994
 
 
4995
 
  switch (prebuilt->row_read_type) {
4996
 
  case ROW_READ_WITH_LOCKS:
4997
 
    if (!srv_locks_unsafe_for_binlog
4998
 
        && prebuilt->trx->isolation_level
4999
 
        > TRX_ISO_READ_COMMITTED) {
5000
 
      break;
5001
 
    }
5002
 
    /* fall through */
5003
 
  case ROW_READ_TRY_SEMI_CONSISTENT:
5004
 
    row_unlock_for_mysql(prebuilt, FALSE);
5005
 
    break;
5006
 
  case ROW_READ_DID_SEMI_CONSISTENT:
5007
 
    prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
5008
 
    break;
5009
 
  }
5010
 
 
5011
 
  return;
 
4352
        /* Consistent read does not take any locks, thus there is
 
4353
        nothing to unlock. */
 
4354
 
 
4355
        if (prebuilt->select_lock_type == LOCK_NONE) {
 
4356
          return;
 
4357
        }
 
4358
 
 
4359
        switch (prebuilt->row_read_type) {
 
4360
        case ROW_READ_WITH_LOCKS:
 
4361
                if (!srv_locks_unsafe_for_binlog
 
4362
                    && prebuilt->trx->isolation_level
 
4363
                    != TRX_ISO_READ_COMMITTED) {
 
4364
                        break;
 
4365
                }
 
4366
                /* fall through */
 
4367
        case ROW_READ_TRY_SEMI_CONSISTENT:
 
4368
                row_unlock_for_mysql(prebuilt, FALSE);
 
4369
                break;
 
4370
        case ROW_READ_DID_SEMI_CONSISTENT:
 
4371
                prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
 
4372
                break;
 
4373
        }
 
4374
 
 
4375
        return;
5012
4376
}
5013
4377
 
5014
4378
/* See Cursor.h and row0mysql.h for docs on this function. */
5017
4381
ha_innobase::was_semi_consistent_read(void)
5018
4382
/*=======================================*/
5019
4383
{
5020
 
  return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
 
4384
        return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
5021
4385
}
5022
4386
 
5023
4387
/* See Cursor.h and row0mysql.h for docs on this function. */
5026
4390
ha_innobase::try_semi_consistent_read(bool yes)
5027
4391
/*===========================================*/
5028
4392
{
5029
 
  ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
5030
 
 
5031
 
  /* Row read type is set to semi consistent read if this was
5032
 
  requested by the MySQL and either innodb_locks_unsafe_for_binlog
5033
 
  option is used or this session is using READ COMMITTED isolation
5034
 
  level. */
5035
 
 
5036
 
  if (yes
5037
 
      && (srv_locks_unsafe_for_binlog
5038
 
    || prebuilt->trx->isolation_level <= TRX_ISO_READ_COMMITTED)) {
5039
 
    prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
5040
 
  } else {
5041
 
    prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
5042
 
  }
 
4393
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
4394
 
 
4395
        /* Row read type is set to semi consistent read if this was
 
4396
        requested by the MySQL and either innodb_locks_unsafe_for_binlog
 
4397
        option is used or this session is using READ COMMITTED isolation
 
4398
        level. */
 
4399
 
 
4400
        if (yes
 
4401
            && (srv_locks_unsafe_for_binlog
 
4402
                || prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
 
4403
                prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
 
4404
        } else {
 
4405
                prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
 
4406
        }
5043
4407
}
5044
4408
 
5045
4409
/******************************************************************//**
5046
4410
Initializes a handle to use an index.
5047
 
@return 0 or error number */
 
4411
@return 0 or error number */
5048
4412
UNIV_INTERN
5049
4413
int
5050
 
ha_innobase::doStartIndexScan(
 
4414
ha_innobase::index_init(
5051
4415
/*====================*/
5052
 
  uint  keynr,  /*!< in: key (index) number */
5053
 
  bool )    /*!< in: 1 if result MUST be sorted according to index */
 
4416
        uint    keynr,  /*!< in: key (index) number */
 
4417
        bool )          /*!< in: 1 if result MUST be sorted according to index */
5054
4418
{
5055
 
  return(change_active_index(keynr));
 
4419
        return(change_active_index(keynr));
5056
4420
}
5057
4421
 
5058
4422
/******************************************************************//**
5059
4423
Currently does nothing.
5060
 
@return 0 */
 
4424
@return 0 */
5061
4425
UNIV_INTERN
5062
4426
int
5063
 
ha_innobase::doEndIndexScan(void)
 
4427
ha_innobase::index_end(void)
5064
4428
/*========================*/
5065
4429
{
5066
 
  int error = 0;
5067
 
  active_index=MAX_KEY;
5068
 
  return(error);
 
4430
        int     error   = 0;
 
4431
        active_index=MAX_KEY;
 
4432
        return(error);
5069
4433
}
5070
4434
 
5071
4435
/*********************************************************************//**
5075
4439
ulint
5076
4440
convert_search_mode_to_innobase(
5077
4441
/*============================*/
5078
 
  enum ha_rkey_function find_flag)
 
4442
        enum ha_rkey_function   find_flag)
5079
4443
{
5080
 
  switch (find_flag) {
5081
 
  case HA_READ_KEY_EXACT:
5082
 
    /* this does not require the index to be UNIQUE */
5083
 
    return(PAGE_CUR_GE);
5084
 
  case HA_READ_KEY_OR_NEXT:
5085
 
    return(PAGE_CUR_GE);
5086
 
  case HA_READ_KEY_OR_PREV:
5087
 
    return(PAGE_CUR_LE);
5088
 
  case HA_READ_AFTER_KEY: 
5089
 
    return(PAGE_CUR_G);
5090
 
  case HA_READ_BEFORE_KEY:
5091
 
    return(PAGE_CUR_L);
5092
 
  case HA_READ_PREFIX:
5093
 
    return(PAGE_CUR_GE);
5094
 
  case HA_READ_PREFIX_LAST:
5095
 
    return(PAGE_CUR_LE);
5096
 
  case HA_READ_PREFIX_LAST_OR_PREV:
5097
 
    return(PAGE_CUR_LE);
5098
 
    /* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
5099
 
    pass a complete-field prefix of a key value as the search
5100
 
    tuple. I.e., it is not allowed that the last field would
5101
 
    just contain n first bytes of the full field value.
5102
 
    MySQL uses a 'padding' trick to convert LIKE 'abc%'
5103
 
    type queries so that it can use as a search tuple
5104
 
    a complete-field-prefix of a key value. Thus, the InnoDB
5105
 
    search mode PAGE_CUR_LE_OR_EXTENDS is never used.
5106
 
    TODO: when/if MySQL starts to use also partial-field
5107
 
    prefixes, we have to deal with stripping of spaces
5108
 
    and comparison of non-latin1 char type fields in
5109
 
    innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
5110
 
    work correctly. */
5111
 
  case HA_READ_MBR_CONTAIN:
5112
 
  case HA_READ_MBR_INTERSECT:
5113
 
  case HA_READ_MBR_WITHIN:
5114
 
  case HA_READ_MBR_DISJOINT:
5115
 
  case HA_READ_MBR_EQUAL:
5116
 
    return(PAGE_CUR_UNSUPP);
5117
 
  /* do not use "default:" in order to produce a gcc warning:
5118
 
  enumeration value '...' not handled in switch
5119
 
  (if -Wswitch or -Wall is used) */
5120
 
  }
5121
 
 
5122
 
  my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
5123
 
 
5124
 
  return(PAGE_CUR_UNSUPP);
 
4444
        switch (find_flag) {
 
4445
        case HA_READ_KEY_EXACT:
 
4446
                /* this does not require the index to be UNIQUE */
 
4447
                return(PAGE_CUR_GE);
 
4448
        case HA_READ_KEY_OR_NEXT:
 
4449
                return(PAGE_CUR_GE);
 
4450
        case HA_READ_KEY_OR_PREV:
 
4451
                return(PAGE_CUR_LE);
 
4452
        case HA_READ_AFTER_KEY: 
 
4453
                return(PAGE_CUR_G);
 
4454
        case HA_READ_BEFORE_KEY:
 
4455
                return(PAGE_CUR_L);
 
4456
        case HA_READ_PREFIX:
 
4457
                return(PAGE_CUR_GE);
 
4458
        case HA_READ_PREFIX_LAST:
 
4459
                return(PAGE_CUR_LE);
 
4460
        case HA_READ_PREFIX_LAST_OR_PREV:
 
4461
                return(PAGE_CUR_LE);
 
4462
                /* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
 
4463
                pass a complete-field prefix of a key value as the search
 
4464
                tuple. I.e., it is not allowed that the last field would
 
4465
                just contain n first bytes of the full field value.
 
4466
                MySQL uses a 'padding' trick to convert LIKE 'abc%'
 
4467
                type queries so that it can use as a search tuple
 
4468
                a complete-field-prefix of a key value. Thus, the InnoDB
 
4469
                search mode PAGE_CUR_LE_OR_EXTENDS is never used.
 
4470
                TODO: when/if MySQL starts to use also partial-field
 
4471
                prefixes, we have to deal with stripping of spaces
 
4472
                and comparison of non-latin1 char type fields in
 
4473
                innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
 
4474
                work correctly. */
 
4475
        case HA_READ_MBR_CONTAIN:
 
4476
        case HA_READ_MBR_INTERSECT:
 
4477
        case HA_READ_MBR_WITHIN:
 
4478
        case HA_READ_MBR_DISJOINT:
 
4479
        case HA_READ_MBR_EQUAL:
 
4480
                return(PAGE_CUR_UNSUPP);
 
4481
        /* do not use "default:" in order to produce a gcc warning:
 
4482
        enumeration value '...' not handled in switch
 
4483
        (if -Wswitch or -Wall is used) */
 
4484
        }
 
4485
 
 
4486
        my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
 
4487
 
 
4488
        return(PAGE_CUR_UNSUPP);
5125
4489
}
5126
4490
 
5127
4491
/*
5137
4501
 
5138
4502
  A) if the user has not explicitly set any MySQL table level locks:
5139
4503
 
5140
 
  1) Drizzle calls StorageEngine::doStartStatement(), indicating to
5141
 
     InnoDB that a new SQL statement has begun.
5142
 
 
5143
 
  2a) For each InnoDB-managed table in the SELECT, Drizzle calls ::external_lock
5144
 
     to set an 'intention' table level lock on the table of the Cursor instance.
5145
 
     There we set prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should 
5146
 
     be set true if we are taking this table handle instance to use in a new SQL
5147
 
     statement issued by the user.
5148
 
 
5149
 
  2b) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
 
4504
  1) MySQL calls ::external_lock to set an 'intention' table level lock on
 
4505
the table of the handle instance. There we set
 
4506
prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should be set
 
4507
true if we are taking this table handle instance to use in a new SQL
 
4508
statement issued by the user. We also increment trx->n_mysql_tables_in_use.
 
4509
 
 
4510
  2) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
5150
4511
instructions to prebuilt->template of the table handle instance in
5151
4512
::index_read. The template is used to save CPU time in large joins.
5152
4513
 
5158
4519
  4) We do the SELECT. MySQL may repeatedly call ::index_read for the
5159
4520
same table handle instance, if it is a join.
5160
4521
 
5161
 
5) When the SELECT ends, the Drizzle kernel calls doEndStatement()
5162
 
 
5163
 
 (a) we execute a COMMIT there if the autocommit is on. The Drizzle interpreter 
5164
 
     does NOT execute autocommit for pure read transactions, though it should.
5165
 
     That is why we must execute the COMMIT in ::doEndStatement().
 
4522
  5) When the SELECT ends, MySQL removes its intention table level locks
 
4523
in ::external_lock. When trx->n_mysql_tables_in_use drops to zero,
 
4524
 (a) we execute a COMMIT there if the autocommit is on,
5166
4525
 (b) we also release possible 'SQL statement level resources' InnoDB may
5167
 
     have for this SQL statement.
5168
 
 
5169
 
  @todo
5170
 
 
5171
 
  Remove need for InnoDB to call autocommit for read-only trx
5172
 
 
5173
 
  @todo Check the below is still valid (I don't think it is...)
 
4526
have for this SQL statement. The MySQL interpreter does NOT execute
 
4527
autocommit for pure read transactions, though it should. That is why the
 
4528
table Cursor in that case has to execute the COMMIT in ::external_lock.
5174
4529
 
5175
4530
  B) If the user has explicitly set MySQL table level locks, then MySQL
5176
4531
does NOT call ::external_lock at the start of the statement. To determine
5185
4540
/**********************************************************************//**
5186
4541
Positions an index cursor to the index specified in the handle. Fetches the
5187
4542
row if any.
5188
 
@return 0, HA_ERR_KEY_NOT_FOUND, or error number */
 
4543
@return 0, HA_ERR_KEY_NOT_FOUND, or error number */
5189
4544
UNIV_INTERN
5190
4545
int
5191
4546
ha_innobase::index_read(
5192
4547
/*====================*/
5193
 
  unsigned char*    buf,  /*!< in/out: buffer for the returned
5194
 
          row */
5195
 
  const unsigned char*  key_ptr,/*!< in: key value; if this is NULL
5196
 
          we position the cursor at the
5197
 
          start or end of index; this can
5198
 
          also contain an InnoDB row id, in
5199
 
          which case key_len is the InnoDB
5200
 
          row id length; the key value can
5201
 
          also be a prefix of a full key value,
5202
 
          and the last column can be a prefix
5203
 
          of a full column */
5204
 
  uint      key_len,/*!< in: key value length */
5205
 
  enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
 
4548
        unsigned char*          buf,    /*!< in/out: buffer for the returned
 
4549
                                        row */
 
4550
        const unsigned char*    key_ptr,/*!< in: key value; if this is NULL
 
4551
                                        we position the cursor at the
 
4552
                                        start or end of index; this can
 
4553
                                        also contain an InnoDB row id, in
 
4554
                                        which case key_len is the InnoDB
 
4555
                                        row id length; the key value can
 
4556
                                        also be a prefix of a full key value,
 
4557
                                        and the last column can be a prefix
 
4558
                                        of a full column */
 
4559
        uint                    key_len,/*!< in: key value length */
 
4560
        enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
5206
4561
{
5207
 
  ulint   mode;
5208
 
  dict_index_t* index;
5209
 
  ulint   match_mode  = 0;
5210
 
  int   error;
5211
 
  ulint   ret;
5212
 
 
5213
 
  ut_a(prebuilt->trx == session_to_trx(user_session));
5214
 
 
5215
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
5216
 
 
5217
 
  index = prebuilt->index;
5218
 
 
5219
 
  if (UNIV_UNLIKELY(index == NULL)) {
5220
 
    prebuilt->index_usable = FALSE;
5221
 
    return(HA_ERR_CRASHED);
5222
 
  }
5223
 
 
5224
 
  if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
5225
 
    return(HA_ERR_TABLE_DEF_CHANGED);
5226
 
  }
5227
 
 
5228
 
  /* Note that if the index for which the search template is built is not
5229
 
  necessarily prebuilt->index, but can also be the clustered index */
5230
 
 
5231
 
  if (prebuilt->sql_stat_start) {
5232
 
    build_template(prebuilt, user_session, getTable(),
5233
 
             ROW_MYSQL_REC_FIELDS);
5234
 
  }
5235
 
 
5236
 
  if (key_ptr) {
5237
 
    /* Convert the search key value to InnoDB format into
5238
 
    prebuilt->search_tuple */
5239
 
 
5240
 
    row_sel_convert_mysql_key_to_innobase(
5241
 
      prebuilt->search_tuple,
5242
 
      (byte*) &key_val_buff[0],
5243
 
      (ulint)upd_and_key_val_buff_len,
5244
 
      index,
5245
 
      (byte*) key_ptr,
5246
 
      (ulint) key_len,
5247
 
      prebuilt->trx);
5248
 
  } else {
5249
 
    /* We position the cursor to the last or the first entry
5250
 
    in the index */
5251
 
 
5252
 
    dtuple_set_n_fields(prebuilt->search_tuple, 0);
5253
 
  }
5254
 
 
5255
 
  mode = convert_search_mode_to_innobase(find_flag);
5256
 
 
5257
 
  match_mode = 0;
5258
 
 
5259
 
  if (find_flag == HA_READ_KEY_EXACT) {
5260
 
 
5261
 
    match_mode = ROW_SEL_EXACT;
5262
 
 
5263
 
  } else if (find_flag == HA_READ_PREFIX
5264
 
       || find_flag == HA_READ_PREFIX_LAST) {
5265
 
 
5266
 
    match_mode = ROW_SEL_EXACT_PREFIX;
5267
 
  }
5268
 
 
5269
 
  last_match_mode = (uint) match_mode;
5270
 
 
5271
 
  if (mode != PAGE_CUR_UNSUPP) {
5272
 
 
5273
 
    innodb_srv_conc_enter_innodb(prebuilt->trx);
5274
 
 
5275
 
    ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
5276
 
             match_mode, 0);
5277
 
 
5278
 
    innodb_srv_conc_exit_innodb(prebuilt->trx);
5279
 
  } else {
5280
 
 
5281
 
    ret = DB_UNSUPPORTED;
5282
 
  }
5283
 
 
5284
 
  switch (ret) {
5285
 
  case DB_SUCCESS:
5286
 
    error = 0;
5287
 
    getTable()->status = 0;
5288
 
    break;
5289
 
  case DB_RECORD_NOT_FOUND:
5290
 
    error = HA_ERR_KEY_NOT_FOUND;
5291
 
    getTable()->status = STATUS_NOT_FOUND;
5292
 
    break;
5293
 
  case DB_END_OF_INDEX:
5294
 
    error = HA_ERR_KEY_NOT_FOUND;
5295
 
    getTable()->status = STATUS_NOT_FOUND;
5296
 
    break;
5297
 
  default:
5298
 
    error = convert_error_code_to_mysql((int) ret,
5299
 
                prebuilt->table->flags,
5300
 
                user_session);
5301
 
    getTable()->status = STATUS_NOT_FOUND;
5302
 
    break;
5303
 
  }
5304
 
 
5305
 
  return(error);
 
4562
        ulint           mode;
 
4563
        dict_index_t*   index;
 
4564
        ulint           match_mode      = 0;
 
4565
        int             error;
 
4566
        ulint           ret;
 
4567
 
 
4568
        ut_a(prebuilt->trx == session_to_trx(user_session));
 
4569
 
 
4570
        ha_statistic_increment(&SSV::ha_read_key_count);
 
4571
 
 
4572
        index = prebuilt->index;
 
4573
 
 
4574
        /* Note that if the index for which the search template is built is not
 
4575
        necessarily prebuilt->index, but can also be the clustered index */
 
4576
 
 
4577
        if (prebuilt->sql_stat_start) {
 
4578
                build_template(prebuilt, user_session, table,
 
4579
                               ROW_MYSQL_REC_FIELDS);
 
4580
        }
 
4581
 
 
4582
        if (key_ptr) {
 
4583
                /* Convert the search key value to InnoDB format into
 
4584
                prebuilt->search_tuple */
 
4585
 
 
4586
                row_sel_convert_mysql_key_to_innobase(
 
4587
                        prebuilt->search_tuple,
 
4588
                        (byte*) key_val_buff,
 
4589
                        (ulint)upd_and_key_val_buff_len,
 
4590
                        index,
 
4591
                        (byte*) key_ptr,
 
4592
                        (ulint) key_len,
 
4593
                        prebuilt->trx);
 
4594
        } else {
 
4595
                /* We position the cursor to the last or the first entry
 
4596
                in the index */
 
4597
 
 
4598
                dtuple_set_n_fields(prebuilt->search_tuple, 0);
 
4599
        }
 
4600
 
 
4601
        mode = convert_search_mode_to_innobase(find_flag);
 
4602
 
 
4603
        match_mode = 0;
 
4604
 
 
4605
        if (find_flag == HA_READ_KEY_EXACT) {
 
4606
 
 
4607
                match_mode = ROW_SEL_EXACT;
 
4608
 
 
4609
        } else if (find_flag == HA_READ_PREFIX
 
4610
                   || find_flag == HA_READ_PREFIX_LAST) {
 
4611
 
 
4612
                match_mode = ROW_SEL_EXACT_PREFIX;
 
4613
        }
 
4614
 
 
4615
        last_match_mode = (uint) match_mode;
 
4616
 
 
4617
        if (mode != PAGE_CUR_UNSUPP) {
 
4618
 
 
4619
                innodb_srv_conc_enter_innodb(prebuilt->trx);
 
4620
 
 
4621
                ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
 
4622
                                           match_mode, 0);
 
4623
 
 
4624
                innodb_srv_conc_exit_innodb(prebuilt->trx);
 
4625
        } else {
 
4626
 
 
4627
                ret = DB_UNSUPPORTED;
 
4628
        }
 
4629
 
 
4630
        switch (ret) {
 
4631
        case DB_SUCCESS:
 
4632
                error = 0;
 
4633
                table->status = 0;
 
4634
                break;
 
4635
        case DB_RECORD_NOT_FOUND:
 
4636
                error = HA_ERR_KEY_NOT_FOUND;
 
4637
                table->status = STATUS_NOT_FOUND;
 
4638
                break;
 
4639
        case DB_END_OF_INDEX:
 
4640
                error = HA_ERR_KEY_NOT_FOUND;
 
4641
                table->status = STATUS_NOT_FOUND;
 
4642
                break;
 
4643
        default:
 
4644
                error = convert_error_code_to_mysql((int) ret,
 
4645
                                                    prebuilt->table->flags,
 
4646
                                                    user_session);
 
4647
                table->status = STATUS_NOT_FOUND;
 
4648
                break;
 
4649
        }
 
4650
 
 
4651
        return(error);
5306
4652
}
5307
4653
 
5308
4654
/*******************************************************************//**
5309
4655
The following functions works like index_read, but it find the last
5310
4656
row with the current key value or prefix.
5311
 
@return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
 
4657
@return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
5312
4658
UNIV_INTERN
5313
4659
int
5314
4660
ha_innobase::index_read_last(
5315
4661
/*=========================*/
5316
 
  unsigned char*  buf,  /*!< out: fetched row */
5317
 
  const unsigned char*  key_ptr,/*!< in: key value, or a prefix of a full
5318
 
        key value */
5319
 
  uint    key_len)/*!< in: length of the key val or prefix
5320
 
        in bytes */
 
4662
        unsigned char*  buf,    /*!< out: fetched row */
 
4663
        const unsigned char*    key_ptr,/*!< in: key value, or a prefix of a full
 
4664
                                key value */
 
4665
        uint            key_len)/*!< in: length of the key val or prefix
 
4666
                                in bytes */
5321
4667
{
5322
 
  return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
 
4668
        return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
5323
4669
}
5324
4670
 
5325
4671
/********************************************************************//**
5326
4672
Get the index for a handle. Does not change active index.
5327
 
@return NULL or index instance. */
 
4673
@return NULL or index instance. */
5328
4674
UNIV_INTERN
5329
4675
dict_index_t*
5330
4676
ha_innobase::innobase_get_index(
5331
4677
/*============================*/
5332
 
  uint    keynr)  /*!< in: use this index; MAX_KEY means always
5333
 
        clustered index, even if it was internally
5334
 
        generated by InnoDB */
 
4678
        uint            keynr)  /*!< in: use this index; MAX_KEY means always
 
4679
                                clustered index, even if it was internally
 
4680
                                generated by InnoDB */
5335
4681
{
5336
 
  dict_index_t* index = 0;
5337
 
 
5338
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
5339
 
 
5340
 
  if (keynr != MAX_KEY && getTable()->getShare()->sizeKeys() > 0) 
5341
 
  {
5342
 
    KeyInfo *key = getTable()->key_info + keynr;
5343
 
    index = innobase_index_lookup(share, keynr);
5344
 
 
5345
 
    if (index) {
5346
 
      ut_a(ut_strcmp(index->name, key->name) == 0);
5347
 
    } else {
5348
 
      /* Can't find index with keynr in the translation
5349
 
         table. Only print message if the index translation
5350
 
         table exists */
5351
 
      if (share->idx_trans_tbl.index_mapping) {
5352
 
        errmsg_printf(ERRMSG_LVL_ERROR,
5353
 
                      "InnoDB could not find "
5354
 
                      "index %s key no %u for "
5355
 
                      "table %s through its "
5356
 
                      "index translation table",
5357
 
                      key ? key->name : "NULL",
5358
 
                      keynr,
5359
 
                      prebuilt->table->name);
5360
 
      }
5361
 
 
5362
 
      index = dict_table_get_index_on_name(prebuilt->table,
5363
 
                                           key->name);
5364
 
    }
5365
 
  } else {
5366
 
    index = dict_table_get_first_index(prebuilt->table);
5367
 
  }
5368
 
 
5369
 
  if (!index) {
5370
 
    errmsg_printf(ERRMSG_LVL_ERROR, 
5371
 
      "Innodb could not find key n:o %u with name %s "
5372
 
      "from dict cache for table %s",
5373
 
      keynr, getTable()->getShare()->getTableProto()->indexes(keynr).name().c_str(),
5374
 
      prebuilt->table->name);
5375
 
  }
5376
 
 
5377
 
  return(index);
 
4682
        KEY*            key = 0;
 
4683
        dict_index_t*   index = 0;
 
4684
 
 
4685
        ha_statistic_increment(&SSV::ha_read_key_count);
 
4686
 
 
4687
        ut_ad(user_session == ha_session());
 
4688
        ut_a(prebuilt->trx == session_to_trx(user_session));
 
4689
 
 
4690
        if (keynr != MAX_KEY && table->s->keys > 0) {
 
4691
                key = table->key_info + keynr;
 
4692
 
 
4693
                index = dict_table_get_index_on_name(prebuilt->table,
 
4694
                                                     key->name);
 
4695
        } else {
 
4696
                index = dict_table_get_first_index(prebuilt->table);
 
4697
        }
 
4698
 
 
4699
        if (!index) {
 
4700
                errmsg_printf(ERRMSG_LVL_ERROR, 
 
4701
                        "Innodb could not find key n:o %u with name %s "
 
4702
                        "from dict cache for table %s",
 
4703
                        keynr, key ? key->name : "NULL",
 
4704
                        prebuilt->table->name);
 
4705
        }
 
4706
 
 
4707
        return(index);
5378
4708
}
5379
4709
 
5380
4710
/********************************************************************//**
5381
4711
Changes the active index of a handle.
5382
 
@return 0 or error code */
 
4712
@return 0 or error code */
5383
4713
UNIV_INTERN
5384
4714
int
5385
4715
ha_innobase::change_active_index(
5386
4716
/*=============================*/
5387
 
  uint  keynr)  /*!< in: use this index; MAX_KEY means always clustered
5388
 
      index, even if it was internally generated by
5389
 
      InnoDB */
 
4717
        uint    keynr)  /*!< in: use this index; MAX_KEY means always clustered
 
4718
                        index, even if it was internally generated by
 
4719
                        InnoDB */
5390
4720
{
5391
 
  ut_ad(user_session == table->in_use);
5392
 
  ut_a(prebuilt->trx == session_to_trx(user_session));
5393
 
 
5394
 
  active_index = keynr;
5395
 
 
5396
 
  prebuilt->index = innobase_get_index(keynr);
5397
 
 
5398
 
  if (UNIV_UNLIKELY(!prebuilt->index)) {
5399
 
    errmsg_printf(ERRMSG_LVL_WARN, "InnoDB: change_active_index(%u) failed",
5400
 
          keynr);
5401
 
    prebuilt->index_usable = FALSE;
5402
 
    return(1);
5403
 
  }
5404
 
 
5405
 
  prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
5406
 
                 prebuilt->index);
5407
 
 
5408
 
  if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
5409
 
    push_warning_printf(user_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5410
 
                        HA_ERR_TABLE_DEF_CHANGED,
5411
 
                        "InnoDB: insufficient history for index %u",
5412
 
                        keynr);
5413
 
    /* The caller seems to ignore this.  Thus, we must check
5414
 
    this again in row_search_for_mysql(). */
5415
 
    return(2);
5416
 
  }
5417
 
 
5418
 
  ut_a(prebuilt->search_tuple != 0);
5419
 
 
5420
 
  dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
5421
 
 
5422
 
  dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
5423
 
      prebuilt->index->n_fields);
5424
 
 
5425
 
  /* MySQL changes the active index for a handle also during some
5426
 
  queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
5427
 
  and then calculates the sum. Previously we played safe and used
5428
 
  the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
5429
 
  copying. Starting from MySQL-4.1 we use a more efficient flag here. */
5430
 
 
5431
 
  build_template(prebuilt, user_session, getTable(), ROW_MYSQL_REC_FIELDS);
5432
 
 
5433
 
  return(0);
 
4721
        ut_ad(user_session == ha_session());
 
4722
        ut_a(prebuilt->trx == session_to_trx(user_session));
 
4723
 
 
4724
        active_index = keynr;
 
4725
 
 
4726
        prebuilt->index = innobase_get_index(keynr);
 
4727
 
 
4728
        if (UNIV_UNLIKELY(!prebuilt->index)) {
 
4729
                errmsg_printf(ERRMSG_LVL_WARN, "InnoDB: change_active_index(%u) failed",
 
4730
                                  keynr);
 
4731
                return(1);
 
4732
        }
 
4733
 
 
4734
        prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
 
4735
                                                           prebuilt->index);
 
4736
 
 
4737
        if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
 
4738
                errmsg_printf(ERRMSG_LVL_WARN,
 
4739
                                 "InnoDB: insufficient history for index %u",
 
4740
                                  keynr);
 
4741
                /* The caller seems to ignore this.  Thus, we must check
 
4742
                this again in row_search_for_mysql(). */
 
4743
                return(2);
 
4744
        }
 
4745
 
 
4746
        ut_a(prebuilt->search_tuple != 0);
 
4747
 
 
4748
        dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
 
4749
 
 
4750
        dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
 
4751
                        prebuilt->index->n_fields);
 
4752
 
 
4753
        /* MySQL changes the active index for a handle also during some
 
4754
        queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
 
4755
        and then calculates the sum. Previously we played safe and used
 
4756
        the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
 
4757
        copying. Starting from MySQL-4.1 we use a more efficient flag here. */
 
4758
 
 
4759
        build_template(prebuilt, user_session, table, ROW_MYSQL_REC_FIELDS);
 
4760
 
 
4761
        return(0);
5434
4762
}
5435
4763
 
5436
4764
/**********************************************************************//**
5437
4765
Positions an index cursor to the index specified in keynr. Fetches the
5438
4766
row if any.
5439
4767
??? This is only used to read whole keys ???
5440
 
@return error number or 0 */
 
4768
@return error number or 0 */
5441
4769
UNIV_INTERN
5442
4770
int
5443
4771
ha_innobase::index_read_idx(
5444
4772
/*========================*/
5445
 
  unsigned char*  buf,    /*!< in/out: buffer for the returned
5446
 
          row */
5447
 
  uint    keynr,    /*!< in: use this index */
5448
 
  const unsigned char*  key,  /*!< in: key value; if this is NULL
5449
 
          we position the cursor at the
5450
 
          start or end of index */
5451
 
  uint    key_len,  /*!< in: key value length */
5452
 
  enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
 
4773
        unsigned char*  buf,            /*!< in/out: buffer for the returned
 
4774
                                        row */
 
4775
        uint            keynr,          /*!< in: use this index */
 
4776
        const unsigned char*    key,    /*!< in: key value; if this is NULL
 
4777
                                        we position the cursor at the
 
4778
                                        start or end of index */
 
4779
        uint            key_len,        /*!< in: key value length */
 
4780
        enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
5453
4781
{
5454
 
  if (change_active_index(keynr)) {
5455
 
 
5456
 
    return(1);
5457
 
  }
5458
 
 
5459
 
  return(index_read(buf, key, key_len, find_flag));
 
4782
        if (change_active_index(keynr)) {
 
4783
 
 
4784
                return(1);
 
4785
        }
 
4786
 
 
4787
        return(index_read(buf, key, key_len, find_flag));
5460
4788
}
5461
4789
 
5462
4790
/***********************************************************************//**
5463
4791
Reads the next or previous row from a cursor, which must have previously been
5464
4792
positioned using index_read.
5465
 
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4793
@return 0, HA_ERR_END_OF_FILE, or error number */
5466
4794
UNIV_INTERN
5467
4795
int
5468
4796
ha_innobase::general_fetch(
5469
4797
/*=======================*/
5470
 
  unsigned char*  buf,  /*!< in/out: buffer for next row in MySQL
5471
 
        format */
5472
 
  uint  direction,  /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
5473
 
  uint  match_mode) /*!< in: 0, ROW_SEL_EXACT, or
5474
 
        ROW_SEL_EXACT_PREFIX */
 
4798
        unsigned char*  buf,    /*!< in/out: buffer for next row in MySQL
 
4799
                                format */
 
4800
        uint    direction,      /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
 
4801
        uint    match_mode)     /*!< in: 0, ROW_SEL_EXACT, or
 
4802
                                ROW_SEL_EXACT_PREFIX */
5475
4803
{
5476
 
  ulint   ret;
5477
 
  int   error = 0;
5478
 
 
5479
 
  ut_a(prebuilt->trx == session_to_trx(user_session));
5480
 
 
5481
 
  innodb_srv_conc_enter_innodb(prebuilt->trx);
5482
 
 
5483
 
  ret = row_search_for_mysql(
5484
 
    (byte*)buf, 0, prebuilt, match_mode, direction);
5485
 
 
5486
 
  innodb_srv_conc_exit_innodb(prebuilt->trx);
5487
 
 
5488
 
  switch (ret) {
5489
 
  case DB_SUCCESS:
5490
 
    error = 0;
5491
 
    getTable()->status = 0;
5492
 
    break;
5493
 
  case DB_RECORD_NOT_FOUND:
5494
 
    error = HA_ERR_END_OF_FILE;
5495
 
    getTable()->status = STATUS_NOT_FOUND;
5496
 
    break;
5497
 
  case DB_END_OF_INDEX:
5498
 
    error = HA_ERR_END_OF_FILE;
5499
 
    getTable()->status = STATUS_NOT_FOUND;
5500
 
    break;
5501
 
  default:
5502
 
    error = convert_error_code_to_mysql(
5503
 
      (int) ret, prebuilt->table->flags, user_session);
5504
 
    getTable()->status = STATUS_NOT_FOUND;
5505
 
    break;
5506
 
  }
5507
 
 
5508
 
  return(error);
 
4804
        ulint           ret;
 
4805
        int             error   = 0;
 
4806
 
 
4807
        ut_a(prebuilt->trx == session_to_trx(user_session));
 
4808
 
 
4809
        innodb_srv_conc_enter_innodb(prebuilt->trx);
 
4810
 
 
4811
        ret = row_search_for_mysql(
 
4812
                (byte*)buf, 0, prebuilt, match_mode, direction);
 
4813
 
 
4814
        innodb_srv_conc_exit_innodb(prebuilt->trx);
 
4815
 
 
4816
        switch (ret) {
 
4817
        case DB_SUCCESS:
 
4818
                error = 0;
 
4819
                table->status = 0;
 
4820
                break;
 
4821
        case DB_RECORD_NOT_FOUND:
 
4822
                error = HA_ERR_END_OF_FILE;
 
4823
                table->status = STATUS_NOT_FOUND;
 
4824
                break;
 
4825
        case DB_END_OF_INDEX:
 
4826
                error = HA_ERR_END_OF_FILE;
 
4827
                table->status = STATUS_NOT_FOUND;
 
4828
                break;
 
4829
        default:
 
4830
                error = convert_error_code_to_mysql(
 
4831
                        (int) ret, prebuilt->table->flags, user_session);
 
4832
                table->status = STATUS_NOT_FOUND;
 
4833
                break;
 
4834
        }
 
4835
 
 
4836
        return(error);
5509
4837
}
5510
4838
 
5511
4839
/***********************************************************************//**
5512
4840
Reads the next row from a cursor, which must have previously been
5513
4841
positioned using index_read.
5514
 
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4842
@return 0, HA_ERR_END_OF_FILE, or error number */
5515
4843
UNIV_INTERN
5516
4844
int
5517
4845
ha_innobase::index_next(
5518
4846
/*====================*/
5519
 
  unsigned char*  buf)  /*!< in/out: buffer for next row in MySQL
5520
 
        format */
 
4847
        unsigned char*  buf)    /*!< in/out: buffer for next row in MySQL
 
4848
                                format */
5521
4849
{
5522
 
  ha_statistic_increment(&system_status_var::ha_read_next_count);
 
4850
        ha_statistic_increment(&SSV::ha_read_next_count);
5523
4851
 
5524
 
  return(general_fetch(buf, ROW_SEL_NEXT, 0));
 
4852
        return(general_fetch(buf, ROW_SEL_NEXT, 0));
5525
4853
}
5526
4854
 
5527
4855
/*******************************************************************//**
5528
4856
Reads the next row matching to the key value given as the parameter.
5529
 
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4857
@return 0, HA_ERR_END_OF_FILE, or error number */
5530
4858
UNIV_INTERN
5531
4859
int
5532
4860
ha_innobase::index_next_same(
5533
4861
/*=========================*/
5534
 
  unsigned char*    buf,  /*!< in/out: buffer for the row */
5535
 
  const unsigned char*  , /*!< in: key value */
5536
 
  uint    ) /*!< in: key value length */
 
4862
        unsigned char*          buf,    /*!< in/out: buffer for the row */
 
4863
        const unsigned char*    ,       /*!< in: key value */
 
4864
        uint            )       /*!< in: key value length */
5537
4865
{
5538
 
  ha_statistic_increment(&system_status_var::ha_read_next_count);
 
4866
        ha_statistic_increment(&SSV::ha_read_next_count);
5539
4867
 
5540
 
  return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
 
4868
        return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
5541
4869
}
5542
4870
 
5543
4871
/***********************************************************************//**
5544
4872
Reads the previous row from a cursor, which must have previously been
5545
4873
positioned using index_read.
5546
 
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4874
@return 0, HA_ERR_END_OF_FILE, or error number */
5547
4875
UNIV_INTERN
5548
4876
int
5549
4877
ha_innobase::index_prev(
5550
4878
/*====================*/
5551
 
  unsigned char*  buf)  /*!< in/out: buffer for previous row in MySQL format */
 
4879
        unsigned char*  buf)    /*!< in/out: buffer for previous row in MySQL format */
5552
4880
{
5553
 
  ha_statistic_increment(&system_status_var::ha_read_prev_count);
 
4881
        ha_statistic_increment(&SSV::ha_read_prev_count);
5554
4882
 
5555
 
  return(general_fetch(buf, ROW_SEL_PREV, 0));
 
4883
        return(general_fetch(buf, ROW_SEL_PREV, 0));
5556
4884
}
5557
4885
 
5558
4886
/********************************************************************//**
5559
4887
Positions a cursor on the first record in an index and reads the
5560
4888
corresponding row to buf.
5561
 
@return 0, HA_ERR_END_OF_FILE, or error code */
 
4889
@return 0, HA_ERR_END_OF_FILE, or error code */
5562
4890
UNIV_INTERN
5563
4891
int
5564
4892
ha_innobase::index_first(
5565
4893
/*=====================*/
5566
 
  unsigned char*  buf)  /*!< in/out: buffer for the row */
 
4894
        unsigned char*  buf)    /*!< in/out: buffer for the row */
5567
4895
{
5568
 
  int error;
5569
 
 
5570
 
  ha_statistic_increment(&system_status_var::ha_read_first_count);
5571
 
 
5572
 
  error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
5573
 
 
5574
 
  /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
5575
 
 
5576
 
  if (error == HA_ERR_KEY_NOT_FOUND) {
5577
 
    error = HA_ERR_END_OF_FILE;
5578
 
  }
5579
 
 
5580
 
  return(error);
 
4896
        int     error;
 
4897
 
 
4898
        ha_statistic_increment(&SSV::ha_read_first_count);
 
4899
 
 
4900
        error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
 
4901
 
 
4902
        /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
 
4903
 
 
4904
        if (error == HA_ERR_KEY_NOT_FOUND) {
 
4905
                error = HA_ERR_END_OF_FILE;
 
4906
        }
 
4907
 
 
4908
        return(error);
5581
4909
}
5582
4910
 
5583
4911
/********************************************************************//**
5584
4912
Positions a cursor on the last record in an index and reads the
5585
4913
corresponding row to buf.
5586
 
@return 0, HA_ERR_END_OF_FILE, or error code */
 
4914
@return 0, HA_ERR_END_OF_FILE, or error code */
5587
4915
UNIV_INTERN
5588
4916
int
5589
4917
ha_innobase::index_last(
5590
4918
/*====================*/
5591
 
  unsigned char*  buf)  /*!< in/out: buffer for the row */
 
4919
        unsigned char*  buf)    /*!< in/out: buffer for the row */
5592
4920
{
5593
 
  int error;
5594
 
 
5595
 
  ha_statistic_increment(&system_status_var::ha_read_last_count);
5596
 
 
5597
 
  error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
5598
 
 
5599
 
  /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
5600
 
 
5601
 
  if (error == HA_ERR_KEY_NOT_FOUND) {
5602
 
    error = HA_ERR_END_OF_FILE;
5603
 
  }
5604
 
 
5605
 
  return(error);
 
4921
        int     error;
 
4922
 
 
4923
        ha_statistic_increment(&SSV::ha_read_last_count);
 
4924
 
 
4925
        error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
 
4926
 
 
4927
        /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
 
4928
 
 
4929
        if (error == HA_ERR_KEY_NOT_FOUND) {
 
4930
                error = HA_ERR_END_OF_FILE;
 
4931
        }
 
4932
 
 
4933
        return(error);
5606
4934
}
5607
4935
 
5608
4936
/****************************************************************//**
5609
4937
Initialize a table scan.
5610
 
@return 0 or error number */
 
4938
@return 0 or error number */
5611
4939
UNIV_INTERN
5612
4940
int
5613
 
ha_innobase::doStartTableScan(
 
4941
ha_innobase::rnd_init(
5614
4942
/*==================*/
5615
 
  bool  scan) /*!< in: TRUE if table/index scan FALSE otherwise */
 
4943
        bool    scan)   /*!< in: TRUE if table/index scan FALSE otherwise */
5616
4944
{
5617
 
  int err;
5618
 
 
5619
 
  /* Store the active index value so that we can restore the original
5620
 
  value after a scan */
5621
 
 
5622
 
  if (prebuilt->clust_index_was_generated) {
5623
 
    err = change_active_index(MAX_KEY);
5624
 
  } else {
5625
 
    err = change_active_index(primary_key);
5626
 
  }
5627
 
 
5628
 
  /* Don't use semi-consistent read in random row reads (by position).
5629
 
  This means we must disable semi_consistent_read if scan is false */
5630
 
 
5631
 
  if (!scan) {
5632
 
    try_semi_consistent_read(0);
5633
 
  }
5634
 
 
5635
 
  start_of_scan = 1;
5636
 
 
5637
 
  return(err);
 
4945
        int     err;
 
4946
 
 
4947
        /* Store the active index value so that we can restore the original
 
4948
        value after a scan */
 
4949
 
 
4950
        if (prebuilt->clust_index_was_generated) {
 
4951
                err = change_active_index(MAX_KEY);
 
4952
        } else {
 
4953
                err = change_active_index(primary_key);
 
4954
        }
 
4955
 
 
4956
        /* Don't use semi-consistent read in random row reads (by position).
 
4957
        This means we must disable semi_consistent_read if scan is false */
 
4958
 
 
4959
        if (!scan) {
 
4960
                try_semi_consistent_read(0);
 
4961
        }
 
4962
 
 
4963
        start_of_scan = 1;
 
4964
 
 
4965
        return(err);
5638
4966
}
5639
4967
 
5640
4968
/*****************************************************************//**
5641
4969
Ends a table scan.
5642
 
@return 0 or error number */
 
4970
@return 0 or error number */
5643
4971
UNIV_INTERN
5644
4972
int
5645
 
ha_innobase::doEndTableScan(void)
 
4973
ha_innobase::rnd_end(void)
5646
4974
/*======================*/
5647
4975
{
5648
 
  return(doEndIndexScan());
 
4976
        return(index_end());
5649
4977
}
5650
4978
 
5651
4979
/*****************************************************************//**
5652
4980
Reads the next row in a table scan (also used to read the FIRST row
5653
4981
in a table scan).
5654
 
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4982
@return 0, HA_ERR_END_OF_FILE, or error number */
5655
4983
UNIV_INTERN
5656
4984
int
5657
4985
ha_innobase::rnd_next(
5658
4986
/*==================*/
5659
 
  unsigned char*  buf)  /*!< in/out: returns the row in this buffer,
5660
 
      in MySQL format */
 
4987
        unsigned char*  buf)    /*!< in/out: returns the row in this buffer,
 
4988
                        in MySQL format */
5661
4989
{
5662
 
  int error;
5663
 
 
5664
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
5665
 
 
5666
 
  if (start_of_scan) {
5667
 
    error = index_first(buf);
5668
 
 
5669
 
    if (error == HA_ERR_KEY_NOT_FOUND) {
5670
 
      error = HA_ERR_END_OF_FILE;
5671
 
    }
5672
 
 
5673
 
    start_of_scan = 0;
5674
 
  } else {
5675
 
    error = general_fetch(buf, ROW_SEL_NEXT, 0);
5676
 
  }
5677
 
 
5678
 
  return(error);
 
4990
        int     error;
 
4991
 
 
4992
        ha_statistic_increment(&SSV::ha_read_rnd_next_count);
 
4993
 
 
4994
        if (start_of_scan) {
 
4995
                error = index_first(buf);
 
4996
 
 
4997
                if (error == HA_ERR_KEY_NOT_FOUND) {
 
4998
                        error = HA_ERR_END_OF_FILE;
 
4999
                }
 
5000
 
 
5001
                start_of_scan = 0;
 
5002
        } else {
 
5003
                error = general_fetch(buf, ROW_SEL_NEXT, 0);
 
5004
        }
 
5005
 
 
5006
        return(error);
5679
5007
}
5680
5008
 
5681
5009
/**********************************************************************//**
5682
5010
Fetches a row from the table based on a row reference.
5683
 
@return 0, HA_ERR_KEY_NOT_FOUND, or error code */
 
5011
@return 0, HA_ERR_KEY_NOT_FOUND, or error code */
5684
5012
UNIV_INTERN
5685
5013
int
5686
5014
ha_innobase::rnd_pos(
5687
5015
/*=================*/
5688
 
  unsigned char*  buf,  /*!< in/out: buffer for the row */
5689
 
  unsigned char*  pos)  /*!< in: primary key value of the row in the
5690
 
      MySQL format, or the row id if the clustered
5691
 
      index was internally generated by InnoDB; the
5692
 
      length of data in pos has to be ref_length */
 
5016
        unsigned char*  buf,    /*!< in/out: buffer for the row */
 
5017
        unsigned char*  pos)    /*!< in: primary key value of the row in the
 
5018
                        MySQL format, or the row id if the clustered
 
5019
                        index was internally generated by InnoDB; the
 
5020
                        length of data in pos has to be ref_length */
5693
5021
{
5694
 
  int   error;
5695
 
  uint    keynr = active_index;
5696
 
 
5697
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_count);
5698
 
 
5699
 
  ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
5700
 
 
5701
 
  if (prebuilt->clust_index_was_generated) {
5702
 
    /* No primary key was defined for the table and we
5703
 
    generated the clustered index from the row id: the
5704
 
    row reference is the row id, not any key value
5705
 
    that MySQL knows of */
5706
 
 
5707
 
    error = change_active_index(MAX_KEY);
5708
 
  } else {
5709
 
    error = change_active_index(primary_key);
5710
 
  }
5711
 
 
5712
 
  if (error) {
5713
 
    return(error);
5714
 
  }
5715
 
 
5716
 
  /* Note that we assume the length of the row reference is fixed
5717
 
  for the table, and it is == ref_length */
5718
 
 
5719
 
  error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
5720
 
 
5721
 
  if (error) {
5722
 
  }
5723
 
 
5724
 
  change_active_index(keynr);
5725
 
 
5726
 
  return(error);
 
5022
        int             error;
 
5023
        uint            keynr   = active_index;
 
5024
 
 
5025
        ha_statistic_increment(&SSV::ha_read_rnd_count);
 
5026
 
 
5027
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
5028
 
 
5029
        if (prebuilt->clust_index_was_generated) {
 
5030
                /* No primary key was defined for the table and we
 
5031
                generated the clustered index from the row id: the
 
5032
                row reference is the row id, not any key value
 
5033
                that MySQL knows of */
 
5034
 
 
5035
                error = change_active_index(MAX_KEY);
 
5036
        } else {
 
5037
                error = change_active_index(primary_key);
 
5038
        }
 
5039
 
 
5040
        if (error) {
 
5041
                return(error);
 
5042
        }
 
5043
 
 
5044
        /* Note that we assume the length of the row reference is fixed
 
5045
        for the table, and it is == ref_length */
 
5046
 
 
5047
        error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
 
5048
 
 
5049
        if (error) {
 
5050
        }
 
5051
 
 
5052
        change_active_index(keynr);
 
5053
 
 
5054
        return(error);
5727
5055
}
5728
5056
 
5729
5057
/*********************************************************************//**
5738
5066
void
5739
5067
ha_innobase::position(
5740
5068
/*==================*/
5741
 
  const unsigned char*  record) /*!< in: row in MySQL format */
 
5069
        const unsigned char*    record) /*!< in: row in MySQL format */
5742
5070
{
5743
 
  uint    len;
5744
 
 
5745
 
  ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
5746
 
 
5747
 
  if (prebuilt->clust_index_was_generated) {
5748
 
    /* No primary key was defined for the table and we
5749
 
    generated the clustered index from row id: the
5750
 
    row reference will be the row id, not any key value
5751
 
    that MySQL knows of */
5752
 
 
5753
 
    len = DATA_ROW_ID_LEN;
5754
 
 
5755
 
    memcpy(ref, prebuilt->row_id, len);
5756
 
  } else {
5757
 
    len = store_key_val_for_row(primary_key, (char*)ref,
5758
 
               ref_length, record);
5759
 
  }
5760
 
 
5761
 
  /* We assume that the 'ref' value len is always fixed for the same
5762
 
  table. */
5763
 
 
5764
 
  if (len != ref_length) {
5765
 
    errmsg_printf(ERRMSG_LVL_ERROR, "Stored ref len is %lu, but table ref len is %lu",
5766
 
        (ulong) len, (ulong) ref_length);
5767
 
  }
 
5071
        uint            len;
 
5072
 
 
5073
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
5074
 
 
5075
        if (prebuilt->clust_index_was_generated) {
 
5076
                /* No primary key was defined for the table and we
 
5077
                generated the clustered index from row id: the
 
5078
                row reference will be the row id, not any key value
 
5079
                that MySQL knows of */
 
5080
 
 
5081
                len = DATA_ROW_ID_LEN;
 
5082
 
 
5083
                memcpy(ref, prebuilt->row_id, len);
 
5084
        } else {
 
5085
                len = store_key_val_for_row(primary_key, (char*)ref,
 
5086
                                                         ref_length, record);
 
5087
        }
 
5088
 
 
5089
        /* We assume that the 'ref' value len is always fixed for the same
 
5090
        table. */
 
5091
 
 
5092
        if (len != ref_length) {
 
5093
          errmsg_printf(ERRMSG_LVL_ERROR, "Stored ref len is %lu, but table ref len is %lu",
 
5094
                          (ulong) len, (ulong) ref_length);
 
5095
        }
5768
5096
}
5769
5097
 
5770
5098
 
5774
5102
int
5775
5103
create_table_def(
5776
5104
/*=============*/
5777
 
  trx_t*    trx,    /*!< in: InnoDB transaction handle */
5778
 
  Table*    form,   /*!< in: information on table
5779
 
          columns and indexes */
5780
 
  const char* table_name, /*!< in: table name */
5781
 
  const char* path_of_temp_table,/*!< in: if this is a table explicitly
5782
 
          created by the user with the
5783
 
          TEMPORARY keyword, then this
5784
 
          parameter is the dir path where the
5785
 
          table should be placed if we create
5786
 
          an .ibd file for it (no .ibd extension
5787
 
          in the path, though); otherwise this
5788
 
          is NULL */
5789
 
  ulint   flags)    /*!< in: table flags */
 
5105
        trx_t*          trx,            /*!< in: InnoDB transaction handle */
 
5106
        Table*          form,           /*!< in: information on table
 
5107
                                        columns and indexes */
 
5108
        const char*     table_name,     /*!< in: table name */
 
5109
        const char*     path_of_temp_table,/*!< in: if this is a table explicitly
 
5110
                                        created by the user with the
 
5111
                                        TEMPORARY keyword, then this
 
5112
                                        parameter is the dir path where the
 
5113
                                        table should be placed if we create
 
5114
                                        an .ibd file for it (no .ibd extension
 
5115
                                        in the path, though); otherwise this
 
5116
                                        is NULL */
 
5117
        ulint           flags)          /*!< in: table flags */
5790
5118
{
5791
 
  Field*    field;
5792
 
  dict_table_t* table;
5793
 
  ulint   n_cols;
5794
 
  int   error;
5795
 
  ulint   col_type;
5796
 
  ulint   col_len;
5797
 
  ulint   nulls_allowed;
5798
 
  ulint   unsigned_type;
5799
 
  ulint   binary_type;
5800
 
  ulint   long_true_varchar;
5801
 
  ulint   charset_no;
5802
 
  ulint   i;
5803
 
 
5804
 
  n_cols = form->getShare()->sizeFields();
5805
 
 
5806
 
  /* We pass 0 as the space id, and determine at a lower level the space
5807
 
  id where to store the table */
5808
 
 
5809
 
  table = dict_mem_table_create(table_name, 0, n_cols, flags);
5810
 
 
5811
 
  if (path_of_temp_table) {
5812
 
    table->dir_path_of_temp_table =
5813
 
      mem_heap_strdup(table->heap, path_of_temp_table);
5814
 
  }
5815
 
 
5816
 
  for (i = 0; i < n_cols; i++) {
5817
 
    field = form->getField(i);
5818
 
 
5819
 
    col_type = get_innobase_type_from_mysql_type(&unsigned_type,
5820
 
                  field);
5821
 
 
5822
 
    if (!col_type) {
5823
 
      push_warning_printf(
5824
 
                          (Session*) trx->mysql_thd,
5825
 
                          DRIZZLE_ERROR::WARN_LEVEL_WARN,
5826
 
                          ER_CANT_CREATE_TABLE,
5827
 
                          "Error creating table '%s' with "
5828
 
                          "column '%s'. Please check its "
5829
 
                          "column type and try to re-create "
5830
 
                          "the table with an appropriate "
5831
 
                          "column type.",
5832
 
                          table->name, (char*) field->field_name);
5833
 
      goto err_col;
5834
 
    }
5835
 
 
5836
 
    if (field->null_ptr) {
5837
 
      nulls_allowed = 0;
5838
 
    } else {
5839
 
      nulls_allowed = DATA_NOT_NULL;
5840
 
    }
5841
 
 
5842
 
    if (field->binary()) {
5843
 
      binary_type = DATA_BINARY_TYPE;
5844
 
    } else {
5845
 
      binary_type = 0;
5846
 
    }
5847
 
 
5848
 
    charset_no = 0;
5849
 
 
5850
 
    if (dtype_is_string_type(col_type)) {
5851
 
 
5852
 
      charset_no = (ulint)field->charset()->number;
5853
 
 
5854
 
      if (UNIV_UNLIKELY(charset_no >= 256)) {
5855
 
        /* in data0type.h we assume that the
5856
 
        number fits in one byte in prtype */
5857
 
        push_warning_printf(
5858
 
          (Session*) trx->mysql_thd,
5859
 
          DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5860
 
          ER_CANT_CREATE_TABLE,
5861
 
          "In InnoDB, charset-collation codes"
5862
 
          " must be below 256."
5863
 
          " Unsupported code %lu.",
5864
 
          (ulong) charset_no);
5865
 
        return(ER_CANT_CREATE_TABLE);
5866
 
      }
5867
 
    }
5868
 
 
5869
 
    ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
5870
 
             that this fits in one byte */
5871
 
    col_len = field->pack_length();
5872
 
 
5873
 
    /* The MySQL pack length contains 1 or 2 bytes length field
5874
 
    for a true VARCHAR. Let us subtract that, so that the InnoDB
5875
 
    column length in the InnoDB data dictionary is the real
5876
 
    maximum byte length of the actual data. */
5877
 
 
5878
 
    long_true_varchar = 0;
5879
 
 
5880
 
    if (field->type() == DRIZZLE_TYPE_VARCHAR) {
5881
 
      col_len -= ((Field_varstring*)field)->pack_length_no_ptr();
5882
 
 
5883
 
      if (((Field_varstring*)field)->pack_length_no_ptr() == 2) {
5884
 
        long_true_varchar = DATA_LONG_TRUE_VARCHAR;
5885
 
      }
5886
 
    }
5887
 
 
5888
 
    /* First check whether the column to be added has a
5889
 
       system reserved name. */
5890
 
    if (dict_col_name_is_reserved(field->field_name)){
5891
 
      my_error(ER_WRONG_COLUMN_NAME, MYF(0), field->field_name);
5892
 
 
5893
 
  err_col:
5894
 
      dict_mem_table_free(table);
5895
 
      trx_commit_for_mysql(trx);
5896
 
 
5897
 
      error = DB_ERROR;
5898
 
      goto error_ret;
5899
 
    }
5900
 
 
5901
 
    dict_mem_table_add_col(table, table->heap,
5902
 
      (char*) field->field_name,
5903
 
      col_type,
5904
 
      dtype_form_prtype(
5905
 
        (ulint)field->type()
5906
 
        | nulls_allowed | unsigned_type
5907
 
        | binary_type | long_true_varchar,
5908
 
        charset_no),
5909
 
      col_len);
5910
 
  }
5911
 
 
5912
 
  error = row_create_table_for_mysql(table, trx);
5913
 
 
5914
 
        if (error == DB_DUPLICATE_KEY) {
5915
 
                char buf[100];
5916
 
                char* buf_end = innobase_convert_identifier(
5917
 
                        buf, sizeof buf - 1, table_name, strlen(table_name),
5918
 
                        trx->mysql_thd, TRUE);
5919
 
 
5920
 
                *buf_end = '\0';
5921
 
                my_error(ER_TABLE_EXISTS_ERROR, MYF(0), buf);
5922
 
        }
5923
 
 
5924
 
error_ret:
5925
 
  error = convert_error_code_to_mysql(error, flags, NULL);
5926
 
 
5927
 
  return(error);
 
5119
        Field*          field;
 
5120
        dict_table_t*   table;
 
5121
        ulint           n_cols;
 
5122
        int             error;
 
5123
        ulint           col_type;
 
5124
        ulint           col_len;
 
5125
        ulint           nulls_allowed;
 
5126
        ulint           unsigned_type;
 
5127
        ulint           binary_type;
 
5128
        ulint           long_true_varchar;
 
5129
        ulint           charset_no;
 
5130
        ulint           i;
 
5131
 
 
5132
        n_cols = form->s->fields;
 
5133
 
 
5134
        /* We pass 0 as the space id, and determine at a lower level the space
 
5135
        id where to store the table */
 
5136
 
 
5137
        table = dict_mem_table_create(table_name, 0, n_cols, flags);
 
5138
 
 
5139
        if (path_of_temp_table) {
 
5140
                table->dir_path_of_temp_table =
 
5141
                        mem_heap_strdup(table->heap, path_of_temp_table);
 
5142
        }
 
5143
 
 
5144
        for (i = 0; i < n_cols; i++) {
 
5145
                field = form->field[i];
 
5146
 
 
5147
                col_type = get_innobase_type_from_mysql_type(&unsigned_type,
 
5148
                                                                        field);
 
5149
                if (field->null_ptr) {
 
5150
                        nulls_allowed = 0;
 
5151
                } else {
 
5152
                        nulls_allowed = DATA_NOT_NULL;
 
5153
                }
 
5154
 
 
5155
                if (field->binary()) {
 
5156
                        binary_type = DATA_BINARY_TYPE;
 
5157
                } else {
 
5158
                        binary_type = 0;
 
5159
                }
 
5160
 
 
5161
                charset_no = 0;
 
5162
 
 
5163
                if (dtype_is_string_type(col_type)) {
 
5164
 
 
5165
                        charset_no = (ulint)field->charset()->number;
 
5166
 
 
5167
                        if (UNIV_UNLIKELY(charset_no >= 256)) {
 
5168
                                /* in data0type.h we assume that the
 
5169
                                number fits in one byte in prtype */
 
5170
                                push_warning_printf(
 
5171
                                        (Session*) trx->mysql_thd,
 
5172
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5173
                                        ER_CANT_CREATE_TABLE,
 
5174
                                        "In InnoDB, charset-collation codes"
 
5175
                                        " must be below 256."
 
5176
                                        " Unsupported code %lu.",
 
5177
                                        (ulong) charset_no);
 
5178
                                return(ER_CANT_CREATE_TABLE);
 
5179
                        }
 
5180
                }
 
5181
 
 
5182
                ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
 
5183
                                           that this fits in one byte */
 
5184
                col_len = field->pack_length();
 
5185
 
 
5186
                /* The MySQL pack length contains 1 or 2 bytes length field
 
5187
                for a true VARCHAR. Let us subtract that, so that the InnoDB
 
5188
                column length in the InnoDB data dictionary is the real
 
5189
                maximum byte length of the actual data. */
 
5190
 
 
5191
                long_true_varchar = 0;
 
5192
 
 
5193
                if (field->type() == DRIZZLE_TYPE_VARCHAR) {
 
5194
                        col_len -= ((Field_varstring*)field)->length_bytes;
 
5195
 
 
5196
                        if (((Field_varstring*)field)->length_bytes == 2) {
 
5197
                                long_true_varchar = DATA_LONG_TRUE_VARCHAR;
 
5198
                        }
 
5199
                }
 
5200
 
 
5201
                dict_mem_table_add_col(table, table->heap,
 
5202
                        (char*) field->field_name,
 
5203
                        col_type,
 
5204
                        dtype_form_prtype(
 
5205
                                (ulint)field->type()
 
5206
                                | nulls_allowed | unsigned_type
 
5207
                                | binary_type | long_true_varchar,
 
5208
                                charset_no),
 
5209
                        col_len);
 
5210
        }
 
5211
 
 
5212
        error = row_create_table_for_mysql(table, trx);
 
5213
 
 
5214
        error = convert_error_code_to_mysql(error, flags, NULL);
 
5215
 
 
5216
        return(error);
5928
5217
}
5929
5218
 
5930
5219
/*****************************************************************//**
5933
5222
int
5934
5223
create_index(
5935
5224
/*=========*/
5936
 
  trx_t*    trx,    /*!< in: InnoDB transaction handle */
5937
 
  Table*    form,   /*!< in: information on table
5938
 
          columns and indexes */
5939
 
  ulint   flags,    /*!< in: InnoDB table flags */
5940
 
  const char* table_name, /*!< in: table name */
5941
 
  uint    key_num)  /*!< in: index number */
 
5225
        trx_t*          trx,            /*!< in: InnoDB transaction handle */
 
5226
        Table*          form,           /*!< in: information on table
 
5227
                                        columns and indexes */
 
5228
        ulint           flags,          /*!< in: InnoDB table flags */
 
5229
        const char*     table_name,     /*!< in: table name */
 
5230
        uint            key_num)        /*!< in: index number */
5942
5231
{
5943
 
  Field*    field;
5944
 
  dict_index_t* index;
5945
 
  int   error;
5946
 
  ulint   n_fields;
5947
 
  KeyInfo*    key;
5948
 
  KeyPartInfo*  key_part;
5949
 
  ulint   ind_type;
5950
 
  ulint   col_type;
5951
 
  ulint   prefix_len;
5952
 
  ulint   is_unsigned;
5953
 
  ulint   i;
5954
 
  ulint   j;
5955
 
  ulint*    field_lengths;
5956
 
 
5957
 
  key = &form->key_info[key_num];
5958
 
 
5959
 
  n_fields = key->key_parts;
5960
 
 
5961
 
  /* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */
5962
 
  ut_a(innobase_strcasecmp(key->name, innobase_index_reserve_name) != 0);
5963
 
 
5964
 
  ind_type = 0;
5965
 
 
5966
 
  if (key_num == form->getShare()->getPrimaryKey()) {
5967
 
    ind_type = ind_type | DICT_CLUSTERED;
5968
 
  }
5969
 
 
5970
 
  if (key->flags & HA_NOSAME ) {
5971
 
    ind_type = ind_type | DICT_UNIQUE;
5972
 
  }
5973
 
 
5974
 
  /* We pass 0 as the space id, and determine at a lower level the space
5975
 
  id where to store the table */
5976
 
 
5977
 
  index = dict_mem_index_create(table_name, key->name, 0,
5978
 
              ind_type, n_fields);
5979
 
 
5980
 
  field_lengths = (ulint*) malloc(sizeof(ulint) * n_fields);
5981
 
 
5982
 
  for (i = 0; i < n_fields; i++) {
5983
 
    key_part = key->key_part + i;
5984
 
 
5985
 
    /* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
5986
 
    field in an index: we only store a specified number of first
5987
 
    bytes of the column to the index field.) The flag does not
5988
 
    seem to be properly set by MySQL. Let us fall back on testing
5989
 
    the length of the key part versus the column. */
5990
 
 
5991
 
    field = NULL;
5992
 
    for (j = 0; j < form->getShare()->sizeFields(); j++)
5993
 
    {
5994
 
 
5995
 
      field = form->getField(j);
5996
 
 
5997
 
      if (0 == innobase_strcasecmp(
5998
 
          field->field_name,
5999
 
          key_part->field->field_name)) {
6000
 
        /* Found the corresponding column */
6001
 
 
6002
 
        break;
6003
 
      }
6004
 
    }
6005
 
 
6006
 
    ut_a(j < form->getShare()->sizeFields());
6007
 
 
6008
 
    col_type = get_innobase_type_from_mysql_type(
6009
 
          &is_unsigned, key_part->field);
6010
 
 
6011
 
    if (DATA_BLOB == col_type
6012
 
      || (key_part->length < field->pack_length()
6013
 
        && field->type() != DRIZZLE_TYPE_VARCHAR)
6014
 
      || (field->type() == DRIZZLE_TYPE_VARCHAR
6015
 
        && key_part->length < field->pack_length()
6016
 
        - ((Field_varstring*)field)->pack_length_no_ptr())) {
6017
 
 
6018
 
      prefix_len = key_part->length;
6019
 
 
6020
 
      if (col_type == DATA_INT
6021
 
        || col_type == DATA_FLOAT
6022
 
        || col_type == DATA_DOUBLE
6023
 
        || col_type == DATA_DECIMAL) {
6024
 
        errmsg_printf(ERRMSG_LVL_ERROR, 
6025
 
          "MySQL is trying to create a column "
6026
 
          "prefix index field, on an "
6027
 
          "inappropriate data type. Table "
6028
 
          "name %s, column name %s.",
6029
 
          table_name,
6030
 
          key_part->field->field_name);
6031
 
 
6032
 
        prefix_len = 0;
6033
 
      }
6034
 
    } else {
6035
 
      prefix_len = 0;
6036
 
    }
6037
 
 
6038
 
    field_lengths[i] = key_part->length;
6039
 
 
6040
 
    dict_mem_index_add_field(index,
6041
 
      (char*) key_part->field->field_name, prefix_len);
6042
 
  }
6043
 
 
6044
 
  /* Even though we've defined max_supported_key_part_length, we
6045
 
  still do our own checking using field_lengths to be absolutely
6046
 
  sure we don't create too long indexes. */
6047
 
  error = row_create_index_for_mysql(index, trx, field_lengths);
6048
 
 
6049
 
  error = convert_error_code_to_mysql(error, flags, NULL);
6050
 
 
6051
 
  free(field_lengths);
6052
 
 
6053
 
  return(error);
 
5232
        Field*          field;
 
5233
        dict_index_t*   index;
 
5234
        int             error;
 
5235
        ulint           n_fields;
 
5236
        KEY*            key;
 
5237
        KEY_PART_INFO*  key_part;
 
5238
        ulint           ind_type;
 
5239
        ulint           col_type;
 
5240
        ulint           prefix_len;
 
5241
        ulint           is_unsigned;
 
5242
        ulint           i;
 
5243
        ulint           j;
 
5244
        ulint*          field_lengths;
 
5245
 
 
5246
        key = form->key_info + key_num;
 
5247
 
 
5248
        n_fields = key->key_parts;
 
5249
 
 
5250
        ind_type = 0;
 
5251
 
 
5252
        if (key_num == form->s->primary_key) {
 
5253
                ind_type = ind_type | DICT_CLUSTERED;
 
5254
        }
 
5255
 
 
5256
        if (key->flags & HA_NOSAME ) {
 
5257
                ind_type = ind_type | DICT_UNIQUE;
 
5258
        }
 
5259
 
 
5260
        /* We pass 0 as the space id, and determine at a lower level the space
 
5261
        id where to store the table */
 
5262
 
 
5263
        index = dict_mem_index_create(table_name, key->name, 0,
 
5264
                                      ind_type, n_fields);
 
5265
 
 
5266
        field_lengths = (ulint*) malloc(sizeof(ulint) * n_fields);
 
5267
 
 
5268
        for (i = 0; i < n_fields; i++) {
 
5269
                key_part = key->key_part + i;
 
5270
 
 
5271
                /* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
 
5272
                field in an index: we only store a specified number of first
 
5273
                bytes of the column to the index field.) The flag does not
 
5274
                seem to be properly set by MySQL. Let us fall back on testing
 
5275
                the length of the key part versus the column. */
 
5276
 
 
5277
                field = NULL;
 
5278
                for (j = 0; j < form->s->fields; j++) {
 
5279
 
 
5280
                        field = form->field[j];
 
5281
 
 
5282
                        if (0 == innobase_strcasecmp(
 
5283
                                        field->field_name,
 
5284
                                        key_part->field->field_name)) {
 
5285
                                /* Found the corresponding column */
 
5286
 
 
5287
                                break;
 
5288
                        }
 
5289
                }
 
5290
 
 
5291
                ut_a(j < form->s->fields);
 
5292
 
 
5293
                col_type = get_innobase_type_from_mysql_type(
 
5294
                                        &is_unsigned, key_part->field);
 
5295
 
 
5296
                if (DATA_BLOB == col_type
 
5297
                        || (key_part->length < field->pack_length()
 
5298
                                && field->type() != DRIZZLE_TYPE_VARCHAR)
 
5299
                        || (field->type() == DRIZZLE_TYPE_VARCHAR
 
5300
                                && key_part->length < field->pack_length()
 
5301
                                - ((Field_varstring*)field)->length_bytes)) {
 
5302
 
 
5303
                        prefix_len = key_part->length;
 
5304
 
 
5305
                        if (col_type == DATA_INT
 
5306
                                || col_type == DATA_FLOAT
 
5307
                                || col_type == DATA_DOUBLE
 
5308
                                || col_type == DATA_DECIMAL) {
 
5309
                                errmsg_printf(ERRMSG_LVL_ERROR, 
 
5310
                                        "MySQL is trying to create a column "
 
5311
                                        "prefix index field, on an "
 
5312
                                        "inappropriate data type. Table "
 
5313
                                        "name %s, column name %s.",
 
5314
                                        table_name,
 
5315
                                        key_part->field->field_name);
 
5316
 
 
5317
                                prefix_len = 0;
 
5318
                        }
 
5319
                } else {
 
5320
                        prefix_len = 0;
 
5321
                }
 
5322
 
 
5323
                field_lengths[i] = key_part->length;
 
5324
 
 
5325
                dict_mem_index_add_field(index,
 
5326
                        (char*) key_part->field->field_name, prefix_len);
 
5327
        }
 
5328
 
 
5329
        /* Even though we've defined max_supported_key_part_length, we
 
5330
        still do our own checking using field_lengths to be absolutely
 
5331
        sure we don't create too long indexes. */
 
5332
        error = row_create_index_for_mysql(index, trx, field_lengths);
 
5333
 
 
5334
        error = convert_error_code_to_mysql(error, flags, NULL);
 
5335
 
 
5336
        free(field_lengths);
 
5337
 
 
5338
        return(error);
6054
5339
}
6055
5340
 
6056
5341
/*****************************************************************//**
6060
5345
int
6061
5346
create_clustered_index_when_no_primary(
6062
5347
/*===================================*/
6063
 
  trx_t*    trx,    /*!< in: InnoDB transaction handle */
6064
 
  ulint   flags,    /*!< in: InnoDB table flags */
6065
 
  const char* table_name) /*!< in: table name */
 
5348
        trx_t*          trx,            /*!< in: InnoDB transaction handle */
 
5349
        ulint           flags,          /*!< in: InnoDB table flags */
 
5350
        const char*     table_name)     /*!< in: table name */
6066
5351
{
6067
 
  dict_index_t* index;
6068
 
  int   error;
6069
 
 
6070
 
  /* We pass 0 as the space id, and determine at a lower level the space
6071
 
  id where to store the table */
6072
 
 
6073
 
  index = dict_mem_index_create(table_name,
6074
 
                                innobase_index_reserve_name,
6075
 
                                0, DICT_CLUSTERED, 0);
6076
 
 
6077
 
  error = row_create_index_for_mysql(index, trx, NULL);
6078
 
 
6079
 
  error = convert_error_code_to_mysql(error, flags, NULL);
6080
 
 
6081
 
  return(error);
 
5352
        dict_index_t*   index;
 
5353
        int             error;
 
5354
 
 
5355
        /* We pass 0 as the space id, and determine at a lower level the space
 
5356
        id where to store the table */
 
5357
 
 
5358
        index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX",
 
5359
                                      0, DICT_CLUSTERED, 0);
 
5360
 
 
5361
        error = row_create_index_for_mysql(index, trx, NULL);
 
5362
 
 
5363
        error = convert_error_code_to_mysql(error, flags, NULL);
 
5364
 
 
5365
        return(error);
6082
5366
}
6083
5367
 
6084
5368
/*****************************************************************//**
6086
5370
in future. For now, it checks two specifiers:
6087
5371
KEY_BLOCK_SIZE and ROW_FORMAT
6088
5372
If innodb_strict_mode is not set then this function is a no-op
6089
 
@return TRUE if valid. */
6090
 
#if 0
 
5373
@return TRUE if valid. */
6091
5374
static
6092
5375
ibool
6093
5376
create_options_are_valid(
6094
5377
/*=====================*/
6095
 
  Session*  session,  /*!< in: connection thread. */
6096
 
  Table&    form,   /*!< in: information on table
6097
 
          columns and indexes */
 
5378
        Session*        session,        /*!< in: connection thread. */
 
5379
        Table&          form,           /*!< in: information on table
 
5380
                                        columns and indexes */
6098
5381
        message::Table& create_proto)
6099
5382
{
6100
 
  ibool kbs_specified = FALSE;
6101
 
  ibool ret   = TRUE;
6102
 
 
6103
 
 
6104
 
  ut_ad(session != NULL);
6105
 
 
6106
 
  /* If innodb_strict_mode is not set don't do any validation. */
6107
 
  if (!(SessionVAR(session, strict_mode))) {
6108
 
    return(TRUE);
6109
 
  }
6110
 
 
6111
 
  /* Now check for ROW_FORMAT specifier. */
6112
 
  return(ret);
 
5383
        ibool   kbs_specified   = FALSE;
 
5384
        ibool   ret             = TRUE;
 
5385
 
 
5386
 
 
5387
        ut_ad(session != NULL);
 
5388
 
 
5389
        /* If innodb_strict_mode is not set don't do any validation. */
 
5390
        if (!(SessionVAR(session, strict_mode))) {
 
5391
                return(TRUE);
 
5392
        }
 
5393
 
 
5394
        /* First check if KEY_BLOCK_SIZE was specified. */
 
5395
        if (create_proto.options().has_key_block_size()) {
 
5396
 
 
5397
                kbs_specified = TRUE;
 
5398
                switch (create_proto.options().key_block_size()) {
 
5399
                case 1:
 
5400
                case 2:
 
5401
                case 4:
 
5402
                case 8:
 
5403
                case 16:
 
5404
                        /* Valid value. */
 
5405
                        break;
 
5406
                default:
 
5407
                        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5408
                                            ER_ILLEGAL_HA_CREATE_OPTION,
 
5409
                                            "InnoDB: invalid"
 
5410
                                            " KEY_BLOCK_SIZE = %lu."
 
5411
                                            " Valid values are"
 
5412
                                            " [1, 2, 4, 8, 16]",
 
5413
                                            create_proto.options().key_block_size());
 
5414
                        ret = FALSE;
 
5415
                }
 
5416
        }
 
5417
        
 
5418
        /* If KEY_BLOCK_SIZE was specified, check for its
 
5419
        dependencies. */
 
5420
        if (kbs_specified && !srv_file_per_table) {
 
5421
                push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5422
                             ER_ILLEGAL_HA_CREATE_OPTION,
 
5423
                             "InnoDB: KEY_BLOCK_SIZE"
 
5424
                             " requires innodb_file_per_table.");
 
5425
                ret = FALSE;
 
5426
        }
 
5427
 
 
5428
        if (kbs_specified && srv_file_format < DICT_TF_FORMAT_ZIP) {
 
5429
                push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5430
                             ER_ILLEGAL_HA_CREATE_OPTION,
 
5431
                             "InnoDB: KEY_BLOCK_SIZE"
 
5432
                             " requires innodb_file_format >"
 
5433
                             " Antelope.");
 
5434
                ret = FALSE;
 
5435
        }
 
5436
 
 
5437
        /* Now check for ROW_FORMAT specifier. */
 
5438
        if (create_proto.options().has_row_type()) {
 
5439
                switch (form.s->row_type) {
 
5440
                        const char* row_format_name;
 
5441
                case ROW_TYPE_COMPRESSED:
 
5442
                case ROW_TYPE_DYNAMIC:
 
5443
                        row_format_name
 
5444
                                = form.s->row_type == ROW_TYPE_COMPRESSED
 
5445
                                ? "COMPRESSED"
 
5446
                                : "DYNAMIC";
 
5447
 
 
5448
                        /* These two ROW_FORMATs require
 
5449
                        srv_file_per_table and srv_file_format */
 
5450
                        if (!srv_file_per_table) {
 
5451
                                push_warning_printf(
 
5452
                                        session,
 
5453
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5454
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5455
                                        "InnoDB: ROW_FORMAT=%s"
 
5456
                                        " requires innodb_file_per_table.",
 
5457
                                        row_format_name);
 
5458
                                        ret = FALSE;
 
5459
 
 
5460
                        }
 
5461
 
 
5462
                        if (srv_file_format < DICT_TF_FORMAT_ZIP) {
 
5463
                                push_warning_printf(
 
5464
                                        session,
 
5465
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5466
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5467
                                        "InnoDB: ROW_FORMAT=%s"
 
5468
                                        " requires innodb_file_format >"
 
5469
                                        " Antelope.",
 
5470
                                        row_format_name);
 
5471
                                        ret = FALSE;
 
5472
                        }
 
5473
 
 
5474
                        /* Cannot specify KEY_BLOCK_SIZE with
 
5475
                        ROW_FORMAT = DYNAMIC.
 
5476
                        However, we do allow COMPRESSED to be
 
5477
                        specified with KEY_BLOCK_SIZE. */
 
5478
                        if (kbs_specified
 
5479
                            && form.s->row_type == ROW_TYPE_DYNAMIC) {
 
5480
                                push_warning_printf(
 
5481
                                        session,
 
5482
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5483
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5484
                                        "InnoDB: cannot specify"
 
5485
                                        " ROW_FORMAT = DYNAMIC with"
 
5486
                                        " KEY_BLOCK_SIZE.");
 
5487
                                        ret = FALSE;
 
5488
                        }
 
5489
 
 
5490
                        break;
 
5491
 
 
5492
                case ROW_TYPE_REDUNDANT:
 
5493
                case ROW_TYPE_COMPACT:
 
5494
                case ROW_TYPE_DEFAULT:
 
5495
                        /* Default is COMPACT. */
 
5496
                        row_format_name
 
5497
                                = form.s->row_type == ROW_TYPE_REDUNDANT
 
5498
                                ? "REDUNDANT"
 
5499
                                : "COMPACT";
 
5500
 
 
5501
                        /* Cannot specify KEY_BLOCK_SIZE with these
 
5502
                        format specifiers. */
 
5503
                        if (kbs_specified) {
 
5504
                                push_warning_printf(
 
5505
                                        session,
 
5506
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5507
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5508
                                        "InnoDB: cannot specify"
 
5509
                                        " ROW_FORMAT = %s with"
 
5510
                                        " KEY_BLOCK_SIZE.",
 
5511
                                        row_format_name);
 
5512
                                        ret = FALSE;
 
5513
                        }
 
5514
 
 
5515
                        break;
 
5516
 
 
5517
                default:
 
5518
                        push_warning(session,
 
5519
                                     DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5520
                                     ER_ILLEGAL_HA_CREATE_OPTION,
 
5521
                                     "InnoDB: invalid ROW_FORMAT specifier.");
 
5522
                        ret = FALSE;
 
5523
 
 
5524
                }
 
5525
        }
 
5526
 
 
5527
        return(ret);
6113
5528
}
6114
 
#endif
6115
5529
 
6116
5530
/*********************************************************************
6117
5531
Creates a new table to an InnoDB database. */
6119
5533
int
6120
5534
InnobaseEngine::doCreateTable(
6121
5535
/*================*/
6122
 
  Session         &session, /*!< in: Session */
6123
 
  Table&    form,   /*!< in: information on table columns and indexes */
6124
 
        const TableIdentifier &identifier,
 
5536
        Session*        session,        /*!< in: Session */
 
5537
        const char*     table_name,     /*!< in: table name */
 
5538
        Table&          form,           /*!< in: information on table
 
5539
                                        columns and indexes */
6125
5540
        message::Table& create_proto)
6126
5541
{
6127
 
  int   error;
6128
 
  dict_table_t* innobase_table;
6129
 
  trx_t*    parent_trx;
6130
 
  trx_t*    trx;
6131
 
  int   primary_key_no;
6132
 
  uint    i;
6133
 
  char    name2[FN_REFLEN];
6134
 
  char    norm_name[FN_REFLEN];
6135
 
  ib_int64_t  auto_inc_value;
6136
 
  ulint   iflags;
6137
 
  /* Cache the value of innodb_file_format, in case it is
6138
 
    modified by another thread while the table is being created. */
6139
 
  const ulint file_format = srv_file_format;
6140
 
  bool lex_identified_temp_table= (create_proto.type() == message::Table::TEMPORARY);
6141
 
  const char* stmt;
6142
 
  size_t stmt_len;
6143
 
 
6144
 
  const char *table_name= identifier.getPath().c_str();
6145
 
 
6146
 
  if (form.getShare()->sizeFields() > 1000) {
6147
 
    /* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
6148
 
      but we play safe here */
6149
 
 
6150
 
    return(HA_ERR_TO_BIG_ROW);
6151
 
  }
6152
 
 
6153
 
  /* Get the transaction associated with the current session, or create one
6154
 
    if not yet created */
6155
 
 
6156
 
  parent_trx = check_trx_exists(&session);
6157
 
 
6158
 
  /* In case MySQL calls this in the middle of a SELECT query, release
6159
 
    possible adaptive hash latch to avoid deadlocks of threads */
6160
 
 
6161
 
  trx_search_latch_release_if_reserved(parent_trx);
6162
 
 
6163
 
  trx = innobase_trx_allocate(&session);
6164
 
 
6165
 
  srv_lower_case_table_names = TRUE;
6166
 
 
6167
 
  strcpy(name2, table_name);
6168
 
 
6169
 
  normalize_table_name(norm_name, name2);
6170
 
 
6171
 
  /* Latch the InnoDB data dictionary exclusively so that no deadlocks
6172
 
    or lock waits can happen in it during a table create operation.
6173
 
    Drop table etc. do this latching in row0mysql.c. */
6174
 
 
6175
 
  row_mysql_lock_data_dictionary(trx);
6176
 
 
6177
 
  /* Create the table definition in InnoDB */
6178
 
 
6179
 
  iflags = 0;
6180
 
 
6181
 
#if 0 // Since we validate the options before this stage, we no longer need to do this.
6182
 
  /* Validate create options if innodb_strict_mode is set. */
6183
 
  if (! create_options_are_valid(&session, form, create_proto)) {
6184
 
    error = ER_ILLEGAL_HA_CREATE_OPTION;
6185
 
    goto cleanup;
6186
 
  }
 
5542
        int             error;
 
5543
        dict_table_t*   innobase_table;
 
5544
        trx_t*          parent_trx;
 
5545
        trx_t*          trx;
 
5546
        int             primary_key_no;
 
5547
        uint            i;
 
5548
        char            name2[FN_REFLEN];
 
5549
        char            norm_name[FN_REFLEN];
 
5550
        ib_int64_t      auto_inc_value;
 
5551
        ulint           iflags;
 
5552
        /* Cache the value of innodb_file_format, in case it is
 
5553
        modified by another thread while the table is being created. */
 
5554
        const ulint     file_format = srv_file_format;
 
5555
        bool lex_identified_temp_table= (create_proto.type() == message::Table::TEMPORARY);
 
5556
 
 
5557
        assert(session != NULL);
 
5558
 
 
5559
#ifdef __WIN__
 
5560
        /* Names passed in from server are in two formats:
 
5561
        1. <database_name>/<table_name>: for normal table creation
 
5562
        2. full path: for temp table creation, or sym link
 
5563
 
 
5564
        When srv_file_per_table is on, check for full path pattern, i.e.
 
5565
        X:\dir\...,             X is a driver letter, or
 
5566
        \\dir1\dir2\...,        UNC path
 
5567
        returns error if it is in full path format, but not creating a temp.
 
5568
        table. Currently InnoDB does not support symbolic link on Windows. */
 
5569
 
 
5570
        if (srv_file_per_table
 
5571
            && (! lex_identified_temp_table)) {
 
5572
 
 
5573
                if ((table_name[1] == ':')
 
5574
                    || (table_name[0] == '\\' && table_name[1] == '\\')) {
 
5575
                        errmsg_printf(ERRMSG_LVL_ERROR, "Cannot create table %s\n", table_name);
 
5576
                        return(HA_ERR_GENERIC);
 
5577
                }
 
5578
        }
6187
5579
#endif
6188
5580
 
6189
 
  // We assume compact format by default
6190
 
  iflags= DICT_TF_COMPACT;
6191
 
 
6192
 
  size_t num_engine_options= create_proto.engine().options_size();
6193
 
  for (size_t x= 0; x < num_engine_options; ++x)
6194
 
  {
6195
 
    if (boost::iequals(create_proto.engine().options(x).name(), "ROW_FORMAT"))
6196
 
    {
6197
 
      if (boost::iequals(create_proto.engine().options(x).state(), "COMPRESSED"))
6198
 
      {
6199
 
        iflags= DICT_TF_FORMAT_ZIP;
6200
 
      }
6201
 
      else if (boost::iequals(create_proto.engine().options(x).state(), "COMPACT"))
6202
 
      {
6203
 
        iflags= DICT_TF_FORMAT_ZIP;
6204
 
      }
6205
 
      else if (boost::iequals(create_proto.engine().options(x).state(), "DYNAMIC"))
6206
 
      {
6207
 
        iflags= DICT_TF_COMPACT;
6208
 
      }
6209
 
      else if (boost::iequals(create_proto.engine().options(x).state(), "REDUNDANT"))
6210
 
      {
6211
 
        iflags= DICT_TF_COMPACT;
6212
 
      }
6213
 
    }
6214
 
    else
6215
 
    {
6216
 
      assert(0); // This should never happen since we have already validated the options.
6217
 
    }
6218
 
  }
6219
 
 
6220
 
  if (iflags == DICT_TF_FORMAT_ZIP)
6221
 
  {
6222
 
    /* 
6223
 
      ROW_FORMAT=COMPRESSED without KEY_BLOCK_SIZE implies half the maximum KEY_BLOCK_SIZE.
6224
 
      @todo implement KEY_BLOCK_SIZE
6225
 
    */
6226
 
    iflags= (DICT_TF_ZSSIZE_MAX - 1)
6227
 
      << DICT_TF_ZSSIZE_SHIFT
6228
 
      | DICT_TF_COMPACT
6229
 
      | DICT_TF_FORMAT_ZIP
6230
 
      << DICT_TF_FORMAT_SHIFT;
 
5581
        if (form.s->fields > 1000) {
 
5582
                /* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
 
5583
                but we play safe here */
 
5584
 
 
5585
                return(HA_ERR_TO_BIG_ROW);
 
5586
        }
 
5587
 
 
5588
        /* Get the transaction associated with the current session, or create one
 
5589
        if not yet created */
 
5590
 
 
5591
        parent_trx = check_trx_exists(session);
 
5592
 
 
5593
        /* In case MySQL calls this in the middle of a SELECT query, release
 
5594
        possible adaptive hash latch to avoid deadlocks of threads */
 
5595
 
 
5596
        trx_search_latch_release_if_reserved(parent_trx);
 
5597
 
 
5598
        trx = innobase_trx_allocate(session);
 
5599
 
 
5600
        srv_lower_case_table_names = TRUE;
 
5601
 
 
5602
        strcpy(name2, table_name);
 
5603
 
 
5604
        normalize_table_name(norm_name, name2);
 
5605
 
 
5606
        /* Latch the InnoDB data dictionary exclusively so that no deadlocks
 
5607
        or lock waits can happen in it during a table create operation.
 
5608
        Drop table etc. do this latching in row0mysql.c. */
 
5609
 
 
5610
        row_mysql_lock_data_dictionary(trx);
 
5611
 
 
5612
        /* Create the table definition in InnoDB */
 
5613
 
 
5614
        iflags = 0;
 
5615
 
 
5616
        /* Validate create options if innodb_strict_mode is set. */
 
5617
        if (! create_options_are_valid(session, form, create_proto)) {
 
5618
                error = ER_ILLEGAL_HA_CREATE_OPTION;
 
5619
                goto cleanup;
 
5620
        }
 
5621
 
 
5622
        if (create_proto.options().has_key_block_size()) {
 
5623
                /* Determine the page_zip.ssize corresponding to the
 
5624
                requested page size (key_block_size) in kilobytes. */
 
5625
 
 
5626
                ulint   ssize, ksize;
 
5627
                ulint   key_block_size = create_proto.options().key_block_size();
 
5628
 
 
5629
                for (ssize = ksize = 1; ssize <= DICT_TF_ZSSIZE_MAX;
 
5630
                     ssize++, ksize <<= 1) {
 
5631
                        if (key_block_size == ksize) {
 
5632
                                iflags = ssize << DICT_TF_ZSSIZE_SHIFT
 
5633
                                        | DICT_TF_COMPACT
 
5634
                                        | DICT_TF_FORMAT_ZIP
 
5635
                                          << DICT_TF_FORMAT_SHIFT;
 
5636
                                break;
 
5637
                        }
 
5638
                }
 
5639
 
 
5640
                if (!srv_file_per_table) {
 
5641
                        push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5642
                                     ER_ILLEGAL_HA_CREATE_OPTION,
 
5643
                                     "InnoDB: KEY_BLOCK_SIZE"
 
5644
                                     " requires innodb_file_per_table.");
 
5645
                        iflags = 0;
 
5646
                }
 
5647
 
 
5648
                if (file_format < DICT_TF_FORMAT_ZIP) {
 
5649
                        push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5650
                                     ER_ILLEGAL_HA_CREATE_OPTION,
 
5651
                                     "InnoDB: KEY_BLOCK_SIZE"
 
5652
                                     " requires innodb_file_format >"
 
5653
                                     " Antelope.");
 
5654
                        iflags = 0;
 
5655
                }
 
5656
 
 
5657
                if (!iflags) {
 
5658
                        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5659
                                            ER_ILLEGAL_HA_CREATE_OPTION,
 
5660
                                            "InnoDB: ignoring"
 
5661
                                            " KEY_BLOCK_SIZE=%lu.",
 
5662
                                            create_proto.options().key_block_size());
 
5663
                }
 
5664
        }
 
5665
 
 
5666
        if (create_proto.options().has_row_type()) {
 
5667
                if (iflags) {
 
5668
                        /* KEY_BLOCK_SIZE was specified. */
 
5669
                        if (form.s->row_type != ROW_TYPE_COMPRESSED) {
 
5670
                                /* ROW_FORMAT other than COMPRESSED
 
5671
                                ignores KEY_BLOCK_SIZE.  It does not
 
5672
                                make sense to reject conflicting
 
5673
                                KEY_BLOCK_SIZE and ROW_FORMAT, because
 
5674
                                such combinations can be obtained
 
5675
                                with ALTER TABLE anyway. */
 
5676
                                push_warning_printf(
 
5677
                                        session,
 
5678
                                        DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5679
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5680
                                        "InnoDB: ignoring KEY_BLOCK_SIZE=%lu"
 
5681
                                        " unless ROW_FORMAT=COMPRESSED.",
 
5682
                                        create_proto.options().key_block_size());
 
5683
                                iflags = 0;
 
5684
                        }
 
5685
                } else {
 
5686
                        /* No KEY_BLOCK_SIZE */
 
5687
                        if (form.s->row_type == ROW_TYPE_COMPRESSED) {
 
5688
                                /* ROW_FORMAT=COMPRESSED without
 
5689
                                KEY_BLOCK_SIZE implies half the
 
5690
                                maximum KEY_BLOCK_SIZE. */
 
5691
                                iflags = (DICT_TF_ZSSIZE_MAX - 1)
 
5692
                                        << DICT_TF_ZSSIZE_SHIFT
 
5693
                                        | DICT_TF_COMPACT
 
5694
                                        | DICT_TF_FORMAT_ZIP
 
5695
                                        << DICT_TF_FORMAT_SHIFT;
6231
5696
#if DICT_TF_ZSSIZE_MAX < 1
6232
5697
# error "DICT_TF_ZSSIZE_MAX < 1"
6233
5698
#endif
6234
 
 
6235
 
    if (strict_mode)
6236
 
    {
6237
 
      if (! srv_file_per_table)
6238
 
      {
6239
 
        push_warning_printf(
6240
 
                            &session,
6241
 
                            DRIZZLE_ERROR::WARN_LEVEL_WARN,
6242
 
                            ER_ILLEGAL_HA_CREATE_OPTION,
6243
 
                            "InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.");
6244
 
      } 
6245
 
      else if (file_format < DICT_TF_FORMAT_ZIP) 
6246
 
      {
6247
 
        push_warning_printf(
6248
 
                            &session,
6249
 
                            DRIZZLE_ERROR::WARN_LEVEL_WARN,
6250
 
                            ER_ILLEGAL_HA_CREATE_OPTION,
6251
 
                            "InnoDB: ROW_FORMAT=compressed requires innodb_file_format > Antelope.");
6252
 
      }
6253
 
    }
6254
 
  }
6255
 
 
6256
 
  /* Look for a primary key */
6257
 
 
6258
 
  primary_key_no= (form.getShare()->hasPrimaryKey() ?
6259
 
                   (int) form.getShare()->getPrimaryKey() :
6260
 
                   -1);
6261
 
 
6262
 
  /* Our function innobase_get_mysql_key_number_for_index assumes
6263
 
    the primary key is always number 0, if it exists */
6264
 
 
6265
 
  assert(primary_key_no == -1 || primary_key_no == 0);
6266
 
 
6267
 
  /* Check for name conflicts (with reserved name) for
6268
 
     any user indices to be created. */
6269
 
  if (innobase_index_name_is_reserved(trx, form.key_info,
6270
 
                                      form.getShare()->keys)) {
6271
 
    error = -1;
6272
 
    goto cleanup;
6273
 
  }
6274
 
 
6275
 
  if (lex_identified_temp_table)
6276
 
    iflags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT;
6277
 
 
6278
 
  error= create_table_def(trx, &form, norm_name,
6279
 
                          lex_identified_temp_table ? name2 : NULL,
6280
 
                          iflags);
6281
 
 
6282
 
  session.setXaId(trx->id);
6283
 
 
6284
 
  if (error) {
6285
 
    goto cleanup;
6286
 
  }
6287
 
 
6288
 
  /* Create the keys */
6289
 
 
6290
 
  if (form.getShare()->sizeKeys() == 0 || primary_key_no == -1) {
6291
 
    /* Create an index which is used as the clustered index;
6292
 
      order the rows by their row id which is internally generated
6293
 
      by InnoDB */
6294
 
 
6295
 
    error = create_clustered_index_when_no_primary(trx, iflags, norm_name);
6296
 
    if (error) {
6297
 
      goto cleanup;
6298
 
    }
6299
 
  }
6300
 
 
6301
 
  if (primary_key_no != -1) {
6302
 
    /* In InnoDB the clustered index must always be created first */
6303
 
    if ((error = create_index(trx, &form, iflags, norm_name,
6304
 
                              (uint) primary_key_no))) {
6305
 
      goto cleanup;
6306
 
    }
6307
 
  }
6308
 
 
6309
 
  for (i = 0; i < form.getShare()->sizeKeys(); i++) {
6310
 
    if (i != (uint) primary_key_no) {
6311
 
 
6312
 
      if ((error = create_index(trx, &form, iflags, norm_name,
6313
 
                                i))) {
6314
 
        goto cleanup;
6315
 
      }
6316
 
    }
6317
 
  }
6318
 
 
6319
 
  stmt = innobase_get_stmt(&session, &stmt_len);
6320
 
 
6321
 
  if (stmt) {
6322
 
    string generated_create_table;
6323
 
    const char *query= stmt;
6324
 
 
6325
 
    if (session_sql_command(&session) == SQLCOM_CREATE_TABLE)
6326
 
    {
6327
 
      message::transformTableDefinitionToSql(create_proto,
6328
 
                                             generated_create_table,
6329
 
                                             message::DRIZZLE, true);
6330
 
      query= generated_create_table.c_str();
6331
 
    }
6332
 
 
6333
 
    error = row_table_add_foreign_constraints(trx,
6334
 
                                              query, strlen(query),
6335
 
                                              norm_name,
6336
 
                                              lex_identified_temp_table);
6337
 
 
6338
 
    error = convert_error_code_to_mysql(error, iflags, NULL);
6339
 
 
6340
 
    if (error) {
6341
 
      goto cleanup;
6342
 
    }
6343
 
  }
6344
 
 
6345
 
  innobase_commit_low(trx);
6346
 
 
6347
 
  row_mysql_unlock_data_dictionary(trx);
6348
 
 
6349
 
  /* Flush the log to reduce probability that the .frm files and
6350
 
    the InnoDB data dictionary get out-of-sync if the user runs
6351
 
    with innodb_flush_log_at_trx_commit = 0 */
6352
 
 
6353
 
  log_buffer_flush_to_disk();
6354
 
 
6355
 
  innobase_table = dict_table_get(norm_name, FALSE);
6356
 
 
6357
 
  assert(innobase_table != 0);
6358
 
 
6359
 
  if (innobase_table) {
6360
 
    /* We update the highest file format in the system table
6361
 
      space, if this table has higher file format setting. */
6362
 
 
6363
 
    char changed_file_format_max[100];
6364
 
    strcpy(changed_file_format_max, innobase_file_format_max.c_str());
6365
 
    trx_sys_file_format_max_upgrade((const char **)&changed_file_format_max,
6366
 
      dict_table_get_format(innobase_table));
6367
 
    innobase_file_format_max= changed_file_format_max;
6368
 
  }
6369
 
 
6370
 
  /* Note: We can't call update_session() as prebuilt will not be
6371
 
    setup at this stage and so we use session. */
6372
 
 
6373
 
  /* We need to copy the AUTOINC value from the old table if
6374
 
    this is an ALTER TABLE or CREATE INDEX because CREATE INDEX
6375
 
    does a table copy too. */
6376
 
 
6377
 
  if ((create_proto.options().has_auto_increment_value()
6378
 
       || session_sql_command(&session) == SQLCOM_ALTER_TABLE
6379
 
       || session_sql_command(&session) == SQLCOM_CREATE_INDEX)
6380
 
      && create_proto.options().auto_increment_value() != 0) {
6381
 
 
6382
 
    /* Query was one of :
6383
 
       CREATE TABLE ...AUTO_INCREMENT = x; or
6384
 
       ALTER TABLE...AUTO_INCREMENT = x;   or
6385
 
       CREATE INDEX x on t(...);
6386
 
       Find out a table definition from the dictionary and get
6387
 
       the current value of the auto increment field. Set a new
6388
 
       value to the auto increment field if the value is greater
6389
 
       than the maximum value in the column. */
6390
 
 
6391
 
    auto_inc_value = create_proto.options().auto_increment_value();
6392
 
 
6393
 
    dict_table_autoinc_lock(innobase_table);
6394
 
    dict_table_autoinc_initialize(innobase_table, auto_inc_value);
6395
 
    dict_table_autoinc_unlock(innobase_table);
6396
 
  }
6397
 
 
6398
 
  /* Tell the InnoDB server that there might be work for
6399
 
    utility threads: */
6400
 
 
6401
 
  srv_active_wake_master_thread();
6402
 
 
6403
 
  trx_free_for_mysql(trx);
6404
 
 
6405
 
  if (lex_identified_temp_table)
6406
 
  {
6407
 
    session.getMessageCache().storeTableMessage(identifier, create_proto);
6408
 
  }
6409
 
  else
6410
 
  {
6411
 
    StorageEngine::writeDefinitionFromPath(identifier, create_proto);
6412
 
  }
6413
 
 
6414
 
  return(0);
 
5699
                        }
 
5700
                }
 
5701
 
 
5702
                switch (form.s->row_type) {
 
5703
                        const char* row_format_name;
 
5704
                case ROW_TYPE_REDUNDANT:
 
5705
                        break;
 
5706
                case ROW_TYPE_COMPRESSED:
 
5707
                case ROW_TYPE_DYNAMIC:
 
5708
                        row_format_name
 
5709
                                = form.s->row_type == ROW_TYPE_COMPRESSED
 
5710
                                ? "COMPRESSED"
 
5711
                                : "DYNAMIC";
 
5712
 
 
5713
                        if (!srv_file_per_table) {
 
5714
                                push_warning_printf(
 
5715
                                        session,
 
5716
                                        DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5717
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5718
                                        "InnoDB: ROW_FORMAT=%s"
 
5719
                                        " requires innodb_file_per_table.",
 
5720
                                        row_format_name);
 
5721
                        } else if (file_format < DICT_TF_FORMAT_ZIP) {
 
5722
                                push_warning_printf(
 
5723
                                        session,
 
5724
                                        DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5725
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5726
                                        "InnoDB: ROW_FORMAT=%s"
 
5727
                                        " requires innodb_file_format >"
 
5728
                                        " Antelope.",
 
5729
                                        row_format_name);
 
5730
                        } else {
 
5731
                                iflags |= DICT_TF_COMPACT
 
5732
                                        | (DICT_TF_FORMAT_ZIP
 
5733
                                           << DICT_TF_FORMAT_SHIFT);
 
5734
                                break;
 
5735
                        }
 
5736
 
 
5737
                        /* fall through */
 
5738
                case ROW_TYPE_NOT_USED:
 
5739
                case ROW_TYPE_FIXED:
 
5740
                default:
 
5741
                        error = ER_ILLEGAL_HA_CREATE_OPTION;
 
5742
                        goto cleanup;
 
5743
                case ROW_TYPE_DEFAULT:
 
5744
                case ROW_TYPE_COMPACT:
 
5745
                        iflags = DICT_TF_COMPACT;
 
5746
                        break;
 
5747
                }
 
5748
        } else if (!iflags) {
 
5749
                /* No KEY_BLOCK_SIZE or ROW_FORMAT specified:
 
5750
                use ROW_FORMAT=COMPACT by default. */
 
5751
                iflags = DICT_TF_COMPACT;
 
5752
        }
 
5753
 
 
5754
        error = create_table_def(trx, &form, norm_name,
 
5755
                lex_identified_temp_table ? name2 : NULL,
 
5756
                iflags);
 
5757
 
 
5758
        if (error) {
 
5759
                goto cleanup;
 
5760
        }
 
5761
 
 
5762
        /* Look for a primary key */
 
5763
 
 
5764
        primary_key_no= (form.s->primary_key != MAX_KEY ?
 
5765
                         (int) form.s->primary_key :
 
5766
                         -1);
 
5767
 
 
5768
        /* Our function row_get_mysql_key_number_for_index assumes
 
5769
        the primary key is always number 0, if it exists */
 
5770
 
 
5771
        assert(primary_key_no == -1 || primary_key_no == 0);
 
5772
 
 
5773
        /* Create the keys */
 
5774
 
 
5775
        if (form.s->keys == 0 || primary_key_no == -1) {
 
5776
                /* Create an index which is used as the clustered index;
 
5777
                order the rows by their row id which is internally generated
 
5778
                by InnoDB */
 
5779
 
 
5780
                error = create_clustered_index_when_no_primary(
 
5781
                        trx, iflags, norm_name);
 
5782
                if (error) {
 
5783
                        goto cleanup;
 
5784
                }
 
5785
        }
 
5786
 
 
5787
        if (primary_key_no != -1) {
 
5788
                /* In InnoDB the clustered index must always be created
 
5789
                first */
 
5790
                if ((error = create_index(trx, &form, iflags, norm_name,
 
5791
                                          (uint) primary_key_no))) {
 
5792
                        goto cleanup;
 
5793
                }
 
5794
        }
 
5795
 
 
5796
        for (i = 0; i < form.s->keys; i++) {
 
5797
 
 
5798
                if (i != (uint) primary_key_no) {
 
5799
 
 
5800
                        if ((error = create_index(trx, &form, iflags, norm_name,
 
5801
                                                  i))) {
 
5802
                                goto cleanup;
 
5803
                        }
 
5804
                }
 
5805
        }
 
5806
 
 
5807
        if (*trx->mysql_query_str) {
 
5808
                error = row_table_add_foreign_constraints(trx,
 
5809
                        *trx->mysql_query_str, norm_name,
 
5810
                        lex_identified_temp_table);
 
5811
 
 
5812
                error = convert_error_code_to_mysql(error, iflags, NULL);
 
5813
 
 
5814
                if (error) {
 
5815
                        goto cleanup;
 
5816
                }
 
5817
        }
 
5818
 
 
5819
        innobase_commit_low(trx);
 
5820
 
 
5821
        row_mysql_unlock_data_dictionary(trx);
 
5822
 
 
5823
        /* Flush the log to reduce probability that the .frm files and
 
5824
        the InnoDB data dictionary get out-of-sync if the user runs
 
5825
        with innodb_flush_log_at_trx_commit = 0 */
 
5826
 
 
5827
        log_buffer_flush_to_disk();
 
5828
 
 
5829
        innobase_table = dict_table_get(norm_name, FALSE);
 
5830
 
 
5831
        assert(innobase_table != 0);
 
5832
 
 
5833
        if (innobase_table) {
 
5834
                /* We update the highest file format in the system table
 
5835
                space, if this table has higher file format setting. */
 
5836
 
 
5837
                trx_sys_file_format_max_upgrade(
 
5838
                        (const char**) &innobase_file_format_check,
 
5839
                        dict_table_get_format(innobase_table));
 
5840
        }
 
5841
 
 
5842
        /* Note: We can't call update_session() as prebuilt will not be
 
5843
        setup at this stage and so we use session. */
 
5844
 
 
5845
        /* We need to copy the AUTOINC value from the old table if
 
5846
        this is an ALTER TABLE. */
 
5847
 
 
5848
        if ((create_proto.options().has_auto_increment_value()
 
5849
            || session_sql_command(session) == SQLCOM_ALTER_TABLE)
 
5850
            && create_proto.options().auto_increment_value() != 0) {
 
5851
 
 
5852
                /* Query was ALTER TABLE...AUTO_INCREMENT = x; or
 
5853
                CREATE TABLE ...AUTO_INCREMENT = x; Find out a table
 
5854
                definition from the dictionary and get the current value
 
5855
                of the auto increment field. Set a new value to the
 
5856
                auto increment field if the value is greater than the
 
5857
                maximum value in the column. */
 
5858
 
 
5859
                auto_inc_value = create_proto.options().auto_increment_value();
 
5860
 
 
5861
                dict_table_autoinc_lock(innobase_table);
 
5862
                dict_table_autoinc_initialize(innobase_table, auto_inc_value);
 
5863
                dict_table_autoinc_unlock(innobase_table);
 
5864
        }
 
5865
 
 
5866
        /* Tell the InnoDB server that there might be work for
 
5867
        utility threads: */
 
5868
 
 
5869
        srv_active_wake_master_thread();
 
5870
 
 
5871
        trx_free_for_mysql(trx);
 
5872
 
 
5873
        return(0);
6415
5874
 
6416
5875
cleanup:
6417
 
  innobase_commit_low(trx);
6418
 
 
6419
 
  row_mysql_unlock_data_dictionary(trx);
6420
 
 
6421
 
  trx_free_for_mysql(trx);
6422
 
 
6423
 
  return(error);
 
5876
        innobase_commit_low(trx);
 
5877
 
 
5878
        row_mysql_unlock_data_dictionary(trx);
 
5879
 
 
5880
        trx_free_for_mysql(trx);
 
5881
 
 
5882
        return(error);
6424
5883
}
6425
5884
 
6426
5885
/*****************************************************************//**
6427
5886
Discards or imports an InnoDB tablespace.
6428
 
@return 0 == success, -1 == error */
 
5887
@return 0 == success, -1 == error */
6429
5888
UNIV_INTERN
6430
5889
int
6431
5890
ha_innobase::discard_or_import_tablespace(
6432
5891
/*======================================*/
6433
 
  my_bool discard)  /*!< in: TRUE if discard, else import */
 
5892
        my_bool discard)        /*!< in: TRUE if discard, else import */
6434
5893
{
6435
 
  dict_table_t* dict_table;
6436
 
  trx_t*    trx;
6437
 
  int   err;
6438
 
 
6439
 
  ut_a(prebuilt->trx);
6440
 
  ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
6441
 
  ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
6442
 
 
6443
 
  dict_table = prebuilt->table;
6444
 
  trx = prebuilt->trx;
6445
 
 
6446
 
  if (discard) {
6447
 
    err = row_discard_tablespace_for_mysql(dict_table->name, trx);
6448
 
  } else {
6449
 
    err = row_import_tablespace_for_mysql(dict_table->name, trx);
6450
 
  }
6451
 
 
6452
 
  err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
6453
 
 
6454
 
  return(err);
 
5894
        dict_table_t*   dict_table;
 
5895
        trx_t*          trx;
 
5896
        int             err;
 
5897
 
 
5898
        ut_a(prebuilt->trx);
 
5899
        ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
 
5900
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
5901
 
 
5902
        dict_table = prebuilt->table;
 
5903
        trx = prebuilt->trx;
 
5904
 
 
5905
        if (discard) {
 
5906
                err = row_discard_tablespace_for_mysql(dict_table->name, trx);
 
5907
        } else {
 
5908
                err = row_import_tablespace_for_mysql(dict_table->name, trx);
 
5909
        }
 
5910
 
 
5911
        err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
 
5912
 
 
5913
        return(err);
6455
5914
}
6456
5915
 
6457
5916
/*****************************************************************//**
6458
5917
Deletes all rows of an InnoDB table.
6459
 
@return error number */
 
5918
@return error number */
6460
5919
UNIV_INTERN
6461
5920
int
6462
5921
ha_innobase::delete_all_rows(void)
6463
5922
/*==============================*/
6464
5923
{
6465
 
  int   error;
6466
 
 
6467
 
  /* Get the transaction associated with the current session, or create one
6468
 
  if not yet created, and update prebuilt->trx */
6469
 
 
6470
 
  update_session(getTable()->in_use);
6471
 
 
6472
 
  if (session_sql_command(user_session) != SQLCOM_TRUNCATE) {
6473
 
  fallback:
6474
 
    /* We only handle TRUNCATE TABLE t as a special case.
6475
 
    DELETE FROM t will have to use ha_innobase::doDeleteRecord(),
6476
 
    because DELETE is transactional while TRUNCATE is not. */
6477
 
    return(errno=HA_ERR_WRONG_COMMAND);
6478
 
  }
6479
 
 
6480
 
  /* Truncate the table in InnoDB */
6481
 
 
6482
 
  error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
6483
 
  if (error == DB_ERROR) {
6484
 
    /* Cannot truncate; resort to ha_innobase::doDeleteRecord() */
6485
 
    goto fallback;
6486
 
  }
6487
 
 
6488
 
  error = convert_error_code_to_mysql(error, prebuilt->table->flags,
6489
 
              NULL);
6490
 
 
6491
 
  return(error);
 
5924
        int             error;
 
5925
 
 
5926
        /* Get the transaction associated with the current session, or create one
 
5927
        if not yet created, and update prebuilt->trx */
 
5928
 
 
5929
        update_session(ha_session());
 
5930
 
 
5931
        if (session_sql_command(user_session) != SQLCOM_TRUNCATE) {
 
5932
        fallback:
 
5933
                /* We only handle TRUNCATE TABLE t as a special case.
 
5934
                DELETE FROM t will have to use ha_innobase::delete_row(),
 
5935
                because DELETE is transactional while TRUNCATE is not. */
 
5936
                return(errno=HA_ERR_WRONG_COMMAND);
 
5937
        }
 
5938
 
 
5939
        /* Truncate the table in InnoDB */
 
5940
 
 
5941
        error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
 
5942
        if (error == DB_ERROR) {
 
5943
                /* Cannot truncate; resort to ha_innobase::delete_row() */
 
5944
                goto fallback;
 
5945
        }
 
5946
 
 
5947
        error = convert_error_code_to_mysql(error, prebuilt->table->flags,
 
5948
                                            NULL);
 
5949
 
 
5950
        return(error);
6492
5951
}
6493
5952
 
6494
5953
/*****************************************************************//**
6497
5956
Then the current user cannot have locks set on the table. Drop table
6498
5957
operation inside InnoDB will remove all locks any user has on the table
6499
5958
inside InnoDB.
6500
 
@return error number */
 
5959
@return error number */
6501
5960
UNIV_INTERN
6502
5961
int
6503
5962
InnobaseEngine::doDropTable(
6504
5963
/*======================*/
6505
 
        Session &session,
6506
 
        const TableIdentifier &identifier)
 
5964
        Session& session,
 
5965
        const string table_path)        /* in: table name */
6507
5966
{
6508
 
  int error;
6509
 
  trx_t*  parent_trx;
6510
 
  trx_t*  trx;
6511
 
  char  norm_name[1000];
6512
 
 
6513
 
  ut_a(identifier.getPath().length() < 1000);
6514
 
 
6515
 
  /* Strangely, MySQL passes the table name without the '.frm'
6516
 
    extension, in contrast to ::create */
6517
 
  normalize_table_name(norm_name, identifier.getPath().c_str());
6518
 
 
6519
 
  /* Get the transaction associated with the current session, or create one
6520
 
    if not yet created */
6521
 
 
6522
 
  parent_trx = check_trx_exists(&session);
6523
 
 
6524
 
  /* In case MySQL calls this in the middle of a SELECT query, release
6525
 
    possible adaptive hash latch to avoid deadlocks of threads */
6526
 
 
6527
 
  trx_search_latch_release_if_reserved(parent_trx);
6528
 
 
6529
 
  trx = innobase_trx_allocate(&session);
6530
 
 
6531
 
  srv_lower_case_table_names = TRUE;
6532
 
 
6533
 
  /* Drop the table in InnoDB */
6534
 
 
6535
 
  error = row_drop_table_for_mysql(norm_name, trx,
6536
 
                                   session_sql_command(&session)
6537
 
                                   == SQLCOM_DROP_DB);
6538
 
 
6539
 
  session.setXaId(trx->id);
6540
 
 
6541
 
  /* Flush the log to reduce probability that the .frm files and
6542
 
    the InnoDB data dictionary get out-of-sync if the user runs
6543
 
    with innodb_flush_log_at_trx_commit = 0 */
6544
 
 
6545
 
  log_buffer_flush_to_disk();
6546
 
 
6547
 
  /* Tell the InnoDB server that there might be work for
6548
 
    utility threads: */
6549
 
 
6550
 
  srv_active_wake_master_thread();
6551
 
 
6552
 
  innobase_commit_low(trx);
6553
 
 
6554
 
  trx_free_for_mysql(trx);
6555
 
 
6556
 
  if (error != ENOENT)
6557
 
    error = convert_error_code_to_mysql(error, 0, NULL);
6558
 
 
6559
 
  if (error == 0 || error == ENOENT)
6560
 
  {
6561
 
    if (identifier.getType() == message::Table::TEMPORARY)
6562
 
    {
6563
 
      session.getMessageCache().removeTableMessage(identifier);
6564
 
      ulint sql_command = session_sql_command(&session);
6565
 
 
6566
 
      // If this was the final removal to an alter table then we will need
6567
 
      // to remove the .dfe that was left behind.
6568
 
      if ((sql_command == SQLCOM_ALTER_TABLE
6569
 
       || sql_command == SQLCOM_CREATE_INDEX
6570
 
       || sql_command == SQLCOM_DROP_INDEX))
6571
 
      {
6572
 
        string path(identifier.getPath());
6573
 
 
6574
 
        path.append(DEFAULT_FILE_EXTENSION);
6575
 
 
6576
 
        (void)internal::my_delete(path.c_str(), MYF(0));
6577
 
      }
6578
 
    }
6579
 
    else
6580
 
    {
6581
 
      string path(identifier.getPath());
6582
 
 
6583
 
      path.append(DEFAULT_FILE_EXTENSION);
6584
 
 
6585
 
      (void)internal::my_delete(path.c_str(), MYF(0));
6586
 
    }
6587
 
  }
6588
 
 
6589
 
  return(error);
 
5967
        int     error;
 
5968
        trx_t*  parent_trx;
 
5969
        trx_t*  trx;
 
5970
        char    norm_name[1000];
 
5971
 
 
5972
        ut_a(table_path.length() < 1000);
 
5973
 
 
5974
        /* Strangely, MySQL passes the table name without the '.frm'
 
5975
        extension, in contrast to ::create */
 
5976
        normalize_table_name(norm_name, table_path.c_str());
 
5977
 
 
5978
        /* Get the transaction associated with the current session, or create one
 
5979
        if not yet created */
 
5980
 
 
5981
        parent_trx = check_trx_exists(&session);
 
5982
 
 
5983
        /* In case MySQL calls this in the middle of a SELECT query, release
 
5984
        possible adaptive hash latch to avoid deadlocks of threads */
 
5985
 
 
5986
        trx_search_latch_release_if_reserved(parent_trx);
 
5987
 
 
5988
        trx = innobase_trx_allocate(&session);
 
5989
 
 
5990
        srv_lower_case_table_names = TRUE;
 
5991
 
 
5992
        /* Drop the table in InnoDB */
 
5993
 
 
5994
        error = row_drop_table_for_mysql(norm_name, trx,
 
5995
                                         session_sql_command(&session)
 
5996
                                         == SQLCOM_DROP_DB);
 
5997
 
 
5998
        /* Flush the log to reduce probability that the .frm files and
 
5999
        the InnoDB data dictionary get out-of-sync if the user runs
 
6000
        with innodb_flush_log_at_trx_commit = 0 */
 
6001
 
 
6002
        log_buffer_flush_to_disk();
 
6003
 
 
6004
        /* Tell the InnoDB server that there might be work for
 
6005
        utility threads: */
 
6006
 
 
6007
        srv_active_wake_master_thread();
 
6008
 
 
6009
        innobase_commit_low(trx);
 
6010
 
 
6011
        trx_free_for_mysql(trx);
 
6012
 
 
6013
        if(error!=ENOENT)
 
6014
          error = convert_error_code_to_mysql(error, 0, NULL);
 
6015
 
 
6016
        return(error);
6590
6017
}
6591
6018
 
6592
6019
/*****************************************************************//**
6593
6020
Removes all tables in the named database inside InnoDB. */
6594
 
bool
6595
 
InnobaseEngine::doDropSchema(
 
6021
void
 
6022
InnobaseEngine::drop_database(
6596
6023
/*===================*/
6597
 
                             const SchemaIdentifier &identifier)
6598
 
    /*!< in: database path; inside InnoDB the name
6599
 
      of the last directory in the path is used as
6600
 
      the database name: for example, in 'mysql/data/test'
6601
 
      the database name is 'test' */
6602
 
{
6603
 
  trx_t*  trx;
6604
 
  int error;
6605
 
  string schema_path(identifier.getPath());
6606
 
  Session*  session   = current_session;
6607
 
 
6608
 
  /* Get the transaction associated with the current session, or create one
6609
 
    if not yet created */
6610
 
 
6611
 
  assert(this == innodb_engine_ptr);
6612
 
 
6613
 
  /* In the Windows plugin, session = current_session is always NULL */
6614
 
  if (session) {
6615
 
    trx_t*  parent_trx = check_trx_exists(session);
6616
 
 
6617
 
    /* In case Drizzle calls this in the middle of a SELECT
6618
 
      query, release possible adaptive hash latch to avoid
6619
 
      deadlocks of threads */
6620
 
 
6621
 
    trx_search_latch_release_if_reserved(parent_trx);
6622
 
  }
6623
 
 
6624
 
  schema_path.append("/");
6625
 
  trx = innobase_trx_allocate(session);
6626
 
  error = row_drop_database_for_mysql(schema_path.c_str(), trx);
6627
 
 
6628
 
  /* Flush the log to reduce probability that the .frm files and
6629
 
    the InnoDB data dictionary get out-of-sync if the user runs
6630
 
    with innodb_flush_log_at_trx_commit = 0 */
6631
 
 
6632
 
  log_buffer_flush_to_disk();
6633
 
 
6634
 
  /* Tell the InnoDB server that there might be work for
6635
 
    utility threads: */
6636
 
 
6637
 
  srv_active_wake_master_thread();
6638
 
 
6639
 
  innobase_commit_low(trx);
6640
 
  trx_free_for_mysql(trx);
6641
 
 
6642
 
  return false; // We are just a listener since we lack control over DDL, so we give no positive acknowledgement. 
6643
 
}
6644
 
 
6645
 
void InnobaseEngine::dropTemporarySchema()
6646
 
{
6647
 
  SchemaIdentifier schema_identifier(GLOBAL_TEMPORARY_EXT);
6648
 
  trx_t*  trx= NULL;
6649
 
  string schema_path(GLOBAL_TEMPORARY_EXT);
6650
 
 
6651
 
  schema_path.append("/");
6652
 
 
6653
 
  trx = trx_allocate_for_mysql();
6654
 
 
6655
 
  trx->mysql_thd = NULL;
6656
 
 
6657
 
  trx->check_foreigns = false;
6658
 
  trx->check_unique_secondary = false;
6659
 
 
6660
 
  (void)row_drop_database_for_mysql(schema_path.c_str(), trx);
6661
 
 
6662
 
  /* Flush the log to reduce probability that the .frm files and
6663
 
    the InnoDB data dictionary get out-of-sync if the user runs
6664
 
    with innodb_flush_log_at_trx_commit = 0 */
6665
 
 
6666
 
  log_buffer_flush_to_disk();
6667
 
 
6668
 
  /* Tell the InnoDB server that there might be work for
6669
 
    utility threads: */
6670
 
 
6671
 
  srv_active_wake_master_thread();
6672
 
 
6673
 
  innobase_commit_low(trx);
6674
 
  trx_free_for_mysql(trx);
 
6024
        char*   path)   /*!< in: database path; inside InnoDB the name
 
6025
                        of the last directory in the path is used as
 
6026
                        the database name: for example, in 'mysql/data/test'
 
6027
                        the database name is 'test' */
 
6028
{
 
6029
        ulint   len             = 0;
 
6030
        trx_t*  trx;
 
6031
        char*   ptr;
 
6032
        int     error;
 
6033
        char*   namebuf;
 
6034
        Session*        session         = current_session;
 
6035
 
 
6036
        /* Get the transaction associated with the current session, or create one
 
6037
        if not yet created */
 
6038
 
 
6039
        assert(this == innodb_engine_ptr);
 
6040
 
 
6041
        /* In the Windows plugin, session = current_session is always NULL */
 
6042
        if (session) {
 
6043
                trx_t*  parent_trx = check_trx_exists(session);
 
6044
 
 
6045
                /* In case Drizzle calls this in the middle of a SELECT
 
6046
                query, release possible adaptive hash latch to avoid
 
6047
                deadlocks of threads */
 
6048
 
 
6049
                trx_search_latch_release_if_reserved(parent_trx);
 
6050
        }
 
6051
 
 
6052
        ptr = strchr(path, '\0') - 2;
 
6053
 
 
6054
        while (ptr >= path && *ptr != '\\' && *ptr != '/') {
 
6055
                ptr--;
 
6056
                len++;
 
6057
        }
 
6058
 
 
6059
        ptr++;
 
6060
        namebuf = (char*) malloc((uint) len + 2);
 
6061
 
 
6062
        memcpy(namebuf, ptr, len);
 
6063
        namebuf[len] = '/';
 
6064
        namebuf[len + 1] = '\0';
 
6065
#ifdef  __WIN__
 
6066
        innobase_casedn_str(namebuf);
 
6067
#endif
 
6068
#if defined __WIN__ && !defined MYSQL_SERVER
 
6069
        /* In the Windows plugin, thd = current_thd is always NULL */
 
6070
        trx = trx_allocate_for_mysql();
 
6071
        trx->mysql_thd = NULL;
 
6072
        trx->mysql_query_str = NULL;
 
6073
#else
 
6074
        trx = innobase_trx_allocate(session);
 
6075
#endif
 
6076
        error = row_drop_database_for_mysql(namebuf, trx);
 
6077
        free(namebuf);
 
6078
 
 
6079
        /* Flush the log to reduce probability that the .frm files and
 
6080
        the InnoDB data dictionary get out-of-sync if the user runs
 
6081
        with innodb_flush_log_at_trx_commit = 0 */
 
6082
 
 
6083
        log_buffer_flush_to_disk();
 
6084
 
 
6085
        /* Tell the InnoDB server that there might be work for
 
6086
        utility threads: */
 
6087
 
 
6088
        srv_active_wake_master_thread();
 
6089
 
 
6090
        innobase_commit_low(trx);
 
6091
        trx_free_for_mysql(trx);
6675
6092
}
6676
6093
/*********************************************************************//**
6677
6094
Renames an InnoDB table.
6678
 
@return 0 or error code */
 
6095
@return 0 or error code */
6679
6096
static
6680
6097
int
6681
6098
innobase_rename_table(
6682
6099
/*==================*/
6683
 
  trx_t*    trx,  /*!< in: transaction */
6684
 
  const char* from, /*!< in: old name of the table */
6685
 
  const char* to, /*!< in: new name of the table */
6686
 
  ibool   lock_and_commit)
6687
 
        /*!< in: TRUE=lock data dictionary and commit */
 
6100
        trx_t*          trx,    /*!< in: transaction */
 
6101
        const char*     from,   /*!< in: old name of the table */
 
6102
        const char*     to,     /*!< in: new name of the table */
 
6103
        ibool           lock_and_commit)
 
6104
                                /*!< in: TRUE=lock data dictionary and commit */
6688
6105
{
6689
 
  int error;
6690
 
  char norm_to[FN_REFLEN];
6691
 
  char norm_from[FN_REFLEN];
6692
 
 
6693
 
  srv_lower_case_table_names = TRUE;
6694
 
 
6695
 
  normalize_table_name(norm_to, to);
6696
 
  normalize_table_name(norm_from, from);
6697
 
 
6698
 
  /* Serialize data dictionary operations with dictionary mutex:
6699
 
  no deadlocks can occur then in these operations */
6700
 
 
6701
 
  if (lock_and_commit) {
6702
 
    row_mysql_lock_data_dictionary(trx);
6703
 
  }
6704
 
 
6705
 
  error = row_rename_table_for_mysql(
6706
 
    norm_from, norm_to, trx, lock_and_commit);
6707
 
 
6708
 
  if (error != DB_SUCCESS) {
6709
 
    FILE* ef = dict_foreign_err_file;
6710
 
 
6711
 
    fputs("InnoDB: Renaming table ", ef);
6712
 
    ut_print_name(ef, trx, TRUE, norm_from);
6713
 
    fputs(" to ", ef);
6714
 
    ut_print_name(ef, trx, TRUE, norm_to);
6715
 
    fputs(" failed!\n", ef);
6716
 
  }
6717
 
 
6718
 
  if (lock_and_commit) {
6719
 
    row_mysql_unlock_data_dictionary(trx);
6720
 
 
6721
 
    /* Flush the log to reduce probability that the .frm
6722
 
    files and the InnoDB data dictionary get out-of-sync
6723
 
    if the user runs with innodb_flush_log_at_trx_commit = 0 */
6724
 
 
6725
 
    log_buffer_flush_to_disk();
6726
 
  }
6727
 
 
6728
 
  return error;
 
6106
        int     error;
 
6107
        char*   norm_to;
 
6108
        char*   norm_from;
 
6109
 
 
6110
        srv_lower_case_table_names = TRUE;
 
6111
 
 
6112
        // Magic number 64 arbitrary
 
6113
        norm_to = (char*) malloc(strlen(to) + 64);
 
6114
        norm_from = (char*) malloc(strlen(from) + 64);
 
6115
 
 
6116
        normalize_table_name(norm_to, to);
 
6117
        normalize_table_name(norm_from, from);
 
6118
 
 
6119
        /* Serialize data dictionary operations with dictionary mutex:
 
6120
        no deadlocks can occur then in these operations */
 
6121
 
 
6122
        if (lock_and_commit) {
 
6123
                row_mysql_lock_data_dictionary(trx);
 
6124
        }
 
6125
 
 
6126
        error = row_rename_table_for_mysql(
 
6127
                norm_from, norm_to, trx, lock_and_commit);
 
6128
 
 
6129
        if (error != DB_SUCCESS) {
 
6130
                FILE* ef = dict_foreign_err_file;
 
6131
 
 
6132
                fputs("InnoDB: Renaming table ", ef);
 
6133
                ut_print_name(ef, trx, TRUE, norm_from);
 
6134
                fputs(" to ", ef);
 
6135
                ut_print_name(ef, trx, TRUE, norm_to);
 
6136
                fputs(" failed!\n", ef);
 
6137
        }
 
6138
 
 
6139
        if (lock_and_commit) {
 
6140
                row_mysql_unlock_data_dictionary(trx);
 
6141
 
 
6142
                /* Flush the log to reduce probability that the .frm
 
6143
                files and the InnoDB data dictionary get out-of-sync
 
6144
                if the user runs with innodb_flush_log_at_trx_commit = 0 */
 
6145
 
 
6146
                log_buffer_flush_to_disk();
 
6147
        }
 
6148
 
 
6149
        free(norm_to);
 
6150
        free(norm_from);
 
6151
 
 
6152
        return error;
6729
6153
}
6730
6154
/*********************************************************************//**
6731
6155
Renames an InnoDB table.
6732
 
@return 0 or error code */
6733
 
UNIV_INTERN int InnobaseEngine::doRenameTable(Session &session, const TableIdentifier &from, const TableIdentifier &to)
 
6156
@return 0 or error code */
 
6157
UNIV_INTERN
 
6158
int
 
6159
InnobaseEngine::doRenameTable(
 
6160
/*======================*/
 
6161
        Session*        session,
 
6162
        const char*     from,   /*!< in: old name of the table */
 
6163
        const char*     to)     /*!< in: new name of the table */
6734
6164
{
6735
 
  // A temp table alter table/rename is a shallow rename and only the
6736
 
  // definition needs to be updated.
6737
 
  if (to.getType() == message::Table::TEMPORARY && from.getType() == message::Table::TEMPORARY)
6738
 
  {
6739
 
    session.getMessageCache().renameTableMessage(from, to);
6740
 
    return 0;
6741
 
  }
6742
 
 
6743
 
  trx_t*  trx;
6744
 
  int error;
6745
 
  trx_t*  parent_trx;
6746
 
 
6747
 
  /* Get the transaction associated with the current session, or create one
6748
 
    if not yet created */
6749
 
 
6750
 
  parent_trx = check_trx_exists(&session);
6751
 
 
6752
 
  /* In case MySQL calls this in the middle of a SELECT query, release
6753
 
    possible adaptive hash latch to avoid deadlocks of threads */
6754
 
 
6755
 
  trx_search_latch_release_if_reserved(parent_trx);
6756
 
 
6757
 
  trx = innobase_trx_allocate(&session);
6758
 
 
6759
 
  error = innobase_rename_table(trx, from.getPath().c_str(), to.getPath().c_str(), TRUE);
6760
 
 
6761
 
  session.setXaId(trx->id);
6762
 
 
6763
 
  /* Tell the InnoDB server that there might be work for
6764
 
    utility threads: */
6765
 
 
6766
 
  srv_active_wake_master_thread();
6767
 
 
6768
 
  innobase_commit_low(trx);
6769
 
  trx_free_for_mysql(trx);
6770
 
 
6771
 
  /* Add a special case to handle the Duplicated Key error
6772
 
     and return DB_ERROR instead.
6773
 
     This is to avoid a possible SIGSEGV error from mysql error
6774
 
     handling code. Currently, mysql handles the Duplicated Key
6775
 
     error by re-entering the storage layer and getting dup key
6776
 
     info by calling get_dup_key(). This operation requires a valid
6777
 
     table handle ('row_prebuilt_t' structure) which could no
6778
 
     longer be available in the error handling stage. The suggested
6779
 
     solution is to report a 'table exists' error message (since
6780
 
     the dup key error here is due to an existing table whose name
6781
 
     is the one we are trying to rename to) and return the generic
6782
 
     error code. */
6783
 
  if (error == (int) DB_DUPLICATE_KEY) {
6784
 
    my_error(ER_TABLE_EXISTS_ERROR, MYF(0), to.getPath().c_str());
6785
 
    error = DB_ERROR;
6786
 
  }
6787
 
 
6788
 
  error = convert_error_code_to_mysql(error, 0, NULL);
6789
 
 
6790
 
  if (not error)
6791
 
  {
6792
 
    // If this fails, we are in trouble
6793
 
    plugin::StorageEngine::renameDefinitionFromPath(to, from);
6794
 
  }
6795
 
 
6796
 
  return(error);
 
6165
        trx_t*  trx;
 
6166
        int     error;
 
6167
        trx_t*  parent_trx;
 
6168
 
 
6169
        /* Get the transaction associated with the current session, or create one
 
6170
        if not yet created */
 
6171
 
 
6172
        parent_trx = check_trx_exists(session);
 
6173
 
 
6174
        /* In case MySQL calls this in the middle of a SELECT query, release
 
6175
        possible adaptive hash latch to avoid deadlocks of threads */
 
6176
 
 
6177
        trx_search_latch_release_if_reserved(parent_trx);
 
6178
 
 
6179
        trx = innobase_trx_allocate(session);
 
6180
 
 
6181
        error = innobase_rename_table(trx, from, to, TRUE);
 
6182
 
 
6183
        /* Tell the InnoDB server that there might be work for
 
6184
        utility threads: */
 
6185
 
 
6186
        srv_active_wake_master_thread();
 
6187
 
 
6188
        innobase_commit_low(trx);
 
6189
        trx_free_for_mysql(trx);
 
6190
 
 
6191
        error = convert_error_code_to_mysql(error, 0, NULL);
 
6192
 
 
6193
        return(error);
6797
6194
}
6798
6195
 
6799
6196
/*********************************************************************//**
6800
6197
Estimates the number of index records in a range.
6801
 
@return estimated number of rows */
 
6198
@return estimated number of rows */
6802
6199
UNIV_INTERN
6803
6200
ha_rows
6804
6201
ha_innobase::records_in_range(
6805
6202
/*==========================*/
6806
 
  uint      keynr,    /*!< in: index number */
6807
 
  key_range   *min_key, /*!< in: start key value of the
6808
 
               range, may also be 0 */
6809
 
  key_range   *max_key) /*!< in: range end key val, may
6810
 
               also be 0 */
 
6203
        uint                    keynr,          /*!< in: index number */
 
6204
        key_range               *min_key,       /*!< in: start key value of the
 
6205
                                                   range, may also be 0 */
 
6206
        key_range               *max_key)       /*!< in: range end key val, may
 
6207
                                                   also be 0 */
6811
6208
{
6812
 
  KeyInfo*    key;
6813
 
  dict_index_t* index;
6814
 
  unsigned char*    key_val_buff2 = (unsigned char*) malloc(
6815
 
              getTable()->getShare()->stored_rec_length
6816
 
          + getTable()->getShare()->max_key_length + 100);
6817
 
  ulint   buff2_len = getTable()->getShare()->stored_rec_length
6818
 
          + getTable()->getShare()->max_key_length + 100;
6819
 
  dtuple_t* range_start;
6820
 
  dtuple_t* range_end;
6821
 
  ib_int64_t  n_rows;
6822
 
  ulint   mode1;
6823
 
  ulint   mode2;
6824
 
  mem_heap_t* heap;
6825
 
 
6826
 
  ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
6827
 
 
6828
 
  prebuilt->trx->op_info = (char*)"estimating records in index range";
6829
 
 
6830
 
  /* In case MySQL calls this in the middle of a SELECT query, release
6831
 
  possible adaptive hash latch to avoid deadlocks of threads */
6832
 
 
6833
 
  trx_search_latch_release_if_reserved(prebuilt->trx);
6834
 
 
6835
 
  active_index = keynr;
6836
 
 
6837
 
  key = &getTable()->key_info[active_index];
6838
 
 
6839
 
  index = innobase_get_index(keynr);
6840
 
 
6841
 
  /* There exists possibility of not being able to find requested
6842
 
     index due to inconsistency between MySQL and InoDB dictionary info.
6843
 
     Necessary message should have been printed in innobase_get_index() */
6844
 
  if (UNIV_UNLIKELY(!index)) {
6845
 
    n_rows = HA_POS_ERROR;
6846
 
    goto func_exit;
6847
 
  }
6848
 
 
6849
 
  if (UNIV_UNLIKELY(!row_merge_is_index_usable(prebuilt->trx, index))) {
6850
 
    n_rows = HA_ERR_TABLE_DEF_CHANGED;
6851
 
    goto func_exit;
6852
 
  }
6853
 
 
6854
 
  heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
6855
 
            + sizeof(dtuple_t)));
6856
 
 
6857
 
  range_start = dtuple_create(heap, key->key_parts);
6858
 
  dict_index_copy_types(range_start, index, key->key_parts);
6859
 
 
6860
 
  range_end = dtuple_create(heap, key->key_parts);
6861
 
  dict_index_copy_types(range_end, index, key->key_parts);
6862
 
 
6863
 
  row_sel_convert_mysql_key_to_innobase(
6864
 
        range_start, (byte*) &key_val_buff[0],
6865
 
        (ulint)upd_and_key_val_buff_len,
6866
 
        index,
6867
 
        (byte*) (min_key ? min_key->key :
6868
 
           (const unsigned char*) 0),
6869
 
        (ulint) (min_key ? min_key->length : 0),
6870
 
        prebuilt->trx);
6871
 
 
6872
 
  row_sel_convert_mysql_key_to_innobase(
6873
 
        range_end, (byte*) key_val_buff2,
6874
 
        buff2_len, index,
6875
 
        (byte*) (max_key ? max_key->key :
6876
 
           (const unsigned char*) 0),
6877
 
        (ulint) (max_key ? max_key->length : 0),
6878
 
        prebuilt->trx);
6879
 
 
6880
 
  mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
6881
 
            HA_READ_KEY_EXACT);
6882
 
  mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
6883
 
            HA_READ_KEY_EXACT);
6884
 
 
6885
 
  if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
6886
 
 
6887
 
    n_rows = btr_estimate_n_rows_in_range(index, range_start,
6888
 
                  mode1, range_end,
6889
 
                  mode2);
6890
 
  } else {
6891
 
 
6892
 
    n_rows = HA_POS_ERROR;
6893
 
  }
6894
 
 
6895
 
  mem_heap_free(heap);
6896
 
 
6897
 
func_exit:
6898
 
  free(key_val_buff2);
6899
 
 
6900
 
  prebuilt->trx->op_info = (char*)"";
6901
 
 
6902
 
  /* The MySQL optimizer seems to believe an estimate of 0 rows is
6903
 
  always accurate and may return the result 'Empty set' based on that.
6904
 
  The accuracy is not guaranteed, and even if it were, for a locking
6905
 
  read we should anyway perform the search to set the next-key lock.
6906
 
  Add 1 to the value to make sure MySQL does not make the assumption! */
6907
 
 
6908
 
  if (n_rows == 0) {
6909
 
    n_rows = 1;
6910
 
  }
6911
 
 
6912
 
  return((ha_rows) n_rows);
 
6209
        KEY*            key;
 
6210
        dict_index_t*   index;
 
6211
        unsigned char*          key_val_buff2   = (unsigned char*) malloc(
 
6212
                                                  table->s->stored_rec_length
 
6213
                                        + table->s->max_key_length + 100);
 
6214
        ulint           buff2_len = table->s->stored_rec_length
 
6215
                                        + table->s->max_key_length + 100;
 
6216
        dtuple_t*       range_start;
 
6217
        dtuple_t*       range_end;
 
6218
        ib_int64_t      n_rows;
 
6219
        ulint           mode1;
 
6220
        ulint           mode2;
 
6221
        mem_heap_t*     heap;
 
6222
 
 
6223
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
6224
 
 
6225
        prebuilt->trx->op_info = (char*)"estimating records in index range";
 
6226
 
 
6227
        /* In case MySQL calls this in the middle of a SELECT query, release
 
6228
        possible adaptive hash latch to avoid deadlocks of threads */
 
6229
 
 
6230
        trx_search_latch_release_if_reserved(prebuilt->trx);
 
6231
 
 
6232
        active_index = keynr;
 
6233
 
 
6234
        key = table->key_info + active_index;
 
6235
 
 
6236
        index = dict_table_get_index_on_name(prebuilt->table, key->name);
 
6237
 
 
6238
        /* MySQL knows about this index and so we must be able to find it.*/
 
6239
        ut_a(index);
 
6240
 
 
6241
        heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
 
6242
                                    + sizeof(dtuple_t)));
 
6243
 
 
6244
        range_start = dtuple_create(heap, key->key_parts);
 
6245
        dict_index_copy_types(range_start, index, key->key_parts);
 
6246
 
 
6247
        range_end = dtuple_create(heap, key->key_parts);
 
6248
        dict_index_copy_types(range_end, index, key->key_parts);
 
6249
 
 
6250
        row_sel_convert_mysql_key_to_innobase(
 
6251
                                range_start, (byte*) key_val_buff,
 
6252
                                (ulint)upd_and_key_val_buff_len,
 
6253
                                index,
 
6254
                                (byte*) (min_key ? min_key->key :
 
6255
                                         (const unsigned char*) 0),
 
6256
                                (ulint) (min_key ? min_key->length : 0),
 
6257
                                prebuilt->trx);
 
6258
 
 
6259
        row_sel_convert_mysql_key_to_innobase(
 
6260
                                range_end, (byte*) key_val_buff2,
 
6261
                                buff2_len, index,
 
6262
                                (byte*) (max_key ? max_key->key :
 
6263
                                         (const unsigned char*) 0),
 
6264
                                (ulint) (max_key ? max_key->length : 0),
 
6265
                                prebuilt->trx);
 
6266
 
 
6267
        mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
 
6268
                                                HA_READ_KEY_EXACT);
 
6269
        mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
 
6270
                                                HA_READ_KEY_EXACT);
 
6271
 
 
6272
        if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
 
6273
 
 
6274
                n_rows = btr_estimate_n_rows_in_range(index, range_start,
 
6275
                                                      mode1, range_end,
 
6276
                                                      mode2);
 
6277
        } else {
 
6278
 
 
6279
                n_rows = HA_POS_ERROR;
 
6280
        }
 
6281
 
 
6282
        mem_heap_free(heap);
 
6283
 
 
6284
        free(key_val_buff2);
 
6285
 
 
6286
        prebuilt->trx->op_info = (char*)"";
 
6287
 
 
6288
        /* The MySQL optimizer seems to believe an estimate of 0 rows is
 
6289
        always accurate and may return the result 'Empty set' based on that.
 
6290
        The accuracy is not guaranteed, and even if it were, for a locking
 
6291
        read we should anyway perform the search to set the next-key lock.
 
6292
        Add 1 to the value to make sure MySQL does not make the assumption! */
 
6293
 
 
6294
        if (n_rows == 0) {
 
6295
                n_rows = 1;
 
6296
        }
 
6297
 
 
6298
        return((ha_rows) n_rows);
6913
6299
}
6914
6300
 
6915
6301
/*********************************************************************//**
6916
6302
Gives an UPPER BOUND to the number of rows in a table. This is used in
6917
6303
filesort.cc.
6918
 
@return upper bound of rows */
 
6304
@return upper bound of rows */
6919
6305
UNIV_INTERN
6920
6306
ha_rows
6921
6307
ha_innobase::estimate_rows_upper_bound(void)
6922
6308
/*======================================*/
6923
6309
{
6924
 
  dict_index_t* index;
6925
 
  uint64_t  estimate;
6926
 
  uint64_t  local_data_file_length;
6927
 
 
6928
 
  /* We do not know if MySQL can call this function before calling
6929
 
  external_lock(). To be safe, update the session of the current table
6930
 
  handle. */
6931
 
 
6932
 
  update_session(getTable()->in_use);
6933
 
 
6934
 
  prebuilt->trx->op_info = (char*)
6935
 
         "calculating upper bound for table rows";
6936
 
 
6937
 
  /* In case MySQL calls this in the middle of a SELECT query, release
6938
 
  possible adaptive hash latch to avoid deadlocks of threads */
6939
 
 
6940
 
  trx_search_latch_release_if_reserved(prebuilt->trx);
6941
 
 
6942
 
  index = dict_table_get_first_index(prebuilt->table);
6943
 
 
6944
 
  ut_a(index->stat_n_leaf_pages > 0);
6945
 
 
6946
 
  local_data_file_length =
6947
 
    ((uint64_t) index->stat_n_leaf_pages) * UNIV_PAGE_SIZE;
6948
 
 
6949
 
 
6950
 
  /* Calculate a minimum length for a clustered index record and from
6951
 
  that an upper bound for the number of rows. Since we only calculate
6952
 
  new statistics in row0mysql.c when a table has grown by a threshold
6953
 
  factor, we must add a safety factor 2 in front of the formula below. */
6954
 
 
6955
 
  estimate = 2 * local_data_file_length /
6956
 
           dict_index_calc_min_rec_len(index);
6957
 
 
6958
 
  prebuilt->trx->op_info = (char*)"";
6959
 
 
6960
 
  return((ha_rows) estimate);
 
6310
        dict_index_t*   index;
 
6311
        uint64_t        estimate;
 
6312
        uint64_t        local_data_file_length;
 
6313
 
 
6314
        /* We do not know if MySQL can call this function before calling
 
6315
        external_lock(). To be safe, update the session of the current table
 
6316
        handle. */
 
6317
 
 
6318
        update_session(ha_session());
 
6319
 
 
6320
        prebuilt->trx->op_info = (char*)
 
6321
                                 "calculating upper bound for table rows";
 
6322
 
 
6323
        /* In case MySQL calls this in the middle of a SELECT query, release
 
6324
        possible adaptive hash latch to avoid deadlocks of threads */
 
6325
 
 
6326
        trx_search_latch_release_if_reserved(prebuilt->trx);
 
6327
 
 
6328
        index = dict_table_get_first_index(prebuilt->table);
 
6329
 
 
6330
        ut_a(index->stat_n_leaf_pages > 0);
 
6331
 
 
6332
        local_data_file_length =
 
6333
                ((uint64_t) index->stat_n_leaf_pages) * UNIV_PAGE_SIZE;
 
6334
 
 
6335
 
 
6336
        /* Calculate a minimum length for a clustered index record and from
 
6337
        that an upper bound for the number of rows. Since we only calculate
 
6338
        new statistics in row0mysql.c when a table has grown by a threshold
 
6339
        factor, we must add a safety factor 2 in front of the formula below. */
 
6340
 
 
6341
        estimate = 2 * local_data_file_length /
 
6342
                                         dict_index_calc_min_rec_len(index);
 
6343
 
 
6344
        prebuilt->trx->op_info = (char*)"";
 
6345
 
 
6346
        return((ha_rows) estimate);
6961
6347
}
6962
6348
 
6963
6349
/*********************************************************************//**
6964
6350
How many seeks it will take to read through the table. This is to be
6965
6351
comparable to the number returned by records_in_range so that we can
6966
6352
decide if we should scan the table or use keys.
6967
 
@return estimated time measured in disk seeks */
 
6353
@return estimated time measured in disk seeks */
6968
6354
UNIV_INTERN
6969
6355
double
6970
6356
ha_innobase::scan_time()
6971
6357
/*====================*/
6972
6358
{
6973
 
  /* Since MySQL seems to favor table scans too much over index
6974
 
  searches, we pretend that a sequential read takes the same time
6975
 
  as a random disk read, that is, we do not divide the following
6976
 
  by 10, which would be physically realistic. */
 
6359
        /* Since MySQL seems to favor table scans too much over index
 
6360
        searches, we pretend that a sequential read takes the same time
 
6361
        as a random disk read, that is, we do not divide the following
 
6362
        by 10, which would be physically realistic. */
6977
6363
 
6978
 
  return((double) (prebuilt->table->stat_clustered_index_size));
 
6364
        return((double) (prebuilt->table->stat_clustered_index_size));
6979
6365
}
6980
6366
 
6981
6367
/******************************************************************//**
6982
6368
Calculate the time it takes to read a set of ranges through an index
6983
6369
This enables us to optimise reads for clustered indexes.
6984
 
@return estimated time measured in disk seeks */
 
6370
@return estimated time measured in disk seeks */
6985
6371
UNIV_INTERN
6986
6372
double
6987
6373
ha_innobase::read_time(
6988
6374
/*===================*/
6989
 
  uint  index,  /*!< in: key number */
6990
 
  uint  ranges, /*!< in: how many ranges */
6991
 
  ha_rows rows) /*!< in: estimated number of rows in the ranges */
6992
 
{
6993
 
  ha_rows total_rows;
6994
 
  double  time_for_scan;
6995
 
 
6996
 
  if (index != getTable()->getShare()->getPrimaryKey()) {
6997
 
    /* Not clustered */
6998
 
    return(Cursor::read_time(index, ranges, rows));
6999
 
  }
7000
 
 
7001
 
  if (rows <= 2) {
7002
 
 
7003
 
    return((double) rows);
7004
 
  }
7005
 
 
7006
 
  /* Assume that the read time is proportional to the scan time for all
7007
 
  rows + at most one seek per range. */
7008
 
 
7009
 
  time_for_scan = scan_time();
7010
 
 
7011
 
  if ((total_rows = estimate_rows_upper_bound()) < rows) {
7012
 
 
7013
 
    return(time_for_scan);
7014
 
  }
7015
 
 
7016
 
  return(ranges + (double) rows / (double) total_rows * time_for_scan);
7017
 
}
7018
 
 
7019
 
/*********************************************************************//**
7020
 
Calculates the key number used inside MySQL for an Innobase index. We will
7021
 
first check the "index translation table" for a match of the index to get
7022
 
the index number. If there does not exist an "index translation table",
7023
 
or not able to find the index in the translation table, then we will fall back
7024
 
to the traditional way of looping through dict_index_t list to find a
7025
 
match. In this case, we have to take into account if we generated a
7026
 
default clustered index for the table
7027
 
@return the key number used inside MySQL */
7028
 
static
7029
 
unsigned int
7030
 
innobase_get_mysql_key_number_for_index(
7031
 
/*====================================*/
7032
 
        INNOBASE_SHARE*         share,  /*!< in: share structure for index
7033
 
                                        translation table. */
7034
 
        const drizzled::Table*  table,  /*!< in: table in MySQL data
7035
 
                                        dictionary */
7036
 
        dict_table_t*           ib_table,/*!< in: table in Innodb data
7037
 
                                        dictionary */
7038
 
        const dict_index_t*     index)  /*!< in: index */
7039
 
{
7040
 
        const dict_index_t*     ind;
7041
 
        unsigned int            i;
7042
 
 
7043
 
        ut_ad(index);
7044
 
        ut_ad(ib_table);
7045
 
        ut_ad(table);
7046
 
        ut_ad(share);
7047
 
 
7048
 
        /* If index does not belong to the table of share structure. Search
7049
 
        index->table instead */
7050
 
        if (index->table != ib_table) {
7051
 
                i = 0;
7052
 
                ind = dict_table_get_first_index(index->table);
7053
 
 
7054
 
                while (index != ind) {
7055
 
                        ind = dict_table_get_next_index(ind);
7056
 
                        i++;
7057
 
                }
7058
 
 
7059
 
                if (row_table_got_default_clust_index(index->table)) {
7060
 
                        ut_a(i > 0);
7061
 
                        i--;
7062
 
                }
7063
 
 
7064
 
                return(i);
7065
 
        }
7066
 
 
7067
 
        /* If index does not belong to the table of share structure. Search
7068
 
        index->table instead */
7069
 
        if (index->table != ib_table) {
7070
 
                i = 0;
7071
 
                ind = dict_table_get_first_index(index->table);
7072
 
 
7073
 
                while (index != ind) {
7074
 
                        ind = dict_table_get_next_index(ind);
7075
 
                        i++;
7076
 
                }
7077
 
 
7078
 
                if (row_table_got_default_clust_index(index->table)) {
7079
 
                        ut_a(i > 0);
7080
 
                        i--;
7081
 
                }
7082
 
 
7083
 
                return(i);
7084
 
        }
7085
 
 
7086
 
        /* If index translation table exists, we will first check
7087
 
        the index through index translation table for a match. */
7088
 
        if (share->idx_trans_tbl.index_mapping) {
7089
 
                for (i = 0; i < share->idx_trans_tbl.index_count; i++) {
7090
 
                        if (share->idx_trans_tbl.index_mapping[i] == index) {
7091
 
                                return(i);
7092
 
                        }
7093
 
                }
7094
 
 
7095
 
                /* Print an error message if we cannot find the index
7096
 
                ** in the "index translation table". */
7097
 
                errmsg_printf(ERRMSG_LVL_ERROR,
7098
 
                              "Cannot find index %s in InnoDB index "
7099
 
                                "translation table.", index->name);
7100
 
        }
7101
 
 
7102
 
        /* If we do not have an "index translation table", or not able
7103
 
        to find the index in the translation table, we'll directly find
7104
 
        matching index in the dict_index_t list */
7105
 
        for (i = 0; i < table->getShare()->keys; i++) {
7106
 
                ind = dict_table_get_index_on_name(
7107
 
                        ib_table, table->key_info[i].name);
7108
 
 
7109
 
                if (index == ind) {
7110
 
                        return(i);
7111
 
                }
7112
 
        }
7113
 
 
7114
 
                errmsg_printf(ERRMSG_LVL_ERROR,
7115
 
                              "Cannot find matching index number for index %s "
7116
 
                              "in InnoDB index list.", index->name);
7117
 
 
7118
 
        return(0);
7119
 
}
 
6375
        uint    index,  /*!< in: key number */
 
6376
        uint    ranges, /*!< in: how many ranges */
 
6377
        ha_rows rows)   /*!< in: estimated number of rows in the ranges */
 
6378
{
 
6379
        ha_rows total_rows;
 
6380
        double  time_for_scan;
 
6381
 
 
6382
        if (index != table->s->primary_key) {
 
6383
                /* Not clustered */
 
6384
                return(Cursor::read_time(index, ranges, rows));
 
6385
        }
 
6386
 
 
6387
        if (rows <= 2) {
 
6388
 
 
6389
                return((double) rows);
 
6390
        }
 
6391
 
 
6392
        /* Assume that the read time is proportional to the scan time for all
 
6393
        rows + at most one seek per range. */
 
6394
 
 
6395
        time_for_scan = scan_time();
 
6396
 
 
6397
        if ((total_rows = estimate_rows_upper_bound()) < rows) {
 
6398
 
 
6399
                return(time_for_scan);
 
6400
        }
 
6401
 
 
6402
        return(ranges + (double) rows / (double) total_rows * time_for_scan);
 
6403
}
 
6404
 
7120
6405
/*********************************************************************//**
7121
6406
Returns statistics information of the table to the MySQL interpreter,
7122
6407
in various fields of the handle object. */
7124
6409
int
7125
6410
ha_innobase::info(
7126
6411
/*==============*/
7127
 
  uint flag)  /*!< in: what information MySQL requests */
 
6412
        uint flag)      /*!< in: what information MySQL requests */
7128
6413
{
7129
 
  dict_table_t* ib_table;
7130
 
  dict_index_t* index;
7131
 
  ha_rows   rec_per_key;
7132
 
  ib_int64_t  n_rows;
7133
 
  os_file_stat_t  stat_info;
7134
 
 
7135
 
  /* If we are forcing recovery at a high level, we will suppress
7136
 
  statistics calculation on tables, because that may crash the
7137
 
  server if an index is badly corrupted. */
7138
 
 
7139
 
  /* We do not know if MySQL can call this function before calling
7140
 
  external_lock(). To be safe, update the session of the current table
7141
 
  handle. */
7142
 
 
7143
 
  update_session(getTable()->in_use);
7144
 
 
7145
 
  /* In case MySQL calls this in the middle of a SELECT query, release
7146
 
  possible adaptive hash latch to avoid deadlocks of threads */
7147
 
 
7148
 
  prebuilt->trx->op_info = (char*)"returning various info to MySQL";
7149
 
 
7150
 
  trx_search_latch_release_if_reserved(prebuilt->trx);
7151
 
 
7152
 
  ib_table = prebuilt->table;
7153
 
 
7154
 
  if (flag & HA_STATUS_TIME) {
7155
 
    /* In Analyze we call with this flag: update
7156
 
       then statistics so that they are up-to-date */
7157
 
 
7158
 
    prebuilt->trx->op_info = "updating table statistics";
7159
 
 
7160
 
    dict_update_statistics(ib_table);
7161
 
 
7162
 
    prebuilt->trx->op_info = "returning various info to MySQL";
7163
 
 
7164
 
    fs::path get_status_path(getDataHomeCatalog());
7165
 
    get_status_path /= ib_table->name;
7166
 
    fs::change_extension(get_status_path, "dfe");
7167
 
 
7168
 
    /* Note that we do not know the access time of the table,
7169
 
    nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
7170
 
 
7171
 
    if (os_file_get_status(get_status_path.file_string().c_str(), &stat_info)) {
7172
 
      stats.create_time = (ulong) stat_info.ctime;
7173
 
    }
7174
 
  }
7175
 
 
7176
 
  if (flag & HA_STATUS_VARIABLE) {
7177
 
    n_rows = ib_table->stat_n_rows;
7178
 
 
7179
 
    /* Because we do not protect stat_n_rows by any mutex in a
7180
 
    delete, it is theoretically possible that the value can be
7181
 
    smaller than zero! TODO: fix this race.
7182
 
 
7183
 
    The MySQL optimizer seems to assume in a left join that n_rows
7184
 
    is an accurate estimate if it is zero. Of course, it is not,
7185
 
    since we do not have any locks on the rows yet at this phase.
7186
 
    Since SHOW TABLE STATUS seems to call this function with the
7187
 
    HA_STATUS_TIME flag set, while the left join optimizer does not
7188
 
    set that flag, we add one to a zero value if the flag is not
7189
 
    set. That way SHOW TABLE STATUS will show the best estimate,
7190
 
    while the optimizer never sees the table empty. */
7191
 
 
7192
 
    if (n_rows < 0) {
7193
 
      n_rows = 0;
7194
 
    }
7195
 
 
7196
 
    if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
7197
 
      n_rows++;
7198
 
    }
7199
 
 
7200
 
    /* Fix bug#40386: Not flushing query cache after truncate.
7201
 
    n_rows can not be 0 unless the table is empty, set to 1
7202
 
    instead. The original problem of bug#29507 is actually
7203
 
    fixed in the server code. */
7204
 
    if (session_sql_command(user_session) == SQLCOM_TRUNCATE) {
7205
 
 
7206
 
      n_rows = 1;
7207
 
 
7208
 
      /* We need to reset the prebuilt value too, otherwise
7209
 
      checks for values greater than the last value written
7210
 
      to the table will fail and the autoinc counter will
7211
 
      not be updated. This will force doInsertRecord() into
7212
 
      attempting an update of the table's AUTOINC counter. */
7213
 
 
7214
 
      prebuilt->autoinc_last_value = 0;
7215
 
    }
7216
 
 
7217
 
    stats.records = (ha_rows)n_rows;
7218
 
    stats.deleted = 0;
7219
 
    stats.data_file_length = ((uint64_t)
7220
 
        ib_table->stat_clustered_index_size)
7221
 
          * UNIV_PAGE_SIZE;
7222
 
    stats.index_file_length = ((uint64_t)
7223
 
        ib_table->stat_sum_of_other_index_sizes)
7224
 
          * UNIV_PAGE_SIZE;
7225
 
 
7226
 
    /* Since fsp_get_available_space_in_free_extents() is
7227
 
    acquiring latches inside InnoDB, we do not call it if we
7228
 
    are asked by MySQL to avoid locking. Another reason to
7229
 
    avoid the call is that it uses quite a lot of CPU.
7230
 
    See Bug#38185. */
7231
 
    if (flag & HA_STATUS_NO_LOCK) {
7232
 
      /* We do not update delete_length if no
7233
 
         locking is requested so the "old" value can
7234
 
         remain. delete_length is initialized to 0 in
7235
 
         the ha_statistics' constructor. */
7236
 
    } else if (UNIV_UNLIKELY
7237
 
               (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE)) {
7238
 
      /* Avoid accessing the tablespace if
7239
 
         innodb_crash_recovery is set to a high value. */
7240
 
      stats.delete_length = 0;
7241
 
    } else {
7242
 
      /* lock the data dictionary to avoid races with
7243
 
      ibd_file_missing and tablespace_discarded */
7244
 
      row_mysql_lock_data_dictionary(prebuilt->trx);
7245
 
 
7246
 
      /* ib_table->space must be an existent tablespace */
7247
 
      if (!ib_table->ibd_file_missing
7248
 
          && !ib_table->tablespace_discarded) {
7249
 
 
7250
 
        stats.delete_length =
7251
 
          fsp_get_available_space_in_free_extents(
7252
 
            ib_table->space) * 1024;
7253
 
      } else {
7254
 
 
7255
 
        Session*  session;
7256
 
 
7257
 
        session= getTable()->in_use;
7258
 
        assert(session);
7259
 
 
7260
 
        push_warning_printf(
7261
 
          session,
7262
 
          DRIZZLE_ERROR::WARN_LEVEL_WARN,
7263
 
          ER_CANT_GET_STAT,
7264
 
          "InnoDB: Trying to get the free "
7265
 
          "space for table %s but its "
7266
 
          "tablespace has been discarded or "
7267
 
          "the .ibd file is missing. Setting "
7268
 
          "the free space to zero.",
7269
 
          ib_table->name);
7270
 
 
7271
 
        stats.delete_length = 0;
7272
 
      }
7273
 
 
7274
 
      row_mysql_unlock_data_dictionary(prebuilt->trx);
7275
 
    }
7276
 
 
7277
 
    stats.check_time = 0;
7278
 
 
7279
 
    if (stats.records == 0) {
7280
 
      stats.mean_rec_length = 0;
7281
 
    } else {
7282
 
      stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
7283
 
    }
7284
 
  }
7285
 
 
7286
 
  if (flag & HA_STATUS_CONST) {
7287
 
    ulong i;
7288
 
    /* Verify the number of index in InnoDB and MySQL
7289
 
       matches up. If prebuilt->clust_index_was_generated
7290
 
       holds, InnoDB defines GEN_CLUST_INDEX internally */
7291
 
    ulint       num_innodb_index = UT_LIST_GET_LEN(ib_table->indexes) - prebuilt->clust_index_was_generated;
7292
 
 
7293
 
    if (getTable()->getShare()->keys != num_innodb_index) {
7294
 
      errmsg_printf(ERRMSG_LVL_ERROR, "Table %s contains %lu "
7295
 
                      "indexes inside InnoDB, which "
7296
 
                      "is different from the number of "
7297
 
                      "indexes %u defined in the MySQL ",
7298
 
                      ib_table->name, num_innodb_index,
7299
 
                      getTable()->getShare()->keys);
7300
 
    }
7301
 
 
7302
 
    for (i = 0; i < getTable()->getShare()->sizeKeys(); i++) {
7303
 
      ulong j;
7304
 
      /* We could get index quickly through internal
7305
 
         index mapping with the index translation table.
7306
 
         The identity of index (match up index name with
7307
 
         that of table->key_info[i]) is already verified in
7308
 
         innobase_get_index().  */
7309
 
      index = innobase_get_index(i);
7310
 
 
7311
 
      if (index == NULL) {
7312
 
        errmsg_printf(ERRMSG_LVL_ERROR, "Table %s contains fewer "
7313
 
            "indexes inside InnoDB than "
7314
 
            "are defined in the MySQL "
7315
 
            ".frm file. Have you mixed up "
7316
 
            ".frm files from different "
7317
 
            "installations? See "
7318
 
            REFMAN
7319
 
            "innodb-troubleshooting.html\n",
7320
 
            ib_table->name);
7321
 
        break;
7322
 
      }
7323
 
 
7324
 
      for (j = 0; j < getTable()->key_info[i].key_parts; j++) {
7325
 
 
7326
 
        if (j + 1 > index->n_uniq) {
7327
 
          errmsg_printf(ERRMSG_LVL_ERROR, 
 
6414
        dict_table_t*   ib_table;
 
6415
        dict_index_t*   index;
 
6416
        ha_rows         rec_per_key;
 
6417
        ib_int64_t      n_rows;
 
6418
        ulong           j;
 
6419
        ulong           i;
 
6420
        char            path[FN_REFLEN];
 
6421
        os_file_stat_t  stat_info;
 
6422
 
 
6423
        /* If we are forcing recovery at a high level, we will suppress
 
6424
        statistics calculation on tables, because that may crash the
 
6425
        server if an index is badly corrupted. */
 
6426
 
 
6427
        if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
 
6428
 
 
6429
                /* We return success (0) instead of HA_ERR_CRASHED,
 
6430
                because we want MySQL to process this query and not
 
6431
                stop, like it would do if it received the error code
 
6432
                HA_ERR_CRASHED. */
 
6433
 
 
6434
                return(0);
 
6435
        }
 
6436
 
 
6437
        /* We do not know if MySQL can call this function before calling
 
6438
        external_lock(). To be safe, update the session of the current table
 
6439
        handle. */
 
6440
 
 
6441
        update_session(ha_session());
 
6442
 
 
6443
        /* In case MySQL calls this in the middle of a SELECT query, release
 
6444
        possible adaptive hash latch to avoid deadlocks of threads */
 
6445
 
 
6446
        prebuilt->trx->op_info = (char*)"returning various info to MySQL";
 
6447
 
 
6448
        trx_search_latch_release_if_reserved(prebuilt->trx);
 
6449
 
 
6450
        ib_table = prebuilt->table;
 
6451
 
 
6452
        if (flag & HA_STATUS_TIME) {
 
6453
                if (innobase_stats_on_metadata) {
 
6454
                        /* In sql_show we call with this flag: update
 
6455
                        then statistics so that they are up-to-date */
 
6456
 
 
6457
                        prebuilt->trx->op_info = "updating table statistics";
 
6458
 
 
6459
                        dict_update_statistics(ib_table);
 
6460
 
 
6461
                        prebuilt->trx->op_info = "returning various info to MySQL";
 
6462
                }
 
6463
 
 
6464
                snprintf(path, sizeof(path), "%s/%s%s",
 
6465
                               drizzle_data_home, ib_table->name, ".dfe");
 
6466
 
 
6467
                internal::unpack_filename(path,path);
 
6468
 
 
6469
                /* Note that we do not know the access time of the table,
 
6470
                nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
 
6471
 
 
6472
                if (os_file_get_status(path,&stat_info)) {
 
6473
                        stats.create_time = (ulong) stat_info.ctime;
 
6474
                }
 
6475
        }
 
6476
 
 
6477
        if (flag & HA_STATUS_VARIABLE) {
 
6478
                n_rows = ib_table->stat_n_rows;
 
6479
 
 
6480
                /* Because we do not protect stat_n_rows by any mutex in a
 
6481
                delete, it is theoretically possible that the value can be
 
6482
                smaller than zero! TODO: fix this race.
 
6483
 
 
6484
                The MySQL optimizer seems to assume in a left join that n_rows
 
6485
                is an accurate estimate if it is zero. Of course, it is not,
 
6486
                since we do not have any locks on the rows yet at this phase.
 
6487
                Since SHOW TABLE STATUS seems to call this function with the
 
6488
                HA_STATUS_TIME flag set, while the left join optimizer does not
 
6489
                set that flag, we add one to a zero value if the flag is not
 
6490
                set. That way SHOW TABLE STATUS will show the best estimate,
 
6491
                while the optimizer never sees the table empty. */
 
6492
 
 
6493
                if (n_rows < 0) {
 
6494
                        n_rows = 0;
 
6495
                }
 
6496
 
 
6497
                if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
 
6498
                        n_rows++;
 
6499
                }
 
6500
 
 
6501
                /* Fix bug#40386: Not flushing query cache after truncate.
 
6502
                n_rows can not be 0 unless the table is empty, set to 1
 
6503
                instead. The original problem of bug#29507 is actually
 
6504
                fixed in the server code. */
 
6505
                if (session_sql_command(user_session) == SQLCOM_TRUNCATE) {
 
6506
 
 
6507
                        n_rows = 1;
 
6508
 
 
6509
                        /* We need to reset the prebuilt value too, otherwise
 
6510
                        checks for values greater than the last value written
 
6511
                        to the table will fail and the autoinc counter will
 
6512
                        not be updated. This will force write_row() into
 
6513
                        attempting an update of the table's AUTOINC counter. */
 
6514
 
 
6515
                        prebuilt->autoinc_last_value = 0;
 
6516
                }
 
6517
 
 
6518
                stats.records = (ha_rows)n_rows;
 
6519
                stats.deleted = 0;
 
6520
                stats.data_file_length = ((uint64_t)
 
6521
                                ib_table->stat_clustered_index_size)
 
6522
                                        * UNIV_PAGE_SIZE;
 
6523
                stats.index_file_length = ((uint64_t)
 
6524
                                ib_table->stat_sum_of_other_index_sizes)
 
6525
                                        * UNIV_PAGE_SIZE;
 
6526
 
 
6527
                /* Since fsp_get_available_space_in_free_extents() is
 
6528
                acquiring latches inside InnoDB, we do not call it if we
 
6529
                are asked by MySQL to avoid locking. Another reason to
 
6530
                avoid the call is that it uses quite a lot of CPU.
 
6531
                See Bug#38185.
 
6532
                We do not update delete_length if no locking is requested
 
6533
                so the "old" value can remain. delete_length is initialized
 
6534
                to 0 in the ha_statistics' constructor. */
 
6535
                if (!(flag & HA_STATUS_NO_LOCK)) {
 
6536
 
 
6537
                        /* lock the data dictionary to avoid races with
 
6538
                        ibd_file_missing and tablespace_discarded */
 
6539
                        row_mysql_lock_data_dictionary(prebuilt->trx);
 
6540
 
 
6541
                        /* ib_table->space must be an existent tablespace */
 
6542
                        if (!ib_table->ibd_file_missing
 
6543
                            && !ib_table->tablespace_discarded) {
 
6544
 
 
6545
                                stats.delete_length =
 
6546
                                        fsp_get_available_space_in_free_extents(
 
6547
                                                ib_table->space) * 1024;
 
6548
                        } else {
 
6549
 
 
6550
                                Session*        session;
 
6551
 
 
6552
                                session = ha_session();
 
6553
 
 
6554
                                push_warning_printf(
 
6555
                                        session,
 
6556
                                        DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
6557
                                        ER_CANT_GET_STAT,
 
6558
                                        "InnoDB: Trying to get the free "
 
6559
                                        "space for table %s but its "
 
6560
                                        "tablespace has been discarded or "
 
6561
                                        "the .ibd file is missing. Setting "
 
6562
                                        "the free space to zero.",
 
6563
                                        ib_table->name);
 
6564
 
 
6565
                                stats.delete_length = 0;
 
6566
                        }
 
6567
 
 
6568
                        row_mysql_unlock_data_dictionary(prebuilt->trx);
 
6569
                }
 
6570
 
 
6571
                stats.check_time = 0;
 
6572
 
 
6573
                if (stats.records == 0) {
 
6574
                        stats.mean_rec_length = 0;
 
6575
                } else {
 
6576
                        stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
 
6577
                }
 
6578
        }
 
6579
 
 
6580
        if (flag & HA_STATUS_CONST) {
 
6581
                index = dict_table_get_first_index(ib_table);
 
6582
 
 
6583
                if (prebuilt->clust_index_was_generated) {
 
6584
                        index = dict_table_get_next_index(index);
 
6585
                }
 
6586
 
 
6587
                for (i = 0; i < table->s->keys; i++) {
 
6588
                        if (index == NULL) {
 
6589
                                errmsg_printf(ERRMSG_LVL_ERROR, "Table %s contains fewer "
 
6590
                                                "indexes inside InnoDB than "
 
6591
                                                "are defined in the MySQL "
 
6592
                                                ".frm file. Have you mixed up "
 
6593
                                                ".frm files from different "
 
6594
                                                "installations? See "
 
6595
                                                REFMAN
 
6596
                                                "innodb-troubleshooting.html\n",
 
6597
                                                ib_table->name);
 
6598
                                break;
 
6599
                        }
 
6600
 
 
6601
                        for (j = 0; j < table->key_info[i].key_parts; j++) {
 
6602
 
 
6603
                                if (j + 1 > index->n_uniq) {
 
6604
                                        errmsg_printf(ERRMSG_LVL_ERROR, 
7328
6605
"Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking "
7329
6606
"statistics for %lu columns. Have you mixed up .frm files from different "
7330
6607
"installations? "
7331
6608
"See " REFMAN "innodb-troubleshooting.html\n",
7332
 
              index->name,
7333
 
              ib_table->name,
7334
 
              (unsigned long)
7335
 
              index->n_uniq, j + 1);
7336
 
          break;
7337
 
        }
7338
 
 
7339
 
        dict_index_stat_mutex_enter(index);
7340
 
 
7341
 
        if (index->stat_n_diff_key_vals[j + 1] == 0) {
7342
 
 
7343
 
          rec_per_key = stats.records;
7344
 
        } else {
7345
 
          rec_per_key = (ha_rows)(stats.records /
7346
 
           index->stat_n_diff_key_vals[j + 1]);
7347
 
        }
7348
 
 
7349
 
        dict_index_stat_mutex_exit(index);
7350
 
 
7351
 
        /* Since MySQL seems to favor table scans
7352
 
        too much over index searches, we pretend
7353
 
        index selectivity is 2 times better than
7354
 
        our estimate: */
7355
 
 
7356
 
        rec_per_key = rec_per_key / 2;
7357
 
 
7358
 
        if (rec_per_key == 0) {
7359
 
          rec_per_key = 1;
7360
 
        }
7361
 
 
7362
 
        getTable()->key_info[i].rec_per_key[j]=
7363
 
          rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
7364
 
          (ulong) rec_per_key;
7365
 
      }
7366
 
    }
7367
 
  }
7368
 
 
7369
 
  if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
7370
 
    goto func_exit;
7371
 
  }
7372
 
 
7373
 
  if (flag & HA_STATUS_ERRKEY) {
7374
 
    const dict_index_t* err_index;
7375
 
 
7376
 
    ut_a(prebuilt->trx);
7377
 
    ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
7378
 
 
7379
 
    err_index = trx_get_error_info(prebuilt->trx);
7380
 
 
7381
 
    if (err_index) {
7382
 
      errkey = (unsigned int)
7383
 
        innobase_get_mysql_key_number_for_index(share, getTable(), ib_table,
7384
 
                                                err_index);
7385
 
    } else {
7386
 
      errkey = (unsigned int) prebuilt->trx->error_key_num;
7387
 
    }
7388
 
  }
7389
 
 
7390
 
  if ((flag & HA_STATUS_AUTO) && getTable()->found_next_number_field) {
7391
 
    stats.auto_increment_value = innobase_peek_autoinc();
7392
 
  }
7393
 
 
7394
 
func_exit:
7395
 
  prebuilt->trx->op_info = (char*)"";
7396
 
 
7397
 
  return(0);
 
6609
                                                        index->name,
 
6610
                                                        ib_table->name,
 
6611
                                                        (unsigned long)
 
6612
                                                        index->n_uniq, j + 1);
 
6613
                                        break;
 
6614
                                }
 
6615
 
 
6616
                                if (index->stat_n_diff_key_vals[j + 1] == 0) {
 
6617
 
 
6618
                                        rec_per_key = stats.records;
 
6619
                                } else {
 
6620
                                        rec_per_key = (ha_rows)(stats.records /
 
6621
                                         index->stat_n_diff_key_vals[j + 1]);
 
6622
                                }
 
6623
 
 
6624
                                /* Since MySQL seems to favor table scans
 
6625
                                too much over index searches, we pretend
 
6626
                                index selectivity is 2 times better than
 
6627
                                our estimate: */
 
6628
 
 
6629
                                rec_per_key = rec_per_key / 2;
 
6630
 
 
6631
                                if (rec_per_key == 0) {
 
6632
                                        rec_per_key = 1;
 
6633
                                }
 
6634
 
 
6635
                                table->key_info[i].rec_per_key[j]=
 
6636
                                  rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
 
6637
                                  (ulong) rec_per_key;
 
6638
                        }
 
6639
 
 
6640
                        index = dict_table_get_next_index(index);
 
6641
                }
 
6642
        }
 
6643
 
 
6644
        if (flag & HA_STATUS_ERRKEY) {
 
6645
                const dict_index_t*     err_index;
 
6646
 
 
6647
                ut_a(prebuilt->trx);
 
6648
                ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
 
6649
 
 
6650
                err_index = trx_get_error_info(prebuilt->trx);
 
6651
 
 
6652
                if (err_index) {
 
6653
                        errkey = (unsigned int)
 
6654
                                row_get_mysql_key_number_for_index(err_index);
 
6655
                } else {
 
6656
                        errkey = (unsigned int) prebuilt->trx->error_key_num;
 
6657
                }
 
6658
        }
 
6659
 
 
6660
        if ((flag & HA_STATUS_AUTO) && table->found_next_number_field) {
 
6661
                stats.auto_increment_value = innobase_peek_autoinc();
 
6662
        }
 
6663
 
 
6664
        prebuilt->trx->op_info = (char*)"";
 
6665
 
 
6666
        return(0);
7398
6667
}
7399
6668
 
7400
6669
/**********************************************************************//**
7401
6670
Updates index cardinalities of the table, based on 8 random dives into
7402
6671
each index tree. This does NOT calculate exact statistics on the table.
7403
 
@return returns always 0 (success) */
 
6672
@return returns always 0 (success) */
7404
6673
UNIV_INTERN
7405
6674
int
7406
6675
ha_innobase::analyze(
7407
6676
/*=================*/
7408
 
  Session*)   /*!< in: connection thread handle */
 
6677
        Session*)               /*!< in: connection thread handle */
7409
6678
{
7410
 
  /* Simply call ::info() with all the flags */
7411
 
  info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
 
6679
        /* Simply call ::info() with all the flags */
 
6680
        info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
7412
6681
 
7413
 
  return(0);
 
6682
        return(0);
7414
6683
}
7415
6684
 
7416
6685
/*******************************************************************//**
7417
6686
Tries to check that an InnoDB table is not corrupted. If corruption is
7418
6687
noticed, prints to stderr information about it. In case of corruption
7419
6688
may also assert a failure and crash the server.
7420
 
@return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
 
6689
@return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
7421
6690
UNIV_INTERN
7422
6691
int
7423
6692
ha_innobase::check(
7424
6693
/*===============*/
7425
 
  Session*  session)  /*!< in: user thread handle */
 
6694
        Session*        session)        /*!< in: user thread handle */
7426
6695
{
7427
 
  dict_index_t* index;
7428
 
  ulint         n_rows;
7429
 
  ulint         n_rows_in_table = ULINT_UNDEFINED;
7430
 
  ibool         is_ok           = TRUE;
7431
 
  ulint         old_isolation_level;
7432
 
 
7433
 
  assert(session == getTable()->in_use);
7434
 
  ut_a(prebuilt->trx);
7435
 
  ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
7436
 
  ut_a(prebuilt->trx == session_to_trx(session));
7437
 
 
7438
 
  if (prebuilt->mysql_template == NULL) {
7439
 
    /* Build the template; we will use a dummy template
7440
 
    in index scans done in checking */
7441
 
 
7442
 
    build_template(prebuilt, NULL, getTable(), ROW_MYSQL_WHOLE_ROW);
7443
 
  }
7444
 
 
7445
 
  if (prebuilt->table->ibd_file_missing) {
7446
 
        errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: Error:\n"
7447
 
                    "InnoDB: MySQL is trying to use a table handle"
7448
 
                    " but the .ibd file for\n"
7449
 
                    "InnoDB: table %s does not exist.\n"
7450
 
                    "InnoDB: Have you deleted the .ibd file"
7451
 
                    " from the database directory under\n"
7452
 
                    "InnoDB: the MySQL datadir, or have you"
7453
 
                    " used DISCARD TABLESPACE?\n"
7454
 
                    "InnoDB: Please refer to\n"
7455
 
                    "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
7456
 
                    "InnoDB: how you can resolve the problem.\n",
7457
 
                    prebuilt->table->name);
7458
 
    return(HA_ADMIN_CORRUPT);
7459
 
  }
7460
 
 
7461
 
  prebuilt->trx->op_info = "checking table";
7462
 
 
7463
 
  old_isolation_level = prebuilt->trx->isolation_level;
7464
 
 
7465
 
  /* We must run the index record counts at an isolation level
7466
 
     >= READ COMMITTED, because a dirty read can see a wrong number
7467
 
     of records in some index; to play safe, we use always
7468
 
     REPEATABLE READ here */
7469
 
 
7470
 
  prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
7471
 
 
7472
 
  /* Enlarge the fatal lock wait timeout during CHECK TABLE. */
7473
 
  mutex_enter(&kernel_mutex);
7474
 
  srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
7475
 
  mutex_exit(&kernel_mutex);
7476
 
 
7477
 
  for (index = dict_table_get_first_index(prebuilt->table);
7478
 
       index != NULL;
7479
 
       index = dict_table_get_next_index(index)) {
7480
 
#if 0
7481
 
    fputs("Validating index ", stderr);
7482
 
    ut_print_name(stderr, trx, FALSE, index->name);
7483
 
    putc('\n', stderr);
7484
 
#endif
7485
 
 
7486
 
    if (!btr_validate_index(index, prebuilt->trx)) {
7487
 
      is_ok = FALSE;
7488
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7489
 
                          ER_NOT_KEYFILE,
7490
 
                          "InnoDB: The B-tree of"
7491
 
                          " index '%-.200s' is corrupted.",
7492
 
                          index->name);
7493
 
      continue;
7494
 
    }
7495
 
 
7496
 
    /* Instead of invoking change_active_index(), set up
7497
 
       a dummy template for non-locking reads, disabling
7498
 
       access to the clustered index. */
7499
 
    prebuilt->index = index;
7500
 
 
7501
 
    prebuilt->index_usable = row_merge_is_index_usable(
7502
 
                        prebuilt->trx, prebuilt->index);
7503
 
 
7504
 
    if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
7505
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7506
 
                          HA_ERR_TABLE_DEF_CHANGED,
7507
 
                          "InnoDB: Insufficient history for"
7508
 
                          " index '%-.200s'",
7509
 
                          index->name);
7510
 
      continue;
7511
 
    }
7512
 
 
7513
 
    prebuilt->sql_stat_start = TRUE;
7514
 
    prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
7515
 
    prebuilt->n_template = 0;
7516
 
    prebuilt->need_to_access_clustered = FALSE;
7517
 
 
7518
 
    dtuple_set_n_fields(prebuilt->search_tuple, 0);
7519
 
 
7520
 
    prebuilt->select_lock_type = LOCK_NONE;
7521
 
 
7522
 
    if (!row_check_index_for_mysql(prebuilt, index, &n_rows)) {
7523
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7524
 
                          ER_NOT_KEYFILE,
7525
 
                          "InnoDB: The B-tree of"
7526
 
                          " index '%-.200s' is corrupted.",
7527
 
                          index->name);
7528
 
      is_ok = FALSE;
7529
 
    }
7530
 
 
7531
 
    if (user_session->getKilled()) {
7532
 
      break;
7533
 
    }
7534
 
 
7535
 
#if 0
7536
 
    fprintf(stderr, "%lu entries in index %s\n", n_rows,
7537
 
            index->name);
7538
 
#endif
7539
 
 
7540
 
    if (index == dict_table_get_first_index(prebuilt->table)) {
7541
 
      n_rows_in_table = n_rows;
7542
 
    } else if (n_rows != n_rows_in_table) {
7543
 
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7544
 
                          ER_NOT_KEYFILE,
7545
 
                          "InnoDB: Index '%-.200s'"
7546
 
                          " contains %lu entries,"
7547
 
                          " should be %lu.",
7548
 
                          index->name,
7549
 
                          (ulong) n_rows,
7550
 
                          (ulong) n_rows_in_table);
7551
 
      is_ok = FALSE;
7552
 
    }
7553
 
  }
7554
 
 
7555
 
  /* Restore the original isolation level */
7556
 
  prebuilt->trx->isolation_level = old_isolation_level;
7557
 
 
7558
 
  /* We validate also the whole adaptive hash index for all tables
7559
 
     at every CHECK TABLE */
7560
 
 
7561
 
  if (!btr_search_validate()) {
7562
 
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
7563
 
                 ER_NOT_KEYFILE,
7564
 
                 "InnoDB: The adaptive hash index is corrupted.");
7565
 
    is_ok = FALSE;
7566
 
  }
7567
 
 
7568
 
  /* Restore the fatal lock wait timeout after CHECK TABLE. */
7569
 
  mutex_enter(&kernel_mutex);
7570
 
  srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
7571
 
  mutex_exit(&kernel_mutex);
7572
 
 
7573
 
  prebuilt->trx->op_info = "";
7574
 
  if (user_session->getKilled()) {
7575
 
    my_error(ER_QUERY_INTERRUPTED, MYF(0));
7576
 
  }
7577
 
 
7578
 
  return(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT);
 
6696
        ulint           ret;
 
6697
 
 
6698
        assert(session == ha_session());
 
6699
        ut_a(prebuilt->trx);
 
6700
        ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
 
6701
        ut_a(prebuilt->trx == session_to_trx(session));
 
6702
 
 
6703
        if (prebuilt->mysql_template == NULL) {
 
6704
                /* Build the template; we will use a dummy template
 
6705
                in index scans done in checking */
 
6706
 
 
6707
                build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
 
6708
        }
 
6709
 
 
6710
        ret = row_check_table_for_mysql(prebuilt);
 
6711
 
 
6712
        if (ret == DB_SUCCESS) {
 
6713
                return(HA_ADMIN_OK);
 
6714
        }
 
6715
 
 
6716
        return(HA_ADMIN_CORRUPT);
7579
6717
}
7580
6718
 
7581
6719
/*************************************************************//**
7582
6720
Adds information about free space in the InnoDB tablespace to a table comment
7583
6721
which is printed out when a user calls SHOW TABLE STATUS. Adds also info on
7584
6722
foreign keys.
7585
 
@return table comment + InnoDB free space + info on foreign keys */
 
6723
@return table comment + InnoDB free space + info on foreign keys */
7586
6724
UNIV_INTERN
7587
6725
char*
7588
6726
ha_innobase::update_table_comment(
7589
6727
/*==============================*/
7590
 
  const char* comment)/*!< in: table comment defined by user */
 
6728
        const char*     comment)/*!< in: table comment defined by user */
7591
6729
{
7592
 
  uint  length = (uint) strlen(comment);
7593
 
  char* str;
7594
 
  long  flen;
7595
 
 
7596
 
  /* We do not know if MySQL can call this function before calling
7597
 
  external_lock(). To be safe, update the session of the current table
7598
 
  handle. */
7599
 
 
7600
 
  if (length > 64000 - 3) {
7601
 
    return((char*)comment); /* string too long */
7602
 
  }
7603
 
 
7604
 
  update_session(getTable()->in_use);
7605
 
 
7606
 
  prebuilt->trx->op_info = (char*)"returning table comment";
7607
 
 
7608
 
  /* In case MySQL calls this in the middle of a SELECT query, release
7609
 
  possible adaptive hash latch to avoid deadlocks of threads */
7610
 
 
7611
 
  trx_search_latch_release_if_reserved(prebuilt->trx);
7612
 
  str = NULL;
7613
 
 
7614
 
  /* output the data to a temporary file */
7615
 
 
7616
 
  mutex_enter(&srv_dict_tmpfile_mutex);
7617
 
  rewind(srv_dict_tmpfile);
7618
 
 
7619
 
  fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
7620
 
    fsp_get_available_space_in_free_extents(
7621
 
      prebuilt->table->space));
7622
 
 
7623
 
  dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
7624
 
        prebuilt->trx, prebuilt->table);
7625
 
  flen = ftell(srv_dict_tmpfile);
7626
 
  if (flen < 0) {
7627
 
    flen = 0;
7628
 
  } else if (length + flen + 3 > 64000) {
7629
 
    flen = 64000 - 3 - length;
7630
 
  }
7631
 
 
7632
 
  /* allocate buffer for the full string, and
7633
 
  read the contents of the temporary file */
7634
 
 
7635
 
  str = (char*) malloc(length + flen + 3);
7636
 
 
7637
 
  if (str) {
7638
 
    char* pos = str + length;
7639
 
    if (length) {
7640
 
      memcpy(str, comment, length);
7641
 
      *pos++ = ';';
7642
 
      *pos++ = ' ';
7643
 
    }
7644
 
    rewind(srv_dict_tmpfile);
7645
 
    flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
7646
 
    pos[flen] = 0;
7647
 
  }
7648
 
 
7649
 
  mutex_exit(&srv_dict_tmpfile_mutex);
7650
 
 
7651
 
  prebuilt->trx->op_info = (char*)"";
7652
 
 
7653
 
  return(str ? str : (char*) comment);
 
6730
        uint    length = (uint) strlen(comment);
 
6731
        char*   str;
 
6732
        long    flen;
 
6733
 
 
6734
        /* We do not know if MySQL can call this function before calling
 
6735
        external_lock(). To be safe, update the session of the current table
 
6736
        handle. */
 
6737
 
 
6738
        if (length > 64000 - 3) {
 
6739
                return((char*)comment); /* string too long */
 
6740
        }
 
6741
 
 
6742
        update_session(ha_session());
 
6743
 
 
6744
        prebuilt->trx->op_info = (char*)"returning table comment";
 
6745
 
 
6746
        /* In case MySQL calls this in the middle of a SELECT query, release
 
6747
        possible adaptive hash latch to avoid deadlocks of threads */
 
6748
 
 
6749
        trx_search_latch_release_if_reserved(prebuilt->trx);
 
6750
        str = NULL;
 
6751
 
 
6752
        /* output the data to a temporary file */
 
6753
 
 
6754
        mutex_enter(&srv_dict_tmpfile_mutex);
 
6755
        rewind(srv_dict_tmpfile);
 
6756
 
 
6757
        fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
 
6758
                fsp_get_available_space_in_free_extents(
 
6759
                        prebuilt->table->space));
 
6760
 
 
6761
        dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
 
6762
                                prebuilt->trx, prebuilt->table);
 
6763
        flen = ftell(srv_dict_tmpfile);
 
6764
        if (flen < 0) {
 
6765
                flen = 0;
 
6766
        } else if (length + flen + 3 > 64000) {
 
6767
                flen = 64000 - 3 - length;
 
6768
        }
 
6769
 
 
6770
        /* allocate buffer for the full string, and
 
6771
        read the contents of the temporary file */
 
6772
 
 
6773
        str = (char*) malloc(length + flen + 3);
 
6774
 
 
6775
        if (str) {
 
6776
                char* pos       = str + length;
 
6777
                if (length) {
 
6778
                        memcpy(str, comment, length);
 
6779
                        *pos++ = ';';
 
6780
                        *pos++ = ' ';
 
6781
                }
 
6782
                rewind(srv_dict_tmpfile);
 
6783
                flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
 
6784
                pos[flen] = 0;
 
6785
        }
 
6786
 
 
6787
        mutex_exit(&srv_dict_tmpfile_mutex);
 
6788
 
 
6789
        prebuilt->trx->op_info = (char*)"";
 
6790
 
 
6791
        return(str ? str : (char*) comment);
7654
6792
}
7655
6793
 
7656
6794
/*******************************************************************//**
7663
6801
ha_innobase::get_foreign_key_create_info(void)
7664
6802
/*==========================================*/
7665
6803
{
7666
 
  char* str = 0;
7667
 
  long  flen;
7668
 
 
7669
 
  ut_a(prebuilt != NULL);
7670
 
 
7671
 
  /* We do not know if MySQL can call this function before calling
7672
 
  external_lock(). To be safe, update the session of the current table
7673
 
  handle. */
7674
 
 
7675
 
  update_session(getTable()->in_use);
7676
 
 
7677
 
  prebuilt->trx->op_info = (char*)"getting info on foreign keys";
7678
 
 
7679
 
  /* In case MySQL calls this in the middle of a SELECT query,
7680
 
  release possible adaptive hash latch to avoid
7681
 
  deadlocks of threads */
7682
 
 
7683
 
  trx_search_latch_release_if_reserved(prebuilt->trx);
7684
 
 
7685
 
  mutex_enter(&srv_dict_tmpfile_mutex);
7686
 
  rewind(srv_dict_tmpfile);
7687
 
 
7688
 
  /* output the data to a temporary file */
7689
 
  dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
7690
 
        prebuilt->trx, prebuilt->table);
7691
 
  prebuilt->trx->op_info = (char*)"";
7692
 
 
7693
 
  flen = ftell(srv_dict_tmpfile);
7694
 
  if (flen < 0) {
7695
 
    flen = 0;
7696
 
  } else if (flen > 64000 - 1) {
7697
 
    flen = 64000 - 1;
7698
 
  }
7699
 
 
7700
 
  /* allocate buffer for the string, and
7701
 
  read the contents of the temporary file */
7702
 
 
7703
 
  str = (char*) malloc(flen + 1);
7704
 
 
7705
 
  if (str) {
7706
 
    rewind(srv_dict_tmpfile);
7707
 
    flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
7708
 
    str[flen] = 0;
7709
 
  }
7710
 
 
7711
 
  mutex_exit(&srv_dict_tmpfile_mutex);
7712
 
 
7713
 
  return(str);
 
6804
        char*   str     = 0;
 
6805
        long    flen;
 
6806
 
 
6807
        ut_a(prebuilt != NULL);
 
6808
 
 
6809
        /* We do not know if MySQL can call this function before calling
 
6810
        external_lock(). To be safe, update the session of the current table
 
6811
        handle. */
 
6812
 
 
6813
        update_session(ha_session());
 
6814
 
 
6815
        prebuilt->trx->op_info = (char*)"getting info on foreign keys";
 
6816
 
 
6817
        /* In case MySQL calls this in the middle of a SELECT query,
 
6818
        release possible adaptive hash latch to avoid
 
6819
        deadlocks of threads */
 
6820
 
 
6821
        trx_search_latch_release_if_reserved(prebuilt->trx);
 
6822
 
 
6823
        mutex_enter(&srv_dict_tmpfile_mutex);
 
6824
        rewind(srv_dict_tmpfile);
 
6825
 
 
6826
        /* output the data to a temporary file */
 
6827
        dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
 
6828
                                prebuilt->trx, prebuilt->table);
 
6829
        prebuilt->trx->op_info = (char*)"";
 
6830
 
 
6831
        flen = ftell(srv_dict_tmpfile);
 
6832
        if (flen < 0) {
 
6833
                flen = 0;
 
6834
        } else if (flen > 64000 - 1) {
 
6835
                flen = 64000 - 1;
 
6836
        }
 
6837
 
 
6838
        /* allocate buffer for the string, and
 
6839
        read the contents of the temporary file */
 
6840
 
 
6841
        str = (char*) malloc(flen + 1);
 
6842
 
 
6843
        if (str) {
 
6844
                rewind(srv_dict_tmpfile);
 
6845
                flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
 
6846
                str[flen] = 0;
 
6847
        }
 
6848
 
 
6849
        mutex_exit(&srv_dict_tmpfile_mutex);
 
6850
 
 
6851
        return(str);
7714
6852
}
7715
6853
 
7716
6854
 
7717
6855
UNIV_INTERN
7718
6856
int
7719
 
ha_innobase::get_foreign_key_list(Session *session, List<ForeignKeyInfo> *f_key_list)
 
6857
ha_innobase::get_foreign_key_list(Session *session, List<FOREIGN_KEY_INFO> *f_key_list)
7720
6858
{
7721
6859
  dict_foreign_t* foreign;
7722
6860
 
7723
6861
  ut_a(prebuilt != NULL);
7724
 
  update_session(getTable()->in_use);
 
6862
  update_session(ha_session());
7725
6863
  prebuilt->trx->op_info = (char*)"getting list of foreign keys";
7726
6864
  trx_search_latch_release_if_reserved(prebuilt->trx);
7727
6865
  mutex_enter(&(dict_sys->mutex));
7728
6866
  foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
7729
6867
 
7730
6868
  while (foreign != NULL) {
7731
 
 
7732
 
    uint i;
7733
 
    LEX_STRING *name = 0;
7734
 
    uint ulen;
7735
 
    char uname[NAME_LEN + 1];           /* Unencoded name */
7736
 
    char db_name[NAME_LEN + 1];
7737
 
    const char *tmp_buff;
7738
 
 
7739
 
    /** Foreign id **/
7740
 
    tmp_buff = foreign->id;
7741
 
    i = 0;
7742
 
    while (tmp_buff[i] != '/')
7743
 
      i++;
7744
 
    tmp_buff += i + 1;
7745
 
    LEX_STRING *tmp_foreign_id = session->make_lex_string(NULL, tmp_buff, strlen(tmp_buff), true);
7746
 
 
7747
 
    /* Database name */
7748
 
    tmp_buff = foreign->referenced_table_name;
7749
 
 
7750
 
    i= 0;
7751
 
    while (tmp_buff[i] != '/')
7752
 
    {
7753
 
      db_name[i]= tmp_buff[i];
7754
 
      i++;
7755
 
    }
7756
 
    db_name[i] = 0;
7757
 
    ulen= TableIdentifier::filename_to_tablename(db_name, uname, sizeof(uname));
7758
 
    LEX_STRING *tmp_referenced_db = session->make_lex_string(NULL, uname, ulen, true);
7759
 
 
7760
 
    /* Table name */
7761
 
    tmp_buff += i + 1;
7762
 
    ulen= TableIdentifier::filename_to_tablename(tmp_buff, uname, sizeof(uname));
7763
 
    LEX_STRING *tmp_referenced_table = session->make_lex_string(NULL, uname, ulen, true);
7764
 
 
7765
 
    /** Foreign Fields **/
7766
 
    List<LEX_STRING> tmp_foreign_fields;
7767
 
    List<LEX_STRING> tmp_referenced_fields;
7768
 
    for (i= 0;;) {
7769
 
      tmp_buff= foreign->foreign_col_names[i];
7770
 
      name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
7771
 
      tmp_foreign_fields.push_back(name);
7772
 
      tmp_buff= foreign->referenced_col_names[i];
7773
 
      name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
7774
 
      tmp_referenced_fields.push_back(name);
7775
 
      if (++i >= foreign->n_fields)
7776
 
        break;
7777
 
    }
7778
 
 
7779
 
    ulong length;
7780
 
    if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)
7781
 
    {
7782
 
      length=7;
7783
 
      tmp_buff= "CASCADE";
7784
 
    }
7785
 
    else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
7786
 
    {
7787
 
      length=8;
7788
 
      tmp_buff= "SET NULL";
7789
 
    }
7790
 
    else if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION)
7791
 
    {
7792
 
      length=9;
7793
 
      tmp_buff= "NO ACTION";
7794
 
    }
7795
 
    else
7796
 
    {
7797
 
      length=8;
7798
 
      tmp_buff= "RESTRICT";
7799
 
    }
7800
 
    LEX_STRING *tmp_delete_method = session->make_lex_string(NULL, tmp_buff, length, true);
7801
 
 
7802
 
 
7803
 
    if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)
7804
 
    {
7805
 
      length=7;
7806
 
      tmp_buff= "CASCADE";
7807
 
    }
7808
 
    else if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
7809
 
    {
7810
 
      length=8;
7811
 
      tmp_buff= "SET NULL";
7812
 
    }
7813
 
    else if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION)
7814
 
    {
7815
 
      length=9;
7816
 
      tmp_buff= "NO ACTION";
7817
 
    }
7818
 
    else
7819
 
    {
7820
 
      length=8;
7821
 
      tmp_buff= "RESTRICT";
7822
 
    }
7823
 
    LEX_STRING *tmp_update_method = session->make_lex_string(NULL, tmp_buff, length, true);
7824
 
 
7825
 
    LEX_STRING *tmp_referenced_key_name = NULL;
7826
 
 
7827
 
    if (foreign->referenced_index &&
7828
 
        foreign->referenced_index->name)
7829
 
    {
7830
 
      tmp_referenced_key_name = session->make_lex_string(NULL,
7831
 
                                                         foreign->referenced_index->name, strlen(foreign->referenced_index->name), true);
7832
 
    }
7833
 
 
7834
 
    ForeignKeyInfo f_key_info(
7835
 
                              tmp_foreign_id, tmp_referenced_db, tmp_referenced_table,
7836
 
                              tmp_update_method, tmp_delete_method, tmp_referenced_key_name,
7837
 
                              tmp_foreign_fields, tmp_referenced_fields);
7838
 
 
7839
 
    ForeignKeyInfo *pf_key_info = (ForeignKeyInfo *)
7840
 
      session->memdup(&f_key_info, sizeof(ForeignKeyInfo));
7841
 
    f_key_list->push_back(pf_key_info);
7842
 
    foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 
6869
          uint i;
 
6870
          FOREIGN_KEY_INFO f_key_info;
 
6871
          LEX_STRING *name= 0;
 
6872
          uint ulen;
 
6873
          char uname[NAME_LEN+1];           /* Unencoded name */
 
6874
          char db_name[NAME_LEN+1];
 
6875
          const char *tmp_buff;
 
6876
 
 
6877
          tmp_buff= foreign->id;
 
6878
          i= 0;
 
6879
          while (tmp_buff[i] != '/')
 
6880
                  i++;
 
6881
          tmp_buff+= i + 1;
 
6882
          f_key_info.forein_id = session->make_lex_string(NULL, tmp_buff, strlen(tmp_buff), true);
 
6883
          tmp_buff= foreign->referenced_table_name;
 
6884
 
 
6885
          /* Database name */
 
6886
          i= 0;
 
6887
          while (tmp_buff[i] != '/')
 
6888
          {
 
6889
            db_name[i]= tmp_buff[i];
 
6890
            i++;
 
6891
          }
 
6892
          db_name[i]= 0;
 
6893
          ulen= filename_to_tablename(db_name, uname, sizeof(uname));
 
6894
          f_key_info.referenced_db = session->make_lex_string(NULL, uname, ulen, true);
 
6895
 
 
6896
          /* Table name */
 
6897
          tmp_buff+= i + 1;
 
6898
          ulen= filename_to_tablename(tmp_buff, uname, sizeof(uname));
 
6899
          f_key_info.referenced_table = session->make_lex_string(NULL, uname, ulen, true);
 
6900
 
 
6901
          for (i= 0;;) {
 
6902
                  tmp_buff= foreign->foreign_col_names[i];
 
6903
                  name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
 
6904
                  f_key_info.foreign_fields.push_back(name);
 
6905
                  tmp_buff= foreign->referenced_col_names[i];
 
6906
                  name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
 
6907
                  f_key_info.referenced_fields.push_back(name);
 
6908
                  if (++i >= foreign->n_fields)
 
6909
                          break;
 
6910
          }
 
6911
 
 
6912
          ulong length;
 
6913
          if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)
 
6914
          {
 
6915
            length=7;
 
6916
            tmp_buff= "CASCADE";
 
6917
          }
 
6918
          else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
 
6919
          {
 
6920
            length=8;
 
6921
            tmp_buff= "SET NULL";
 
6922
          }
 
6923
          else if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION)
 
6924
          {
 
6925
            length=9;
 
6926
            tmp_buff= "NO ACTION";
 
6927
          }
 
6928
          else
 
6929
          {
 
6930
            length=8;
 
6931
            tmp_buff= "RESTRICT";
 
6932
          }
 
6933
          f_key_info.delete_method = session->make_lex_string(
 
6934
                  f_key_info.delete_method, tmp_buff, length, true);
 
6935
 
 
6936
 
 
6937
          if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)
 
6938
          {
 
6939
            length=7;
 
6940
            tmp_buff= "CASCADE";
 
6941
          }
 
6942
          else if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
 
6943
          {
 
6944
            length=8;
 
6945
            tmp_buff= "SET NULL";
 
6946
          }
 
6947
          else if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION)
 
6948
          {
 
6949
            length=9;
 
6950
            tmp_buff= "NO ACTION";
 
6951
          }
 
6952
          else
 
6953
          {
 
6954
            length=8;
 
6955
            tmp_buff= "RESTRICT";
 
6956
          }
 
6957
          f_key_info.update_method = session->make_lex_string(
 
6958
                  f_key_info.update_method, tmp_buff, length, true);
 
6959
          if (foreign->referenced_index &&
 
6960
              foreign->referenced_index->name)
 
6961
          {
 
6962
            f_key_info.referenced_key_name = session->make_lex_string(
 
6963
                    f_key_info.referenced_key_name,
 
6964
                    foreign->referenced_index->name,
 
6965
                    strlen(foreign->referenced_index->name), true);
 
6966
          }
 
6967
          else
 
6968
            f_key_info.referenced_key_name= 0;
 
6969
 
 
6970
          FOREIGN_KEY_INFO *pf_key_info = (FOREIGN_KEY_INFO *)
 
6971
                  session_memdup(session, &f_key_info, sizeof(FOREIGN_KEY_INFO));
 
6972
          f_key_list->push_back(pf_key_info);
 
6973
          foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
7843
6974
  }
7844
6975
  mutex_exit(&(dict_sys->mutex));
7845
6976
  prebuilt->trx->op_info = (char*)"";
7851
6982
Checks if ALTER TABLE may change the storage engine of the table.
7852
6983
Changing storage engines is not allowed for tables for which there
7853
6984
are foreign key constraints (parent or child tables).
7854
 
@return TRUE if can switch engines */
 
6985
@return TRUE if can switch engines */
7855
6986
UNIV_INTERN
7856
6987
bool
7857
6988
ha_innobase::can_switch_engines(void)
7858
6989
/*=================================*/
7859
6990
{
7860
 
  bool  can_switch;
7861
 
 
7862
 
  ut_a(prebuilt->trx == session_to_trx(getTable()->in_use));
7863
 
 
7864
 
  prebuilt->trx->op_info =
7865
 
      "determining if there are foreign key constraints";
7866
 
  row_mysql_lock_data_dictionary(prebuilt->trx);
7867
 
 
7868
 
  can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
7869
 
      && !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
7870
 
 
7871
 
  row_mysql_unlock_data_dictionary(prebuilt->trx);
7872
 
  prebuilt->trx->op_info = "";
7873
 
 
7874
 
  return(can_switch);
 
6991
        bool    can_switch;
 
6992
 
 
6993
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
6994
 
 
6995
        prebuilt->trx->op_info =
 
6996
                        "determining if there are foreign key constraints";
 
6997
        row_mysql_lock_data_dictionary(prebuilt->trx);
 
6998
 
 
6999
        can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
 
7000
                        && !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
 
7001
 
 
7002
        row_mysql_unlock_data_dictionary(prebuilt->trx);
 
7003
        prebuilt->trx->op_info = "";
 
7004
 
 
7005
        return(can_switch);
7875
7006
}
7876
7007
 
7877
7008
/*******************************************************************//**
7879
7010
a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
7880
7011
delete is then allowed internally to resolve a duplicate key conflict in
7881
7012
REPLACE, not an update.
7882
 
@return > 0 if referenced by a FOREIGN KEY */
 
7013
@return > 0 if referenced by a FOREIGN KEY */
7883
7014
UNIV_INTERN
7884
7015
uint
7885
7016
ha_innobase::referenced_by_foreign_key(void)
7886
7017
/*========================================*/
7887
7018
{
7888
 
  if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
7889
 
 
7890
 
    return(1);
7891
 
  }
7892
 
 
7893
 
  return(0);
 
7019
        if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
 
7020
 
 
7021
                return(1);
 
7022
        }
 
7023
 
 
7024
        return(0);
7894
7025
}
7895
7026
 
7896
7027
/*******************************************************************//**
7900
7031
void
7901
7032
ha_innobase::free_foreign_key_create_info(
7902
7033
/*======================================*/
7903
 
  char* str)  /*!< in, own: create info string to free */
 
7034
        char*   str)    /*!< in, own: create info string to free */
7904
7035
{
7905
 
  if (str) {
7906
 
    free(str);
7907
 
  }
 
7036
        if (str) {
 
7037
                free(str);
 
7038
        }
7908
7039
}
7909
7040
 
7910
7041
/*******************************************************************//**
7911
7042
Tells something additional to the Cursor about how to do things.
7912
 
@return 0 or error number */
 
7043
@return 0 or error number */
7913
7044
UNIV_INTERN
7914
7045
int
7915
7046
ha_innobase::extra(
7916
7047
/*===============*/
7917
 
  enum ha_extra_function operation)
7918
 
         /*!< in: HA_EXTRA_FLUSH or some other flag */
 
7048
        enum ha_extra_function operation)
 
7049
                           /*!< in: HA_EXTRA_FLUSH or some other flag */
7919
7050
{
7920
 
  /* Warning: since it is not sure that MySQL calls external_lock
7921
 
  before calling this function, the trx field in prebuilt can be
7922
 
  obsolete! */
7923
 
 
7924
 
  switch (operation) {
7925
 
    case HA_EXTRA_FLUSH:
7926
 
      if (prebuilt->blob_heap) {
7927
 
        row_mysql_prebuilt_free_blob_heap(prebuilt);
7928
 
      }
7929
 
      break;
7930
 
    case HA_EXTRA_RESET_STATE:
7931
 
      reset_template(prebuilt);
7932
 
      break;
7933
 
    case HA_EXTRA_NO_KEYREAD:
7934
 
      prebuilt->read_just_key = 0;
7935
 
      break;
7936
 
    case HA_EXTRA_KEYREAD:
7937
 
      prebuilt->read_just_key = 1;
7938
 
      break;
7939
 
    case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
7940
 
      prebuilt->keep_other_fields_on_keyread = 1;
7941
 
      break;
7942
 
 
7943
 
      /* IMPORTANT: prebuilt->trx can be obsolete in
7944
 
      this method, because it is not sure that MySQL
7945
 
      calls external_lock before this method with the
7946
 
      parameters below.  We must not invoke update_session()
7947
 
      either, because the calling threads may change.
7948
 
      CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
7949
 
    case HA_EXTRA_IGNORE_DUP_KEY:
7950
 
      session_to_trx(getTable()->in_use)->duplicates |= TRX_DUP_IGNORE;
7951
 
      break;
7952
 
    case HA_EXTRA_WRITE_CAN_REPLACE:
7953
 
      session_to_trx(getTable()->in_use)->duplicates |= TRX_DUP_REPLACE;
7954
 
      break;
7955
 
    case HA_EXTRA_WRITE_CANNOT_REPLACE:
7956
 
      session_to_trx(getTable()->in_use)->duplicates &= ~TRX_DUP_REPLACE;
7957
 
      break;
7958
 
    case HA_EXTRA_NO_IGNORE_DUP_KEY:
7959
 
      session_to_trx(getTable()->in_use)->duplicates &=
7960
 
        ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
7961
 
      break;
7962
 
    default:/* Do nothing */
7963
 
      ;
7964
 
  }
7965
 
 
7966
 
  return(0);
 
7051
        /* Warning: since it is not sure that MySQL calls external_lock
 
7052
        before calling this function, the trx field in prebuilt can be
 
7053
        obsolete! */
 
7054
 
 
7055
        switch (operation) {
 
7056
                case HA_EXTRA_FLUSH:
 
7057
                        if (prebuilt->blob_heap) {
 
7058
                                row_mysql_prebuilt_free_blob_heap(prebuilt);
 
7059
                        }
 
7060
                        break;
 
7061
                case HA_EXTRA_RESET_STATE:
 
7062
                        reset_template(prebuilt);
 
7063
                        break;
 
7064
                case HA_EXTRA_NO_KEYREAD:
 
7065
                        prebuilt->read_just_key = 0;
 
7066
                        break;
 
7067
                case HA_EXTRA_KEYREAD:
 
7068
                        prebuilt->read_just_key = 1;
 
7069
                        break;
 
7070
                case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
 
7071
                        prebuilt->keep_other_fields_on_keyread = 1;
 
7072
                        break;
 
7073
 
 
7074
                        /* IMPORTANT: prebuilt->trx can be obsolete in
 
7075
                        this method, because it is not sure that MySQL
 
7076
                        calls external_lock before this method with the
 
7077
                        parameters below.  We must not invoke update_session()
 
7078
                        either, because the calling threads may change.
 
7079
                        CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
 
7080
                case HA_EXTRA_IGNORE_DUP_KEY:
 
7081
                        session_to_trx(ha_session())->duplicates |= TRX_DUP_IGNORE;
 
7082
                        break;
 
7083
                case HA_EXTRA_WRITE_CAN_REPLACE:
 
7084
                        session_to_trx(ha_session())->duplicates |= TRX_DUP_REPLACE;
 
7085
                        break;
 
7086
                case HA_EXTRA_WRITE_CANNOT_REPLACE:
 
7087
                        session_to_trx(ha_session())->duplicates &= ~TRX_DUP_REPLACE;
 
7088
                        break;
 
7089
                case HA_EXTRA_NO_IGNORE_DUP_KEY:
 
7090
                        session_to_trx(ha_session())->duplicates &=
 
7091
                                ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
 
7092
                        break;
 
7093
                default:/* Do nothing */
 
7094
                        ;
 
7095
        }
 
7096
 
 
7097
        return(0);
7967
7098
}
7968
7099
 
7969
7100
UNIV_INTERN
7970
7101
int
7971
7102
ha_innobase::reset()
7972
7103
{
7973
 
  if (prebuilt->blob_heap) {
7974
 
    row_mysql_prebuilt_free_blob_heap(prebuilt);
7975
 
  }
7976
 
 
7977
 
  reset_template(prebuilt);
7978
 
 
7979
 
  /* TODO: This should really be reset in reset_template() but for now
7980
 
  it's safer to do it explicitly here. */
7981
 
 
7982
 
  /* This is a statement level counter. */
7983
 
  prebuilt->autoinc_last_value = 0;
7984
 
 
7985
 
  return(0);
 
7104
        if (prebuilt->blob_heap) {
 
7105
                row_mysql_prebuilt_free_blob_heap(prebuilt);
 
7106
        }
 
7107
 
 
7108
        reset_template(prebuilt);
 
7109
 
 
7110
        /* TODO: This should really be reset in reset_template() but for now
 
7111
        it's safer to do it explicitly here. */
 
7112
 
 
7113
        /* This is a statement level counter. */
 
7114
        prebuilt->autoinc_last_value = 0;
 
7115
 
 
7116
        return(0);
 
7117
}
 
7118
 
 
7119
/******************************************************************//**
 
7120
MySQL calls this function at the start of each SQL statement inside LOCK
 
7121
TABLES. Inside LOCK TABLES the ::external_lock method does not work to
 
7122
mark SQL statement borders. Note also a special case: if a temporary table
 
7123
is created inside LOCK TABLES, MySQL has not called external_lock() at all
 
7124
on that table.
 
7125
MySQL-5.0 also calls this before each statement in an execution of a stored
 
7126
procedure. To make the execution more deterministic for binlogging, MySQL-5.0
 
7127
locks all tables involved in a stored procedure with full explicit table
 
7128
locks (session_in_lock_tables(session) holds in store_lock()) before executing
 
7129
the procedure.
 
7130
@return 0 or error code */
 
7131
UNIV_INTERN
 
7132
int
 
7133
ha_innobase::start_stmt(
 
7134
/*====================*/
 
7135
        Session*        session,        /*!< in: handle to the user thread */
 
7136
        thr_lock_type   lock_type)
 
7137
{
 
7138
        trx_t*          trx;
 
7139
 
 
7140
        update_session(session);
 
7141
 
 
7142
        trx = prebuilt->trx;
 
7143
 
 
7144
        /* Here we release the search latch and the InnoDB thread FIFO ticket
 
7145
        if they were reserved. They should have been released already at the
 
7146
        end of the previous statement, but because inside LOCK TABLES the
 
7147
        lock count method does not work to mark the end of a SELECT statement,
 
7148
        that may not be the case. We MUST release the search latch before an
 
7149
        INSERT, for example. */
 
7150
 
 
7151
        innobase_release_stat_resources(trx);
 
7152
 
 
7153
        /* Reset the AUTOINC statement level counter for multi-row INSERTs. */
 
7154
        trx->n_autoinc_rows = 0;
 
7155
 
 
7156
        prebuilt->sql_stat_start = TRUE;
 
7157
        prebuilt->hint_need_to_fetch_extra_cols = 0;
 
7158
        reset_template(prebuilt);
 
7159
 
 
7160
        if (!prebuilt->mysql_has_locked) {
 
7161
                /* This handle is for a temporary table created inside
 
7162
                this same LOCK TABLES; since MySQL does NOT call external_lock
 
7163
                in this case, we must use x-row locks inside InnoDB to be
 
7164
                prepared for an update of a row */
 
7165
 
 
7166
                prebuilt->select_lock_type = LOCK_X;
 
7167
        } else {
 
7168
                if (trx->isolation_level != TRX_ISO_SERIALIZABLE
 
7169
                        && session_sql_command(session) == SQLCOM_SELECT
 
7170
                        && lock_type == TL_READ) {
 
7171
 
 
7172
                        /* For other than temporary tables, we obtain
 
7173
                        no lock for consistent read (plain SELECT). */
 
7174
 
 
7175
                        prebuilt->select_lock_type = LOCK_NONE;
 
7176
                } else {
 
7177
                        /* Not a consistent read: restore the
 
7178
                        select_lock_type value. The value of
 
7179
                        stored_select_lock_type was decided in:
 
7180
                        1) ::store_lock(),
 
7181
                        2) ::external_lock(),
 
7182
                        3) ::init_table_handle_for_HANDLER(), and
 
7183
                      */
 
7184
 
 
7185
                        prebuilt->select_lock_type =
 
7186
                                prebuilt->stored_select_lock_type;
 
7187
                }
 
7188
        }
 
7189
 
 
7190
        trx->detailed_error[0] = '\0';
 
7191
 
 
7192
        /* Set the MySQL flag to mark that there is an active transaction */
 
7193
        if (trx->active_trans == 0) {
 
7194
 
 
7195
                innobase_register_trx_and_stmt(engine, session);
 
7196
                trx->active_trans = 1;
 
7197
        } else {
 
7198
                innobase_register_stmt(engine, session);
 
7199
        }
 
7200
 
 
7201
        return(0);
7986
7202
}
7987
7203
 
7988
7204
/******************************************************************//**
7989
7205
Maps a MySQL trx isolation level code to the InnoDB isolation level code
7990
 
@return InnoDB isolation level */
 
7206
@return InnoDB isolation level */
7991
7207
static inline
7992
7208
ulint
7993
7209
innobase_map_isolation_level(
7994
7210
/*=========================*/
7995
 
  enum_tx_isolation iso)  /*!< in: MySQL isolation level code */
 
7211
        enum_tx_isolation       iso)    /*!< in: MySQL isolation level code */
7996
7212
{
7997
 
  switch(iso) {
7998
 
    case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
7999
 
    case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
8000
 
    case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
8001
 
    case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
8002
 
    default: ut_a(0); return(0);
8003
 
  }
 
7213
        switch(iso) {
 
7214
                case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
 
7215
                case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
 
7216
                case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
 
7217
                case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
 
7218
                default: ut_a(0); return(0);
 
7219
        }
8004
7220
}
8005
7221
 
8006
7222
/******************************************************************//**
8007
7223
As MySQL will execute an external lock for every new table it uses when it
8008
 
starts to process an SQL statement.  We can use this function to store the pointer to
8009
 
the Session in the handle.
8010
 
@return 0 */
 
7224
starts to process an SQL statement (an exception is when MySQL calls
 
7225
start_stmt for the handle) we can use this function to store the pointer to
 
7226
the Session in the handle. We will also use this function to communicate
 
7227
to InnoDB that a new SQL statement has started and that we must store a
 
7228
savepoint to our transaction handle, so that we are able to roll back
 
7229
the SQL statement in case of an error.
 
7230
@return 0 */
8011
7231
UNIV_INTERN
8012
7232
int
8013
7233
ha_innobase::external_lock(
8014
7234
/*=======================*/
8015
 
  Session*  session,  /*!< in: handle to the user thread */
8016
 
  int lock_type)  /*!< in: lock type */
8017
 
{
8018
 
  update_session(session);
8019
 
 
8020
 
  trx_t *trx= prebuilt->trx;
8021
 
 
8022
 
  prebuilt->sql_stat_start = TRUE;
8023
 
  prebuilt->hint_need_to_fetch_extra_cols = 0;
8024
 
 
8025
 
  reset_template(prebuilt);
8026
 
 
8027
 
  if (lock_type == F_WRLCK) {
8028
 
 
8029
 
    /* If this is a SELECT, then it is in UPDATE TABLE ...
8030
 
    or SELECT ... FOR UPDATE */
8031
 
    prebuilt->select_lock_type = LOCK_X;
8032
 
    prebuilt->stored_select_lock_type = LOCK_X;
8033
 
  }
8034
 
 
8035
 
  if (lock_type != F_UNLCK) {
8036
 
    /* MySQL is setting a new table lock */
8037
 
 
8038
 
    if (trx->isolation_level == TRX_ISO_SERIALIZABLE
8039
 
      && prebuilt->select_lock_type == LOCK_NONE
8040
 
      && session_test_options(session,
8041
 
        OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
8042
 
 
8043
 
      /* To get serializable execution, we let InnoDB
8044
 
      conceptually add 'LOCK IN SHARE MODE' to all SELECTs
8045
 
      which otherwise would have been consistent reads. An
8046
 
      exception is consistent reads in the AUTOCOMMIT=1 mode:
8047
 
      we know that they are read-only transactions, and they
8048
 
      can be serialized also if performed as consistent
8049
 
      reads. */
8050
 
 
8051
 
      prebuilt->select_lock_type = LOCK_S;
8052
 
      prebuilt->stored_select_lock_type = LOCK_S;
8053
 
    }
8054
 
 
8055
 
    /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
8056
 
    TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
8057
 
    an InnoDB table lock if it is released immediately at the end
8058
 
    of LOCK TABLES, and InnoDB's table locks in that case cause
8059
 
    VERY easily deadlocks.
8060
 
 
8061
 
    We do not set InnoDB table locks if user has not explicitly
8062
 
    requested a table lock. Note that session_in_lock_tables(session)
8063
 
    can hold in some cases, e.g., at the start of a stored
8064
 
    procedure call (SQLCOM_CALL). */
8065
 
 
8066
 
    if (prebuilt->select_lock_type != LOCK_NONE) {
8067
 
      trx->mysql_n_tables_locked++;
8068
 
    }
8069
 
 
8070
 
    prebuilt->mysql_has_locked = TRUE;
8071
 
 
8072
 
    return(0);
8073
 
  }
8074
 
 
8075
 
  /* MySQL is releasing a table lock */
8076
 
  prebuilt->mysql_has_locked = FALSE;
8077
 
  trx->mysql_n_tables_locked= 0;
8078
 
 
8079
 
  return(0);
 
7235
        Session*        session,        /*!< in: handle to the user thread */
 
7236
        int     lock_type)      /*!< in: lock type */
 
7237
{
 
7238
        trx_t*          trx;
 
7239
 
 
7240
 
 
7241
        update_session(session);
 
7242
 
 
7243
        trx = prebuilt->trx;
 
7244
 
 
7245
        prebuilt->sql_stat_start = TRUE;
 
7246
        prebuilt->hint_need_to_fetch_extra_cols = 0;
 
7247
 
 
7248
        reset_template(prebuilt);
 
7249
 
 
7250
        if (lock_type == F_WRLCK) {
 
7251
 
 
7252
                /* If this is a SELECT, then it is in UPDATE TABLE ...
 
7253
                or SELECT ... FOR UPDATE */
 
7254
                prebuilt->select_lock_type = LOCK_X;
 
7255
                prebuilt->stored_select_lock_type = LOCK_X;
 
7256
        }
 
7257
 
 
7258
        if (lock_type != F_UNLCK) {
 
7259
                /* MySQL is setting a new table lock */
 
7260
 
 
7261
                trx->detailed_error[0] = '\0';
 
7262
 
 
7263
                /* Set the MySQL flag to mark that there is an active
 
7264
                transaction */
 
7265
                if (trx->active_trans == 0) {
 
7266
 
 
7267
                        innobase_register_trx_and_stmt(engine, session);
 
7268
                        trx->active_trans = 1;
 
7269
                } else if (trx->n_mysql_tables_in_use == 0) {
 
7270
                        innobase_register_stmt(engine, session);
 
7271
                }
 
7272
 
 
7273
                if (trx->isolation_level == TRX_ISO_SERIALIZABLE
 
7274
                        && prebuilt->select_lock_type == LOCK_NONE
 
7275
                        && session_test_options(session,
 
7276
                                OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
 
7277
 
 
7278
                        /* To get serializable execution, we let InnoDB
 
7279
                        conceptually add 'LOCK IN SHARE MODE' to all SELECTs
 
7280
                        which otherwise would have been consistent reads. An
 
7281
                        exception is consistent reads in the AUTOCOMMIT=1 mode:
 
7282
                        we know that they are read-only transactions, and they
 
7283
                        can be serialized also if performed as consistent
 
7284
                        reads. */
 
7285
 
 
7286
                        prebuilt->select_lock_type = LOCK_S;
 
7287
                        prebuilt->stored_select_lock_type = LOCK_S;
 
7288
                }
 
7289
 
 
7290
                /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
 
7291
                TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
 
7292
                an InnoDB table lock if it is released immediately at the end
 
7293
                of LOCK TABLES, and InnoDB's table locks in that case cause
 
7294
                VERY easily deadlocks.
 
7295
 
 
7296
                We do not set InnoDB table locks if user has not explicitly
 
7297
                requested a table lock. Note that session_in_lock_tables(session)
 
7298
                can hold in some cases, e.g., at the start of a stored
 
7299
                procedure call (SQLCOM_CALL). */
 
7300
 
 
7301
                if (prebuilt->select_lock_type != LOCK_NONE) {
 
7302
                        trx->mysql_n_tables_locked++;
 
7303
                }
 
7304
 
 
7305
                trx->n_mysql_tables_in_use++;
 
7306
                prebuilt->mysql_has_locked = TRUE;
 
7307
 
 
7308
                return(0);
 
7309
        }
 
7310
 
 
7311
        /* MySQL is releasing a table lock */
 
7312
 
 
7313
        trx->n_mysql_tables_in_use--;
 
7314
        prebuilt->mysql_has_locked = FALSE;
 
7315
 
 
7316
        /* Release a possible FIFO ticket and search latch. Since we
 
7317
        may reserve the kernel mutex, we have to release the search
 
7318
        system latch first to obey the latching order. */
 
7319
 
 
7320
        innobase_release_stat_resources(trx);
 
7321
 
 
7322
        /* If the MySQL lock count drops to zero we know that the current SQL
 
7323
        statement has ended */
 
7324
 
 
7325
        if (trx->n_mysql_tables_in_use == 0) {
 
7326
 
 
7327
                trx->mysql_n_tables_locked = 0;
 
7328
                prebuilt->used_in_HANDLER = FALSE;
 
7329
 
 
7330
                if (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
 
7331
                        if (trx->active_trans != 0) {
 
7332
                                engine->commit(session, TRUE);
 
7333
                        }
 
7334
                } else {
 
7335
                        if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
 
7336
                                                && trx->global_read_view) {
 
7337
 
 
7338
                                /* At low transaction isolation levels we let
 
7339
                                each consistent read set its own snapshot */
 
7340
 
 
7341
                                read_view_close_for_mysql(trx);
 
7342
                        }
 
7343
                }
 
7344
        }
 
7345
 
 
7346
        return(0);
 
7347
}
 
7348
 
 
7349
/************************************************************************//**
 
7350
Here we export InnoDB status variables to MySQL. */
 
7351
static
 
7352
void
 
7353
innodb_export_status(void)
 
7354
/*======================*/
 
7355
{
 
7356
        if (innodb_inited) {
 
7357
                srv_export_innodb_status();
 
7358
        }
8080
7359
}
8081
7360
 
8082
7361
/************************************************************************//**
8086
7365
bool
8087
7366
innodb_show_status(
8088
7367
/*===============*/
8089
 
  plugin::StorageEngine*  engine, /*!< in: the innodb StorageEngine */
8090
 
  Session*  session,/*!< in: the MySQL query thread of the caller */
8091
 
  stat_print_fn *stat_print)
 
7368
        plugin::StorageEngine*  engine, /*!< in: the innodb StorageEngine */
 
7369
        Session*        session,/*!< in: the MySQL query thread of the caller */
 
7370
        stat_print_fn *stat_print)
8092
7371
{
8093
 
  trx_t*      trx;
8094
 
  static const char truncated_msg[] = "... truncated...\n";
8095
 
  const long    MAX_STATUS_SIZE = 1048576;
8096
 
  ulint     trx_list_start = ULINT_UNDEFINED;
8097
 
  ulint     trx_list_end = ULINT_UNDEFINED;
8098
 
 
8099
 
  assert(engine == innodb_engine_ptr);
8100
 
 
8101
 
  trx = check_trx_exists(session);
8102
 
 
8103
 
  innobase_release_stat_resources(trx);
8104
 
 
8105
 
  /* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
8106
 
  bytes of text. */
8107
 
 
8108
 
  long  flen, usable_len;
8109
 
  char* str;
8110
 
 
8111
 
  mutex_enter(&srv_monitor_file_mutex);
8112
 
  rewind(srv_monitor_file);
8113
 
  srv_printf_innodb_monitor(srv_monitor_file, FALSE,
8114
 
        &trx_list_start, &trx_list_end);
8115
 
  flen = ftell(srv_monitor_file);
8116
 
  os_file_set_eof(srv_monitor_file);
8117
 
 
8118
 
  if (flen < 0) {
8119
 
    flen = 0;
8120
 
  }
8121
 
 
8122
 
  if (flen > MAX_STATUS_SIZE) {
8123
 
    usable_len = MAX_STATUS_SIZE;
8124
 
    srv_truncated_status_writes++;
8125
 
  } else {
8126
 
    usable_len = flen;
8127
 
  }
8128
 
 
8129
 
  /* allocate buffer for the string, and
8130
 
  read the contents of the temporary file */
8131
 
 
8132
 
  if (!(str = (char*) malloc(usable_len + 1))) {
8133
 
    mutex_exit(&srv_monitor_file_mutex);
8134
 
    return(TRUE);
8135
 
  }
8136
 
 
8137
 
  rewind(srv_monitor_file);
8138
 
  if (flen < MAX_STATUS_SIZE) {
8139
 
    /* Display the entire output. */
8140
 
    flen = (long) fread(str, 1, flen, srv_monitor_file);
8141
 
  } else if (trx_list_end < (ulint) flen
8142
 
      && trx_list_start < trx_list_end
8143
 
      && trx_list_start + (flen - trx_list_end)
8144
 
      < MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
8145
 
    /* Omit the beginning of the list of active transactions. */
8146
 
    long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
8147
 
    memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
8148
 
    len += sizeof truncated_msg - 1;
8149
 
    usable_len = (MAX_STATUS_SIZE - 1) - len;
8150
 
    fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
8151
 
    len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
8152
 
    flen = len;
8153
 
  } else {
8154
 
    /* Omit the end of the output. */
8155
 
    flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
8156
 
  }
8157
 
 
8158
 
  mutex_exit(&srv_monitor_file_mutex);
8159
 
 
8160
 
  stat_print(session, innobase_engine_name, strlen(innobase_engine_name),
8161
 
             STRING_WITH_LEN(""), str, flen);
8162
 
 
8163
 
  free(str);
8164
 
 
8165
 
  return(FALSE);
 
7372
        trx_t*                  trx;
 
7373
        static const char       truncated_msg[] = "... truncated...\n";
 
7374
        const long              MAX_STATUS_SIZE = 64000;
 
7375
        ulint                   trx_list_start = ULINT_UNDEFINED;
 
7376
        ulint                   trx_list_end = ULINT_UNDEFINED;
 
7377
 
 
7378
        assert(engine == innodb_engine_ptr);
 
7379
 
 
7380
        trx = check_trx_exists(session);
 
7381
 
 
7382
        innobase_release_stat_resources(trx);
 
7383
 
 
7384
        /* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
 
7385
        bytes of text. */
 
7386
 
 
7387
        long    flen, usable_len;
 
7388
        char*   str;
 
7389
 
 
7390
        mutex_enter(&srv_monitor_file_mutex);
 
7391
        rewind(srv_monitor_file);
 
7392
        srv_printf_innodb_monitor(srv_monitor_file,
 
7393
                                &trx_list_start, &trx_list_end);
 
7394
        flen = ftell(srv_monitor_file);
 
7395
        os_file_set_eof(srv_monitor_file);
 
7396
 
 
7397
        if (flen < 0) {
 
7398
                flen = 0;
 
7399
        }
 
7400
 
 
7401
        if (flen > MAX_STATUS_SIZE) {
 
7402
                usable_len = MAX_STATUS_SIZE;
 
7403
        } else {
 
7404
                usable_len = flen;
 
7405
        }
 
7406
 
 
7407
        /* allocate buffer for the string, and
 
7408
        read the contents of the temporary file */
 
7409
 
 
7410
        if (!(str = (char*) malloc(usable_len + 1))) {
 
7411
          mutex_exit(&srv_monitor_file_mutex);
 
7412
          return(TRUE);
 
7413
        }
 
7414
 
 
7415
        rewind(srv_monitor_file);
 
7416
        if (flen < MAX_STATUS_SIZE) {
 
7417
                /* Display the entire output. */
 
7418
                flen = (long) fread(str, 1, flen, srv_monitor_file);
 
7419
        } else if (trx_list_end < (ulint) flen
 
7420
                        && trx_list_start < trx_list_end
 
7421
                        && trx_list_start + (flen - trx_list_end)
 
7422
                        < MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
 
7423
                /* Omit the beginning of the list of active transactions. */
 
7424
                long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
 
7425
                memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
 
7426
                len += sizeof truncated_msg - 1;
 
7427
                usable_len = (MAX_STATUS_SIZE - 1) - len;
 
7428
                fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
 
7429
                len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
 
7430
                flen = len;
 
7431
        } else {
 
7432
                /* Omit the end of the output. */
 
7433
                flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
 
7434
        }
 
7435
 
 
7436
        mutex_exit(&srv_monitor_file_mutex);
 
7437
 
 
7438
        bool result = FALSE;
 
7439
 
 
7440
        if (stat_print(session, innobase_engine_name, strlen(innobase_engine_name),
 
7441
                        STRING_WITH_LEN(""), str, flen)) {
 
7442
                result= TRUE;
 
7443
        }
 
7444
        free(str);
 
7445
 
 
7446
        return(FALSE);
8166
7447
}
8167
7448
 
8168
7449
/************************************************************************//**
8169
 
Implements the SHOW MUTEX STATUS command.
8170
 
@return true on failure false on success*/
 
7450
Implements the SHOW MUTEX STATUS command. . */
8171
7451
static
8172
7452
bool
8173
7453
innodb_mutex_show_status(
8174
7454
/*=====================*/
8175
 
  plugin::StorageEngine*  engine,   /*!< in: the innodb StorageEngine */
8176
 
  Session*  session,  /*!< in: the MySQL query thread of the
8177
 
          caller */
8178
 
  stat_print_fn*  stat_print)   /*!< in: function for printing
8179
 
                                        statistics */
 
7455
        plugin::StorageEngine*  engine,         /*!< in: the innodb StorageEngine */
 
7456
        Session*        session,        /*!< in: the MySQL query thread of the
 
7457
                                        caller */
 
7458
        stat_print_fn*  stat_print)
8180
7459
{
8181
 
  char buf1[IO_SIZE], buf2[IO_SIZE];
8182
 
  mutex_t*  mutex;
8183
 
  rw_lock_t*  lock;
8184
 
  ulint         block_mutex_oswait_count = 0;
8185
 
  ulint         block_lock_oswait_count = 0;
8186
 
  mutex_t*      block_mutex = NULL;
8187
 
  rw_lock_t*    block_lock = NULL;
 
7460
        char buf1[IO_SIZE], buf2[IO_SIZE];
 
7461
        mutex_t*        mutex;
 
7462
        rw_lock_t*      lock;
8188
7463
#ifdef UNIV_DEBUG
8189
 
  ulint   rw_lock_count= 0;
8190
 
  ulint   rw_lock_count_spin_loop= 0;
8191
 
  ulint   rw_lock_count_spin_rounds= 0;
8192
 
  ulint   rw_lock_count_os_wait= 0;
8193
 
  ulint   rw_lock_count_os_yield= 0;
8194
 
  uint64_t rw_lock_wait_time= 0;
 
7464
        ulint     rw_lock_count= 0;
 
7465
        ulint     rw_lock_count_spin_loop= 0;
 
7466
        ulint     rw_lock_count_spin_rounds= 0;
 
7467
        ulint     rw_lock_count_os_wait= 0;
 
7468
        ulint     rw_lock_count_os_yield= 0;
 
7469
        uint64_t rw_lock_wait_time= 0;
8195
7470
#endif /* UNIV_DEBUG */
8196
 
  uint    engine_name_len= strlen(innobase_engine_name), buf1len, buf2len;
8197
 
  assert(engine == innodb_engine_ptr);
8198
 
 
8199
 
  mutex_enter(&mutex_list_mutex);
8200
 
 
8201
 
  for (mutex = UT_LIST_GET_FIRST(mutex_list); mutex != NULL;
8202
 
       mutex = UT_LIST_GET_NEXT(list, mutex)) {
8203
 
    if (mutex->count_os_wait == 0) {
8204
 
      continue;
8205
 
    }
8206
 
 
8207
 
 
8208
 
    if (buf_pool_is_block_mutex(mutex)) {
8209
 
      block_mutex = mutex;
8210
 
      block_mutex_oswait_count += mutex->count_os_wait;
8211
 
      continue;
8212
 
    }
 
7471
        uint      engine_name_len= strlen(innobase_engine_name), buf1len, buf2len;
 
7472
        assert(engine == innodb_engine_ptr);
 
7473
 
 
7474
        mutex_enter(&mutex_list_mutex);
 
7475
 
 
7476
        mutex = UT_LIST_GET_FIRST(mutex_list);
 
7477
 
 
7478
        while (mutex != NULL) {
 
7479
                if (mutex->count_os_wait == 0
 
7480
                    || buf_pool_is_block_mutex(mutex)) {
 
7481
                        goto next_mutex;
 
7482
                }
8213
7483
#ifdef UNIV_DEBUG
8214
 
    if (mutex->mutex_type != 1) {
8215
 
      if (mutex->count_using > 0) {
8216
 
        buf1len= my_snprintf(buf1, sizeof(buf1),
8217
 
          "%s:%s",
8218
 
          mutex->cmutex_name, mutex->cfile_name);
8219
 
        buf2len= my_snprintf(buf2, sizeof(buf2),
8220
 
          "count=%lu, spin_waits=%lu,"
8221
 
          " spin_rounds=%lu, "
8222
 
          "os_waits=%lu, os_yields=%lu,"
8223
 
          " os_wait_times=%lu",
8224
 
          mutex->count_using,
8225
 
          mutex->count_spin_loop,
8226
 
          mutex->count_spin_rounds,
8227
 
          mutex->count_os_wait,
8228
 
          mutex->count_os_yield,
8229
 
          (ulong) (mutex->lspent_time/1000));
 
7484
                if (mutex->mutex_type != 1) {
 
7485
                        if (mutex->count_using > 0) {
 
7486
                                buf1len= my_snprintf(buf1, sizeof(buf1),
 
7487
                                        "%s:%s",
 
7488
                                        mutex->cmutex_name, mutex->cfile_name);
 
7489
                                buf2len= my_snprintf(buf2, sizeof(buf2),
 
7490
                                        "count=%lu, spin_waits=%lu,"
 
7491
                                        " spin_rounds=%lu, "
 
7492
                                        "os_waits=%lu, os_yields=%lu,"
 
7493
                                        " os_wait_times=%lu",
 
7494
                                        mutex->count_using,
 
7495
                                        mutex->count_spin_loop,
 
7496
                                        mutex->count_spin_rounds,
 
7497
                                        mutex->count_os_wait,
 
7498
                                        mutex->count_os_yield,
 
7499
                                        (ulong) (mutex->lspent_time/1000));
8230
7500
 
8231
 
        if (stat_print(session, innobase_engine_name,
8232
 
            engine_name_len, buf1, buf1len,
8233
 
            buf2, buf2len)) {
8234
 
          mutex_exit(&mutex_list_mutex);
8235
 
          return(1);
8236
 
        }
8237
 
      }
8238
 
    } else {
8239
 
      rw_lock_count += mutex->count_using;
8240
 
      rw_lock_count_spin_loop += mutex->count_spin_loop;
8241
 
      rw_lock_count_spin_rounds += mutex->count_spin_rounds;
8242
 
      rw_lock_count_os_wait += mutex->count_os_wait;
8243
 
      rw_lock_count_os_yield += mutex->count_os_yield;
8244
 
      rw_lock_wait_time += mutex->lspent_time;
8245
 
    }
 
7501
                                if (stat_print(session, innobase_engine_name,
 
7502
                                                engine_name_len, buf1, buf1len,
 
7503
                                                buf2, buf2len)) {
 
7504
                                        mutex_exit(&mutex_list_mutex);
 
7505
                                        return(1);
 
7506
                                }
 
7507
                        }
 
7508
                }
 
7509
                else {
 
7510
                        rw_lock_count += mutex->count_using;
 
7511
                        rw_lock_count_spin_loop += mutex->count_spin_loop;
 
7512
                        rw_lock_count_spin_rounds += mutex->count_spin_rounds;
 
7513
                        rw_lock_count_os_wait += mutex->count_os_wait;
 
7514
                        rw_lock_count_os_yield += mutex->count_os_yield;
 
7515
                        rw_lock_wait_time += mutex->lspent_time;
 
7516
                }
8246
7517
#else /* UNIV_DEBUG */
8247
 
    buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
8248
 
          mutex->cfile_name, (ulong) mutex->cline);
8249
 
    buf2len= snprintf(buf2, sizeof(buf2), "os_waits=%lu",
8250
 
                      (ulong) mutex->count_os_wait);
 
7518
                buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
 
7519
                                  mutex->cfile_name, (ulong) mutex->cline);
 
7520
                buf2len= snprintf(buf2, sizeof(buf2), "os_waits=%lu",
 
7521
                                  mutex->count_os_wait);
8251
7522
 
8252
 
    if (stat_print(session, innobase_engine_name,
8253
 
             engine_name_len, buf1, buf1len,
8254
 
             buf2, buf2len)) {
8255
 
      mutex_exit(&mutex_list_mutex);
8256
 
      return(1);
8257
 
    }
 
7523
                if (stat_print(session, innobase_engine_name,
 
7524
                               engine_name_len, buf1, buf1len,
 
7525
                               buf2, buf2len)) {
 
7526
                        mutex_exit(&mutex_list_mutex);
 
7527
                        return(1);
 
7528
                }
8258
7529
#endif /* UNIV_DEBUG */
8259
 
  }
8260
 
 
8261
 
  if (block_mutex) {
8262
 
    buf1len = snprintf(buf1, sizeof buf1,
8263
 
                       "combined %s:%lu",
8264
 
                       block_mutex->cfile_name,
8265
 
                       (ulong) block_mutex->cline);
8266
 
    buf2len = snprintf(buf2, sizeof buf2,
8267
 
                       "os_waits=%lu",
8268
 
                       (ulong) block_mutex_oswait_count);
8269
 
 
8270
 
    if (stat_print(session, innobase_engine_name,
8271
 
                   strlen(innobase_engine_name), buf1, buf1len,
8272
 
                   buf2, buf2len)) {
8273
 
      mutex_exit(&mutex_list_mutex);
8274
 
      return(1);
8275
 
    }
8276
 
  }
8277
 
 
8278
 
  mutex_exit(&mutex_list_mutex);
8279
 
 
8280
 
  mutex_enter(&rw_lock_list_mutex);
8281
 
 
8282
 
  for (lock = UT_LIST_GET_FIRST(rw_lock_list); lock != NULL;
8283
 
       lock = UT_LIST_GET_NEXT(list, lock)) {
8284
 
    if (lock->count_os_wait == 0) {
8285
 
      continue;
8286
 
    }
8287
 
 
8288
 
    if (buf_pool_is_block_lock(lock)) {
8289
 
      block_lock = lock;
8290
 
      block_lock_oswait_count += lock->count_os_wait;
8291
 
      continue;
8292
 
    }
8293
 
 
8294
 
    buf1len = snprintf(buf1, sizeof buf1, "%s:%lu",
8295
 
                       lock->cfile_name, (ulong) lock->cline);
8296
 
    buf2len = snprintf(buf2, sizeof buf2, "os_waits=%lu",
8297
 
                       (ulong) lock->count_os_wait);
8298
 
 
8299
 
    if (stat_print(session, innobase_engine_name,
8300
 
                   strlen(innobase_engine_name), buf1, buf1len,
8301
 
                   buf2, buf2len)) {
8302
 
      mutex_exit(&rw_lock_list_mutex);
8303
 
      return(1);
8304
 
    }
8305
 
  }
8306
 
 
8307
 
  if (block_lock) {
8308
 
    buf1len = snprintf(buf1, sizeof buf1,
8309
 
                       "combined %s:%lu",
8310
 
                       block_lock->cfile_name,
8311
 
                       (ulong) block_lock->cline);
8312
 
    buf2len = snprintf(buf2, sizeof buf2,
8313
 
                       "os_waits=%lu",
8314
 
                       (ulong) block_lock_oswait_count);
8315
 
 
8316
 
    if (stat_print(session, innobase_engine_name,
8317
 
                   strlen(innobase_engine_name), buf1, buf1len,
8318
 
                   buf2, buf2len)) {
8319
 
      mutex_exit(&rw_lock_list_mutex);
8320
 
      return(1);
8321
 
    }
8322
 
  }
8323
 
 
8324
 
  mutex_exit(&rw_lock_list_mutex);
 
7530
 
 
7531
next_mutex:
 
7532
                mutex = UT_LIST_GET_NEXT(list, mutex);
 
7533
        }
 
7534
 
 
7535
        mutex_exit(&mutex_list_mutex);
 
7536
 
 
7537
        mutex_enter(&rw_lock_list_mutex);
 
7538
 
 
7539
        lock = UT_LIST_GET_FIRST(rw_lock_list);
 
7540
 
 
7541
        while (lock != NULL) {
 
7542
                if (lock->count_os_wait
 
7543
                    && !buf_pool_is_block_lock(lock)) {
 
7544
                        buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
 
7545
                                    lock->cfile_name, (unsigned long) lock->cline);
 
7546
                        buf2len= snprintf(buf2, sizeof(buf2),
 
7547
                                    "os_waits=%lu", lock->count_os_wait);
 
7548
 
 
7549
                        if (stat_print(session, innobase_engine_name,
 
7550
                                       engine_name_len, buf1, buf1len,
 
7551
                                       buf2, buf2len)) {
 
7552
                                mutex_exit(&rw_lock_list_mutex);
 
7553
                                return(1);
 
7554
                        }
 
7555
                }
 
7556
                lock = UT_LIST_GET_NEXT(list, lock);
 
7557
        }
 
7558
 
 
7559
        mutex_exit(&rw_lock_list_mutex);
8325
7560
 
8326
7561
#ifdef UNIV_DEBUG
8327
 
  buf2len = snprintf(buf2, sizeof buf2,
8328
 
                     "count=%lu, spin_waits=%lu, spin_rounds=%lu, "
8329
 
                     "os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
8330
 
                     (ulong) rw_lock_count,
8331
 
                     (ulong) rw_lock_count_spin_loop,
8332
 
                     (ulong) rw_lock_count_spin_rounds,
8333
 
                     (ulong) rw_lock_count_os_wait,
8334
 
                     (ulong) rw_lock_count_os_yield,
8335
 
                     (ulong) (rw_lock_wait_time / 1000));
 
7562
        buf2len= my_snprintf(buf2, sizeof(buf2),
 
7563
                "count=%lu, spin_waits=%lu, spin_rounds=%lu, "
 
7564
                "os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
 
7565
                rw_lock_count, rw_lock_count_spin_loop,
 
7566
                rw_lock_count_spin_rounds,
 
7567
                rw_lock_count_os_wait, rw_lock_count_os_yield,
 
7568
                (ulong) (rw_lock_wait_time/1000));
8336
7569
 
8337
 
  if (stat_print(session, innobase_engine_name, engine_name_len,
8338
 
      STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
8339
 
    return(1);
8340
 
  }
 
7570
        if (stat_print(session, innobase_engine_name, engine_name_len,
 
7571
                        STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
 
7572
                return(1);
 
7573
        }
8341
7574
#endif /* UNIV_DEBUG */
8342
7575
 
8343
 
  return(FALSE);
 
7576
        return(FALSE);
8344
7577
}
8345
7578
 
8346
7579
bool InnobaseEngine::show_status(Session* session, 
8347
7580
                                 stat_print_fn* stat_print,
8348
7581
                                 enum ha_stat_type stat_type)
8349
7582
{
8350
 
  assert(this == innodb_engine_ptr);
 
7583
        assert(this == innodb_engine_ptr);
8351
7584
 
8352
 
  switch (stat_type) {
8353
 
  case HA_ENGINE_STATUS:
8354
 
    return innodb_show_status(this, session, stat_print);
8355
 
  case HA_ENGINE_MUTEX:
8356
 
    return innodb_mutex_show_status(this, session, stat_print);
8357
 
  default:
8358
 
    return(FALSE);
8359
 
  }
 
7585
        switch (stat_type) {
 
7586
        case HA_ENGINE_STATUS:
 
7587
                return innodb_show_status(this, session, stat_print);
 
7588
        case HA_ENGINE_MUTEX:
 
7589
                return innodb_mutex_show_status(this, session, stat_print);
 
7590
        default:
 
7591
                return(FALSE);
 
7592
        }
8360
7593
}
8361
7594
 
8362
7595
/************************************************************************//**
8366
7599
 
8367
7600
static INNOBASE_SHARE* get_share(const char* table_name)
8368
7601
{
8369
 
  INNOBASE_SHARE *share;
8370
 
  pthread_mutex_lock(&innobase_share_mutex);
8371
 
 
8372
 
  ulint fold = ut_fold_string(table_name);
8373
 
 
8374
 
  HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
8375
 
        INNOBASE_SHARE*, share,
8376
 
        ut_ad(share->use_count > 0),
8377
 
        !strcmp(share->table_name, table_name));
8378
 
 
8379
 
  if (!share) {
8380
 
    /* TODO: invoke HASH_MIGRATE if innobase_open_tables
8381
 
    grows too big */
8382
 
 
8383
 
    share= new INNOBASE_SHARE(table_name);
8384
 
 
8385
 
    HASH_INSERT(INNOBASE_SHARE, table_name_hash,
8386
 
          innobase_open_tables, fold, share);
8387
 
 
8388
 
    thr_lock_init(&share->lock);
8389
 
 
8390
 
    /* Index translation table initialization */
8391
 
    share->idx_trans_tbl.index_mapping = NULL;
8392
 
    share->idx_trans_tbl.index_count = 0;
8393
 
    share->idx_trans_tbl.array_size = 0;
8394
 
  }
8395
 
 
8396
 
  share->use_count++;
8397
 
  pthread_mutex_unlock(&innobase_share_mutex);
8398
 
 
8399
 
  return(share);
 
7602
        INNOBASE_SHARE *share;
 
7603
        pthread_mutex_lock(&innobase_share_mutex);
 
7604
 
 
7605
        ulint   fold = ut_fold_string(table_name);
 
7606
 
 
7607
        HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
 
7608
                    INNOBASE_SHARE*, share,
 
7609
                    ut_ad(share->use_count > 0),
 
7610
                    !strcmp(share->table_name, table_name));
 
7611
 
 
7612
        if (!share) {
 
7613
 
 
7614
                uint length = (uint) strlen(table_name);
 
7615
 
 
7616
                /* TODO: invoke HASH_MIGRATE if innobase_open_tables
 
7617
                grows too big */
 
7618
 
 
7619
                share = (INNOBASE_SHARE *) malloc(sizeof(*share)+length+1);
 
7620
                memset(share, 0, sizeof(*share)+length+1);
 
7621
 
 
7622
                share->table_name = (char*) memcpy(share + 1,
 
7623
                                                   table_name, length + 1);
 
7624
 
 
7625
                HASH_INSERT(INNOBASE_SHARE, table_name_hash,
 
7626
                            innobase_open_tables, fold, share);
 
7627
 
 
7628
                thr_lock_init(&share->lock);
 
7629
        }
 
7630
 
 
7631
        share->use_count++;
 
7632
        pthread_mutex_unlock(&innobase_share_mutex);
 
7633
 
 
7634
        return(share);
8400
7635
}
8401
7636
 
8402
7637
static void free_share(INNOBASE_SHARE* share)
8403
7638
{
8404
 
  pthread_mutex_lock(&innobase_share_mutex);
 
7639
        pthread_mutex_lock(&innobase_share_mutex);
8405
7640
 
8406
7641
#ifdef UNIV_DEBUG
8407
 
  INNOBASE_SHARE* share2;
8408
 
  ulint fold = ut_fold_string(share->table_name);
8409
 
 
8410
 
  HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
8411
 
        INNOBASE_SHARE*, share2,
8412
 
        ut_ad(share->use_count > 0),
8413
 
        !strcmp(share->table_name, share2->table_name));
8414
 
 
8415
 
  ut_a(share2 == share);
 
7642
        INNOBASE_SHARE* share2;
 
7643
        ulint   fold = ut_fold_string(share->table_name);
 
7644
 
 
7645
        HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
 
7646
                    INNOBASE_SHARE*, share2,
 
7647
                    ut_ad(share->use_count > 0),
 
7648
                    !strcmp(share->table_name, share2->table_name));
 
7649
 
 
7650
        ut_a(share2 == share);
8416
7651
#endif /* UNIV_DEBUG */
8417
7652
 
8418
 
  if (!--share->use_count) {
8419
 
    ulint fold = ut_fold_string(share->table_name);
8420
 
 
8421
 
    HASH_DELETE(INNOBASE_SHARE, table_name_hash,
8422
 
          innobase_open_tables, fold, share);
8423
 
    share->lock.deinit();
8424
 
 
8425
 
    /* Free any memory from index translation table */
8426
 
    free(share->idx_trans_tbl.index_mapping);
8427
 
 
8428
 
    delete share;
8429
 
 
8430
 
    /* TODO: invoke HASH_MIGRATE if innobase_open_tables
8431
 
    shrinks too much */
8432
 
  }
8433
 
 
8434
 
  pthread_mutex_unlock(&innobase_share_mutex);
 
7653
        if (!--share->use_count) {
 
7654
                ulint   fold = ut_fold_string(share->table_name);
 
7655
 
 
7656
                HASH_DELETE(INNOBASE_SHARE, table_name_hash,
 
7657
                            innobase_open_tables, fold, share);
 
7658
                thr_lock_delete(&share->lock);
 
7659
                free(share);
 
7660
 
 
7661
                /* TODO: invoke HASH_MIGRATE if innobase_open_tables
 
7662
                shrinks too much */
 
7663
        }
 
7664
 
 
7665
        pthread_mutex_unlock(&innobase_share_mutex);
8435
7666
}
8436
7667
 
8437
7668
/*****************************************************************//**
8442
7673
SELECT the read lock is released early on the 'const' tables where we only
8443
7674
fetch one row. MySQL does not call this when it releases all locks at the
8444
7675
end of an SQL statement.
8445
 
@return pointer to the next element in the 'to' array */
 
7676
@return pointer to the next element in the 'to' array */
8446
7677
UNIV_INTERN
8447
7678
THR_LOCK_DATA**
8448
7679
ha_innobase::store_lock(
8449
7680
/*====================*/
8450
 
  Session*    session,  /*!< in: user thread handle */
8451
 
  THR_LOCK_DATA**   to,   /*!< in: pointer to an array
8452
 
            of pointers to lock structs;
8453
 
            pointer to the 'lock' field
8454
 
            of current handle is stored
8455
 
            next to this array */
8456
 
  enum thr_lock_type  lock_type)  /*!< in: lock type to store in
8457
 
            'lock'; this may also be
8458
 
            TL_IGNORE */
 
7681
        Session*                session,        /*!< in: user thread handle */
 
7682
        THR_LOCK_DATA**         to,             /*!< in: pointer to an array
 
7683
                                                of pointers to lock structs;
 
7684
                                                pointer to the 'lock' field
 
7685
                                                of current handle is stored
 
7686
                                                next to this array */
 
7687
        enum thr_lock_type      lock_type)      /*!< in: lock type to store in
 
7688
                                                'lock'; this may also be
 
7689
                                                TL_IGNORE */
8459
7690
{
8460
 
  trx_t*    trx;
8461
 
 
8462
 
  /* Note that trx in this function is NOT necessarily prebuilt->trx
8463
 
  because we call update_session() later, in ::external_lock()! Failure to
8464
 
  understand this caused a serious memory corruption bug in 5.1.11. */
8465
 
 
8466
 
  trx = check_trx_exists(session);
8467
 
 
8468
 
  assert(EQ_CURRENT_SESSION(session));
8469
 
  const uint32_t sql_command = session_sql_command(session);
8470
 
 
8471
 
  if (sql_command == SQLCOM_DROP_TABLE) {
8472
 
 
8473
 
    /* MySQL calls this function in DROP Table though this table
8474
 
    handle may belong to another session that is running a query.
8475
 
    Let us in that case skip any changes to the prebuilt struct. */ 
8476
 
 
8477
 
  } else if (lock_type == TL_READ_WITH_SHARED_LOCKS
8478
 
       || lock_type == TL_READ_NO_INSERT
8479
 
       || (lock_type != TL_IGNORE
8480
 
           && sql_command != SQLCOM_SELECT)) {
8481
 
 
8482
 
    /* The OR cases above are in this order:
8483
 
    1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
8484
 
    are processing a stored procedure or function, or
8485
 
    2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
8486
 
    3) this is a SELECT ... IN SHARE MODE, or
8487
 
    4) we are doing a complex SQL statement like
8488
 
    INSERT INTO ... SELECT ... and the logical logging (MySQL
8489
 
    binlog) requires the use of a locking read, or
8490
 
    MySQL is doing LOCK TABLES ... READ.
8491
 
    5) we let InnoDB do locking reads for all SQL statements that
8492
 
    are not simple SELECTs; note that select_lock_type in this
8493
 
    case may get strengthened in ::external_lock() to LOCK_X.
8494
 
    Note that we MUST use a locking read in all data modifying
8495
 
    SQL statements, because otherwise the execution would not be
8496
 
    serializable, and also the results from the update could be
8497
 
    unexpected if an obsolete consistent read view would be
8498
 
    used. */
8499
 
 
8500
 
    ulint isolation_level;
8501
 
 
8502
 
    isolation_level = trx->isolation_level;
8503
 
 
8504
 
    if ((srv_locks_unsafe_for_binlog
8505
 
         || isolation_level <= TRX_ISO_READ_COMMITTED)
8506
 
        && isolation_level != TRX_ISO_SERIALIZABLE
8507
 
        && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
8508
 
        && (sql_command == SQLCOM_INSERT_SELECT
8509
 
            || sql_command == SQLCOM_REPLACE_SELECT
8510
 
            || sql_command == SQLCOM_UPDATE
8511
 
            || sql_command == SQLCOM_CREATE_TABLE
8512
 
            || sql_command == SQLCOM_SET_OPTION)) {
8513
 
 
8514
 
      /* If we either have innobase_locks_unsafe_for_binlog
8515
 
      option set or this session is using READ COMMITTED
8516
 
      isolation level and isolation level of the transaction
8517
 
      is not set to serializable and MySQL is doing
8518
 
      INSERT INTO...SELECT or REPLACE INTO...SELECT
8519
 
      or UPDATE ... = (SELECT ...) or CREATE  ...
8520
 
      SELECT... or SET ... = (SELECT ...) without
8521
 
      FOR UPDATE or IN SHARE MODE in select,
8522
 
      then we use consistent read for select. */
8523
 
 
8524
 
      prebuilt->select_lock_type = LOCK_NONE;
8525
 
      prebuilt->stored_select_lock_type = LOCK_NONE;
8526
 
    } else if (sql_command == SQLCOM_CHECKSUM) {
8527
 
      /* Use consistent read for checksum table */
8528
 
 
8529
 
      prebuilt->select_lock_type = LOCK_NONE;
8530
 
      prebuilt->stored_select_lock_type = LOCK_NONE;
8531
 
    } else {
8532
 
      prebuilt->select_lock_type = LOCK_S;
8533
 
      prebuilt->stored_select_lock_type = LOCK_S;
8534
 
    }
8535
 
 
8536
 
  } else if (lock_type != TL_IGNORE) {
8537
 
 
8538
 
    /* We set possible LOCK_X value in external_lock, not yet
8539
 
    here even if this would be SELECT ... FOR UPDATE */
8540
 
 
8541
 
    prebuilt->select_lock_type = LOCK_NONE;
8542
 
    prebuilt->stored_select_lock_type = LOCK_NONE;
8543
 
  }
8544
 
 
8545
 
  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
8546
 
 
8547
 
    /* If we are not doing a LOCK TABLE, DISCARD/IMPORT
8548
 
    TABLESPACE or TRUNCATE TABLE then allow multiple
8549
 
    writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
8550
 
    < TL_WRITE_CONCURRENT_INSERT.
8551
 
    */
8552
 
 
8553
 
    if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
8554
 
         && lock_type <= TL_WRITE)
8555
 
        && !session_tablespace_op(session)
8556
 
        && sql_command != SQLCOM_TRUNCATE
8557
 
        && sql_command != SQLCOM_CREATE_TABLE) {
8558
 
 
8559
 
      lock_type = TL_WRITE_ALLOW_WRITE;
8560
 
    }
8561
 
 
8562
 
    /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
8563
 
    MySQL would use the lock TL_READ_NO_INSERT on t2, and that
8564
 
    would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
8565
 
    to t2. Convert the lock to a normal read lock to allow
8566
 
    concurrent inserts to t2.
8567
 
    */
8568
 
 
8569
 
    if (lock_type == TL_READ_NO_INSERT) {
8570
 
 
8571
 
      lock_type = TL_READ;
8572
 
    }
8573
 
 
8574
 
    lock.type = lock_type;
8575
 
  }
8576
 
 
8577
 
  *to++= &lock;
8578
 
 
8579
 
  return(to);
 
7691
        trx_t*          trx;
 
7692
 
 
7693
        /* Note that trx in this function is NOT necessarily prebuilt->trx
 
7694
        because we call update_session() later, in ::external_lock()! Failure to
 
7695
        understand this caused a serious memory corruption bug in 5.1.11. */
 
7696
 
 
7697
        trx = check_trx_exists(session);
 
7698
 
 
7699
        /* NOTE: MySQL can call this function with lock 'type' TL_IGNORE!
 
7700
        Be careful to ignore TL_IGNORE if we are going to do something with
 
7701
        only 'real' locks! */
 
7702
 
 
7703
        /* If no MySQL table is in use, we need to set the isolation level
 
7704
        of the transaction. */
 
7705
 
 
7706
        if (lock_type != TL_IGNORE
 
7707
            && trx->n_mysql_tables_in_use == 0) {
 
7708
                trx->isolation_level = innobase_map_isolation_level(
 
7709
                        (enum_tx_isolation) session_tx_isolation(session));
 
7710
 
 
7711
                if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
 
7712
                    && trx->global_read_view) {
 
7713
 
 
7714
                        /* At low transaction isolation levels we let
 
7715
                        each consistent read set its own snapshot */
 
7716
 
 
7717
                        read_view_close_for_mysql(trx);
 
7718
                }
 
7719
        }
 
7720
 
 
7721
        assert(EQ_CURRENT_SESSION(session));
 
7722
        const uint32_t sql_command = session_sql_command(session);
 
7723
 
 
7724
        if (sql_command == SQLCOM_DROP_TABLE) {
 
7725
 
 
7726
                /* MySQL calls this function in DROP Table though this table
 
7727
                handle may belong to another session that is running a query.
 
7728
                Let us in that case skip any changes to the prebuilt struct. */ 
 
7729
 
 
7730
        } else if (lock_type == TL_READ_WITH_SHARED_LOCKS
 
7731
                   || lock_type == TL_READ_NO_INSERT
 
7732
                   || (lock_type != TL_IGNORE
 
7733
                       && sql_command != SQLCOM_SELECT)) {
 
7734
 
 
7735
                /* The OR cases above are in this order:
 
7736
                1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
 
7737
                are processing a stored procedure or function, or
 
7738
                2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
 
7739
                3) this is a SELECT ... IN SHARE MODE, or
 
7740
                4) we are doing a complex SQL statement like
 
7741
                INSERT INTO ... SELECT ... and the logical logging (MySQL
 
7742
                binlog) requires the use of a locking read, or
 
7743
                MySQL is doing LOCK TABLES ... READ.
 
7744
                5) we let InnoDB do locking reads for all SQL statements that
 
7745
                are not simple SELECTs; note that select_lock_type in this
 
7746
                case may get strengthened in ::external_lock() to LOCK_X.
 
7747
                Note that we MUST use a locking read in all data modifying
 
7748
                SQL statements, because otherwise the execution would not be
 
7749
                serializable, and also the results from the update could be
 
7750
                unexpected if an obsolete consistent read view would be
 
7751
                used. */
 
7752
 
 
7753
                ulint   isolation_level;
 
7754
 
 
7755
                isolation_level = trx->isolation_level;
 
7756
 
 
7757
                if ((srv_locks_unsafe_for_binlog
 
7758
                     || isolation_level == TRX_ISO_READ_COMMITTED)
 
7759
                    && isolation_level != TRX_ISO_SERIALIZABLE
 
7760
                    && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
 
7761
                    && (sql_command == SQLCOM_INSERT_SELECT
 
7762
                        || sql_command == SQLCOM_UPDATE
 
7763
                        || sql_command == SQLCOM_CREATE_TABLE)) {
 
7764
 
 
7765
                        /* If we either have innobase_locks_unsafe_for_binlog
 
7766
                        option set or this session is using READ COMMITTED
 
7767
                        isolation level and isolation level of the transaction
 
7768
                        is not set to serializable and MySQL is doing
 
7769
                        INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
 
7770
                        CREATE  ... SELECT... without FOR UPDATE or
 
7771
                        IN SHARE MODE in select, then we use consistent
 
7772
                        read for select. */
 
7773
 
 
7774
                        prebuilt->select_lock_type = LOCK_NONE;
 
7775
                        prebuilt->stored_select_lock_type = LOCK_NONE;
 
7776
                } else if (sql_command == SQLCOM_CHECKSUM) {
 
7777
                        /* Use consistent read for checksum table */
 
7778
 
 
7779
                        prebuilt->select_lock_type = LOCK_NONE;
 
7780
                        prebuilt->stored_select_lock_type = LOCK_NONE;
 
7781
                } else {
 
7782
                        prebuilt->select_lock_type = LOCK_S;
 
7783
                        prebuilt->stored_select_lock_type = LOCK_S;
 
7784
                }
 
7785
 
 
7786
        } else if (lock_type != TL_IGNORE) {
 
7787
 
 
7788
                /* We set possible LOCK_X value in external_lock, not yet
 
7789
                here even if this would be SELECT ... FOR UPDATE */
 
7790
 
 
7791
                prebuilt->select_lock_type = LOCK_NONE;
 
7792
                prebuilt->stored_select_lock_type = LOCK_NONE;
 
7793
        }
 
7794
 
 
7795
        if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
 
7796
 
 
7797
                /* If we are not doing a LOCK TABLE, DISCARD/IMPORT
 
7798
                TABLESPACE or TRUNCATE TABLE then allow multiple
 
7799
                writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
 
7800
                < TL_WRITE_CONCURRENT_INSERT.
 
7801
 
 
7802
                We especially allow multiple writers if MySQL is at the
 
7803
                start of a stored procedure call (SQLCOM_CALL) or a
 
7804
                stored function call (MySQL does have in_lock_tables
 
7805
                TRUE there). */
 
7806
 
 
7807
                if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
 
7808
                     && lock_type <= TL_WRITE)
 
7809
                    && !session_tablespace_op(session)
 
7810
                    && sql_command != SQLCOM_TRUNCATE
 
7811
                    && sql_command != SQLCOM_CREATE_TABLE) {
 
7812
 
 
7813
                        lock_type = TL_WRITE_ALLOW_WRITE;
 
7814
                }
 
7815
 
 
7816
                /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
 
7817
                MySQL would use the lock TL_READ_NO_INSERT on t2, and that
 
7818
                would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
 
7819
                to t2. Convert the lock to a normal read lock to allow
 
7820
                concurrent inserts to t2.
 
7821
 
 
7822
                We especially allow concurrent inserts if MySQL is at the
 
7823
                start of a stored procedure call (SQLCOM_CALL)
 
7824
                (MySQL does have session_in_lock_tables() TRUE there). */
 
7825
 
 
7826
                if (lock_type == TL_READ_NO_INSERT) {
 
7827
 
 
7828
                        lock_type = TL_READ;
 
7829
                }
 
7830
 
 
7831
                lock.type = lock_type;
 
7832
        }
 
7833
 
 
7834
        *to++= &lock;
 
7835
 
 
7836
        return(to);
8580
7837
}
8581
7838
 
8582
7839
/*********************************************************************//**
8583
7840
Read the next autoinc value. Acquire the relevant locks before reading
8584
7841
the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
8585
7842
on return and all relevant locks acquired.
8586
 
@return DB_SUCCESS or error code */
 
7843
@return DB_SUCCESS or error code */
8587
7844
UNIV_INTERN
8588
7845
ulint
8589
7846
ha_innobase::innobase_get_autoinc(
8590
7847
/*==============================*/
8591
 
  uint64_t* value)    /*!< out: autoinc value */
 
7848
        uint64_t*       value)          /*!< out: autoinc value */
8592
7849
{
8593
 
  *value = 0;
8594
 
 
8595
 
  dict_table_autoinc_lock(prebuilt->table);
8596
 
  prebuilt->autoinc_error= DB_SUCCESS;
8597
 
  /* Determine the first value of the interval */
8598
 
  *value = dict_table_autoinc_read(prebuilt->table);
8599
 
 
8600
 
  /* It should have been initialized during open. */
8601
 
  if (*value == 0) {
8602
 
    prebuilt->autoinc_error = DB_UNSUPPORTED;
8603
 
    dict_table_autoinc_unlock(prebuilt->table);
8604
 
  }
8605
 
 
8606
 
  return(DB_SUCCESS);
 
7850
        *value = 0;
 
7851
 
 
7852
        prebuilt->autoinc_error = innobase_lock_autoinc();
 
7853
 
 
7854
        if (prebuilt->autoinc_error == DB_SUCCESS) {
 
7855
 
 
7856
                /* Determine the first value of the interval */
 
7857
                *value = dict_table_autoinc_read(prebuilt->table);
 
7858
 
 
7859
                /* It should have been initialized during open. */
 
7860
                ut_a(*value != 0);
 
7861
        }
 
7862
 
 
7863
        return(prebuilt->autoinc_error);
8607
7864
}
8608
7865
 
8609
7866
/*******************************************************************//**
8610
 
This function reads the global auto-inc counter. It doesn't use the
 
7867
This function reads the global auto-inc counter. It doesn't use the 
8611
7868
AUTOINC lock even if the lock mode is set to TRADITIONAL.
8612
 
@return the autoinc value */
 
7869
@return the autoinc value */
8613
7870
UNIV_INTERN
8614
7871
uint64_t
8615
7872
ha_innobase::innobase_peek_autoinc(void)
8616
7873
/*====================================*/
8617
7874
{
8618
 
  uint64_t  auto_inc;
8619
 
  dict_table_t* innodb_table;
8620
 
 
8621
 
  ut_a(prebuilt != NULL);
8622
 
  ut_a(prebuilt->table != NULL);
8623
 
 
8624
 
  innodb_table = prebuilt->table;
8625
 
 
8626
 
  dict_table_autoinc_lock(innodb_table);
8627
 
 
8628
 
  auto_inc = dict_table_autoinc_read(innodb_table);
8629
 
 
8630
 
  if (auto_inc == 0) {
8631
 
    ut_print_timestamp(stderr);
8632
 
    fprintf(stderr, "  InnoDB: AUTOINC next value generation "
8633
 
            "is disabled for '%s'\n", innodb_table->name);
8634
 
  }
8635
 
 
8636
 
  dict_table_autoinc_unlock(innodb_table);
8637
 
 
8638
 
  return(auto_inc);
 
7875
        uint64_t        auto_inc;
 
7876
        dict_table_t*   innodb_table;
 
7877
 
 
7878
        ut_a(prebuilt != NULL);
 
7879
        ut_a(prebuilt->table != NULL);
 
7880
 
 
7881
        innodb_table = prebuilt->table;
 
7882
 
 
7883
        dict_table_autoinc_lock(innodb_table);
 
7884
 
 
7885
        auto_inc = dict_table_autoinc_read(innodb_table);
 
7886
 
 
7887
        ut_a(auto_inc > 0);
 
7888
 
 
7889
        dict_table_autoinc_unlock(innodb_table);
 
7890
 
 
7891
        return(auto_inc);
8639
7892
}
8640
7893
 
8641
7894
/*********************************************************************//**
8649
7902
void
8650
7903
ha_innobase::get_auto_increment(
8651
7904
/*============================*/
8652
 
        uint64_t  offset,              /*!< in: table autoinc offset */
8653
 
        uint64_t  increment,           /*!< in: table autoinc increment */
8654
 
        uint64_t  nb_desired_values,   /*!< in: number of values reqd */
8655
 
        uint64_t  *first_value,        /*!< out: the autoinc value */
8656
 
        uint64_t  *nb_reserved_values) /*!< out: count of reserved values */
 
7905
        uint64_t        offset,              /*!< in: table autoinc offset */
 
7906
        uint64_t        increment,           /*!< in: table autoinc increment */
 
7907
        uint64_t        nb_desired_values,   /*!< in: number of values reqd */
 
7908
        uint64_t        *first_value,        /*!< out: the autoinc value */
 
7909
        uint64_t        *nb_reserved_values) /*!< out: count of reserved values */
8657
7910
{
8658
 
  trx_t*    trx;
8659
 
  ulint   error;
8660
 
  uint64_t  autoinc = 0;
8661
 
 
8662
 
  /* Prepare prebuilt->trx in the table handle */
8663
 
  update_session(getTable()->in_use);
8664
 
 
8665
 
  error = innobase_get_autoinc(&autoinc);
8666
 
 
8667
 
  if (error != DB_SUCCESS) {
8668
 
    *first_value = (~(uint64_t) 0);
8669
 
    return;
8670
 
  }
8671
 
 
8672
 
  /* This is a hack, since nb_desired_values seems to be accurate only
8673
 
  for the first call to get_auto_increment() for multi-row INSERT and
8674
 
  meaningless for other statements e.g, LOAD etc. Subsequent calls to
8675
 
  this method for the same statement results in different values which
8676
 
  don't make sense. Therefore we store the value the first time we are
8677
 
  called and count down from that as rows are written (see doInsertRecord()).
8678
 
  */
8679
 
 
8680
 
  trx = prebuilt->trx;
8681
 
 
8682
 
  /* Note: We can't rely on *first_value since some MySQL engines,
8683
 
  in particular the partition engine, don't initialize it to 0 when
8684
 
  invoking this method. So we are not sure if it's guaranteed to
8685
 
  be 0 or not. */
8686
 
 
8687
 
  /* We need the upper limit of the col type to check for
8688
 
     whether we update the table autoinc counter or not. */
8689
 
  uint64_t col_max_value = innobase_get_int_col_max_value(getTable()->next_number_field);
8690
 
 
8691
 
  /* Called for the first time ? */
8692
 
  if (trx->n_autoinc_rows == 0) {
8693
 
 
8694
 
    trx->n_autoinc_rows = (ulint) nb_desired_values;
8695
 
 
8696
 
    /* It's possible for nb_desired_values to be 0:
8697
 
    e.g., INSERT INTO T1(C) SELECT C FROM T2; */
8698
 
    if (nb_desired_values == 0) {
8699
 
 
8700
 
      trx->n_autoinc_rows = 1;
8701
 
    }
8702
 
 
8703
 
    set_if_bigger(*first_value, autoinc);
8704
 
  /* Not in the middle of a mult-row INSERT. */
8705
 
  } else if (prebuilt->autoinc_last_value == 0) {
8706
 
    set_if_bigger(*first_value, autoinc);
8707
 
    /* Check for -ve values. */
8708
 
  } else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) {
8709
 
    /* Set to next logical value. */
8710
 
    ut_a(autoinc > trx->n_autoinc_rows);
8711
 
    *first_value = (autoinc - trx->n_autoinc_rows) - 1;
8712
 
  }
8713
 
 
8714
 
  *nb_reserved_values = trx->n_autoinc_rows;
8715
 
 
8716
 
  /* This all current style autoinc. */
8717
 
  {
8718
 
    uint64_t  need;
8719
 
    uint64_t  current;
8720
 
    uint64_t  next_value;
8721
 
 
8722
 
    current = *first_value > col_max_value ? autoinc : *first_value;
8723
 
    need = *nb_reserved_values * increment;
8724
 
 
8725
 
    /* Compute the last value in the interval */
8726
 
    next_value = innobase_next_autoinc(current, need, offset, col_max_value);
8727
 
 
8728
 
    prebuilt->autoinc_last_value = next_value;
8729
 
 
8730
 
    if (prebuilt->autoinc_last_value < *first_value) {
8731
 
      *first_value = (~(unsigned long long) 0);
8732
 
    } else {
8733
 
      /* Update the table autoinc variable */
8734
 
      dict_table_autoinc_update_if_greater(
8735
 
        prebuilt->table, prebuilt->autoinc_last_value);
8736
 
    }
8737
 
  }
8738
 
 
8739
 
  /* The increment to be used to increase the AUTOINC value, we use
8740
 
  this in doInsertRecord() and doUpdateRecord() to increase the autoinc counter
8741
 
  for columns that are filled by the user. We need the offset and
8742
 
  the increment. */
8743
 
  prebuilt->autoinc_offset = offset;
8744
 
  prebuilt->autoinc_increment = increment;
8745
 
 
8746
 
  dict_table_autoinc_unlock(prebuilt->table);
 
7911
        trx_t*          trx;
 
7912
        ulint           error;
 
7913
        uint64_t        autoinc = 0;
 
7914
 
 
7915
        /* Prepare prebuilt->trx in the table handle */
 
7916
        update_session(ha_session());
 
7917
 
 
7918
        error = innobase_get_autoinc(&autoinc);
 
7919
 
 
7920
        if (error != DB_SUCCESS) {
 
7921
                *first_value = (~(uint64_t) 0);
 
7922
                return;
 
7923
        }
 
7924
 
 
7925
        /* This is a hack, since nb_desired_values seems to be accurate only
 
7926
        for the first call to get_auto_increment() for multi-row INSERT and
 
7927
        meaningless for other statements e.g, LOAD etc. Subsequent calls to
 
7928
        this method for the same statement results in different values which
 
7929
        don't make sense. Therefore we store the value the first time we are
 
7930
        called and count down from that as rows are written (see write_row()).
 
7931
        */
 
7932
 
 
7933
        trx = prebuilt->trx;
 
7934
 
 
7935
        /* Note: We can't rely on *first_value since some MySQL engines,
 
7936
        in particular the partition engine, don't initialize it to 0 when
 
7937
        invoking this method. So we are not sure if it's guaranteed to
 
7938
        be 0 or not. */
 
7939
 
 
7940
        /* Called for the first time ? */
 
7941
        if (trx->n_autoinc_rows == 0) {
 
7942
 
 
7943
                trx->n_autoinc_rows = (ulint) nb_desired_values;
 
7944
 
 
7945
                /* It's possible for nb_desired_values to be 0:
 
7946
                e.g., INSERT INTO T1(C) SELECT C FROM T2; */
 
7947
                if (nb_desired_values == 0) {
 
7948
 
 
7949
                        trx->n_autoinc_rows = 1;
 
7950
                }
 
7951
 
 
7952
                set_if_bigger(*first_value, autoinc);
 
7953
        /* Not in the middle of a mult-row INSERT. */
 
7954
        } else if (prebuilt->autoinc_last_value == 0) {
 
7955
                set_if_bigger(*first_value, autoinc);
 
7956
        }
 
7957
 
 
7958
        *nb_reserved_values = trx->n_autoinc_rows;
 
7959
 
 
7960
        /* With old style AUTOINC locking we only update the table's
 
7961
        AUTOINC counter after attempting to insert the row. */
 
7962
        if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) {
 
7963
                uint64_t        need;
 
7964
                uint64_t        next_value;
 
7965
                uint64_t        col_max_value;
 
7966
 
 
7967
                /* We need the upper limit of the col type to check for
 
7968
                whether we update the table autoinc counter or not. */
 
7969
                col_max_value = innobase_get_int_col_max_value(
 
7970
                        table->next_number_field);
 
7971
 
 
7972
                need = *nb_reserved_values * increment;
 
7973
 
 
7974
                /* Compute the last value in the interval */
 
7975
                next_value = innobase_next_autoinc(
 
7976
                        *first_value, need, offset, col_max_value);
 
7977
 
 
7978
                prebuilt->autoinc_last_value = next_value;
 
7979
 
 
7980
                if (prebuilt->autoinc_last_value < *first_value) {
 
7981
                        *first_value = (~(unsigned long long) 0);
 
7982
                } else {
 
7983
                        /* Update the table autoinc variable */
 
7984
                        dict_table_autoinc_update_if_greater(
 
7985
                                prebuilt->table, prebuilt->autoinc_last_value);
 
7986
                }
 
7987
        } else {
 
7988
                /* This will force write_row() into attempting an update
 
7989
                of the table's AUTOINC counter. */
 
7990
                prebuilt->autoinc_last_value = 0;
 
7991
        }
 
7992
 
 
7993
        /* The increment to be used to increase the AUTOINC value, we use
 
7994
        this in write_row() and update_row() to increase the autoinc counter
 
7995
        for columns that are filled by the user. We need the offset and
 
7996
        the increment. */
 
7997
        prebuilt->autoinc_offset = offset;
 
7998
        prebuilt->autoinc_increment = increment;
 
7999
 
 
8000
        dict_table_autoinc_unlock(prebuilt->table);
8747
8001
}
8748
8002
 
8749
8003
/*******************************************************************//**
8751
8005
inserted will get the given value. This is called e.g. after TRUNCATE
8752
8006
is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is
8753
8007
returned by storage engines that don't support this operation.
8754
 
@return 0 or error code */
 
8008
@return 0 or error code */
8755
8009
UNIV_INTERN
8756
8010
int
8757
8011
ha_innobase::reset_auto_increment(
8758
8012
/*==============================*/
8759
 
  uint64_t  value)    /*!< in: new value for table autoinc */
 
8013
        uint64_t        value)          /*!< in: new value for table autoinc */
8760
8014
{
8761
 
  int error;
8762
 
 
8763
 
  update_session(getTable()->in_use);
8764
 
 
8765
 
  error = row_lock_table_autoinc_for_mysql(prebuilt);
8766
 
 
8767
 
  if (error != DB_SUCCESS) {
8768
 
    error = convert_error_code_to_mysql(error,
8769
 
                prebuilt->table->flags,
8770
 
                user_session);
8771
 
 
8772
 
    return(error);
8773
 
  }
8774
 
 
8775
 
  /* The next value can never be 0. */
8776
 
  if (value == 0) {
8777
 
    value = 1;
8778
 
  }
8779
 
 
8780
 
  innobase_reset_autoinc(value);
8781
 
 
8782
 
  return 0;
 
8015
        int     error;
 
8016
 
 
8017
        update_session(ha_session());
 
8018
 
 
8019
        error = row_lock_table_autoinc_for_mysql(prebuilt);
 
8020
 
 
8021
        if (error != DB_SUCCESS) {
 
8022
                error = convert_error_code_to_mysql(error,
 
8023
                                                    prebuilt->table->flags,
 
8024
                                                    user_session);
 
8025
 
 
8026
                return(error);
 
8027
        }
 
8028
 
 
8029
        /* The next value can never be 0. */
 
8030
        if (value == 0) {
 
8031
                value = 1;
 
8032
        }
 
8033
 
 
8034
        innobase_reset_autoinc(value);
 
8035
 
 
8036
        return 0;
8783
8037
}
8784
8038
 
8785
8039
/* See comment in Cursor.cc */
8787
8041
bool
8788
8042
InnobaseEngine::get_error_message(int, String *buf)
8789
8043
{
8790
 
  trx_t*  trx = check_trx_exists(current_session);
8791
 
 
8792
 
  buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
8793
 
    system_charset_info);
8794
 
 
8795
 
  return(FALSE);
 
8044
        trx_t*  trx = check_trx_exists(current_session);
 
8045
 
 
8046
        buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
 
8047
                system_charset_info);
 
8048
 
 
8049
        return(FALSE);
8796
8050
}
8797
8051
 
8798
8052
/*******************************************************************//**
8799
8053
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
8800
8054
If there is no explicitly declared non-null unique key or a primary key, then
8801
8055
InnoDB internally uses the row id as the primary key.
8802
 
@return < 0 if ref1 < ref2, 0 if equal, else > 0 */
 
8056
@return < 0 if ref1 < ref2, 0 if equal, else > 0 */
8803
8057
UNIV_INTERN
8804
8058
int
8805
8059
ha_innobase::cmp_ref(
8806
8060
/*=================*/
8807
 
  const unsigned char*  ref1, /*!< in: an (internal) primary key value in the
8808
 
        MySQL key value format */
8809
 
  const unsigned char*  ref2) /*!< in: an (internal) primary key value in the
8810
 
        MySQL key value format */
 
8061
        const unsigned char*    ref1,   /*!< in: an (internal) primary key value in the
 
8062
                                MySQL key value format */
 
8063
        const unsigned char*    ref2)   /*!< in: an (internal) primary key value in the
 
8064
                                MySQL key value format */
8811
8065
{
8812
 
  enum_field_types mysql_type;
8813
 
  Field*    field;
8814
 
  KeyPartInfo*  key_part;
8815
 
  KeyPartInfo*  key_part_end;
8816
 
  uint    len1;
8817
 
  uint    len2;
8818
 
  int   result;
8819
 
 
8820
 
  if (prebuilt->clust_index_was_generated) {
8821
 
    /* The 'ref' is an InnoDB row id */
8822
 
 
8823
 
    return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
8824
 
  }
8825
 
 
8826
 
  /* Do a type-aware comparison of primary key fields. PK fields
8827
 
  are always NOT NULL, so no checks for NULL are performed. */
8828
 
 
8829
 
  key_part = getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_part;
8830
 
 
8831
 
  key_part_end = key_part
8832
 
      + getTable()->key_info[getTable()->getShare()->getPrimaryKey()].key_parts;
8833
 
 
8834
 
  for (; key_part != key_part_end; ++key_part) {
8835
 
    field = key_part->field;
8836
 
    mysql_type = field->type();
8837
 
 
8838
 
    if (mysql_type == DRIZZLE_TYPE_BLOB) {
8839
 
 
8840
 
      /* In the MySQL key value format, a column prefix of
8841
 
      a BLOB is preceded by a 2-byte length field */
8842
 
 
8843
 
      len1 = innobase_read_from_2_little_endian(ref1);
8844
 
      len2 = innobase_read_from_2_little_endian(ref2);
8845
 
 
8846
 
      ref1 += 2;
8847
 
      ref2 += 2;
8848
 
      result = ((Field_blob*)field)->cmp( ref1, len1,
 
8066
        enum_field_types mysql_type;
 
8067
        Field*          field;
 
8068
        KEY_PART_INFO*  key_part;
 
8069
        KEY_PART_INFO*  key_part_end;
 
8070
        uint            len1;
 
8071
        uint            len2;
 
8072
        int             result;
 
8073
 
 
8074
        if (prebuilt->clust_index_was_generated) {
 
8075
                /* The 'ref' is an InnoDB row id */
 
8076
 
 
8077
                return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
 
8078
        }
 
8079
 
 
8080
        /* Do a type-aware comparison of primary key fields. PK fields
 
8081
        are always NOT NULL, so no checks for NULL are performed. */
 
8082
 
 
8083
        key_part = table->key_info[table->s->primary_key].key_part;
 
8084
 
 
8085
        key_part_end = key_part
 
8086
                        + table->key_info[table->s->primary_key].key_parts;
 
8087
 
 
8088
        for (; key_part != key_part_end; ++key_part) {
 
8089
                field = key_part->field;
 
8090
                mysql_type = field->type();
 
8091
 
 
8092
                if (mysql_type == DRIZZLE_TYPE_BLOB) {
 
8093
 
 
8094
                        /* In the MySQL key value format, a column prefix of
 
8095
                        a BLOB is preceded by a 2-byte length field */
 
8096
 
 
8097
                        len1 = innobase_read_from_2_little_endian(ref1);
 
8098
                        len2 = innobase_read_from_2_little_endian(ref2);
 
8099
 
 
8100
                        ref1 += 2;
 
8101
                        ref2 += 2;
 
8102
                        result = ((Field_blob*)field)->cmp( ref1, len1,
8849
8103
                                                            ref2, len2);
8850
 
    } else {
8851
 
      result = field->key_cmp(ref1, ref2);
8852
 
    }
8853
 
 
8854
 
    if (result) {
8855
 
 
8856
 
      return(result);
8857
 
    }
8858
 
 
8859
 
    ref1 += key_part->store_length;
8860
 
    ref2 += key_part->store_length;
8861
 
  }
8862
 
 
8863
 
  return(0);
 
8104
                } else {
 
8105
                        result = field->key_cmp(ref1, ref2);
 
8106
                }
 
8107
 
 
8108
                if (result) {
 
8109
 
 
8110
                        return(result);
 
8111
                }
 
8112
 
 
8113
                ref1 += key_part->store_length;
 
8114
                ref2 += key_part->store_length;
 
8115
        }
 
8116
 
 
8117
        return(0);
8864
8118
}
8865
8119
 
8866
8120
/**********************************************************************
8868
8122
characters for prefix indexes using a multibyte character set. The function
8869
8123
finds charset information and returns length of prefix_len characters in the
8870
8124
index field in bytes.
8871
 
@return number of bytes occupied by the first n characters */
 
8125
@return number of bytes occupied by the first n characters */
8872
8126
extern "C" UNIV_INTERN
8873
8127
ulint
8874
8128
innobase_get_at_most_n_mbchars(
8875
8129
/*===========================*/
8876
 
  ulint charset_id, /*!< in: character set id */
8877
 
  ulint prefix_len, /*!< in: prefix length in bytes of the index
8878
 
        (this has to be divided by mbmaxlen to get the
8879
 
        number of CHARACTERS n in the prefix) */
8880
 
  ulint data_len,   /*!< in: length of the string in bytes */
8881
 
  const char* str); /*!< in: character string */
 
8130
        ulint charset_id,       /*!< in: character set id */
 
8131
        ulint prefix_len,       /*!< in: prefix length in bytes of the index
 
8132
                                (this has to be divided by mbmaxlen to get the
 
8133
                                number of CHARACTERS n in the prefix) */
 
8134
        ulint data_len,         /*!< in: length of the string in bytes */
 
8135
        const char* str);       /*!< in: character string */
8882
8136
 
8883
8137
ulint
8884
8138
innobase_get_at_most_n_mbchars(
8885
8139
/*===========================*/
8886
 
  ulint charset_id, /*!< in: character set id */
8887
 
  ulint prefix_len, /*!< in: prefix length in bytes of the index
8888
 
        (this has to be divided by mbmaxlen to get the
8889
 
        number of CHARACTERS n in the prefix) */
8890
 
  ulint data_len,   /*!< in: length of the string in bytes */
8891
 
  const char* str)  /*!< in: character string */
8892
 
{
8893
 
  ulint char_length;    /*!< character length in bytes */
8894
 
  ulint n_chars;      /*!< number of characters in prefix */
8895
 
  const CHARSET_INFO* charset;  /*!< charset used in the field */
8896
 
 
8897
 
  charset = get_charset((uint) charset_id);
8898
 
 
8899
 
  ut_ad(charset);
8900
 
  ut_ad(charset->mbmaxlen);
8901
 
 
8902
 
  /* Calculate how many characters at most the prefix index contains */
8903
 
 
8904
 
  n_chars = prefix_len / charset->mbmaxlen;
8905
 
 
8906
 
  /* If the charset is multi-byte, then we must find the length of the
8907
 
  first at most n chars in the string. If the string contains less
8908
 
  characters than n, then we return the length to the end of the last
8909
 
  character. */
8910
 
 
8911
 
  if (charset->mbmaxlen > 1) {
8912
 
    /* my_charpos() returns the byte length of the first n_chars
8913
 
    characters, or a value bigger than the length of str, if
8914
 
    there were not enough full characters in str.
8915
 
 
8916
 
    Why does the code below work:
8917
 
    Suppose that we are looking for n UTF-8 characters.
8918
 
 
8919
 
    1) If the string is long enough, then the prefix contains at
8920
 
    least n complete UTF-8 characters + maybe some extra
8921
 
    characters + an incomplete UTF-8 character. No problem in
8922
 
    this case. The function returns the pointer to the
8923
 
    end of the nth character.
8924
 
 
8925
 
    2) If the string is not long enough, then the string contains
8926
 
    the complete value of a column, that is, only complete UTF-8
8927
 
    characters, and we can store in the column prefix index the
8928
 
    whole string. */
8929
 
 
8930
 
    char_length = my_charpos(charset, str,
8931
 
            str + data_len, (int) n_chars);
8932
 
    if (char_length > data_len) {
8933
 
      char_length = data_len;
8934
 
    }
8935
 
  } else {
8936
 
    if (data_len < prefix_len) {
8937
 
      char_length = data_len;
8938
 
    } else {
8939
 
      char_length = prefix_len;
8940
 
    }
8941
 
  }
8942
 
 
8943
 
  return(char_length);
8944
 
}
8945
 
/**
8946
 
 * We will also use this function to communicate
8947
 
 * to InnoDB that a new SQL statement has started and that we must store a
8948
 
 * savepoint to our transaction handle, so that we are able to roll back
8949
 
 * the SQL statement in case of an error.
8950
 
 */
8951
 
void
8952
 
InnobaseEngine::doStartStatement(
8953
 
  Session *session) /*!< in: handle to the Drizzle session */
8954
 
{
8955
 
  /* 
8956
 
   * Create the InnoDB transaction structure
8957
 
   * for the session
8958
 
   */
8959
 
  trx_t *trx= check_trx_exists(session);
8960
 
 
8961
 
  /* "reset" the error message for the transaction */
8962
 
  trx->detailed_error[0]= '\0';
8963
 
 
8964
 
  /* Set the isolation level of the transaction. */
8965
 
  trx->isolation_level= innobase_map_isolation_level(session_tx_isolation(session));
8966
 
}
8967
 
 
8968
 
void
8969
 
InnobaseEngine::doEndStatement(
8970
 
  Session *session)
8971
 
{
8972
 
  trx_t *trx= check_trx_exists(session);
8973
 
 
8974
 
  /* Release a possible FIFO ticket and search latch. Since we
8975
 
  may reserve the kernel mutex, we have to release the search
8976
 
  system latch first to obey the latching order. */
8977
 
 
8978
 
  innobase_release_stat_resources(trx);
8979
 
 
 
8140
        ulint charset_id,       /*!< in: character set id */
 
8141
        ulint prefix_len,       /*!< in: prefix length in bytes of the index
 
8142
                                (this has to be divided by mbmaxlen to get the
 
8143
                                number of CHARACTERS n in the prefix) */
 
8144
        ulint data_len,         /*!< in: length of the string in bytes */
 
8145
        const char* str)        /*!< in: character string */
 
8146
{
 
8147
        ulint char_length;              /*!< character length in bytes */
 
8148
        ulint n_chars;                  /*!< number of characters in prefix */
 
8149
        const CHARSET_INFO* charset;    /*!< charset used in the field */
 
8150
 
 
8151
        charset = get_charset((uint) charset_id);
 
8152
 
 
8153
        ut_ad(charset);
 
8154
        ut_ad(charset->mbmaxlen);
 
8155
 
 
8156
        /* Calculate how many characters at most the prefix index contains */
 
8157
 
 
8158
        n_chars = prefix_len / charset->mbmaxlen;
 
8159
 
 
8160
        /* If the charset is multi-byte, then we must find the length of the
 
8161
        first at most n chars in the string. If the string contains less
 
8162
        characters than n, then we return the length to the end of the last
 
8163
        character. */
 
8164
 
 
8165
        if (charset->mbmaxlen > 1) {
 
8166
                /* my_charpos() returns the byte length of the first n_chars
 
8167
                characters, or a value bigger than the length of str, if
 
8168
                there were not enough full characters in str.
 
8169
 
 
8170
                Why does the code below work:
 
8171
                Suppose that we are looking for n UTF-8 characters.
 
8172
 
 
8173
                1) If the string is long enough, then the prefix contains at
 
8174
                least n complete UTF-8 characters + maybe some extra
 
8175
                characters + an incomplete UTF-8 character. No problem in
 
8176
                this case. The function returns the pointer to the
 
8177
                end of the nth character.
 
8178
 
 
8179
                2) If the string is not long enough, then the string contains
 
8180
                the complete value of a column, that is, only complete UTF-8
 
8181
                characters, and we can store in the column prefix index the
 
8182
                whole string. */
 
8183
 
 
8184
                char_length = my_charpos(charset, str,
 
8185
                                                str + data_len, (int) n_chars);
 
8186
                if (char_length > data_len) {
 
8187
                        char_length = data_len;
 
8188
                }
 
8189
        } else {
 
8190
                if (data_len < prefix_len) {
 
8191
                        char_length = data_len;
 
8192
                } else {
 
8193
                        char_length = prefix_len;
 
8194
                }
 
8195
        }
 
8196
 
 
8197
        return(char_length);
8980
8198
}
8981
8199
 
8982
8200
/*******************************************************************//**
8983
8201
This function is used to prepare an X/Open XA distributed transaction.
8984
 
@return 0 or error number */
 
8202
@return 0 or error number */
8985
8203
int
8986
 
InnobaseEngine::doXaPrepare(
 
8204
InnobaseEngine::prepare(
8987
8205
/*================*/
8988
 
  Session*  session,/*!< in: handle to the MySQL thread of
8989
 
        the user whose XA transaction should
8990
 
        be prepared */
8991
 
  bool    all)  /*!< in: TRUE - commit transaction
8992
 
        FALSE - the current SQL statement
8993
 
        ended */
8994
 
{
8995
 
  int error = 0;
8996
 
  trx_t* trx = check_trx_exists(session);
8997
 
 
8998
 
  assert(this == innodb_engine_ptr);
8999
 
 
9000
 
  /* we use support_xa value as it was seen at transaction start
9001
 
  time, not the current session variable value. Any possible changes
9002
 
  to the session variable take effect only in the next transaction */
9003
 
  if (!trx->support_xa) {
9004
 
 
9005
 
    return(0);
9006
 
  }
9007
 
 
9008
 
  session->get_xid(reinterpret_cast<DRIZZLE_XID*>(&trx->xid));
9009
 
 
9010
 
  /* Release a possible FIFO ticket and search latch. Since we will
9011
 
  reserve the kernel mutex, we have to release the search system latch
9012
 
  first to obey the latching order. */
9013
 
 
9014
 
  innobase_release_stat_resources(trx);
9015
 
 
9016
 
  if (all
9017
 
    || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
9018
 
 
9019
 
    /* We were instructed to prepare the whole transaction, or
9020
 
    this is an SQL statement end and autocommit is on */
9021
 
 
9022
 
    ut_ad(trx->conc_state != TRX_NOT_STARTED);
9023
 
 
9024
 
    error = (int) trx_prepare_for_mysql(trx);
9025
 
  } else {
9026
 
    /* We just mark the SQL statement ended and do not do a
9027
 
    transaction prepare */
9028
 
 
9029
 
    /* If we had reserved the auto-inc lock for some
9030
 
    table in this SQL statement we release it now */
9031
 
 
9032
 
    row_unlock_table_autoinc_for_mysql(trx);
9033
 
 
9034
 
    /* Store the current undo_no of the transaction so that we
9035
 
    know where to roll back if we have to roll back the next
9036
 
    SQL statement */
9037
 
 
9038
 
    trx_mark_sql_stat_end(trx);
9039
 
  }
9040
 
 
9041
 
  /* Tell the InnoDB server that there might be work for utility
9042
 
  threads: */
9043
 
 
9044
 
  srv_active_wake_master_thread();
9045
 
 
9046
 
  return(error);
9047
 
}
9048
 
 
9049
 
uint64_t InnobaseEngine::doGetCurrentTransactionId(Session *session)
9050
 
{
9051
 
  trx_t *trx= session_to_trx(session);
9052
 
  return (trx->id);
9053
 
}
9054
 
 
9055
 
uint64_t InnobaseEngine::doGetNewTransactionId(Session *session)
9056
 
{
9057
 
  trx_t*& trx = session_to_trx(session);
9058
 
 
9059
 
  if (trx == NULL)
9060
 
  {
9061
 
    trx = innobase_trx_allocate(session);
9062
 
 
9063
 
    innobase_trx_init(session, trx);
9064
 
  }
9065
 
 
9066
 
  mutex_enter(&kernel_mutex);
9067
 
  trx->id= trx_sys_get_new_trx_id();
9068
 
  mutex_exit(&kernel_mutex);
9069
 
 
9070
 
  uint64_t transaction_id= trx->id;
9071
 
 
9072
 
  return transaction_id;
 
8206
        Session*        session,/*!< in: handle to the MySQL thread of
 
8207
                                the user whose XA transaction should
 
8208
                                be prepared */
 
8209
        bool            all)    /*!< in: TRUE - commit transaction
 
8210
                                FALSE - the current SQL statement
 
8211
                                ended */
 
8212
{
 
8213
        int error = 0;
 
8214
        trx_t* trx = check_trx_exists(session);
 
8215
 
 
8216
        assert(this == innodb_engine_ptr);
 
8217
 
 
8218
        /* we use support_xa value as it was seen at transaction start
 
8219
        time, not the current session variable value. Any possible changes
 
8220
        to the session variable take effect only in the next transaction */
 
8221
        if (!trx->support_xa) {
 
8222
 
 
8223
                return(0);
 
8224
        }
 
8225
 
 
8226
        session_get_xid(session, reinterpret_cast<DRIZZLE_XID*>(&trx->xid));
 
8227
 
 
8228
        /* Release a possible FIFO ticket and search latch. Since we will
 
8229
        reserve the kernel mutex, we have to release the search system latch
 
8230
        first to obey the latching order. */
 
8231
 
 
8232
        innobase_release_stat_resources(trx);
 
8233
 
 
8234
        if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) {
 
8235
 
 
8236
          errmsg_printf(ERRMSG_LVL_ERROR,
 
8237
                        "trx->active_trans == 0, but trx->conc_state != "
 
8238
                        "TRX_NOT_STARTED");
 
8239
        }
 
8240
 
 
8241
        if (all
 
8242
                || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
 
8243
 
 
8244
                /* We were instructed to prepare the whole transaction, or
 
8245
                this is an SQL statement end and autocommit is on */
 
8246
 
 
8247
                ut_ad(trx->active_trans);
 
8248
 
 
8249
                error = (int) trx_prepare_for_mysql(trx);
 
8250
        } else {
 
8251
                /* We just mark the SQL statement ended and do not do a
 
8252
                transaction prepare */
 
8253
 
 
8254
                /* If we had reserved the auto-inc lock for some
 
8255
                table in this SQL statement we release it now */
 
8256
 
 
8257
                row_unlock_table_autoinc_for_mysql(trx);
 
8258
 
 
8259
                /* Store the current undo_no of the transaction so that we
 
8260
                know where to roll back if we have to roll back the next
 
8261
                SQL statement */
 
8262
 
 
8263
                trx_mark_sql_stat_end(trx);
 
8264
        }
 
8265
 
 
8266
        /* Tell the InnoDB server that there might be work for utility
 
8267
        threads: */
 
8268
 
 
8269
        srv_active_wake_master_thread();
 
8270
 
 
8271
        if (all || !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
 
8272
        {
 
8273
 
 
8274
                /* For ibbackup to work the order of transactions in binlog
 
8275
                and InnoDB must be the same. Consider the situation
 
8276
 
 
8277
                  thread1> prepare; write to binlog; ...
 
8278
                          <context switch>
 
8279
                  thread2> prepare; write to binlog; commit
 
8280
                  thread1>                           ... commit
 
8281
 
 
8282
                To ensure this will not happen we're taking the mutex on
 
8283
                prepare, and releasing it on commit.
 
8284
 
 
8285
                Note: only do it for normal commits, done via ha_commit_trans.
 
8286
                If 2pc protocol is executed by external transaction
 
8287
                coordinator, it will be just a regular MySQL client
 
8288
                executing XA PREPARE and XA COMMIT commands.
 
8289
                In this case we cannot know how many minutes or hours
 
8290
                will be between XA PREPARE and XA COMMIT, and we don't want
 
8291
                to block for undefined period of time.
 
8292
                */
 
8293
                pthread_mutex_lock(&prepare_commit_mutex);
 
8294
                trx->active_trans = 2;
 
8295
        }
 
8296
        return(error);
9073
8297
}
9074
8298
 
9075
8299
/*******************************************************************//**
9076
8300
This function is used to recover X/Open XA distributed transactions.
9077
 
@return number of prepared transactions stored in xid_list */
 
8301
@return number of prepared transactions stored in xid_list */
9078
8302
int
9079
 
InnobaseEngine::doXaRecover(
 
8303
InnobaseEngine::recover(
9080
8304
/*================*/
9081
 
  ::drizzled::XID*  xid_list,/*!< in/out: prepared transactions */
9082
 
  size_t len) /*!< in: number of slots in xid_list */
 
8305
        ::drizzled::XID*        xid_list,/*!< in/out: prepared transactions */
 
8306
        uint                    len)    /*!< in: number of slots in xid_list */
9083
8307
{
9084
 
  assert(this == innodb_engine_ptr);
9085
 
 
9086
 
  if (len == 0 || xid_list == NULL) {
9087
 
 
9088
 
    return(0);
9089
 
  }
9090
 
 
9091
 
  return(trx_recover_for_mysql((::XID *)xid_list, len));
 
8308
        assert(this == innodb_engine_ptr);
 
8309
 
 
8310
        if (len == 0 || xid_list == NULL) {
 
8311
 
 
8312
                return(0);
 
8313
        }
 
8314
 
 
8315
        return(trx_recover_for_mysql((::XID *)xid_list, len));
9092
8316
}
9093
8317
 
9094
8318
/*******************************************************************//**
9095
8319
This function is used to commit one X/Open XA distributed transaction
9096
8320
which is in the prepared state
9097
 
@return 0 or error number */
 
8321
@return 0 or error number */
9098
8322
int
9099
 
InnobaseEngine::doXaCommitXid(
 
8323
InnobaseEngine::commit_by_xid(
9100
8324
/*===================*/
9101
 
  ::drizzled::XID*  xid)  /*!< in: X/Open XA transaction identification */
 
8325
        ::drizzled::XID*        xid)    /*!< in: X/Open XA transaction identification */
9102
8326
{
9103
 
  trx_t*  trx;
9104
 
 
9105
 
  assert(this == innodb_engine_ptr);
9106
 
 
9107
 
  trx = trx_get_trx_by_xid((::XID *)xid);
9108
 
 
9109
 
  if (trx) {
9110
 
    innobase_commit_low(trx);
9111
 
 
9112
 
    return(XA_OK);
9113
 
  } else {
9114
 
    return(XAER_NOTA);
9115
 
  }
 
8327
        trx_t*  trx;
 
8328
 
 
8329
        assert(this == innodb_engine_ptr);
 
8330
 
 
8331
        trx = trx_get_trx_by_xid((::XID *)xid);
 
8332
 
 
8333
        if (trx) {
 
8334
                innobase_commit_low(trx);
 
8335
 
 
8336
                return(XA_OK);
 
8337
        } else {
 
8338
                return(XAER_NOTA);
 
8339
        }
9116
8340
}
9117
8341
 
9118
8342
/*******************************************************************//**
9119
8343
This function is used to rollback one X/Open XA distributed transaction
9120
8344
which is in the prepared state
9121
 
@return 0 or error number */
 
8345
@return 0 or error number */
9122
8346
int
9123
 
InnobaseEngine::doXaRollbackXid(
 
8347
InnobaseEngine::rollback_by_xid(
9124
8348
/*=====================*/
9125
 
  ::drizzled::XID*    xid)  /*!< in: X/Open XA transaction
9126
 
        identification */
 
8349
        ::drizzled::XID*                xid)    /*!< in: X/Open XA transaction
 
8350
                                identification */
9127
8351
{
9128
 
  trx_t*  trx;
9129
 
 
9130
 
  assert(this == innodb_engine_ptr);
9131
 
 
9132
 
  trx = trx_get_trx_by_xid((::XID *)xid);
9133
 
 
9134
 
  if (trx) {
9135
 
    return(innobase_rollback_trx(trx));
9136
 
  } else {
9137
 
    return(XAER_NOTA);
9138
 
  }
 
8352
        trx_t*  trx;
 
8353
 
 
8354
        assert(this == innodb_engine_ptr);
 
8355
 
 
8356
        trx = trx_get_trx_by_xid((::XID *)xid);
 
8357
 
 
8358
        if (trx) {
 
8359
                return(innobase_rollback_trx(trx));
 
8360
        } else {
 
8361
                return(XAER_NOTA);
 
8362
        }
9139
8363
}
9140
8364
 
9141
8365
 
9142
8366
/************************************************************//**
9143
8367
Validate the file format name and return its corresponding id.
9144
 
@return valid file format id */
 
8368
@return valid file format id */
9145
8369
static
9146
8370
uint
9147
8371
innobase_file_format_name_lookup(
9148
8372
/*=============================*/
9149
 
  const char* format_name)  /*!< in: pointer to file format name */
9150
 
{
9151
 
  char* endp;
9152
 
  uint  format_id;
9153
 
 
9154
 
  ut_a(format_name != NULL);
9155
 
 
9156
 
  /* The format name can contain the format id itself instead of
9157
 
  the name and we check for that. */
9158
 
  format_id = (uint) strtoul(format_name, &endp, 10);
9159
 
 
9160
 
  /* Check for valid parse. */
9161
 
  if (*endp == '\0' && *format_name != '\0') {
9162
 
 
9163
 
    if (format_id <= DICT_TF_FORMAT_MAX) {
9164
 
 
9165
 
      return(format_id);
9166
 
    }
9167
 
  } else {
9168
 
 
9169
 
    for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
9170
 
         format_id++) {
9171
 
      const char* name;
9172
 
 
9173
 
      name = trx_sys_file_format_id_to_name(format_id);
9174
 
 
9175
 
      if (!innobase_strcasecmp(format_name, name)) {
9176
 
 
9177
 
        return(format_id);
9178
 
      }
9179
 
    }
9180
 
  }
9181
 
 
9182
 
  return(DICT_TF_FORMAT_MAX + 1);
 
8373
        const char*     format_name)    /*!< in: pointer to file format name */
 
8374
{
 
8375
        char*   endp;
 
8376
        uint    format_id;
 
8377
 
 
8378
        ut_a(format_name != NULL);
 
8379
 
 
8380
        /* The format name can contain the format id itself instead of
 
8381
        the name and we check for that. */
 
8382
        format_id = (uint) strtoul(format_name, &endp, 10);
 
8383
 
 
8384
        /* Check for valid parse. */
 
8385
        if (*endp == '\0' && *format_name != '\0') {
 
8386
 
 
8387
                if (format_id <= DICT_TF_FORMAT_MAX) {
 
8388
 
 
8389
                        return(format_id);
 
8390
                }
 
8391
        } else {
 
8392
 
 
8393
                for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
 
8394
                     format_id++) {
 
8395
                        const char*     name;
 
8396
 
 
8397
                        name = trx_sys_file_format_id_to_name(format_id);
 
8398
 
 
8399
                        if (!innobase_strcasecmp(format_name, name)) {
 
8400
 
 
8401
                                return(format_id);
 
8402
                        }
 
8403
                }
 
8404
        }
 
8405
 
 
8406
        return(DICT_TF_FORMAT_MAX + 1);
 
8407
}
 
8408
 
 
8409
/************************************************************//**
 
8410
Validate the file format check value, is it one of "on" or "off",
 
8411
as a side effect it sets the srv_check_file_format_at_startup variable.
 
8412
@return true if config value one of "on" or  "off" */
 
8413
static
 
8414
bool
 
8415
innobase_file_format_check_on_off(
 
8416
/*==============================*/
 
8417
        const char*     format_check)   /*!< in: parameter value */
 
8418
{
 
8419
        bool            ret = true;
 
8420
 
 
8421
        if (!innobase_strcasecmp(format_check, "off")) {
 
8422
 
 
8423
                /* Set the value to disable checking. */
 
8424
                srv_check_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
 
8425
 
 
8426
        } else if (!innobase_strcasecmp(format_check, "on")) {
 
8427
 
 
8428
                /* Set the value to the lowest supported format. */
 
8429
                srv_check_file_format_at_startup = DICT_TF_FORMAT_51;
 
8430
        } else {
 
8431
                ret = FALSE;
 
8432
        }
 
8433
 
 
8434
        return(ret);
9183
8435
}
9184
8436
 
9185
8437
/************************************************************//**
9186
8438
Validate the file format check config parameters, as a side effect it
9187
 
sets the srv_max_file_format_at_startup variable.
9188
 
@return the format_id if valid config value, otherwise, return -1 */
 
8439
sets the srv_check_file_format_at_startup variable.
 
8440
@return true if valid config value */
9189
8441
static
9190
 
int
9191
 
innobase_file_format_validate_and_set(
 
8442
bool
 
8443
innobase_file_format_check_validate(
9192
8444
/*================================*/
9193
 
  const char* format_max) /*!< in: parameter value */
9194
 
{
9195
 
  uint    format_id;
9196
 
 
9197
 
  format_id = innobase_file_format_name_lookup(format_max);
9198
 
 
9199
 
  if (format_id < DICT_TF_FORMAT_MAX + 1) {
9200
 
    srv_max_file_format_at_startup = format_id;
9201
 
    return((int) format_id);
9202
 
  } else {
9203
 
    return(-1);
9204
 
  }
9205
 
}
9206
 
 
9207
 
 
9208
 
 
9209
 
static void init_options(drizzled::module::option_context &context)
9210
 
{
9211
 
  context("disable-checksums",
9212
 
          "Disable InnoDB checksums validation.");
9213
 
  context("data-home-dir",
9214
 
          po::value<string>(),
9215
 
          "The common part for InnoDB table spaces.");
9216
 
  context("disable-doublewrite",
9217
 
          "Disable InnoDB doublewrite buffer.");
9218
 
  context("io-capacity",
9219
 
          po::value<io_capacity_constraint>(&innodb_io_capacity)->default_value(200),
9220
 
          "Number of IOPs the server can do. Tunes the background IO rate");
9221
 
  context("fast-shutdown",
9222
 
          po::value<trinary_constraint>(&innobase_fast_shutdown)->default_value(1), 
9223
 
          "Speeds up the shutdown process of the InnoDB storage engine. Possible values are 0, 1 (faster) or 2 (fastest - crash-like).");
9224
 
  context("purge-batch-size",
9225
 
          po::value<purge_batch_constraint>(&innodb_purge_batch_size)->default_value(20),
9226
 
          "Number of UNDO logs to purge in one batch from the history list. "
9227
 
          "Default is 20.");
9228
 
  context("purge-threads",
9229
 
          po::value<purge_threads_constraint>(&innodb_n_purge_threads)->default_value(0),
9230
 
          "Purge threads can be either 0 or 1. Defalut is 0.");
9231
 
  context("file-per-table",
9232
 
          po::value<bool>(&srv_file_per_table)->default_value(false)->zero_tokens(),
9233
 
          "Stores each InnoDB table to an .ibd file in the database dir.");
9234
 
  context("file-format",
9235
 
          po::value<string>(&innobase_file_format_name)->default_value("Antelope"),
9236
 
          "File format to use for new tables in .ibd files.");
9237
 
  context("file-format-max",
9238
 
          po::value<string>(&innobase_file_format_max)->default_value("Antelope"),
9239
 
          "The highest file format in the tablespace.");
9240
 
  context("file-format-check",
9241
 
          po::value<bool>(&innobase_file_format_check)->default_value(true)->zero_tokens(),
9242
 
          "Whether to perform system file format check.");
9243
 
  context("flush-log-at-trx-commit",
9244
 
          po::value<trinary_constraint>(&innodb_flush_log_at_trx_commit)->default_value(1),
9245
 
          "Set to 0 (write and flush once per second), 1 (write and flush at each commit) or 2 (write at commit, flush once per second).");
9246
 
  context("flush-method",
9247
 
          po::value<string>(),
9248
 
          "With which method to flush data.");
9249
 
  context("log-group-home-dir",
9250
 
          po::value<string>(),
9251
 
          "Path to InnoDB log files.");
9252
 
  context("max-dirty-pages-pct",
9253
 
          po::value<max_dirty_pages_constraint>(&innodb_max_dirty_pages_pct)->default_value(75),
9254
 
          "Percentage of dirty pages allowed in bufferpool.");
9255
 
  context("disable-adaptive-flushing",
9256
 
          "Do not attempt flushing dirty pages to avoid IO bursts at checkpoints.");
9257
 
  context("max-purge-lag",
9258
 
          po::value<uint64_constraint>(&innodb_max_purge_lag)->default_value(0),
9259
 
          "Desired maximum length of the purge queue (0 = no limit)");
9260
 
  context("status-file",
9261
 
          po::value<bool>(&innobase_create_status_file)->default_value(false)->zero_tokens(),
9262
 
          "Enable SHOW INNODB STATUS output in the innodb_status.<pid> file");
9263
 
  context("disable-stats-on-metadata",
9264
 
          "Disable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)");
9265
 
  context("stats-sample-pages",
9266
 
          po::value<uint64_nonzero_constraint>(&innodb_stats_sample_pages)->default_value(8),
9267
 
          "The number of index pages to sample when calculating statistics (default 8)");
9268
 
  context("disable-adaptive-hash-index",
9269
 
          "Enable InnoDB adaptive hash index (enabled by default)");
9270
 
  context("replication-delay",
9271
 
          po::value<uint64_constraint>(&innodb_replication_delay)->default_value(0),
9272
 
          "Replication thread delay (ms) on the slave server if innodb_thread_concurrency is reached (0 by default)");
9273
 
  context("additional-mem-pool-size",
9274
 
          po::value<additional_mem_pool_constraint>(&innobase_additional_mem_pool_size)->default_value(8*1024*1024L),
9275
 
          "Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.");
9276
 
  context("autoextend-increment",
9277
 
          po::value<autoextend_constraint>(&innodb_auto_extend_increment)->default_value(8L),
9278
 
          "Data file autoextend increment in megabytes");
9279
 
  context("buffer-pool-size",
9280
 
          po::value<buffer_pool_constraint>(&innobase_buffer_pool_size)->default_value(128*1024*1024L),
9281
 
          "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.");
9282
 
  context("buffer-pool-instances",
9283
 
          po::value<buffer_pool_instances_constraint>(&innobase_buffer_pool_instances)->default_value(1),
9284
 
          "Number of buffer pool instances, set to higher value on high-end machines to increase scalability");
9285
 
 
9286
 
  context("commit-concurrency",
9287
 
          po::value<concurrency_constraint>(&innobase_commit_concurrency)->default_value(0),
9288
 
          "Helps in performance tuning in heavily concurrent environments.");
9289
 
  context("concurrency-tickets",
9290
 
          po::value<uint32_nonzero_constraint>(&innodb_concurrency_tickets)->default_value(500L),
9291
 
          "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket");
9292
 
  context("read-io-threads",
9293
 
          po::value<io_threads_constraint>(&innobase_read_io_threads)->default_value(4),
9294
 
          "Number of background read I/O threads in InnoDB.");
9295
 
  context("write-io-threads",
9296
 
          po::value<io_threads_constraint>(&innobase_write_io_threads)->default_value(4),
9297
 
          "Number of background write I/O threads in InnoDB.");
9298
 
  context("force-recovery",
9299
 
          po::value<force_recovery_constraint>(&innobase_force_recovery)->default_value(0),
9300
 
          "Helps to save your data in case the disk image of the database becomes corrupt.");
9301
 
  context("log-buffer-size",
9302
 
          po::value<log_buffer_constraint>(&innobase_log_buffer_size)->default_value(8*1024*1024L),
9303
 
          "The size of the buffer which InnoDB uses to write log to the log files on disk.");
9304
 
  context("log-file-size",
9305
 
          po::value<log_file_constraint>(&innobase_log_file_size)->default_value(20*1024*1024L),
9306
 
          "The size of the buffer which InnoDB uses to write log to the log files on disk.");
9307
 
  context("log-files-in-group",
9308
 
          po::value<log_files_in_group_constraint>(&innobase_log_files_in_group)->default_value(2),
9309
 
          "Number of log files in the log group. InnoDB writes to the files in a circular fashion.");
9310
 
  context("mirrored-log-groups",
9311
 
          po::value<mirrored_log_groups_constraint>(&innobase_mirrored_log_groups)->default_value(1),
9312
 
          "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.");
9313
 
  context("open-files",
9314
 
          po::value<open_files_constraint>(&innobase_open_files)->default_value(300L),
9315
 
          "How many files at the maximum InnoDB keeps open at the same time.");
9316
 
  context("sync-spin-loops",
9317
 
          po::value<uint32_constraint>(&innodb_sync_spin_loops)->default_value(30L),
9318
 
          "Count of spin-loop rounds in InnoDB mutexes (30 by default)");
9319
 
  context("spin-wait-delay",
9320
 
          po::value<uint32_constraint>(&innodb_spin_wait_delay)->default_value(6L),
9321
 
          "Maximum delay between polling for a spin lock (6 by default)");
9322
 
  context("thread-concurrency",
9323
 
          po::value<concurrency_constraint>(&innobase_thread_concurrency)->default_value(0),
9324
 
          "Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.");
9325
 
  context("thread-sleep-delay",
9326
 
          po::value<uint32_constraint>(&innodb_thread_sleep_delay)->default_value(10000L),
9327
 
          "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep");
9328
 
  context("data-file-path",
9329
 
          po::value<string>(),
9330
 
          "Path to individual files and their sizes.");
9331
 
  context("version",
9332
 
          po::value<string>()->default_value(INNODB_VERSION_STR),
9333
 
          "InnoDB version");
9334
 
  context("use-internal-malloc",
9335
 
          "Use InnoDB's internal memory allocator instal of the OS memory allocator.");
9336
 
  context("change-buffering",
9337
 
          po::value<string>(&innobase_change_buffering),
9338
 
          "Buffer changes to reduce random access: OFF, ON, inserting, deleting, changing, or purging.");
9339
 
  context("read-ahead-threshold",
9340
 
          po::value<read_ahead_threshold_constraint>(&innodb_read_ahead_threshold)->default_value(56),
9341
 
          "Number of pages that must be accessed sequentially for InnoDB to trigger a readahead.");
9342
 
  context("disable-xa",
9343
 
          "Disable InnoDB support for the XA two-phase commit");
9344
 
  context("disable-table-locks",
9345
 
          "Disable InnoDB locking in LOCK TABLES");
9346
 
  context("strict-mode",
9347
 
          po::value<bool>(&strict_mode)->default_value(false)->zero_tokens(),
9348
 
          "Use strict mode when evaluating create options.");
9349
 
  context("replication-log",
9350
 
          po::value<bool>(&innobase_use_replication_log)->default_value(false),
9351
 
          _("Enable internal replication log."));
9352
 
  context("lock-wait-timeout",
9353
 
          po::value<lock_wait_constraint>(&lock_wait_timeout)->default_value(50),
9354
 
          _("Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout."));
9355
 
  context("old-blocks-pct",
9356
 
          po::value<old_blocks_constraint>(&innobase_old_blocks_pct)->default_value(100 * 3 / 8),
9357
 
          _("Percentage of the buffer pool to reserve for 'old' blocks."));
9358
 
  context("old-blocks-time",
9359
 
          po::value<uint32_t>(&buf_LRU_old_threshold_ms)->default_value(0),
9360
 
          _("ove blocks to the 'new' end of the buffer pool if the first access"
9361
 
            " was at least this many milliseconds ago."
9362
 
            " The timeout is disabled if 0 (the default)."));
9363
 
}
9364
 
 
9365
 
 
 
8445
        const char*     format_check)   /*!< in: parameter value */
 
8446
{
 
8447
        uint            format_id;
 
8448
        bool            ret = true;
 
8449
 
 
8450
        format_id = innobase_file_format_name_lookup(format_check);
 
8451
 
 
8452
        if (format_id < DICT_TF_FORMAT_MAX + 1) {
 
8453
                srv_check_file_format_at_startup = format_id;
 
8454
        } else {
 
8455
                ret = false;
 
8456
        }
 
8457
 
 
8458
        return(ret);
 
8459
}
 
8460
 
 
8461
/*************************************************************//**
 
8462
Check if it is a valid file format. This function is registered as
 
8463
a callback with MySQL.
 
8464
@return 0 for valid file format */
 
8465
static
 
8466
int
 
8467
innodb_file_format_name_validate(
 
8468
/*=============================*/
 
8469
        Session*                        ,       /*!< in: thread handle */
 
8470
        drizzle_sys_var*        ,       /*!< in: pointer to system
 
8471
                                                variable */
 
8472
        void*                           save,   /*!< out: immediate result
 
8473
                                                for update function */
 
8474
        drizzle_value*          value)  /*!< in: incoming string */
 
8475
{
 
8476
        const char*     file_format_input;
 
8477
        char            buff[STRING_BUFFER_USUAL_SIZE];
 
8478
        int             len = sizeof(buff);
 
8479
 
 
8480
        ut_a(save != NULL);
 
8481
        ut_a(value != NULL);
 
8482
 
 
8483
        file_format_input = value->val_str(value, buff, &len);
 
8484
 
 
8485
        if (file_format_input != NULL) {
 
8486
                uint    format_id;
 
8487
 
 
8488
                format_id = innobase_file_format_name_lookup(
 
8489
                        file_format_input);
 
8490
 
 
8491
                if (format_id <= DICT_TF_FORMAT_MAX) {
 
8492
 
 
8493
                        *static_cast<const char**>(save) = file_format_input;
 
8494
                        return(0);
 
8495
                }
 
8496
        }
 
8497
 
 
8498
        *static_cast<const char**>(save) = NULL;
 
8499
        return(1);
 
8500
}
 
8501
 
 
8502
/****************************************************************//**
 
8503
Update the system variable innodb_file_format using the "saved"
 
8504
value. This function is registered as a callback with MySQL. */
 
8505
static
 
8506
void
 
8507
innodb_file_format_name_update(
 
8508
/*===========================*/
 
8509
        Session*                        ,               /*!< in: thread handle */
 
8510
        drizzle_sys_var*        ,               /*!< in: pointer to
 
8511
                                                        system variable */
 
8512
        void*                           var_ptr,        /*!< out: where the
 
8513
                                                        formal string goes */
 
8514
        const void*                     save)           /*!< in: immediate result
 
8515
                                                        from check function */
 
8516
{
 
8517
        const char* format_name;
 
8518
 
 
8519
        ut_a(var_ptr != NULL);
 
8520
        ut_a(save != NULL);
 
8521
 
 
8522
        format_name = *static_cast<const char*const*>(save);
 
8523
 
 
8524
        if (format_name) {
 
8525
                uint    format_id;
 
8526
 
 
8527
                format_id = innobase_file_format_name_lookup(format_name);
 
8528
 
 
8529
                if (format_id <= DICT_TF_FORMAT_MAX) {
 
8530
                        srv_file_format = format_id;
 
8531
                }
 
8532
        }
 
8533
 
 
8534
        *static_cast<const char**>(var_ptr)
 
8535
                = trx_sys_file_format_id_to_name(srv_file_format);
 
8536
}
 
8537
 
 
8538
/*************************************************************//**
 
8539
Check if valid argument to innodb_file_format_check. This
 
8540
function is registered as a callback with MySQL.
 
8541
@return 0 for valid file format */
 
8542
static
 
8543
int
 
8544
innodb_file_format_check_validate(
 
8545
/*==============================*/
 
8546
        Session*                        ,       /*!< in: thread handle */
 
8547
        drizzle_sys_var*        ,       /*!< in: pointer to system
 
8548
                                                variable */
 
8549
        void*                           save,   /*!< out: immediate result
 
8550
                                                for update function */
 
8551
        drizzle_value*          value)  /*!< in: incoming string */
 
8552
{
 
8553
        const char*     file_format_input;
 
8554
        char            buff[STRING_BUFFER_USUAL_SIZE];
 
8555
        int             len = sizeof(buff);
 
8556
 
 
8557
        ut_a(save != NULL);
 
8558
        ut_a(value != NULL);
 
8559
 
 
8560
        file_format_input = value->val_str(value, buff, &len);
 
8561
 
 
8562
        if (file_format_input != NULL) {
 
8563
 
 
8564
                /* Check if user set on/off, we want to print a suitable
 
8565
                message if they did so. */
 
8566
 
 
8567
                if (innobase_file_format_check_on_off(file_format_input)) {
 
8568
                        errmsg_printf(ERRMSG_LVL_WARN, 
 
8569
                                "InnoDB: invalid innodb_file_format_check "
 
8570
                                "value; on/off can only be set at startup or "
 
8571
                                "in the configuration file");
 
8572
                } else if (innobase_file_format_check_validate(
 
8573
                                file_format_input)) {
 
8574
 
 
8575
                        *static_cast<const char**>(save) = file_format_input;
 
8576
 
 
8577
                        return(0);
 
8578
 
 
8579
                } else {
 
8580
                        errmsg_printf(ERRMSG_LVL_WARN, 
 
8581
                                "InnoDB: invalid innodb_file_format_check "
 
8582
                                "value; can be any format up to %s "
 
8583
                                "or its equivalent numeric id",
 
8584
                                trx_sys_file_format_id_to_name(
 
8585
                                        DICT_TF_FORMAT_MAX));
 
8586
                }
 
8587
        }
 
8588
 
 
8589
        *static_cast<const char**>(save) = NULL;
 
8590
        return(1);
 
8591
}
 
8592
 
 
8593
/****************************************************************//**
 
8594
Update the system variable innodb_file_format_check using the "saved"
 
8595
value. This function is registered as a callback with MySQL. */
 
8596
static
 
8597
void
 
8598
innodb_file_format_check_update(
 
8599
/*============================*/
 
8600
        Session*                        session,        /*!< in: thread handle */
 
8601
        drizzle_sys_var*        ,               /*!< in: pointer to
 
8602
                                                        system variable */
 
8603
        void*                           var_ptr,        /*!< out: where the
 
8604
                                                        formal string goes */
 
8605
        const void*                     save)           /*!< in: immediate result
 
8606
                                                        from check function */
 
8607
{
 
8608
        const char*     format_name_in;
 
8609
        const char**    format_name_out;
 
8610
        uint            format_id;
 
8611
 
 
8612
        ut_a(save != NULL);
 
8613
        ut_a(var_ptr != NULL);
 
8614
 
 
8615
        format_name_in = *static_cast<const char*const*>(save);
 
8616
 
 
8617
        if (!format_name_in) {
 
8618
 
 
8619
                return;
 
8620
        }
 
8621
 
 
8622
        format_id = innobase_file_format_name_lookup(format_name_in);
 
8623
 
 
8624
        if (format_id > DICT_TF_FORMAT_MAX) {
 
8625
                /* DEFAULT is "on", which is invalid at runtime. */
 
8626
                push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
8627
                                    ER_WRONG_ARGUMENTS,
 
8628
                                    "Ignoring SET innodb_file_format=%s",
 
8629
                                    format_name_in);
 
8630
                return;
 
8631
        }
 
8632
 
 
8633
        format_name_out = static_cast<const char**>(var_ptr);
 
8634
 
 
8635
        /* Update the max format id in the system tablespace. */
 
8636
        if (trx_sys_file_format_max_set(format_id, format_name_out)) {
 
8637
                ut_print_timestamp(stderr);
 
8638
                fprintf(stderr,
 
8639
                        " [Info] InnoDB: the file format in the system "
 
8640
                        "tablespace is now set to %s.\n", *format_name_out);
 
8641
        }
 
8642
}
 
8643
 
 
8644
/****************************************************************//**
 
8645
Update the system variable innodb_adaptive_hash_index using the "saved"
 
8646
value. This function is registered as a callback with MySQL. */
 
8647
static
 
8648
void
 
8649
innodb_adaptive_hash_index_update(
 
8650
/*==============================*/
 
8651
        Session*                        ,               /*!< in: thread handle */
 
8652
        drizzle_sys_var*        ,               /*!< in: pointer to
 
8653
                                                        system variable */
 
8654
        void*                           ,       /*!< out: where the
 
8655
                                                        formal string goes */
 
8656
        const void*                     save)           /*!< in: immediate result
 
8657
                                                        from check function */
 
8658
{
 
8659
        if (*(bool*) save) {
 
8660
                btr_search_enable();
 
8661
        } else {
 
8662
                btr_search_disable();
 
8663
        }
 
8664
}
 
8665
 
 
8666
/*************************************************************//**
 
8667
Check if it is a valid value of innodb_change_buffering.  This function is
 
8668
registered as a callback with MySQL.
 
8669
@return 0 for valid innodb_change_buffering */
 
8670
static
 
8671
int
 
8672
innodb_change_buffering_validate(
 
8673
/*=============================*/
 
8674
        Session*                        ,       /*!< in: thread handle */
 
8675
        drizzle_sys_var*        ,       /*!< in: pointer to system
 
8676
                                                variable */
 
8677
        void*                           save,   /*!< out: immediate result
 
8678
                                                for update function */
 
8679
        drizzle_value*          value)  /*!< in: incoming string */
 
8680
{
 
8681
        const char*     change_buffering_input;
 
8682
        char            buff[STRING_BUFFER_USUAL_SIZE];
 
8683
        int             len = sizeof(buff);
 
8684
 
 
8685
        ut_a(save != NULL);
 
8686
        ut_a(value != NULL);
 
8687
 
 
8688
        change_buffering_input = value->val_str(value, buff, &len);
 
8689
 
 
8690
        if (change_buffering_input != NULL) {
 
8691
                ulint   use;
 
8692
 
 
8693
                for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values);
 
8694
                     use++) {
 
8695
                        if (!innobase_strcasecmp(
 
8696
                                    change_buffering_input,
 
8697
                                    innobase_change_buffering_values[use])) {
 
8698
                                *(ibuf_use_t*) save = (ibuf_use_t) use;
 
8699
                                return(0);
 
8700
                        }
 
8701
                }
 
8702
        }
 
8703
 
 
8704
        return(1);
 
8705
}
 
8706
 
 
8707
/****************************************************************//**
 
8708
Update the system variable innodb_change_buffering using the "saved"
 
8709
value. This function is registered as a callback with MySQL. */
 
8710
static
 
8711
void
 
8712
innodb_change_buffering_update(
 
8713
/*===========================*/
 
8714
        Session*                        ,               /*!< in: thread handle */
 
8715
        drizzle_sys_var*        ,               /*!< in: pointer to
 
8716
                                                        system variable */
 
8717
        void*                           var_ptr,        /*!< out: where the
 
8718
                                                        formal string goes */
 
8719
        const void*                     save)           /*!< in: immediate result
 
8720
                                                        from check function */
 
8721
{
 
8722
        ut_a(var_ptr != NULL);
 
8723
        ut_a(save != NULL);
 
8724
        ut_a((*(ibuf_use_t*) save) < IBUF_USE_COUNT);
 
8725
 
 
8726
        ibuf_use = *(const ibuf_use_t*) save;
 
8727
 
 
8728
        *(const char**) var_ptr = innobase_change_buffering_values[ibuf_use];
 
8729
}
 
8730
 
 
8731
static int show_innodb_vars(SHOW_VAR *var, char *)
 
8732
{
 
8733
  innodb_export_status();
 
8734
  var->type= SHOW_ARRAY;
 
8735
  var->value= (char *) &innodb_status_variables;
 
8736
  return 0;
 
8737
}
 
8738
 
 
8739
static st_show_var_func_container
 
8740
show_innodb_vars_cont = { &show_innodb_vars };
 
8741
 
 
8742
static SHOW_VAR innodb_status_variables_export[]= {
 
8743
  {"Innodb",                   (char*) &show_innodb_vars_cont, SHOW_FUNC},
 
8744
  {NULL, NULL, SHOW_LONG}
 
8745
};
 
8746
 
 
8747
 
 
8748
/* plugin options */
 
8749
static DRIZZLE_SYSVAR_BOOL(checksums, innobase_use_checksums,
 
8750
  PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
 
8751
  "Enable InnoDB checksums validation (enabled by default). "
 
8752
  "Disable with --skip-innodb-checksums.",
 
8753
  NULL, NULL, TRUE);
 
8754
 
 
8755
static DRIZZLE_SYSVAR_STR(data_home_dir, innobase_data_home_dir,
 
8756
  PLUGIN_VAR_READONLY,
 
8757
  "The common part for InnoDB table spaces.",
 
8758
  NULL, NULL, NULL);
 
8759
 
 
8760
static DRIZZLE_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite,
 
8761
  PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
 
8762
  "Enable InnoDB doublewrite buffer (enabled by default). "
 
8763
  "Disable with --skip-innodb-doublewrite.",
 
8764
  NULL, NULL, TRUE);
 
8765
 
 
8766
static DRIZZLE_SYSVAR_ULONG(io_capacity, srv_io_capacity,
 
8767
  PLUGIN_VAR_RQCMDARG,
 
8768
  "Number of IOPs the server can do. Tunes the background IO rate",
 
8769
  NULL, NULL, 200, 100, ~0L, 0);
 
8770
 
 
8771
static DRIZZLE_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown,
 
8772
  PLUGIN_VAR_OPCMDARG,
 
8773
  "Speeds up the shutdown process of the InnoDB storage engine. Possible "
 
8774
  "values are 0, 1 (faster)"
 
8775
  " or 2 (fastest - crash-like)"
 
8776
  ".",
 
8777
  NULL, NULL, 1, 0, 2, 0);
 
8778
 
 
8779
static DRIZZLE_SYSVAR_BOOL(file_per_table, srv_file_per_table,
 
8780
  PLUGIN_VAR_NOCMDARG,
 
8781
  "Stores each InnoDB table to an .ibd file in the database dir.",
 
8782
  NULL, NULL, FALSE);
 
8783
 
 
8784
static DRIZZLE_SYSVAR_STR(file_format, innobase_file_format_name,
 
8785
  PLUGIN_VAR_RQCMDARG,
 
8786
  "File format to use for new tables in .ibd files.",
 
8787
  innodb_file_format_name_validate,
 
8788
  innodb_file_format_name_update, "Antelope");
 
8789
 
 
8790
static DRIZZLE_SYSVAR_STR(file_format_check, innobase_file_format_check,
 
8791
  PLUGIN_VAR_OPCMDARG,
 
8792
  "The highest file format in the tablespace.",
 
8793
  innodb_file_format_check_validate,
 
8794
  innodb_file_format_check_update,
 
8795
  "on");
 
8796
 
 
8797
static DRIZZLE_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit,
 
8798
  PLUGIN_VAR_OPCMDARG,
 
8799
  "Set to 0 (write and flush once per second),"
 
8800
  " 1 (write and flush at each commit)"
 
8801
  " or 2 (write at commit, flush once per second).",
 
8802
  NULL, NULL, 1, 0, 2, 0);
 
8803
 
 
8804
static DRIZZLE_SYSVAR_STR(flush_method, innobase_unix_file_flush_method,
 
8805
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8806
  "With which method to flush data.", NULL, NULL, NULL);
 
8807
 
 
8808
static DRIZZLE_SYSVAR_BOOL(locks_unsafe_for_binlog, innobase_locks_unsafe_for_binlog,
 
8809
  PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
 
8810
  "Force InnoDB to not use next-key locking, to use only row-level locking.",
 
8811
  NULL, NULL, TRUE);
 
8812
 
 
8813
#ifdef UNIV_LOG_ARCHIVE
 
8814
static DRIZZLE_SYSVAR_STR(log_arch_dir, innobase_log_arch_dir,
 
8815
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8816
  "Where full logs should be archived.", NULL, NULL, NULL);
 
8817
 
 
8818
static DRIZZLE_SYSVAR_BOOL(log_archive, innobase_log_archive,
 
8819
  PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
 
8820
  "Set to 1 if you want to have logs archived.", NULL, NULL, FALSE);
 
8821
#endif /* UNIV_LOG_ARCHIVE */
 
8822
 
 
8823
static DRIZZLE_SYSVAR_STR(log_group_home_dir, innobase_log_group_home_dir,
 
8824
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8825
  "Path to InnoDB log files.", NULL, NULL, NULL);
 
8826
 
 
8827
static DRIZZLE_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct,
 
8828
  PLUGIN_VAR_RQCMDARG,
 
8829
  "Percentage of dirty pages allowed in bufferpool.",
 
8830
  NULL, NULL, 75, 0, 99, 0);
 
8831
 
 
8832
static DRIZZLE_SYSVAR_BOOL(adaptive_flushing, srv_adaptive_flushing,
 
8833
  PLUGIN_VAR_NOCMDARG,
 
8834
  "Attempt flushing dirty pages to avoid IO bursts at checkpoints.",
 
8835
  NULL, NULL, TRUE);
 
8836
 
 
8837
static DRIZZLE_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag,
 
8838
  PLUGIN_VAR_RQCMDARG,
 
8839
  "Desired maximum length of the purge queue (0 = no limit)",
 
8840
  NULL, NULL, 0, 0, ~0L, 0);
 
8841
 
 
8842
static DRIZZLE_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout,
 
8843
  PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
 
8844
  "Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)",
 
8845
  NULL, NULL, FALSE);
 
8846
 
 
8847
static DRIZZLE_SYSVAR_BOOL(status_file, innobase_create_status_file,
 
8848
  PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_NOSYSVAR,
 
8849
  "Enable SHOW INNODB STATUS output in the innodb_status.<pid> file",
 
8850
  NULL, NULL, FALSE);
 
8851
 
 
8852
static DRIZZLE_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata,
 
8853
  PLUGIN_VAR_OPCMDARG,
 
8854
  "Enable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)",
 
8855
  NULL, NULL, TRUE);
 
8856
 
 
8857
static DRIZZLE_SYSVAR_ULONGLONG(stats_sample_pages, srv_stats_sample_pages,
 
8858
  PLUGIN_VAR_RQCMDARG,
 
8859
  "The number of index pages to sample when calculating statistics (default 8)",
 
8860
  NULL, NULL, 8, 1, ~0ULL, 0);
 
8861
 
 
8862
static DRIZZLE_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
 
8863
  PLUGIN_VAR_OPCMDARG,
 
8864
  "Enable InnoDB adaptive hash index (enabled by default).  "
 
8865
  "Disable with --skip-innodb-adaptive-hash-index.",
 
8866
  NULL, innodb_adaptive_hash_index_update, TRUE);
 
8867
 
 
8868
static DRIZZLE_SYSVAR_ULONG(replication_delay, srv_replication_delay,
 
8869
  PLUGIN_VAR_RQCMDARG,
 
8870
  "Replication thread delay (ms) on the slave server if "
 
8871
  "innodb_thread_concurrency is reached (0 by default)",
 
8872
  NULL, NULL, 0, 0, ~0UL, 0);
 
8873
 
 
8874
static DRIZZLE_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size,
 
8875
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8876
  "Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.",
 
8877
  NULL, NULL, 8*1024*1024L, 512*1024L, LONG_MAX, 1024);
 
8878
 
 
8879
static DRIZZLE_SYSVAR_UINT(autoextend_increment, srv_auto_extend_increment,
 
8880
  PLUGIN_VAR_RQCMDARG,
 
8881
  "Data file autoextend increment in megabytes",
 
8882
  NULL, NULL, 8L, 1L, 1000L, 0);
 
8883
 
 
8884
static DRIZZLE_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size,
 
8885
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8886
  "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
 
8887
  NULL, NULL, 128*1024*1024L, 5*1024*1024L, INT64_MAX, 1024*1024L);
 
8888
 
 
8889
static DRIZZLE_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency,
 
8890
  PLUGIN_VAR_RQCMDARG,
 
8891
  "Helps in performance tuning in heavily concurrent environments.",
 
8892
  innobase_commit_concurrency_validate, NULL, 0, 0, 1000, 0);
 
8893
 
 
8894
static DRIZZLE_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter,
 
8895
  PLUGIN_VAR_RQCMDARG,
 
8896
  "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket",
 
8897
  NULL, NULL, 500L, 1L, ~0L, 0);
 
8898
 
 
8899
static DRIZZLE_SYSVAR_LONG(file_io_threads, innobase_file_io_threads,
 
8900
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8901
  "Number of file I/O threads in InnoDB.",
 
8902
  NULL, NULL, 4, 4, 64, 0);
 
8903
 
 
8904
static DRIZZLE_SYSVAR_ULONG(read_io_threads, innobase_read_io_threads,
 
8905
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8906
  "Number of background read I/O threads in InnoDB.",
 
8907
  NULL, NULL, 4, 1, 64, 0);
 
8908
 
 
8909
static DRIZZLE_SYSVAR_ULONG(write_io_threads, innobase_write_io_threads,
 
8910
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8911
  "Number of background write I/O threads in InnoDB.",
 
8912
  NULL, NULL, 4, 1, 64, 0);
 
8913
 
 
8914
static DRIZZLE_SYSVAR_LONG(force_recovery, innobase_force_recovery,
 
8915
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8916
  "Helps to save your data in case the disk image of the database becomes corrupt.",
 
8917
  NULL, NULL, 0, 0, 6, 0);
 
8918
 
 
8919
static DRIZZLE_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
 
8920
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8921
  "The size of the buffer which InnoDB uses to write log to the log files on disk.",
 
8922
  NULL, NULL, 8*1024*1024L, 256*1024L, LONG_MAX, 1024);
 
8923
 
 
8924
static DRIZZLE_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size,
 
8925
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8926
  "Size of each log file in a log group.",
 
8927
  NULL, NULL, 5*1024*1024L, 1*1024*1024L, INT64_MAX, 1024*1024L);
 
8928
 
 
8929
static DRIZZLE_SYSVAR_LONG(log_files_in_group, innobase_log_files_in_group,
 
8930
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8931
  "Number of log files in the log group. InnoDB writes to the files in a circular fashion. Value 3 is recommended here.",
 
8932
  NULL, NULL, 2, 2, 100, 0);
 
8933
 
 
8934
static DRIZZLE_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups,
 
8935
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8936
  "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
 
8937
  NULL, NULL, 1, 1, 10, 0);
 
8938
 
 
8939
static DRIZZLE_SYSVAR_LONG(open_files, innobase_open_files,
 
8940
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8941
  "How many files at the maximum InnoDB keeps open at the same time.",
 
8942
  NULL, NULL, 300L, 10L, LONG_MAX, 0);
 
8943
 
 
8944
static DRIZZLE_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds,
 
8945
  PLUGIN_VAR_RQCMDARG,
 
8946
  "Count of spin-loop rounds in InnoDB mutexes (30 by default)",
 
8947
  NULL, NULL, 30L, 0L, ~0L, 0);
 
8948
 
 
8949
static DRIZZLE_SYSVAR_ULONG(spin_wait_delay, srv_spin_wait_delay,
 
8950
  PLUGIN_VAR_OPCMDARG,
 
8951
  "Maximum delay between polling for a spin lock (6 by default)",
 
8952
  NULL, NULL, 6L, 0L, ~0L, 0);
 
8953
 
 
8954
static DRIZZLE_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency,
 
8955
  PLUGIN_VAR_RQCMDARG,
 
8956
  "Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.",
 
8957
  NULL, NULL, 0, 0, 1000, 0);
 
8958
 
 
8959
static DRIZZLE_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay,
 
8960
  PLUGIN_VAR_RQCMDARG,
 
8961
  "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep",
 
8962
  NULL, NULL, 10000L, 0L, ~0L, 0);
 
8963
 
 
8964
static DRIZZLE_SYSVAR_STR(data_file_path, innobase_data_file_path,
 
8965
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8966
  "Path to individual files and their sizes.",
 
8967
  NULL, NULL, NULL);
 
8968
 
 
8969
static DRIZZLE_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode,
 
8970
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8971
  "The AUTOINC lock modes supported by InnoDB:               "
 
8972
  "0 => Old style AUTOINC locking (for backward"
 
8973
  " compatibility)                                           "
 
8974
  "1 => New style AUTOINC locking                            "
 
8975
  "2 => No AUTOINC locking (unsafe for SBR)",
 
8976
  NULL, NULL,
 
8977
  AUTOINC_NO_LOCKING,   /* Default setting */
 
8978
  AUTOINC_OLD_STYLE_LOCKING,    /* Minimum value */
 
8979
  AUTOINC_NO_LOCKING, 0);       /* Maximum value */
 
8980
 
 
8981
static DRIZZLE_SYSVAR_STR(version, innodb_version_str,
 
8982
  PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
 
8983
  "InnoDB version", NULL, NULL, INNODB_VERSION_STR);
 
8984
 
 
8985
static DRIZZLE_SYSVAR_BOOL(use_sys_malloc, srv_use_sys_malloc,
 
8986
  PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
 
8987
  "Use OS memory allocator instead of InnoDB's internal memory allocator",
 
8988
  NULL, NULL, TRUE);
 
8989
 
 
8990
static DRIZZLE_SYSVAR_STR(change_buffering, innobase_change_buffering,
 
8991
  PLUGIN_VAR_RQCMDARG,
 
8992
  "Buffer changes to reduce random access: "
 
8993
  "OFF, ON, inserting, deleting, changing, or purging.",
 
8994
  innodb_change_buffering_validate,
 
8995
  innodb_change_buffering_update, NULL);
 
8996
 
 
8997
static DRIZZLE_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold,
 
8998
  PLUGIN_VAR_RQCMDARG,
 
8999
  "Number of pages that must be accessed sequentially for InnoDB to"
 
9000
  "trigger a readahead.",
 
9001
  NULL, NULL, 56, 0, 64, 0);
 
9002
 
 
9003
static drizzle_sys_var* innobase_system_variables[]= {
 
9004
  DRIZZLE_SYSVAR(additional_mem_pool_size),
 
9005
  DRIZZLE_SYSVAR(autoextend_increment),
 
9006
  DRIZZLE_SYSVAR(buffer_pool_size),
 
9007
  DRIZZLE_SYSVAR(checksums),
 
9008
  DRIZZLE_SYSVAR(commit_concurrency),
 
9009
  DRIZZLE_SYSVAR(concurrency_tickets),
 
9010
  DRIZZLE_SYSVAR(data_file_path),
 
9011
  DRIZZLE_SYSVAR(data_home_dir),
 
9012
  DRIZZLE_SYSVAR(doublewrite),
 
9013
  DRIZZLE_SYSVAR(fast_shutdown),
 
9014
  DRIZZLE_SYSVAR(file_io_threads),
 
9015
  DRIZZLE_SYSVAR(read_io_threads),
 
9016
  DRIZZLE_SYSVAR(write_io_threads),
 
9017
  DRIZZLE_SYSVAR(file_per_table),
 
9018
  DRIZZLE_SYSVAR(file_format),
 
9019
  DRIZZLE_SYSVAR(file_format_check),
 
9020
  DRIZZLE_SYSVAR(flush_log_at_trx_commit),
 
9021
  DRIZZLE_SYSVAR(flush_method),
 
9022
  DRIZZLE_SYSVAR(force_recovery),
 
9023
  DRIZZLE_SYSVAR(locks_unsafe_for_binlog),
 
9024
  DRIZZLE_SYSVAR(lock_wait_timeout),
 
9025
#ifdef UNIV_LOG_ARCHIVE
 
9026
  DRIZZLE_SYSVAR(log_arch_dir),
 
9027
  DRIZZLE_SYSVAR(log_archive),
 
9028
#endif /* UNIV_LOG_ARCHIVE */
 
9029
  DRIZZLE_SYSVAR(log_buffer_size),
 
9030
  DRIZZLE_SYSVAR(log_file_size),
 
9031
  DRIZZLE_SYSVAR(log_files_in_group),
 
9032
  DRIZZLE_SYSVAR(log_group_home_dir),
 
9033
  DRIZZLE_SYSVAR(max_dirty_pages_pct),
 
9034
  DRIZZLE_SYSVAR(max_purge_lag),
 
9035
  DRIZZLE_SYSVAR(adaptive_flushing),
 
9036
  DRIZZLE_SYSVAR(mirrored_log_groups),
 
9037
  DRIZZLE_SYSVAR(open_files),
 
9038
  DRIZZLE_SYSVAR(rollback_on_timeout),
 
9039
  DRIZZLE_SYSVAR(stats_on_metadata),
 
9040
  DRIZZLE_SYSVAR(stats_sample_pages),
 
9041
  DRIZZLE_SYSVAR(adaptive_hash_index),
 
9042
  DRIZZLE_SYSVAR(replication_delay),
 
9043
  DRIZZLE_SYSVAR(status_file),
 
9044
  DRIZZLE_SYSVAR(strict_mode),
 
9045
  DRIZZLE_SYSVAR(support_xa),
 
9046
  DRIZZLE_SYSVAR(sync_spin_loops),
 
9047
  DRIZZLE_SYSVAR(spin_wait_delay),
 
9048
  DRIZZLE_SYSVAR(table_locks),
 
9049
  DRIZZLE_SYSVAR(thread_concurrency),
 
9050
  DRIZZLE_SYSVAR(thread_sleep_delay),
 
9051
  DRIZZLE_SYSVAR(autoinc_lock_mode),
 
9052
  DRIZZLE_SYSVAR(version),
 
9053
  DRIZZLE_SYSVAR(use_sys_malloc),
 
9054
  DRIZZLE_SYSVAR(change_buffering),
 
9055
  DRIZZLE_SYSVAR(read_ahead_threshold),
 
9056
  DRIZZLE_SYSVAR(io_capacity),
 
9057
  NULL
 
9058
};
9366
9059
 
9367
9060
DRIZZLE_DECLARE_PLUGIN
9368
9061
{
9373
9066
  "Supports transactions, row-level locking, and foreign keys",
9374
9067
  PLUGIN_LICENSE_GPL,
9375
9068
  innobase_init, /* Plugin Init */
9376
 
  NULL, /* system variables */
9377
 
  init_options /* reserved */
 
9069
  innobase_deinit, /* Plugin Deinit */
 
9070
  innodb_status_variables_export,/* status variables             */
 
9071
  innobase_system_variables, /* system variables */
 
9072
  NULL /* reserved */
9378
9073
}
9379
9074
DRIZZLE_DECLARE_PLUGIN_END;
9380
9075
 
9381
9076
int ha_innobase::read_range_first(const key_range *start_key,
9382
 
          const key_range *end_key,
9383
 
          bool eq_range_arg,
9384
 
          bool sorted)
 
9077
                                  const key_range *end_key,
 
9078
                                  bool eq_range_arg,
 
9079
                                  bool sorted)
9385
9080
{
9386
9081
  int res;
9387
9082
  //if (!eq_range_arg)
9401
9096
  return res;
9402
9097
}
9403
9098
 
9404
 
/***********************************************************************
9405
 
This function checks each index name for a table against reserved
9406
 
system default primary index name 'GEN_CLUST_INDEX'. If a name matches,
9407
 
this function pushes an warning message to the client, and returns true. */
9408
 
extern "C" UNIV_INTERN
9409
 
bool
9410
 
innobase_index_name_is_reserved(
9411
 
/*============================*/
9412
 
                                        /* out: true if an index name
9413
 
                                        matches the reserved name */
9414
 
        const trx_t*    trx,            /* in: InnoDB transaction handle */
9415
 
        const KeyInfo*  key_info,       /* in: Indexes to be created */
9416
 
        ulint           num_of_keys)    /* in: Number of indexes to
9417
 
                                        be created. */
 
9099
/** @brief Initialize the default value of innodb_commit_concurrency.
 
9100
 
 
9101
Once InnoDB is running, the innodb_commit_concurrency must not change
 
9102
from zero to nonzero. (Bug #42101)
 
9103
 
 
9104
The initial default value is 0, and without this extra initialization,
 
9105
SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
 
9106
to 0, even if it was initially set to nonzero at the command line
 
9107
or configuration file. */
 
9108
static
 
9109
void
 
9110
innobase_commit_concurrency_init_default(void)
 
9111
/*==========================================*/
9418
9112
{
9419
 
  const KeyInfo*        key;
9420
 
  uint          key_num;        /* index number */
9421
 
 
9422
 
  for (key_num = 0; key_num < num_of_keys; key_num++) {
9423
 
    key = &key_info[key_num];
9424
 
 
9425
 
    if (innobase_strcasecmp(key->name,
9426
 
                            innobase_index_reserve_name) == 0) {
9427
 
      /* Push warning to drizzle */
9428
 
      push_warning_printf((Session*)trx->mysql_thd,
9429
 
                          DRIZZLE_ERROR::WARN_LEVEL_WARN,
9430
 
                          ER_WRONG_NAME_FOR_INDEX,
9431
 
                          "Cannot Create Index with name "
9432
 
                          "'%s'. The name is reserved "
9433
 
                          "for the system default primary "
9434
 
                          "index.",
9435
 
                          innobase_index_reserve_name);
9436
 
 
9437
 
      my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
9438
 
               innobase_index_reserve_name);
9439
 
 
9440
 
      return(true);
9441
 
    }
9442
 
  }
9443
 
 
9444
 
  return(false);
 
9113
        DRIZZLE_SYSVAR_NAME(commit_concurrency).def_val
 
9114
                = innobase_commit_concurrency;
9445
9115
}
9446
9116
 
9447
9117
#ifdef UNIV_COMPILE_TEST_FUNCS
9448
9118
 
9449
9119
typedef struct innobase_convert_name_test_struct {
9450
 
  char*   buf;
9451
 
  ulint   buflen;
9452
 
  const char* id;
9453
 
  ulint   idlen;
9454
 
  void*   session;
9455
 
  ibool   file_id;
 
9120
        char*           buf;
 
9121
        ulint           buflen;
 
9122
        const char*     id;
 
9123
        ulint           idlen;
 
9124
        void*           session;
 
9125
        ibool           file_id;
9456
9126
 
9457
 
  const char* expected;
 
9127
        const char*     expected;
9458
9128
} innobase_convert_name_test_t;
9459
9129
 
9460
9130
void
9461
9131
test_innobase_convert_name()
9462
9132
{
9463
 
  char  buf[1024];
9464
 
  ulint i;
9465
 
 
9466
 
  innobase_convert_name_test_t test_input[] = {
9467
 
    {buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
9468
 
    {buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
9469
 
    {buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
9470
 
    {buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
9471
 
    {buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
9472
 
 
9473
 
    {buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9474
 
    {buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9475
 
    {buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9476
 
    {buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
9477
 
    {buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
9478
 
    {buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
9479
 
    {buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
9480
 
 
9481
 
    {buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
9482
 
      "\"#mysql50#ab\"\"cd\""},
9483
 
    {buf, 17, "ab\"cd", 5, NULL, TRUE,
9484
 
      "\"#mysql50#ab\"\"cd\""},
9485
 
    {buf, 16, "ab\"cd", 5, NULL, TRUE,
9486
 
      "\"#mysql50#ab\"\"c\""},
9487
 
    {buf, 15, "ab\"cd", 5, NULL, TRUE,
9488
 
      "\"#mysql50#ab\"\"\""},
9489
 
    {buf, 14, "ab\"cd", 5, NULL, TRUE,
9490
 
      "\"#mysql50#ab\""},
9491
 
    {buf, 13, "ab\"cd", 5, NULL, TRUE,
9492
 
      "\"#mysql50#ab\""},
9493
 
    {buf, 12, "ab\"cd", 5, NULL, TRUE,
9494
 
      "\"#mysql50#a\""},
9495
 
    {buf, 11, "ab\"cd", 5, NULL, TRUE,
9496
 
      "\"#mysql50#\""},
9497
 
    {buf, 10, "ab\"cd", 5, NULL, TRUE,
9498
 
      "\"#mysql50\""},
9499
 
 
9500
 
    {buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
9501
 
    {buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
9502
 
    {buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
9503
 
    {buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
9504
 
    {buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9505
 
    {buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9506
 
    {buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
9507
 
    {buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
9508
 
    {buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
9509
 
    /* XXX probably "" is a better result in this case
9510
 
    {buf, 1, "ab/cd", 5, NULL, TRUE, "."},
9511
 
    */
9512
 
    {buf, 0, "ab/cd", 5, NULL, TRUE, ""},
9513
 
  };
9514
 
 
9515
 
  for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
9516
 
 
9517
 
    char* end;
9518
 
    ibool ok = TRUE;
9519
 
    size_t  res_len;
9520
 
 
9521
 
    fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
9522
 
      test_input[i].buflen,
9523
 
      test_input[i].id,
9524
 
      test_input[i].idlen,
9525
 
      test_input[i].expected);
9526
 
 
9527
 
    end = innobase_convert_name(
9528
 
      test_input[i].buf,
9529
 
      test_input[i].buflen,
9530
 
      test_input[i].id,
9531
 
      test_input[i].idlen,
9532
 
      test_input[i].session,
9533
 
      test_input[i].file_id);
9534
 
 
9535
 
    res_len = (size_t) (end - test_input[i].buf);
9536
 
 
9537
 
    if (res_len != strlen(test_input[i].expected)) {
9538
 
 
9539
 
      fprintf(stderr, "unexpected len of the result: %u, "
9540
 
        "expected: %u\n", (unsigned) res_len,
9541
 
        (unsigned) strlen(test_input[i].expected));
9542
 
      ok = FALSE;
9543
 
    }
9544
 
 
9545
 
    if (memcmp(test_input[i].buf,
9546
 
         test_input[i].expected,
9547
 
         strlen(test_input[i].expected)) != 0
9548
 
        || !ok) {
9549
 
 
9550
 
      fprintf(stderr, "unexpected result: %.*s, "
9551
 
        "expected: %s\n", (int) res_len,
9552
 
        test_input[i].buf,
9553
 
        test_input[i].expected);
9554
 
      ok = FALSE;
9555
 
    }
9556
 
 
9557
 
    if (ok) {
9558
 
      fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
9559
 
        buf);
9560
 
    } else {
9561
 
      fprintf(stderr, "FAILED\n\n");
9562
 
      return;
9563
 
    }
9564
 
  }
 
9133
        char    buf[1024];
 
9134
        ulint   i;
 
9135
 
 
9136
        innobase_convert_name_test_t test_input[] = {
 
9137
                {buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
 
9138
                {buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
 
9139
                {buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
 
9140
                {buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
 
9141
                {buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
 
9142
 
 
9143
                {buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
 
9144
                {buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
 
9145
                {buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
 
9146
                {buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
 
9147
                {buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
 
9148
                {buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
 
9149
                {buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
 
9150
 
 
9151
                {buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
 
9152
                        "\"#mysql50#ab\"\"cd\""},
 
9153
                {buf, 17, "ab\"cd", 5, NULL, TRUE,
 
9154
                        "\"#mysql50#ab\"\"cd\""},
 
9155
                {buf, 16, "ab\"cd", 5, NULL, TRUE,
 
9156
                        "\"#mysql50#ab\"\"c\""},
 
9157
                {buf, 15, "ab\"cd", 5, NULL, TRUE,
 
9158
                        "\"#mysql50#ab\"\"\""},
 
9159
                {buf, 14, "ab\"cd", 5, NULL, TRUE,
 
9160
                        "\"#mysql50#ab\""},
 
9161
                {buf, 13, "ab\"cd", 5, NULL, TRUE,
 
9162
                        "\"#mysql50#ab\""},
 
9163
                {buf, 12, "ab\"cd", 5, NULL, TRUE,
 
9164
                        "\"#mysql50#a\""},
 
9165
                {buf, 11, "ab\"cd", 5, NULL, TRUE,
 
9166
                        "\"#mysql50#\""},
 
9167
                {buf, 10, "ab\"cd", 5, NULL, TRUE,
 
9168
                        "\"#mysql50\""},
 
9169
 
 
9170
                {buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
 
9171
                {buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
 
9172
                {buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
 
9173
                {buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
 
9174
                {buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
 
9175
                {buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
 
9176
                {buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
 
9177
                {buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
 
9178
                {buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
 
9179
                /* XXX probably "" is a better result in this case
 
9180
                {buf, 1, "ab/cd", 5, NULL, TRUE, "."},
 
9181
                */
 
9182
                {buf, 0, "ab/cd", 5, NULL, TRUE, ""},
 
9183
        };
 
9184
 
 
9185
        for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
 
9186
 
 
9187
                char*   end;
 
9188
                ibool   ok = TRUE;
 
9189
                size_t  res_len;
 
9190
 
 
9191
                fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
 
9192
                        test_input[i].buflen,
 
9193
                        test_input[i].id,
 
9194
                        test_input[i].idlen,
 
9195
                        test_input[i].expected);
 
9196
 
 
9197
                end = innobase_convert_name(
 
9198
                        test_input[i].buf,
 
9199
                        test_input[i].buflen,
 
9200
                        test_input[i].id,
 
9201
                        test_input[i].idlen,
 
9202
                        test_input[i].session,
 
9203
                        test_input[i].file_id);
 
9204
 
 
9205
                res_len = (size_t) (end - test_input[i].buf);
 
9206
 
 
9207
                if (res_len != strlen(test_input[i].expected)) {
 
9208
 
 
9209
                        fprintf(stderr, "unexpected len of the result: %u, "
 
9210
                                "expected: %u\n", (unsigned) res_len,
 
9211
                                (unsigned) strlen(test_input[i].expected));
 
9212
                        ok = FALSE;
 
9213
                }
 
9214
 
 
9215
                if (memcmp(test_input[i].buf,
 
9216
                           test_input[i].expected,
 
9217
                           strlen(test_input[i].expected)) != 0
 
9218
                    || !ok) {
 
9219
 
 
9220
                        fprintf(stderr, "unexpected result: %.*s, "
 
9221
                                "expected: %s\n", (int) res_len,
 
9222
                                test_input[i].buf,
 
9223
                                test_input[i].expected);
 
9224
                        ok = FALSE;
 
9225
                }
 
9226
 
 
9227
                if (ok) {
 
9228
                        fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
 
9229
                                buf);
 
9230
                } else {
 
9231
                        fprintf(stderr, "FAILED\n\n");
 
9232
                        return;
 
9233
                }
 
9234
        }
9565
9235
}
9566
9236
 
9567
9237
#endif /* UNIV_COMPILE_TEST_FUNCS */