summaryrefslogtreecommitdiff
path: root/sql/ha_innodb.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/ha_innodb.cc')
-rw-r--r--sql/ha_innodb.cc272
1 files changed, 173 insertions, 99 deletions
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 8bd43ea92cd..664968aaef4 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -80,7 +80,6 @@ extern "C" {
#define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */
#define HA_INNOBASE_RANGE_COUNT 100
-bool innodb_skip = 0;
uint innobase_init_flags = 0;
ulong innobase_cache_size = 0;
@@ -135,7 +134,6 @@ static mysql_byte* innobase_get_key(INNOBASE_SHARE *share,uint *length,
my_bool not_used __attribute__((unused)));
static INNOBASE_SHARE *get_share(const char *table_name);
static void free_share(INNOBASE_SHARE *share);
-static void innobase_print_error(const char* db_errpfx, char* buffer);
/* General functions */
@@ -290,7 +288,7 @@ convert_error_code_to_mysql(
} else if (error == (int) DB_CANNOT_DROP_CONSTRAINT) {
- return(HA_WRONG_CREATE_OPTION);
+ return(HA_ERR_ROW_IS_REFERENCED);
} else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) {
@@ -552,7 +550,7 @@ innobase_query_caching_of_table_permitted(
if (thd->variables.tx_isolation == ISO_SERIALIZABLE) {
/* In the SERIALIZABLE mode we add LOCK IN SHARE MODE to every
- plain SELECT */
+ plain SELECT if AUTOCOMMIT is not on. */
return((my_bool)FALSE);
}
@@ -703,7 +701,7 @@ ha_innobase::init_table_handle_for_HANDLER(void)
/* Always fetch all columns in the index record */
- prebuilt->hint_no_need_to_fetch_extra_cols = FALSE;
+ prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS;
/* We want always to fetch all columns in the whole row? Or do
we???? */
@@ -755,7 +753,7 @@ innobase_init(void)
srv_set_thread_priorities = TRUE;
srv_query_thread_priority = QUERY_PRIOR;
}
-
+
/* Set InnoDB initialization parameters according to the values
read from MySQL .cnf file */
@@ -870,16 +868,22 @@ innobase_init(void)
srv_print_verbose_log = mysql_embedded ? 0 : 1;
- if (strcmp(default_charset_info->name, "latin1") == 0) {
+ /* Store the default charset-collation number of this MySQL
+ installation */
- /* Store the character ordering table to InnoDB.
- For non-latin1 charsets we use the MySQL comparison
- functions, and consequently we do not need to know
- the ordering internally in InnoDB. */
+ data_mysql_default_charset_coll = (ulint)default_charset_info->number;
- memcpy(srv_latin1_ordering,
- default_charset_info->sort_order, 256);
- }
+ data_mysql_latin1_swedish_charset_coll =
+ (ulint)my_charset_latin1.number;
+
+ /* 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);
/* Since we in this module access directly the fields of a trx
struct, and due to different headers and flags it might happen that
@@ -976,28 +980,13 @@ innobase_commit_low(
}
#ifdef HAVE_REPLICATION
- /* TODO: Guilhem should check if master_log_name, pending
- etc. are right if the master log gets rotated! Possible bug here.
- Comment by Heikki March 4, 2003. */
-
if (current_thd->slave_thread) {
/* Update the replication position info inside InnoDB */
trx->mysql_master_log_file_name
= active_mi->rli.group_master_log_name;
- /*
- Guilhem to Heikki: in 5.0 we don't need to do a computation
- (old_pos+len) to get the end_pos, because we already have the
- end_pos under hand in the replication code
- (Query_log_event::exec_event()).
- I tested the code change below (simulated a crash with kill
- -9) and got the good (binlog, position) displayed by InnoDB at
- crash recovery, so this code change is ok.
- */
- trx->mysql_master_log_pos = ((ib_longlong)
- (active_mi->rli.future_group_master_log_pos
- ));
-
+ trx->mysql_master_log_pos= ((ib_longlong)
+ active_mi->rli.future_group_master_log_pos);
}
#endif /* HAVE_REPLICATION */
@@ -1302,18 +1291,6 @@ innobase_close_connection(
return(0);
}
-/**********************************************************************
-Prints an error message. */
-static
-void
-innobase_print_error(
-/*=================*/
- const char* db_errpfx, /* in: error prefix text */
- char* buffer) /* in: error text */
-{
- sql_print_error("%s: %s", db_errpfx, buffer);
-}
-
/*****************************************************************************
** InnoDB database tables
@@ -1670,10 +1647,10 @@ reset_null_bits(
extern "C" {
/*****************************************************************
-InnoDB uses this function is 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! */
+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(
@@ -1681,6 +1658,7 @@ 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 */
@@ -1688,6 +1666,7 @@ innobase_mysql_cmp(
unsigned int b_length) /* in: data field length,
not UNIV_SQL_NULL */
{
+ CHARSET_INFO* charset;
enum_field_types mysql_tp;
int ret;
@@ -1704,9 +1683,27 @@ innobase_mysql_cmp(
case FIELD_TYPE_MEDIUM_BLOB:
case FIELD_TYPE_BLOB:
case FIELD_TYPE_LONG_BLOB:
- // BAR TODO: Discuss with heikki.tuuri@innodb.com
- // so that he sends CHARSET_INFO for the field to this function.
- ret = my_strnncoll(default_charset_info,
+ /* 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) {
+ fprintf(stderr,
+"InnoDB: fatal error: InnoDB needs charset %lu for doing a comparison,\n"
+"InnoDB: but MySQL cannot find that charset.\n", (ulong)charset_number);
+ ut_a(0);
+ }
+ }
+
+ ret = my_strnncoll(charset,
a, a_length,
b, b_length);
if (ret < 0) {
@@ -1733,9 +1730,9 @@ get_innobase_type_from_mysql_type(
/* out: DATA_BINARY, DATA_VARCHAR, ... */
Field* field) /* in: MySQL field */
{
- /* The following asserts 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 */
+ /* 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 */
DBUG_ASSERT((ulint)FIELD_TYPE_STRING < 256);
DBUG_ASSERT((ulint)FIELD_TYPE_VAR_STRING < 256);
@@ -1750,8 +1747,8 @@ get_innobase_type_from_mysql_type(
return(DATA_BINARY);
} else if (strcmp(
- default_charset_info->name,
- "latin1") == 0) {
+ field->charset()->name,
+ "latin1_swedish_ci") == 0) {
return(DATA_VARCHAR);
} else {
return(DATA_VARMYSQL);
@@ -1760,8 +1757,8 @@ get_innobase_type_from_mysql_type(
return(DATA_FIXBINARY);
} else if (strcmp(
- default_charset_info->name,
- "latin1") == 0) {
+ field->charset()->name,
+ "latin1_swedish_ci") == 0) {
return(DATA_CHAR);
} else {
return(DATA_MYSQL);
@@ -1935,6 +1932,7 @@ build_template(
ulint n_fields;
ulint n_requested_fields = 0;
ibool fetch_all_in_key = FALSE;
+ ibool fetch_primary_key_cols = FALSE;
ulint i;
if (prebuilt->select_lock_type == LOCK_X) {
@@ -1945,8 +1943,9 @@ build_template(
templ_type = ROW_MYSQL_WHOLE_ROW;
}
- if (templ_type == ROW_MYSQL_REC_FIELDS
- && !prebuilt->hint_no_need_to_fetch_extra_cols) {
+ if (templ_type == ROW_MYSQL_REC_FIELDS) {
+ if (prebuilt->hint_need_to_fetch_extra_cols
+ == ROW_RETRIEVE_ALL_COLS) {
/* We know we must at least fetch all columns in the key, or
all columns in the table */
@@ -1961,15 +1960,18 @@ build_template(
fetch_all_in_key = TRUE;
} else {
- /* We are building a temporary table: fetch all
- columns; the reason is that MySQL may use the
- clustered index key to store rows, but the mechanism
- we use below to detect required columns does not
- reveal that. Actually, it might be enough to
- fetch only all in the key also in this case! */
-
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;
+ }
}
clust_index = dict_table_get_first_index_noninline(prebuilt->table);
@@ -1988,7 +1990,7 @@ build_template(
the clustered index */
}
- n_fields = (ulint)table->fields;
+ n_fields = (ulint)table->fields; /* number of columns */
if (!prebuilt->mysql_template) {
prebuilt->mysql_template = (mysql_row_templ_t*)
@@ -2001,6 +2003,8 @@ build_template(
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];
@@ -2015,8 +2019,10 @@ build_template(
if (templ_type == ROW_MYSQL_REC_FIELDS &&
((prebuilt->read_just_key && !index_contains_field) ||
- (!(fetch_all_in_key && index_contains_field)
- && thd->query_id != field->query_id))) {
+ (!(fetch_all_in_key && index_contains_field) &&
+ !(fetch_primary_key_cols &&
+ dict_table_col_in_clustered_key(index->table, i)) &&
+ thd->query_id != field->query_id))) {
/* This field is not needed in the query, skip it */
@@ -2097,14 +2103,32 @@ ha_innobase::write_row(
DBUG_ENTER("ha_innobase::write_row");
- ut_ad(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ if (prebuilt->trx !=
+ (trx_t*) current_thd->transaction.all.innobase_tid) {
+ char err_buf[2000];
+
+ fprintf(stderr,
+"InnoDB: Error: the transaction object for the table handle is at\n"
+"InnoDB: %lx, but for the current thread it is at %lx\n",
+ (ulong)prebuilt->trx,
+ (ulong)current_thd->transaction.all.innobase_tid);
+
+ ut_sprintf_buf(err_buf, ((byte*)prebuilt) - 100, 200);
+ fprintf(stderr,
+"InnoDB: Dump of 200 bytes around prebuilt: %.1000s\n", err_buf);
+
+ ut_sprintf_buf(err_buf,
+ ((byte*)(&(current_thd->transaction.all))) - 100, 200);
+ fprintf(stderr,
+"InnoDB: Dump of 200 bytes around transaction.all: %.1000s\n", err_buf);
+
+ ut_a(0);
+ }
statistic_increment(ha_write_count, &LOCK_status);
- if (table->time_stamp) {
- update_timestamp(record + table->time_stamp - 1);
- }
+ if (table->timestamp_default_now)
+ update_timestamp(record + table->timestamp_default_now - 1);
if (last_query_id != user_thd->query_id) {
prebuilt->sql_stat_start = TRUE;
@@ -2475,9 +2499,8 @@ ha_innobase::update_row(
ut_ad(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
- if (table->time_stamp) {
- update_timestamp(new_row + table->time_stamp - 1);
- }
+ if (table->timestamp_on_update_now)
+ update_timestamp(new_row + table->timestamp_on_update_now - 1);
if (last_query_id != user_thd->query_id) {
prebuilt->sql_stat_start = TRUE;
@@ -3249,7 +3272,7 @@ create_table_def(
ulint nulls_allowed;
ulint unsigned_type;
ulint binary_type;
- ulint nonlatin1_type;
+ ulint charset_no;
ulint i;
DBUG_ENTER("create_table_def");
@@ -3278,24 +3301,28 @@ create_table_def(
unsigned_type = 0;
}
- if (col_type == DATA_BLOB
- && strcmp(default_charset_info->name, "latin1") != 0) {
- nonlatin1_type = DATA_NONLATIN1;
- } else {
- nonlatin1_type = 0;
- }
-
if (field->binary()) {
binary_type = DATA_BINARY_TYPE;
- nonlatin1_type = 0;
} else {
binary_type = 0;
}
+ charset_no = 0;
+
+ if (dtype_is_string_type(col_type)) {
+
+ charset_no = (ulint)field->charset()->number;
+
+ ut_a(charset_no < 256); /* in ut0type.h we assume that
+ the number fits in one byte */
+ }
+
dict_mem_table_add_col(table, (char*) field->field_name,
- col_type, (ulint)field->type()
+ col_type, dtype_form_prtype(
+ (ulint)field->type()
| nulls_allowed | unsigned_type
- | nonlatin1_type | binary_type,
+ | binary_type,
+ + charset_no),
field->pack_length(), 0);
}
@@ -3479,7 +3506,7 @@ ha_innobase::create(
/* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
but we play safe here */
- return(HA_ERR_TO_BIG_ROW);
+ DBUG_RETURN(HA_ERR_TO_BIG_ROW);
}
/* Get the transaction associated with the current thd, or create one
@@ -3693,6 +3720,7 @@ ha_innobase::delete_table(
int error;
trx_t* parent_trx;
trx_t* trx;
+ THD *thd= current_thd;
char norm_name[1000];
DBUG_ENTER("ha_innobase::delete_table");
@@ -3718,6 +3746,14 @@ ha_innobase::delete_table(
trx->mysql_thd = current_thd;
trx->mysql_query_str = &((*current_thd).query);
+ if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) {
+ trx->check_foreigns = FALSE;
+ }
+
+ if (thd->options & OPTION_RELAXED_UNIQUE_CHECKS) {
+ trx->check_unique_secondary = FALSE;
+ }
+
name_len = strlen(name);
assert(name_len < 1000);
@@ -3799,6 +3835,10 @@ innobase_drop_database(
trx->mysql_thd = current_thd;
trx->mysql_query_str = &((*current_thd).query);
+ if (current_thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) {
+ trx->check_foreigns = FALSE;
+ }
+
error = row_drop_database_for_mysql(namebuf, trx);
/* Flush the log to reduce probability that the .frm files and
@@ -4414,6 +4454,27 @@ ha_innobase::get_foreign_key_create_info(void)
}
/***********************************************************************
+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 */
+{
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
+
+ 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. */
@@ -4463,7 +4524,14 @@ ha_innobase::extra(
prebuilt->read_just_key = 0;
break;
case HA_EXTRA_RETRIEVE_ALL_COLS:
- prebuilt->hint_no_need_to_fetch_extra_cols = FALSE;
+ prebuilt->hint_need_to_fetch_extra_cols
+ = ROW_RETRIEVE_ALL_COLS;
+ break;
+ case HA_EXTRA_RETRIEVE_PRIMARY_KEY:
+ if (prebuilt->hint_need_to_fetch_extra_cols == 0) {
+ prebuilt->hint_need_to_fetch_extra_cols
+ = ROW_RETRIEVE_PRIMARY_KEY;
+ }
break;
case HA_EXTRA_KEYREAD:
prebuilt->read_just_key = 1;
@@ -4524,7 +4592,7 @@ ha_innobase::start_stmt(
auto_inc_counter_for_this_stat = 0;
prebuilt->sql_stat_start = TRUE;
- prebuilt->hint_no_need_to_fetch_extra_cols = TRUE;
+ prebuilt->hint_need_to_fetch_extra_cols = 0;
prebuilt->read_just_key = 0;
if (!prebuilt->mysql_has_locked) {
@@ -4601,7 +4669,7 @@ ha_innobase::external_lock(
trx = prebuilt->trx;
prebuilt->sql_stat_start = TRUE;
- prebuilt->hint_no_need_to_fetch_extra_cols = TRUE;
+ prebuilt->hint_need_to_fetch_extra_cols = 0;
prebuilt->read_just_key = 0;
@@ -4629,11 +4697,17 @@ ha_innobase::external_lock(
}
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
- && prebuilt->select_lock_type == LOCK_NONE) {
-
- /* To get serializable execution we let InnoDB
- conceptually add 'LOCK IN SHARE MODE' to all SELECTs
- which otherwise would have been consistent reads */
+ && prebuilt->select_lock_type == LOCK_NONE
+ && (thd->options
+ & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
+
+ /* 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;
}
@@ -4700,7 +4774,7 @@ innodb_show_status(
DBUG_ENTER("innodb_show_status");
- if (innodb_skip) {
+ if (have_innodb != SHOW_OPTION_YES) {
my_message(ER_NOT_SUPPORTED_YET,
"Cannot call SHOW INNODB STATUS because skip-innodb is defined",
MYF(0));
@@ -4939,7 +5013,7 @@ ha_innobase::innobase_read_and_init_auto_inc(
/* Play safe and also give in another way the hint to fetch
all columns in the key: */
- prebuilt->hint_no_need_to_fetch_extra_cols = FALSE;
+ prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS;
prebuilt->trx->mysql_n_tables_locked += 1;