2005-10-27 09:29:40 +02:00
/* Copyright (C) 2000-2005 MySQL AB & Innobase Oy
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-01-11 10:36:27 +01:00
the Free Software Foundation ; version 2 of the License .
2005-10-27 09:29:40 +02:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2006-02-21 13:37:54 +01:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
2005-10-27 09:29:40 +02:00
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
2006-02-21 13:37:54 +01:00
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA */
2005-10-27 09:29:40 +02:00
/* This file defines the InnoDB handler: the interface between MySQL and InnoDB
NOTE : You can only use noninlined InnoDB functions in this file , because we
2007-04-12 13:19:36 +02:00
have disabled the InnoDB inlining in this file . */
2005-10-27 09:29:40 +02:00
/* TODO list for the InnoDB handler in 5.0:
2007-05-10 13:31:36 +02:00
- Remove the flag trx - > active_trans and look at trx - > conc_state
2005-10-27 09:29:40 +02:00
- fix savepoint functions to use savepoint storage area
- Find out what kind of problems the OS X case - insensitivity causes to
table and database names ; should we ' normalize ' the names like we do
in Windows ?
*/
# ifdef USE_PRAGMA_IMPLEMENTATION
# pragma implementation // gcc: Class implementation
# endif
2006-09-11 10:58:43 +02:00
# include <mysql_priv.h>
2007-04-11 03:34:33 +02:00
# include <mysqld_error.h>
2005-10-27 09:29:40 +02:00
# include <m_ctype.h>
# include <hash.h>
# include <myisampack.h>
# include <mysys_err.h>
# include <my_sys.h>
# include "ha_innodb.h"
2007-05-10 13:31:36 +02:00
# include <mysql/plugin.h>
/** to protect innobase_open_files */
static pthread_mutex_t innobase_share_mutex ;
/** to force correct commit order in binlog */
static pthread_mutex_t prepare_commit_mutex ;
static ulong commit_threads = 0 ;
static pthread_mutex_t commit_threads_m ;
static pthread_cond_t commit_cond ;
static pthread_mutex_t commit_cond_m ;
2009-10-01 13:55:49 +02:00
static pthread_mutex_t analyze_mutex ;
2007-05-10 13:31:36 +02:00
static bool innodb_inited = 0 ;
2005-10-27 09:29:40 +02:00
2006-10-03 14:46:23 +02:00
/*
This needs to exist until the query cache callback is removed
or learns to pass hton .
*/
2007-05-10 13:31:36 +02:00
static handlerton * innodb_hton_ptr ;
2006-10-03 14:46:23 +02:00
2005-10-27 09:29:40 +02:00
# define INSIDE_HA_INNOBASE_CC
/* Include necessary InnoDB headers */
extern " C " {
2007-07-31 07:56:17 +02:00
# include "../storage/innobase/include/univ.i"
# include "../storage/innobase/include/os0file.h"
# include "../storage/innobase/include/os0thread.h"
# include "../storage/innobase/include/srv0start.h"
# include "../storage/innobase/include/srv0srv.h"
# include "../storage/innobase/include/trx0roll.h"
# include "../storage/innobase/include/trx0trx.h"
# include "../storage/innobase/include/trx0sys.h"
# include "../storage/innobase/include/mtr0mtr.h"
# include "../storage/innobase/include/row0ins.h"
# include "../storage/innobase/include/row0mysql.h"
# include "../storage/innobase/include/row0sel.h"
# include "../storage/innobase/include/row0upd.h"
# include "../storage/innobase/include/log0log.h"
# include "../storage/innobase/include/lock0lock.h"
# include "../storage/innobase/include/dict0crea.h"
# include "../storage/innobase/include/btr0cur.h"
# include "../storage/innobase/include/btr0btr.h"
# include "../storage/innobase/include/fsp0fsp.h"
# include "../storage/innobase/include/sync0sync.h"
# include "../storage/innobase/include/fil0fil.h"
# include "../storage/innobase/include/trx0xa.h"
# include "../storage/innobase/include/thr0loc.h"
# include "../storage/innobase/include/ha_prototypes.h"
2005-10-27 09:29:40 +02:00
}
2007-08-20 23:48:16 +02:00
static const long AUTOINC_OLD_STYLE_LOCKING = 0 ;
static const long AUTOINC_NEW_STYLE_LOCKING = 1 ;
static const long AUTOINC_NO_LOCKING = 2 ;
2007-05-10 13:31:36 +02:00
static long innobase_mirrored_log_groups , innobase_log_files_in_group ,
2006-02-21 13:37:54 +01:00
innobase_log_buffer_size , innobase_buffer_pool_awe_mem_mb ,
innobase_additional_mem_pool_size , innobase_file_io_threads ,
innobase_lock_wait_timeout , innobase_force_recovery ,
2007-08-20 23:48:16 +02:00
innobase_open_files , innobase_autoinc_lock_mode ;
2009-05-14 13:04:55 +02:00
static ulong innobase_commit_concurrency = 0 ;
2005-11-29 12:10:15 +01:00
2007-05-11 17:38:34 +02:00
static long long innobase_buffer_pool_size , innobase_log_file_size ;
2005-10-27 09:29:40 +02:00
/* The default values for the following char* start-up parameters
are determined in innobase_init below : */
2006-02-21 13:37:54 +01:00
2007-05-10 13:31:36 +02:00
static char * innobase_data_home_dir = NULL ;
static char * innobase_data_file_path = NULL ;
static char * innobase_log_group_home_dir = NULL ;
2005-10-27 09:29:40 +02:00
/* The following has a misleading name: starting from 4.0.5, this also
affects Windows : */
2007-05-10 13:31:36 +02:00
static char * innobase_unix_file_flush_method = NULL ;
2005-10-27 09:29:40 +02:00
/* Below we have boolean-valued start-up parameters, and their default
values */
2007-05-10 13:31:36 +02:00
static ulong innobase_fast_shutdown = 1 ;
# ifdef UNIV_LOG_ARCHIVE
static my_bool innobase_log_archive = FALSE ;
static char * innobase_log_arch_dir = NULL ;
# endif /* UNIV_LOG_ARCHIVE */
static my_bool innobase_use_doublewrite = TRUE ;
static my_bool innobase_use_checksums = TRUE ;
static my_bool innobase_file_per_table = FALSE ;
static my_bool innobase_locks_unsafe_for_binlog = FALSE ;
static my_bool innobase_rollback_on_timeout = FALSE ;
static my_bool innobase_create_status_file = FALSE ;
2008-10-28 11:10:25 +01:00
static my_bool innobase_stats_on_metadata = TRUE ;
2008-02-05 14:29:30 +01:00
static my_bool innobase_adaptive_hash_index = TRUE ;
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
static char * internal_innobase_data_file_path = NULL ;
2005-10-27 09:29:40 +02:00
/* The following counter is used to convey information to InnoDB
about server activity : in selects it is not sensible to call
srv_active_wake_master_thread after each fetch or search , we only do
it every INNOBASE_WAKE_INTERVAL ' th step . */
# define INNOBASE_WAKE_INTERVAL 32
2007-03-08 08:54:54 +01:00
static ulong innobase_active_counter = 0 ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
static HASH innobase_open_tables ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
# ifdef __NETWARE__ /* some special cleanup for NetWare */
2005-10-27 09:29:40 +02:00
bool nw_panic = FALSE ;
# endif
2007-08-15 14:29:46 +02:00
static uchar * innobase_get_key ( INNOBASE_SHARE * share , size_t * length ,
2006-02-21 13:37:54 +01:00
my_bool not_used __attribute__ ( ( unused ) ) ) ;
2005-10-27 09:29:40 +02:00
static INNOBASE_SHARE * get_share ( const char * table_name ) ;
static void free_share ( INNOBASE_SHARE * share ) ;
2006-10-03 14:46:23 +02:00
static int innobase_close_connection ( handlerton * hton , THD * thd ) ;
static int innobase_commit ( handlerton * hton , THD * thd , bool all ) ;
static int innobase_rollback ( handlerton * hton , THD * thd , bool all ) ;
2009-09-15 01:39:21 +02:00
static int innobase_rollback_to_savepoint ( handlerton * hton , THD * thd ,
2006-10-03 14:46:23 +02:00
void * savepoint ) ;
static int innobase_savepoint ( handlerton * hton , THD * thd , void * savepoint ) ;
2009-09-15 01:39:21 +02:00
static int innobase_release_savepoint ( handlerton * hton , THD * thd ,
2006-10-03 14:46:23 +02:00
void * savepoint ) ;
static handler * innobase_create_handler ( handlerton * hton ,
TABLE_SHARE * table ,
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
MEM_ROOT * mem_root ) ;
2005-10-27 09:29:40 +02:00
2009-09-15 01:39:21 +02:00
/***********************************************************************
This function checks each index name for a table against reserved
system default primary index name ' GEN_CLUST_INDEX ' . If a name matches ,
this function pushes an error message to the client , and returns true . */
static
bool
innobase_index_name_is_reserved (
/*============================*/
/* out: true if index name matches a
reserved name */
const trx_t * trx , /* in: InnoDB transaction handle */
const TABLE * form , /* in: information on table
columns and indexes */
const char * norm_name ) ; /* in: table name */
2006-05-08 10:08:27 +02:00
static const char innobase_hton_name [ ] = " InnoDB " ;
2005-10-27 09:29:40 +02:00
2009-09-15 01:39:21 +02:00
/* "GEN_CLUST_INDEX" is the name reserved for Innodb default
system primary index . */
static const char innobase_index_reserve_name [ ] = " GEN_CLUST_INDEX " ;
2009-06-25 14:11:57 +02:00
/** @brief Initialize the default value of innodb_commit_concurrency.
Once InnoDB is running , the innodb_commit_concurrency must not change
from zero to nonzero . ( Bug # 42101 )
The initial default value is 0 , and without this extra initialization ,
SET GLOBAL innodb_commit_concurrency = DEFAULT would set the parameter
to 0 , even if it was initially set to nonzero at the command line
or configuration file . */
static
void
innobase_commit_concurrency_init_default ( void ) ;
/*==========================================*/
2009-05-14 13:04:55 +02:00
/*****************************************************************
Check for a valid value of innobase_commit_concurrency . */
static
int
innobase_commit_concurrency_validate (
/*=================================*/
/* out: 0 for valid
innodb_commit_concurrency */
THD * thd , /* in: thread handle */
struct st_mysql_sys_var * var , /* in: pointer to system
variable */
void * save , /* out: immediate result
for update function */
struct st_mysql_value * value ) /* in: incoming string */
{
long long intbuf ;
ulong commit_concurrency ;
DBUG_ENTER ( " innobase_commit_concurrency_validate " ) ;
if ( value - > val_int ( value , & intbuf ) ) {
/* The value is NULL. That is invalid. */
DBUG_RETURN ( 1 ) ;
}
* reinterpret_cast < ulong * > ( save ) = commit_concurrency
= static_cast < ulong > ( intbuf ) ;
/* Allow the value to be updated, as long as it remains zero
or nonzero . */
DBUG_RETURN ( ! ( ! commit_concurrency = = ! innobase_commit_concurrency ) ) ;
}
2007-05-10 13:31:36 +02:00
static MYSQL_THDVAR_BOOL ( support_xa , PLUGIN_VAR_OPCMDARG ,
" Enable InnoDB support for the XA two-phase commit " ,
/* check_func */ NULL , /* update_func */ NULL ,
/* default */ TRUE ) ;
static MYSQL_THDVAR_BOOL ( table_locks , PLUGIN_VAR_OPCMDARG ,
" Enable InnoDB locking in LOCK TABLES " ,
/* check_func */ NULL , /* update_func */ NULL ,
/* default */ TRUE ) ;
2006-10-03 14:46:23 +02:00
static handler * innobase_create_handler ( handlerton * hton ,
2010-03-30 09:39:02 +02:00
TABLE_SHARE * table ,
2006-10-03 14:46:23 +02:00
MEM_ROOT * mem_root )
2005-10-27 09:51:34 +02:00
{
2006-10-03 14:46:23 +02:00
return new ( mem_root ) ha_innobase ( hton , table ) ;
2005-10-27 09:51:34 +02:00
}
2007-02-12 14:08:02 +01:00
/***********************************************************************
This function is used to prepare X / Open XA distributed transaction */
static
int
innobase_xa_prepare (
/*================*/
/* out: 0 or error number */
handlerton * hton ,
THD * thd , /* in: handle to the MySQL thread of the user
whose XA transaction should be prepared */
bool all ) ; /* in: TRUE - commit transaction
FALSE - the current SQL statement ended */
/***********************************************************************
This function is used to recover X / Open XA distributed transactions */
static
int
innobase_xa_recover (
/*================*/
/* out: number of prepared transactions
stored in xid_list */
handlerton * hton ,
XID * xid_list , /* in/out: prepared transactions */
uint len ) ; /* in: number of slots in xid_list */
/***********************************************************************
This function is used to commit one X / Open XA distributed transaction
which is in the prepared state */
static
int
innobase_commit_by_xid (
/*===================*/
/* out: 0 or error number */
handlerton * hton ,
XID * xid ) ; /* in: X/Open XA transaction identification */
/***********************************************************************
This function is used to rollback one X / Open XA distributed transaction
which is in the prepared state */
static
int
innobase_rollback_by_xid (
/*=====================*/
/* out: 0 or error number */
handlerton * hton ,
XID * xid ) ; /* in: X/Open XA transaction identification */
/***********************************************************************
Create a consistent view for a cursor based on current transaction
which is created if the corresponding MySQL thread still lacks one .
This consistent view is then used inside of MySQL when accessing records
using a cursor . */
static
void *
innobase_create_cursor_view (
/*========================*/
/* out: pointer to cursor view or NULL */
handlerton * hton , /* in: innobase hton */
THD * thd ) ; /* in: user thread handle */
/***********************************************************************
Set the given consistent cursor view to a transaction which is created
if the corresponding MySQL thread still lacks one . If the given
consistent cursor view is NULL global read view of a transaction is
restored to a transaction read view . */
static
void
innobase_set_cursor_view (
/*=====================*/
handlerton * hton ,
THD * thd , /* in: user thread handle */
void * curview ) ; /* in: Consistent cursor view to be set */
/***********************************************************************
Close the given consistent cursor view of a transaction and restore
global read view to a transaction read view . Transaction is created if the
corresponding MySQL thread still lacks one . */
static
void
innobase_close_cursor_view (
/*=======================*/
handlerton * hton ,
THD * thd , /* in: user thread handle */
void * curview ) ; /* in: Consistent read view to be closed */
/*********************************************************************
Removes all tables in the named database inside InnoDB . */
static
void
innobase_drop_database (
/*===================*/
/* out: error number */
handlerton * hton , /* in: handlerton of Innodb */
char * path ) ; /* in: database path; inside InnoDB the name
of the last directory in the path is used as
the database name : for example , in ' mysql / data / test '
the database name is ' test ' */
/***********************************************************************
Closes an InnoDB database . */
static
int
innobase_end ( handlerton * hton , ha_panic_function type ) ;
/*********************************************************************
Creates an InnoDB transaction struct for the thd if it does not yet have one .
Starts a new InnoDB transaction if a transaction is not yet started . And
assigns a new snapshot for a consistent read if the transaction does not yet
have one . */
static
int
innobase_start_trx_and_assign_read_view (
/*====================================*/
/* out: 0 */
handlerton * hton , /* in: Innodb handlerton */
THD * thd ) ; /* in: MySQL thread handle of the user for whom
the transaction should be committed */
/********************************************************************
Flushes InnoDB logs to disk and makes a checkpoint . Really , a commit flushes
the logs , and the name of this function should be innobase_checkpoint . */
static
bool
innobase_flush_logs (
/*================*/
/* out: TRUE if error */
handlerton * hton ) ; /* in: InnoDB handlerton */
/****************************************************************************
Implements the SHOW INNODB STATUS command . Sends the output of the InnoDB
Monitor to the client . */
static
bool
innodb_show_status (
/*===============*/
handlerton * hton , /* in: the innodb handlerton */
THD * thd , /* in: the MySQL query thread of the caller */
stat_print_fn * stat_print ) ;
static
bool innobase_show_status ( handlerton * hton , THD * thd ,
stat_print_fn * stat_print ,
enum ha_stat_type stat_type ) ;
2005-10-27 09:51:34 +02:00
2005-10-27 09:29:40 +02:00
/*********************************************************************
Commits a transaction in an InnoDB database . */
2007-03-27 10:22:27 +02:00
static
2005-10-27 09:29:40 +02:00
void
innobase_commit_low (
/*================*/
trx_t * trx ) ; /* in: transaction handle */
2007-03-27 10:22:27 +02:00
static SHOW_VAR innodb_status_variables [ ] = {
2005-10-27 09:29:40 +02:00
{ " buffer_pool_pages_data " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_buffer_pool_pages_data , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " buffer_pool_pages_dirty " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_buffer_pool_pages_dirty , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " buffer_pool_pages_flushed " ,
( char * ) & export_vars . innodb_buffer_pool_pages_flushed , SHOW_LONG } ,
{ " buffer_pool_pages_free " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_buffer_pool_pages_free , SHOW_LONG } ,
2008-05-19 15:59:42 +02:00
# ifdef UNIV_DEBUG
2005-10-27 09:29:40 +02:00
{ " buffer_pool_pages_latched " ,
( char * ) & export_vars . innodb_buffer_pool_pages_latched , SHOW_LONG } ,
2008-05-19 15:59:42 +02:00
# endif /* UNIV_DEBUG */
2005-10-27 09:29:40 +02:00
{ " buffer_pool_pages_misc " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_buffer_pool_pages_misc , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " buffer_pool_pages_total " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_buffer_pool_pages_total , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " buffer_pool_read_ahead_rnd " ,
( char * ) & export_vars . innodb_buffer_pool_read_ahead_rnd , SHOW_LONG } ,
{ " buffer_pool_read_ahead_seq " ,
( char * ) & export_vars . innodb_buffer_pool_read_ahead_seq , SHOW_LONG } ,
{ " buffer_pool_read_requests " ,
( char * ) & export_vars . innodb_buffer_pool_read_requests , SHOW_LONG } ,
{ " buffer_pool_reads " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_buffer_pool_reads , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " buffer_pool_wait_free " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_buffer_pool_wait_free , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " buffer_pool_write_requests " ,
( char * ) & export_vars . innodb_buffer_pool_write_requests , SHOW_LONG } ,
{ " data_fsyncs " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_data_fsyncs , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " data_pending_fsyncs " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_data_pending_fsyncs , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " data_pending_reads " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_data_pending_reads , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " data_pending_writes " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_data_pending_writes , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " data_read " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_data_read , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " data_reads " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_data_reads , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " data_writes " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_data_writes , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " data_written " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_data_written , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " dblwr_pages_written " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_dblwr_pages_written , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " dblwr_writes " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_dblwr_writes , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " log_waits " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_log_waits , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " log_write_requests " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_log_write_requests , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " log_writes " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_log_writes , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " os_log_fsyncs " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_os_log_fsyncs , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " os_log_pending_fsyncs " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_os_log_pending_fsyncs , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " os_log_pending_writes " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_os_log_pending_writes , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " os_log_written " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_os_log_written , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " page_size " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_page_size , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " pages_created " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_pages_created , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " pages_read " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_pages_read , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " pages_written " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_pages_written , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " row_lock_current_waits " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_row_lock_current_waits , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " row_lock_time " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_row_lock_time , SHOW_LONGLONG } ,
2005-10-27 09:29:40 +02:00
{ " row_lock_time_avg " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_row_lock_time_avg , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " row_lock_time_max " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_row_lock_time_max , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " row_lock_waits " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_row_lock_waits , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " rows_deleted " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_rows_deleted , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " rows_inserted " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_rows_inserted , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " rows_read " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_rows_read , SHOW_LONG } ,
2005-10-27 09:29:40 +02:00
{ " rows_updated " ,
2006-02-21 13:37:54 +01:00
( char * ) & export_vars . innodb_rows_updated , SHOW_LONG } ,
2006-09-04 12:45:05 +02:00
{ NullS , NullS , SHOW_LONG }
} ;
2005-10-27 09:29:40 +02:00
/* General functions */
2007-05-08 09:20:02 +02:00
/**********************************************************************
Returns true if the thread is the replication thread on the slave
server . Used in srv_conc_enter_innodb ( ) to determine if the thread
should be allowed to enter InnoDB - the replication thread is treated
differently than other threads . Also used in
srv_conc_force_exit_innodb ( ) . */
extern " C "
ibool
thd_is_replication_slave_thread (
/*============================*/
/* out: true if thd is the replication thread */
void * thd ) /* in: thread handle (THD*) */
{
2007-05-10 13:31:36 +02:00
return ( ( ibool ) thd_slave_thread ( ( THD * ) thd ) ) ;
2007-05-08 09:20:02 +02:00
}
2005-10-27 09:29:40 +02:00
/**********************************************************************
Save some CPU by testing the value of srv_thread_concurrency in inline
functions . */
inline
void
innodb_srv_conc_enter_innodb (
/*=========================*/
trx_t * trx ) /* in: transaction handle */
{
2006-01-19 14:30:20 +01:00
if ( UNIV_LIKELY ( ! srv_thread_concurrency ) ) {
2005-10-27 09:29:40 +02:00
return ;
}
srv_conc_enter_innodb ( trx ) ;
}
/**********************************************************************
Save some CPU by testing the value of srv_thread_concurrency in inline
functions . */
inline
void
innodb_srv_conc_exit_innodb (
/*========================*/
trx_t * trx ) /* in: transaction handle */
{
2008-11-24 21:06:50 +01:00
if ( UNIV_LIKELY ( ! trx - > declared_to_be_inside_innodb ) ) {
2005-10-27 09:29:40 +02:00
return ;
}
srv_conc_exit_innodb ( trx ) ;
}
/**********************************************************************
Releases possible search latch and InnoDB thread FIFO ticket . These should
be released at each SQL statement end , and also when mysqld passes the
control to the client . It does no harm to release these also in the middle
of an SQL statement . */
inline
void
innobase_release_stat_resources (
/*============================*/
trx_t * trx ) /* in: transaction object */
{
if ( trx - > has_search_latch ) {
trx_search_latch_release_if_reserved ( trx ) ;
}
if ( trx - > declared_to_be_inside_innodb ) {
/* Release our possible ticket in the FIFO */
srv_conc_force_exit_innodb ( trx ) ;
}
}
2007-05-15 16:53:04 +02:00
/**********************************************************************
Returns true if the transaction this thread is processing has edited
non - transactional tables . Used by the deadlock detector when deciding
which transaction to rollback in case of a deadlock - we try to avoid
rolling back transactions that have edited non - transactional tables . */
extern " C "
ibool
thd_has_edited_nontrans_tables (
/*===========================*/
/* out: true if non-transactional tables have
been edited */
void * thd ) /* in: thread handle (THD*) */
{
return ( ( ibool ) thd_non_transactional_update ( ( THD * ) thd ) ) ;
}
2008-08-21 14:25:05 +02:00
/**********************************************************************
Returns true if the thread is executing a SELECT statement . */
extern " C "
ibool
thd_is_select (
/*==========*/
/* out: true if thd is executing SELECT */
const void * thd ) /* in: thread handle (THD*) */
{
return ( thd_sql_command ( ( const THD * ) thd ) = = SQLCOM_SELECT ) ;
}
2007-02-14 21:03:58 +01:00
/************************************************************************
Obtain the InnoDB transaction of a MySQL thread . */
inline
trx_t * &
thd_to_trx (
/*=======*/
2007-05-10 14:09:03 +02:00
/* out: reference to transaction pointer */
THD * thd ) /* in: MySQL thread */
2007-02-14 21:03:58 +01:00
{
2007-05-10 14:09:03 +02:00
return ( * ( trx_t * * ) thd_ha_data ( thd , innodb_hton_ptr ) ) ;
2007-02-14 21:03:58 +01:00
}
2005-10-27 09:29:40 +02:00
/************************************************************************
Call this function when mysqld passes control to the client . That is to
avoid deadlocks on the adaptive hash S - latch possibly held by thd . For more
documentation , see handler . cc . */
2007-02-12 14:08:02 +01:00
static
2005-10-27 09:51:34 +02:00
int
2005-10-27 09:29:40 +02:00
innobase_release_temporary_latches (
/*===============================*/
2007-05-10 13:31:36 +02:00
/* out: 0 */
handlerton * hton , /* in: handlerton */
THD * thd ) /* in: MySQL thread */
2005-10-27 09:29:40 +02:00
{
trx_t * trx ;
2007-05-10 14:09:03 +02:00
DBUG_ASSERT ( hton = = innodb_hton_ptr ) ;
2005-10-27 09:29:40 +02:00
if ( ! innodb_inited ) {
2006-02-21 13:37:54 +01:00
2005-10-27 09:51:34 +02:00
return 0 ;
2005-10-27 09:29:40 +02:00
}
2007-05-10 14:09:03 +02:00
trx = thd_to_trx ( thd ) ;
2005-10-27 09:29:40 +02:00
if ( trx ) {
2006-02-21 13:37:54 +01:00
innobase_release_stat_resources ( trx ) ;
2005-10-27 09:29:40 +02:00
}
2005-10-27 09:51:34 +02:00
return 0 ;
2005-10-27 09:29:40 +02:00
}
/************************************************************************
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
time calls srv_active_wake_master_thread . This function should be used
when a single database operation may introduce a small need for
server utility activity , like checkpointing . */
inline
void
innobase_active_small ( void )
/*=======================*/
{
innobase_active_counter + + ;
if ( ( innobase_active_counter % INNOBASE_WAKE_INTERVAL ) = = 0 ) {
srv_active_wake_master_thread ( ) ;
}
}
/************************************************************************
Converts an InnoDB error code to a MySQL error code and also tells to MySQL
about a possible transaction rollback inside InnoDB caused by a lock wait
timeout or a deadlock . */
static
int
convert_error_code_to_mysql (
/*========================*/
/* out: MySQL error code */
int error , /* in: InnoDB error code */
THD * thd ) /* in: user thread handle or NULL */
{
if ( error = = DB_SUCCESS ) {
return ( 0 ) ;
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_DUPLICATE_KEY ) {
2005-10-27 09:29:40 +02:00
2009-11-20 06:55:48 +01:00
/* Be cautious with returning this error, since
mysql could re - enter the storage layer to get
duplicated key info , the operation requires a
valid table handle and / or transaction information ,
which might not always be available in the error
handling stage . */
2006-02-21 13:37:54 +01:00
return ( HA_ERR_FOUND_DUPP_KEY ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_FOREIGN_DUPLICATE_KEY ) {
2006-02-10 10:16:35 +01:00
return ( HA_ERR_FOREIGN_DUPLICATE_KEY ) ;
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_RECORD_NOT_FOUND ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_NO_ACTIVE_RECORD ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_ERROR ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( - 1 ) ; /* unspecified error */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_DEADLOCK ) {
/* Since we rolled back the whole transaction, we must
tell it also to MySQL so that MySQL knows to empty the
cached binlog for this transaction */
2005-10-27 09:29:40 +02:00
2007-11-30 13:20:56 +01:00
if ( thd ) {
thd_mark_transaction_to_rollback ( thd , TRUE ) ;
}
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_LOCK_DEADLOCK ) ;
} else if ( error = = ( int ) DB_LOCK_WAIT_TIMEOUT ) {
2005-10-27 09:29:40 +02:00
/* Starting from 5.0.13, we let MySQL just roll back the
latest SQL statement in a lock wait timeout . Previously , we
rolled back the whole transaction . */
2007-11-30 13:20:56 +01:00
if ( thd ) {
thd_mark_transaction_to_rollback (
thd , ( bool ) row_rollback_on_timeout ) ;
}
2007-01-11 12:45:58 +01:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_LOCK_WAIT_TIMEOUT ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_NO_REFERENCED_ROW ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_NO_REFERENCED_ROW ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_ROW_IS_REFERENCED ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_ROW_IS_REFERENCED ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_CANNOT_ADD_CONSTRAINT ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_CANNOT_ADD_FOREIGN ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_CANNOT_DROP_CONSTRAINT ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_ROW_IS_REFERENCED ) ; /* TODO: This is a bit
2005-10-27 09:29:40 +02:00
misleading , a new MySQL error
code should be introduced */
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_COL_APPEARS_TWICE_IN_INDEX ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_CRASHED ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_OUT_OF_FILE_SPACE ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_RECORD_FILE_FULL ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_TABLE_IS_BEING_USED ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_WRONG_COMMAND ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_TABLE_NOT_FOUND ) {
2005-10-27 09:29:40 +02:00
2007-07-31 07:56:17 +02:00
return ( HA_ERR_NO_SUCH_TABLE ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_TOO_BIG_RECORD ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_TO_BIG_ROW ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
} else if ( error = = ( int ) DB_CORRUPTION ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_CRASHED ) ;
} else if ( error = = ( int ) DB_NO_SAVEPOINT ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( HA_ERR_NO_SAVEPOINT ) ;
} else if ( error = = ( int ) DB_LOCK_TABLE_FULL ) {
2006-03-17 09:20:14 +01:00
/* Since we rolled back the whole transaction, we must
tell it also to MySQL so that MySQL knows to empty the
cached binlog for this transaction */
2007-11-30 13:20:56 +01:00
if ( thd ) {
thd_mark_transaction_to_rollback ( thd , TRUE ) ;
}
2006-03-17 09:20:14 +01:00
return ( HA_ERR_LOCK_TABLE_FULL ) ;
2007-04-11 04:43:56 +02:00
} else if ( error = = DB_TOO_MANY_CONCURRENT_TRXS ) {
2009-09-09 16:26:29 +02:00
return ( HA_ERR_TOO_MANY_CONCURRENT_TRXS ) ;
2007-04-11 04:43:56 +02:00
2007-11-14 13:49:24 +01:00
} else if ( error = = DB_UNSUPPORTED ) {
return ( HA_ERR_UNSUPPORTED ) ;
2006-03-17 09:20:14 +01:00
} else {
return ( - 1 ) ; // Unknown error
}
2005-10-27 09:29:40 +02:00
}
/*****************************************************************
Prints info of a THD object ( = = user session thread ) to the given file .
NOTE that / mysql / innobase / trx / trx0trx . c must contain the prototype for
this function ! */
extern " C "
void
innobase_mysql_print_thd (
/*=====================*/
2006-02-21 13:37:54 +01:00
FILE * f , /* in: output stream */
void * input_thd , /* in: pointer to a MySQL THD object */
2005-10-27 09:29:40 +02:00
uint max_query_len ) /* in: max query length to print, or 0 to
use the default max length */
{
2007-05-10 13:31:36 +02:00
THD * thd ;
char buffer [ 1024 ] ;
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
thd = ( THD * ) input_thd ;
fputs ( thd_security_context ( thd , buffer , sizeof ( buffer ) ,
max_query_len ) , f ) ;
2005-10-27 09:29:40 +02:00
putc ( ' \n ' , f ) ;
}
/**********************************************************************
Get the variable length bounds of the given character set .
NOTE that the exact prototype of this function has to be in
2007-05-03 14:27:08 +02:00
/ innobase / include / data0type . ic ! */
2005-10-27 09:29:40 +02:00
extern " C "
void
innobase_get_cset_width (
/*====================*/
ulint cset , /* in: MySQL charset-collation code */
ulint * mbminlen , /* out: minimum length of a char (in bytes) */
ulint * mbmaxlen ) /* out: maximum length of a char (in bytes) */
{
CHARSET_INFO * cs ;
ut_ad ( cset < 256 ) ;
ut_ad ( mbminlen ) ;
ut_ad ( mbmaxlen ) ;
cs = all_charsets [ cset ] ;
if ( cs ) {
* mbminlen = cs - > mbminlen ;
* mbmaxlen = cs - > mbmaxlen ;
} else {
2009-09-09 18:47:31 +02:00
if ( current_thd
& & ( thd_sql_command ( current_thd ) = = SQLCOM_DROP_TABLE ) ) {
/* Fix bug#46256: allow tables to be dropped if the
collation is not found , but issue a warning . */
if ( ( global_system_variables . log_warnings )
& & ( cset ! = 0 ) ) {
sql_print_warning (
2009-09-10 06:41:48 +02:00
" Unknown collation #%lu. " , cset ) ;
2009-09-09 18:47:31 +02:00
}
} else {
ut_a ( cset = = 0 ) ;
}
2005-10-27 09:29:40 +02:00
* mbminlen = * mbmaxlen = 0 ;
}
}
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
/**********************************************************************
Converts an identifier to a table name .
NOTE that the exact prototype of this function has to be in
/ innobase / dict / dict0dict . c ! */
extern " C "
void
innobase_convert_from_table_id (
/*===========================*/
char * to , /* out: converted identifier */
const char * from , /* in: identifier to convert */
ulint len ) /* in: length of 'to', in bytes */
{
uint errors ;
2007-05-10 13:31:36 +02:00
strconvert ( thd_charset ( current_thd ) , from ,
2007-03-01 16:21:12 +01:00
& my_charset_filename , to , ( uint ) len , & errors ) ;
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
}
/**********************************************************************
Converts an identifier to UTF - 8.
NOTE that the exact prototype of this function has to be in
/ innobase / dict / dict0dict . c ! */
extern " C "
void
innobase_convert_from_id (
/*=====================*/
char * to , /* out: converted identifier */
const char * from , /* in: identifier to convert */
ulint len ) /* in: length of 'to', in bytes */
{
uint errors ;
2007-05-10 13:31:36 +02:00
strconvert ( thd_charset ( current_thd ) , from ,
2007-03-01 16:21:12 +01:00
system_charset_info , to , ( uint ) len , & errors ) ;
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
}
2005-10-27 09:29:40 +02:00
/**********************************************************************
Compares NUL - terminated UTF - 8 strings case insensitively .
NOTE that the exact prototype of this function has to be in
/ innobase / dict / dict0dict . c ! */
extern " C "
int
innobase_strcasecmp (
/*================*/
/* out: 0 if a=b, <0 if a<b, >1 if a>b */
const char * a , /* in: first string to compare */
const char * b ) /* in: second string to compare */
{
return ( my_strcasecmp ( system_charset_info , a , b ) ) ;
}
/**********************************************************************
Makes all characters in a NUL - terminated UTF - 8 string lower case .
NOTE that the exact prototype of this function has to be in
/ innobase / dict / dict0dict . c ! */
extern " C "
void
innobase_casedn_str (
/*================*/
char * a ) /* in/out: string to put in lower case */
{
my_casedn_str ( system_charset_info , a ) ;
}
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
/**************************************************************************
Determines the connection character set .
NOTE that the exact prototype of this function has to be in
/ innobase / dict / dict0dict . c ! */
extern " C "
struct charset_info_st *
innobase_get_charset (
/*=================*/
/* out: connection character set */
void * mysql_thd ) /* in: MySQL thread handle */
{
2007-05-10 13:31:36 +02:00
return ( thd_charset ( ( THD * ) mysql_thd ) ) ;
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
}
2009-11-09 10:43:31 +01:00
# if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list ;
/*******************************************************************/ /**
Map an OS error to an errno value . The OS error number is stored in
_doserrno and the mapped value is stored in errno ) */
extern " C "
void __cdecl
_dosmaperr (
unsigned long ) ; /*!< in: OS error value */
/*********************************************************************/ /**
Creates a temporary file .
@ return temporary file descriptor , or < 0 on error */
extern " C "
int
innobase_mysql_tmpfile ( void )
/*========================*/
{
int fd ; /* handle of opened file */
HANDLE osfh ; /* OS handle of opened file */
char * tmpdir ; /* point to the directory
where to create file */
TCHAR path_buf [ MAX_PATH - 14 ] ; /* buffer for tmp file path.
The length cannot be longer
than MAX_PATH - 14 , or
GetTempFileName will fail . */
char filename [ MAX_PATH ] ; /* name of the tmpfile */
DWORD fileaccess = GENERIC_READ /* OS file access */
| GENERIC_WRITE
| DELETE ;
DWORD fileshare = FILE_SHARE_READ /* OS file sharing mode */
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE ;
DWORD filecreate = CREATE_ALWAYS ; /* OS method of open/create */
DWORD fileattrib = /* OS file attribute flags */
FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_DELETE_ON_CLOSE
| FILE_ATTRIBUTE_TEMPORARY
| FILE_FLAG_SEQUENTIAL_SCAN ;
DBUG_ENTER ( " innobase_mysql_tmpfile " ) ;
tmpdir = my_tmpdir ( & mysql_tmpdir_list ) ;
/* The tmpdir parameter can not be NULL for GetTempFileName. */
if ( ! tmpdir ) {
uint ret ;
/* Use GetTempPath to determine path for temporary files. */
ret = GetTempPath ( sizeof ( path_buf ) , path_buf ) ;
if ( ret > sizeof ( path_buf ) | | ( ret = = 0 ) ) {
_dosmaperr ( GetLastError ( ) ) ; /* map error */
DBUG_RETURN ( - 1 ) ;
}
tmpdir = path_buf ;
}
/* Use GetTempFileName to generate a unique filename. */
if ( ! GetTempFileName ( tmpdir , " ib " , 0 , filename ) ) {
_dosmaperr ( GetLastError ( ) ) ; /* map error */
DBUG_RETURN ( - 1 ) ;
}
DBUG_PRINT ( " info " , ( " filename: %s " , filename ) ) ;
/* Open/Create the file. */
osfh = CreateFile ( filename , fileaccess , fileshare , NULL ,
filecreate , fileattrib , NULL ) ;
if ( osfh = = INVALID_HANDLE_VALUE ) {
/* open/create file failed! */
_dosmaperr ( GetLastError ( ) ) ; /* map error */
DBUG_RETURN ( - 1 ) ;
}
do {
/* Associates a CRT file descriptor with the OS file handle. */
fd = _open_osfhandle ( ( intptr_t ) osfh , 0 ) ;
} while ( fd = = - 1 & & errno = = EINTR ) ;
if ( fd = = - 1 ) {
/* Open failed, close the file handle. */
_dosmaperr ( GetLastError ( ) ) ; /* map error */
CloseHandle ( osfh ) ; /* no need to check if
CloseHandle fails */
}
DBUG_RETURN ( fd ) ;
}
# else
2005-10-27 09:29:40 +02:00
/*************************************************************************
Creates a temporary file . */
extern " C "
int
innobase_mysql_tmpfile ( void )
/*========================*/
/* out: temporary file descriptor, or < 0 on error */
{
2007-07-31 07:56:17 +02:00
int fd2 = - 1 ;
File fd = mysql_tmpfile ( " ib " ) ;
if ( fd > = 0 ) {
/* Copy the file descriptor, so that the additional resources
allocated by create_temp_file ( ) can be freed by invoking
my_close ( ) .
Because the file descriptor returned by this function
will be passed to fdopen ( ) , it will be closed by invoking
fclose ( ) , which in turn will invoke close ( ) instead of
my_close ( ) . */
fd2 = dup ( fd ) ;
if ( fd2 < 0 ) {
DBUG_PRINT ( " error " , ( " Got error %d on dup " , fd2 ) ) ;
my_errno = errno ;
my_error ( EE_OUT_OF_FILERESOURCES ,
MYF ( ME_BELL + ME_WAITTANG ) ,
" ib* " , my_errno ) ;
}
my_close ( fd , MYF ( MY_WME ) ) ;
}
return ( fd2 ) ;
2005-10-27 09:29:40 +02:00
}
2009-11-09 10:43:31 +01:00
# endif
2005-10-27 09:29:40 +02:00
2006-05-11 06:51:52 +02:00
/*************************************************************************
Wrapper around MySQL ' s copy_and_convert function , see it for
documentation . */
extern " C "
ulint
innobase_convert_string (
/*====================*/
void * to ,
ulint to_length ,
CHARSET_INFO * to_cs ,
const void * from ,
ulint from_length ,
CHARSET_INFO * from_cs ,
uint * errors )
{
2007-03-01 16:21:12 +01:00
return ( copy_and_convert ( ( char * ) to , ( uint32 ) to_length , to_cs ,
( const char * ) from , ( uint32 ) from_length , from_cs ,
errors ) ) ;
2006-05-11 06:51:52 +02:00
}
2008-10-04 00:48:04 +02:00
/*************************************************************************
Compute the next autoinc value .
For MySQL replication the autoincrement values can be partitioned among
the nodes . The offset is the start or origin of the autoincrement value
for a particular node . For n nodes the increment will be n and the offset
will be in the interval [ 1 , n ] . The formula tries to allocate the next
value for a particular node .
Note : This function is also called with increment set to the number of
values we want to reserve for multi - value inserts e . g . ,
INSERT INTO T VALUES ( ) , ( ) , ( ) ;
innobase_next_autoinc ( ) will be called with increment set to
n * 3 where autoinc_lock_mode ! = TRADITIONAL because we want
to reserve 3 values for the multi - value INSERT above . */
static
ulonglong
innobase_next_autoinc (
/*==================*/
/* out: the next value */
ulonglong current , /* in: Current value */
ulonglong increment , /* in: increment current by */
2008-10-22 23:42:24 +02:00
ulonglong offset , /* in: AUTOINC offset */
ulonglong max_value ) /* in: max value for type */
2008-10-04 00:48:04 +02:00
{
ulonglong next_value ;
/* Should never be 0. */
ut_a ( increment > 0 ) ;
2009-02-25 04:32:01 +01:00
/* According to MySQL documentation, if the offset is greater than
the increment then the offset is ignored . */
if ( offset > increment ) {
offset = 0 ;
}
2008-10-23 06:30:32 +02:00
if ( max_value < = current ) {
next_value = max_value ;
} else if ( offset < = 1 ) {
2008-10-04 00:48:04 +02:00
/* Offset 0 and 1 are the same, because there must be at
least one node in the system . */
2008-10-22 23:42:24 +02:00
if ( max_value - current < = increment ) {
next_value = max_value ;
2008-10-04 00:48:04 +02:00
} else {
next_value = current + increment ;
}
} else {
if ( current > offset ) {
next_value = ( ( current - offset ) / increment ) + 1 ;
} else {
next_value = ( ( offset - current ) / increment ) + 1 ;
}
ut_a ( increment > 0 ) ;
ut_a ( next_value > 0 ) ;
/* Check for multiplication overflow. */
2008-10-22 23:42:24 +02:00
if ( increment > ( max_value / next_value ) ) {
2008-10-04 00:48:04 +02:00
2008-10-22 23:42:24 +02:00
next_value = max_value ;
2008-10-04 00:48:04 +02:00
} else {
next_value * = increment ;
2008-10-23 06:30:32 +02:00
ut_a ( max_value > = next_value ) ;
2008-10-04 00:48:04 +02:00
/* Check for overflow. */
2008-10-22 23:42:24 +02:00
if ( max_value - next_value < = offset ) {
next_value = max_value ;
2008-10-04 00:48:04 +02:00
} else {
next_value + = offset ;
}
}
}
2008-10-23 06:30:32 +02:00
ut_a ( next_value < = max_value ) ;
2008-10-04 00:48:04 +02:00
return ( next_value ) ;
}
2005-10-27 09:29:40 +02:00
/*************************************************************************
Gets the InnoDB transaction handle for a MySQL handler object , creates
an InnoDB transaction struct if the corresponding MySQL thread struct still
lacks one . */
static
trx_t *
check_trx_exists (
/*=============*/
/* out: InnoDB transaction handle */
THD * thd ) /* in: user thread handle */
{
2007-05-10 14:09:03 +02:00
trx_t * & trx = thd_to_trx ( thd ) ;
2005-10-27 09:29:40 +02:00
ut_ad ( thd = = current_thd ) ;
if ( trx = = NULL ) {
2006-02-21 13:37:54 +01:00
DBUG_ASSERT ( thd ! = NULL ) ;
2005-10-27 09:29:40 +02:00
trx = trx_allocate_for_mysql ( ) ;
trx - > mysql_thd = thd ;
2007-05-10 13:31:36 +02:00
trx - > mysql_query_str = thd_query ( thd ) ;
2005-10-27 09:29:40 +02:00
/* Update the info whether we should skip XA steps that eat
CPU time */
2007-05-10 13:31:36 +02:00
trx - > support_xa = THDVAR ( thd , support_xa ) ;
2005-10-27 09:29:40 +02:00
} else {
if ( trx - > magic_n ! = TRX_MAGIC_N ) {
2006-03-06 10:45:04 +01:00
mem_analyze_corruption ( trx ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 14:09:03 +02:00
ut_error ;
2005-10-27 09:29:40 +02:00
}
}
2007-05-10 13:31:36 +02:00
if ( thd_test_options ( thd , OPTION_NO_FOREIGN_KEY_CHECKS ) ) {
2005-10-27 09:29:40 +02:00
trx - > check_foreigns = FALSE ;
} else {
trx - > check_foreigns = TRUE ;
}
2007-05-10 13:31:36 +02:00
if ( thd_test_options ( thd , OPTION_RELAXED_UNIQUE_CHECKS ) ) {
2005-10-27 09:29:40 +02:00
trx - > check_unique_secondary = FALSE ;
} else {
trx - > check_unique_secondary = TRUE ;
}
return ( trx ) ;
}
/*************************************************************************
Construct ha_innobase handler . */
2006-10-03 14:46:23 +02:00
ha_innobase : : ha_innobase ( handlerton * hton , TABLE_SHARE * table_arg )
: handler ( hton , table_arg ) ,
2005-10-27 09:29:40 +02:00
int_table_flags ( HA_REC_NOT_IN_SEQ |
2006-02-21 13:37:54 +01:00
HA_NULL_IN_KEY |
HA_CAN_INDEX_BLOBS |
HA_CAN_SQL_HANDLER |
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
HA_PRIMARY_KEY_REQUIRED_FOR_POSITION |
2006-02-21 13:37:54 +01:00
HA_PRIMARY_KEY_IN_READ_INDEX |
2007-07-31 07:56:17 +02:00
HA_BINLOG_ROW_CAPABLE |
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
HA_CAN_GEOMETRY | HA_PARTIAL_COLUMN_READ |
2006-02-21 13:37:54 +01:00
HA_TABLE_SCAN_ON_INDEX ) ,
2005-10-27 09:29:40 +02:00
start_of_scan ( 0 ) ,
num_write_row ( 0 )
{ }
/*************************************************************************
Updates the user_thd field in a handle and also allocates a new InnoDB
transaction handle if needed , and updates the transaction fields in the
prebuilt struct . * /
inline
int
ha_innobase : : update_thd (
/*====================*/
/* out: 0 or error code */
THD * thd ) /* in: thd to use the handle */
{
trx_t * trx ;
2007-05-10 14:09:03 +02:00
trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
if ( prebuilt - > trx ! = trx ) {
row_update_prebuilt_trx ( prebuilt , trx ) ;
}
user_thd = thd ;
return ( 0 ) ;
}
/*************************************************************************
Registers that InnoDB takes part in an SQL statement , so that MySQL knows to
roll back the statement if the statement results in an error . This MUST be
called for every SQL statement that may be rolled back by MySQL . Calling this
several times to register the same statement is allowed , too . */
inline
void
innobase_register_stmt (
/*===================*/
2006-10-03 14:46:23 +02:00
handlerton * hton , /* in: Innobase hton */
2005-10-27 09:29:40 +02:00
THD * thd ) /* in: MySQL thd (connection) object */
{
2006-02-21 13:37:54 +01:00
/* Register the statement */
2006-10-03 14:46:23 +02:00
trans_register_ha ( thd , FALSE , hton ) ;
2005-10-27 09:29:40 +02:00
}
/*************************************************************************
Registers an InnoDB transaction in MySQL , so that the MySQL XA code knows
to call the InnoDB prepare and commit , or rollback for the transaction . This
MUST be called for every transaction for which the user may call commit or
rollback . Calling this several times to register the same transaction is
allowed , too .
This function also registers the current SQL statement . */
inline
void
innobase_register_trx_and_stmt (
/*===========================*/
2006-10-03 14:46:23 +02:00
handlerton * hton , /* in: Innobase handlerton */
2005-10-27 09:29:40 +02:00
THD * thd ) /* in: MySQL thd (connection) object */
{
/* NOTE that actually innobase_register_stmt() registers also
the transaction in the AUTOCOMMIT = 1 mode . */
2006-10-03 14:46:23 +02:00
innobase_register_stmt ( hton , thd ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
if ( thd_test_options ( thd , OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN ) ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* No autocommit mode, register for a transaction */
2006-10-03 14:46:23 +02:00
trans_register_ha ( thd , TRUE , hton ) ;
2006-02-21 13:37:54 +01:00
}
2005-10-27 09:29:40 +02:00
}
/* BACKGROUND INFO: HOW THE MYSQL QUERY CACHE WORKS WITH INNODB
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 ) The use of the query cache for TBL is disabled when there is an
uncommitted change to TBL .
2 ) When a change to TBL commits , InnoDB stores the current value of
its global trx id counter , let us denote it by INV_TRX_ID , to the table object
in the InnoDB data dictionary , and does only allow such transactions whose
id < = INV_TRX_ID to use the query cache .
3 ) When InnoDB does an INSERT / DELETE / UPDATE to a table TBL , or an implicit
modification because an ON DELETE CASCADE , we invalidate the MySQL query cache
of TBL immediately .
How this is implemented inside InnoDB :
1 ) Since every modification always sets an IX type table lock on the InnoDB
table , it is easy to check if there can be uncommitted modifications for a
table : just check if there are locks in the lock list of the table .
2 ) When a transaction inside InnoDB commits , it reads the global trx id
counter and stores the value INV_TRX_ID to the tables on which it had a lock .
3 ) If there is an implicit table change from ON DELETE CASCADE or SET NULL ,
InnoDB calls an invalidate method for the MySQL query cache for that table .
How this is implemented inside sql_cache . cc :
1 ) The query cache for an InnoDB table TBL is invalidated immediately at an
INSERT / UPDATE / DELETE , just like in the case of MyISAM . No need to delay
invalidation to the transaction commit .
2 ) To store or retrieve a value from the query cache of an InnoDB table TBL ,
any query must first ask InnoDB ' s permission . We must pass the thd as a
parameter because InnoDB will look at the trx id , if any , associated with
that thd .
3 ) Use of the query cache for InnoDB tables is now allowed also when
AUTOCOMMIT = = 0 or we are inside BEGIN . . . COMMIT . Thus transactions no longer
put restrictions on the use of the query cache .
*/
/**********************************************************************
The MySQL query cache uses this to check from InnoDB if the query cache at
the moment is allowed to operate on an InnoDB table . The SQL query must
be a non - locking SELECT .
The query cache is allowed to operate on certain query only if this function
returns TRUE for all tables in the query .
If thd is not in the autocommit state , this function also starts a new
transaction for thd if there is no active trx yet , and assigns a consistent
read view to it if there is no read view yet .
Why a deadlock of threads is not possible : the query cache calls this function
at the start of a SELECT processing . Then the calling thread cannot be
holding any InnoDB semaphores . The calling thread is holding the
query cache mutex , and this function will reserver the InnoDB kernel mutex .
Thus , the ' rank ' in sync0sync . h of the MySQL query cache mutex is above
the InnoDB kernel mutex . */
2007-03-21 11:02:00 +01:00
static
2005-10-27 09:29:40 +02:00
my_bool
innobase_query_caching_of_table_permitted (
/*======================================*/
/* out: TRUE if permitted, FALSE if not;
note that the value FALSE does not mean
we should invalidate the query cache :
invalidation is called explicitly */
THD * thd , /* in: thd of the user who is trying to
store a result to the query cache or
retrieve it */
char * full_name , /* in: concatenation of database name,
the null character ' \0 ' , and the table
name */
uint full_name_len , /* in: length of the full name, i.e.
len ( dbname ) + len ( tablename ) + 1 */
2006-02-21 13:37:54 +01:00
ulonglong * unused ) /* unused for this engine */
2005-10-27 09:29:40 +02:00
{
ibool is_autocommit ;
trx_t * trx ;
char norm_name [ 1000 ] ;
ut_a ( full_name_len < 999 ) ;
2007-05-10 14:09:03 +02:00
trx = check_trx_exists ( thd ) ;
2007-05-10 13:31:36 +02:00
if ( trx - > isolation_level = = TRX_ISO_SERIALIZABLE ) {
2005-10-27 09:29:40 +02:00
/* In the SERIALIZABLE mode we add LOCK IN SHARE MODE to every
plain SELECT if AUTOCOMMIT is not on . */
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
return ( ( my_bool ) FALSE ) ;
}
if ( trx - > has_search_latch ) {
sql_print_error ( " The calling thread is holding the adaptive "
" search, latch though calling "
" innobase_query_caching_of_table_permitted. " ) ;
2006-01-12 09:42:46 +01:00
2006-01-17 14:08:48 +01:00
mutex_enter_noninline ( & kernel_mutex ) ;
2006-01-12 09:42:46 +01:00
trx_print ( stderr , trx , 1024 ) ;
2006-01-17 14:08:48 +01:00
mutex_exit_noninline ( & kernel_mutex ) ;
2005-10-27 09:29:40 +02:00
}
innobase_release_stat_resources ( trx ) ;
2007-05-10 13:31:36 +02:00
if ( ! thd_test_options ( thd , OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN ) ) {
2005-10-27 09:29:40 +02:00
is_autocommit = TRUE ;
} else {
is_autocommit = FALSE ;
}
if ( is_autocommit & & trx - > n_mysql_tables_in_use = = 0 ) {
/* We are going to retrieve the query result from the query
cache . This cannot be a store operation to the query cache
because then MySQL would have locks on tables already .
TODO : if the user has used LOCK TABLES to lock the table ,
then we open a transaction in the call of row_ . . below .
That trx can stay open until UNLOCK TABLES . The same problem
exists even if we do not use the query cache . MySQL should be
modified so that it ALWAYS calls some cleanup function when
the processing of a query ends !
We can imagine we instantaneously serialize this consistent
read trx to the current trx id counter . If trx2 would have
changed the tables of a query result stored in the cache , and
trx2 would have already committed , making the result obsolete ,
then trx2 would have already invalidated the cache . Thus we
can trust the result in the cache is ok for this query . */
return ( ( my_bool ) TRUE ) ;
}
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
/* Normalize the table name to InnoDB format */
memcpy ( norm_name , full_name , full_name_len ) ;
norm_name [ strlen ( norm_name ) ] = ' / ' ; /* InnoDB uses '/' as the
separator between db and table */
norm_name [ full_name_len ] = ' \0 ' ;
# ifdef __WIN__
innobase_casedn_str ( norm_name ) ;
# endif
/* The call of row_search_.. will start a new transaction if it is
not yet started */
2006-02-21 13:37:54 +01:00
if ( trx - > active_trans = = 0 ) {
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
innobase_register_trx_and_stmt ( innodb_hton_ptr , thd ) ;
2006-02-21 13:37:54 +01:00
trx - > active_trans = 1 ;
}
2005-10-27 09:29:40 +02:00
if ( row_search_check_if_query_cache_permitted ( trx , norm_name ) ) {
/* printf("Query cache for %s permitted\n", norm_name); */
return ( ( my_bool ) TRUE ) ;
}
/* printf("Query cache for %s NOT permitted\n", norm_name); */
return ( ( my_bool ) FALSE ) ;
}
/*********************************************************************
Invalidates the MySQL query cache for the table .
NOTE that the exact prototype of this function has to be in
/ innobase / row / row0ins . c ! */
extern " C "
void
innobase_invalidate_query_cache (
/*============================*/
trx_t * trx , /* in: transaction which modifies the table */
char * full_name , /* in: concatenation of database name, null
char ' \0 ' , table name , null char ' \0 ' ;
NOTE that in Windows this is always
in LOWER CASE ! */
ulint full_name_len ) /* in: full name length where also the null
chars count */
{
/* Note that the sync0sync.h rank of the query cache mutex is just
above the InnoDB kernel mutex . The caller of this function must not
have latches of a lower rank . */
/* Argument TRUE below means we are using transactions */
# ifdef HAVE_QUERY_CACHE
2007-05-10 13:31:36 +02:00
mysql_query_cache_invalidate4 ( ( THD * ) trx - > mysql_thd ,
( const char * ) full_name ,
( uint32 ) full_name_len ,
TRUE ) ;
2005-10-27 09:29:40 +02:00
# endif
}
2009-11-04 11:28:10 +01:00
/*****************************************************************/ /**
Convert an SQL identifier to the MySQL system_charset_info ( UTF - 8 )
and quote it if needed .
@ return pointer to the end of buf */
static
char *
innobase_convert_identifier (
/*========================*/
char * buf , /*!< out: buffer for converted identifier */
ulint buflen , /*!< in: length of buf, in bytes */
const char * id , /*!< in: identifier to convert */
ulint idlen , /*!< in: length of id, in bytes */
void * thd , /*!< in: MySQL connection thread, or NULL */
ibool file_id ) /*!< in: TRUE=id is a table or database name;
FALSE = id is an UTF - 8 string */
2005-10-27 09:29:40 +02:00
{
2009-11-04 11:28:10 +01:00
char nz [ NAME_LEN + 1 ] ;
# if MYSQL_VERSION_ID >= 50141
char nz2 [ NAME_LEN + 1 + EXPLAIN_FILENAME_MAX_EXTRA_LENGTH ] ;
# else /* MYSQL_VERSION_ID >= 50141 */
char nz2 [ NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix ] ;
# endif /* MYSQL_VERSION_ID >= 50141 */
const char * s = id ;
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
int q ;
2009-11-04 11:28:10 +01:00
if ( file_id ) {
/* Decode the table name. The MySQL function expects
a NUL - terminated string . The input and output strings
buffers must not be shared . */
if ( UNIV_UNLIKELY ( idlen > ( sizeof nz ) - 1 ) ) {
idlen = ( sizeof nz ) - 1 ;
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
}
2009-11-04 11:28:10 +01:00
memcpy ( nz , id , idlen ) ;
nz [ idlen ] = 0 ;
s = nz2 ;
# if MYSQL_VERSION_ID >= 50141
idlen = explain_filename ( ( THD * ) thd , nz , nz2 , sizeof nz2 ,
EXPLAIN_PARTITIONS_AS_COMMENT ) ;
goto no_quote ;
# else /* MYSQL_VERSION_ID >= 50141 */
idlen = filename_to_tablename ( nz , nz2 , sizeof nz2 ) ;
# endif /* MYSQL_VERSION_ID >= 50141 */
}
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
2009-11-04 11:28:10 +01:00
/* See if the identifier needs to be quoted. */
if ( UNIV_UNLIKELY ( ! thd ) ) {
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
q = ' " ' ;
} else {
2009-11-04 11:28:10 +01:00
q = get_quote_char_for_identifier ( ( THD * ) thd , s , ( int ) idlen ) ;
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
}
if ( q = = EOF ) {
2009-11-04 11:28:10 +01:00
# if MYSQL_VERSION_ID >= 50141
no_quote :
# endif /* MYSQL_VERSION_ID >= 50141 */
if ( UNIV_UNLIKELY ( idlen > buflen ) ) {
idlen = buflen ;
}
memcpy ( buf , s , idlen ) ;
return ( buf + idlen ) ;
}
/* Quote the identifier. */
if ( buflen < 2 ) {
return ( buf ) ;
}
* buf + + = q ;
buflen - - ;
for ( ; idlen ; idlen - - ) {
int c = * s + + ;
if ( UNIV_UNLIKELY ( c = = q ) ) {
if ( UNIV_UNLIKELY ( buflen < 3 ) ) {
break ;
}
* buf + + = c ;
* buf + + = c ;
buflen - = 2 ;
} else {
if ( UNIV_UNLIKELY ( buflen < 2 ) ) {
break ;
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
}
2009-11-04 11:28:10 +01:00
* buf + + = c ;
buflen - - ;
}
}
* buf + + = q ;
return ( buf ) ;
}
/*****************************************************************/ /**
Convert a table or index name to the MySQL system_charset_info ( UTF - 8 )
and quote it if needed .
@ return pointer to the end of buf */
extern " C "
char *
innobase_convert_name (
/*==================*/
char * buf , /*!< out: buffer for converted identifier */
ulint buflen , /*!< in: length of buf, in bytes */
const char * id , /*!< in: identifier to convert */
ulint idlen , /*!< in: length of id, in bytes */
void * thd , /*!< in: MySQL connection thread, or NULL */
ibool table_id ) /*!< in: TRUE=id is a table or database name;
FALSE = id is an index name */
{
char * s = buf ;
const char * bufend = buf + buflen ;
if ( table_id ) {
const char * slash = ( const char * ) memchr ( id , ' / ' , idlen ) ;
if ( ! slash ) {
goto no_db_name ;
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
}
2009-11-04 11:28:10 +01:00
/* Print the database name and table name separately. */
s = innobase_convert_identifier ( s , bufend - s , id , slash - id ,
thd , TRUE ) ;
if ( UNIV_LIKELY ( s < bufend ) ) {
* s + + = ' . ' ;
s = innobase_convert_identifier ( s , bufend - s ,
slash + 1 , idlen
- ( slash - id ) - 1 ,
thd , TRUE ) ;
}
} else {
no_db_name :
s = innobase_convert_identifier ( buf , buflen , id , idlen ,
thd , table_id ) ;
2005-10-27 09:29:40 +02:00
}
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
2009-11-04 11:28:10 +01:00
return ( s ) ;
2005-10-27 09:29:40 +02:00
}
/**************************************************************************
Determines if the currently running transaction has been interrupted . */
extern " C "
ibool
trx_is_interrupted (
/*===============*/
/* out: TRUE if interrupted */
trx_t * trx ) /* in: transaction */
{
2007-05-10 13:31:36 +02:00
return ( trx & & trx - > mysql_thd & & thd_killed ( ( THD * ) trx - > mysql_thd ) ) ;
2005-10-27 09:29:40 +02:00
}
2007-05-14 13:08:44 +02:00
/******************************************************************
Resets some fields of a prebuilt struct . The template is used in fast
retrieval of just those column values MySQL needs in its processing . */
static
void
reset_template (
/*===========*/
row_prebuilt_t * prebuilt ) /* in/out: prebuilt struct */
{
prebuilt - > keep_other_fields_on_keyread = 0 ;
prebuilt - > read_just_key = 0 ;
}
2005-10-27 09:29:40 +02:00
/*********************************************************************
Call this when you have opened a new table handle in HANDLER , before you
call index_read_idx ( ) etc . Actually , we can let the cursor stay open even
over a transaction commit ! Then you should call this before every operation ,
fetch next etc . This function inits the necessary things even after a
transaction commit . */
void
ha_innobase : : init_table_handle_for_HANDLER ( void )
/*============================================*/
{
2006-02-21 13:37:54 +01:00
/* If current thd does not yet have a trx struct, create one.
If the current handle does not yet have a prebuilt struct , create
one . Update the trx pointers in the prebuilt struct . Normally
this operation is done in external_lock . */
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
update_thd ( ha_thd ( ) ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* Initialize the prebuilt struct much like it would be inited in
external_lock */
2005-10-27 09:29:40 +02:00
innobase_release_stat_resources ( prebuilt - > trx ) ;
2006-02-21 13:37:54 +01:00
/* If the transaction is not started yet, start it */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
trx_start_if_not_started_noninline ( prebuilt - > trx ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* Assign a read view if the transaction does not have it yet */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
trx_assign_read_view ( prebuilt - > trx ) ;
2005-10-27 09:29:40 +02:00
/* Set the MySQL flag to mark that there is an active transaction */
2006-02-21 13:37:54 +01:00
if ( prebuilt - > trx - > active_trans = = 0 ) {
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
innobase_register_trx_and_stmt ( ht , user_thd ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
prebuilt - > trx - > active_trans = 1 ;
}
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* We did the necessary inits in this function, no need to repeat them
in row_search_for_mysql */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
prebuilt - > sql_stat_start = FALSE ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* We let HANDLER always to do the reads as consistent reads, even
if the trx isolation level would have been specified as SERIALIZABLE */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
prebuilt - > select_lock_type = LOCK_NONE ;
prebuilt - > stored_select_lock_type = LOCK_NONE ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* Always fetch all columns in the index record */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
prebuilt - > hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* We want always to fetch all columns in the whole row? Or do
2005-10-27 09:29:40 +02:00
we ? ? ? ? */
prebuilt - > used_in_HANDLER = TRUE ;
2007-05-14 13:08:44 +02:00
reset_template ( prebuilt ) ;
2005-10-27 09:29:40 +02:00
}
/*************************************************************************
Opens an InnoDB database . */
2007-02-12 14:08:02 +01:00
static
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
int
2007-05-10 13:31:36 +02:00
innobase_init (
/*==========*/
/* out: 0 on success, error code on failure */
void * p ) /* in: InnoDB handlerton */
2005-10-27 09:29:40 +02:00
{
static char current_dir [ 3 ] ; /* Set if using current lib */
int err ;
bool ret ;
2006-02-21 13:37:54 +01:00
char * default_path ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " innobase_init " ) ;
2006-10-03 14:46:23 +02:00
handlerton * innobase_hton = ( handlerton * ) p ;
2007-05-10 13:31:36 +02:00
innodb_hton_ptr = innobase_hton ;
2006-09-20 11:38:09 +02:00
2007-05-10 13:31:36 +02:00
innobase_hton - > state = SHOW_OPTION_YES ;
2006-09-20 11:38:09 +02:00
innobase_hton - > db_type = DB_TYPE_INNODB ;
innobase_hton - > savepoint_offset = sizeof ( trx_named_savept_t ) ;
innobase_hton - > close_connection = innobase_close_connection ;
innobase_hton - > savepoint_set = innobase_savepoint ;
innobase_hton - > savepoint_rollback = innobase_rollback_to_savepoint ;
innobase_hton - > savepoint_release = innobase_release_savepoint ;
innobase_hton - > commit = innobase_commit ;
innobase_hton - > rollback = innobase_rollback ;
innobase_hton - > prepare = innobase_xa_prepare ;
innobase_hton - > recover = innobase_xa_recover ;
innobase_hton - > commit_by_xid = innobase_commit_by_xid ;
innobase_hton - > rollback_by_xid = innobase_rollback_by_xid ;
innobase_hton - > create_cursor_read_view = innobase_create_cursor_view ;
innobase_hton - > set_cursor_read_view = innobase_set_cursor_view ;
innobase_hton - > close_cursor_read_view = innobase_close_cursor_view ;
innobase_hton - > create = innobase_create_handler ;
innobase_hton - > drop_database = innobase_drop_database ;
innobase_hton - > panic = innobase_end ;
innobase_hton - > start_consistent_snapshot = innobase_start_trx_and_assign_read_view ;
innobase_hton - > flush_logs = innobase_flush_logs ;
innobase_hton - > show_status = innobase_show_status ;
innobase_hton - > flags = HTON_NO_FLAGS ;
innobase_hton - > release_temporary_latches = innobase_release_temporary_latches ;
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
2005-10-27 09:29:40 +02:00
ut_a ( DATA_MYSQL_TRUE_VARCHAR = = ( ulint ) MYSQL_TYPE_VARCHAR ) ;
Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).
innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.
dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.
dict_scan_id(): Convert the identifier to UTF-8.
dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().
mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
2006-05-24 12:27:17 +02:00
# ifdef UNIV_DEBUG
static const char test_filename [ ] = " -@ " ;
char test_tablename [ sizeof test_filename
+ sizeof srv_mysql50_table_name_prefix ] ;
if ( ( sizeof test_tablename ) - 1
! = filename_to_tablename ( test_filename , test_tablename ,
sizeof test_tablename )
| | strncmp ( test_tablename ,
srv_mysql50_table_name_prefix ,
sizeof srv_mysql50_table_name_prefix )
| | strcmp ( test_tablename
+ sizeof srv_mysql50_table_name_prefix ,
test_filename ) ) {
sql_print_error ( " tablename encoding has been changed " ) ;
goto error ;
}
# endif /* UNIV_DEBUG */
2005-11-29 12:10:15 +01:00
/* Check that values don't overflow on 32-bit systems. */
if ( sizeof ( ulint ) = = 4 ) {
if ( innobase_buffer_pool_size > UINT_MAX32 ) {
sql_print_error (
" innobase_buffer_pool_size can't be over 4GB "
" on 32-bit systems " ) ;
2006-01-18 11:52:53 +01:00
goto error ;
2005-11-29 12:10:15 +01:00
}
if ( innobase_log_file_size > UINT_MAX32 ) {
sql_print_error (
" innobase_log_file_size can't be over 4GB "
" on 32-bit systems " ) ;
2006-01-18 11:52:53 +01:00
goto error ;
2005-11-29 12:10:15 +01:00
}
}
2006-02-21 13:37:54 +01:00
os_innodb_umask = ( ulint ) my_umask ;
2005-10-27 09:29:40 +02:00
/* First calculate the default path for innodb_data_home_dir etc.,
in case the user has not given any value .
Note that when using the embedded server , the datadirectory is not
necessarily the current directory of this program . */
if ( mysqld_embedded ) {
default_path = mysql_real_data_home ;
fil_path_to_mysql_datadir = mysql_real_data_home ;
} else {
2006-02-21 13:37:54 +01:00
/* It's better to use current lib, to keep paths short */
current_dir [ 0 ] = FN_CURLIB ;
current_dir [ 1 ] = FN_LIBCHAR ;
current_dir [ 2 ] = 0 ;
default_path = current_dir ;
2005-10-27 09:29:40 +02:00
}
ut_a ( default_path ) ;
if ( specialflag & SPECIAL_NO_PRIOR ) {
2006-02-21 13:37:54 +01:00
srv_set_thread_priorities = FALSE ;
2005-10-27 09:29:40 +02:00
} else {
2006-02-21 13:37:54 +01:00
srv_set_thread_priorities = TRUE ;
srv_query_thread_priority = QUERY_PRIOR ;
2005-10-27 09:29:40 +02:00
}
/* Set InnoDB initialization parameters according to the values
read from MySQL . cnf file */
/*--------------- Data files -------------------------*/
/* The default dir for data files is the datadir of MySQL */
srv_data_home = ( innobase_data_home_dir ? innobase_data_home_dir :
default_path ) ;
/* Set default InnoDB data file size to 10 MB and let it be
2006-02-21 13:37:54 +01:00
auto - extending . Thus users can use InnoDB in > = 4.0 without having
2005-10-27 09:29:40 +02:00
to specify any startup options . */
if ( ! innobase_data_file_path ) {
2006-02-21 13:37:54 +01:00
innobase_data_file_path = ( char * ) " ibdata1:10M:autoextend " ;
2005-10-27 09:29:40 +02:00
}
/* Since InnoDB edits the argument in the next call, we make another
copy of it : */
internal_innobase_data_file_path = my_strdup ( innobase_data_file_path ,
MYF ( MY_FAE ) ) ;
ret = ( bool ) srv_parse_data_file_paths_and_sizes (
internal_innobase_data_file_path ,
& srv_data_file_names ,
& srv_data_file_sizes ,
& srv_data_file_is_raw_partition ,
& srv_n_data_files ,
& srv_auto_extend_last_data_file ,
& srv_last_file_size_max ) ;
if ( ret = = FALSE ) {
2006-02-21 13:37:54 +01:00
sql_print_error (
2005-10-27 09:29:40 +02:00
" InnoDB: syntax error in innodb_data_file_path " ) ;
2006-02-21 13:37:54 +01:00
my_free ( internal_innobase_data_file_path ,
2005-10-27 09:29:40 +02:00
MYF ( MY_ALLOW_ZERO_PTR ) ) ;
2006-02-21 13:37:54 +01:00
goto error ;
2005-10-27 09:29:40 +02:00
}
/* -------------- Log files ---------------------------*/
/* The default dir for log files is the datadir of MySQL */
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
if ( ! innobase_log_group_home_dir ) {
2006-02-21 13:37:54 +01:00
innobase_log_group_home_dir = default_path ;
2005-10-27 09:29:40 +02:00
}
2006-02-21 13:37:54 +01:00
# ifdef UNIV_LOG_ARCHIVE
2005-10-27 09:29:40 +02:00
/* Since innodb_log_arch_dir has no relevance under MySQL,
starting from 4.0 .6 we always set it the same as
innodb_log_group_home_dir : */
innobase_log_arch_dir = innobase_log_group_home_dir ;
srv_arch_dir = innobase_log_arch_dir ;
# endif /* UNIG_LOG_ARCHIVE */
ret = ( bool )
srv_parse_log_group_home_dirs ( innobase_log_group_home_dir ,
& srv_log_group_home_dirs ) ;
if ( ret = = FALSE | | innobase_mirrored_log_groups ! = 1 ) {
sql_print_error ( " syntax error in innodb_log_group_home_dir, or a "
" wrong number of mirrored log groups " ) ;
2006-02-21 13:37:54 +01:00
my_free ( internal_innobase_data_file_path ,
2005-10-27 09:29:40 +02:00
MYF ( MY_ALLOW_ZERO_PTR ) ) ;
2006-02-21 13:37:54 +01:00
goto error ;
2005-10-27 09:29:40 +02:00
}
/* --------------------------------------------------*/
srv_file_flush_method_str = innobase_unix_file_flush_method ;
srv_n_log_groups = ( ulint ) innobase_mirrored_log_groups ;
srv_n_log_files = ( ulint ) innobase_log_files_in_group ;
srv_log_file_size = ( ulint ) innobase_log_file_size ;
# ifdef UNIV_LOG_ARCHIVE
srv_log_archive_on = ( ulint ) innobase_log_archive ;
# endif /* UNIV_LOG_ARCHIVE */
srv_log_buffer_size = ( ulint ) innobase_log_buffer_size ;
2006-02-21 13:37:54 +01:00
/* We set srv_pool_size here in units of 1 kB. InnoDB internally
changes the value so that it becomes the number of database pages . */
if ( innobase_buffer_pool_awe_mem_mb = = 0 ) {
2007-05-11 17:38:34 +02:00
srv_pool_size = ( ulint ) ( innobase_buffer_pool_size / 1024 ) ;
2006-02-21 13:37:54 +01:00
} else {
srv_use_awe = TRUE ;
srv_pool_size = ( ulint )
( 1024 * innobase_buffer_pool_awe_mem_mb ) ;
srv_awe_window_size = ( ulint ) innobase_buffer_pool_size ;
/* Note that what the user specified as
innodb_buffer_pool_size is actually the AWE memory window
size in this case , and the real buffer pool size is
determined by . . _awe_mem_mb . */
}
2005-10-27 09:29:40 +02:00
srv_mem_pool_size = ( ulint ) innobase_additional_mem_pool_size ;
srv_n_file_io_threads = ( ulint ) innobase_file_io_threads ;
srv_lock_wait_timeout = ( ulint ) innobase_lock_wait_timeout ;
srv_force_recovery = ( ulint ) innobase_force_recovery ;
srv_use_doublewrite_buf = ( ibool ) innobase_use_doublewrite ;
srv_use_checksums = ( ibool ) innobase_use_checksums ;
2007-05-10 13:31:36 +02:00
# ifdef HAVE_LARGE_PAGES
if ( ( os_use_large_pages = ( ibool ) my_use_large_pages ) )
os_large_page_size = ( ulint ) opt_large_page_size ;
# endif
2006-02-21 13:37:54 +01:00
2007-01-11 12:45:58 +01:00
row_rollback_on_timeout = ( ibool ) innobase_rollback_on_timeout ;
2005-10-27 09:29:40 +02:00
srv_file_per_table = ( ibool ) innobase_file_per_table ;
2006-02-21 13:37:54 +01:00
srv_locks_unsafe_for_binlog = ( ibool ) innobase_locks_unsafe_for_binlog ;
2005-10-27 09:29:40 +02:00
srv_max_n_open_files = ( ulint ) innobase_open_files ;
srv_innodb_status = ( ibool ) innobase_create_status_file ;
2007-09-14 10:19:48 +02:00
srv_use_adaptive_hash_indexes =
2008-02-05 14:29:30 +01:00
( ibool ) innobase_adaptive_hash_index ;
2007-09-14 10:19:48 +02:00
2005-10-27 09:29:40 +02:00
srv_print_verbose_log = mysqld_embedded ? 0 : 1 ;
/* Store the default charset-collation number of this MySQL
installation */
data_mysql_default_charset_coll = ( ulint ) default_charset_info - > number ;
ut_a ( DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL = =
my_charset_latin1 . number ) ;
2005-12-14 15:05:34 +01:00
ut_a ( DATA_MYSQL_BINARY_CHARSET_COLL = = my_charset_bin . number ) ;
2005-10-27 09:29:40 +02:00
/* Store the latin1_swedish_ci character ordering table to InnoDB. For
non - latin1_swedish_ci charsets we use the MySQL comparison functions ,
and consequently we do not need to know the ordering internally in
InnoDB . */
ut_a ( 0 = = strcmp ( ( char * ) my_charset_latin1 . name ,
( char * ) " latin1_swedish_ci " ) ) ;
memcpy ( srv_latin1_ordering , my_charset_latin1 . sort_order , 256 ) ;
2009-06-25 14:11:57 +02:00
innobase_commit_concurrency_init_default ( ) ;
2005-10-27 09:29:40 +02:00
/* Since we in this module access directly the fields of a trx
2006-02-21 13:37:54 +01:00
struct , and due to different headers and flags it might happen that
2005-10-27 09:29:40 +02:00
mutex_t has a different size in this module and in InnoDB
modules , we check at run time that the size is the same in
these compilation modules . */
srv_sizeof_trx_t_in_ha_innodb_cc = sizeof ( trx_t ) ;
err = innobase_start_or_create_for_mysql ( ) ;
if ( err ! = DB_SUCCESS ) {
2006-02-21 13:37:54 +01:00
my_free ( internal_innobase_data_file_path ,
2005-10-27 09:29:40 +02:00
MYF ( MY_ALLOW_ZERO_PTR ) ) ;
2006-02-21 13:37:54 +01:00
goto error ;
2005-10-27 09:29:40 +02:00
}
( void ) hash_init ( & innobase_open_tables , system_charset_info , 32 , 0 , 0 ,
2006-02-21 13:37:54 +01:00
( hash_get_key ) innobase_get_key , 0 , 0 ) ;
pthread_mutex_init ( & innobase_share_mutex , MY_MUTEX_INIT_FAST ) ;
pthread_mutex_init ( & prepare_commit_mutex , MY_MUTEX_INIT_FAST ) ;
pthread_mutex_init ( & commit_threads_m , MY_MUTEX_INIT_FAST ) ;
pthread_mutex_init ( & commit_cond_m , MY_MUTEX_INIT_FAST ) ;
2009-10-01 13:55:49 +02:00
pthread_mutex_init ( & analyze_mutex , MY_MUTEX_INIT_FAST ) ;
2006-02-21 13:37:54 +01:00
pthread_cond_init ( & commit_cond , NULL ) ;
2005-10-27 09:29:40 +02:00
innodb_inited = 1 ;
DBUG_RETURN ( FALSE ) ;
error :
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( TRUE ) ;
2005-10-27 09:29:40 +02:00
}
/***********************************************************************
Closes an InnoDB database . */
2007-02-12 14:08:02 +01:00
static
2005-10-27 09:51:34 +02:00
int
2006-10-03 14:46:23 +02:00
innobase_end ( handlerton * hton , ha_panic_function type )
2005-10-27 09:29:40 +02:00
/*==============*/
/* out: TRUE if error */
{
int err = 0 ;
DBUG_ENTER ( " innobase_end " ) ;
2006-02-21 13:37:54 +01:00
# ifdef __NETWARE__ /* some special cleanup for NetWare */
2005-10-27 09:29:40 +02:00
if ( nw_panic ) {
set_panic_flag_for_netware ( ) ;
}
# endif
if ( innodb_inited ) {
2006-02-21 13:37:54 +01:00
srv_fast_shutdown = ( ulint ) innobase_fast_shutdown ;
innodb_inited = 0 ;
if ( innobase_shutdown_for_mysql ( ) ! = DB_SUCCESS ) {
err = 1 ;
2005-10-27 09:29:40 +02:00
}
2006-02-21 13:37:54 +01:00
hash_free ( & innobase_open_tables ) ;
my_free ( internal_innobase_data_file_path ,
2005-10-27 09:29:40 +02:00
MYF ( MY_ALLOW_ZERO_PTR ) ) ;
2006-02-21 13:37:54 +01:00
pthread_mutex_destroy ( & innobase_share_mutex ) ;
pthread_mutex_destroy ( & prepare_commit_mutex ) ;
pthread_mutex_destroy ( & commit_threads_m ) ;
pthread_mutex_destroy ( & commit_cond_m ) ;
2009-10-01 13:55:49 +02:00
pthread_mutex_destroy ( & analyze_mutex ) ;
2006-02-21 13:37:54 +01:00
pthread_cond_destroy ( & commit_cond ) ;
2005-10-27 09:29:40 +02:00
}
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( err ) ;
2005-10-27 09:29:40 +02:00
}
/********************************************************************
Flushes InnoDB logs to disk and makes a checkpoint . Really , a commit flushes
the logs , and the name of this function should be innobase_checkpoint . */
2007-02-12 14:08:02 +01:00
static
2005-10-27 09:29:40 +02:00
bool
2006-10-03 14:46:23 +02:00
innobase_flush_logs ( handlerton * hton )
2005-10-27 09:29:40 +02:00
/*=====================*/
/* out: TRUE if error */
{
2006-02-21 13:37:54 +01:00
bool result = 0 ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " innobase_flush_logs " ) ;
2005-10-27 09:29:40 +02:00
log_buffer_flush_to_disk ( ) ;
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( result ) ;
2005-10-27 09:29:40 +02:00
}
/*********************************************************************
Commits a transaction in an InnoDB database . */
2007-03-27 10:22:27 +02:00
static
2005-10-27 09:29:40 +02:00
void
innobase_commit_low (
/*================*/
trx_t * trx ) /* in: transaction handle */
{
2006-02-21 13:37:54 +01:00
if ( trx - > conc_state = = TRX_NOT_STARTED ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ;
}
2005-10-27 09:29:40 +02:00
trx_commit_for_mysql ( trx ) ;
}
/*********************************************************************
Creates an InnoDB transaction struct for the thd if it does not yet have one .
Starts a new InnoDB transaction if a transaction is not yet started . And
assigns a new snapshot for a consistent read if the transaction does not yet
have one . */
2007-02-12 14:08:02 +01:00
static
2005-10-27 09:29:40 +02:00
int
innobase_start_trx_and_assign_read_view (
/*====================================*/
/* out: 0 */
2006-10-03 14:46:23 +02:00
handlerton * hton , /* in: Innodb handlerton */
2005-10-27 09:29:40 +02:00
THD * thd ) /* in: MySQL thread handle of the user for whom
the transaction should be committed */
{
trx_t * trx ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " innobase_start_trx_and_assign_read_view " ) ;
2005-10-27 09:29:40 +02:00
/* Create a new trx struct for thd, if it does not yet have one */
2007-05-10 14:09:03 +02:00
trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
/* This is just to play safe: release a possible FIFO ticket and
search latch . Since we will reserve the kernel mutex , we have to
release the search system latch first to obey the latching order . */
innobase_release_stat_resources ( trx ) ;
/* If the transaction is not started yet, start it */
trx_start_if_not_started_noninline ( trx ) ;
/* Assign a read view if the transaction does not have it yet */
trx_assign_read_view ( trx ) ;
/* Set the MySQL flag to mark that there is an active transaction */
2006-02-21 13:37:54 +01:00
if ( trx - > active_trans = = 0 ) {
2006-10-03 14:46:23 +02:00
innobase_register_trx_and_stmt ( hton , current_thd ) ;
2006-02-21 13:37:54 +01:00
trx - > active_trans = 1 ;
}
2005-10-27 09:29:40 +02:00
DBUG_RETURN ( 0 ) ;
}
/*********************************************************************
Commits a transaction in an InnoDB database or marks an SQL statement
ended . */
static
int
innobase_commit (
/*============*/
/* out: 0 */
2006-10-03 14:46:23 +02:00
handlerton * hton , /* in: Innodb handlerton */
THD * thd , /* in: MySQL thread handle of the user for whom
2005-10-27 09:29:40 +02:00
the transaction should be committed */
2006-02-21 13:37:54 +01:00
bool all ) /* in: TRUE - commit transaction
FALSE - the current SQL statement ended */
2005-10-27 09:29:40 +02:00
{
trx_t * trx ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " innobase_commit " ) ;
DBUG_PRINT ( " trans " , ( " ending transaction " ) ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 14:09:03 +02:00
trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
/* Update the info whether we should skip XA steps that eat CPU time */
2007-05-10 13:31:36 +02:00
trx - > support_xa = THDVAR ( thd , support_xa ) ;
2005-10-27 09:29:40 +02:00
2007-03-27 19:59:15 +02:00
/* Since we will reserve the kernel mutex, we have to release
the search system latch first to obey the latching order . */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( trx - > has_search_latch ) {
2007-03-27 19:59:15 +02:00
trx_search_latch_release_if_reserved ( trx ) ;
2006-02-21 13:37:54 +01:00
}
/* The flag trx->active_trans is set to 1 in
2005-10-27 09:29:40 +02:00
1. : : external_lock ( ) ,
2. : : start_stmt ( ) ,
3. innobase_query_caching_of_table_permitted ( ) ,
4. innobase_savepoint ( ) ,
5. : : init_table_handle_for_HANDLER ( ) ,
6. innobase_start_trx_and_assign_read_view ( ) ,
7. : : transactional_table_lock ( )
and it is only set to 0 in a commit or a rollback . If it is 0 we know
there cannot be resources to be freed and we could return immediately .
For the time being , we play safe and do the cleanup though there should
be nothing to clean up . */
2006-02-21 13:37:54 +01:00
if ( trx - > active_trans = = 0
& & trx - > conc_state ! = TRX_NOT_STARTED ) {
sql_print_error ( " trx->active_trans == 0, but "
" trx->conc_state != TRX_NOT_STARTED " ) ;
2005-10-27 09:29:40 +02:00
}
2006-02-21 13:37:54 +01:00
if ( all
2007-05-10 13:31:36 +02:00
| | ( ! thd_test_options ( thd , OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN ) ) ) {
2006-02-21 13:37:54 +01:00
/* We were instructed to commit the whole transaction, or
2005-10-27 09:29:40 +02:00
this is an SQL statement end and autocommit is on */
2006-02-21 13:37:54 +01:00
/* We need current binlog position for ibbackup to work.
Note , the position is current because of
prepare_commit_mutex */
2005-10-27 09:29:40 +02:00
retry :
2009-05-14 13:04:55 +02:00
if ( innobase_commit_concurrency > 0 ) {
2006-02-21 13:37:54 +01:00
pthread_mutex_lock ( & commit_cond_m ) ;
commit_threads + + ;
2009-05-14 13:04:55 +02:00
if ( commit_threads > innobase_commit_concurrency ) {
2006-02-21 13:37:54 +01:00
commit_threads - - ;
pthread_cond_wait ( & commit_cond ,
& commit_cond_m ) ;
pthread_mutex_unlock ( & commit_cond_m ) ;
goto retry ;
}
else {
pthread_mutex_unlock ( & commit_cond_m ) ;
}
}
2007-05-10 13:31:36 +02:00
trx - > mysql_log_file_name = mysql_bin_log_file_name ( ) ;
trx - > mysql_log_offset = ( ib_longlong ) mysql_bin_log_file_pos ( ) ;
2005-10-27 09:29:40 +02:00
innobase_commit_low ( trx ) ;
2009-05-14 13:04:55 +02:00
if ( innobase_commit_concurrency > 0 ) {
2006-02-21 13:37:54 +01:00
pthread_mutex_lock ( & commit_cond_m ) ;
commit_threads - - ;
pthread_cond_signal ( & commit_cond ) ;
pthread_mutex_unlock ( & commit_cond_m ) ;
}
if ( trx - > active_trans = = 2 ) {
pthread_mutex_unlock ( & prepare_commit_mutex ) ;
}
trx - > active_trans = 0 ;
2005-10-27 09:29:40 +02:00
} else {
2006-02-21 13:37:54 +01:00
/* We just mark the SQL statement ended and do not do a
2005-10-27 09:29:40 +02:00
transaction commit */
2007-11-30 10:36:27 +01:00
/* If we had reserved the auto-inc lock for some
table in this SQL statement we release it now */
row_unlock_table_autoinc_for_mysql ( trx ) ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
/* Store the current undo_no of the transaction so that we
know where to roll back if we have to roll back the next
SQL statement */
trx_mark_sql_stat_end ( trx ) ;
}
2007-07-24 03:42:16 +02:00
trx - > n_autoinc_rows = 0 ; /* Reset the number AUTO-INC rows required */
2006-02-21 13:37:54 +01:00
if ( trx - > declared_to_be_inside_innodb ) {
2007-03-27 19:59:15 +02:00
/* Release our possible ticket in the FIFO */
2005-10-27 09:29:40 +02:00
2007-03-27 19:59:15 +02:00
srv_conc_force_exit_innodb ( trx ) ;
2006-02-21 13:37:54 +01:00
}
2007-03-27 19:59:15 +02:00
/* Tell the InnoDB server that there might be work for utility
threads : */
2005-10-27 09:29:40 +02:00
srv_active_wake_master_thread ( ) ;
DBUG_RETURN ( 0 ) ;
}
/*********************************************************************
Rolls back a transaction or the latest SQL statement . */
2007-05-10 13:31:36 +02:00
static
int
2005-10-27 09:29:40 +02:00
innobase_rollback (
/*==============*/
/* out: 0 or error number */
2006-10-03 14:46:23 +02:00
handlerton * hton , /* in: Innodb handlerton */
2005-10-27 09:29:40 +02:00
THD * thd , /* in: handle to the MySQL thread of the user
whose transaction should be rolled back */
2006-02-21 13:37:54 +01:00
bool all ) /* in: TRUE - commit transaction
FALSE - the current SQL statement ended */
2005-10-27 09:29:40 +02:00
{
int error = 0 ;
trx_t * trx ;
DBUG_ENTER ( " innobase_rollback " ) ;
DBUG_PRINT ( " trans " , ( " aborting transaction " ) ) ;
2007-05-10 14:09:03 +02:00
trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
/* Update the info whether we should skip XA steps that eat CPU time */
2007-05-10 13:31:36 +02:00
trx - > support_xa = THDVAR ( thd , support_xa ) ;
2005-10-27 09:29:40 +02:00
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex , we have to release the search system latch
first to obey the latching order . */
innobase_release_stat_resources ( trx ) ;
2009-10-12 05:09:56 +02:00
trx - > n_autoinc_rows = 0 ; /* Reset the number AUTO-INC rows required */
2007-11-30 10:36:27 +01:00
/* If we had reserved the auto-inc lock for some table (if
we come here to roll back the latest SQL statement ) we
release it now before a possibly lengthy rollback */
2006-02-21 13:37:54 +01:00
2007-11-30 10:36:27 +01:00
row_unlock_table_autoinc_for_mysql ( trx ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( all
2007-05-10 13:31:36 +02:00
| | ! thd_test_options ( thd , OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN ) ) {
2005-10-27 09:29:40 +02:00
error = trx_rollback_for_mysql ( trx ) ;
2006-02-21 13:37:54 +01:00
trx - > active_trans = 0 ;
2005-10-27 09:29:40 +02:00
} else {
error = trx_rollback_last_sql_stat_for_mysql ( trx ) ;
}
DBUG_RETURN ( convert_error_code_to_mysql ( error , NULL ) ) ;
}
/*********************************************************************
Rolls back a transaction */
2007-03-27 10:22:27 +02:00
static
2005-10-27 09:29:40 +02:00
int
innobase_rollback_trx (
/*==================*/
/* out: 0 or error number */
trx_t * trx ) /* in: transaction */
{
int error = 0 ;
DBUG_ENTER ( " innobase_rollback_trx " ) ;
DBUG_PRINT ( " trans " , ( " aborting transaction " ) ) ;
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex , we have to release the search system latch
first to obey the latching order . */
innobase_release_stat_resources ( trx ) ;
2007-11-30 10:36:27 +01:00
/* If we had reserved the auto-inc lock for some table (if
we come here to roll back the latest SQL statement ) we
release it now before a possibly lengthy rollback */
2006-02-21 13:37:54 +01:00
2007-11-30 10:36:27 +01:00
row_unlock_table_autoinc_for_mysql ( trx ) ;
2005-10-27 09:29:40 +02:00
error = trx_rollback_for_mysql ( trx ) ;
DBUG_RETURN ( convert_error_code_to_mysql ( error , NULL ) ) ;
}
/*********************************************************************
Rolls back a transaction to a savepoint . */
2007-05-10 14:09:03 +02:00
static
int
2005-10-27 09:29:40 +02:00
innobase_rollback_to_savepoint (
/*===========================*/
/* out: 0 if success, HA_ERR_NO_SAVEPOINT if
no savepoint with the given name */
2006-10-03 14:46:23 +02:00
handlerton * hton , /* in: Innodb handlerton */
2005-10-27 09:29:40 +02:00
THD * thd , /* in: handle to the MySQL thread of the user
whose transaction should be rolled back */
2006-02-21 13:37:54 +01:00
void * savepoint ) /* in: savepoint data */
2005-10-27 09:29:40 +02:00
{
2006-02-21 13:37:54 +01:00
ib_longlong mysql_binlog_cache_pos ;
int error = 0 ;
trx_t * trx ;
char name [ 64 ] ;
2005-10-27 09:29:40 +02:00
DBUG_ENTER ( " innobase_rollback_to_savepoint " ) ;
2007-05-10 14:09:03 +02:00
trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex , we have to release the search system latch
first to obey the latching order . */
innobase_release_stat_resources ( trx ) ;
2006-02-21 13:37:54 +01:00
/* TODO: use provided savepoint data area to store savepoint data */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
longlong2str ( ( ulint ) savepoint , name , 36 ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
error = ( int ) trx_rollback_to_savepoint_for_mysql ( trx , name ,
2005-10-27 09:29:40 +02:00
& mysql_binlog_cache_pos ) ;
DBUG_RETURN ( convert_error_code_to_mysql ( error , NULL ) ) ;
}
/*********************************************************************
Release transaction savepoint name . */
static
int
innobase_release_savepoint (
/*=======================*/
/* out: 0 if success, HA_ERR_NO_SAVEPOINT if
no savepoint with the given name */
2006-10-03 14:46:23 +02:00
handlerton * hton , /* in: handlerton for Innodb */
2005-10-27 09:29:40 +02:00
THD * thd , /* in: handle to the MySQL thread of the user
whose transaction should be rolled back */
2006-02-21 13:37:54 +01:00
void * savepoint ) /* in: savepoint data */
2005-10-27 09:29:40 +02:00
{
2006-02-21 13:37:54 +01:00
int error = 0 ;
trx_t * trx ;
char name [ 64 ] ;
2005-10-27 09:29:40 +02:00
DBUG_ENTER ( " innobase_release_savepoint " ) ;
2007-05-10 14:09:03 +02:00
trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* TODO: use provided savepoint data area to store savepoint data */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
longlong2str ( ( ulint ) savepoint , name , 36 ) ;
2005-10-27 09:29:40 +02:00
error = ( int ) trx_release_savepoint_for_mysql ( trx , name ) ;
DBUG_RETURN ( convert_error_code_to_mysql ( error , NULL ) ) ;
}
/*********************************************************************
Sets a transaction savepoint . */
static
int
innobase_savepoint (
/*===============*/
/* out: always 0, that is, always succeeds */
2006-10-03 14:46:23 +02:00
handlerton * hton , /* in: handle to the Innodb handlerton */
2005-10-27 09:29:40 +02:00
THD * thd , /* in: handle to the MySQL thread */
2006-02-21 13:37:54 +01:00
void * savepoint ) /* in: savepoint data */
2005-10-27 09:29:40 +02:00
{
int error = 0 ;
trx_t * trx ;
DBUG_ENTER ( " innobase_savepoint " ) ;
2006-02-21 13:37:54 +01:00
/*
In the autocommit mode there is no sense to set a savepoint
( unless we are in sub - statement ) , so SQL layer ensures that
this method is never called in such situation .
*/
2007-05-10 13:31:36 +02:00
# ifdef MYSQL_SERVER /* plugins cannot access thd->in_sub_stmt */
DBUG_ASSERT ( thd_test_options ( thd , OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN ) | |
2006-02-21 13:37:54 +01:00
thd - > in_sub_stmt ) ;
2007-05-10 13:31:36 +02:00
# endif /* MYSQL_SERVER */
2005-10-27 09:29:40 +02:00
2007-05-10 14:09:03 +02:00
trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex , we have to release the search system latch
first to obey the latching order . */
innobase_release_stat_resources ( trx ) ;
2006-02-21 13:37:54 +01:00
/* cannot happen outside of transaction */
DBUG_ASSERT ( trx - > active_trans ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* TODO: use provided savepoint data area to store savepoint data */
char name [ 64 ] ;
longlong2str ( ( ulint ) savepoint , name , 36 ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
error = ( int ) trx_savepoint_for_mysql ( trx , name , ( ib_longlong ) 0 ) ;
2005-10-27 09:29:40 +02:00
DBUG_RETURN ( convert_error_code_to_mysql ( error , NULL ) ) ;
}
/*********************************************************************
Frees a possible InnoDB trx object associated with the current THD . */
static
int
innobase_close_connection (
/*======================*/
/* out: 0 or error number */
2006-10-03 14:46:23 +02:00
handlerton * hton , /* in: innobase handlerton */
2005-10-27 09:29:40 +02:00
THD * thd ) /* in: handle to the MySQL thread of the user
whose resources should be free ' d */
{
trx_t * trx ;
2007-05-10 14:09:03 +02:00
DBUG_ENTER ( " innobase_close_connection " ) ;
DBUG_ASSERT ( hton = = innodb_hton_ptr ) ;
trx = thd_to_trx ( thd ) ;
2005-10-27 09:29:40 +02:00
ut_a ( trx ) ;
2006-02-21 13:37:54 +01:00
if ( trx - > active_trans = = 0
& & trx - > conc_state ! = TRX_NOT_STARTED ) {
sql_print_error ( " trx->active_trans == 0, but "
" trx->conc_state != TRX_NOT_STARTED " ) ;
2005-10-27 09:29:40 +02:00
}
if ( trx - > conc_state ! = TRX_NOT_STARTED & &
2006-02-21 13:37:54 +01:00
global_system_variables . log_warnings ) {
sql_print_warning (
" MySQL is closing a connection that has an active "
" InnoDB transaction. %lu row modifications will "
" roll back. " ,
( ulong ) trx - > undo_no . low ) ;
}
2005-10-27 09:29:40 +02:00
innobase_rollback_trx ( trx ) ;
2006-03-31 06:58:02 +02:00
thr_local_free ( trx - > mysql_thread_id ) ;
2006-02-21 13:37:54 +01:00
trx_free_for_mysql ( trx ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 14:09:03 +02:00
DBUG_RETURN ( 0 ) ;
2005-10-27 09:29:40 +02:00
}
/*****************************************************************************
* * InnoDB database tables
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/********************************************************************
Get the record format from the data dictionary . */
enum row_type
ha_innobase : : get_row_type ( ) const
/*=============================*/
/* out: ROW_TYPE_REDUNDANT or ROW_TYPE_COMPACT */
{
if ( prebuilt & & prebuilt - > table ) {
2006-03-13 10:27:34 +01:00
if ( dict_table_is_comp_noninline ( prebuilt - > table ) ) {
2005-10-27 09:29:40 +02:00
return ( ROW_TYPE_COMPACT ) ;
} else {
return ( ROW_TYPE_REDUNDANT ) ;
}
}
ut_ad ( 0 ) ;
return ( ROW_TYPE_NOT_USED ) ;
}
2007-07-31 07:56:17 +02:00
/********************************************************************
Get the table flags to use for the statement . */
handler : : Table_flags
ha_innobase : : table_flags ( ) const
{
/* Need to use tx_isolation here since table flags is (also)
called before prebuilt is inited . */
ulong const tx_isolation = thd_tx_isolation ( current_thd ) ;
if ( tx_isolation < = ISO_READ_COMMITTED )
return int_table_flags ;
return int_table_flags | HA_BINLOG_STMT_CAPABLE ;
}
2005-10-27 09:29:40 +02:00
/********************************************************************
Gives the file extension of an InnoDB single - table tablespace . */
static const char * ha_innobase_exts [ ] = {
" .ibd " ,
NullS
} ;
const char * *
ha_innobase : : bas_ext ( ) const
/*========================*/
/* out: file extension string */
{
return ha_innobase_exts ;
}
/*********************************************************************
Normalizes a table name string . A normalized name consists of the
database name catenated to ' / ' and table name . An example :
test / mytable . On Windows normalization puts both the database name and the
table name always to lower case . */
static
void
normalize_table_name (
/*=================*/
char * norm_name , /* out: normalized name as a
null - terminated string */
const char * name ) /* in: table name string */
{
char * name_ptr ;
char * db_ptr ;
char * ptr ;
/* Scan name from the end */
ptr = strend ( name ) - 1 ;
while ( ptr > = name & & * ptr ! = ' \\ ' & & * ptr ! = ' / ' ) {
ptr - - ;
}
name_ptr = ptr + 1 ;
DBUG_ASSERT ( ptr > name ) ;
ptr - - ;
while ( ptr > = name & & * ptr ! = ' \\ ' & & * ptr ! = ' / ' ) {
ptr - - ;
}
db_ptr = ptr + 1 ;
memcpy ( norm_name , db_ptr , strlen ( name ) + 1 - ( db_ptr - name ) ) ;
norm_name [ name_ptr - db_ptr - 1 ] = ' / ' ;
# ifdef __WIN__
innobase_casedn_str ( norm_name ) ;
# endif
}
2010-01-12 11:22:19 +01:00
/************************************************************************
Get the upper limit of the MySQL integral and floating - point type . */
static
ulonglong
innobase_get_int_col_max_value (
/*===========================*/
/* out: maximum allowed value for the field */
const Field * field ) /* in: MySQL field */
{
ulonglong max_value = 0 ;
switch ( field - > key_type ( ) ) {
/* TINY */
case HA_KEYTYPE_BINARY :
max_value = 0xFFULL ;
break ;
case HA_KEYTYPE_INT8 :
max_value = 0x7FULL ;
break ;
/* SHORT */
case HA_KEYTYPE_USHORT_INT :
max_value = 0xFFFFULL ;
break ;
case HA_KEYTYPE_SHORT_INT :
max_value = 0x7FFFULL ;
break ;
/* MEDIUM */
case HA_KEYTYPE_UINT24 :
max_value = 0xFFFFFFULL ;
break ;
case HA_KEYTYPE_INT24 :
max_value = 0x7FFFFFULL ;
break ;
/* LONG */
case HA_KEYTYPE_ULONG_INT :
max_value = 0xFFFFFFFFULL ;
break ;
case HA_KEYTYPE_LONG_INT :
max_value = 0x7FFFFFFFULL ;
break ;
/* BIG */
case HA_KEYTYPE_ULONGLONG :
max_value = 0xFFFFFFFFFFFFFFFFULL ;
break ;
case HA_KEYTYPE_LONGLONG :
max_value = 0x7FFFFFFFFFFFFFFFULL ;
break ;
case HA_KEYTYPE_FLOAT :
/* We use the maximum as per IEEE754-2008 standard, 2^24 */
max_value = 0x1000000ULL ;
break ;
case HA_KEYTYPE_DOUBLE :
/* We use the maximum as per IEEE754-2008 standard, 2^53 */
max_value = 0x20000000000000ULL ;
break ;
default :
ut_error ;
}
return ( max_value ) ;
}
2008-10-23 06:30:32 +02:00
/************************************************************************
Set the autoinc column max value . This should only be called once from
ha_innobase : : open ( ) . Therefore there ' s no need for a covering lock . */
2010-01-12 11:22:19 +01:00
void
2008-10-23 06:30:32 +02:00
ha_innobase : : innobase_initialize_autoinc ( )
/*======================================*/
{
ulonglong auto_inc ;
2010-01-12 11:22:19 +01:00
const Field * field = table - > found_next_number_field ;
2009-06-04 01:17:14 +02:00
2010-01-12 11:22:19 +01:00
if ( field ! = NULL ) {
auto_inc = innobase_get_int_col_max_value ( field ) ;
} else {
/* We have no idea what's been passed in to us as the
2010-01-29 23:35:00 +01:00
autoinc column . We set it to the 0 , effectively disabling
updates to the table . */
auto_inc = 0 ;
2009-06-04 01:17:14 +02:00
2010-01-12 11:22:19 +01:00
ut_print_timestamp ( stderr ) ;
fprintf ( stderr , " InnoDB: Unable to determine the AUTOINC "
" column name \n " ) ;
}
if ( srv_force_recovery > = SRV_FORCE_NO_IBUF_MERGE ) {
/* If the recovery level is set so high that writes
2010-01-29 23:35:00 +01:00
are disabled we force the AUTOINC counter to 0
2010-01-12 11:22:19 +01:00
value effectively disabling writes to the table .
Secondly , we avoid reading the table in case the read
results in failure due to a corrupted table / index .
We will not return an error to the client , so that the
tables can be dumped with minimal hassle . If an error
were returned in this case , the first attempt to read
the table would fail and subsequent SELECTs would succeed . */
2010-01-29 23:35:00 +01:00
auto_inc = 0 ;
2010-01-12 11:22:19 +01:00
} else if ( field = = NULL ) {
2010-01-29 23:35:00 +01:00
/* This is a far more serious error, best to avoid
opening the table and return failure . */
2010-01-12 11:22:19 +01:00
my_error ( ER_AUTOINC_READ_FAILED , MYF ( 0 ) ) ;
} else {
dict_index_t * index ;
const char * col_name ;
ulonglong read_auto_inc ;
ulint err ;
update_thd ( ha_thd ( ) ) ;
col_name = field - > field_name ;
index = innobase_get_index ( table - > s - > next_number_index ) ;
/* Execute SELECT MAX(col_name) FROM TABLE; */
err = row_search_max_autoinc ( index , col_name , & read_auto_inc ) ;
switch ( err ) {
case DB_SUCCESS :
/* At the this stage we do not know the increment
or the offset , so use a default increment of 1. */
auto_inc = read_auto_inc + 1 ;
break ;
case DB_RECORD_NOT_FOUND :
ut_print_timestamp ( stderr ) ;
fprintf ( stderr , " InnoDB: MySQL and InnoDB data "
" dictionaries are out of sync. \n "
" InnoDB: Unable to find the AUTOINC column "
" %s in the InnoDB table %s. \n "
" InnoDB: We set the next AUTOINC column "
2010-01-29 23:35:00 +01:00
" value to 0, \n "
2010-01-12 11:22:19 +01:00
" InnoDB: in effect disabling the AUTOINC "
" next value generation. \n "
" InnoDB: You can either set the next "
" AUTOINC value explicitly using ALTER TABLE \n "
" InnoDB: or fix the data dictionary by "
" recreating the table. \n " ,
col_name , index - > table - > name ) ;
2010-01-29 23:35:00 +01:00
/* This will disable the AUTOINC generation. */
auto_inc = 0 ;
/* We want the open to succeed, so that the user can
take corrective action . ie . reads should succeed but
updates should fail . */
err = DB_SUCCESS ;
2010-01-12 11:22:19 +01:00
break ;
default :
/* row_search_max_autoinc() should only return
one of DB_SUCCESS or DB_RECORD_NOT_FOUND . */
ut_error ;
}
}
2008-10-23 06:30:32 +02:00
2010-01-12 11:22:19 +01:00
dict_table_autoinc_initialize ( prebuilt - > table , auto_inc ) ;
2008-10-23 06:30:32 +02:00
}
2005-10-27 09:29:40 +02:00
/*********************************************************************
Creates and opens a handle to a table which already exists in an InnoDB
database . */
int
ha_innobase : : open (
/*==============*/
/* out: 1 if error, 0 if success */
const char * name , /* in: table name */
2006-02-21 13:37:54 +01:00
int mode , /* in: not used */
uint test_if_locked ) /* in: not used */
2005-10-27 09:29:40 +02:00
{
dict_table_t * ib_table ;
2006-02-21 13:37:54 +01:00
char norm_name [ 1000 ] ;
2005-10-27 09:29:40 +02:00
THD * thd ;
2008-01-15 04:22:37 +01:00
ulint retries = 0 ;
char * is_part = NULL ;
2005-10-27 09:29:40 +02:00
DBUG_ENTER ( " ha_innobase::open " ) ;
UT_NOT_USED ( mode ) ;
UT_NOT_USED ( test_if_locked ) ;
2007-05-10 13:31:36 +02:00
thd = ha_thd ( ) ;
2008-09-16 17:11:26 +02:00
/* Under some cases MySQL seems to call this function while
holding btr_search_latch . This breaks the latching order as
we acquire dict_sys - > mutex below and leads to a deadlock . */
if ( thd ! = NULL ) {
innobase_release_temporary_latches ( ht , thd ) ;
}
2005-10-27 09:29:40 +02:00
normalize_table_name ( norm_name , name ) ;
user_thd = NULL ;
if ( ! ( share = get_share ( name ) ) ) {
DBUG_RETURN ( 1 ) ;
}
/* Create buffers for packing the fields of a record. Why
table - > reclength did not work here ? Obviously , because char
fields when packed actually became 1 byte longer , when we also
stored the string length as the first byte . */
upd_and_key_val_buff_len =
table - > s - > reclength + table - > s - > max_key_length
+ MAX_REF_PARTS * 3 ;
2007-08-15 14:29:46 +02:00
if ( ! ( uchar * ) my_multi_malloc ( MYF ( MY_WME ) ,
2006-02-21 13:37:54 +01:00
& upd_buff , upd_and_key_val_buff_len ,
& key_val_buff , upd_and_key_val_buff_len ,
NullS ) ) {
free_share ( share ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( 1 ) ;
}
2005-10-27 09:29:40 +02:00
2008-01-15 04:22:37 +01:00
/* We look for pattern #P# to see if the table is partitioned
MySQL table . The retry logic for partitioned tables is a
workaround for http : //bugs.mysql.com/bug.php?id=33349. Look
at support issue https : //support.mysql.com/view.php?id=21080
for more details . */
is_part = strstr ( norm_name , " #P# " ) ;
retry :
2005-10-27 09:29:40 +02:00
/* Get pointer to a table object in InnoDB dictionary cache */
2006-12-12 10:37:18 +01:00
ib_table = dict_table_get ( norm_name , TRUE ) ;
2008-01-15 04:22:37 +01:00
2006-02-21 13:37:54 +01:00
if ( NULL = = ib_table ) {
2008-01-15 04:22:37 +01:00
if ( is_part & & retries < 10 ) {
+ + retries ;
os_thread_sleep ( 100000 ) ;
goto retry ;
}
if ( is_part ) {
sql_print_error ( " Failed to open table %s after "
" %lu attemtps. \n " , norm_name ,
retries ) ;
}
2007-10-12 18:40:42 +02:00
sql_print_error ( " Cannot find or open table %s from \n "
" the internal data dictionary of InnoDB "
" though the .frm file for the \n "
" table exists. Maybe you have deleted and "
" recreated InnoDB data \n "
" files but have forgotten to delete the "
" corresponding .frm files \n "
" of InnoDB tables, or you have moved .frm "
" files to another database? \n "
" or, the table contains indexes that this "
" version of the engine \n "
" doesn't support. \n "
2006-08-08 12:54:57 +02:00
" See http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html \n "
2005-10-27 09:29:40 +02:00
" how you can resolve the problem. \n " ,
norm_name ) ;
2006-02-21 13:37:54 +01:00
free_share ( share ) ;
2007-06-04 10:45:27 +02:00
my_free ( upd_buff , MYF ( 0 ) ) ;
2006-02-21 13:37:54 +01:00
my_errno = ENOENT ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( HA_ERR_NO_SUCH_TABLE ) ;
}
2005-10-27 09:29:40 +02:00
2007-02-15 15:10:41 +01:00
if ( ib_table - > ibd_file_missing & & ! thd_tablespace_op ( thd ) ) {
2005-10-27 09:29:40 +02:00
sql_print_error ( " MySQL is trying to open a table handle but "
" the .ibd file for \n table %s does not exist. \n "
" Have you deleted the .ibd file from the "
" database directory under \n the MySQL datadir, "
" or have you used DISCARD TABLESPACE? \n "
2006-08-08 12:54:57 +02:00
" See http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html \n "
2005-10-27 09:29:40 +02:00
" how you can resolve the problem. \n " ,
norm_name ) ;
2006-02-21 13:37:54 +01:00
free_share ( share ) ;
2007-06-04 10:45:27 +02:00
my_free ( upd_buff , MYF ( 0 ) ) ;
2006-02-21 13:37:54 +01:00
my_errno = ENOENT ;
2005-10-27 09:29:40 +02:00
dict_table_decrement_handle_count ( ib_table ) ;
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( HA_ERR_NO_SUCH_TABLE ) ;
}
2005-10-27 09:29:40 +02:00
2007-01-11 15:24:53 +01:00
prebuilt = row_create_prebuilt ( ib_table ) ;
2005-10-27 09:29:40 +02:00
2007-01-11 15:24:53 +01:00
prebuilt - > mysql_row_len = table - > s - > reclength ;
2008-12-18 14:33:36 +01:00
prebuilt - > default_rec = table - > s - > default_values ;
ut_ad ( prebuilt - > default_rec ) ;
2005-10-27 09:29:40 +02:00
/* Looks like MySQL-3.23 sometimes has primary key number != 0 */
2006-02-21 13:37:54 +01:00
primary_key = table - > s - > primary_key ;
2005-10-27 09:29:40 +02:00
key_used_on_scan = primary_key ;
/* Allocate a buffer for a 'row reference'. A row reference is
a string of bytes of length ref_length which uniquely specifies
2006-02-21 13:37:54 +01:00
a row in our table . Note that MySQL may also compare two row
references for equality by doing a simple memcmp on the strings
of length ref_length ! */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( ! row_table_got_default_clust_index ( ib_table ) ) {
if ( primary_key > = MAX_KEY ) {
2005-10-27 09:29:40 +02:00
sql_print_error ( " Table %s has a primary key in InnoDB data "
" dictionary, but not in MySQL! " , name ) ;
}
2007-01-11 15:24:53 +01:00
prebuilt - > clust_index_was_generated = FALSE ;
2006-02-21 13:37:54 +01:00
/* MySQL allocates the buffer for ref. key_info->key_length
2005-10-27 09:29:40 +02:00
includes space for all key columns + one byte for each column
that may be NULL . ref_length must be as exact as possible to
save space , because all row reference buffers are allocated
based on ref_length . */
2006-02-21 13:37:54 +01:00
ref_length = table - > key_info [ primary_key ] . key_length ;
2005-10-27 09:29:40 +02:00
} else {
2006-02-21 13:37:54 +01:00
if ( primary_key ! = MAX_KEY ) {
2005-10-27 09:29:40 +02:00
sql_print_error ( " Table %s has no primary key in InnoDB data "
" dictionary, but has one in MySQL! If you "
" created the table with a MySQL version < "
" 3.23.54 and did not define a primary key, "
" but defined a unique key with all non-NULL "
" columns, then MySQL internally treats that "
" key as the primary key. You can fix this "
" error by dump + DROP + CREATE + reimport "
" of the table. " , name ) ;
}
2007-01-11 15:24:53 +01:00
prebuilt - > clust_index_was_generated = TRUE ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
ref_length = DATA_ROW_ID_LEN ;
2005-10-27 09:29:40 +02:00
/* If we automatically created the clustered index, then
MySQL does not know about it , and MySQL must NOT be aware
of the index used on scan , to make it avoid checking if we
update the column of the index . That is why we assert below
that key_used_on_scan is the undefined value MAX_KEY .
The column is the row id in the automatical generation case ,
and it will never be updated anyway . */
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
if ( key_used_on_scan ! = MAX_KEY ) {
2006-02-21 13:37:54 +01:00
sql_print_warning (
" Table %s key_used_on_scan is %lu even "
" though there is no primary key inside "
" InnoDB. " , name , ( ulong ) key_used_on_scan ) ;
2005-10-27 09:29:40 +02:00
}
}
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
stats . block_size = 16 * 1024 ; /* Index block size in InnoDB: used by MySQL
2005-10-27 09:29:40 +02:00
in query optimization */
/* Init table lock structure */
thr_lock_data_init ( & share - > lock , & lock , ( void * ) 0 ) ;
2006-02-21 13:37:54 +01:00
info ( HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST ) ;
2005-10-27 09:29:40 +02:00
2008-10-23 06:30:32 +02:00
/* Only if the table has an AUTOINC column. */
if ( prebuilt - > table ! = NULL & & table - > found_next_number_field ! = NULL ) {
dict_table_autoinc_lock ( prebuilt - > table ) ;
/* Since a table can already be "open" in InnoDB's internal
data dictionary , we only init the autoinc counter once , the
first time the table is loaded . We can safely reuse the
autoinc value from a previous MySQL open . */
if ( dict_table_autoinc_read ( prebuilt - > table ) = = 0 ) {
2010-01-12 11:22:19 +01:00
innobase_initialize_autoinc ( ) ;
2008-10-23 06:30:32 +02:00
}
dict_table_autoinc_unlock ( prebuilt - > table ) ;
}
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( 0 ) ;
2005-10-27 09:29:40 +02:00
}
2005-11-04 11:57:22 +01:00
uint
ha_innobase : : max_supported_key_part_length ( ) const
{
return ( DICT_MAX_INDEX_COL_LEN - 1 ) ;
}
2005-10-27 09:29:40 +02:00
/**********************************************************************
Closes a handle to an InnoDB table . */
int
ha_innobase : : close ( void )
/*====================*/
/* out: 0 */
{
2007-04-20 19:51:54 +02:00
THD * thd ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " ha_innobase::close " ) ;
2005-10-27 09:29:40 +02:00
2007-04-20 19:51:54 +02:00
thd = current_thd ; // avoid calling current_thd twice, it may be slow
if ( thd ! = NULL ) {
innobase_release_temporary_latches ( ht , thd ) ;
}
2007-04-16 18:27:41 +02:00
2007-01-11 15:24:53 +01:00
row_prebuilt_free ( prebuilt ) ;
2005-10-27 09:29:40 +02:00
2007-06-04 10:45:27 +02:00
my_free ( upd_buff , MYF ( 0 ) ) ;
2006-02-21 13:37:54 +01:00
free_share ( share ) ;
2005-10-27 09:29:40 +02:00
/* Tell InnoDB server that there might be work for
utility threads : */
srv_active_wake_master_thread ( ) ;
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( 0 ) ;
2005-10-27 09:29:40 +02:00
}
/* The following accessor functions should really be inside MySQL code! */
/******************************************************************
Gets field offset for a field in a table . */
inline
uint
get_field_offset (
/*=============*/
/* out: offset */
TABLE * table , /* in: MySQL table object */
Field * field ) /* in: MySQL field object */
{
2007-06-04 10:45:27 +02:00
return ( ( uint ) ( field - > ptr - table - > record [ 0 ] ) ) ;
2005-10-27 09:29:40 +02:00
}
/******************************************************************
Checks if a field in a record is SQL NULL . Uses the record format
information in table to track the null bit in record . */
2006-11-16 16:05:23 +01:00
static inline
2005-10-27 09:29:40 +02:00
uint
field_in_record_is_null (
/*====================*/
/* out: 1 if NULL, 0 otherwise */
TABLE * table , /* in: MySQL table object */
Field * field , /* in: MySQL field object */
char * record ) /* in: a row in MySQL format */
{
int null_offset ;
if ( ! field - > null_ptr ) {
return ( 0 ) ;
}
null_offset = ( uint ) ( ( char * ) field - > null_ptr
- ( char * ) table - > record [ 0 ] ) ;
if ( record [ null_offset ] & field - > null_bit ) {
return ( 1 ) ;
}
return ( 0 ) ;
}
/******************************************************************
Sets a field in a record to SQL NULL . Uses the record format
information in table to track the null bit in record . */
inline
void
set_field_in_record_to_null (
/*========================*/
TABLE * table , /* in: MySQL table object */
Field * field , /* in: MySQL field object */
char * record ) /* in: a row in MySQL format */
{
int null_offset ;
null_offset = ( uint ) ( ( char * ) field - > null_ptr
- ( char * ) table - > record [ 0 ] ) ;
record [ null_offset ] = record [ null_offset ] | field - > null_bit ;
}
extern " C " {
/*****************************************************************
InnoDB uses this function to compare two data fields for which the data type
is such that we must use MySQL code to compare them . NOTE that the prototype
of this function is in rem0cmp . c in InnoDB source code ! If you change this
function , remember to update the prototype there ! */
int
innobase_mysql_cmp (
/*===============*/
/* out: 1, 0, -1, if a is greater,
equal , less than b , respectively */
int mysql_type , /* in: MySQL type */
uint charset_number , /* in: number of the charset */
unsigned char * a , /* in: data field */
unsigned int a_length , /* in: data field length,
not UNIV_SQL_NULL */
unsigned char * b , /* in: data field */
unsigned int b_length ) /* in: data field length,
not UNIV_SQL_NULL */
{
CHARSET_INFO * charset ;
enum_field_types mysql_tp ;
2006-02-21 13:37:54 +01:00
int ret ;
2005-10-27 09:29:40 +02:00
DBUG_ASSERT ( a_length ! = UNIV_SQL_NULL ) ;
DBUG_ASSERT ( b_length ! = UNIV_SQL_NULL ) ;
mysql_tp = ( enum_field_types ) mysql_type ;
switch ( mysql_tp ) {
2006-02-21 13:37:54 +01:00
case MYSQL_TYPE_BIT :
2005-10-27 09:29:40 +02:00
case MYSQL_TYPE_STRING :
case MYSQL_TYPE_VAR_STRING :
2007-02-02 12:14:02 +01:00
case MYSQL_TYPE_TINY_BLOB :
case MYSQL_TYPE_MEDIUM_BLOB :
case MYSQL_TYPE_BLOB :
case MYSQL_TYPE_LONG_BLOB :
2006-02-21 13:37:54 +01:00
case MYSQL_TYPE_VARCHAR :
2005-10-27 09:29:40 +02:00
/* Use the charset number to pick the right charset struct for
the comparison . Since the MySQL function get_charset may be
slow before Bar removes the mutex operation there , we first
look at 2 common charsets directly . */
if ( charset_number = = default_charset_info - > number ) {
charset = default_charset_info ;
} else if ( charset_number = = my_charset_latin1 . number ) {
charset = & my_charset_latin1 ;
} else {
charset = get_charset ( charset_number , MYF ( MY_WME ) ) ;
if ( charset = = NULL ) {
sql_print_error ( " InnoDB needs charset %lu for doing "
" a comparison, but MySQL cannot "
" find that charset. " ,
( ulong ) charset_number ) ;
ut_a ( 0 ) ;
}
}
2006-02-21 13:37:54 +01:00
/* Starting from 4.1.3, we use strnncollsp() in comparisons of
non - latin1_swedish_ci strings . NOTE that the collation order
changes then : ' b \ 0 \ 0. . . ' is ordered BEFORE ' b . . . ' . Users
having indexes on such data need to rebuild their tables ! */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
ret = charset - > coll - > strnncollsp ( charset ,
a , a_length ,
b , b_length , 0 ) ;
2005-10-27 09:29:40 +02:00
if ( ret < 0 ) {
2006-02-21 13:37:54 +01:00
return ( - 1 ) ;
2005-10-27 09:29:40 +02:00
} else if ( ret > 0 ) {
2006-02-21 13:37:54 +01:00
return ( 1 ) ;
2005-10-27 09:29:40 +02:00
} else {
2006-02-21 13:37:54 +01:00
return ( 0 ) ;
}
2005-10-27 09:29:40 +02:00
default :
assert ( 0 ) ;
}
return ( 0 ) ;
}
}
/******************************************************************
Converts a MySQL type to an InnoDB type . Note that this function returns
the ' mtype ' of InnoDB . InnoDB differentiates between MySQL ' s old < = 4.1
VARCHAR and the new true VARCHAR in > = 5.0 .3 by the ' prtype ' . */
inline
ulint
get_innobase_type_from_mysql_type (
/*==============================*/
/* out: DATA_BINARY, DATA_VARCHAR, ... */
ulint * unsigned_flag , /* out: DATA_UNSIGNED if an 'unsigned type';
at least ENUM and SET , and unsigned integer
types are ' unsigned types ' */
Field * field ) /* in: MySQL field */
{
/* The following asserts try to check that the MySQL type code fits in
8 bits : this is used in ibuf and also when DATA_NOT_NULL is ORed to
the type */
2007-02-02 12:14:02 +01:00
DBUG_ASSERT ( ( ulint ) MYSQL_TYPE_STRING < 256 ) ;
DBUG_ASSERT ( ( ulint ) MYSQL_TYPE_VAR_STRING < 256 ) ;
DBUG_ASSERT ( ( ulint ) MYSQL_TYPE_DOUBLE < 256 ) ;
DBUG_ASSERT ( ( ulint ) MYSQL_TYPE_FLOAT < 256 ) ;
DBUG_ASSERT ( ( ulint ) MYSQL_TYPE_DECIMAL < 256 ) ;
2005-10-27 09:29:40 +02:00
if ( field - > flags & UNSIGNED_FLAG ) {
* unsigned_flag = DATA_UNSIGNED ;
} else {
* unsigned_flag = 0 ;
}
2007-02-02 12:14:02 +01:00
if ( field - > real_type ( ) = = MYSQL_TYPE_ENUM
| | field - > real_type ( ) = = MYSQL_TYPE_SET ) {
2005-10-27 09:29:40 +02:00
/* MySQL has field->type() a string type for these, but the
data is actually internally stored as an unsigned integer
code ! */
* unsigned_flag = DATA_UNSIGNED ; /* MySQL has its own unsigned
flag set to zero , even though
internally this is an unsigned
integer type */
return ( DATA_INT ) ;
}
switch ( field - > type ( ) ) {
2006-02-21 13:37:54 +01:00
/* NOTE that we only allow string types in DATA_MYSQL and
DATA_VARMYSQL */
case MYSQL_TYPE_VAR_STRING : /* old <= 4.1 VARCHAR */
case MYSQL_TYPE_VARCHAR : /* new >= 5.0.3 true VARCHAR */
if ( field - > binary ( ) ) {
return ( DATA_BINARY ) ;
} else if ( strcmp (
field - > charset ( ) - > name ,
" latin1_swedish_ci " ) = = 0 ) {
return ( DATA_VARCHAR ) ;
} else {
return ( DATA_VARMYSQL ) ;
}
case MYSQL_TYPE_BIT :
case MYSQL_TYPE_STRING : if ( field - > binary ( ) ) {
return ( DATA_FIXBINARY ) ;
} else if ( strcmp (
field - > charset ( ) - > name ,
" latin1_swedish_ci " ) = = 0 ) {
return ( DATA_CHAR ) ;
} else {
return ( DATA_MYSQL ) ;
}
2007-02-02 12:14:02 +01:00
case MYSQL_TYPE_NEWDECIMAL :
2006-02-21 13:37:54 +01:00
return ( DATA_FIXBINARY ) ;
2007-02-02 12:14:02 +01:00
case MYSQL_TYPE_LONG :
case MYSQL_TYPE_LONGLONG :
case MYSQL_TYPE_TINY :
case MYSQL_TYPE_SHORT :
case MYSQL_TYPE_INT24 :
case MYSQL_TYPE_DATE :
case MYSQL_TYPE_DATETIME :
case MYSQL_TYPE_YEAR :
case MYSQL_TYPE_NEWDATE :
case MYSQL_TYPE_TIME :
case MYSQL_TYPE_TIMESTAMP :
2006-02-21 13:37:54 +01:00
return ( DATA_INT ) ;
2007-02-02 12:14:02 +01:00
case MYSQL_TYPE_FLOAT :
2006-02-21 13:37:54 +01:00
return ( DATA_FLOAT ) ;
2007-02-02 12:14:02 +01:00
case MYSQL_TYPE_DOUBLE :
2006-02-21 13:37:54 +01:00
return ( DATA_DOUBLE ) ;
2007-02-02 12:14:02 +01:00
case MYSQL_TYPE_DECIMAL :
2006-02-21 13:37:54 +01:00
return ( DATA_DECIMAL ) ;
2007-02-02 12:14:02 +01:00
case MYSQL_TYPE_GEOMETRY :
case MYSQL_TYPE_TINY_BLOB :
case MYSQL_TYPE_MEDIUM_BLOB :
case MYSQL_TYPE_BLOB :
case MYSQL_TYPE_LONG_BLOB :
2006-02-21 13:37:54 +01:00
return ( DATA_BLOB ) ;
default :
assert ( 0 ) ;
2005-10-27 09:29:40 +02:00
}
return ( 0 ) ;
}
/***********************************************************************
Writes an unsigned integer value < 64 k to 2 bytes , in the little - endian
storage format . */
inline
void
innobase_write_to_2_little_endian (
/*==============================*/
byte * buf , /* in: where to store */
ulint val ) /* in: value to write, must be < 64k */
{
ut_a ( val < 256 * 256 ) ;
buf [ 0 ] = ( byte ) ( val & 0xFF ) ;
buf [ 1 ] = ( byte ) ( val / 256 ) ;
}
/***********************************************************************
Reads an unsigned integer value < 64 k from 2 bytes , in the little - endian
storage format . */
inline
uint
innobase_read_from_2_little_endian (
/*===============================*/
2007-08-15 14:29:46 +02:00
/* out: value */
const uchar * buf ) /* in: from where to read */
2005-10-27 09:29:40 +02:00
{
return ( uint ) ( ( ulint ) ( buf [ 0 ] ) + 256 * ( ( ulint ) ( buf [ 1 ] ) ) ) ;
}
/***********************************************************************
Stores a key value for a row to a buffer . */
uint
ha_innobase : : store_key_val_for_row (
/*===============================*/
/* out: key value length as stored in buff */
2006-02-21 13:37:54 +01:00
uint keynr , /* in: key number */
2005-10-27 09:29:40 +02:00
char * buff , /* in/out: buffer for the key value (in MySQL
format ) */
uint buff_len , /* in: buffer length */
2007-08-15 14:29:46 +02:00
const uchar * record ) /* in: row in MySQL format */
2005-10-27 09:29:40 +02:00
{
2006-02-21 13:37:54 +01:00
KEY * key_info = table - > key_info + keynr ;
KEY_PART_INFO * key_part = key_info - > key_part ;
KEY_PART_INFO * end = key_part + key_info - > key_parts ;
2005-10-27 09:29:40 +02:00
char * buff_start = buff ;
enum_field_types mysql_type ;
Field * field ;
ibool is_null ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " store_key_val_for_row " ) ;
2005-10-27 09:29:40 +02:00
/* The format for storing a key field in MySQL is the following:
1. If the column can be NULL , then in the first byte we put 1 if the
field value is NULL , 0 otherwise .
2. If the column is of a BLOB type ( it must be a column prefix field
in this case ) , then we put the length of the data in the field to the
next 2 bytes , in the little - endian format . If the field is SQL NULL ,
then these 2 bytes are set to 0. Note that the length of data in the
field is < = column prefix length .
3. In a column prefix field , prefix_len next bytes are reserved for
data . In a normal field the max field length next bytes are reserved
for data . For a VARCHAR ( n ) the max field length is n . If the stored
value is the SQL NULL then these data bytes are set to 0.
4. We always use a 2 byte length for a true > = 5.0 .3 VARCHAR . Note that
in the MySQL row format , the length is stored in 1 or 2 bytes ,
depending on the maximum allowed length . But in the MySQL key value
format , the length always takes 2 bytes .
We have to zero - fill the buffer so that MySQL is able to use a
simple memcmp to compare two key values to determine if they are
equal . MySQL does this to compare contents of two ' ref ' values . */
bzero ( buff , buff_len ) ;
2006-02-21 13:37:54 +01:00
for ( ; key_part ! = end ; key_part + + ) {
is_null = FALSE ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( key_part - > null_bit ) {
if ( record [ key_part - > null_offset ]
2005-10-27 09:29:40 +02:00
& key_part - > null_bit ) {
* buff = 1 ;
is_null = TRUE ;
2006-02-21 13:37:54 +01:00
} else {
2005-10-27 09:29:40 +02:00
* buff = 0 ;
}
buff + + ;
2006-02-21 13:37:54 +01:00
}
2005-10-27 09:29:40 +02:00
field = key_part - > field ;
mysql_type = field - > type ( ) ;
if ( mysql_type = = MYSQL_TYPE_VARCHAR ) {
/* >= 5.0.3 true VARCHAR */
ulint lenlen ;
ulint len ;
byte * data ;
ulint key_len ;
2005-12-12 12:18:31 +01:00
ulint true_len ;
2005-10-27 09:29:40 +02:00
CHARSET_INFO * cs ;
int error = 0 ;
2005-12-12 12:18:31 +01:00
key_len = key_part - > length ;
2005-10-27 09:29:40 +02:00
if ( is_null ) {
2005-12-12 12:18:31 +01:00
buff + = key_len + 2 ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
continue ;
}
2005-12-12 12:18:31 +01:00
cs = field - > charset ( ) ;
2005-10-27 09:29:40 +02:00
lenlen = ( ulint )
( ( ( Field_varstring * ) field ) - > length_bytes ) ;
2006-02-21 13:37:54 +01:00
data = row_mysql_read_true_varchar ( & len ,
2005-10-27 09:29:40 +02:00
( byte * ) ( record
+ ( ulint ) get_field_offset ( table , field ) ) ,
lenlen ) ;
2006-01-12 09:58:56 +01:00
true_len = len ;
2005-12-12 12:18:31 +01:00
/* For multi byte character sets we need to calculate
the true length of the key */
2006-01-12 09:58:56 +01:00
if ( len > 0 & & cs - > mbmaxlen > 1 ) {
2005-12-12 12:18:31 +01:00
true_len = ( ulint ) cs - > cset - > well_formed_len ( cs ,
( const char * ) data ,
2006-01-12 09:58:56 +01:00
( const char * ) data + len ,
2007-03-01 16:21:12 +01:00
( uint ) ( key_len /
cs - > mbmaxlen ) ,
2005-12-12 12:18:31 +01:00
& error ) ;
}
2005-10-27 09:29:40 +02:00
/* In a column prefix index, we may need to truncate
the stored value : */
2006-01-12 09:58:56 +01:00
if ( true_len > key_len ) {
true_len = key_len ;
2005-10-27 09:29:40 +02:00
}
/* The length in a key value is always stored in 2
bytes */
2006-01-12 09:58:56 +01:00
row_mysql_store_true_var_len ( ( byte * ) buff , true_len , 2 ) ;
2005-10-27 09:29:40 +02:00
buff + = 2 ;
2006-01-12 09:58:56 +01:00
memcpy ( buff , data , true_len ) ;
2005-10-27 09:29:40 +02:00
/* Note that we always reserve the maximum possible
length of the true VARCHAR in the key value , though
only len first bytes after the 2 length bytes contain
actual data . The rest of the space was reset to zero
in the bzero ( ) call above . */
2005-12-12 12:18:31 +01:00
buff + = key_len ;
2005-10-27 09:29:40 +02:00
2007-02-02 12:14:02 +01:00
} else if ( mysql_type = = MYSQL_TYPE_TINY_BLOB
| | mysql_type = = MYSQL_TYPE_MEDIUM_BLOB
| | mysql_type = = MYSQL_TYPE_BLOB
2009-10-08 00:27:08 +02:00
| | mysql_type = = MYSQL_TYPE_LONG_BLOB
/* MYSQL_TYPE_GEOMETRY data is treated
as BLOB data in innodb . */
| | mysql_type = = MYSQL_TYPE_GEOMETRY ) {
2005-10-27 09:29:40 +02:00
CHARSET_INFO * cs ;
ulint key_len ;
2005-12-12 12:18:31 +01:00
ulint true_len ;
2005-10-27 09:29:40 +02:00
int error = 0 ;
2005-12-12 12:18:31 +01:00
ulint blob_len ;
byte * blob_data ;
2005-10-27 09:29:40 +02:00
ut_a ( key_part - > key_part_flag & HA_PART_KEY_SEG ) ;
2005-12-12 12:18:31 +01:00
key_len = key_part - > length ;
2006-02-21 13:37:54 +01:00
if ( is_null ) {
2005-12-12 12:18:31 +01:00
buff + = key_len + 2 ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
continue ;
}
2006-02-21 13:37:54 +01:00
2005-12-12 12:18:31 +01:00
cs = field - > charset ( ) ;
2006-02-21 13:37:54 +01:00
blob_data = row_mysql_read_blob_ref ( & blob_len ,
2005-10-27 09:29:40 +02:00
( byte * ) ( record
+ ( ulint ) get_field_offset ( table , field ) ) ,
( ulint ) field - > pack_length ( ) ) ;
2006-01-12 09:58:56 +01:00
true_len = blob_len ;
2005-10-27 09:29:40 +02:00
ut_a ( get_field_offset ( table , field )
2006-02-21 13:37:54 +01:00
= = key_part - > offset ) ;
2005-10-27 09:29:40 +02:00
2005-12-12 12:18:31 +01:00
/* For multi byte character sets we need to calculate
the true length of the key */
2006-02-21 13:37:54 +01:00
2006-01-12 09:58:56 +01:00
if ( blob_len > 0 & & cs - > mbmaxlen > 1 ) {
2005-12-12 12:18:31 +01:00
true_len = ( ulint ) cs - > cset - > well_formed_len ( cs ,
( const char * ) blob_data ,
2006-02-21 13:37:54 +01:00
( const char * ) blob_data
2006-01-12 09:58:56 +01:00
+ blob_len ,
2007-03-01 16:21:12 +01:00
( uint ) ( key_len /
cs - > mbmaxlen ) ,
2005-12-12 12:18:31 +01:00
& error ) ;
}
2005-10-27 09:29:40 +02:00
/* All indexes on BLOB and TEXT are column prefix
indexes , and we may need to truncate the data to be
stored in the key value : */
2006-01-12 09:58:56 +01:00
if ( true_len > key_len ) {
true_len = key_len ;
2005-10-27 09:29:40 +02:00
}
/* MySQL reserves 2 bytes for the length and the
storage of the number is little - endian */
innobase_write_to_2_little_endian (
2006-01-12 09:58:56 +01:00
( byte * ) buff , true_len ) ;
2005-10-27 09:29:40 +02:00
buff + = 2 ;
2006-01-12 09:58:56 +01:00
memcpy ( buff , blob_data , true_len ) ;
2005-10-27 09:29:40 +02:00
/* Note that we always reserve the maximum possible
length of the BLOB prefix in the key value . */
2005-12-12 12:18:31 +01:00
buff + = key_len ;
2005-10-27 09:29:40 +02:00
} else {
/* Here we handle all other data types except the
true VARCHAR , BLOB and TEXT . Note that the column
value we store may be also in a column prefix
index . */
CHARSET_INFO * cs ;
2005-12-12 12:18:31 +01:00
ulint true_len ;
ulint key_len ;
2007-08-15 14:29:46 +02:00
const uchar * src_start ;
2005-10-27 09:29:40 +02:00
int error = 0 ;
2005-12-12 12:18:31 +01:00
enum_field_types real_type ;
key_len = key_part - > length ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( is_null ) {
2005-12-12 12:18:31 +01:00
buff + = key_len ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
continue ;
}
src_start = record + key_part - > offset ;
2005-12-12 12:18:31 +01:00
real_type = field - > real_type ( ) ;
true_len = key_len ;
/* Character set for the field is defined only
2006-01-12 09:58:56 +01:00
to fields whose type is string and real field
2005-12-12 12:18:31 +01:00
type is not enum or set . For these fields check
if character set is multi byte . */
2007-02-02 12:14:02 +01:00
if ( real_type ! = MYSQL_TYPE_ENUM
& & real_type ! = MYSQL_TYPE_SET
2005-12-12 12:18:31 +01:00
& & ( mysql_type = = MYSQL_TYPE_VAR_STRING
| | mysql_type = = MYSQL_TYPE_STRING ) ) {
cs = field - > charset ( ) ;
2006-02-21 13:37:54 +01:00
/* For multi byte character sets we need to
2005-12-12 12:18:31 +01:00
calculate the true length of the key */
if ( key_len > 0 & & cs - > mbmaxlen > 1 ) {
2006-02-21 13:37:54 +01:00
true_len = ( ulint )
2005-12-12 12:18:31 +01:00
cs - > cset - > well_formed_len ( cs ,
( const char * ) src_start ,
2006-02-21 13:37:54 +01:00
( const char * ) src_start
2005-12-12 12:18:31 +01:00
+ key_len ,
2007-03-01 16:21:12 +01:00
( uint ) ( key_len /
cs - > mbmaxlen ) ,
2005-12-12 12:18:31 +01:00
& error ) ;
}
2005-10-27 09:29:40 +02:00
}
2005-12-12 12:18:31 +01:00
memcpy ( buff , src_start , true_len ) ;
buff + = true_len ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* Pad the unused space with spaces. Note that no
padding is ever needed for UCS - 2 because in MySQL ,
all UCS2 characters are 2 bytes , as MySQL does not
2005-12-12 12:18:31 +01:00
support surrogate pairs , which are needed to represent
characters in the range U + 10000 to U + 10FF FF . */
2005-10-27 09:29:40 +02:00
2005-12-12 12:18:31 +01:00
if ( true_len < key_len ) {
ulint pad_len = key_len - true_len ;
memset ( buff , ' ' , pad_len ) ;
buff + = pad_len ;
2005-10-27 09:29:40 +02:00
}
}
2006-02-21 13:37:54 +01:00
}
2005-10-27 09:29:40 +02:00
ut_a ( buff < = buff_start + buff_len ) ;
DBUG_RETURN ( ( uint ) ( buff - buff_start ) ) ;
}
/******************************************************************
Builds a ' template ' to the prebuilt struct . The template is used in fast
retrieval of just those column values MySQL needs in its processing . */
2006-09-14 15:10:46 +02:00
static
2005-10-27 09:29:40 +02:00
void
2006-09-14 15:10:46 +02:00
build_template (
2005-10-27 09:29:40 +02:00
/*===========*/
2007-05-14 13:08:44 +02:00
row_prebuilt_t * prebuilt , /* in/out: prebuilt struct */
2005-10-27 09:29:40 +02:00
THD * thd , /* in: current user thread, used
only if templ_type is
ROW_MYSQL_REC_FIELDS */
TABLE * table , /* in: MySQL table */
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
uint templ_type ) /* in: ROW_MYSQL_WHOLE_ROW or
2005-10-27 09:29:40 +02:00
ROW_MYSQL_REC_FIELDS */
{
dict_index_t * index ;
dict_index_t * clust_index ;
mysql_row_templ_t * templ ;
Field * field ;
ulint n_fields ;
ulint n_requested_fields = 0 ;
ibool fetch_all_in_key = FALSE ;
ibool fetch_primary_key_cols = FALSE ;
ulint i ;
/* byte offset of the end of last requested column */
ulint mysql_prefix_len = 0 ;
if ( prebuilt - > select_lock_type = = LOCK_X ) {
/* We always retrieve the whole clustered index record if we
use exclusive row level locks , for example , if the read is
done in an UPDATE statement . */
2006-02-21 13:37:54 +01:00
templ_type = ROW_MYSQL_WHOLE_ROW ;
2005-10-27 09:29:40 +02:00
}
if ( templ_type = = ROW_MYSQL_REC_FIELDS ) {
2006-02-21 13:37:54 +01:00
if ( prebuilt - > hint_need_to_fetch_extra_cols
= = ROW_RETRIEVE_ALL_COLS ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* We know we must at least fetch all columns in the
key , or all columns in the table */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( prebuilt - > read_just_key ) {
/* MySQL has instructed us that it is enough
to fetch the columns in the key ; looks like
MySQL can set this flag also when there is
only a prefix of the column in the key : in
that case we retrieve the whole column from
the clustered index */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
fetch_all_in_key = TRUE ;
} else {
templ_type = ROW_MYSQL_WHOLE_ROW ;
}
} else if ( prebuilt - > hint_need_to_fetch_extra_cols
= = ROW_RETRIEVE_PRIMARY_KEY ) {
/* We must at least fetch all primary key cols. Note
that if the clustered index was internally generated
by InnoDB on the row id ( no primary key was
defined ) , then row_search_for_mysql ( ) will always
retrieve the row id to a special buffer in the
prebuilt struct . * /
fetch_primary_key_cols = TRUE ;
2005-10-27 09:29:40 +02:00
}
}
clust_index = dict_table_get_first_index_noninline ( prebuilt - > table ) ;
if ( templ_type = = ROW_MYSQL_REC_FIELDS ) {
index = prebuilt - > index ;
} else {
index = clust_index ;
}
if ( index = = clust_index ) {
prebuilt - > need_to_access_clustered = TRUE ;
} else {
prebuilt - > need_to_access_clustered = FALSE ;
/* Below we check column by column if we need to access
the clustered index */
}
n_fields = ( ulint ) table - > s - > fields ; /* number of columns */
if ( ! prebuilt - > mysql_template ) {
prebuilt - > mysql_template = ( mysql_row_templ_t * )
mem_alloc_noninline (
n_fields * sizeof ( mysql_row_templ_t ) ) ;
}
prebuilt - > template_type = templ_type ;
prebuilt - > null_bitmap_len = table - > s - > null_bytes ;
prebuilt - > templ_contains_blob = FALSE ;
/* Note that in InnoDB, i is the column number. MySQL calls columns
' fields ' . */
for ( i = 0 ; i < n_fields ; i + + ) {
templ = prebuilt - > mysql_template + n_requested_fields ;
field = table - > field [ i ] ;
if ( UNIV_LIKELY ( templ_type = = ROW_MYSQL_REC_FIELDS ) ) {
/* Decide which columns we should fetch
and which we can skip . */
register const ibool index_contains_field =
dict_index_contains_col_or_prefix ( index , i ) ;
if ( ! index_contains_field & & prebuilt - > read_just_key ) {
/* If this is a 'key read', we do not need
columns that are not in the key */
goto skip_field ;
}
if ( index_contains_field & & fetch_all_in_key ) {
/* This field is needed in the query */
goto include_field ;
}
2009-02-12 00:34:27 +01:00
if ( bitmap_is_set ( table - > read_set , i ) | |
bitmap_is_set ( table - > write_set , i ) ) {
2005-10-27 09:29:40 +02:00
/* This field is needed in the query */
goto include_field ;
}
if ( fetch_primary_key_cols
2006-02-21 13:37:54 +01:00
& & dict_table_col_in_clustered_key (
index - > table , i ) ) {
2005-10-27 09:29:40 +02:00
/* This field is needed in the query */
goto include_field ;
}
/* This field is not needed in the query, skip it */
goto skip_field ;
}
include_field :
n_requested_fields + + ;
templ - > col_no = i ;
if ( index = = clust_index ) {
2006-09-18 10:50:31 +02:00
templ - > rec_field_no = dict_col_get_clust_pos_noninline (
& index - > table - > cols [ i ] , index ) ;
2005-10-27 09:29:40 +02:00
} else {
templ - > rec_field_no = dict_index_get_nth_col_pos (
index , i ) ;
}
if ( templ - > rec_field_no = = ULINT_UNDEFINED ) {
prebuilt - > need_to_access_clustered = TRUE ;
}
if ( field - > null_ptr ) {
templ - > mysql_null_byte_offset =
( ulint ) ( ( char * ) field - > null_ptr
- ( char * ) table - > record [ 0 ] ) ;
templ - > mysql_null_bit_mask = ( ulint ) field - > null_bit ;
} else {
templ - > mysql_null_bit_mask = 0 ;
}
templ - > mysql_col_offset = ( ulint )
get_field_offset ( table , field ) ;
templ - > mysql_col_len = ( ulint ) field - > pack_length ( ) ;
if ( mysql_prefix_len < templ - > mysql_col_offset
+ templ - > mysql_col_len ) {
mysql_prefix_len = templ - > mysql_col_offset
+ templ - > mysql_col_len ;
}
dict_col_t: Copy the fields of "dtype_t type" directly to this structure,
so that all integer fields can be packed into 64 bits. (Bug #20877)
dtype_t: Change the type of all bit-fields to unsigned.
dict_table_get_nth_col(), dict_table_get_sys_col_noninline(),
dict_table_get_sys_col(), dict_field_get_col(): Return const
dict_col_t*, so that changes to dict_col_t can be detected more
easily. Add const to many dict_col_t* declarations.
dict_index_get_nth_type(): Replace with dict_index_get_nth_col().
dict_col_get_type(): Replace with dict_col_copy_type().
dict_col_get_min_size(), dict_col_get_max_size(), dict_col_get_fixed_size(),
dict_col_get_sql_null_size(): New functions.
dtype_get_at_most_n_mbchars(): Replace the parameter dtype
with the parameters prtype, mbminlen, mbmaxlen.
dtype_get_pad_char(), cmp_data_data(), cmp_data_data_slow(),
cmp_whole_field(): Replace the dtype_t* parameter with the ulint
parameters mtype, prtype.
dtype_copy(): Add a const qualifier to type2 (the one being copied from).
dtype_set_mblen(): Replaced with dtype_get_mblen().
dtype_get_fixed_size_low(), dtype_get_min_size_low(),
dtype_get_fixed_max_low(): Replace dtype_get_fixed_size(),
dtype_get_min_size(), and dtype_get_max_size(). These are used by the
dict_col_get_{fixed,min,max}_size() functions.
cmp_types_are_equal(): Replace with cmp_cols_are_equal().
dict_table_get_col_name(): Add a const qualifier parameter to the
parameter "table".
dtype_binary, dtype_binary_val: Remove.
dtype_is_fixed_size(): Remove.
2006-09-18 13:51:38 +02:00
templ - > type = index - > table - > cols [ i ] . mtype ;
2005-10-27 09:29:40 +02:00
templ - > mysql_type = ( ulint ) field - > type ( ) ;
if ( templ - > mysql_type = = DATA_MYSQL_TRUE_VARCHAR ) {
templ - > mysql_length_bytes = ( ulint )
2006-02-21 13:37:54 +01:00
( ( ( Field_varstring * ) field ) - > length_bytes ) ;
2005-10-27 09:29:40 +02:00
}
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
templ - > charset = dtype_get_charset_coll_noninline (
dict_col_t: Copy the fields of "dtype_t type" directly to this structure,
so that all integer fields can be packed into 64 bits. (Bug #20877)
dtype_t: Change the type of all bit-fields to unsigned.
dict_table_get_nth_col(), dict_table_get_sys_col_noninline(),
dict_table_get_sys_col(), dict_field_get_col(): Return const
dict_col_t*, so that changes to dict_col_t can be detected more
easily. Add const to many dict_col_t* declarations.
dict_index_get_nth_type(): Replace with dict_index_get_nth_col().
dict_col_get_type(): Replace with dict_col_copy_type().
dict_col_get_min_size(), dict_col_get_max_size(), dict_col_get_fixed_size(),
dict_col_get_sql_null_size(): New functions.
dtype_get_at_most_n_mbchars(): Replace the parameter dtype
with the parameters prtype, mbminlen, mbmaxlen.
dtype_get_pad_char(), cmp_data_data(), cmp_data_data_slow(),
cmp_whole_field(): Replace the dtype_t* parameter with the ulint
parameters mtype, prtype.
dtype_copy(): Add a const qualifier to type2 (the one being copied from).
dtype_set_mblen(): Replaced with dtype_get_mblen().
dtype_get_fixed_size_low(), dtype_get_min_size_low(),
dtype_get_fixed_max_low(): Replace dtype_get_fixed_size(),
dtype_get_min_size(), and dtype_get_max_size(). These are used by the
dict_col_get_{fixed,min,max}_size() functions.
cmp_types_are_equal(): Replace with cmp_cols_are_equal().
dict_table_get_col_name(): Add a const qualifier parameter to the
parameter "table".
dtype_binary, dtype_binary_val: Remove.
dtype_is_fixed_size(): Remove.
2006-09-18 13:51:38 +02:00
index - > table - > cols [ i ] . prtype ) ;
templ - > mbminlen = index - > table - > cols [ i ] . mbminlen ;
templ - > mbmaxlen = index - > table - > cols [ i ] . mbmaxlen ;
templ - > is_unsigned = index - > table - > cols [ i ] . prtype
2005-10-27 09:29:40 +02:00
& DATA_UNSIGNED ;
if ( templ - > type = = DATA_BLOB ) {
prebuilt - > templ_contains_blob = TRUE ;
}
skip_field :
;
}
prebuilt - > n_template = n_requested_fields ;
prebuilt - > mysql_prefix_len = mysql_prefix_len ;
if ( index ! = clust_index & & prebuilt - > need_to_access_clustered ) {
/* Change rec_field_no's to correspond to the clustered index
record */
for ( i = 0 ; i < n_requested_fields ; i + + ) {
templ = prebuilt - > mysql_template + i ;
2006-09-18 10:50:31 +02:00
templ - > rec_field_no = dict_col_get_clust_pos_noninline (
& index - > table - > cols [ templ - > col_no ] ,
clust_index ) ;
2005-10-27 09:29:40 +02:00
}
}
}
2007-07-24 03:42:16 +02:00
/************************************************************************
This special handling is really to overcome the limitations of MySQL ' s
binlogging . We need to eliminate the non - determinism that will arise in
INSERT . . . SELECT type of statements , since MySQL binlog only stores the
min value of the autoinc interval . Once that is fixed we can get rid of
the special lock handling . */
ulong
2008-10-23 06:30:32 +02:00
ha_innobase : : innobase_lock_autoinc ( void )
2007-07-24 03:42:16 +02:00
/*====================================*/
/* out: DB_SUCCESS if all OK else
error code */
{
ulint error = DB_SUCCESS ;
2007-08-20 23:48:16 +02:00
switch ( innobase_autoinc_lock_mode ) {
case AUTOINC_NO_LOCKING :
/* Acquire only the AUTOINC mutex. */
2007-07-24 03:42:16 +02:00
dict_table_autoinc_lock ( prebuilt - > table ) ;
2007-08-20 23:48:16 +02:00
break ;
2007-07-24 03:42:16 +02:00
2007-08-20 23:48:16 +02:00
case AUTOINC_NEW_STYLE_LOCKING :
/* For simple (single/multi) row INSERTs, we fallback to the
old style only if another transaction has already acquired
the AUTOINC lock on behalf of a LOAD FILE or INSERT . . . SELECT
etc . type of statement . */
2008-05-28 10:18:35 +02:00
if ( thd_sql_command ( user_thd ) = = SQLCOM_INSERT
| | thd_sql_command ( user_thd ) = = SQLCOM_REPLACE ) {
2007-08-23 05:37:37 +02:00
dict_table_t * table = prebuilt - > table ;
2007-08-20 23:48:16 +02:00
/* Acquire the AUTOINC mutex. */
2007-08-23 05:37:37 +02:00
dict_table_autoinc_lock ( table ) ;
2007-07-24 03:42:16 +02:00
2007-08-23 05:37:37 +02:00
/* We need to check that another transaction isn't
already holding the AUTOINC lock on the table . */
if ( table - > n_waiting_or_granted_auto_inc_locks ) {
2007-08-20 23:48:16 +02:00
/* Release the mutex to avoid deadlocks. */
2007-08-23 05:37:37 +02:00
dict_table_autoinc_unlock ( table ) ;
2007-08-20 23:48:16 +02:00
} else {
break ;
}
2007-07-24 03:42:16 +02:00
}
2007-08-20 23:48:16 +02:00
/* Fall through to old style locking. */
case AUTOINC_OLD_STYLE_LOCKING :
2007-07-24 03:42:16 +02:00
error = row_lock_table_autoinc_for_mysql ( prebuilt ) ;
if ( error = = DB_SUCCESS ) {
2007-08-20 23:48:16 +02:00
/* Acquire the AUTOINC mutex. */
2007-07-24 03:42:16 +02:00
dict_table_autoinc_lock ( prebuilt - > table ) ;
}
2007-08-20 23:48:16 +02:00
break ;
default :
ut_error ;
2007-07-24 03:42:16 +02:00
}
return ( ulong ( error ) ) ;
}
/************************************************************************
Reset the autoinc value in the table . */
ulong
ha_innobase : : innobase_reset_autoinc (
/*================================*/
/* out: DB_SUCCESS if all went well
else error code */
ulonglong autoinc ) /* in: value to store */
{
ulint error ;
2008-10-23 06:30:32 +02:00
error = innobase_lock_autoinc ( ) ;
2007-07-24 03:42:16 +02:00
if ( error = = DB_SUCCESS ) {
dict_table_autoinc_initialize ( prebuilt - > table , autoinc ) ;
dict_table_autoinc_unlock ( prebuilt - > table ) ;
}
return ( ulong ( error ) ) ;
}
/************************************************************************
Store the autoinc value in the table . The autoinc value is only set if
it ' s greater than the existing autoinc value in the table . */
ulong
ha_innobase : : innobase_set_max_autoinc (
/*==================================*/
/* out: DB_SUCCES if all went well
else error code */
ulonglong auto_inc ) /* in: value to store */
{
ulint error ;
2008-10-23 06:30:32 +02:00
error = innobase_lock_autoinc ( ) ;
2007-07-24 03:42:16 +02:00
if ( error = = DB_SUCCESS ) {
2008-10-23 06:30:32 +02:00
dict_table_autoinc_update_if_greater ( prebuilt - > table , auto_inc ) ;
2007-07-24 03:42:16 +02:00
dict_table_autoinc_unlock ( prebuilt - > table ) ;
}
return ( ulong ( error ) ) ;
}
2005-10-27 09:29:40 +02:00
/************************************************************************
Stores a row in an InnoDB database , to the table specified in this
handle . */
int
ha_innobase : : write_row (
/*===================*/
2007-08-15 14:29:46 +02:00
/* out: error code */
uchar * record ) /* in: a row in MySQL format */
2005-10-27 09:29:40 +02:00
{
2009-03-05 20:21:10 +01:00
ulint error = 0 ;
int error_result = 0 ;
2006-02-21 13:37:54 +01:00
ibool auto_inc_used = FALSE ;
2007-05-10 13:31:36 +02:00
ulint sql_command ;
2007-05-10 14:09:03 +02:00
trx_t * trx = thd_to_trx ( user_thd ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " ha_innobase::write_row " ) ;
2005-10-27 09:29:40 +02:00
2007-02-14 21:03:58 +01:00
if ( prebuilt - > trx ! = trx ) {
2005-10-27 09:29:40 +02:00
sql_print_error ( " The transaction object for the table handle is at "
" %p, but for the current thread it is at %p " ,
2007-02-14 21:03:58 +01:00
prebuilt - > trx , trx ) ;
2005-10-27 09:29:40 +02:00
fputs ( " InnoDB: Dump of 200 bytes around prebuilt: " , stderr ) ;
ut_print_buf ( stderr , ( ( const byte * ) prebuilt ) - 100 , 200 ) ;
fputs ( " \n "
2007-02-14 21:03:58 +01:00
" InnoDB: Dump of 200 bytes around ha_data: " ,
2005-10-27 09:29:40 +02:00
stderr ) ;
2007-02-14 21:03:58 +01:00
ut_print_buf ( stderr , ( ( const byte * ) trx ) - 100 , 200 ) ;
2005-10-27 09:29:40 +02:00
putc ( ' \n ' , stderr ) ;
ut_error ;
}
2007-03-19 10:28:49 +01:00
ha_statistic_increment ( & SSV : : ha_write_count ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( table - > timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT )
table - > timestamp_field - > set_time ( ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
sql_command = thd_sql_command ( user_thd ) ;
if ( ( sql_command = = SQLCOM_ALTER_TABLE
| | sql_command = = SQLCOM_OPTIMIZE
| | sql_command = = SQLCOM_CREATE_INDEX
| | sql_command = = SQLCOM_DROP_INDEX )
& & num_write_row > = 10000 ) {
2005-10-27 09:29:40 +02:00
/* ALTER TABLE is COMMITted at every 10000 copied rows.
The IX table lock for the original table has to be re - issued .
As this method will be called on a temporary table where the
contents of the original table is being copied to , it is
a bit tricky to determine the source table . The cursor
position in the source table need not be adjusted after the
intermediate COMMIT , since writes by other transactions are
being blocked by a MySQL table lock TL_WRITE_ALLOW_READ . */
dict_table_t * src_table ;
ulint mode ;
num_write_row = 0 ;
/* Commit the transaction. This will release the table
locks , so they have to be acquired again . */
/* Altering an InnoDB table */
/* Get the source table. */
src_table = lock_get_src_table (
prebuilt - > trx , prebuilt - > table , & mode ) ;
if ( ! src_table ) {
no_commit :
/* Unknown situation: do not commit */
/*
ut_print_timestamp ( stderr ) ;
fprintf ( stderr ,
2007-10-24 13:35:23 +02:00
" InnoDB: ALTER TABLE is holding lock "
2005-10-27 09:29:40 +02:00
" on %lu tables! \n " ,
prebuilt - > trx - > mysql_n_tables_locked ) ;
*/
;
} else if ( src_table = = prebuilt - > table ) {
/* Source table is not in InnoDB format:
no need to re - acquire locks on it . */
/* Altering to InnoDB format */
2006-10-03 14:46:23 +02:00
innobase_commit ( ht , user_thd , 1 ) ;
2005-10-27 09:29:40 +02:00
/* Note that this transaction is still active. */
prebuilt - > trx - > active_trans = 1 ;
/* We will need an IX lock on the destination table. */
2006-02-21 13:37:54 +01:00
prebuilt - > sql_stat_start = TRUE ;
2005-10-27 09:29:40 +02:00
} else {
/* Ensure that there are no other table locks than
LOCK_IX and LOCK_AUTO_INC on the destination table . */
if ( ! lock_is_table_exclusive ( prebuilt - > table ,
prebuilt - > trx ) ) {
goto no_commit ;
}
/* Commit the transaction. This will release the table
locks , so they have to be acquired again . */
2006-10-03 14:46:23 +02:00
innobase_commit ( ht , user_thd , 1 ) ;
2005-10-27 09:29:40 +02:00
/* Note that this transaction is still active. */
prebuilt - > trx - > active_trans = 1 ;
/* Re-acquire the table lock on the source table. */
row_lock_table_for_mysql ( prebuilt , src_table , mode ) ;
/* We will need an IX lock on the destination table. */
2006-02-21 13:37:54 +01:00
prebuilt - > sql_stat_start = TRUE ;
2005-10-27 09:29:40 +02:00
}
}
num_write_row + + ;
2007-07-24 03:42:16 +02:00
/* This is the case where the table has an auto-increment column */
2006-02-21 13:37:54 +01:00
if ( table - > next_number_field & & record = = table - > record [ 0 ] ) {
2005-10-27 09:29:40 +02:00
2008-10-22 10:01:18 +02:00
/* Reset the error code before calling
innobase_get_auto_increment ( ) . */
prebuilt - > autoinc_error = DB_SUCCESS ;
2007-07-24 03:42:16 +02:00
if ( ( error = update_auto_increment ( ) ) ) {
2010-01-29 23:13:42 +01:00
/* We don't want to mask autoinc overflow errors. */
2010-01-29 23:35:00 +01:00
/* Handle the case where the AUTOINC sub-system
failed during initialization . */
if ( prebuilt - > autoinc_error = = DB_UNSUPPORTED ) {
error_result = ER_AUTOINC_READ_FAILED ;
/* Set the error message to report too. */
my_error ( ER_AUTOINC_READ_FAILED , MYF ( 0 ) ) ;
goto func_exit ;
} else if ( prebuilt - > autoinc_error ! = DB_SUCCESS ) {
error = ( int ) prebuilt - > autoinc_error ;
2008-10-22 10:01:18 +02:00
goto report_error ;
}
/* MySQL errors are passed straight back. */
2009-03-05 20:21:10 +01:00
error_result = ( int ) error ;
2005-10-27 09:29:40 +02:00
goto func_exit ;
}
2007-07-24 03:42:16 +02:00
auto_inc_used = TRUE ;
2005-10-27 09:29:40 +02:00
}
if ( prebuilt - > mysql_template = = NULL
2007-07-24 03:42:16 +02:00
| | prebuilt - > template_type ! = ROW_MYSQL_WHOLE_ROW ) {
2005-10-27 09:29:40 +02:00
/* Build the template used in converting quickly between
the two database formats */
build_template ( prebuilt , NULL , table , ROW_MYSQL_WHOLE_ROW ) ;
}
innodb_srv_conc_enter_innodb ( prebuilt - > trx ) ;
error = row_insert_for_mysql ( ( byte * ) record , prebuilt ) ;
2007-07-24 03:42:16 +02:00
/* Handle duplicate key errors */
if ( auto_inc_used ) {
2007-10-16 13:08:35 +02:00
ulint err ;
2007-07-24 03:42:16 +02:00
ulonglong auto_inc ;
2008-10-22 23:42:24 +02:00
ulonglong col_max_value ;
2005-10-27 09:29:40 +02:00
2007-07-24 03:42:16 +02:00
/* Note the number of rows processed for this statement, used
by get_auto_increment ( ) to determine the number of AUTO - INC
values to reserve . This is only useful for a mult - value INSERT
and is a statement level counter . */
if ( trx - > n_autoinc_rows > 0 ) {
- - trx - > n_autoinc_rows ;
}
2005-10-27 09:29:40 +02:00
2008-10-22 23:42:24 +02:00
/* We need the upper limit of the col type to check for
whether we update the table autoinc counter or not . */
col_max_value = innobase_get_int_col_max_value (
table - > next_number_field ) ;
2007-07-24 03:42:16 +02:00
/* Get the value that MySQL attempted to store in the table.*/
2006-02-21 13:37:54 +01:00
auto_inc = table - > next_number_field - > val_int ( ) ;
2005-10-27 09:29:40 +02:00
2007-07-24 03:42:16 +02:00
switch ( error ) {
case DB_DUPLICATE_KEY :
2005-10-27 09:29:40 +02:00
2007-07-24 03:42:16 +02:00
/* A REPLACE command and LOAD DATA INFILE REPLACE
handle a duplicate key error themselves , but we
must update the autoinc counter if we are performing
those statements . */
2005-10-27 09:29:40 +02:00
2007-07-24 03:42:16 +02:00
switch ( sql_command ) {
case SQLCOM_LOAD :
if ( ( trx - > duplicates
& ( TRX_DUP_IGNORE | TRX_DUP_REPLACE ) ) ) {
2005-10-27 09:29:40 +02:00
2007-07-24 03:42:16 +02:00
goto set_max_autoinc ;
}
break ;
2005-10-27 09:29:40 +02:00
2007-07-24 03:42:16 +02:00
case SQLCOM_REPLACE :
case SQLCOM_INSERT_SELECT :
case SQLCOM_REPLACE_SELECT :
goto set_max_autoinc ;
break ;
2005-10-27 09:29:40 +02:00
2007-07-24 03:42:16 +02:00
default :
break ;
}
break ;
case DB_SUCCESS :
/* If the actual value inserted is greater than
the upper limit of the interval , then we try and
update the table upper limit . Note : last_value
will be 0 if get_auto_increment ( ) was not called . */
2009-11-26 00:14:42 +01:00
if ( auto_inc > = prebuilt - > autoinc_last_value ) {
2007-07-24 03:42:16 +02:00
set_max_autoinc :
2009-11-26 00:14:42 +01:00
/* This should filter out the negative
values set explicitly by the user . */
if ( auto_inc < = col_max_value ) {
ut_a ( prebuilt - > autoinc_increment > 0 ) ;
2008-03-05 21:23:39 +01:00
2009-11-26 00:14:42 +01:00
ulonglong need ;
ulonglong offset ;
2008-03-05 21:23:39 +01:00
2009-11-26 00:14:42 +01:00
offset = prebuilt - > autoinc_offset ;
need = prebuilt - > autoinc_increment ;
2008-03-05 21:23:39 +01:00
2009-11-26 00:14:42 +01:00
auto_inc = innobase_next_autoinc (
auto_inc ,
need , offset , col_max_value ) ;
2007-07-24 03:42:16 +02:00
2009-11-26 00:14:42 +01:00
err = innobase_set_max_autoinc (
auto_inc ) ;
2007-10-16 13:08:35 +02:00
2009-11-26 00:14:42 +01:00
if ( err ! = DB_SUCCESS ) {
error = err ;
}
2007-10-16 13:08:35 +02:00
}
2007-07-24 03:42:16 +02:00
}
break ;
2006-02-21 13:37:54 +01:00
}
}
2005-10-27 09:29:40 +02:00
innodb_srv_conc_exit_innodb ( prebuilt - > trx ) ;
2008-10-22 10:01:18 +02:00
report_error :
2009-03-05 20:21:10 +01:00
error_result = convert_error_code_to_mysql ( ( int ) error , user_thd ) ;
2005-10-27 09:29:40 +02:00
func_exit :
innobase_active_small ( ) ;
2009-03-05 20:21:10 +01:00
DBUG_RETURN ( error_result ) ;
2005-10-27 09:29:40 +02:00
}
/**************************************************************************
Checks which fields have changed in a row and stores information
of them to an update vector . */
static
int
calc_row_difference (
/*================*/
/* out: error number or 0 */
upd_t * uvect , /* in/out: update vector */
2007-08-15 14:29:46 +02:00
uchar * old_row , /* in: old row in MySQL format */
uchar * new_row , /* in: new row in MySQL format */
2005-10-27 09:29:40 +02:00
struct st_table * table , /* in: table in MySQL data
dictionary */
2007-08-15 14:29:46 +02:00
uchar * upd_buff , /* in: buffer to use */
2005-10-27 09:29:40 +02:00
ulint buff_len , /* in: buffer length */
row_prebuilt_t * prebuilt , /* in: InnoDB prebuilt struct */
THD * thd ) /* in: user thread */
{
2007-08-15 14:29:46 +02:00
uchar * original_upd_buff = upd_buff ;
2005-10-27 09:29:40 +02:00
Field * field ;
enum_field_types field_mysql_type ;
uint n_fields ;
ulint o_len ;
ulint n_len ;
ulint col_pack_len ;
byte * new_mysql_row_col ;
2006-02-21 13:37:54 +01:00
byte * o_ptr ;
byte * n_ptr ;
byte * buf ;
2005-10-27 09:29:40 +02:00
upd_field_t * ufield ;
ulint col_type ;
ulint n_changed = 0 ;
dfield_t dfield ;
2006-09-14 13:51:34 +02:00
dict_index_t * clust_index ;
2005-10-27 09:29:40 +02:00
uint i ;
n_fields = table - > s - > fields ;
2006-09-14 13:51:34 +02:00
clust_index = dict_table_get_first_index_noninline ( prebuilt - > table ) ;
2005-10-27 09:29:40 +02:00
/* We use upd_buff to convert changed fields */
buf = ( byte * ) upd_buff ;
for ( i = 0 ; i < n_fields ; i + + ) {
field = table - > field [ i ] ;
o_ptr = ( byte * ) old_row + get_field_offset ( table , field ) ;
n_ptr = ( byte * ) new_row + get_field_offset ( table , field ) ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
/* Use new_mysql_row_col and col_pack_len save the values */
new_mysql_row_col = n_ptr ;
col_pack_len = field - > pack_length ( ) ;
o_len = col_pack_len ;
n_len = col_pack_len ;
/* We use o_ptr and n_ptr to dig up the actual data for
2006-02-21 13:37:54 +01:00
comparison . */
2005-10-27 09:29:40 +02:00
field_mysql_type = field - > type ( ) ;
2006-02-21 13:37:54 +01:00
dict_col_t: Copy the fields of "dtype_t type" directly to this structure,
so that all integer fields can be packed into 64 bits. (Bug #20877)
dtype_t: Change the type of all bit-fields to unsigned.
dict_table_get_nth_col(), dict_table_get_sys_col_noninline(),
dict_table_get_sys_col(), dict_field_get_col(): Return const
dict_col_t*, so that changes to dict_col_t can be detected more
easily. Add const to many dict_col_t* declarations.
dict_index_get_nth_type(): Replace with dict_index_get_nth_col().
dict_col_get_type(): Replace with dict_col_copy_type().
dict_col_get_min_size(), dict_col_get_max_size(), dict_col_get_fixed_size(),
dict_col_get_sql_null_size(): New functions.
dtype_get_at_most_n_mbchars(): Replace the parameter dtype
with the parameters prtype, mbminlen, mbmaxlen.
dtype_get_pad_char(), cmp_data_data(), cmp_data_data_slow(),
cmp_whole_field(): Replace the dtype_t* parameter with the ulint
parameters mtype, prtype.
dtype_copy(): Add a const qualifier to type2 (the one being copied from).
dtype_set_mblen(): Replaced with dtype_get_mblen().
dtype_get_fixed_size_low(), dtype_get_min_size_low(),
dtype_get_fixed_max_low(): Replace dtype_get_fixed_size(),
dtype_get_min_size(), and dtype_get_max_size(). These are used by the
dict_col_get_{fixed,min,max}_size() functions.
cmp_types_are_equal(): Replace with cmp_cols_are_equal().
dict_table_get_col_name(): Add a const qualifier parameter to the
parameter "table".
dtype_binary, dtype_binary_val: Remove.
dtype_is_fixed_size(): Remove.
2006-09-18 13:51:38 +02:00
col_type = prebuilt - > table - > cols [ i ] . mtype ;
2005-10-27 09:29:40 +02:00
switch ( col_type ) {
case DATA_BLOB :
o_ptr = row_mysql_read_blob_ref ( & o_len , o_ptr , o_len ) ;
n_ptr = row_mysql_read_blob_ref ( & n_len , n_ptr , n_len ) ;
break ;
case DATA_VARCHAR :
case DATA_BINARY :
case DATA_VARMYSQL :
if ( field_mysql_type = = MYSQL_TYPE_VARCHAR ) {
/* This is a >= 5.0.3 type true VARCHAR where
the real payload data length is stored in
1 or 2 bytes */
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
o_ptr = row_mysql_read_true_varchar (
2006-02-21 13:37:54 +01:00
& o_len , o_ptr ,
( ulint )
( ( ( Field_varstring * ) field ) - > length_bytes ) ) ;
2005-10-27 09:29:40 +02:00
n_ptr = row_mysql_read_true_varchar (
2006-02-21 13:37:54 +01:00
& n_len , n_ptr ,
( ulint )
( ( ( Field_varstring * ) field ) - > length_bytes ) ) ;
2005-10-27 09:29:40 +02:00
}
break ;
default :
;
}
if ( field - > null_ptr ) {
if ( field_in_record_is_null ( table , field ,
( char * ) old_row ) ) {
o_len = UNIV_SQL_NULL ;
}
if ( field_in_record_is_null ( table , field ,
( char * ) new_row ) ) {
n_len = UNIV_SQL_NULL ;
}
}
if ( o_len ! = n_len | | ( o_len ! = UNIV_SQL_NULL & &
0 ! = memcmp ( o_ptr , n_ptr , o_len ) ) ) {
/* The field has changed */
ufield = uvect - > fields + n_changed ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
/* Let us use a dummy dfield to make the conversion
from the MySQL column format to the InnoDB format */
dict_col_t: Copy the fields of "dtype_t type" directly to this structure,
so that all integer fields can be packed into 64 bits. (Bug #20877)
dtype_t: Change the type of all bit-fields to unsigned.
dict_table_get_nth_col(), dict_table_get_sys_col_noninline(),
dict_table_get_sys_col(), dict_field_get_col(): Return const
dict_col_t*, so that changes to dict_col_t can be detected more
easily. Add const to many dict_col_t* declarations.
dict_index_get_nth_type(): Replace with dict_index_get_nth_col().
dict_col_get_type(): Replace with dict_col_copy_type().
dict_col_get_min_size(), dict_col_get_max_size(), dict_col_get_fixed_size(),
dict_col_get_sql_null_size(): New functions.
dtype_get_at_most_n_mbchars(): Replace the parameter dtype
with the parameters prtype, mbminlen, mbmaxlen.
dtype_get_pad_char(), cmp_data_data(), cmp_data_data_slow(),
cmp_whole_field(): Replace the dtype_t* parameter with the ulint
parameters mtype, prtype.
dtype_copy(): Add a const qualifier to type2 (the one being copied from).
dtype_set_mblen(): Replaced with dtype_get_mblen().
dtype_get_fixed_size_low(), dtype_get_min_size_low(),
dtype_get_fixed_max_low(): Replace dtype_get_fixed_size(),
dtype_get_min_size(), and dtype_get_max_size(). These are used by the
dict_col_get_{fixed,min,max}_size() functions.
cmp_types_are_equal(): Replace with cmp_cols_are_equal().
dict_table_get_col_name(): Add a const qualifier parameter to the
parameter "table".
dtype_binary, dtype_binary_val: Remove.
dtype_is_fixed_size(): Remove.
2006-09-18 13:51:38 +02:00
dict_col_copy_type_noninline ( prebuilt - > table - > cols + i ,
& dfield . type ) ;
2005-10-27 09:29:40 +02:00
if ( n_len ! = UNIV_SQL_NULL ) {
buf = row_mysql_store_col_in_innobase_format (
2006-02-27 10:11:57 +01:00
& dfield ,
( byte * ) buf ,
TRUE ,
new_mysql_row_col ,
col_pack_len ,
2006-03-13 10:27:34 +01:00
dict_table_is_comp_noninline (
prebuilt - > table ) ) ;
2005-10-27 09:29:40 +02:00
ufield - > new_val . data = dfield . data ;
ufield - > new_val . len = dfield . len ;
} else {
ufield - > new_val . data = NULL ;
ufield - > new_val . len = UNIV_SQL_NULL ;
}
ufield - > exp = NULL ;
2006-09-18 10:50:31 +02:00
ufield - > field_no = dict_col_get_clust_pos_noninline (
& prebuilt - > table - > cols [ i ] , clust_index ) ;
2005-10-27 09:29:40 +02:00
n_changed + + ;
}
}
uvect - > n_fields = n_changed ;
uvect - > info_bits = 0 ;
ut_a ( buf < = ( byte * ) original_upd_buff + buff_len ) ;
return ( 0 ) ;
}
/**************************************************************************
Updates a row given as a parameter to a new value . Note that we are given
whole rows , not just the fields which are updated : this incurs some
overhead for CPU when we check which fields are actually updated .
TODO : currently InnoDB does not prevent the ' Halloween problem ' :
in a searched update a single row can get updated several times
if its index columns are updated ! */
int
ha_innobase : : update_row (
/*====================*/
/* out: error number or 0 */
2007-08-15 14:29:46 +02:00
const uchar * old_row , /* in: old row in MySQL format */
uchar * new_row ) /* in: new row in MySQL format */
2005-10-27 09:29:40 +02:00
{
upd_t * uvect ;
int error = 0 ;
2007-05-10 14:09:03 +02:00
trx_t * trx = thd_to_trx ( user_thd ) ;
2005-10-27 09:29:40 +02:00
DBUG_ENTER ( " ha_innobase::update_row " ) ;
2007-02-14 21:03:58 +01:00
ut_a ( prebuilt - > trx = = trx ) ;
2005-10-27 09:29:40 +02:00
2008-04-24 13:32:30 +02:00
ha_statistic_increment ( & SSV : : ha_update_count ) ;
2006-02-21 13:37:54 +01:00
if ( table - > timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE )
table - > timestamp_field - > set_time ( ) ;
2005-10-27 09:29:40 +02:00
if ( prebuilt - > upd_node ) {
uvect = prebuilt - > upd_node - > update ;
} else {
uvect = row_get_prebuilt_update_vector ( prebuilt ) ;
}
/* Build an update vector from the modified fields in the rows
( uses upd_buff of the handle ) */
2007-08-15 14:29:46 +02:00
calc_row_difference ( uvect , ( uchar * ) old_row , new_row , table ,
2005-10-27 09:29:40 +02:00
upd_buff , ( ulint ) upd_and_key_val_buff_len ,
prebuilt , user_thd ) ;
/* This is not a delete */
prebuilt - > upd_node - > is_delete = FALSE ;
assert ( prebuilt - > template_type = = ROW_MYSQL_WHOLE_ROW ) ;
2007-02-14 21:03:58 +01:00
innodb_srv_conc_enter_innodb ( trx ) ;
2005-10-27 09:29:40 +02:00
error = row_update_for_mysql ( ( byte * ) old_row , prebuilt ) ;
2007-07-24 03:42:16 +02:00
/* We need to do some special AUTOINC handling for the following case:
INSERT INTO t ( c1 , c2 ) VALUES ( x , y ) ON DUPLICATE KEY UPDATE . . .
We need to use the AUTOINC counter that was actually used by
MySQL in the UPDATE statement , which can be different from the
value used in the INSERT statement . */
if ( error = = DB_SUCCESS
& & table - > next_number_field
& & new_row = = table - > record [ 0 ]
& & thd_sql_command ( user_thd ) = = SQLCOM_INSERT
& & ( trx - > duplicates & ( TRX_DUP_IGNORE | TRX_DUP_REPLACE ) )
= = TRX_DUP_IGNORE ) {
2008-10-22 23:42:24 +02:00
ulonglong auto_inc ;
ulonglong col_max_value ;
2007-07-24 03:42:16 +02:00
auto_inc = table - > next_number_field - > val_int ( ) ;
2008-10-22 23:42:24 +02:00
/* We need the upper limit of the col type to check for
whether we update the table autoinc counter or not . */
col_max_value = innobase_get_int_col_max_value (
table - > next_number_field ) ;
2008-10-23 06:30:32 +02:00
if ( auto_inc < = col_max_value & & auto_inc ! = 0 ) {
2008-10-04 00:48:04 +02:00
ulonglong need ;
ulonglong offset ;
offset = prebuilt - > autoinc_offset ;
need = prebuilt - > autoinc_increment ;
auto_inc = innobase_next_autoinc (
2008-10-22 23:42:24 +02:00
auto_inc , need , offset , col_max_value ) ;
2007-07-24 03:42:16 +02:00
2007-10-16 13:08:35 +02:00
error = innobase_set_max_autoinc ( auto_inc ) ;
2007-07-24 03:42:16 +02:00
}
}
2007-02-14 21:03:58 +01:00
innodb_srv_conc_exit_innodb ( trx ) ;
2005-10-27 09:29:40 +02:00
error = convert_error_code_to_mysql ( error , user_thd ) ;
2007-12-13 15:05:51 +01:00
if ( error = = 0 /* success */
& & uvect - > n_fields = = 0 /* no columns were updated */ ) {
/* This is the same as success, but instructs
MySQL that the row is not really updated and it
should not increase the count of updated rows .
This is fix for http : //bugs.mysql.com/29157 */
error = HA_ERR_RECORD_IS_THE_SAME ;
}
2005-10-27 09:29:40 +02:00
/* Tell InnoDB server that there might be work for
utility threads : */
innobase_active_small ( ) ;
DBUG_RETURN ( error ) ;
}
/**************************************************************************
Deletes a row given as the parameter . */
int
ha_innobase : : delete_row (
/*====================*/
2007-08-15 14:29:46 +02:00
/* out: error number or 0 */
const uchar * record ) /* in: a row in MySQL format */
2005-10-27 09:29:40 +02:00
{
int error = 0 ;
2007-05-10 14:09:03 +02:00
trx_t * trx = thd_to_trx ( user_thd ) ;
2005-10-27 09:29:40 +02:00
DBUG_ENTER ( " ha_innobase::delete_row " ) ;
2007-02-14 21:03:58 +01:00
ut_a ( prebuilt - > trx = = trx ) ;
2005-10-27 09:29:40 +02:00
2008-04-24 13:32:30 +02:00
ha_statistic_increment ( & SSV : : ha_delete_count ) ;
2005-10-27 09:29:40 +02:00
if ( ! prebuilt - > upd_node ) {
row_get_prebuilt_update_vector ( prebuilt ) ;
}
/* This is a delete */
prebuilt - > upd_node - > is_delete = TRUE ;
2007-02-14 21:03:58 +01:00
innodb_srv_conc_enter_innodb ( trx ) ;
2005-10-27 09:29:40 +02:00
error = row_update_for_mysql ( ( byte * ) record , prebuilt ) ;
2007-02-14 21:03:58 +01:00
innodb_srv_conc_exit_innodb ( trx ) ;
2005-10-27 09:29:40 +02:00
error = convert_error_code_to_mysql ( error , user_thd ) ;
/* Tell the InnoDB server that there might be work for
utility threads : */
innobase_active_small ( ) ;
DBUG_RETURN ( error ) ;
}
/**************************************************************************
2006-02-21 13:37:54 +01:00
Removes a new lock set on a row , if it was not read optimistically . This can
2006-01-26 11:45:27 +01:00
be called after a row has been read in the processing of an UPDATE or a DELETE
query , if the option innodb_locks_unsafe_for_binlog is set . */
2005-10-27 09:29:40 +02:00
void
ha_innobase : : unlock_row ( void )
/*=========================*/
{
DBUG_ENTER ( " ha_innobase::unlock_row " ) ;
2006-03-28 08:34:12 +02:00
/* Consistent read does not take any locks, thus there is
nothing to unlock . */
if ( prebuilt - > select_lock_type = = LOCK_NONE ) {
DBUG_VOID_RETURN ;
}
2006-01-26 11:45:27 +01:00
switch ( prebuilt - > row_read_type ) {
case ROW_READ_WITH_LOCKS :
2006-03-27 07:33:30 +02:00
if ( ! srv_locks_unsafe_for_binlog
2008-12-22 15:05:19 +01:00
& & prebuilt - > trx - > isolation_level
! = TRX_ISO_READ_COMMITTED ) {
2006-01-26 11:45:27 +01:00
break ;
}
/* fall through */
case ROW_READ_TRY_SEMI_CONSISTENT :
2005-10-27 09:29:40 +02:00
row_unlock_for_mysql ( prebuilt , FALSE ) ;
2006-01-26 11:45:27 +01:00
break ;
case ROW_READ_DID_SEMI_CONSISTENT :
prebuilt - > row_read_type = ROW_READ_TRY_SEMI_CONSISTENT ;
break ;
}
DBUG_VOID_RETURN ;
}
/* See handler.h and row0mysql.h for docs on this function. */
bool
ha_innobase : : was_semi_consistent_read ( void )
/*=======================================*/
{
return ( prebuilt - > row_read_type = = ROW_READ_DID_SEMI_CONSISTENT ) ;
}
/* See handler.h and row0mysql.h for docs on this function. */
void
ha_innobase : : try_semi_consistent_read ( bool yes )
/*===========================================*/
{
2007-05-10 14:09:03 +02:00
ut_a ( prebuilt - > trx = = thd_to_trx ( ha_thd ( ) ) ) ;
2006-08-07 17:39:40 +02:00
2006-03-27 07:33:30 +02:00
/* Row read type is set to semi consistent read if this was
requested by the MySQL and either innodb_locks_unsafe_for_binlog
option is used or this session is using READ COMMITTED isolation
level . */
2007-05-10 13:31:36 +02:00
if ( yes
& & ( srv_locks_unsafe_for_binlog
2006-03-27 07:33:30 +02:00
| | prebuilt - > trx - > isolation_level = = TRX_ISO_READ_COMMITTED ) ) {
2006-01-26 11:45:27 +01:00
prebuilt - > row_read_type = ROW_READ_TRY_SEMI_CONSISTENT ;
} else {
prebuilt - > row_read_type = ROW_READ_WITH_LOCKS ;
2005-10-27 09:29:40 +02:00
}
}
/**********************************************************************
Initializes a handle to use an index . */
int
ha_innobase : : index_init (
/*====================*/
/* out: 0 or error number */
2006-02-21 13:37:54 +01:00
uint keynr , /* in: key (index) number */
bool sorted ) /* in: 1 if result MUST be sorted according to index */
2005-10-27 09:29:40 +02:00
{
2006-02-21 13:37:54 +01:00
int error = 0 ;
DBUG_ENTER ( " index_init " ) ;
2005-10-27 09:29:40 +02:00
error = change_active_index ( keynr ) ;
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( error ) ;
2005-10-27 09:29:40 +02:00
}
/**********************************************************************
Currently does nothing . */
int
ha_innobase : : index_end ( void )
/*========================*/
{
2006-02-21 13:37:54 +01:00
int error = 0 ;
DBUG_ENTER ( " index_end " ) ;
active_index = MAX_KEY ;
DBUG_RETURN ( error ) ;
2005-10-27 09:29:40 +02:00
}
/*************************************************************************
Converts a search mode flag understood by MySQL to a flag understood
by InnoDB . */
inline
ulint
convert_search_mode_to_innobase (
/*============================*/
enum ha_rkey_function find_flag )
{
switch ( find_flag ) {
2007-11-14 14:15:24 +01:00
case HA_READ_KEY_EXACT :
/* this does not require the index to be UNIQUE */
return ( PAGE_CUR_GE ) ;
case HA_READ_KEY_OR_NEXT :
return ( PAGE_CUR_GE ) ;
case HA_READ_KEY_OR_PREV :
return ( PAGE_CUR_LE ) ;
case HA_READ_AFTER_KEY :
return ( PAGE_CUR_G ) ;
case HA_READ_BEFORE_KEY :
return ( PAGE_CUR_L ) ;
case HA_READ_PREFIX :
return ( PAGE_CUR_GE ) ;
case HA_READ_PREFIX_LAST :
return ( PAGE_CUR_LE ) ;
case HA_READ_PREFIX_LAST_OR_PREV :
return ( PAGE_CUR_LE ) ;
/* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
pass a complete - field prefix of a key value as the search
tuple . I . e . , it is not allowed that the last field would
just contain n first bytes of the full field value .
MySQL uses a ' padding ' trick to convert LIKE ' abc % '
type queries so that it can use as a search tuple
a complete - field - prefix of a key value . Thus , the InnoDB
search mode PAGE_CUR_LE_OR_EXTENDS is never used .
TODO : when / if MySQL starts to use also partial - field
prefixes , we have to deal with stripping of spaces
and comparison of non - latin1 char type fields in
innobase_mysql_cmp ( ) to get PAGE_CUR_LE_OR_EXTENDS to
work correctly . */
case HA_READ_MBR_CONTAIN :
case HA_READ_MBR_INTERSECT :
case HA_READ_MBR_WITHIN :
case HA_READ_MBR_DISJOINT :
2007-11-16 14:03:21 +01:00
case HA_READ_MBR_EQUAL :
2007-11-14 14:15:24 +01:00
return ( PAGE_CUR_UNSUPP ) ;
/* do not use "default:" in order to produce a gcc warning:
enumeration value ' . . . ' not handled in switch
( if - Wswitch or - Wall is used ) */
2005-10-27 09:29:40 +02:00
}
2007-11-14 13:49:24 +01:00
my_error ( ER_CHECK_NOT_IMPLEMENTED , MYF ( 0 ) , " this functionality " ) ;
return ( PAGE_CUR_UNSUPP ) ;
2005-10-27 09:29:40 +02:00
}
/*
BACKGROUND INFO : HOW A SELECT SQL QUERY IS EXECUTED
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following does not cover all the details , but explains how we determine
the start of a new SQL statement , and what is associated with it .
For each table in the database the MySQL interpreter may have several
table handle instances in use , also in a single SQL query . For each table
handle instance there is an InnoDB ' prebuilt ' struct which contains most
of the InnoDB data associated with this table handle instance .
A ) if the user has not explicitly set any MySQL table level locks :
1 ) MySQL calls : : external_lock to set an ' intention ' table level lock on
the table of the handle instance . There we set
prebuilt - > sql_stat_start = TRUE . The flag sql_stat_start should be set
true if we are taking this table handle instance to use in a new SQL
statement issued by the user . We also increment trx - > n_mysql_tables_in_use .
2 ) If prebuilt - > sql_stat_start = = TRUE we ' pre - compile ' the MySQL search
instructions to prebuilt - > template of the table handle instance in
: : index_read . The template is used to save CPU time in large joins .
3 ) In row_search_for_mysql , if prebuilt - > sql_stat_start is true , we
allocate a new consistent read view for the trx if it does not yet have one ,
or in the case of a locking read , set an InnoDB ' intention ' table level
lock on the table .
4 ) We do the SELECT . MySQL may repeatedly call : : index_read for the
same table handle instance , if it is a join .
5 ) When the SELECT ends , MySQL removes its intention table level locks
in : : external_lock . When trx - > n_mysql_tables_in_use drops to zero ,
( a ) we execute a COMMIT there if the autocommit is on ,
( b ) we also release possible ' SQL statement level resources ' InnoDB may
have for this SQL statement . The MySQL interpreter does NOT execute
autocommit for pure read transactions , though it should . That is why the
table handler in that case has to execute the COMMIT in : : external_lock .
B ) If the user has explicitly set MySQL table level locks , then MySQL
does NOT call : : external_lock at the start of the statement . To determine
when we are at the start of a new SQL statement we at the start of
: : index_read also compare the query id to the latest query id where the
table handle instance was used . If it has changed , we know we are at the
start of a new SQL statement . Since the query id can theoretically
overwrap , we use this test only as a secondary way of determining the
start of a new SQL statement . */
/**************************************************************************
Positions an index cursor to the index specified in the handle . Fetches the
row if any . */
int
ha_innobase : : index_read (
/*====================*/
/* out: 0, HA_ERR_KEY_NOT_FOUND,
or error number */
2007-08-15 14:29:46 +02:00
uchar * buf , /* in/out: buffer for the returned
2005-10-27 09:29:40 +02:00
row */
2007-08-15 14:29:46 +02:00
const uchar * key_ptr , /* in: key value; if this is NULL
2005-10-27 09:29:40 +02:00
we position the cursor at the
start or end of index ; this can
also contain an InnoDB row id , in
which case key_len is the InnoDB
row id length ; the key value can
also be a prefix of a full key value ,
and the last column can be a prefix
of a full column */
uint key_len , /* in: key value length */
enum ha_rkey_function find_flag ) /* in: search flags from my_base.h */
{
ulint mode ;
dict_index_t * index ;
2006-02-21 13:37:54 +01:00
ulint match_mode = 0 ;
int error ;
2005-10-27 09:29:40 +02:00
ulint ret ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " index_read " ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 14:09:03 +02:00
ut_a ( prebuilt - > trx = = thd_to_trx ( user_thd ) ) ;
2005-10-27 09:29:40 +02:00
2007-03-19 10:28:49 +01:00
ha_statistic_increment ( & SSV : : ha_read_key_count ) ;
2005-10-27 09:29:40 +02:00
index = prebuilt - > index ;
/* Note that if the index for which the search template is built is not
2006-02-21 13:37:54 +01:00
necessarily prebuilt - > index , but can also be the clustered index */
2005-10-27 09:29:40 +02:00
if ( prebuilt - > sql_stat_start ) {
build_template ( prebuilt , user_thd , table ,
ROW_MYSQL_REC_FIELDS ) ;
}
if ( key_ptr ) {
2006-02-21 13:37:54 +01:00
/* Convert the search key value to InnoDB format into
2005-10-27 09:29:40 +02:00
prebuilt - > search_tuple */
row_sel_convert_mysql_key_to_innobase ( prebuilt - > search_tuple ,
( byte * ) key_val_buff ,
( ulint ) upd_and_key_val_buff_len ,
index ,
( byte * ) key_ptr ,
( ulint ) key_len , prebuilt - > trx ) ;
} else {
/* We position the cursor to the last or the first entry
in the index */
2006-02-21 13:37:54 +01:00
dtuple_set_n_fields ( prebuilt - > search_tuple , 0 ) ;
2005-10-27 09:29:40 +02:00
}
mode = convert_search_mode_to_innobase ( find_flag ) ;
match_mode = 0 ;
if ( find_flag = = HA_READ_KEY_EXACT ) {
match_mode = ROW_SEL_EXACT ;
} else if ( find_flag = = HA_READ_PREFIX
| | find_flag = = HA_READ_PREFIX_LAST ) {
match_mode = ROW_SEL_EXACT_PREFIX ;
}
last_match_mode = ( uint ) match_mode ;
2007-11-14 13:49:24 +01:00
if ( mode ! = PAGE_CUR_UNSUPP ) {
2005-10-27 09:29:40 +02:00
2007-11-14 13:49:24 +01:00
innodb_srv_conc_enter_innodb ( prebuilt - > trx ) ;
2005-10-27 09:29:40 +02:00
2007-11-14 13:49:24 +01:00
ret = row_search_for_mysql ( ( byte * ) buf , mode , prebuilt ,
match_mode , 0 ) ;
innodb_srv_conc_exit_innodb ( prebuilt - > trx ) ;
} else {
ret = DB_UNSUPPORTED ;
}
2005-10-27 09:29:40 +02:00
if ( ret = = DB_SUCCESS ) {
error = 0 ;
table - > status = 0 ;
} else if ( ret = = DB_RECORD_NOT_FOUND ) {
error = HA_ERR_KEY_NOT_FOUND ;
table - > status = STATUS_NOT_FOUND ;
} else if ( ret = = DB_END_OF_INDEX ) {
error = HA_ERR_KEY_NOT_FOUND ;
table - > status = STATUS_NOT_FOUND ;
} else {
error = convert_error_code_to_mysql ( ( int ) ret , user_thd ) ;
table - > status = STATUS_NOT_FOUND ;
}
DBUG_RETURN ( error ) ;
}
/***********************************************************************
The following functions works like index_read , but it find the last
row with the current key value or prefix . */
int
ha_innobase : : index_read_last (
/*=========================*/
2007-08-15 14:29:46 +02:00
/* out: 0, HA_ERR_KEY_NOT_FOUND, or an
error code */
uchar * buf , /* out: fetched row */
const uchar * key_ptr , /* in: key value, or a prefix of a full
key value */
uint key_len ) /* in: length of the key val or prefix
in bytes */
2005-10-27 09:29:40 +02:00
{
2006-02-21 13:37:54 +01:00
return ( index_read ( buf , key_ptr , key_len , HA_READ_PREFIX_LAST ) ) ;
2005-10-27 09:29:40 +02:00
}
/************************************************************************
2007-07-24 03:42:16 +02:00
Get the index for a handle . Does not change active index . */
2005-10-27 09:29:40 +02:00
2007-07-24 03:42:16 +02:00
dict_index_t *
ha_innobase : : innobase_get_index (
/*============================*/
/* out: NULL or index instance. */
uint keynr ) /* in: use this index; MAX_KEY means always
clustered index , even if it was internally
generated by InnoDB */
2005-10-27 09:29:40 +02:00
{
2007-07-24 03:42:16 +02:00
KEY * key = 0 ;
dict_index_t * index = 0 ;
DBUG_ENTER ( " innobase_get_index " ) ;
2007-05-10 13:31:36 +02:00
ha_statistic_increment ( & SSV : : ha_read_key_count ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
ut_ad ( user_thd = = ha_thd ( ) ) ;
2007-05-10 14:09:03 +02:00
ut_a ( prebuilt - > trx = = thd_to_trx ( user_thd ) ) ;
2005-10-27 09:29:40 +02:00
if ( keynr ! = MAX_KEY & & table - > s - > keys > 0 ) {
2007-07-24 03:42:16 +02:00
key = table - > key_info + keynr ;
2005-10-27 09:29:40 +02:00
2007-07-24 03:42:16 +02:00
index = dict_table_get_index_noninline (
2006-02-21 13:37:54 +01:00
prebuilt - > table , key - > name ) ;
} else {
2007-07-24 03:42:16 +02:00
index = dict_table_get_first_index_noninline ( prebuilt - > table ) ;
2005-10-27 09:29:40 +02:00
}
2007-07-24 03:42:16 +02:00
if ( ! index ) {
2006-02-21 13:37:54 +01:00
sql_print_error (
" Innodb could not find key n:o %u with name %s "
" from dict cache for table %s " ,
keynr , key ? key - > name : " NULL " ,
prebuilt - > table - > name ) ;
2007-07-24 03:42:16 +02:00
}
DBUG_RETURN ( index ) ;
}
/************************************************************************
Changes the active index of a handle . */
int
ha_innobase : : change_active_index (
/*=============================*/
/* out: 0 or error code */
uint keynr ) /* in: use this index; MAX_KEY means always clustered
index , even if it was internally generated by
InnoDB */
{
DBUG_ENTER ( " change_active_index " ) ;
ut_ad ( user_thd = = ha_thd ( ) ) ;
ut_a ( prebuilt - > trx = = thd_to_trx ( user_thd ) ) ;
active_index = keynr ;
2006-02-21 13:37:54 +01:00
2007-07-24 03:42:16 +02:00
prebuilt - > index = innobase_get_index ( keynr ) ;
if ( ! prebuilt - > index ) {
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( 1 ) ;
2005-10-27 09:29:40 +02:00
}
assert ( prebuilt - > search_tuple ! = 0 ) ;
dtuple_set_n_fields ( prebuilt - > search_tuple , prebuilt - > index - > n_fields ) ;
dict_index_copy_types ( prebuilt - > search_tuple , prebuilt - > index ,
prebuilt - > index - > n_fields ) ;
/* MySQL changes the active index for a handle also during some
queries , for example SELECT MAX ( a ) , SUM ( a ) first retrieves the MAX ( )
and then calculates the sum . Previously we played safe and used
the flag ROW_MYSQL_WHOLE_ROW below , but that caused unnecessary
copying . Starting from MySQL - 4.1 we use a more efficient flag here . */
build_template ( prebuilt , user_thd , table , ROW_MYSQL_REC_FIELDS ) ;
DBUG_RETURN ( 0 ) ;
}
/**************************************************************************
Positions an index cursor to the index specified in keynr . Fetches the
row if any . */
/* ??? This is only used to read whole keys ??? */
int
ha_innobase : : index_read_idx (
/*========================*/
/* out: error number or 0 */
2007-08-15 14:29:46 +02:00
uchar * buf , /* in/out: buffer for the returned
2005-10-27 09:29:40 +02:00
row */
2006-02-21 13:37:54 +01:00
uint keynr , /* in: use this index */
2007-08-15 14:29:46 +02:00
const uchar * key , /* in: key value; if this is NULL
2005-10-27 09:29:40 +02:00
we position the cursor at the
start or end of index */
uint key_len , /* in: key value length */
enum ha_rkey_function find_flag ) /* in: search flags from my_base.h */
{
if ( change_active_index ( keynr ) ) {
return ( 1 ) ;
}
return ( index_read ( buf , key , key_len , find_flag ) ) ;
}
/***************************************************************************
Reads the next or previous row from a cursor , which must have previously been
positioned using index_read . */
int
ha_innobase : : general_fetch (
/*=======================*/
/* out: 0, HA_ERR_END_OF_FILE, or error
number */
2007-08-15 14:29:46 +02:00
uchar * buf , /* in/out: buffer for next row in MySQL
2005-10-27 09:29:40 +02:00
format */
2006-02-21 13:37:54 +01:00
uint direction , /* in: ROW_SEL_NEXT or ROW_SEL_PREV */
2005-10-27 09:29:40 +02:00
uint match_mode ) /* in: 0, ROW_SEL_EXACT, or
ROW_SEL_EXACT_PREFIX */
{
ulint ret ;
int error = 0 ;
DBUG_ENTER ( " general_fetch " ) ;
2007-05-10 14:09:03 +02:00
ut_a ( prebuilt - > trx = = thd_to_trx ( user_thd ) ) ;
2005-10-27 09:29:40 +02:00
innodb_srv_conc_enter_innodb ( prebuilt - > trx ) ;
ret = row_search_for_mysql ( ( byte * ) buf , 0 , prebuilt , match_mode ,
direction ) ;
innodb_srv_conc_exit_innodb ( prebuilt - > trx ) ;
if ( ret = = DB_SUCCESS ) {
error = 0 ;
table - > status = 0 ;
} else if ( ret = = DB_RECORD_NOT_FOUND ) {
error = HA_ERR_END_OF_FILE ;
table - > status = STATUS_NOT_FOUND ;
} else if ( ret = = DB_END_OF_INDEX ) {
error = HA_ERR_END_OF_FILE ;
table - > status = STATUS_NOT_FOUND ;
} else {
error = convert_error_code_to_mysql ( ( int ) ret , user_thd ) ;
table - > status = STATUS_NOT_FOUND ;
}
DBUG_RETURN ( error ) ;
}
/***************************************************************************
Reads the next row from a cursor , which must have previously been
positioned using index_read . */
int
ha_innobase : : index_next (
/*====================*/
/* out: 0, HA_ERR_END_OF_FILE, or error
number */
2007-08-15 14:29:46 +02:00
uchar * buf ) /* in/out: buffer for next row in MySQL
2005-10-27 09:29:40 +02:00
format */
{
2007-03-19 10:28:49 +01:00
ha_statistic_increment ( & SSV : : ha_read_next_count ) ;
2005-10-27 09:29:40 +02:00
return ( general_fetch ( buf , ROW_SEL_NEXT , 0 ) ) ;
}
/***********************************************************************
Reads the next row matching to the key value given as the parameter . */
int
ha_innobase : : index_next_same (
/*=========================*/
/* out: 0, HA_ERR_END_OF_FILE, or error
number */
2007-08-15 14:29:46 +02:00
uchar * buf , /* in/out: buffer for the row */
const uchar * key , /* in: key value */
2006-02-21 13:37:54 +01:00
uint keylen ) /* in: key value length */
2005-10-27 09:29:40 +02:00
{
2007-03-19 10:28:49 +01:00
ha_statistic_increment ( & SSV : : ha_read_next_count ) ;
2005-10-27 09:29:40 +02:00
return ( general_fetch ( buf , ROW_SEL_NEXT , last_match_mode ) ) ;
}
/***************************************************************************
Reads the previous row from a cursor , which must have previously been
positioned using index_read . */
int
ha_innobase : : index_prev (
/*====================*/
2007-08-15 14:29:46 +02:00
/* out: 0, HA_ERR_END_OF_FILE, or error number */
uchar * buf ) /* in/out: buffer for previous row in MySQL format */
2005-10-27 09:29:40 +02:00
{
2007-03-19 10:28:49 +01:00
ha_statistic_increment ( & SSV : : ha_read_prev_count ) ;
2006-05-09 08:37:11 +02:00
2005-10-27 09:29:40 +02:00
return ( general_fetch ( buf , ROW_SEL_PREV , 0 ) ) ;
}
/************************************************************************
Positions a cursor on the first record in an index and reads the
corresponding row to buf . */
int
ha_innobase : : index_first (
/*=====================*/
2007-08-15 14:29:46 +02:00
/* out: 0, HA_ERR_END_OF_FILE, or error code */
uchar * buf ) /* in/out: buffer for the row */
2005-10-27 09:29:40 +02:00
{
int error ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " index_first " ) ;
2007-03-19 10:28:49 +01:00
ha_statistic_increment ( & SSV : : ha_read_first_count ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
error = index_read ( buf , NULL , 0 , HA_READ_AFTER_KEY ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( error = = HA_ERR_KEY_NOT_FOUND ) {
error = HA_ERR_END_OF_FILE ;
}
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( error ) ;
2005-10-27 09:29:40 +02:00
}
/************************************************************************
Positions a cursor on the last record in an index and reads the
corresponding row to buf . */
int
ha_innobase : : index_last (
/*====================*/
2007-08-15 14:29:46 +02:00
/* out: 0, HA_ERR_END_OF_FILE, or error code */
uchar * buf ) /* in/out: buffer for the row */
2005-10-27 09:29:40 +02:00
{
int error ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " index_last " ) ;
2007-03-19 10:28:49 +01:00
ha_statistic_increment ( & SSV : : ha_read_last_count ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
error = index_read ( buf , NULL , 0 , HA_READ_BEFORE_KEY ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( error = = HA_ERR_KEY_NOT_FOUND ) {
error = HA_ERR_END_OF_FILE ;
}
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( error ) ;
2005-10-27 09:29:40 +02:00
}
/********************************************************************
Initialize a table scan . */
int
ha_innobase : : rnd_init (
/*==================*/
/* out: 0 or error number */
bool scan ) /* in: ???????? */
{
int err ;
/* Store the active index value so that we can restore the original
value after a scan */
if ( prebuilt - > clust_index_was_generated ) {
err = change_active_index ( MAX_KEY ) ;
} else {
err = change_active_index ( primary_key ) ;
}
2006-01-27 10:34:55 +01:00
/* Don't use semi-consistent read in random row reads (by position).
This means we must disable semi_consistent_read if scan is false */
if ( ! scan ) {
try_semi_consistent_read ( 0 ) ;
}
2006-02-21 13:37:54 +01:00
start_of_scan = 1 ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( err ) ;
2005-10-27 09:29:40 +02:00
}
/*********************************************************************
Ends a table scan . */
int
ha_innobase : : rnd_end ( void )
/*======================*/
/* out: 0 or error number */
{
return ( index_end ( ) ) ;
}
/*********************************************************************
Reads the next row in a table scan ( also used to read the FIRST row
in a table scan ) . */
int
ha_innobase : : rnd_next (
/*==================*/
/* out: 0, HA_ERR_END_OF_FILE, or error number */
2007-08-15 14:29:46 +02:00
uchar * buf ) /* in/out: returns the row in this buffer,
2005-10-27 09:29:40 +02:00
in MySQL format */
{
int error ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " rnd_next " ) ;
2007-03-19 10:28:49 +01:00
ha_statistic_increment ( & SSV : : ha_read_rnd_next_count ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( start_of_scan ) {
2005-10-27 09:29:40 +02:00
error = index_first ( buf ) ;
if ( error = = HA_ERR_KEY_NOT_FOUND ) {
error = HA_ERR_END_OF_FILE ;
}
start_of_scan = 0 ;
} else {
error = general_fetch ( buf , ROW_SEL_NEXT , 0 ) ;
}
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( error ) ;
2005-10-27 09:29:40 +02:00
}
/**************************************************************************
Fetches a row from the table based on a row reference . */
int
ha_innobase : : rnd_pos (
/*=================*/
2007-08-15 14:29:46 +02:00
/* out: 0, HA_ERR_KEY_NOT_FOUND, or error code */
uchar * buf , /* in/out: buffer for the row */
uchar * pos ) /* in: primary key value of the row in the
MySQL format , or the row id if the clustered
index was internally generated by InnoDB ; the
length of data in pos has to be ref_length */
2005-10-27 09:29:40 +02:00
{
int error ;
uint keynr = active_index ;
DBUG_ENTER ( " rnd_pos " ) ;
2007-06-04 10:45:27 +02:00
DBUG_DUMP ( " key " , pos , ref_length ) ;
2005-10-27 09:29:40 +02:00
2007-03-19 10:28:49 +01:00
ha_statistic_increment ( & SSV : : ha_read_rnd_count ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 14:09:03 +02:00
ut_a ( prebuilt - > trx = = thd_to_trx ( ha_thd ( ) ) ) ;
2005-10-27 09:29:40 +02:00
if ( prebuilt - > clust_index_was_generated ) {
/* No primary key was defined for the table and we
generated the clustered index from the row id : the
row reference is the row id , not any key value
that MySQL knows of */
error = change_active_index ( MAX_KEY ) ;
} else {
error = change_active_index ( primary_key ) ;
}
if ( error ) {
2006-11-10 11:09:41 +01:00
DBUG_PRINT ( " error " , ( " Got error: %d " , error ) ) ;
2005-10-27 09:29:40 +02:00
DBUG_RETURN ( error ) ;
}
/* Note that we assume the length of the row reference is fixed
2006-02-21 13:37:54 +01:00
for the table , and it is = = ref_length */
2005-10-27 09:29:40 +02:00
error = index_read ( buf , pos , ref_length , HA_READ_KEY_EXACT ) ;
if ( error ) {
2006-11-10 11:09:41 +01:00
DBUG_PRINT ( " error " , ( " Got error: %d " , error ) ) ;
2005-10-27 09:29:40 +02:00
}
change_active_index ( keynr ) ;
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( error ) ;
2005-10-27 09:29:40 +02:00
}
/*************************************************************************
Stores a reference to the current row to ' ref ' field of the handle . Note
that in the case where we have generated the clustered index for the
table , the function parameter is illogical : we MUST ASSUME that ' record '
is the current ' position ' of the handle , because if row ref is actually
the row id internally generated in InnoDB , then ' record ' does not contain
it . We just guess that the row id must be for the record where the handle
was positioned the last time . */
void
ha_innobase : : position (
/*==================*/
2007-08-15 14:29:46 +02:00
const uchar * record ) /* in: row in MySQL format */
2005-10-27 09:29:40 +02:00
{
uint len ;
2007-05-10 14:09:03 +02:00
ut_a ( prebuilt - > trx = = thd_to_trx ( ha_thd ( ) ) ) ;
2005-10-27 09:29:40 +02:00
if ( prebuilt - > clust_index_was_generated ) {
/* No primary key was defined for the table and we
generated the clustered index from row id : the
row reference will be the row id , not any key value
that MySQL knows of */
len = DATA_ROW_ID_LEN ;
memcpy ( ref , prebuilt - > row_id , len ) ;
} else {
len = store_key_val_for_row ( primary_key , ( char * ) ref ,
ref_length , record ) ;
}
/* We assume that the 'ref' value len is always fixed for the same
table . */
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
if ( len ! = ref_length ) {
sql_print_error ( " Stored ref len is %lu, but table ref len is %lu " ,
2006-02-21 13:37:54 +01:00
( ulong ) len , ( ulong ) ref_length ) ;
2005-10-27 09:29:40 +02:00
}
}
2007-04-11 03:34:33 +02:00
/*********************************************************************
If it ' s a DB_TOO_BIG_RECORD error then set a suitable message to
return to the client . */
2007-06-12 11:51:03 +02:00
inline
2007-04-11 03:34:33 +02:00
void
innodb_check_for_record_too_big_error (
2007-04-11 07:35:12 +02:00
/*==================================*/
2007-06-12 11:51:03 +02:00
ulint comp , /* in: ROW_FORMAT: nonzero=COMPACT, 0=REDUNDANT */
int error ) /* in: error code to check */
2007-04-11 03:34:33 +02:00
{
if ( error = = ( int ) DB_TOO_BIG_RECORD ) {
2007-06-13 12:18:12 +02:00
ulint max_row_size
= page_get_free_space_of_empty_noninline ( comp ) / 2 ;
2007-04-11 03:34:33 +02:00
my_error ( ER_TOO_BIG_ROWSIZE , MYF ( 0 ) , max_row_size ) ;
}
}
2008-02-07 13:02:06 +01:00
/* limit innodb monitor access to users with PROCESS privilege.
See http : //bugs.mysql.com/32710 for expl. why we choose PROCESS. */
# define IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name, thd) \
( row_is_magic_monitor_table ( table_name ) \
& & check_global_access ( thd , PROCESS_ACL ) )
2005-10-27 09:29:40 +02:00
/*********************************************************************
Creates a table definition to an InnoDB database . */
static
int
create_table_def (
/*=============*/
trx_t * trx , /* in: InnoDB transaction handle */
TABLE * form , /* in: information on table
columns and indexes */
const char * table_name , /* in: table name */
const char * path_of_temp_table , /* in: if this is a table explicitly
created by the user with the
TEMPORARY keyword , then this
parameter is the dir path where the
table should be placed if we create
an . ibd file for it ( no . ibd extension
in the path , though ) ; otherwise this
is NULL */
2006-02-27 10:11:57 +01:00
ulint flags ) /* in: table flags */
2005-10-27 09:29:40 +02:00
{
Field * field ;
dict_table_t * table ;
ulint n_cols ;
2006-02-21 13:37:54 +01:00
int error ;
ulint col_type ;
2005-10-27 09:29:40 +02:00
ulint col_len ;
2006-02-21 13:37:54 +01:00
ulint nulls_allowed ;
2005-10-27 09:29:40 +02:00
ulint unsigned_type ;
ulint binary_type ;
ulint long_true_varchar ;
ulint charset_no ;
2006-02-21 13:37:54 +01:00
ulint i ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " create_table_def " ) ;
DBUG_PRINT ( " enter " , ( " table_name: %s " , table_name ) ) ;
2005-10-27 09:29:40 +02:00
2008-02-07 13:02:06 +01:00
ut_a ( trx - > mysql_thd ! = NULL ) ;
if ( IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS ( table_name ,
( THD * ) trx - > mysql_thd ) ) {
DBUG_RETURN ( HA_ERR_GENERIC ) ;
}
2005-10-27 09:29:40 +02:00
n_cols = form - > s - > fields ;
/* We pass 0 as the space id, and determine at a lower level the space
id where to store the table */
2006-02-27 10:11:57 +01:00
table = dict_mem_table_create ( table_name , 0 , n_cols , flags ) ;
2005-10-27 09:29:40 +02:00
if ( path_of_temp_table ) {
table - > dir_path_of_temp_table =
mem_heap_strdup ( table - > heap , path_of_temp_table ) ;
}
for ( i = 0 ; i < n_cols ; i + + ) {
field = form - > field [ i ] ;
col_type = get_innobase_type_from_mysql_type ( & unsigned_type ,
field ) ;
if ( field - > null_ptr ) {
nulls_allowed = 0 ;
} else {
nulls_allowed = DATA_NOT_NULL ;
}
if ( field - > binary ( ) ) {
binary_type = DATA_BINARY_TYPE ;
} else {
binary_type = 0 ;
}
2006-02-21 13:37:54 +01:00
charset_no = 0 ;
2005-10-27 09:29:40 +02:00
if ( dtype_is_string_type ( col_type ) ) {
charset_no = ( ulint ) field - > charset ( ) - > number ;
ut_a ( charset_no < 256 ) ; /* in data0type.h we assume
that the number fits in one
byte */
}
ut_a ( field - > type ( ) < 256 ) ; /* we assume in dtype_form_prtype()
that this fits in one byte */
col_len = field - > pack_length ( ) ;
/* The MySQL pack length contains 1 or 2 bytes length field
for a true VARCHAR . Let us subtract that , so that the InnoDB
column length in the InnoDB data dictionary is the real
maximum byte length of the actual data . */
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
long_true_varchar = 0 ;
if ( field - > type ( ) = = MYSQL_TYPE_VARCHAR ) {
col_len - = ( ( Field_varstring * ) field ) - > length_bytes ;
if ( ( ( Field_varstring * ) field ) - > length_bytes = = 2 ) {
long_true_varchar = DATA_LONG_TRUE_VARCHAR ;
}
}
2009-09-10 22:43:05 +02:00
/* First check whether the column to be added has a
system reserved name . */
if ( dict_col_name_is_reserved ( field - > field_name ) ) {
push_warning_printf (
( THD * ) trx - > mysql_thd ,
2009-10-30 04:18:38 +01:00
MYSQL_ERROR : : WARN_LEVEL_WARN ,
2009-09-10 22:43:05 +02:00
ER_CANT_CREATE_TABLE ,
" Error creating table '%s' with "
" column name '%s'. '%s' is a "
" reserved name. Please try to "
" re-create the table with a "
" different column name. " ,
table - > name , ( char * ) field - > field_name ,
( char * ) field - > field_name ) ;
dict_mem_table_free ( table ) ;
trx_commit_for_mysql ( trx ) ;
error = DB_ERROR ;
goto error_ret ;
}
2007-08-15 14:41:46 +02:00
dict_mem_table_add_col ( table , table - > heap ,
2006-02-21 13:37:54 +01:00
( char * ) field - > field_name ,
col_type ,
dtype_form_prtype (
( ulint ) field - > type ( )
| nulls_allowed | unsigned_type
| binary_type | long_true_varchar ,
charset_no ) ,
Reduce the size of the data dictionary cache. (Bug #20877)
dtype_t: Remove unused field "prec", which was supposed to be used for
the precision of decimal columns in stand-alone InnoDB.
dtype_get_prec(): Remove.
dtype_set(), dict_mem_table_add_col(): Remove parameter "prec".
dtype_t: Turn all fields (mtype, prtype, len, mbminlen, mbmaxlen, len)
into bit-fields.
dict_table_t, dict_index_t, dict_tree_t: Omit magic_n from non-debug builds.
dict_col_t: Turn ind, clust_pos, and ord_part into bit-fields.
Replace the default clust_pos value ULINT_UNDEFINED with
REC_MAX_N_FIELDS and replace all references to clust_pos with calls to
the accessor function dict_col_get_clust_pos().
dict_field_t: Turn prefix_len and fixed_len into bit-fields.
dict_tree_t: Remove pad[64].
dict_table_t: Turn the fields ibd_file_missing, tablespace_discarded,
cached, flags, stat_initialized, and autoinc_inited into bit-fields.
Remove does_not_fit_in_memory from non-debug builds.
dict_index_t: Turn the fields trx_id_offset, n_user_defined_cols,
n_uniq, n_def, n_fields, n_nullable, and cached into bit-fields.
dict_foreign_struct: Turn n_fields and type into bit-fields.
rw_lock_t: Turn cline, last_s_line, and last_x_line into bit-fields.
Omit level unless #defined UNIV_SYNC_DEBUG.
Move REC_MAX_N_FIELDS (and REC_MAX_HEAP_NO and REC_MAX_N_OWNED)
from rem0rec.c to rem0types.h, as they are needed in dict0dict.ic.
dict_col_get_clust_pos(): Map REC_MAX_N_FIELDS to ULINT_UNDEFINED.
2006-09-12 16:06:46 +02:00
col_len ) ;
2005-10-27 09:29:40 +02:00
}
error = row_create_table_for_mysql ( table , trx ) ;
2007-06-13 11:02:58 +02:00
innodb_check_for_record_too_big_error ( flags & DICT_TF_COMPACT , error ) ;
2007-04-11 03:34:33 +02:00
2009-09-10 22:43:05 +02:00
error_ret :
2005-10-27 09:29:40 +02:00
error = convert_error_code_to_mysql ( error , NULL ) ;
DBUG_RETURN ( error ) ;
}
/*********************************************************************
Creates an index in an InnoDB database . */
static
int
create_index (
/*=========*/
trx_t * trx , /* in: InnoDB transaction handle */
TABLE * form , /* in: information on table
columns and indexes */
const char * table_name , /* in: table name */
uint key_num ) /* in: index number */
{
Field * field ;
dict_index_t * index ;
2006-02-21 13:37:54 +01:00
int error ;
2005-10-27 09:29:40 +02:00
ulint n_fields ;
KEY * key ;
KEY_PART_INFO * key_part ;
ulint ind_type ;
ulint col_type ;
ulint prefix_len ;
ulint is_unsigned ;
2006-02-21 13:37:54 +01:00
ulint i ;
ulint j ;
2005-10-27 09:29:40 +02:00
ulint * field_lengths ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " create_index " ) ;
2005-10-27 09:29:40 +02:00
key = form - > key_info + key_num ;
2006-02-21 13:37:54 +01:00
n_fields = key - > key_parts ;
2005-10-27 09:29:40 +02:00
2009-09-15 01:39:21 +02:00
/* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */
ut_a ( innobase_strcasecmp ( key - > name , innobase_index_reserve_name ) ! = 0 ) ;
2006-02-21 13:37:54 +01:00
ind_type = 0 ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( key_num = = form - > s - > primary_key ) {
2005-10-27 09:29:40 +02:00
ind_type = ind_type | DICT_CLUSTERED ;
}
if ( key - > flags & HA_NOSAME ) {
ind_type = ind_type | DICT_UNIQUE ;
}
/* We pass 0 as the space id, and determine at a lower level the space
id where to store the table */
index = dict_mem_index_create ( ( char * ) table_name , key - > name , 0 ,
ind_type , n_fields ) ;
field_lengths = ( ulint * ) my_malloc ( sizeof ( ulint ) * n_fields ,
MYF ( MY_FAE ) ) ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
for ( i = 0 ; i < n_fields ; i + + ) {
key_part = key - > key_part + i ;
/* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
field in an index : we only store a specified number of first
bytes of the column to the index field . ) The flag does not
seem to be properly set by MySQL . Let us fall back on testing
the length of the key part versus the column . */
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
field = NULL ;
for ( j = 0 ; j < form - > s - > fields ; j + + ) {
field = form - > field [ j ] ;
if ( 0 = = innobase_strcasecmp (
field - > field_name ,
key_part - > field - > field_name ) ) {
/* Found the corresponding column */
break ;
}
}
ut_a ( j < form - > s - > fields ) ;
col_type = get_innobase_type_from_mysql_type (
& is_unsigned , key_part - > field ) ;
if ( DATA_BLOB = = col_type
2006-02-21 13:37:54 +01:00
| | ( key_part - > length < field - > pack_length ( )
& & field - > type ( ) ! = MYSQL_TYPE_VARCHAR )
| | ( field - > type ( ) = = MYSQL_TYPE_VARCHAR
& & key_part - > length < field - > pack_length ( )
- ( ( Field_varstring * ) field ) - > length_bytes ) ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
prefix_len = key_part - > length ;
2005-10-27 09:29:40 +02:00
if ( col_type = = DATA_INT
2006-02-21 13:37:54 +01:00
| | col_type = = DATA_FLOAT
| | col_type = = DATA_DOUBLE
| | col_type = = DATA_DECIMAL ) {
sql_print_error (
" MySQL is trying to create a column "
" prefix index field, on an "
" inappropriate data type. Table "
" name %s, column name %s. " ,
table_name ,
key_part - > field - > field_name ) ;
prefix_len = 0 ;
2005-10-27 09:29:40 +02:00
}
} else {
2006-02-21 13:37:54 +01:00
prefix_len = 0 ;
2005-10-27 09:29:40 +02:00
}
field_lengths [ i ] = key_part - > length ;
dict_mem_index_add_field ( index ,
2006-02-20 13:38:10 +01:00
( char * ) key_part - > field - > field_name , prefix_len ) ;
2005-10-27 09:29:40 +02:00
}
2005-11-04 11:57:22 +01:00
/* Even though we've defined max_supported_key_part_length, we
still do our own checking using field_lengths to be absolutely
sure we don ' t create too long indexes . */
2005-10-27 09:29:40 +02:00
error = row_create_index_for_mysql ( index , trx , field_lengths ) ;
2007-06-12 11:51:03 +02:00
innodb_check_for_record_too_big_error ( form - > s - > row_type
! = ROW_TYPE_REDUNDANT , error ) ;
2007-04-11 03:34:33 +02:00
2005-10-27 09:29:40 +02:00
error = convert_error_code_to_mysql ( error , NULL ) ;
2007-06-04 10:45:27 +02:00
my_free ( field_lengths , MYF ( 0 ) ) ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
DBUG_RETURN ( error ) ;
}
/*********************************************************************
Creates an index to an InnoDB table when the user has defined no
primary index . */
static
int
create_clustered_index_when_no_primary (
/*===================================*/
trx_t * trx , /* in: InnoDB transaction handle */
2007-06-12 11:51:03 +02:00
ulint comp , /* in: ROW_FORMAT:
nonzero = COMPACT , 0 = REDUNDANT */
2005-10-27 09:29:40 +02:00
const char * table_name ) /* in: table name */
{
dict_index_t * index ;
2006-02-21 13:37:54 +01:00
int error ;
2005-10-27 09:29:40 +02:00
/* We pass 0 as the space id, and determine at a lower level the space
id where to store the table */
2009-09-15 01:39:21 +02:00
index = dict_mem_index_create ( table_name ,
innobase_index_reserve_name ,
2007-06-12 11:51:03 +02:00
0 , DICT_CLUSTERED , 0 ) ;
2005-10-27 09:29:40 +02:00
error = row_create_index_for_mysql ( index , trx , NULL ) ;
2007-06-12 11:51:03 +02:00
innodb_check_for_record_too_big_error ( comp , error ) ;
2007-04-11 03:34:33 +02:00
2005-10-27 09:29:40 +02:00
error = convert_error_code_to_mysql ( error , NULL ) ;
return ( error ) ;
}
/*********************************************************************
2007-04-02 09:20:23 +02:00
Update create_info . Used in SHOW CREATE TABLE et al . */
void
ha_innobase : : update_create_info (
/*============================*/
HA_CREATE_INFO * create_info ) /* in/out: create info */
{
if ( ! ( create_info - > used_fields & HA_CREATE_USED_AUTO ) ) {
ha_innobase : : info ( HA_STATUS_AUTO ) ;
create_info - > auto_increment_value = stats . auto_increment_value ;
}
}
/*********************************************************************
2005-10-27 09:29:40 +02:00
Creates a new table to an InnoDB database . */
int
ha_innobase : : create (
/*================*/
/* out: error number */
const char * name , /* in: table name */
TABLE * form , /* in: information on table
columns and indexes */
HA_CREATE_INFO * create_info ) /* in: more information of the
created table , contains also the
create statement string */
{
int error ;
dict_table_t * innobase_table ;
trx_t * parent_trx ;
trx_t * trx ;
int primary_key_no ;
uint i ;
char name2 [ FN_REFLEN ] ;
char norm_name [ FN_REFLEN ] ;
2007-05-10 13:31:36 +02:00
THD * thd = ha_thd ( ) ;
2006-02-21 13:37:54 +01:00
ib_longlong auto_inc_value ;
2006-02-27 10:11:57 +01:00
ulint flags ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " ha_innobase::create " ) ;
2005-10-27 09:29:40 +02:00
DBUG_ASSERT ( thd ! = NULL ) ;
2008-05-19 23:37:14 +02:00
DBUG_ASSERT ( create_info ! = NULL ) ;
# ifdef __WIN__
/* Names passed in from server are in two formats:
1. < database_name > / < table_name > : for normal table creation
2. full path : for temp table creation , or sym link
2009-09-22 17:45:07 +02:00
When srv_file_per_table is on and mysqld_embedded is off ,
check for full path pattern , i . e .
2008-05-19 23:37:14 +02:00
X : \ dir \ . . . , X is a driver letter , or
\ \ dir1 \ dir2 \ . . . , UNC path
returns error if it is in full path format , but not creating a temp .
table . Currently InnoDB does not support symbolic link on Windows . */
if ( srv_file_per_table
2009-09-22 17:45:07 +02:00
& & ! mysqld_embedded
2008-05-19 23:37:14 +02:00
& & ( ! create_info - > options & HA_LEX_CREATE_TMP_TABLE ) ) {
if ( ( name [ 1 ] = = ' : ' )
| | ( name [ 0 ] = = ' \\ ' & & name [ 1 ] = = ' \\ ' ) ) {
sql_print_error ( " Cannot create table %s \n " , name ) ;
DBUG_RETURN ( HA_ERR_GENERIC ) ;
}
}
# endif
2005-10-27 09:29:40 +02:00
if ( form - > s - > fields > 1000 ) {
/* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
but we play safe here */
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( HA_ERR_TO_BIG_ROW ) ;
}
2005-10-27 09:29:40 +02:00
/* Get the transaction associated with the current thd, or create one
if not yet created */
2006-02-21 13:37:54 +01:00
2007-05-10 14:09:03 +02:00
parent_trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
2006-02-21 13:37:54 +01:00
trx_search_latch_release_if_reserved ( parent_trx ) ;
2005-10-27 09:29:40 +02:00
trx = trx_allocate_for_mysql ( ) ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
trx - > mysql_thd = thd ;
2007-05-10 13:31:36 +02:00
trx - > mysql_query_str = thd_query ( thd ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
if ( thd_test_options ( thd , OPTION_NO_FOREIGN_KEY_CHECKS ) ) {
2005-10-27 09:29:40 +02:00
trx - > check_foreigns = FALSE ;
}
2007-05-10 13:31:36 +02:00
if ( thd_test_options ( thd , OPTION_RELAXED_UNIQUE_CHECKS ) ) {
2005-10-27 09:29:40 +02:00
trx - > check_unique_secondary = FALSE ;
}
if ( lower_case_table_names ) {
srv_lower_case_table_names = TRUE ;
} else {
srv_lower_case_table_names = FALSE ;
}
2006-01-27 10:41:19 +01:00
strcpy ( name2 , name ) ;
2005-10-27 09:29:40 +02:00
normalize_table_name ( norm_name , name2 ) ;
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
or lock waits can happen in it during a table create operation .
Drop table etc . do this latching in row0mysql . c . */
row_mysql_lock_data_dictionary ( trx ) ;
/* Create the table definition in InnoDB */
2006-02-27 10:11:57 +01:00
flags = 0 ;
if ( form - > s - > row_type ! = ROW_TYPE_REDUNDANT ) {
flags | = DICT_TF_COMPACT ;
}
2005-10-27 09:29:40 +02:00
/* Look for a primary key */
2005-11-30 13:31:55 +01:00
primary_key_no = ( form - > s - > primary_key ! = MAX_KEY ?
2006-02-21 13:37:54 +01:00
( int ) form - > s - > primary_key :
2005-10-27 09:29:40 +02:00
- 1 ) ;
/* Our function row_get_mysql_key_number_for_index assumes
the primary key is always number 0 , if it exists */
DBUG_ASSERT ( primary_key_no = = - 1 | | primary_key_no = = 0 ) ;
2009-09-15 01:39:21 +02:00
/* Check for name conflicts (with reserved name) for
any user indices to be created . */
if ( innobase_index_name_is_reserved ( trx , form , norm_name ) ) {
error = - 1 ;
goto cleanup ;
}
error = create_table_def ( trx , form , norm_name ,
create_info - > options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL ,
flags ) ;
if ( error ) {
goto cleanup ;
}
2005-10-27 09:29:40 +02:00
/* Create the keys */
if ( form - > s - > keys = = 0 | | primary_key_no = = - 1 ) {
/* Create an index which is used as the clustered index;
order the rows by their row id which is internally generated
by InnoDB */
2007-06-12 11:51:03 +02:00
error = create_clustered_index_when_no_primary (
trx , form - > s - > row_type ! = ROW_TYPE_REDUNDANT ,
norm_name ) ;
2006-02-21 13:37:54 +01:00
if ( error ) {
2005-10-27 09:29:40 +02:00
goto cleanup ;
2006-02-21 13:37:54 +01:00
}
2005-10-27 09:29:40 +02:00
}
if ( primary_key_no ! = - 1 ) {
/* In InnoDB the clustered index must always be created
first */
2006-02-21 13:37:54 +01:00
if ( ( error = create_index ( trx , form , norm_name ,
2005-10-27 09:29:40 +02:00
( uint ) primary_key_no ) ) ) {
goto cleanup ;
2006-02-21 13:37:54 +01:00
}
}
2005-10-27 09:29:40 +02:00
for ( i = 0 ; i < form - > s - > keys ; i + + ) {
if ( i ! = ( uint ) primary_key_no ) {
2006-02-21 13:37:54 +01:00
if ( ( error = create_index ( trx , form , norm_name , i ) ) ) {
2005-10-27 09:29:40 +02:00
goto cleanup ;
2006-02-21 13:37:54 +01:00
}
}
}
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
if ( * trx - > mysql_query_str ) {
2005-10-27 09:29:40 +02:00
error = row_table_add_foreign_constraints ( trx ,
2007-05-10 13:31:36 +02:00
* trx - > mysql_query_str , norm_name ,
2005-10-27 09:29:40 +02:00
create_info - > options & HA_LEX_CREATE_TMP_TABLE ) ;
error = convert_error_code_to_mysql ( error , NULL ) ;
if ( error ) {
goto cleanup ;
}
}
2006-02-21 13:37:54 +01:00
innobase_commit_low ( trx ) ;
2005-10-27 09:29:40 +02:00
row_mysql_unlock_data_dictionary ( trx ) ;
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out - of - sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
log_buffer_flush_to_disk ( ) ;
2006-12-12 10:37:18 +01:00
innobase_table = dict_table_get ( norm_name , FALSE ) ;
2005-10-27 09:29:40 +02:00
DBUG_ASSERT ( innobase_table ! = 0 ) ;
2008-03-03 23:50:15 +01:00
/* Note: We can't call update_thd() as prebuilt will not be
setup at this stage and so we use thd . */
/* We need to copy the AUTOINC value from the old table if
2009-10-12 05:37:49 +02:00
this is an ALTER TABLE or CREATE INDEX because CREATE INDEX
does a table copy too . */
2008-03-03 23:50:15 +01:00
if ( ( ( create_info - > used_fields & HA_CREATE_USED_AUTO )
2009-10-12 05:37:49 +02:00
| | thd_sql_command ( thd ) = = SQLCOM_ALTER_TABLE
| | thd_sql_command ( thd ) = = SQLCOM_CREATE_INDEX )
& & create_info - > auto_increment_value > 0 ) {
/* Query was one of :
CREATE TABLE . . . AUTO_INCREMENT = x ; or
ALTER TABLE . . . AUTO_INCREMENT = x ; or
CREATE INDEX x on t ( . . . ) ;
Find out a table definition from the dictionary and get
the current value of the auto increment field . Set a new
value to the auto increment field if the value is greater
than the maximum value in the column . */
2005-10-27 09:29:40 +02:00
auto_inc_value = create_info - > auto_increment_value ;
2007-07-24 03:42:16 +02:00
dict_table_autoinc_lock ( innobase_table ) ;
2005-10-27 09:29:40 +02:00
dict_table_autoinc_initialize ( innobase_table , auto_inc_value ) ;
2007-07-24 03:42:16 +02:00
dict_table_autoinc_unlock ( innobase_table ) ;
2005-10-27 09:29:40 +02:00
}
/* Tell the InnoDB server that there might be work for
utility threads : */
srv_active_wake_master_thread ( ) ;
2006-02-21 13:37:54 +01:00
trx_free_for_mysql ( trx ) ;
2005-10-27 09:29:40 +02:00
DBUG_RETURN ( 0 ) ;
cleanup :
innobase_commit_low ( trx ) ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
row_mysql_unlock_data_dictionary ( trx ) ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
trx_free_for_mysql ( trx ) ;
DBUG_RETURN ( error ) ;
}
/*********************************************************************
Discards or imports an InnoDB tablespace . */
int
ha_innobase : : discard_or_import_tablespace (
/*======================================*/
/* out: 0 == success, -1 == error */
my_bool discard ) /* in: TRUE if discard, else import */
{
dict_table_t * dict_table ;
trx_t * trx ;
int err ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " ha_innobase::discard_or_import_tablespace " ) ;
2005-10-27 09:29:40 +02:00
2007-02-14 21:03:58 +01:00
ut_a ( prebuilt - > trx ) ;
ut_a ( prebuilt - > trx - > magic_n = = TRX_MAGIC_N ) ;
2007-05-10 14:09:03 +02:00
ut_a ( prebuilt - > trx = = thd_to_trx ( ha_thd ( ) ) ) ;
2005-10-27 09:29:40 +02:00
dict_table = prebuilt - > table ;
trx = prebuilt - > trx ;
if ( discard ) {
err = row_discard_tablespace_for_mysql ( dict_table - > name , trx ) ;
} else {
err = row_import_tablespace_for_mysql ( dict_table - > name , trx ) ;
}
err = convert_error_code_to_mysql ( err , NULL ) ;
DBUG_RETURN ( err ) ;
}
/*********************************************************************
Deletes all rows of an InnoDB table . */
int
ha_innobase : : delete_all_rows ( void )
/*==============================*/
/* out: error number */
{
int error ;
DBUG_ENTER ( " ha_innobase::delete_all_rows " ) ;
2007-05-10 13:31:36 +02:00
/* Get the transaction associated with the current thd, or create one
if not yet created , and update prebuilt - > trx */
update_thd ( ha_thd ( ) ) ;
if ( thd_sql_command ( user_thd ) ! = SQLCOM_TRUNCATE ) {
2005-10-27 09:29:40 +02:00
fallback :
/* We only handle TRUNCATE TABLE t as a special case.
2008-10-09 08:53:09 +02:00
DELETE FROM t will have to use ha_innobase : : delete_row ( ) ,
because DELETE is transactional while TRUNCATE is not . */
2005-10-27 09:29:40 +02:00
DBUG_RETURN ( my_errno = HA_ERR_WRONG_COMMAND ) ;
}
/* Truncate the table in InnoDB */
2006-08-11 10:44:10 +02:00
error = row_truncate_table_for_mysql ( prebuilt - > table , prebuilt - > trx ) ;
2005-10-27 09:29:40 +02:00
if ( error = = DB_ERROR ) {
/* Cannot truncate; resort to ha_innobase::delete_row() */
goto fallback ;
}
error = convert_error_code_to_mysql ( error , NULL ) ;
DBUG_RETURN ( error ) ;
}
/*********************************************************************
Drops a table from an InnoDB database . Before calling this function ,
MySQL calls innobase_commit to commit the transaction of the current user .
Then the current user cannot have locks set on the table . Drop table
operation inside InnoDB will remove all locks any user has on the table
inside InnoDB . */
int
ha_innobase : : delete_table (
/*======================*/
/* out: error number */
const char * name ) /* in: table name */
{
ulint name_len ;
int error ;
trx_t * parent_trx ;
trx_t * trx ;
2007-05-10 13:31:36 +02:00
THD * thd = ha_thd ( ) ;
2005-10-27 09:29:40 +02:00
char norm_name [ 1000 ] ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " ha_innobase::delete_table " ) ;
2005-10-27 09:29:40 +02:00
2008-02-07 13:02:06 +01:00
/* Strangely, MySQL passes the table name without the '.frm'
extension , in contrast to : : create */
normalize_table_name ( norm_name , name ) ;
if ( IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS ( norm_name , thd ) ) {
DBUG_RETURN ( HA_ERR_GENERIC ) ;
}
2005-10-27 09:29:40 +02:00
/* Get the transaction associated with the current thd, or create one
if not yet created */
2006-02-21 13:37:54 +01:00
2007-05-10 14:09:03 +02:00
parent_trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
2006-02-21 13:37:54 +01:00
trx_search_latch_release_if_reserved ( parent_trx ) ;
2005-10-27 09:29:40 +02:00
if ( lower_case_table_names ) {
srv_lower_case_table_names = TRUE ;
} else {
srv_lower_case_table_names = FALSE ;
}
trx = trx_allocate_for_mysql ( ) ;
2007-05-10 13:31:36 +02:00
trx - > mysql_thd = thd ;
trx - > mysql_query_str = thd_query ( thd ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
if ( thd_test_options ( thd , OPTION_NO_FOREIGN_KEY_CHECKS ) ) {
2005-10-27 09:29:40 +02:00
trx - > check_foreigns = FALSE ;
}
2007-05-10 13:31:36 +02:00
if ( thd_test_options ( thd , OPTION_RELAXED_UNIQUE_CHECKS ) ) {
2005-10-27 09:29:40 +02:00
trx - > check_unique_secondary = FALSE ;
}
name_len = strlen ( name ) ;
assert ( name_len < 1000 ) ;
2006-02-21 13:37:54 +01:00
/* Drop the table in InnoDB */
2005-10-27 09:29:40 +02:00
error = row_drop_table_for_mysql ( norm_name , trx ,
2007-05-10 13:31:36 +02:00
thd_sql_command ( thd )
= = SQLCOM_DROP_DB ) ;
2005-10-27 09:29:40 +02:00
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out - of - sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
log_buffer_flush_to_disk ( ) ;
/* Tell the InnoDB server that there might be work for
utility threads : */
srv_active_wake_master_thread ( ) ;
2006-02-21 13:37:54 +01:00
innobase_commit_low ( trx ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
trx_free_for_mysql ( trx ) ;
2005-10-27 09:29:40 +02:00
error = convert_error_code_to_mysql ( error , NULL ) ;
DBUG_RETURN ( error ) ;
}
/*********************************************************************
Removes all tables in the named database inside InnoDB . */
2007-02-12 14:08:02 +01:00
static
2005-10-27 09:51:34 +02:00
void
2005-10-27 09:29:40 +02:00
innobase_drop_database (
/*===================*/
/* out: error number */
2006-10-03 14:46:23 +02:00
handlerton * hton , /* in: handlerton of Innodb */
2005-10-27 09:29:40 +02:00
char * path ) /* in: database path; inside InnoDB the name
of the last directory in the path is used as
the database name : for example , in ' mysql / data / test '
the database name is ' test ' */
{
ulint len = 0 ;
trx_t * parent_trx ;
trx_t * trx ;
char * ptr ;
int error ;
char * namebuf ;
2007-05-10 13:31:36 +02:00
THD * thd = current_thd ;
2005-10-27 09:29:40 +02:00
/* Get the transaction associated with the current thd, or create one
if not yet created */
2006-02-21 13:37:54 +01:00
2007-05-10 14:09:03 +02:00
parent_trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
2006-02-21 13:37:54 +01:00
trx_search_latch_release_if_reserved ( parent_trx ) ;
2005-10-27 09:29:40 +02:00
ptr = strend ( path ) - 2 ;
while ( ptr > = path & & * ptr ! = ' \\ ' & & * ptr ! = ' / ' ) {
ptr - - ;
len + + ;
}
ptr + + ;
2007-06-04 10:45:27 +02:00
namebuf = ( char * ) my_malloc ( ( uint ) len + 2 , MYF ( 0 ) ) ;
2005-10-27 09:29:40 +02:00
memcpy ( namebuf , ptr , len ) ;
namebuf [ len ] = ' / ' ;
namebuf [ len + 1 ] = ' \0 ' ;
2006-02-21 13:37:54 +01:00
# ifdef __WIN__
2005-10-27 09:29:40 +02:00
innobase_casedn_str ( namebuf ) ;
# endif
trx = trx_allocate_for_mysql ( ) ;
2007-05-10 13:31:36 +02:00
trx - > mysql_thd = thd ;
trx - > mysql_query_str = thd_query ( thd ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
if ( thd_test_options ( thd , OPTION_NO_FOREIGN_KEY_CHECKS ) ) {
2005-10-27 09:29:40 +02:00
trx - > check_foreigns = FALSE ;
}
2006-02-21 13:37:54 +01:00
error = row_drop_database_for_mysql ( namebuf , trx ) ;
2005-10-27 09:29:40 +02:00
my_free ( namebuf , MYF ( 0 ) ) ;
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out - of - sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
log_buffer_flush_to_disk ( ) ;
/* Tell the InnoDB server that there might be work for
utility threads : */
srv_active_wake_master_thread ( ) ;
2006-02-21 13:37:54 +01:00
innobase_commit_low ( trx ) ;
trx_free_for_mysql ( trx ) ;
# ifdef NO_LONGER_INTERESTED_IN_DROP_DB_ERROR
2005-10-27 09:29:40 +02:00
error = convert_error_code_to_mysql ( error , NULL ) ;
return ( error ) ;
2005-10-27 09:51:34 +02:00
# else
return ;
# endif
2005-10-27 09:29:40 +02:00
}
/*************************************************************************
Renames an InnoDB table . */
int
ha_innobase : : rename_table (
/*======================*/
/* out: 0 or error code */
const char * from , /* in: old name of the table */
const char * to ) /* in: new name of the table */
{
ulint name_len1 ;
ulint name_len2 ;
int error ;
trx_t * parent_trx ;
trx_t * trx ;
char norm_from [ 1000 ] ;
char norm_to [ 1000 ] ;
2007-05-10 13:31:36 +02:00
THD * thd = ha_thd ( ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " ha_innobase::rename_table " ) ;
2005-10-27 09:29:40 +02:00
/* Get the transaction associated with the current thd, or create one
if not yet created */
2006-02-21 13:37:54 +01:00
2007-05-10 14:09:03 +02:00
parent_trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
2006-02-21 13:37:54 +01:00
trx_search_latch_release_if_reserved ( parent_trx ) ;
2005-10-27 09:29:40 +02:00
if ( lower_case_table_names ) {
srv_lower_case_table_names = TRUE ;
} else {
srv_lower_case_table_names = FALSE ;
}
trx = trx_allocate_for_mysql ( ) ;
2007-05-10 13:31:36 +02:00
trx - > mysql_thd = thd ;
trx - > mysql_query_str = thd_query ( thd ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
if ( thd_test_options ( thd , OPTION_NO_FOREIGN_KEY_CHECKS ) ) {
2005-10-27 09:29:40 +02:00
trx - > check_foreigns = FALSE ;
}
name_len1 = strlen ( from ) ;
name_len2 = strlen ( to ) ;
assert ( name_len1 < 1000 ) ;
assert ( name_len2 < 1000 ) ;
normalize_table_name ( norm_from , from ) ;
normalize_table_name ( norm_to , to ) ;
2006-02-21 13:37:54 +01:00
/* Rename the table in InnoDB */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
error = row_rename_table_for_mysql ( norm_from , norm_to , trx ) ;
2005-10-27 09:29:40 +02:00
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out - of - sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
log_buffer_flush_to_disk ( ) ;
/* Tell the InnoDB server that there might be work for
utility threads : */
srv_active_wake_master_thread ( ) ;
2006-02-21 13:37:54 +01:00
innobase_commit_low ( trx ) ;
trx_free_for_mysql ( trx ) ;
2005-10-27 09:29:40 +02:00
2009-11-20 06:55:48 +01:00
/* Add a special case to handle the Duplicated Key error
and return DB_ERROR instead .
This is to avoid a possible SIGSEGV error from mysql error
handling code . Currently , mysql handles the Duplicated Key
error by re - entering the storage layer and getting dup key
info by calling get_dup_key ( ) . This operation requires a valid
table handle ( ' row_prebuilt_t ' structure ) which could no
longer be available in the error handling stage . The suggested
solution is to report a ' table exists ' error message ( since
the dup key error here is due to an existing table whose name
is the one we are trying to rename to ) and return the generic
error code . */
2009-11-20 08:38:43 +01:00
if ( error = = ( int ) DB_DUPLICATE_KEY ) {
2009-11-20 06:55:48 +01:00
my_error ( ER_TABLE_EXISTS_ERROR , MYF ( 0 ) , to ) ;
error = DB_ERROR ;
}
2005-10-27 09:29:40 +02:00
error = convert_error_code_to_mysql ( error , NULL ) ;
DBUG_RETURN ( error ) ;
}
/*************************************************************************
Estimates the number of index records in a range . */
ha_rows
ha_innobase : : records_in_range (
/*==========================*/
/* out: estimated number of
rows */
2006-02-21 13:37:54 +01:00
uint keynr , /* in: index number */
key_range * min_key , /* in: start key value of the
range , may also be 0 */
2005-10-27 09:29:40 +02:00
key_range * max_key ) /* in: range end key val, may
2006-02-21 13:37:54 +01:00
also be 0 */
2005-10-27 09:29:40 +02:00
{
KEY * key ;
dict_index_t * index ;
2007-08-15 14:29:46 +02:00
uchar * key_val_buff2 = ( uchar * ) my_malloc (
2005-10-27 09:29:40 +02:00
table - > s - > reclength
2006-02-21 13:37:54 +01:00
+ table - > s - > max_key_length + 100 ,
2005-10-27 09:29:40 +02:00
MYF ( MY_FAE ) ) ;
ulint buff2_len = table - > s - > reclength
2006-02-21 13:37:54 +01:00
+ table - > s - > max_key_length + 100 ;
2005-10-27 09:29:40 +02:00
dtuple_t * range_start ;
dtuple_t * range_end ;
ib_longlong n_rows ;
ulint mode1 ;
ulint mode2 ;
2006-02-21 13:37:54 +01:00
void * heap1 ;
void * heap2 ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " records_in_range " ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 14:09:03 +02:00
ut_a ( prebuilt - > trx = = thd_to_trx ( ha_thd ( ) ) ) ;
2006-08-07 17:39:40 +02:00
2005-10-27 09:29:40 +02:00
prebuilt - > trx - > op_info = ( char * ) " estimating records in index range " ;
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved ( prebuilt - > trx ) ;
active_index = keynr ;
key = table - > key_info + active_index ;
index = dict_table_get_index_noninline ( prebuilt - > table , key - > name ) ;
range_start = dtuple_create_for_mysql ( & heap1 , key - > key_parts ) ;
2006-02-21 13:37:54 +01:00
dict_index_copy_types ( range_start , index , key - > key_parts ) ;
2005-10-27 09:29:40 +02:00
range_end = dtuple_create_for_mysql ( & heap2 , key - > key_parts ) ;
2006-02-21 13:37:54 +01:00
dict_index_copy_types ( range_end , index , key - > key_parts ) ;
2005-10-27 09:29:40 +02:00
row_sel_convert_mysql_key_to_innobase (
range_start , ( byte * ) key_val_buff ,
( ulint ) upd_and_key_val_buff_len ,
index ,
( byte * ) ( min_key ? min_key - > key :
2007-08-15 14:29:46 +02:00
( const uchar * ) 0 ) ,
2005-10-27 09:29:40 +02:00
( ulint ) ( min_key ? min_key - > length : 0 ) ,
prebuilt - > trx ) ;
row_sel_convert_mysql_key_to_innobase (
range_end , ( byte * ) key_val_buff2 ,
buff2_len , index ,
( byte * ) ( max_key ? max_key - > key :
2007-08-15 14:29:46 +02:00
( const uchar * ) 0 ) ,
2005-10-27 09:29:40 +02:00
( ulint ) ( max_key ? max_key - > length : 0 ) ,
prebuilt - > trx ) ;
mode1 = convert_search_mode_to_innobase ( min_key ? min_key - > flag :
2006-02-21 13:37:54 +01:00
HA_READ_KEY_EXACT ) ;
2005-10-27 09:29:40 +02:00
mode2 = convert_search_mode_to_innobase ( max_key ? max_key - > flag :
2006-02-21 13:37:54 +01:00
HA_READ_KEY_EXACT ) ;
2005-10-27 09:29:40 +02:00
2007-11-14 13:49:24 +01:00
if ( mode1 ! = PAGE_CUR_UNSUPP & & mode2 ! = PAGE_CUR_UNSUPP ) {
n_rows = btr_estimate_n_rows_in_range ( index , range_start ,
mode1 , range_end ,
mode2 ) ;
} else {
2009-04-15 09:55:18 +02:00
n_rows = HA_POS_ERROR ;
2007-11-14 13:49:24 +01:00
}
2005-10-27 09:29:40 +02:00
dtuple_free_for_mysql ( heap1 ) ;
dtuple_free_for_mysql ( heap2 ) ;
2007-06-04 10:45:27 +02:00
my_free ( key_val_buff2 , MYF ( 0 ) ) ;
2005-10-27 09:29:40 +02:00
prebuilt - > trx - > op_info = ( char * ) " " ;
/* The MySQL optimizer seems to believe an estimate of 0 rows is
always accurate and may return the result ' Empty set ' based on that .
The accuracy is not guaranteed , and even if it were , for a locking
read we should anyway perform the search to set the next - key lock .
Add 1 to the value to make sure MySQL does not make the assumption ! */
if ( n_rows = = 0 ) {
2006-02-21 13:37:54 +01:00
n_rows = 1 ;
2005-10-27 09:29:40 +02:00
}
DBUG_RETURN ( ( ha_rows ) n_rows ) ;
}
/*************************************************************************
Gives an UPPER BOUND to the number of rows in a table . This is used in
filesort . cc . */
ha_rows
ha_innobase : : estimate_rows_upper_bound ( void )
/*======================================*/
/* out: upper bound of rows */
{
dict_index_t * index ;
ulonglong estimate ;
ulonglong local_data_file_length ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " estimate_rows_upper_bound " ) ;
2005-10-27 09:29:40 +02:00
/* We do not know if MySQL can call this function before calling
external_lock ( ) . To be safe , update the thd of the current table
handle . */
2007-05-10 13:31:36 +02:00
update_thd ( ha_thd ( ) ) ;
2005-10-27 09:29:40 +02:00
prebuilt - > trx - > op_info = ( char * )
2006-02-21 13:37:54 +01:00
" calculating upper bound for table rows " ;
2005-10-27 09:29:40 +02:00
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved ( prebuilt - > trx ) ;
index = dict_table_get_first_index_noninline ( prebuilt - > table ) ;
local_data_file_length = ( ( ulonglong ) index - > stat_n_leaf_pages )
2006-02-21 13:37:54 +01:00
* UNIV_PAGE_SIZE ;
2005-10-27 09:29:40 +02:00
/* Calculate a minimum length for a clustered index record and from
that an upper bound for the number of rows . Since we only calculate
new statistics in row0mysql . c when a table has grown by a threshold
factor , we must add a safety factor 2 in front of the formula below . */
estimate = 2 * local_data_file_length /
dict_index_calc_min_rec_len ( index ) ;
prebuilt - > trx - > op_info = ( char * ) " " ;
DBUG_RETURN ( ( ha_rows ) estimate ) ;
}
/*************************************************************************
How many seeks it will take to read through the table . This is to be
comparable to the number returned by records_in_range so that we can
decide if we should scan the table or use keys . */
double
ha_innobase : : scan_time ( )
/*====================*/
/* out: estimated time measured in disk seeks */
{
/* Since MySQL seems to favor table scans too much over index
searches , we pretend that a sequential read takes the same time
as a random disk read , that is , we do not divide the following
by 10 , which would be physically realistic . */
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
return ( ( double ) ( prebuilt - > table - > stat_clustered_index_size ) ) ;
}
/**********************************************************************
Calculate the time it takes to read a set of ranges through an index
This enables us to optimise reads for clustered indexes . */
double
ha_innobase : : read_time (
/*===================*/
/* out: estimated time measured in disk seeks */
2006-02-21 13:37:54 +01:00
uint index , /* in: key number */
2005-10-27 09:29:40 +02:00
uint ranges , /* in: how many ranges */
ha_rows rows ) /* in: estimated number of rows in the ranges */
{
ha_rows total_rows ;
2006-02-21 13:37:54 +01:00
double time_for_scan ;
2005-10-27 09:29:40 +02:00
if ( index ! = table - > s - > primary_key ) {
2006-02-21 13:37:54 +01:00
/* Not clustered */
return ( handler : : read_time ( index , ranges , rows ) ) ;
2005-10-27 09:29:40 +02:00
}
if ( rows < = 2 ) {
return ( ( double ) rows ) ;
}
/* Assume that the read time is proportional to the scan time for all
rows + at most one seek per range . */
time_for_scan = scan_time ( ) ;
if ( ( total_rows = estimate_rows_upper_bound ( ) ) < rows ) {
2006-02-21 13:37:54 +01:00
return ( time_for_scan ) ;
2005-10-27 09:29:40 +02:00
}
return ( ranges + ( double ) rows / ( double ) total_rows * time_for_scan ) ;
}
/*************************************************************************
Returns statistics information of the table to the MySQL interpreter ,
in various fields of the handle object . */
2006-11-03 12:44:29 +01:00
int
2005-10-27 09:29:40 +02:00
ha_innobase : : info (
/*==============*/
uint flag ) /* in: what information MySQL requests */
{
dict_table_t * ib_table ;
dict_index_t * index ;
ha_rows rec_per_key ;
ib_longlong n_rows ;
ulong j ;
ulong i ;
char path [ FN_REFLEN ] ;
2006-02-21 13:37:54 +01:00
os_file_stat_t stat_info ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " info " ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* If we are forcing recovery at a high level, we will suppress
2005-10-27 09:29:40 +02:00
statistics calculation on tables , because that may crash the
server if an index is badly corrupted . */
2006-02-21 13:37:54 +01:00
if ( srv_force_recovery > = SRV_FORCE_NO_IBUF_MERGE ) {
2005-10-27 09:29:40 +02:00
2007-05-29 15:16:47 +02:00
/* We return success (0) instead of HA_ERR_CRASHED,
because we want MySQL to process this query and not
stop , like it would do if it received the error code
HA_ERR_CRASHED . */
DBUG_RETURN ( 0 ) ;
2006-02-21 13:37:54 +01:00
}
2005-10-27 09:29:40 +02:00
/* We do not know if MySQL can call this function before calling
external_lock ( ) . To be safe , update the thd of the current table
handle . */
2007-05-10 13:31:36 +02:00
update_thd ( ha_thd ( ) ) ;
2005-10-27 09:29:40 +02:00
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
prebuilt - > trx - > op_info = ( char * ) " returning various info to MySQL " ;
trx_search_latch_release_if_reserved ( prebuilt - > trx ) ;
2006-02-21 13:37:54 +01:00
ib_table = prebuilt - > table ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( flag & HA_STATUS_TIME ) {
2008-10-28 11:10:25 +01:00
if ( innobase_stats_on_metadata ) {
2007-05-10 13:31:36 +02:00
/* In sql_show we call with this flag: update
then statistics so that they are up - to - date */
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
prebuilt - > trx - > op_info = " updating table statistics " ;
2005-10-27 09:29:40 +02:00
2007-03-26 10:16:35 +02:00
dict_update_statistics ( ib_table ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
prebuilt - > trx - > op_info = " returning various info to MySQL " ;
2007-03-26 10:16:35 +02:00
}
2005-10-27 09:29:40 +02:00
2006-12-01 16:38:56 +01:00
my_snprintf ( path , sizeof ( path ) , " %s/%s%s " ,
2006-02-21 13:37:54 +01:00
mysql_data_home , ib_table - > name , reg_ext ) ;
2006-12-01 16:38:56 +01:00
unpack_filename ( path , path ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* Note that we do not know the access time of the table,
2005-10-27 09:29:40 +02:00
nor the CHECK TABLE time , nor the UPDATE or INSERT time . */
if ( os_file_get_status ( path , & stat_info ) ) {
2009-07-20 09:29:47 +02:00
stats . create_time = ( ulong ) stat_info . ctime ;
2005-10-27 09:29:40 +02:00
}
2006-02-21 13:37:54 +01:00
}
2005-10-27 09:29:40 +02:00
if ( flag & HA_STATUS_VARIABLE ) {
n_rows = ib_table - > stat_n_rows ;
/* Because we do not protect stat_n_rows by any mutex in a
delete , it is theoretically possible that the value can be
smaller than zero ! TODO : fix this race .
The MySQL optimizer seems to assume in a left join that n_rows
is an accurate estimate if it is zero . Of course , it is not ,
since we do not have any locks on the rows yet at this phase .
Since SHOW TABLE STATUS seems to call this function with the
HA_STATUS_TIME flag set , while the left join optimizer does not
set that flag , we add one to a zero value if the flag is not
set . That way SHOW TABLE STATUS will show the best estimate ,
while the optimizer never sees the table empty . */
if ( n_rows < 0 ) {
n_rows = 0 ;
}
if ( n_rows = = 0 & & ! ( flag & HA_STATUS_TIME ) ) {
n_rows + + ;
}
2008-11-14 19:31:48 +01:00
/* Fix bug#40386: Not flushing query cache after truncate.
n_rows can not be 0 unless the table is empty , set to 1
instead . The original problem of bug # 29507 is actually
fixed in the server code . */
2008-04-24 13:25:30 +02:00
if ( thd_sql_command ( user_thd ) = = SQLCOM_TRUNCATE ) {
2008-11-14 19:31:48 +01:00
n_rows = 1 ;
2008-06-26 14:55:43 +02:00
/* We need to reset the prebuilt value too, otherwise
checks for values greater than the last value written
to the table will fail and the autoinc counter will
not be updated . This will force write_row ( ) into
attempting an update of the table ' s AUTOINC counter . */
2008-10-04 00:48:04 +02:00
prebuilt - > autoinc_last_value = 0 ;
2008-04-24 13:25:30 +02:00
}
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
stats . records = ( ha_rows ) n_rows ;
stats . deleted = 0 ;
stats . data_file_length = ( ( ulonglong )
2005-10-27 09:29:40 +02:00
ib_table - > stat_clustered_index_size )
2006-02-21 13:37:54 +01:00
* UNIV_PAGE_SIZE ;
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
stats . index_file_length = ( ( ulonglong )
2005-10-27 09:29:40 +02:00
ib_table - > stat_sum_of_other_index_sizes )
2006-02-21 13:37:54 +01:00
* UNIV_PAGE_SIZE ;
2008-07-25 15:24:23 +02:00
/* Since fsp_get_available_space_in_free_extents() is
acquiring latches inside InnoDB , we do not call it if we
are asked by MySQL to avoid locking . Another reason to
avoid the call is that it uses quite a lot of CPU .
See Bug # 38185.
We do not update delete_length if no locking is requested
so the " old " value can remain . delete_length is initialized
to 0 in the ha_statistics ' constructor . */
if ( ! ( flag & HA_STATUS_NO_LOCK ) ) {
2008-10-03 16:17:28 +02:00
/* lock the data dictionary to avoid races with
ibd_file_missing and tablespace_discarded */
row_mysql_lock_data_dictionary ( prebuilt - > trx ) ;
/* ib_table->space must be an existent tablespace */
if ( ! ib_table - > ibd_file_missing
& & ! ib_table - > tablespace_discarded ) {
stats . delete_length =
fsp_get_available_space_in_free_extents (
ib_table - > space ) * 1024 ;
} else {
2008-10-21 08:08:30 +02:00
THD * thd ;
thd = ha_thd ( ) ;
push_warning_printf (
thd ,
MYSQL_ERROR : : WARN_LEVEL_WARN ,
ER_CANT_GET_STAT ,
" InnoDB: Trying to get the free "
" space for table %s but its "
" tablespace has been discarded or "
" the .ibd file is missing. Setting "
" the free space to zero. " ,
ib_table - > name ) ;
2008-10-03 16:17:28 +02:00
stats . delete_length = 0 ;
}
row_mysql_unlock_data_dictionary ( prebuilt - > trx ) ;
2008-07-25 15:24:23 +02:00
}
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
stats . check_time = 0 ;
2005-10-27 09:29:40 +02:00
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
if ( stats . records = = 0 ) {
stats . mean_rec_length = 0 ;
2006-02-21 13:37:54 +01:00
} else {
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
stats . mean_rec_length = ( ulong ) ( stats . data_file_length / stats . records ) ;
2006-02-21 13:37:54 +01:00
}
}
2005-10-27 09:29:40 +02:00
if ( flag & HA_STATUS_CONST ) {
index = dict_table_get_first_index_noninline ( ib_table ) ;
if ( prebuilt - > clust_index_was_generated ) {
index = dict_table_get_next_index_noninline ( index ) ;
}
for ( i = 0 ; i < table - > s - > keys ; i + + ) {
if ( index = = NULL ) {
2006-08-08 12:54:57 +02:00
sql_print_error ( " Table %s contains fewer "
2005-10-27 09:29:40 +02:00
" indexes inside InnoDB than "
" are defined in the MySQL "
" .frm file. Have you mixed up "
" .frm files from different "
2006-08-08 12:54:57 +02:00
" installations? See "
" http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html \n " ,
2005-10-27 09:29:40 +02:00
ib_table - > name ) ;
break ;
}
for ( j = 0 ; j < table - > key_info [ i ] . key_parts ; j + + ) {
if ( j + 1 > index - > n_uniq ) {
2006-08-08 12:54:57 +02:00
sql_print_error (
" Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking "
" statistics for %lu columns. Have you mixed up .frm files from different "
" installations? "
" See http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html \n " ,
2005-10-27 09:29:40 +02:00
index - > name ,
ib_table - > name ,
( unsigned long )
index - > n_uniq , j + 1 ) ;
2006-02-21 13:37:54 +01:00
break ;
2005-10-27 09:29:40 +02:00
}
if ( index - > stat_n_diff_key_vals [ j + 1 ] = = 0 ) {
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
rec_per_key = stats . records ;
2005-10-27 09:29:40 +02:00
} else {
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
rec_per_key = ( ha_rows ) ( stats . records /
2006-02-21 13:37:54 +01:00
index - > stat_n_diff_key_vals [ j + 1 ] ) ;
2005-10-27 09:29:40 +02:00
}
/* Since MySQL seems to favor table scans
too much over index searches , we pretend
index selectivity is 2 times better than
our estimate : */
rec_per_key = rec_per_key / 2 ;
if ( rec_per_key = = 0 ) {
rec_per_key = 1 ;
}
2006-02-21 13:37:54 +01:00
table - > key_info [ i ] . rec_per_key [ j ] =
2005-10-27 09:29:40 +02:00
rec_per_key > = ~ ( ulong ) 0 ? ~ ( ulong ) 0 :
2007-09-24 13:28:51 +02:00
( ulong ) rec_per_key ;
2005-10-27 09:29:40 +02:00
}
index = dict_table_get_next_index_noninline ( index ) ;
}
}
2006-02-21 13:37:54 +01:00
if ( flag & HA_STATUS_ERRKEY ) {
2007-05-21 15:43:36 +02:00
ut_a ( prebuilt - > trx ) ;
ut_a ( prebuilt - > trx - > magic_n = = TRX_MAGIC_N ) ;
2005-10-27 09:29:40 +02:00
errkey = ( unsigned int ) row_get_mysql_key_number_for_index (
2006-02-21 13:37:54 +01:00
( dict_index_t * ) trx_get_error_info ( prebuilt - > trx ) ) ;
}
2005-10-27 09:29:40 +02:00
if ( flag & HA_STATUS_AUTO & & table - > found_next_number_field ) {
2008-10-23 06:30:32 +02:00
stats . auto_increment_value = innobase_peek_autoinc ( ) ;
2005-10-27 09:29:40 +02:00
}
prebuilt - > trx - > op_info = ( char * ) " " ;
2006-11-03 12:44:29 +01:00
DBUG_RETURN ( 0 ) ;
2005-10-27 09:29:40 +02:00
}
/**************************************************************************
Updates index cardinalities of the table , based on 8 random dives into
each index tree . This does NOT calculate exact statistics on the table . */
int
ha_innobase : : analyze (
2006-02-21 13:37:54 +01:00
/*=================*/
2005-10-27 09:29:40 +02:00
/* out: returns always 0 (success) */
THD * thd , /* in: connection thread handle */
HA_CHECK_OPT * check_opt ) /* in: currently ignored */
{
2009-10-01 13:55:49 +02:00
/* Serialize ANALYZE TABLE inside InnoDB, see
Bug # 38996 Race condition in ANALYZE TABLE */
pthread_mutex_lock ( & analyze_mutex ) ;
2005-10-27 09:29:40 +02:00
/* Simply call ::info() with all the flags */
info ( HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE ) ;
2009-10-01 13:55:49 +02:00
pthread_mutex_unlock ( & analyze_mutex ) ;
2005-10-27 09:29:40 +02:00
return ( 0 ) ;
}
/**************************************************************************
2006-03-10 15:26:08 +01:00
This is mapped to " ALTER TABLE tablename ENGINE=InnoDB " , which rebuilds
2005-10-27 09:29:40 +02:00
the table in MySQL . */
int
ha_innobase : : optimize (
/*==================*/
THD * thd , /* in: connection thread handle */
HA_CHECK_OPT * check_opt ) /* in: currently ignored */
{
2006-02-21 13:37:54 +01:00
return ( HA_ADMIN_TRY_ALTER ) ;
2005-10-27 09:29:40 +02:00
}
/***********************************************************************
Tries to check that an InnoDB table is not corrupted . If corruption is
noticed , prints to stderr information about it . In case of corruption
may also assert a failure and crash the server . */
int
ha_innobase : : check (
/*===============*/
/* out: HA_ADMIN_CORRUPT or
HA_ADMIN_OK */
2006-02-21 13:37:54 +01:00
THD * thd , /* in: user thread handle */
HA_CHECK_OPT * check_opt ) /* in: check options, currently
2005-10-27 09:29:40 +02:00
ignored */
{
ulint ret ;
2007-05-10 13:31:36 +02:00
DBUG_ASSERT ( thd = = ha_thd ( ) ) ;
2007-05-21 15:43:36 +02:00
ut_a ( prebuilt - > trx ) ;
ut_a ( prebuilt - > trx - > magic_n = = TRX_MAGIC_N ) ;
2007-05-10 14:09:03 +02:00
ut_a ( prebuilt - > trx = = thd_to_trx ( thd ) ) ;
2005-10-27 09:29:40 +02:00
if ( prebuilt - > mysql_template = = NULL ) {
/* Build the template; we will use a dummy template
in index scans done in checking */
build_template ( prebuilt , NULL , table , ROW_MYSQL_WHOLE_ROW ) ;
}
ret = row_check_table_for_mysql ( prebuilt ) ;
if ( ret = = DB_SUCCESS ) {
return ( HA_ADMIN_OK ) ;
}
2006-02-21 13:37:54 +01:00
return ( HA_ADMIN_CORRUPT ) ;
2005-10-27 09:29:40 +02:00
}
/*****************************************************************
Adds information about free space in the InnoDB tablespace to a table comment
which is printed out when a user calls SHOW TABLE STATUS . Adds also info on
foreign keys . */
char *
ha_innobase : : update_table_comment (
/*==============================*/
/* out: table comment + InnoDB free space +
info on foreign keys */
2006-02-21 13:37:54 +01:00
const char * comment ) /* in: table comment defined by user */
2005-10-27 09:29:40 +02:00
{
2007-01-11 15:24:53 +01:00
uint length = ( uint ) strlen ( comment ) ;
char * str ;
2005-12-08 15:27:09 +01:00
long flen ;
2005-10-27 09:29:40 +02:00
/* We do not know if MySQL can call this function before calling
external_lock ( ) . To be safe , update the thd of the current table
handle . */
if ( length > 64000 - 3 ) {
return ( ( char * ) comment ) ; /* string too long */
}
2007-05-10 13:31:36 +02:00
update_thd ( ha_thd ( ) ) ;
2005-10-27 09:29:40 +02:00
prebuilt - > trx - > op_info = ( char * ) " returning table comment " ;
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved ( prebuilt - > trx ) ;
str = NULL ;
2005-12-08 15:27:09 +01:00
/* output the data to a temporary file */
2005-10-27 09:29:40 +02:00
2005-12-08 15:27:09 +01:00
mutex_enter_noninline ( & srv_dict_tmpfile_mutex ) ;
rewind ( srv_dict_tmpfile ) ;
2007-06-26 15:08:11 +02:00
fprintf ( srv_dict_tmpfile , " InnoDB free: %llu kB " ,
fsp_get_available_space_in_free_extents (
prebuilt - > table - > space ) ) ;
2005-10-27 09:29:40 +02:00
2005-12-08 15:27:09 +01:00
dict_print_info_on_foreign_keys ( FALSE , srv_dict_tmpfile ,
2005-10-27 09:29:40 +02:00
prebuilt - > trx , prebuilt - > table ) ;
2005-12-08 15:27:09 +01:00
flen = ftell ( srv_dict_tmpfile ) ;
if ( flen < 0 ) {
flen = 0 ;
} else if ( length + flen + 3 > 64000 ) {
flen = 64000 - 3 - length ;
}
2005-10-27 09:29:40 +02:00
2005-12-08 15:27:09 +01:00
/* allocate buffer for the full string, and
read the contents of the temporary file */
2005-10-27 09:29:40 +02:00
2007-06-04 10:45:27 +02:00
str = ( char * ) my_malloc ( length + flen + 3 , MYF ( 0 ) ) ;
2005-10-27 09:29:40 +02:00
2005-12-08 15:27:09 +01:00
if ( str ) {
char * pos = str + length ;
if ( length ) {
memcpy ( str , comment , length ) ;
* pos + + = ' ; ' ;
* pos + + = ' ' ;
2005-10-27 09:29:40 +02:00
}
2005-12-08 15:27:09 +01:00
rewind ( srv_dict_tmpfile ) ;
flen = ( uint ) fread ( pos , 1 , flen , srv_dict_tmpfile ) ;
pos [ flen ] = 0 ;
2005-10-27 09:29:40 +02:00
}
2005-12-08 15:27:09 +01:00
mutex_exit_noninline ( & srv_dict_tmpfile_mutex ) ;
2006-02-21 13:37:54 +01:00
prebuilt - > trx - > op_info = ( char * ) " " ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
return ( str ? str : ( char * ) comment ) ;
2005-10-27 09:29:40 +02:00
}
/***********************************************************************
Gets the foreign key create info for a table stored in InnoDB . */
char *
ha_innobase : : get_foreign_key_create_info ( void )
/*==========================================*/
/* out, own: character string in the form which
can be inserted to the CREATE TABLE statement ,
MUST be freed with : : free_foreign_key_create_info */
{
char * str = 0 ;
2005-12-08 15:27:09 +01:00
long flen ;
2005-10-27 09:29:40 +02:00
ut_a ( prebuilt ! = NULL ) ;
/* We do not know if MySQL can call this function before calling
external_lock ( ) . To be safe , update the thd of the current table
handle . */
2007-05-10 13:31:36 +02:00
update_thd ( ha_thd ( ) ) ;
2005-10-27 09:29:40 +02:00
2005-12-08 15:27:09 +01:00
prebuilt - > trx - > op_info = ( char * ) " getting info on foreign keys " ;
2005-10-27 09:29:40 +02:00
2005-12-08 15:27:09 +01:00
/* In case MySQL calls this in the middle of a SELECT query,
release possible adaptive hash latch to avoid
deadlocks of threads */
2005-10-27 09:29:40 +02:00
2005-12-08 15:27:09 +01:00
trx_search_latch_release_if_reserved ( prebuilt - > trx ) ;
2005-10-27 09:29:40 +02:00
2005-12-08 15:27:09 +01:00
mutex_enter_noninline ( & srv_dict_tmpfile_mutex ) ;
rewind ( srv_dict_tmpfile ) ;
2005-10-27 09:29:40 +02:00
2005-12-08 15:27:09 +01:00
/* output the data to a temporary file */
dict_print_info_on_foreign_keys ( TRUE , srv_dict_tmpfile ,
2005-10-27 09:29:40 +02:00
prebuilt - > trx , prebuilt - > table ) ;
2005-12-08 15:27:09 +01:00
prebuilt - > trx - > op_info = ( char * ) " " ;
2005-10-27 09:29:40 +02:00
2005-12-08 15:27:09 +01:00
flen = ftell ( srv_dict_tmpfile ) ;
if ( flen < 0 ) {
flen = 0 ;
} else if ( flen > 64000 - 1 ) {
flen = 64000 - 1 ;
}
2005-10-27 09:29:40 +02:00
2005-12-08 15:27:09 +01:00
/* allocate buffer for the string, and
read the contents of the temporary file */
2005-10-27 09:29:40 +02:00
2007-06-04 10:45:27 +02:00
str = ( char * ) my_malloc ( flen + 1 , MYF ( 0 ) ) ;
2005-10-27 09:29:40 +02:00
2005-12-08 15:27:09 +01:00
if ( str ) {
rewind ( srv_dict_tmpfile ) ;
flen = ( uint ) fread ( str , 1 , flen , srv_dict_tmpfile ) ;
str [ flen ] = 0 ;
2005-10-27 09:29:40 +02:00
}
2005-12-08 15:27:09 +01:00
mutex_exit_noninline ( & srv_dict_tmpfile_mutex ) ;
2006-02-21 13:37:54 +01:00
return ( str ) ;
2005-10-27 09:29:40 +02:00
}
2006-02-21 13:37:54 +01:00
int
2005-10-27 09:29:40 +02:00
ha_innobase : : get_foreign_key_list ( THD * thd , List < FOREIGN_KEY_INFO > * f_key_list )
{
dict_foreign_t * foreign ;
DBUG_ENTER ( " get_foreign_key_list " ) ;
ut_a ( prebuilt ! = NULL ) ;
2007-05-10 13:31:36 +02:00
update_thd ( ha_thd ( ) ) ;
2005-10-27 09:29:40 +02:00
prebuilt - > trx - > op_info = ( char * ) " getting list of foreign keys " ;
trx_search_latch_release_if_reserved ( prebuilt - > trx ) ;
mutex_enter_noninline ( & ( dict_sys - > mutex ) ) ;
foreign = UT_LIST_GET_FIRST ( prebuilt - > table - > foreign_list ) ;
2006-02-21 13:37:54 +01:00
while ( foreign ! = NULL ) {
uint i ;
FOREIGN_KEY_INFO f_key_info ;
LEX_STRING * name = 0 ;
2007-02-02 12:14:02 +01:00
uint ulen ;
2007-04-19 13:44:07 +02:00
char uname [ NAME_LEN + 1 ] ; /* Unencoded name */
char db_name [ NAME_LEN + 1 ] ;
2006-02-21 13:37:54 +01:00
const char * tmp_buff ;
tmp_buff = foreign - > id ;
i = 0 ;
while ( tmp_buff [ i ] ! = ' / ' )
i + + ;
tmp_buff + = i + 1 ;
2007-07-31 07:56:17 +02:00
f_key_info . forein_id = thd_make_lex_string ( thd , 0 ,
tmp_buff , ( uint ) strlen ( tmp_buff ) , 1 ) ;
2006-02-21 13:37:54 +01:00
tmp_buff = foreign - > referenced_table_name ;
2007-02-02 12:14:02 +01:00
/* Database name */
2006-02-21 13:37:54 +01:00
i = 0 ;
while ( tmp_buff [ i ] ! = ' / ' )
2007-02-02 12:14:02 +01:00
{
db_name [ i ] = tmp_buff [ i ] ;
i + + ;
}
db_name [ i ] = 0 ;
ulen = filename_to_tablename ( db_name , uname , sizeof ( uname ) ) ;
2007-07-31 07:56:17 +02:00
f_key_info . referenced_db = thd_make_lex_string ( thd , 0 ,
uname , ulen , 1 ) ;
2007-02-02 12:14:02 +01:00
/* Table name */
2006-02-21 13:37:54 +01:00
tmp_buff + = i + 1 ;
2007-02-02 12:14:02 +01:00
ulen = filename_to_tablename ( tmp_buff , uname , sizeof ( uname ) ) ;
2007-07-31 07:56:17 +02:00
f_key_info . referenced_table = thd_make_lex_string ( thd , 0 ,
uname , ulen , 1 ) ;
2006-02-21 13:37:54 +01:00
for ( i = 0 ; ; ) {
tmp_buff = foreign - > foreign_col_names [ i ] ;
2007-07-31 07:56:17 +02:00
name = thd_make_lex_string ( thd , name ,
tmp_buff , ( uint ) strlen ( tmp_buff ) , 1 ) ;
2006-02-21 13:37:54 +01:00
f_key_info . foreign_fields . push_back ( name ) ;
tmp_buff = foreign - > referenced_col_names [ i ] ;
2007-07-31 07:56:17 +02:00
name = thd_make_lex_string ( thd , name ,
tmp_buff , ( uint ) strlen ( tmp_buff ) , 1 ) ;
2006-02-21 13:37:54 +01:00
f_key_info . referenced_fields . push_back ( name ) ;
if ( + + i > = foreign - > n_fields )
break ;
}
2006-05-08 10:08:27 +02:00
ulong length ;
if ( foreign - > type & DICT_FOREIGN_ON_DELETE_CASCADE )
{
length = 7 ;
tmp_buff = " CASCADE " ;
}
else if ( foreign - > type & DICT_FOREIGN_ON_DELETE_SET_NULL )
{
length = 8 ;
tmp_buff = " SET NULL " ;
}
else if ( foreign - > type & DICT_FOREIGN_ON_DELETE_NO_ACTION )
{
length = 9 ;
tmp_buff = " NO ACTION " ;
}
else
{
length = 8 ;
tmp_buff = " RESTRICT " ;
}
2007-07-31 07:56:17 +02:00
f_key_info . delete_method = thd_make_lex_string (
thd , f_key_info . delete_method , tmp_buff , length , 1 ) ;
2006-05-08 10:08:27 +02:00
if ( foreign - > type & DICT_FOREIGN_ON_UPDATE_CASCADE )
{
length = 7 ;
tmp_buff = " CASCADE " ;
}
else if ( foreign - > type & DICT_FOREIGN_ON_UPDATE_SET_NULL )
{
length = 8 ;
tmp_buff = " SET NULL " ;
}
else if ( foreign - > type & DICT_FOREIGN_ON_UPDATE_NO_ACTION )
{
length = 9 ;
tmp_buff = " NO ACTION " ;
}
else
{
length = 8 ;
tmp_buff = " RESTRICT " ;
}
2007-07-31 07:56:17 +02:00
f_key_info . update_method = thd_make_lex_string (
thd , f_key_info . update_method , tmp_buff , length , 1 ) ;
2007-02-02 12:14:02 +01:00
if ( foreign - > referenced_index & &
foreign - > referenced_index - > name )
{
2007-07-31 07:56:17 +02:00
f_key_info . referenced_key_name = thd_make_lex_string (
thd , f_key_info . referenced_key_name ,
foreign - > referenced_index - > name ,
2009-04-17 22:32:08 +02:00
( uint ) strlen ( foreign - > referenced_index - > name ) , 1 ) ;
2007-02-02 12:14:02 +01:00
}
2008-04-30 17:04:36 +02:00
else
f_key_info . referenced_key_name = 0 ;
2006-02-21 13:37:54 +01:00
2007-05-10 13:31:36 +02:00
FOREIGN_KEY_INFO * pf_key_info = ( FOREIGN_KEY_INFO * )
2007-07-31 07:56:17 +02:00
thd_memdup ( thd , & f_key_info , sizeof ( FOREIGN_KEY_INFO ) ) ;
2006-02-21 13:37:54 +01:00
f_key_list - > push_back ( pf_key_info ) ;
foreign = UT_LIST_GET_NEXT ( foreign_list , foreign ) ;
2005-10-27 09:29:40 +02:00
}
mutex_exit_noninline ( & ( dict_sys - > mutex ) ) ;
prebuilt - > trx - > op_info = ( char * ) " " ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
DBUG_RETURN ( 0 ) ;
}
/*********************************************************************
Checks if ALTER TABLE may change the storage engine of the table .
Changing storage engines is not allowed for tables for which there
are foreign key constraints ( parent or child tables ) . */
bool
ha_innobase : : can_switch_engines ( void )
/*=================================*/
{
bool can_switch ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " ha_innobase::can_switch_engines " ) ;
2006-08-07 17:39:40 +02:00
2007-05-10 14:09:03 +02:00
ut_a ( prebuilt - > trx = = thd_to_trx ( ha_thd ( ) ) ) ;
2006-08-07 17:39:40 +02:00
2005-10-27 09:29:40 +02:00
prebuilt - > trx - > op_info =
" determining if there are foreign key constraints " ;
row_mysql_lock_data_dictionary ( prebuilt - > trx ) ;
can_switch = ! UT_LIST_GET_FIRST ( prebuilt - > table - > referenced_list )
& & ! UT_LIST_GET_FIRST ( prebuilt - > table - > foreign_list ) ;
row_mysql_unlock_data_dictionary ( prebuilt - > trx ) ;
prebuilt - > trx - > op_info = " " ;
DBUG_RETURN ( can_switch ) ;
}
/***********************************************************************
Checks if a table is referenced by a foreign key . The MySQL manual states that
a REPLACE is either equivalent to an INSERT , or DELETE ( s ) + INSERT . Only a
delete is then allowed internally to resolve a duplicate key conflict in
REPLACE , not an update . */
uint
ha_innobase : : referenced_by_foreign_key ( void )
/*========================================*/
/* out: > 0 if referenced by a FOREIGN KEY */
{
if ( dict_table_referenced_by_foreign_key ( prebuilt - > table ) ) {
return ( 1 ) ;
}
return ( 0 ) ;
}
/***********************************************************************
Frees the foreign key create info for a table stored in InnoDB , if it is
non - NULL . */
void
ha_innobase : : free_foreign_key_create_info (
/*======================================*/
2006-02-21 13:37:54 +01:00
char * str ) /* in, own: create info string to free */
2005-10-27 09:29:40 +02:00
{
if ( str ) {
my_free ( str , MYF ( 0 ) ) ;
}
}
/***********************************************************************
Tells something additional to the handler about how to do things . */
int
ha_innobase : : extra (
/*===============*/
/* out: 0 or error number */
enum ha_extra_function operation )
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
/* in: HA_EXTRA_FLUSH or some other flag */
2005-10-27 09:29:40 +02:00
{
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function , the trx field in prebuilt can be
obsolete ! */
switch ( operation ) {
2006-02-21 13:37:54 +01:00
case HA_EXTRA_FLUSH :
if ( prebuilt - > blob_heap ) {
row_mysql_prebuilt_free_blob_heap ( prebuilt ) ;
}
break ;
case HA_EXTRA_RESET_STATE :
2007-05-14 13:08:44 +02:00
reset_template ( prebuilt ) ;
2006-02-21 13:37:54 +01:00
break ;
2005-10-27 09:29:40 +02:00
case HA_EXTRA_NO_KEYREAD :
2006-02-21 13:37:54 +01:00
prebuilt - > read_just_key = 0 ;
break ;
case HA_EXTRA_KEYREAD :
prebuilt - > read_just_key = 1 ;
break ;
2005-10-27 09:29:40 +02:00
case HA_EXTRA_KEYREAD_PRESERVE_FIELDS :
prebuilt - > keep_other_fields_on_keyread = 1 ;
break ;
2007-05-14 13:25:41 +02:00
/* IMPORTANT: prebuilt->trx can be obsolete in
this method , because it is not sure that MySQL
calls external_lock before this method with the
parameters below . We must not invoke update_thd ( )
either , because the calling threads may change .
CAREFUL HERE , OR MEMORY CORRUPTION MAY OCCUR ! */
2007-05-10 13:31:36 +02:00
case HA_EXTRA_IGNORE_DUP_KEY :
2007-05-14 13:25:41 +02:00
thd_to_trx ( ha_thd ( ) ) - > duplicates | = TRX_DUP_IGNORE ;
2007-05-10 13:31:36 +02:00
break ;
case HA_EXTRA_WRITE_CAN_REPLACE :
2007-05-14 13:25:41 +02:00
thd_to_trx ( ha_thd ( ) ) - > duplicates | = TRX_DUP_REPLACE ;
2007-05-10 13:31:36 +02:00
break ;
case HA_EXTRA_WRITE_CANNOT_REPLACE :
2007-05-14 13:25:41 +02:00
thd_to_trx ( ha_thd ( ) ) - > duplicates & = ~ TRX_DUP_REPLACE ;
2007-05-10 13:31:36 +02:00
break ;
case HA_EXTRA_NO_IGNORE_DUP_KEY :
2007-05-14 13:25:41 +02:00
thd_to_trx ( ha_thd ( ) ) - > duplicates & =
2007-05-10 13:31:36 +02:00
~ ( TRX_DUP_IGNORE | TRX_DUP_REPLACE ) ;
break ;
2005-10-27 09:29:40 +02:00
default : /* Do nothing */
;
}
return ( 0 ) ;
}
2008-08-23 23:19:05 +02:00
/**********************************************************************
Reset state of file to after ' open ' .
This function is called after every statement for all tables used
by that statement . */
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
int ha_innobase : : reset ( )
{
2008-08-23 23:19:05 +02:00
if ( prebuilt - > blob_heap ) {
row_mysql_prebuilt_free_blob_heap ( prebuilt ) ;
}
reset_template ( prebuilt ) ;
/* TODO: This should really be reset in reset_template() but for now
it ' s safer to do it explicitly here . */
/* This is a statement level counter. */
2008-10-04 00:48:04 +02:00
prebuilt - > autoinc_last_value = 0 ;
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
2008-08-23 23:19:05 +02:00
return ( 0 ) ;
}
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
2005-10-27 09:29:40 +02:00
/**********************************************************************
MySQL calls this function at the start of each SQL statement inside LOCK
TABLES . Inside LOCK TABLES the : : external_lock method does not work to
mark SQL statement borders . Note also a special case : if a temporary table
is created inside LOCK TABLES , MySQL has not called external_lock ( ) at all
on that table .
MySQL - 5.0 also calls this before each statement in an execution of a stored
procedure . To make the execution more deterministic for binlogging , MySQL - 5.0
locks all tables involved in a stored procedure with full explicit table
2007-02-15 15:09:49 +01:00
locks ( thd_in_lock_tables ( thd ) holds in store_lock ( ) ) before executing the
2005-10-27 09:29:40 +02:00
procedure . */
int
ha_innobase : : start_stmt (
/*====================*/
2006-02-21 13:37:54 +01:00
/* out: 0 or error code */
THD * thd , /* in: handle to the user thread */
thr_lock_type lock_type )
2005-10-27 09:29:40 +02:00
{
trx_t * trx ;
update_thd ( thd ) ;
trx = prebuilt - > trx ;
/* Here we release the search latch and the InnoDB thread FIFO ticket
if they were reserved . They should have been released already at the
end of the previous statement , but because inside LOCK TABLES the
lock count method does not work to mark the end of a SELECT statement ,
that may not be the case . We MUST release the search latch before an
INSERT , for example . */
innobase_release_stat_resources ( trx ) ;
2007-09-08 22:40:10 +02:00
/* Reset the AUTOINC statement level counter for multi-row INSERTs. */
trx - > n_autoinc_rows = 0 ;
2005-10-27 09:29:40 +02:00
prebuilt - > sql_stat_start = TRUE ;
prebuilt - > hint_need_to_fetch_extra_cols = 0 ;
2007-05-14 13:08:44 +02:00
reset_template ( prebuilt ) ;
2005-10-27 09:29:40 +02:00
if ( ! prebuilt - > mysql_has_locked ) {
2006-02-21 13:37:54 +01:00
/* This handle is for a temporary table created inside
this same LOCK TABLES ; since MySQL does NOT call external_lock
in this case , we must use x - row locks inside InnoDB to be
prepared for an update of a row */
prebuilt - > select_lock_type = LOCK_X ;
2005-10-27 09:29:40 +02:00
} else {
if ( trx - > isolation_level ! = TRX_ISO_SERIALIZABLE
2007-05-10 13:31:36 +02:00
& & thd_sql_command ( thd ) = = SQLCOM_SELECT
2006-02-21 13:37:54 +01:00
& & lock_type = = TL_READ ) {
2005-10-27 09:29:40 +02:00
/* For other than temporary tables, we obtain
no lock for consistent read ( plain SELECT ) . */
prebuilt - > select_lock_type = LOCK_NONE ;
} else {
/* Not a consistent read: restore the
select_lock_type value . The value of
stored_select_lock_type was decided in :
1 ) : : store_lock ( ) ,
2006-02-21 13:37:54 +01:00
2 ) : : external_lock ( ) ,
3 ) : : init_table_handle_for_HANDLER ( ) , and
2006-09-20 10:52:00 +02:00
4 ) : : transactional_table_lock ( ) . */
2005-10-27 09:29:40 +02:00
prebuilt - > select_lock_type =
prebuilt - > stored_select_lock_type ;
}
}
trx - > detailed_error [ 0 ] = ' \0 ' ;
/* Set the MySQL flag to mark that there is an active transaction */
2006-02-21 13:37:54 +01:00
if ( trx - > active_trans = = 0 ) {
2005-10-27 09:29:40 +02:00
2006-10-03 14:46:23 +02:00
innobase_register_trx_and_stmt ( ht , thd ) ;
2006-02-21 13:37:54 +01:00
trx - > active_trans = 1 ;
} else {
2006-10-03 14:46:23 +02:00
innobase_register_stmt ( ht , thd ) ;
2005-10-27 09:29:40 +02:00
}
return ( 0 ) ;
}
/**********************************************************************
Maps a MySQL trx isolation level code to the InnoDB isolation level code */
inline
ulint
innobase_map_isolation_level (
/*=========================*/
/* out: InnoDB isolation level */
enum_tx_isolation iso ) /* in: MySQL isolation level code */
{
switch ( iso ) {
case ISO_REPEATABLE_READ : return ( TRX_ISO_REPEATABLE_READ ) ;
case ISO_READ_COMMITTED : return ( TRX_ISO_READ_COMMITTED ) ;
case ISO_SERIALIZABLE : return ( TRX_ISO_SERIALIZABLE ) ;
case ISO_READ_UNCOMMITTED : return ( TRX_ISO_READ_UNCOMMITTED ) ;
default : ut_a ( 0 ) ; return ( 0 ) ;
2006-02-21 13:37:54 +01:00
}
2005-10-27 09:29:40 +02:00
}
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
/**********************************************************************
As MySQL will execute an external lock for every new table it uses when it
starts to process an SQL statement ( an exception is when MySQL calls
start_stmt for the handle ) we can use this function to store the pointer to
the THD in the handle . We will also use this function to communicate
to InnoDB that a new SQL statement has started and that we must store a
savepoint to our transaction handle , so that we are able to roll back
the SQL statement in case of an error . */
int
ha_innobase : : external_lock (
/*=======================*/
2006-02-21 13:37:54 +01:00
/* out: 0 */
2005-10-27 09:29:40 +02:00
THD * thd , /* in: handle to the user thread */
2006-02-21 13:37:54 +01:00
int lock_type ) /* in: lock type */
2005-10-27 09:29:40 +02:00
{
trx_t * trx ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " ha_innobase::external_lock " ) ;
2005-10-27 09:29:40 +02:00
DBUG_PRINT ( " enter " , ( " lock_type: %d " , lock_type ) ) ;
update_thd ( thd ) ;
2007-07-31 07:56:17 +02:00
/* Statement based binlogging does not work in isolation level
READ UNCOMMITTED and READ COMMITTED since the necessary
locks cannot be taken . In this case , we print an
informative error message and return with an error . */
if ( lock_type = = F_WRLCK )
{
ulong const binlog_format = thd_binlog_format ( thd ) ;
ulong const tx_isolation = thd_tx_isolation ( current_thd ) ;
2009-11-11 13:52:14 +01:00
if ( tx_isolation < = ISO_READ_COMMITTED
& & binlog_format = = BINLOG_FORMAT_STMT
& & thd_binlog_filter_ok ( thd ) )
2007-07-31 07:56:17 +02:00
{
char buf [ 256 ] ;
my_snprintf ( buf , sizeof ( buf ) ,
" Transaction level '%s' in "
" InnoDB is not safe for binlog mode '%s' " ,
tx_isolation_names [ tx_isolation ] ,
binlog_format_names [ binlog_format ] ) ;
my_error ( ER_BINLOG_LOGGING_IMPOSSIBLE , MYF ( 0 ) , buf ) ;
DBUG_RETURN ( HA_ERR_LOGGING_IMPOSSIBLE ) ;
}
}
2005-10-27 09:29:40 +02:00
trx = prebuilt - > trx ;
prebuilt - > sql_stat_start = TRUE ;
prebuilt - > hint_need_to_fetch_extra_cols = 0 ;
2007-05-14 13:08:44 +02:00
reset_template ( prebuilt ) ;
2005-10-27 09:29:40 +02:00
if ( lock_type = = F_WRLCK ) {
/* If this is a SELECT, then it is in UPDATE TABLE ...
or SELECT . . . FOR UPDATE */
prebuilt - > select_lock_type = LOCK_X ;
prebuilt - > stored_select_lock_type = LOCK_X ;
}
if ( lock_type ! = F_UNLCK ) {
/* MySQL is setting a new table lock */
trx - > detailed_error [ 0 ] = ' \0 ' ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
/* Set the MySQL flag to mark that there is an active
transaction */
2006-02-21 13:37:54 +01:00
if ( trx - > active_trans = = 0 ) {
2005-10-27 09:29:40 +02:00
2006-10-03 14:46:23 +02:00
innobase_register_trx_and_stmt ( ht , thd ) ;
2006-02-21 13:37:54 +01:00
trx - > active_trans = 1 ;
} else if ( trx - > n_mysql_tables_in_use = = 0 ) {
2006-10-03 14:46:23 +02:00
innobase_register_stmt ( ht , thd ) ;
2005-10-27 09:29:40 +02:00
}
if ( trx - > isolation_level = = TRX_ISO_SERIALIZABLE
2006-02-21 13:37:54 +01:00
& & prebuilt - > select_lock_type = = LOCK_NONE
2007-05-10 13:31:36 +02:00
& & thd_test_options ( thd ,
OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN ) ) {
2005-10-27 09:29:40 +02:00
/* To get serializable execution, we let InnoDB
conceptually add ' LOCK IN SHARE MODE ' to all SELECTs
which otherwise would have been consistent reads . An
exception is consistent reads in the AUTOCOMMIT = 1 mode :
we know that they are read - only transactions , and they
can be serialized also if performed as consistent
reads . */
prebuilt - > select_lock_type = LOCK_S ;
prebuilt - > stored_select_lock_type = LOCK_S ;
}
/* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
TABLES if AUTOCOMMIT = 1. It does not make much sense to acquire
an InnoDB table lock if it is released immediately at the end
of LOCK TABLES , and InnoDB ' s table locks in that case cause
2006-02-21 13:37:54 +01:00
VERY easily deadlocks .
2006-01-12 10:16:11 +01:00
We do not set InnoDB table locks if user has not explicitly
2007-02-15 15:09:49 +01:00
requested a table lock . Note that thd_in_lock_tables ( thd )
can hold in some cases , e . g . , at the start of a stored
2006-01-12 10:16:11 +01:00
procedure call ( SQLCOM_CALL ) . */
2005-10-27 09:29:40 +02:00
if ( prebuilt - > select_lock_type ! = LOCK_NONE ) {
2007-05-10 13:31:36 +02:00
if ( thd_sql_command ( thd ) = = SQLCOM_LOCK_TABLES
& & THDVAR ( thd , table_locks )
& & thd_test_options ( thd , OPTION_NOT_AUTOCOMMIT )
2007-02-15 15:09:49 +01:00
& & thd_in_lock_tables ( thd ) ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
ulint error = row_lock_table_for_mysql (
prebuilt , NULL , 0 ) ;
2005-10-27 09:29:40 +02:00
if ( error ! = DB_SUCCESS ) {
error = convert_error_code_to_mysql (
2007-05-10 13:31:36 +02:00
( int ) error , thd ) ;
2005-10-27 09:29:40 +02:00
DBUG_RETURN ( ( int ) error ) ;
}
}
2006-02-21 13:37:54 +01:00
trx - > mysql_n_tables_locked + + ;
2005-10-27 09:29:40 +02:00
}
2007-09-05 15:02:36 +02:00
trx - > n_mysql_tables_in_use + + ;
prebuilt - > mysql_has_locked = TRUE ;
2005-10-27 09:29:40 +02:00
DBUG_RETURN ( 0 ) ;
}
/* MySQL is releasing a table lock */
trx - > n_mysql_tables_in_use - - ;
prebuilt - > mysql_has_locked = FALSE ;
2007-04-16 18:27:41 +02:00
/* Release a possible FIFO ticket and search latch. Since we
may reserve the kernel mutex , we have to release the search
system latch first to obey the latching order . */
innobase_release_stat_resources ( trx ) ;
2005-10-27 09:29:40 +02:00
/* If the MySQL lock count drops to zero we know that the current SQL
statement has ended */
if ( trx - > n_mysql_tables_in_use = = 0 ) {
2006-02-21 13:37:54 +01:00
trx - > mysql_n_tables_locked = 0 ;
2005-10-27 09:29:40 +02:00
prebuilt - > used_in_HANDLER = FALSE ;
2006-02-21 13:37:54 +01:00
2007-05-10 13:31:36 +02:00
if ( ! thd_test_options ( thd , OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN ) ) {
2006-02-21 13:37:54 +01:00
if ( trx - > active_trans ! = 0 ) {
2006-10-03 14:46:23 +02:00
innobase_commit ( ht , thd , TRUE ) ;
2005-10-27 09:29:40 +02:00
}
} else {
if ( trx - > isolation_level < = TRX_ISO_READ_COMMITTED
2006-02-21 13:37:54 +01:00
& & trx - > global_read_view ) {
2005-10-27 09:29:40 +02:00
/* At low transaction isolation levels we let
each consistent read set its own snapshot */
read_view_close_for_mysql ( trx ) ;
}
}
}
DBUG_RETURN ( 0 ) ;
}
/**********************************************************************
With this function MySQL request a transactional lock to a table when
user issued query LOCK TABLES . . WHERE ENGINE = InnoDB . */
int
ha_innobase : : transactional_table_lock (
/*==================================*/
2006-02-21 13:37:54 +01:00
/* out: error code */
2005-10-27 09:29:40 +02:00
THD * thd , /* in: handle to the user thread */
2006-02-21 13:37:54 +01:00
int lock_type ) /* in: lock type */
2005-10-27 09:29:40 +02:00
{
trx_t * trx ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " ha_innobase::transactional_table_lock " ) ;
2005-10-27 09:29:40 +02:00
DBUG_PRINT ( " enter " , ( " lock_type: %d " , lock_type ) ) ;
/* We do not know if MySQL can call this function before calling
external_lock ( ) . To be safe , update the thd of the current table
handle . */
update_thd ( thd ) ;
2007-05-10 13:31:36 +02:00
if ( prebuilt - > table - > ibd_file_missing & & ! thd_tablespace_op ( thd ) ) {
2006-02-21 13:37:54 +01:00
ut_print_timestamp ( stderr ) ;
2007-10-24 13:35:23 +02:00
fprintf ( stderr ,
" InnoDB: MySQL is trying to use a table handle "
" but the .ibd file for \n "
" InnoDB: table %s does not exist. \n "
" InnoDB: Have you deleted the .ibd file "
" from the database directory under \n "
" InnoDB: the MySQL datadir? "
" InnoDB: See "
" http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html \n "
" InnoDB: how you can resolve the problem. \n " ,
prebuilt - > table - > name ) ;
2005-10-27 09:29:40 +02:00
DBUG_RETURN ( HA_ERR_CRASHED ) ;
}
trx = prebuilt - > trx ;
prebuilt - > sql_stat_start = TRUE ;
prebuilt - > hint_need_to_fetch_extra_cols = 0 ;
2007-05-14 13:08:44 +02:00
reset_template ( prebuilt ) ;
2005-10-27 09:29:40 +02:00
if ( lock_type = = F_WRLCK ) {
prebuilt - > select_lock_type = LOCK_X ;
prebuilt - > stored_select_lock_type = LOCK_X ;
} else if ( lock_type = = F_RDLCK ) {
prebuilt - > select_lock_type = LOCK_S ;
prebuilt - > stored_select_lock_type = LOCK_S ;
} else {
2006-02-21 13:37:54 +01:00
ut_print_timestamp ( stderr ) ;
fprintf ( stderr , " InnoDB error: \n "
2005-10-27 09:29:40 +02:00
" MySQL is trying to set transactional table lock with corrupted lock type \n "
" to table %s, lock type %d does not exist. \n " ,
prebuilt - > table - > name , lock_type ) ;
DBUG_RETURN ( HA_ERR_CRASHED ) ;
}
/* MySQL is setting a new transactional table lock */
/* Set the MySQL flag to mark that there is an active transaction */
2006-02-21 13:37:54 +01:00
if ( trx - > active_trans = = 0 ) {
2005-10-27 09:29:40 +02:00
2006-10-03 14:46:23 +02:00
innobase_register_trx_and_stmt ( ht , thd ) ;
2006-02-21 13:37:54 +01:00
trx - > active_trans = 1 ;
}
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
if ( THDVAR ( thd , table_locks ) & & thd_in_lock_tables ( thd ) ) {
2005-10-27 09:29:40 +02:00
ulint error = DB_SUCCESS ;
error = row_lock_table_for_mysql ( prebuilt , NULL , 0 ) ;
if ( error ! = DB_SUCCESS ) {
2007-05-10 13:31:36 +02:00
error = convert_error_code_to_mysql ( ( int ) error , thd ) ;
2005-10-27 09:29:40 +02:00
DBUG_RETURN ( ( int ) error ) ;
}
2007-05-10 13:31:36 +02:00
if ( thd_test_options ( thd , OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN ) ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* Store the current undo_no of the transaction
so that we know where to roll back if we have
2005-10-27 09:29:40 +02:00
to roll back the next SQL statement */
trx_mark_sql_stat_end ( trx ) ;
}
}
DBUG_RETURN ( 0 ) ;
}
/****************************************************************************
Here we export InnoDB status variables to MySQL . */
2007-03-27 10:22:27 +02:00
static
2005-10-27 09:51:34 +02:00
int
2006-01-27 11:17:02 +01:00
innodb_export_status ( )
/*==================*/
2005-10-27 09:29:40 +02:00
{
2006-02-21 13:37:54 +01:00
if ( innodb_inited ) {
srv_export_innodb_status ( ) ;
}
return 0 ;
2005-10-27 09:29:40 +02:00
}
/****************************************************************************
Implements the SHOW INNODB STATUS command . Sends the output of the InnoDB
Monitor to the client . */
2007-02-12 14:08:02 +01:00
static
2005-10-27 09:29:40 +02:00
bool
innodb_show_status (
/*===============*/
2006-10-03 14:46:23 +02:00
handlerton * hton , /* in: the innodb handlerton */
2005-10-27 09:51:34 +02:00
THD * thd , /* in: the MySQL query thread of the caller */
stat_print_fn * stat_print )
2005-10-27 09:29:40 +02:00
{
trx_t * trx ;
static const char truncated_msg [ ] = " ... truncated... \n " ;
const long MAX_STATUS_SIZE = 64000 ;
ulint trx_list_start = ULINT_UNDEFINED ;
ulint trx_list_end = ULINT_UNDEFINED ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " innodb_show_status " ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 14:09:03 +02:00
trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
innobase_release_stat_resources ( trx ) ;
/* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
bytes of text . */
long flen , usable_len ;
char * str ;
mutex_enter_noninline ( & srv_monitor_file_mutex ) ;
rewind ( srv_monitor_file ) ;
2009-12-17 05:54:24 +01:00
srv_printf_innodb_monitor ( srv_monitor_file , FALSE ,
& trx_list_start , & trx_list_end ) ;
2005-10-27 09:29:40 +02:00
flen = ftell ( srv_monitor_file ) ;
os_file_set_eof ( srv_monitor_file ) ;
if ( flen < 0 ) {
flen = 0 ;
}
if ( flen > MAX_STATUS_SIZE ) {
usable_len = MAX_STATUS_SIZE ;
} else {
usable_len = flen ;
}
/* allocate buffer for the string, and
read the contents of the temporary file */
2007-06-04 10:45:27 +02:00
if ( ! ( str = ( char * ) my_malloc ( usable_len + 1 , MYF ( 0 ) ) ) ) {
2006-02-21 13:37:54 +01:00
mutex_exit_noninline ( & srv_monitor_file_mutex ) ;
DBUG_RETURN ( TRUE ) ;
}
2005-10-27 09:29:40 +02:00
rewind ( srv_monitor_file ) ;
if ( flen < MAX_STATUS_SIZE ) {
/* Display the entire output. */
flen = ( long ) fread ( str , 1 , flen , srv_monitor_file ) ;
} else if ( trx_list_end < ( ulint ) flen
& & trx_list_start < trx_list_end
& & trx_list_start + ( flen - trx_list_end )
< MAX_STATUS_SIZE - sizeof truncated_msg - 1 ) {
/* Omit the beginning of the list of active transactions. */
long len = ( long ) fread ( str , 1 , trx_list_start , srv_monitor_file ) ;
memcpy ( str + len , truncated_msg , sizeof truncated_msg - 1 ) ;
len + = sizeof truncated_msg - 1 ;
usable_len = ( MAX_STATUS_SIZE - 1 ) - len ;
fseek ( srv_monitor_file , flen - usable_len , SEEK_SET ) ;
len + = ( long ) fread ( str + len , 1 , usable_len , srv_monitor_file ) ;
flen = len ;
} else {
/* Omit the end of the output. */
flen = ( long ) fread ( str , 1 , MAX_STATUS_SIZE - 1 , srv_monitor_file ) ;
}
mutex_exit_noninline ( & srv_monitor_file_mutex ) ;
2005-10-27 09:51:34 +02:00
bool result = FALSE ;
2005-10-27 09:29:40 +02:00
2009-04-17 22:32:08 +02:00
if ( stat_print ( thd , innobase_hton_name , ( uint ) strlen ( innobase_hton_name ) ,
2006-02-21 13:37:54 +01:00
STRING_WITH_LEN ( " " ) , str , flen ) ) {
2005-10-27 09:51:34 +02:00
result = TRUE ;
2005-10-27 09:29:40 +02:00
}
2005-10-27 09:51:34 +02:00
my_free ( str , MYF ( 0 ) ) ;
2005-10-27 09:29:40 +02:00
2005-10-27 09:51:34 +02:00
DBUG_RETURN ( FALSE ) ;
2005-10-27 09:29:40 +02:00
}
/****************************************************************************
Implements the SHOW MUTEX STATUS command . . */
2007-03-27 10:22:27 +02:00
static
2005-10-27 09:29:40 +02:00
bool
innodb_mutex_show_status (
2006-02-20 13:12:22 +01:00
/*=====================*/
2006-10-03 14:46:23 +02:00
handlerton * hton , /* in: the innodb handlerton */
2006-02-21 13:37:54 +01:00
THD * thd , /* in: the MySQL query thread of the
caller */
stat_print_fn * stat_print )
{
char buf1 [ IO_SIZE ] , buf2 [ IO_SIZE ] ;
mutex_t * mutex ;
2006-11-21 14:56:18 +01:00
# ifdef UNIV_DEBUG
2006-02-21 13:37:54 +01:00
ulint rw_lock_count = 0 ;
ulint rw_lock_count_spin_loop = 0 ;
ulint rw_lock_count_spin_rounds = 0 ;
ulint rw_lock_count_os_wait = 0 ;
ulint rw_lock_count_os_yield = 0 ;
ulonglong rw_lock_wait_time = 0 ;
2006-11-21 14:56:18 +01:00
# endif /* UNIV_DEBUG */
2009-04-17 22:32:08 +02:00
uint hton_name_len = ( uint ) strlen ( innobase_hton_name ) , buf1len , buf2len ;
2006-02-21 13:37:54 +01:00
DBUG_ENTER ( " innodb_mutex_show_status " ) ;
2005-10-27 09:29:40 +02:00
2006-11-21 14:56:18 +01:00
mutex_enter_noninline ( & mutex_list_mutex ) ;
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
mutex = UT_LIST_GET_FIRST ( mutex_list ) ;
while ( mutex ! = NULL ) {
2006-11-21 14:56:18 +01:00
# ifdef UNIV_DEBUG
2006-02-21 13:37:54 +01:00
if ( mutex - > mutex_type ! = 1 ) {
if ( mutex - > count_using > 0 ) {
buf1len = my_snprintf ( buf1 , sizeof ( buf1 ) ,
" %s:%s " ,
mutex - > cmutex_name , mutex - > cfile_name ) ;
buf2len = my_snprintf ( buf2 , sizeof ( buf2 ) ,
" count=%lu, spin_waits=%lu, "
" spin_rounds=%lu, "
" os_waits=%lu, os_yields=%lu, "
" os_wait_times=%lu " ,
mutex - > count_using ,
mutex - > count_spin_loop ,
mutex - > count_spin_rounds ,
mutex - > count_os_wait ,
mutex - > count_os_yield ,
2007-02-02 12:14:02 +01:00
( ulong ) ( mutex - > lspent_time / 1000 ) ) ;
2006-02-21 13:37:54 +01:00
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
if ( stat_print ( thd , innobase_hton_name ,
2006-02-21 13:37:54 +01:00
hton_name_len , buf1 , buf1len ,
buf2 , buf2len ) ) {
2006-11-21 14:56:18 +01:00
mutex_exit_noninline (
& mutex_list_mutex ) ;
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( 1 ) ;
}
}
}
else {
rw_lock_count + = mutex - > count_using ;
rw_lock_count_spin_loop + = mutex - > count_spin_loop ;
rw_lock_count_spin_rounds + = mutex - > count_spin_rounds ;
rw_lock_count_os_wait + = mutex - > count_os_wait ;
rw_lock_count_os_yield + = mutex - > count_os_yield ;
rw_lock_wait_time + = mutex - > lspent_time ;
}
2006-11-21 14:56:18 +01:00
# else /* UNIV_DEBUG */
2009-04-17 22:32:08 +02:00
buf1len = ( uint ) my_snprintf ( buf1 , sizeof ( buf1 ) , " %s:%lu " ,
2006-11-21 14:56:18 +01:00
mutex - > cfile_name , ( ulong ) mutex - > cline ) ;
2009-04-17 22:32:08 +02:00
buf2len = ( uint ) my_snprintf ( buf2 , sizeof ( buf2 ) , " os_waits=%lu " ,
2006-11-21 14:56:18 +01:00
mutex - > count_os_wait ) ;
if ( stat_print ( thd , innobase_hton_name ,
hton_name_len , buf1 , buf1len ,
buf2 , buf2len ) ) {
mutex_exit_noninline ( & mutex_list_mutex ) ;
DBUG_RETURN ( 1 ) ;
}
# endif /* UNIV_DEBUG */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
mutex = UT_LIST_GET_NEXT ( list , mutex ) ;
}
2006-11-21 14:56:18 +01:00
mutex_exit_noninline ( & mutex_list_mutex ) ;
# ifdef UNIV_DEBUG
2006-02-21 13:37:54 +01:00
buf2len = my_snprintf ( buf2 , sizeof ( buf2 ) ,
" count=%lu, spin_waits=%lu, spin_rounds=%lu, "
" os_waits=%lu, os_yields=%lu, os_wait_times=%lu " ,
rw_lock_count , rw_lock_count_spin_loop ,
rw_lock_count_spin_rounds ,
rw_lock_count_os_wait , rw_lock_count_os_yield ,
2007-02-02 12:14:02 +01:00
( ulong ) ( rw_lock_wait_time / 1000 ) ) ;
2006-02-21 13:37:54 +01:00
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
if ( stat_print ( thd , innobase_hton_name , hton_name_len ,
2006-02-21 13:37:54 +01:00
STRING_WITH_LEN ( " rw_lock_mutexes " ) , buf2 , buf2len ) ) {
DBUG_RETURN ( 1 ) ;
}
2006-11-21 14:56:18 +01:00
# endif /* UNIV_DEBUG */
2006-02-21 13:37:54 +01:00
DBUG_RETURN ( FALSE ) ;
2005-10-27 09:29:40 +02:00
}
2007-02-12 14:08:02 +01:00
static
2006-10-03 14:46:23 +02:00
bool innobase_show_status ( handlerton * hton , THD * thd ,
stat_print_fn * stat_print ,
enum ha_stat_type stat_type )
2006-02-21 13:37:54 +01:00
{
switch ( stat_type ) {
case HA_ENGINE_STATUS :
2006-10-03 14:46:23 +02:00
return innodb_show_status ( hton , thd , stat_print ) ;
2006-02-21 13:37:54 +01:00
case HA_ENGINE_MUTEX :
2006-10-03 14:46:23 +02:00
return innodb_mutex_show_status ( hton , thd , stat_print ) ;
2006-02-21 13:37:54 +01:00
default :
return FALSE ;
}
2005-10-27 09:51:34 +02:00
}
2005-10-27 09:29:40 +02:00
/****************************************************************************
Handling the shared INNOBASE_SHARE structure that is needed to provide table
locking .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-08-15 14:29:46 +02:00
static uchar * innobase_get_key ( INNOBASE_SHARE * share , size_t * length ,
2006-02-21 13:37:54 +01:00
my_bool not_used __attribute__ ( ( unused ) ) )
{
* length = share - > table_name_length ;
2007-08-15 14:29:46 +02:00
return ( uchar * ) share - > table_name ;
2005-10-27 09:29:40 +02:00
}
2006-02-21 13:37:54 +01:00
static INNOBASE_SHARE * get_share ( const char * table_name )
2005-10-27 09:29:40 +02:00
{
2006-02-21 13:37:54 +01:00
INNOBASE_SHARE * share ;
pthread_mutex_lock ( & innobase_share_mutex ) ;
uint length = ( uint ) strlen ( table_name ) ;
if ( ! ( share = ( INNOBASE_SHARE * ) hash_search ( & innobase_open_tables ,
2007-08-15 14:29:46 +02:00
( uchar * ) table_name ,
2006-02-21 13:37:54 +01:00
length ) ) ) {
2006-02-22 13:48:49 +01:00
share = ( INNOBASE_SHARE * ) my_malloc ( sizeof ( * share ) + length + 1 ,
MYF ( MY_FAE | MY_ZEROFILL ) ) ;
2006-02-24 10:41:20 +01:00
2006-02-22 13:48:49 +01:00
share - > table_name_length = length ;
share - > table_name = ( char * ) ( share + 1 ) ;
strmov ( share - > table_name , table_name ) ;
if ( my_hash_insert ( & innobase_open_tables ,
2007-08-15 14:29:46 +02:00
( uchar * ) share ) ) {
2006-02-22 13:48:49 +01:00
pthread_mutex_unlock ( & innobase_share_mutex ) ;
2007-06-04 10:45:27 +02:00
my_free ( share , 0 ) ;
2006-02-22 13:48:49 +01:00
return 0 ;
2006-02-21 13:37:54 +01:00
}
2006-02-22 13:48:49 +01:00
thr_lock_init ( & share - > lock ) ;
pthread_mutex_init ( & share - > mutex , MY_MUTEX_INIT_FAST ) ;
2006-02-21 13:37:54 +01:00
}
share - > use_count + + ;
pthread_mutex_unlock ( & innobase_share_mutex ) ;
return share ;
}
static void free_share ( INNOBASE_SHARE * share )
{
pthread_mutex_lock ( & innobase_share_mutex ) ;
if ( ! - - share - > use_count ) {
2007-08-15 14:29:46 +02:00
hash_delete ( & innobase_open_tables , ( uchar * ) share ) ;
2006-02-21 13:37:54 +01:00
thr_lock_delete ( & share - > lock ) ;
pthread_mutex_destroy ( & share - > mutex ) ;
2007-06-04 10:45:27 +02:00
my_free ( share , MYF ( 0 ) ) ;
2006-02-21 13:37:54 +01:00
}
pthread_mutex_unlock ( & innobase_share_mutex ) ;
2005-10-27 09:29:40 +02:00
}
/*********************************************************************
Converts a MySQL table lock stored in the ' lock ' field of the handle to
a proper type before storing pointer to the lock into an array of pointers .
MySQL also calls this if it wants to reset some table locks to a not - locked
state during the processing of an SQL query . An example is that during a
SELECT the read lock is released early on the ' const ' tables where we only
fetch one row . MySQL does not call this when it releases all locks at the
end of an SQL statement . */
THR_LOCK_DATA * *
ha_innobase : : store_lock (
/*====================*/
/* out: pointer to the next
element in the ' to ' array */
THD * thd , /* in: user thread handle */
THR_LOCK_DATA * * to , /* in: pointer to an array
of pointers to lock structs ;
pointer to the ' lock ' field
of current handle is stored
next to this array */
2006-02-21 13:37:54 +01:00
enum thr_lock_type lock_type ) /* in: lock type to store in
2005-10-27 09:29:40 +02:00
' lock ' ; this may also be
TL_IGNORE */
{
2006-08-07 17:18:22 +02:00
trx_t * trx ;
2006-08-31 21:52:25 +02:00
/* Note that trx in this function is NOT necessarily prebuilt->trx
because we call update_thd ( ) later , in : : external_lock ( ) ! Failure to
understand this caused a serious memory corruption bug in 5.1 .11 . */
2006-08-07 17:18:22 +02:00
2007-05-10 14:09:03 +02:00
trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
2006-08-31 21:52:25 +02:00
/* NOTE: MySQL can call this function with lock 'type' TL_IGNORE!
2005-10-27 09:29:40 +02:00
Be careful to ignore TL_IGNORE if we are going to do something with
only ' real ' locks ! */
2006-08-31 21:52:25 +02:00
/* If no MySQL table is in use, we need to set the isolation level
2006-03-27 07:33:30 +02:00
of the transaction . */
if ( lock_type ! = TL_IGNORE
2007-05-10 13:31:36 +02:00
& & trx - > n_mysql_tables_in_use = = 0 ) {
2006-03-27 07:33:30 +02:00
trx - > isolation_level = innobase_map_isolation_level (
2007-05-10 13:31:36 +02:00
( enum_tx_isolation ) thd_tx_isolation ( thd ) ) ;
2007-03-05 01:37:57 +01:00
if ( trx - > isolation_level < = TRX_ISO_READ_COMMITTED
& & trx - > global_read_view ) {
/* At low transaction isolation levels we let
each consistent read set its own snapshot */
read_view_close_for_mysql ( trx ) ;
}
2006-03-27 07:33:30 +02:00
}
2007-05-10 13:31:36 +02:00
DBUG_ASSERT ( thd = = current_thd ) ;
2007-02-15 15:09:49 +01:00
const bool in_lock_tables = thd_in_lock_tables ( thd ) ;
2007-05-10 13:31:36 +02:00
const uint sql_command = thd_sql_command ( thd ) ;
2007-02-15 15:09:49 +01:00
2007-05-10 13:31:36 +02:00
if ( sql_command = = SQLCOM_DROP_TABLE ) {
2006-08-31 21:52:25 +02:00
/* MySQL calls this function in DROP TABLE though this table
handle may belong to another thd that is running a query . Let
us in that case skip any changes to the prebuilt struct . * /
2007-05-10 13:31:36 +02:00
} else if ( ( lock_type = = TL_READ & & in_lock_tables )
| | ( lock_type = = TL_READ_HIGH_PRIORITY & & in_lock_tables )
| | lock_type = = TL_READ_WITH_SHARED_LOCKS
| | lock_type = = TL_READ_NO_INSERT
| | ( lock_type ! = TL_IGNORE
& & sql_command ! = SQLCOM_SELECT ) ) {
2005-10-27 09:29:40 +02:00
/* The OR cases above are in this order:
2006-10-16 14:19:36 +02:00
1 ) MySQL is doing LOCK TABLES . . . READ LOCAL , or we
are processing a stored procedure or function , or
2005-10-27 09:29:40 +02:00
2 ) ( we do not know when TL_READ_HIGH_PRIORITY is used ) , or
3 ) this is a SELECT . . . IN SHARE MODE , or
4 ) we are doing a complex SQL statement like
INSERT INTO . . . SELECT . . . and the logical logging ( MySQL
binlog ) requires the use of a locking read , or
MySQL is doing LOCK TABLES . . . READ .
5 ) we let InnoDB do locking reads for all SQL statements that
are not simple SELECTs ; note that select_lock_type in this
case may get strengthened in : : external_lock ( ) to LOCK_X .
Note that we MUST use a locking read in all data modifying
SQL statements , because otherwise the execution would not be
serializable , and also the results from the update could be
unexpected if an obsolete consistent read view would be
used . */
2006-03-27 07:33:30 +02:00
ulint isolation_level ;
isolation_level = trx - > isolation_level ;
if ( ( srv_locks_unsafe_for_binlog
2007-05-10 13:31:36 +02:00
| | isolation_level = = TRX_ISO_READ_COMMITTED )
& & isolation_level ! = TRX_ISO_SERIALIZABLE
& & ( lock_type = = TL_READ | | lock_type = = TL_READ_NO_INSERT )
& & ( sql_command = = SQLCOM_INSERT_SELECT
| | sql_command = = SQLCOM_UPDATE
| | sql_command = = SQLCOM_CREATE_TABLE ) ) {
2005-10-27 09:29:40 +02:00
2006-03-27 07:33:30 +02:00
/* If we either have innobase_locks_unsafe_for_binlog
option set or this session is using READ COMMITTED
isolation level and isolation level of the transaction
2005-10-27 09:29:40 +02:00
is not set to serializable and MySQL is doing
2006-03-21 11:00:30 +01:00
INSERT INTO . . . SELECT or UPDATE . . . = ( SELECT . . . ) or
CREATE . . . SELECT . . . without FOR UPDATE or
IN SHARE MODE in select , then we use consistent
read for select . */
2005-10-27 09:29:40 +02:00
prebuilt - > select_lock_type = LOCK_NONE ;
prebuilt - > stored_select_lock_type = LOCK_NONE ;
2007-05-10 13:31:36 +02:00
} else if ( sql_command = = SQLCOM_CHECKSUM ) {
2005-10-27 09:29:40 +02:00
/* Use consistent read for checksum table */
prebuilt - > select_lock_type = LOCK_NONE ;
prebuilt - > stored_select_lock_type = LOCK_NONE ;
} else {
prebuilt - > select_lock_type = LOCK_S ;
prebuilt - > stored_select_lock_type = LOCK_S ;
}
} else if ( lock_type ! = TL_IGNORE ) {
2006-01-12 10:16:11 +01:00
/* We set possible LOCK_X value in external_lock, not yet
2005-10-27 09:29:40 +02:00
here even if this would be SELECT . . . FOR UPDATE */
prebuilt - > select_lock_type = LOCK_NONE ;
prebuilt - > stored_select_lock_type = LOCK_NONE ;
}
if ( lock_type ! = TL_IGNORE & & lock . type = = TL_UNLOCK ) {
2006-01-12 10:16:11 +01:00
/* Starting from 5.0.7, we weaken also the table locks
2005-10-27 09:29:40 +02:00
set at the start of a MySQL stored procedure call , just like
we weaken the locks set at the start of an SQL statement .
2007-02-15 15:09:49 +01:00
MySQL does set in_lock_tables TRUE there , but in reality
2005-10-27 09:29:40 +02:00
we do not need table locks to make the execution of a
single transaction stored procedure call deterministic
( if it does not use a consistent read ) . */
2006-10-16 14:19:36 +02:00
if ( lock_type = = TL_READ
2007-05-10 13:31:36 +02:00
& & sql_command = = SQLCOM_LOCK_TABLES ) {
2005-10-27 09:29:40 +02:00
/* We come here if MySQL is processing LOCK TABLES
. . . READ LOCAL . MyISAM under that table lock type
reads the table as it was at the time the lock was
granted ( new inserts are allowed , but not seen by the
reader ) . To get a similar effect on an InnoDB table ,
we must use LOCK TABLES . . . READ . We convert the lock
type here , so that for InnoDB , READ LOCAL is
equivalent to READ . This will change the InnoDB
behavior in mysqldump , so that dumps of InnoDB tables
are consistent with dumps of MyISAM tables . */
lock_type = TL_READ_NO_INSERT ;
}
2006-01-12 10:16:11 +01:00
/* If we are not doing a LOCK TABLE, DISCARD/IMPORT
2006-02-21 13:37:54 +01:00
TABLESPACE or TRUNCATE TABLE then allow multiple
2006-01-12 10:16:11 +01:00
writers . Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
< TL_WRITE_CONCURRENT_INSERT .
2006-02-21 13:37:54 +01:00
We especially allow multiple writers if MySQL is at the
2006-03-13 10:51:38 +01:00
start of a stored procedure call ( SQLCOM_CALL ) or a
2007-02-15 15:09:49 +01:00
stored function call ( MySQL does have in_lock_tables
2006-03-13 10:51:38 +01:00
TRUE there ) . */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
if ( ( lock_type > = TL_WRITE_CONCURRENT_INSERT
2007-05-10 13:31:36 +02:00
& & lock_type < = TL_WRITE )
& & ! ( in_lock_tables
& & sql_command = = SQLCOM_LOCK_TABLES )
& & ! thd_tablespace_op ( thd )
& & sql_command ! = SQLCOM_TRUNCATE
& & sql_command ! = SQLCOM_OPTIMIZE
& & sql_command ! = SQLCOM_CREATE_TABLE ) {
2005-10-27 09:29:40 +02:00
2006-01-12 10:16:11 +01:00
lock_type = TL_WRITE_ALLOW_WRITE ;
2006-02-21 13:37:54 +01:00
}
2005-10-27 09:29:40 +02:00
/* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
MySQL would use the lock TL_READ_NO_INSERT on t2 , and that
would conflict with TL_WRITE_ALLOW_WRITE , blocking all inserts
to t2 . Convert the lock to a normal read lock to allow
2006-02-21 13:37:54 +01:00
concurrent inserts to t2 .
2006-01-12 10:16:11 +01:00
2006-02-21 13:37:54 +01:00
We especially allow concurrent inserts if MySQL is at the
start of a stored procedure call ( SQLCOM_CALL )
2007-05-10 13:31:36 +02:00
( MySQL does have thd_in_lock_tables ( ) TRUE there ) . */
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
if ( lock_type = = TL_READ_NO_INSERT
2007-05-10 13:31:36 +02:00
& & sql_command ! = SQLCOM_LOCK_TABLES ) {
2005-10-27 09:29:40 +02:00
lock_type = TL_READ ;
}
2006-02-21 13:37:54 +01:00
2006-01-12 10:16:11 +01:00
lock . type = lock_type ;
}
2005-10-27 09:29:40 +02:00
2006-01-12 10:16:11 +01:00
* to + + = & lock ;
2005-10-27 09:29:40 +02:00
return ( to ) ;
}
2008-10-23 06:30:32 +02:00
/*******************************************************************************
Read the next autoinc value . Acquire the relevant locks before reading
the AUTOINC value . If SUCCESS then the table AUTOINC mutex will be locked
on return and all relevant locks acquired . */
2005-10-27 09:29:40 +02:00
2008-10-23 06:30:32 +02:00
ulong
ha_innobase : : innobase_get_autoinc (
/*==============================*/
/* out: DB_SUCCESS or error code */
ulonglong * value ) /* out: autoinc value */
2005-10-27 09:29:40 +02:00
{
2008-10-23 06:30:32 +02:00
* value = 0 ;
prebuilt - > autoinc_error = innobase_lock_autoinc ( ) ;
2005-10-27 09:29:40 +02:00
2008-10-23 06:30:32 +02:00
if ( prebuilt - > autoinc_error = = DB_SUCCESS ) {
2005-10-27 09:29:40 +02:00
2008-10-23 06:30:32 +02:00
/* Determine the first value of the interval */
* value = dict_table_autoinc_read ( prebuilt - > table ) ;
2005-10-27 09:29:40 +02:00
2008-10-23 06:30:32 +02:00
/* It should have been initialized during open. */
2010-01-29 23:35:00 +01:00
if ( * value = = 0 ) {
prebuilt - > autoinc_error = DB_UNSUPPORTED ;
dict_table_autoinc_unlock ( prebuilt - > table ) ;
}
2005-10-27 09:29:40 +02:00
}
2008-10-23 06:30:32 +02:00
return ( ulong ( prebuilt - > autoinc_error ) ) ;
2007-07-24 03:42:16 +02:00
}
2008-10-23 06:30:32 +02:00
/***********************************************************************
This function reads the global auto - inc counter . It doesn ' t use the
AUTOINC lock even if the lock mode is set to TRADITIONAL . */
2007-07-24 03:42:16 +02:00
2008-10-23 06:30:32 +02:00
ulonglong
ha_innobase : : innobase_peek_autoinc ( )
/*================================*/
/* out: the autoinc value */
2007-07-24 03:42:16 +02:00
{
2008-10-23 06:30:32 +02:00
ulonglong auto_inc ;
dict_table_t * innodb_table ;
2007-07-24 03:42:16 +02:00
2008-10-23 06:30:32 +02:00
ut_a ( prebuilt ! = NULL ) ;
ut_a ( prebuilt - > table ! = NULL ) ;
2007-07-24 03:42:16 +02:00
2008-10-23 06:30:32 +02:00
innodb_table = prebuilt - > table ;
2007-07-24 03:42:16 +02:00
2008-10-23 06:30:32 +02:00
dict_table_autoinc_lock ( innodb_table ) ;
2007-07-24 03:42:16 +02:00
2008-10-23 06:30:32 +02:00
auto_inc = dict_table_autoinc_read ( innodb_table ) ;
2007-07-24 03:42:16 +02:00
2008-10-23 06:30:32 +02:00
ut_a ( auto_inc > 0 ) ;
2007-07-24 03:42:16 +02:00
2008-10-23 06:30:32 +02:00
dict_table_autoinc_unlock ( innodb_table ) ;
return ( auto_inc ) ;
2005-10-27 09:29:40 +02:00
}
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
/*******************************************************************************
2005-10-27 09:29:40 +02:00
This function initializes the auto - inc counter if it has not been
initialized yet . This function does not change the value of the auto - inc
counter if it already has been initialized . Returns the value of the
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
auto - inc counter in * first_value , and ULONGLONG_MAX in * nb_reserved_values ( as
we have a table - level lock ) . offset , increment , nb_desired_values are ignored .
* first_value is set to - 1 if error ( deadlock or lock wait timeout ) */
2005-10-27 09:29:40 +02:00
2007-07-24 03:42:16 +02:00
void
ha_innobase : : get_auto_increment (
2007-09-10 22:26:01 +02:00
/*============================*/
2007-07-24 03:42:16 +02:00
ulonglong offset , /* in: */
ulonglong increment , /* in: table autoinc increment */
ulonglong nb_desired_values , /* in: number of values reqd */
ulonglong * first_value , /* out: the autoinc value */
ulonglong * nb_reserved_values ) /* out: count of reserved values */
2005-10-27 09:29:40 +02:00
{
2007-09-08 22:40:10 +02:00
trx_t * trx ;
2007-07-24 03:42:16 +02:00
ulint error ;
ulonglong autoinc = 0 ;
2006-02-21 13:37:54 +01:00
2006-08-07 17:23:32 +02:00
/* Prepare prebuilt->trx in the table handle */
2007-05-10 13:31:36 +02:00
update_thd ( ha_thd ( ) ) ;
2006-08-07 17:23:32 +02:00
2008-10-23 06:30:32 +02:00
error = innobase_get_autoinc ( & autoinc ) ;
2005-10-27 09:29:40 +02:00
2007-07-24 03:42:16 +02:00
if ( error ! = DB_SUCCESS ) {
* first_value = ( ~ ( ulonglong ) 0 ) ;
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
return ;
2005-10-27 09:29:40 +02:00
}
2007-07-24 03:42:16 +02:00
/* This is a hack, since nb_desired_values seems to be accurate only
for the first call to get_auto_increment ( ) for multi - row INSERT and
meaningless for other statements e . g , LOAD etc . Subsequent calls to
this method for the same statement results in different values which
don ' t make sense . Therefore we store the value the first time we are
called and count down from that as rows are written ( see write_row ( ) ) .
2007-09-08 22:40:10 +02:00
*/
2007-07-24 03:42:16 +02:00
2007-09-08 22:40:10 +02:00
trx = prebuilt - > trx ;
2007-07-24 03:42:16 +02:00
2007-11-30 12:41:22 +01:00
/* Note: We can't rely on *first_value since some MySQL engines,
in particular the partition engine , don ' t initialize it to 0 when
invoking this method . So we are not sure if it ' s guaranteed to
be 0 or not . */
2010-01-29 23:43:06 +01:00
/* We need the upper limit of the col type to check for
whether we update the table autoinc counter or not . */
ulonglong col_max_value = innobase_get_int_col_max_value (
table - > next_number_field ) ;
2007-09-08 22:40:10 +02:00
/* Called for the first time ? */
if ( trx - > n_autoinc_rows = = 0 ) {
2007-07-24 03:42:16 +02:00
2007-11-30 10:44:34 +01:00
trx - > n_autoinc_rows = ( ulint ) nb_desired_values ;
2007-07-24 03:42:16 +02:00
2007-09-08 22:40:10 +02:00
/* It's possible for nb_desired_values to be 0:
e . g . , INSERT INTO T1 ( C ) SELECT C FROM T2 ; */
if ( nb_desired_values = = 0 ) {
trx - > n_autoinc_rows = 1 ;
2007-07-24 03:42:16 +02:00
}
2007-11-30 10:40:20 +01:00
set_if_bigger ( * first_value , autoinc ) ;
2007-09-08 22:40:10 +02:00
/* Not in the middle of a mult-row INSERT. */
2008-10-04 00:48:04 +02:00
} else if ( prebuilt - > autoinc_last_value = = 0 ) {
2007-11-30 10:40:20 +01:00
set_if_bigger ( * first_value , autoinc ) ;
2010-01-29 23:43:06 +01:00
/* Check for -ve values. */
} else if ( * first_value > col_max_value & & trx - > n_autoinc_rows > 0 ) {
/* Set to next logical value. */
ut_a ( autoinc > trx - > n_autoinc_rows ) ;
* first_value = ( autoinc - trx - > n_autoinc_rows ) - 1 ;
2007-07-24 03:42:16 +02:00
}
2007-09-08 22:40:10 +02:00
* nb_reserved_values = trx - > n_autoinc_rows ;
2007-07-24 03:42:16 +02:00
2007-08-20 23:48:16 +02:00
/* With old style AUTOINC locking we only update the table's
AUTOINC counter after attempting to insert the row . */
if ( innobase_autoinc_lock_mode ! = AUTOINC_OLD_STYLE_LOCKING ) {
2008-03-05 21:23:39 +01:00
ulonglong need ;
2009-10-12 05:05:00 +02:00
ulonglong current ;
2008-10-04 00:48:04 +02:00
ulonglong next_value ;
2008-03-05 21:23:39 +01:00
2009-10-12 05:05:00 +02:00
current = * first_value > col_max_value ? autoinc : * first_value ;
2008-03-05 21:23:39 +01:00
need = * nb_reserved_values * increment ;
2007-07-24 03:42:16 +02:00
2007-08-20 23:48:16 +02:00
/* Compute the last value in the interval */
2008-10-22 23:42:24 +02:00
next_value = innobase_next_autoinc (
2009-10-12 05:05:00 +02:00
current , need , offset , col_max_value ) ;
2008-10-04 00:48:04 +02:00
prebuilt - > autoinc_last_value = next_value ;
2007-07-24 03:42:16 +02:00
2009-03-02 01:28:52 +01:00
if ( prebuilt - > autoinc_last_value < * first_value ) {
* first_value = ( ~ ( ulonglong ) 0 ) ;
} else {
/* Update the table autoinc variable */
dict_table_autoinc_update_if_greater (
prebuilt - > table , prebuilt - > autoinc_last_value ) ;
}
2007-08-20 23:48:16 +02:00
} else {
/* This will force write_row() into attempting an update
of the table ' s AUTOINC counter . */
2008-10-04 00:48:04 +02:00
prebuilt - > autoinc_last_value = 0 ;
2007-08-20 23:48:16 +02:00
}
2007-07-24 03:42:16 +02:00
/* The increment to be used to increase the AUTOINC value, we use
this in write_row ( ) and update_row ( ) to increase the autoinc counter
2008-10-04 00:48:04 +02:00
for columns that are filled by the user . We need the offset and
the increment . */
prebuilt - > autoinc_offset = offset ;
prebuilt - > autoinc_increment = increment ;
2007-07-24 03:42:16 +02:00
dict_table_autoinc_unlock ( prebuilt - > table ) ;
2005-10-27 09:29:40 +02:00
}
/* See comment in handler.h */
int
2007-09-10 22:26:01 +02:00
ha_innobase : : reset_auto_increment (
/*==============================*/
ulonglong value ) /* in: new value for table autoinc */
2005-10-27 09:29:40 +02:00
{
DBUG_ENTER ( " ha_innobase::reset_auto_increment " ) ;
2007-01-11 15:24:53 +01:00
int error ;
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
update_thd ( ha_thd ( ) ) ;
2006-08-07 17:39:40 +02:00
2005-10-27 09:29:40 +02:00
error = row_lock_table_autoinc_for_mysql ( prebuilt ) ;
if ( error ! = DB_SUCCESS ) {
error = convert_error_code_to_mysql ( error , user_thd ) ;
DBUG_RETURN ( error ) ;
2006-02-21 13:37:54 +01:00
}
2005-10-27 09:29:40 +02:00
2008-10-23 06:30:32 +02:00
/* The next value can never be 0. */
if ( value = = 0 ) {
value = 1 ;
}
2007-07-24 03:42:16 +02:00
innobase_reset_autoinc ( value ) ;
2005-10-27 09:29:40 +02:00
DBUG_RETURN ( 0 ) ;
}
/* See comment in handler.cc */
bool
ha_innobase : : get_error_message ( int error , String * buf )
{
2007-05-10 14:09:03 +02:00
trx_t * trx = check_trx_exists ( ha_thd ( ) ) ;
2005-10-27 09:29:40 +02:00
2009-04-17 22:32:08 +02:00
buf - > copy ( trx - > detailed_error , ( uint ) strlen ( trx - > detailed_error ) ,
2005-10-27 09:29:40 +02:00
system_charset_info ) ;
return FALSE ;
}
/***********************************************************************
Compares two ' refs ' . A ' ref ' is the ( internal ) primary key value of the row .
If there is no explicitly declared non - null unique key or a primary key , then
InnoDB internally uses the row id as the primary key . */
int
ha_innobase : : cmp_ref (
/*=================*/
/* out: < 0 if ref1 < ref2, 0 if equal, else
> 0 */
2007-08-15 14:29:46 +02:00
const uchar * ref1 , /* in: an (internal) primary key value in the
2005-10-27 09:29:40 +02:00
MySQL key value format */
2007-08-15 14:29:46 +02:00
const uchar * ref2 ) /* in: an (internal) primary key value in the
2005-10-27 09:29:40 +02:00
MySQL key value format */
{
enum_field_types mysql_type ;
Field * field ;
KEY_PART_INFO * key_part ;
KEY_PART_INFO * key_part_end ;
uint len1 ;
uint len2 ;
2006-02-21 13:37:54 +01:00
int result ;
2005-10-27 09:29:40 +02:00
if ( prebuilt - > clust_index_was_generated ) {
/* The 'ref' is an InnoDB row id */
return ( memcmp ( ref1 , ref2 , DATA_ROW_ID_LEN ) ) ;
}
/* Do a type-aware comparison of primary key fields. PK fields
are always NOT NULL , so no checks for NULL are performed . */
key_part = table - > key_info [ table - > s - > primary_key ] . key_part ;
key_part_end = key_part
+ table - > key_info [ table - > s - > primary_key ] . key_parts ;
for ( ; key_part ! = key_part_end ; + + key_part ) {
field = key_part - > field ;
mysql_type = field - > type ( ) ;
2007-02-02 12:14:02 +01:00
if ( mysql_type = = MYSQL_TYPE_TINY_BLOB
| | mysql_type = = MYSQL_TYPE_MEDIUM_BLOB
| | mysql_type = = MYSQL_TYPE_BLOB
| | mysql_type = = MYSQL_TYPE_LONG_BLOB ) {
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
/* In the MySQL key value format, a column prefix of
a BLOB is preceded by a 2 - byte length field */
len1 = innobase_read_from_2_little_endian ( ref1 ) ;
len2 = innobase_read_from_2_little_endian ( ref2 ) ;
ref1 + = 2 ;
ref2 + = 2 ;
2007-06-04 10:45:27 +02:00
result = ( ( Field_blob * ) field ) - > cmp ( ref1 , len1 ,
ref2 , len2 ) ;
2005-10-27 09:29:40 +02:00
} else {
result = field - > key_cmp ( ref1 , ref2 ) ;
}
if ( result ) {
return ( result ) ;
}
ref1 + = key_part - > store_length ;
ref2 + = key_part - > store_length ;
}
return ( 0 ) ;
}
2007-03-21 11:02:00 +01:00
/***********************************************************************
Ask InnoDB if a query to a table can be cached . */
my_bool
ha_innobase : : register_query_cache_table (
/*====================================*/
/* out: TRUE if query caching
of the table is permitted */
THD * thd , /* in: user thread handle */
char * table_key , /* in: concatenation of database name,
the null character ' \0 ' ,
and the table name */
uint key_length , /* in: length of the full name, i.e.
len ( dbname ) + len ( tablename ) + 1 */
qc_engine_callback *
call_back , /* out: pointer to function for
checking if query caching
is permitted */
ulonglong * engine_data ) /* in/out: data to call_back */
{
* call_back = innobase_query_caching_of_table_permitted ;
* engine_data = 0 ;
return ( innobase_query_caching_of_table_permitted ( thd , table_key ,
key_length ,
engine_data ) ) ;
}
2005-10-27 09:29:40 +02:00
char *
ha_innobase : : get_mysql_bin_log_name ( )
{
return ( trx_sys_mysql_bin_log_name ) ;
}
ulonglong
ha_innobase : : get_mysql_bin_log_pos ( )
{
2006-02-21 13:37:54 +01:00
/* trx... is ib_longlong, which is a typedef for a 64-bit integer
2005-10-27 09:29:40 +02:00
( __int64 or longlong ) so it ' s ok to cast it to ulonglong . */
2006-02-21 13:37:54 +01:00
return ( trx_sys_mysql_bin_log_pos ) ;
2005-10-27 09:29:40 +02:00
}
/**********************************************************************
This function is used to find the storage length in bytes of the first n
characters for prefix indexes using a multibyte character set . The function
finds charset information and returns length of prefix_len characters in the
index field in bytes .
NOTE : the prototype of this function is copied to data0type . c ! If you change
this function , you MUST change also data0type . c ! */
2007-05-10 13:31:36 +02:00
extern " C "
2005-10-27 09:29:40 +02:00
ulint
innobase_get_at_most_n_mbchars (
/*===========================*/
/* out: number of bytes occupied by the first
n characters */
ulint charset_id , /* in: character set id */
ulint prefix_len , /* in: prefix length in bytes of the index
( this has to be divided by mbmaxlen to get the
number of CHARACTERS n in the prefix ) */
2006-02-21 13:37:54 +01:00
ulint data_len , /* in: length of the string in bytes */
2005-10-27 09:29:40 +02:00
const char * str ) /* in: character string */
{
ulint char_length ; /* character length in bytes */
ulint n_chars ; /* number of characters in prefix */
CHARSET_INFO * charset ; /* charset used in the field */
charset = get_charset ( ( uint ) charset_id , MYF ( MY_WME ) ) ;
ut_ad ( charset ) ;
ut_ad ( charset - > mbmaxlen ) ;
/* Calculate how many characters at most the prefix index contains */
n_chars = prefix_len / charset - > mbmaxlen ;
/* If the charset is multi-byte, then we must find the length of the
first at most n chars in the string . If the string contains less
characters than n , then we return the length to the end of the last
character . */
if ( charset - > mbmaxlen > 1 ) {
/* my_charpos() returns the byte length of the first n_chars
characters , or a value bigger than the length of str , if
there were not enough full characters in str .
Why does the code below work :
Suppose that we are looking for n UTF - 8 characters .
1 ) If the string is long enough , then the prefix contains at
least n complete UTF - 8 characters + maybe some extra
characters + an incomplete UTF - 8 character . No problem in
this case . The function returns the pointer to the
end of the nth character .
2 ) If the string is not long enough , then the string contains
the complete value of a column , that is , only complete UTF - 8
characters , and we can store in the column prefix index the
whole string . */
char_length = my_charpos ( charset , str ,
str + data_len , ( int ) n_chars ) ;
if ( char_length > data_len ) {
char_length = data_len ;
2006-02-21 13:37:54 +01:00
}
2005-10-27 09:29:40 +02:00
} else {
if ( data_len < prefix_len ) {
char_length = data_len ;
} else {
char_length = prefix_len ;
}
}
return ( char_length ) ;
}
/***********************************************************************
This function is used to prepare X / Open XA distributed transaction */
2007-02-12 14:08:02 +01:00
static
2006-02-21 13:37:54 +01:00
int
2005-10-27 09:29:40 +02:00
innobase_xa_prepare (
/*================*/
/* out: 0 or error number */
2006-10-03 14:46:23 +02:00
handlerton * hton ,
2005-10-27 09:29:40 +02:00
THD * thd , /* in: handle to the MySQL thread of the user
whose XA transaction should be prepared */
bool all ) /* in: TRUE - commit transaction
FALSE - the current SQL statement ended */
{
int error = 0 ;
2007-05-10 14:09:03 +02:00
trx_t * trx = check_trx_exists ( thd ) ;
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
if ( thd_sql_command ( thd ) ! = SQLCOM_XA_PREPARE & &
( all | | ! thd_test_options ( thd , OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN ) ) )
2006-08-22 09:20:52 +02:00
{
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* For ibbackup to work the order of transactions in binlog
and InnoDB must be the same . Consider the situation
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
thread1 > prepare ; write to binlog ; . . .
< context switch >
thread2 > prepare ; write to binlog ; commit
thread1 > . . . commit
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
To ensure this will not happen we ' re taking the mutex on
prepare , and releasing it on commit .
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
Note : only do it for normal commits , done via ha_commit_trans .
If 2 pc protocol is executed by external transaction
coordinator , it will be just a regular MySQL client
executing XA PREPARE and XA COMMIT commands .
In this case we cannot know how many minutes or hours
will be between XA PREPARE and XA COMMIT , and we don ' t want
2009-11-10 14:30:20 +01:00
to block for undefined period of time . */
2006-02-21 13:37:54 +01:00
pthread_mutex_lock ( & prepare_commit_mutex ) ;
trx - > active_trans = 2 ;
}
2005-10-27 09:29:40 +02:00
2007-05-10 13:31:36 +02:00
if ( ! THDVAR ( thd , support_xa ) ) {
2005-10-27 09:29:40 +02:00
return ( 0 ) ;
}
2007-07-31 07:56:17 +02:00
thd_get_xid ( thd , ( MYSQL_XID * ) & trx - > xid ) ;
2005-10-27 09:29:40 +02:00
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex , we have to release the search system latch
first to obey the latching order . */
innobase_release_stat_resources ( trx ) ;
if ( trx - > active_trans = = 0 & & trx - > conc_state ! = TRX_NOT_STARTED ) {
sql_print_error ( " trx->active_trans == 0, but trx->conc_state != "
" TRX_NOT_STARTED " ) ;
}
if ( all
2007-05-10 13:31:36 +02:00
| | ( ! thd_test_options ( thd , OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN ) ) ) {
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
/* We were instructed to prepare the whole transaction, or
this is an SQL statement end and autocommit is on */
2005-10-27 09:29:40 +02:00
2006-02-21 13:37:54 +01:00
ut_ad ( trx - > active_trans ) ;
2005-10-27 09:29:40 +02:00
error = ( int ) trx_prepare_for_mysql ( trx ) ;
} else {
2006-02-21 13:37:54 +01:00
/* We just mark the SQL statement ended and do not do a
2005-10-27 09:29:40 +02:00
transaction prepare */
2007-11-30 10:36:27 +01:00
/* If we had reserved the auto-inc lock for some
table in this SQL statement we release it now */
2005-10-27 09:29:40 +02:00
2007-11-30 10:36:27 +01:00
row_unlock_table_autoinc_for_mysql ( trx ) ;
2007-07-24 03:42:16 +02:00
2005-10-27 09:29:40 +02:00
/* Store the current undo_no of the transaction so that we
know where to roll back if we have to roll back the next
SQL statement */
trx_mark_sql_stat_end ( trx ) ;
}
/* Tell the InnoDB server that there might be work for utility
threads : */
srv_active_wake_master_thread ( ) ;
2006-02-21 13:37:54 +01:00
return error ;
2005-10-27 09:29:40 +02:00
}
/***********************************************************************
This function is used to recover X / Open XA distributed transactions */
2007-02-12 14:08:02 +01:00
static
2006-02-21 13:37:54 +01:00
int
2005-10-27 09:29:40 +02:00
innobase_xa_recover (
/*================*/
2006-02-21 13:37:54 +01:00
/* out: number of prepared transactions
2005-10-27 09:29:40 +02:00
stored in xid_list */
2006-10-03 14:46:23 +02:00
handlerton * hton ,
2006-02-21 13:37:54 +01:00
XID * xid_list , /* in/out: prepared transactions */
2005-10-27 09:29:40 +02:00
uint len ) /* in: number of slots in xid_list */
{
if ( len = = 0 | | xid_list = = NULL ) {
return ( 0 ) ;
}
return ( trx_recover_for_mysql ( xid_list , len ) ) ;
}
/***********************************************************************
This function is used to commit one X / Open XA distributed transaction
which is in the prepared state */
2007-02-12 14:08:02 +01:00
static
2006-02-21 13:37:54 +01:00
int
2005-10-27 09:29:40 +02:00
innobase_commit_by_xid (
/*===================*/
/* out: 0 or error number */
2006-10-03 14:46:23 +02:00
handlerton * hton ,
2005-10-27 09:29:40 +02:00
XID * xid ) /* in: X/Open XA transaction identification */
{
trx_t * trx ;
trx = trx_get_trx_by_xid ( xid ) ;
if ( trx ) {
innobase_commit_low ( trx ) ;
2006-02-21 13:37:54 +01:00
2005-10-27 09:29:40 +02:00
return ( XA_OK ) ;
} else {
return ( XAER_NOTA ) ;
}
}
/***********************************************************************
This function is used to rollback one X / Open XA distributed transaction
which is in the prepared state */
2007-02-12 14:08:02 +01:00
static
2006-02-21 13:37:54 +01:00
int
2005-10-27 09:29:40 +02:00
innobase_rollback_by_xid (
/*=====================*/
/* out: 0 or error number */
2006-10-03 14:46:23 +02:00
handlerton * hton ,
2005-10-27 09:29:40 +02:00
XID * xid ) /* in: X/Open XA transaction identification */
{
trx_t * trx ;
trx = trx_get_trx_by_xid ( xid ) ;
if ( trx ) {
return ( innobase_rollback_trx ( trx ) ) ;
} else {
return ( XAER_NOTA ) ;
}
}
/***********************************************************************
Create a consistent view for a cursor based on current transaction
which is created if the corresponding MySQL thread still lacks one .
2006-02-21 13:37:54 +01:00
This consistent view is then used inside of MySQL when accessing records
2005-10-27 09:29:40 +02:00
using a cursor . */
2007-02-12 14:08:02 +01:00
static
2005-10-27 09:29:40 +02:00
void *
2006-10-03 14:46:23 +02:00
innobase_create_cursor_view (
2007-02-12 14:08:02 +01:00
/*========================*/
2006-10-03 14:46:23 +02:00
/* out: pointer to cursor view or NULL */
handlerton * hton , /* in: innobase hton */
THD * thd ) /* in: user thread handle */
2005-10-27 09:29:40 +02:00
{
2007-05-10 14:09:03 +02:00
return ( read_cursor_view_create_for_mysql ( check_trx_exists ( thd ) ) ) ;
2005-10-27 09:29:40 +02:00
}
/***********************************************************************
Close the given consistent cursor view of a transaction and restore
2006-02-21 13:37:54 +01:00
global read view to a transaction read view . Transaction is created if the
2005-10-27 09:29:40 +02:00
corresponding MySQL thread still lacks one . */
2007-02-12 14:08:02 +01:00
static
2005-10-27 09:29:40 +02:00
void
innobase_close_cursor_view (
2007-02-12 14:08:02 +01:00
/*=======================*/
2006-10-03 14:46:23 +02:00
handlerton * hton ,
THD * thd , /* in: user thread handle */
2005-10-27 09:29:40 +02:00
void * curview ) /* in: Consistent read view to be closed */
{
2007-05-10 14:09:03 +02:00
read_cursor_view_close_for_mysql ( check_trx_exists ( thd ) ,
2007-05-10 13:31:36 +02:00
( cursor_view_t * ) curview ) ;
2005-10-27 09:29:40 +02:00
}
/***********************************************************************
2006-02-21 13:37:54 +01:00
Set the given consistent cursor view to a transaction which is created
if the corresponding MySQL thread still lacks one . If the given
2005-10-27 09:29:40 +02:00
consistent cursor view is NULL global read view of a transaction is
restored to a transaction read view . */
2007-02-12 14:08:02 +01:00
static
2005-10-27 09:29:40 +02:00
void
innobase_set_cursor_view (
/*=====================*/
2006-10-03 14:46:23 +02:00
handlerton * hton ,
THD * thd , /* in: user thread handle */
2005-10-27 09:29:40 +02:00
void * curview ) /* in: Consistent cursor view to be set */
{
2007-05-10 14:09:03 +02:00
read_cursor_set_for_mysql ( check_trx_exists ( thd ) ,
2007-05-10 13:31:36 +02:00
( cursor_view_t * ) curview ) ;
2005-10-27 09:29:40 +02:00
}
2010-03-09 16:54:14 +01:00
/***********************************************************************
If col_name is not NULL , check whether the named column is being
renamed in the table . If col_name is not provided , check
whether any one of columns in the table is being renamed . */
static
bool
check_column_being_renamed (
/*=======================*/
/* out: true if find the column
being renamed */
const TABLE * table , /* in: MySQL table */
const char * col_name ) /* in: name of the column */
{
uint k ;
Field * field ;
for ( k = 0 ; k < table - > s - > fields ; k + + ) {
field = table - > field [ k ] ;
if ( field - > flags & FIELD_IS_RENAMED ) {
/* If col_name is not provided, return
if the field is marked as being renamed . */
if ( ! col_name ) {
return ( true ) ;
}
/* If col_name is provided, return only
if names match */
if ( innobase_strcasecmp ( field - > field_name ,
col_name ) = = 0 ) {
return ( true ) ;
}
}
}
return ( false ) ;
}
2005-10-27 09:51:34 +02:00
2009-07-09 17:16:44 +02:00
/***********************************************************************
Check whether any of the given columns is being renamed in the table . */
static
bool
column_is_being_renamed (
/*====================*/
/* out: true if any of col_names is
being renamed in table */
TABLE * table , /* in: MySQL table */
uint n_cols , /* in: number of columns */
const char * * col_names ) /* in: names of the columns */
{
uint j ;
for ( j = 0 ; j < n_cols ; j + + ) {
2010-03-09 16:54:14 +01:00
if ( check_column_being_renamed ( table , col_names [ j ] ) ) {
return ( true ) ;
2009-07-09 17:16:44 +02:00
}
}
return ( false ) ;
}
/***********************************************************************
Check whether a column in table " table " is being renamed and if this column
is part of a foreign key , either part of another table , referencing this
table or part of this table , referencing another table . */
static
bool
foreign_key_column_is_being_renamed (
/*================================*/
/* out: true if a column that
participates in a foreign key definition
is being renamed */
row_prebuilt_t * prebuilt , /* in: InnoDB prebuilt struct */
TABLE * table ) /* in: MySQL table */
{
dict_foreign_t * foreign ;
/* check whether there are foreign keys at all */
if ( UT_LIST_GET_LEN ( prebuilt - > table - > foreign_list ) = = 0
& & UT_LIST_GET_LEN ( prebuilt - > table - > referenced_list ) = = 0 ) {
/* no foreign keys involved with prebuilt->table */
return ( false ) ;
}
row_mysql_lock_data_dictionary ( prebuilt - > trx ) ;
/* Check whether any column in the foreign key constraints which refer
to this table is being renamed . */
for ( foreign = UT_LIST_GET_FIRST ( prebuilt - > table - > referenced_list ) ;
foreign ! = NULL ;
foreign = UT_LIST_GET_NEXT ( referenced_list , foreign ) ) {
if ( column_is_being_renamed ( table , foreign - > n_fields ,
foreign - > referenced_col_names ) ) {
row_mysql_unlock_data_dictionary ( prebuilt - > trx ) ;
return ( true ) ;
}
}
/* Check whether any column in the foreign key constraints in the
table is being renamed . */
for ( foreign = UT_LIST_GET_FIRST ( prebuilt - > table - > foreign_list ) ;
foreign ! = NULL ;
foreign = UT_LIST_GET_NEXT ( foreign_list , foreign ) ) {
if ( column_is_being_renamed ( table , foreign - > n_fields ,
foreign - > foreign_col_names ) ) {
row_mysql_unlock_data_dictionary ( prebuilt - > trx ) ;
return ( true ) ;
}
}
row_mysql_unlock_data_dictionary ( prebuilt - > trx ) ;
return ( false ) ;
}
2006-02-21 13:37:54 +01:00
bool ha_innobase : : check_if_incompatible_data (
HA_CREATE_INFO * info ,
uint table_changes )
2005-10-27 09:51:34 +02:00
{
2006-02-21 13:37:54 +01:00
if ( table_changes ! = IS_EQUAL_YES ) {
2005-10-27 09:51:34 +02:00
2006-02-21 13:37:54 +01:00
return COMPATIBLE_DATA_NO ;
}
/* Check that auto_increment value was not changed */
if ( ( info - > used_fields & HA_CREATE_USED_AUTO ) & &
info - > auto_increment_value ! = 0 ) {
return COMPATIBLE_DATA_NO ;
2010-03-09 16:54:14 +01:00
}
/* For column rename operation, MySQL does not supply enough
information ( new column name etc . ) for InnoDB to make appropriate
system metadata change . To avoid system metadata inconsistency ,
currently we can just request a table rebuild / copy by returning
COMPATIBLE_DATA_NO */
if ( check_column_being_renamed ( table , NULL ) ) {
return COMPATIBLE_DATA_NO ;
2006-02-21 13:37:54 +01:00
}
2009-07-09 17:16:44 +02:00
/* Check if a column participating in a foreign key is being renamed.
There is no mechanism for updating InnoDB foreign key definitions . */
if ( foreign_key_column_is_being_renamed ( prebuilt , table ) ) {
return COMPATIBLE_DATA_NO ;
}
2006-02-21 13:37:54 +01:00
/* Check that row format didn't change */
2008-03-17 09:23:03 +01:00
if ( ( info - > used_fields & HA_CREATE_USED_ROW_FORMAT ) & &
2006-02-21 13:37:54 +01:00
get_row_type ( ) ! = info - > row_type ) {
2005-10-27 09:51:34 +02:00
2006-02-21 13:37:54 +01:00
return COMPATIBLE_DATA_NO ;
}
return COMPATIBLE_DATA_YES ;
}
2006-05-08 10:08:27 +02:00
2006-09-04 12:45:05 +02:00
static int show_innodb_vars ( THD * thd , SHOW_VAR * var , char * buff )
{
innodb_export_status ( ) ;
var - > type = SHOW_ARRAY ;
var - > value = ( char * ) & innodb_status_variables ;
return 0 ;
}
2009-09-15 01:39:21 +02:00
/***********************************************************************
This function checks each index name for a table against reserved
system default primary index name ' GEN_CLUST_INDEX ' . If a name matches ,
this function pushes an error message to the client , and returns true . */
static
bool
innobase_index_name_is_reserved (
/*============================*/
/* out: true if an index name
matches the reserved name */
const trx_t * trx , /* in: InnoDB transaction handle */
const TABLE * form , /* in: information on table
columns and indexes */
const char * norm_name ) /* in: table name */
{
KEY * key ;
uint key_num ; /* index number */
for ( key_num = 0 ; key_num < form - > s - > keys ; key_num + + ) {
key = form - > key_info + key_num ;
if ( innobase_strcasecmp ( key - > name ,
innobase_index_reserve_name ) = = 0 ) {
/* Push warning to mysql */
push_warning_printf ( ( THD * ) trx - > mysql_thd ,
2009-10-30 04:18:38 +01:00
MYSQL_ERROR : : WARN_LEVEL_WARN ,
2009-09-15 01:39:21 +02:00
ER_CANT_CREATE_TABLE ,
" Cannot Create Index with name "
" '%s'. The name is reserved "
" for the system default primary "
" index. " ,
innobase_index_reserve_name ) ;
return ( true ) ;
}
}
return ( false ) ;
}
2007-03-27 10:22:27 +02:00
static SHOW_VAR innodb_status_variables_export [ ] = {
2006-09-04 12:45:05 +02:00
{ " Innodb " , ( char * ) & show_innodb_vars , SHOW_FUNC } ,
{ NullS , NullS , SHOW_LONG }
} ;
2007-03-27 10:22:27 +02:00
static struct st_mysql_storage_engine innobase_storage_engine =
2006-10-03 14:46:23 +02:00
{ MYSQL_HANDLERTON_INTERFACE_VERSION } ;
2006-05-08 10:08:27 +02:00
2007-05-10 13:31:36 +02:00
/* plugin options */
static MYSQL_SYSVAR_BOOL ( checksums , innobase_use_checksums ,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY ,
" Enable InnoDB checksums validation (enabled by default). "
" Disable with --skip-innodb-checksums. " ,
NULL , NULL , TRUE ) ;
static MYSQL_SYSVAR_STR ( data_home_dir , innobase_data_home_dir ,
PLUGIN_VAR_READONLY ,
" The common part for InnoDB table spaces. " ,
NULL , NULL , NULL ) ;
static MYSQL_SYSVAR_BOOL ( doublewrite , innobase_use_doublewrite ,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY ,
" Enable InnoDB doublewrite buffer (enabled by default). "
" Disable with --skip-innodb-doublewrite. " ,
NULL , NULL , TRUE ) ;
static MYSQL_SYSVAR_ULONG ( fast_shutdown , innobase_fast_shutdown ,
PLUGIN_VAR_OPCMDARG ,
" Speeds up the shutdown process of the InnoDB storage engine. Possible "
" values are 0, 1 (faster) "
/*
NetWare can ' t close unclosed files , can ' t automatically kill remaining
threads , etc , so on this OS we disable the crash - like InnoDB shutdown .
*/
IF_NETWARE ( " " , " or 2 (fastest - crash-like) " )
" . " ,
NULL , NULL , 1 , 0 , IF_NETWARE ( 1 , 2 ) , 0 ) ;
static MYSQL_SYSVAR_BOOL ( file_per_table , innobase_file_per_table ,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY ,
" Stores each InnoDB table to an .ibd file in the database dir. " ,
NULL , NULL , FALSE ) ;
static MYSQL_SYSVAR_ULONG ( flush_log_at_trx_commit , srv_flush_log_at_trx_commit ,
PLUGIN_VAR_OPCMDARG ,
" 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). " ,
NULL , NULL , 1 , 0 , 2 , 0 ) ;
static MYSQL_SYSVAR_STR ( flush_method , innobase_unix_file_flush_method ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" With which method to flush data. " , NULL , NULL , NULL ) ;
static MYSQL_SYSVAR_BOOL ( locks_unsafe_for_binlog , innobase_locks_unsafe_for_binlog ,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY ,
" Force InnoDB to not use next-key locking, to use only row-level locking. " ,
NULL , NULL , FALSE ) ;
# ifdef UNIV_LOG_ARCHIVE
static MYSQL_SYSVAR_STR ( log_arch_dir , innobase_log_arch_dir ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" Where full logs should be archived. " , NULL , NULL , NULL ) ;
static MYSQL_SYSVAR_BOOL ( log_archive , innobase_log_archive ,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY ,
" Set to 1 if you want to have logs archived. " , NULL , NULL , FALSE ) ;
# endif /* UNIV_LOG_ARCHIVE */
static MYSQL_SYSVAR_STR ( log_group_home_dir , innobase_log_group_home_dir ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" Path to InnoDB log files. " , NULL , NULL , NULL ) ;
static MYSQL_SYSVAR_ULONG ( max_dirty_pages_pct , srv_max_buf_pool_modified_pct ,
PLUGIN_VAR_RQCMDARG ,
" Percentage of dirty pages allowed in bufferpool. " ,
NULL , NULL , 90 , 0 , 100 , 0 ) ;
static MYSQL_SYSVAR_ULONG ( max_purge_lag , srv_max_purge_lag ,
PLUGIN_VAR_RQCMDARG ,
" Desired maximum length of the purge queue (0 = no limit) " ,
NULL , NULL , 0 , 0 , ~ 0L , 0 ) ;
static MYSQL_SYSVAR_BOOL ( rollback_on_timeout , innobase_rollback_on_timeout ,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY ,
" Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default) " ,
NULL , NULL , FALSE ) ;
static MYSQL_SYSVAR_BOOL ( status_file , innobase_create_status_file ,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_NOSYSVAR ,
" Enable SHOW INNODB STATUS output in the innodb_status.<pid> file " ,
NULL , NULL , FALSE ) ;
static MYSQL_SYSVAR_BOOL ( stats_on_metadata , innobase_stats_on_metadata ,
2008-10-28 11:10:25 +01:00
PLUGIN_VAR_OPCMDARG ,
2007-05-10 13:31:36 +02:00
" Enable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default) " ,
NULL , NULL , TRUE ) ;
2009-04-09 12:01:52 +02:00
static MYSQL_SYSVAR_BOOL ( use_legacy_cardinality_algorithm ,
srv_use_legacy_cardinality_algorithm ,
PLUGIN_VAR_OPCMDARG ,
" Use legacy algorithm for picking random pages during index cardinality "
" estimation. Disable this to use a better algorithm, but note that your "
" query plans may change (enabled by default). " ,
NULL , NULL , TRUE ) ;
2008-02-05 14:29:30 +01:00
static MYSQL_SYSVAR_BOOL ( adaptive_hash_index , innobase_adaptive_hash_index ,
2007-09-14 10:19:48 +02:00
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY ,
2008-02-05 14:29:30 +01:00
" Enable InnoDB adaptive hash index (enabled by default). "
" Disable with --skip-innodb-adaptive-hash-index. " ,
2007-09-14 10:19:48 +02:00
NULL , NULL , TRUE ) ;
2007-05-10 13:31:36 +02:00
static MYSQL_SYSVAR_LONG ( additional_mem_pool_size , innobase_additional_mem_pool_size ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures. " ,
2009-01-26 16:26:25 +01:00
NULL , NULL , 1 * 1024 * 1024L , 512 * 1024L , LONG_MAX , 1024 ) ;
2007-05-10 13:31:36 +02:00
static MYSQL_SYSVAR_ULONG ( autoextend_increment , srv_auto_extend_increment ,
PLUGIN_VAR_RQCMDARG ,
" Data file autoextend increment in megabytes " ,
NULL , NULL , 8L , 1L , 1000L , 0 ) ;
static MYSQL_SYSVAR_LONGLONG ( buffer_pool_size , innobase_buffer_pool_size ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" The size of the memory buffer InnoDB uses to cache data and indexes of its tables. " ,
NULL , NULL , 8 * 1024 * 1024L , 1024 * 1024L , LONGLONG_MAX , 1024 * 1024L ) ;
2009-05-14 13:04:55 +02:00
static MYSQL_SYSVAR_ULONG ( commit_concurrency , innobase_commit_concurrency ,
2007-05-10 13:31:36 +02:00
PLUGIN_VAR_RQCMDARG ,
" Helps in performance tuning in heavily concurrent environments. " ,
2009-05-14 13:04:55 +02:00
innobase_commit_concurrency_validate , NULL , 0 , 0 , 1000 , 0 ) ;
2007-05-10 13:31:36 +02:00
static MYSQL_SYSVAR_ULONG ( concurrency_tickets , srv_n_free_tickets_to_enter ,
PLUGIN_VAR_RQCMDARG ,
" Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket " ,
NULL , NULL , 500L , 1L , ~ 0L , 0 ) ;
static MYSQL_SYSVAR_LONG ( file_io_threads , innobase_file_io_threads ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" Number of file I/O threads in InnoDB. " ,
NULL , NULL , 4 , 4 , 64 , 0 ) ;
static MYSQL_SYSVAR_LONG ( force_recovery , innobase_force_recovery ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" Helps to save your data in case the disk image of the database becomes corrupt. " ,
NULL , NULL , 0 , 0 , 6 , 0 ) ;
static MYSQL_SYSVAR_LONG ( lock_wait_timeout , innobase_lock_wait_timeout ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. " ,
NULL , NULL , 50 , 1 , 1024 * 1024 * 1024 , 0 ) ;
static MYSQL_SYSVAR_LONG ( log_buffer_size , innobase_log_buffer_size ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" The size of the buffer which InnoDB uses to write log to the log files on disk. " ,
2009-01-26 16:26:25 +01:00
NULL , NULL , 1024 * 1024L , 256 * 1024L , LONG_MAX , 1024 ) ;
2007-05-10 13:31:36 +02:00
static MYSQL_SYSVAR_LONGLONG ( log_file_size , innobase_log_file_size ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" Size of each log file in a log group. " ,
NULL , NULL , 5 * 1024 * 1024L , 1 * 1024 * 1024L , LONGLONG_MAX , 1024 * 1024L ) ;
static MYSQL_SYSVAR_LONG ( log_files_in_group , innobase_log_files_in_group ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" Number of log files in the log group. InnoDB writes to the files in a circular fashion. Value 3 is recommended here. " ,
NULL , NULL , 2 , 2 , 100 , 0 ) ;
static MYSQL_SYSVAR_LONG ( mirrored_log_groups , innobase_mirrored_log_groups ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" Number of identical copies of log groups we keep for the database. Currently this should be set to 1. " ,
NULL , NULL , 1 , 1 , 10 , 0 ) ;
static MYSQL_SYSVAR_LONG ( open_files , innobase_open_files ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" How many files at the maximum InnoDB keeps open at the same time. " ,
2009-01-26 16:26:25 +01:00
NULL , NULL , 300L , 10L , LONG_MAX , 0 ) ;
2007-05-10 13:31:36 +02:00
static MYSQL_SYSVAR_ULONG ( sync_spin_loops , srv_n_spin_wait_rounds ,
PLUGIN_VAR_RQCMDARG ,
" Count of spin-loop rounds in InnoDB mutexes " ,
NULL , NULL , 20L , 0L , ~ 0L , 0 ) ;
static MYSQL_SYSVAR_ULONG ( thread_concurrency , srv_thread_concurrency ,
PLUGIN_VAR_RQCMDARG ,
" Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling. " ,
NULL , NULL , 8 , 0 , 1000 , 0 ) ;
static MYSQL_SYSVAR_ULONG ( thread_sleep_delay , srv_thread_sleep_delay ,
PLUGIN_VAR_RQCMDARG ,
" Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep " ,
NULL , NULL , 10000L , 0L , ~ 0L , 0 ) ;
static MYSQL_SYSVAR_STR ( data_file_path , innobase_data_file_path ,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
" Path to individual files and their sizes. " ,
NULL , NULL , NULL ) ;
2007-08-20 23:48:16 +02:00
static MYSQL_SYSVAR_LONG ( autoinc_lock_mode , innobase_autoinc_lock_mode ,
2007-11-30 10:36:27 +01:00
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY ,
2008-01-16 14:50:51 +01:00
" The AUTOINC lock modes supported by InnoDB: "
" 0 => Old style AUTOINC locking (for backward "
" compatibility) "
" 1 => New style AUTOINC locking "
" 2 => No AUTOINC locking (unsafe for SBR) " ,
2007-08-20 23:48:16 +02:00
NULL , NULL ,
AUTOINC_NEW_STYLE_LOCKING , /* Default setting */
AUTOINC_OLD_STYLE_LOCKING , /* Minimum value */
AUTOINC_NO_LOCKING , 0 ) ; /* Maximum value */
2007-05-10 13:31:36 +02:00
static struct st_mysql_sys_var * innobase_system_variables [ ] = {
MYSQL_SYSVAR ( additional_mem_pool_size ) ,
MYSQL_SYSVAR ( autoextend_increment ) ,
MYSQL_SYSVAR ( buffer_pool_size ) ,
MYSQL_SYSVAR ( checksums ) ,
MYSQL_SYSVAR ( commit_concurrency ) ,
MYSQL_SYSVAR ( concurrency_tickets ) ,
MYSQL_SYSVAR ( data_file_path ) ,
MYSQL_SYSVAR ( data_home_dir ) ,
MYSQL_SYSVAR ( doublewrite ) ,
MYSQL_SYSVAR ( fast_shutdown ) ,
MYSQL_SYSVAR ( file_io_threads ) ,
MYSQL_SYSVAR ( file_per_table ) ,
MYSQL_SYSVAR ( flush_log_at_trx_commit ) ,
MYSQL_SYSVAR ( flush_method ) ,
MYSQL_SYSVAR ( force_recovery ) ,
MYSQL_SYSVAR ( locks_unsafe_for_binlog ) ,
MYSQL_SYSVAR ( lock_wait_timeout ) ,
# ifdef UNIV_LOG_ARCHIVE
MYSQL_SYSVAR ( log_arch_dir ) ,
MYSQL_SYSVAR ( log_archive ) ,
# endif /* UNIV_LOG_ARCHIVE */
MYSQL_SYSVAR ( log_buffer_size ) ,
MYSQL_SYSVAR ( log_file_size ) ,
MYSQL_SYSVAR ( log_files_in_group ) ,
MYSQL_SYSVAR ( log_group_home_dir ) ,
MYSQL_SYSVAR ( max_dirty_pages_pct ) ,
MYSQL_SYSVAR ( max_purge_lag ) ,
MYSQL_SYSVAR ( mirrored_log_groups ) ,
MYSQL_SYSVAR ( open_files ) ,
MYSQL_SYSVAR ( rollback_on_timeout ) ,
MYSQL_SYSVAR ( stats_on_metadata ) ,
2009-04-09 12:01:52 +02:00
MYSQL_SYSVAR ( use_legacy_cardinality_algorithm ) ,
2008-02-05 14:29:30 +01:00
MYSQL_SYSVAR ( adaptive_hash_index ) ,
2007-05-10 13:31:36 +02:00
MYSQL_SYSVAR ( status_file ) ,
MYSQL_SYSVAR ( support_xa ) ,
MYSQL_SYSVAR ( sync_spin_loops ) ,
MYSQL_SYSVAR ( table_locks ) ,
MYSQL_SYSVAR ( thread_concurrency ) ,
MYSQL_SYSVAR ( thread_sleep_delay ) ,
2007-08-20 23:48:16 +02:00
MYSQL_SYSVAR ( autoinc_lock_mode ) ,
2007-05-10 13:31:36 +02:00
NULL
} ;
2006-05-08 10:08:27 +02:00
mysql_declare_plugin ( innobase )
{
MYSQL_STORAGE_ENGINE_PLUGIN ,
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
& innobase_storage_engine ,
2006-05-08 10:08:27 +02:00
innobase_hton_name ,
" Innobase OY " ,
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
" Supports transactions, row-level locking, and foreign keys " ,
2006-10-09 11:08:50 +02:00
PLUGIN_LICENSE_GPL ,
Merge changes from MySQL AB:
innodb_mysql.test, innodb_mysql.result:
Bug #16798: Uninitialized row buffer reads in ref-or-null optimizer
Bug #12882: min/max inconsistent on empty table
Test of behaviour with CREATE ... SELECT
Moved from group_min_max.test:
Bug #12672: primary key implicitly included in every innodb index
Bug #6142: a problem with empty innodb table
Bug #9798: group by with rollup
ChangeSet@2006/06/01 21:47:15+03:00 bell@sanja.is.com.ua
# interface for transaction log management added to handlerton
# iterators creation interface added to handlerton
ha_innodb.cc: Add get_log_status = create_iterator = NULL
ChangeSet@2006/06/04 18:52:22+03:00 monty@mysql.com
# This changeset is largely a handler cleanup changeset (WL#3281),
# but includes fixes and cleanups that was found necessary while
# testing the handler changes
# sql/ha_innodb.h
# 2006/06/04 18:52:09+03:00 monty@mysql.com +6 -13
# Update to 'newer' table handler interface
# - table_flags are now ulonglong
# - Added reset() method
# - Removed not needed ha_retrieve_all_cols() and ha_retrieve_all_pk()
# columns.
# - Made build_template() a class function to be able to easier access
# class variables
# sql/ha_innodb.cc
# 2006/06/04 18:52:09+03:00 monty@mysql.com +37 -44
# Update to 'newer' table handler interface
# - Update innobase_create_handler() to new interface
# - Removed HA_NOT_EXACT_COUNT (not needed)
# - Renamed HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
# to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
# - Prefixed base status variables with 'stats'
# - Use table column bitmaps instead of ha_get_bit_in_read_set()
# - Added ::reset(), with code from ::extra(HA_EXTRA_RESET)
# - Removed HA_EXTRA_RETRIVE_ALL_COLS and HA_EXTRA_RETRIEVE_PRIMARY_KEY as
# the table->read_set and table->write_set bitmaps now are accurate
ChangeSet@2006/06/02 22:21:32+02:00 guilhem@mysql.com
# First push for WL#3146 "less locking in auto_increment". It is a
# 0-real-change patch.
# New prototype for get_auto_increment() (but new arguments not yet used),
# to be able to reserve a finite interval of auto_increment values from
# cooperating engines.
# A hint on how many values to reserve is found in
# handler::estimation_rows_to_insert,
# filled by ha_start_bulk_insert(), new wrapper around start_bulk_insert().
# NOTE: this patch changes nothing, for all engines.
# But it makes the API ready for those
# engines which will want to do reservation.
# More csets will come to complete WL#3146.
ha_innodb.h, ha_innodb.cc: update to new prototype of get_auto_increment
ChangeSet@2006/05/28 14:51:01+02:00 serg@sergbook.mysql.com
# handlerton cleanup:
# duplicate fields removed, st_mysql_storage_engine added to support
# run-time handlerton initialization (no compiler warnings), handler API
# is now tied to MySQL version, handlerton->plugin mapping added
# (slot-based), dummy default_hton removed, plugin-type-specific
# initialization generalized, built-in plugins are now initialized too,
# --default-storage-engine no longer needs a list of storage engines
# in handle_options().
#
# sql/ha_innodb.h
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +1 -1
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
#
# sql/ha_innodb.cc
# 2006/05/28 14:50:53+02:00 serg@sergbook.mysql.com +37 -52
# handlerton cleanup: remove duplicate fields, add st_mysql_storage_engine,
# initialize handlerton run-time to avoid compiler warnings
ChangeSet@2006/06/01 23:59:34+02:00 serg@serg.mylan
# second patch for make distcheck
ha_innodb.cc: enclose in #ifdef WITH_INNOBASE_STORAGE_ENGINE / #endif
2006-06-13 14:50:11 +02:00
innobase_init , /* Plugin Init */
2006-05-08 10:08:27 +02:00
NULL , /* Plugin Deinit */
0x0100 /* 1.0 */ ,
2006-09-20 11:38:09 +02:00
innodb_status_variables_export , /* status variables */
2007-05-10 13:31:36 +02:00
innobase_system_variables , /* system variables */
NULL /* reserved */
2006-05-08 10:08:27 +02:00
}
mysql_declare_plugin_end ;
2009-06-25 14:11:57 +02:00
/** @brief Initialize the default value of innodb_commit_concurrency.
Once InnoDB is running , the innodb_commit_concurrency must not change
from zero to nonzero . ( Bug # 42101 )
The initial default value is 0 , and without this extra initialization ,
SET GLOBAL innodb_commit_concurrency = DEFAULT would set the parameter
to 0 , even if it was initially set to nonzero at the command line
or configuration file . */
static
void
innobase_commit_concurrency_init_default ( void )
/*==========================================*/
{
MYSQL_SYSVAR_NAME ( commit_concurrency ) . def_val
= innobase_commit_concurrency ;
}