Drizzled Public API Documentation

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