summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorheikki@hundin.mysql.fi <>2002-03-21 18:03:09 +0200
committerheikki@hundin.mysql.fi <>2002-03-21 18:03:09 +0200
commite90a57aa49c79d75cabef38c764b5f81ba0288dc (patch)
tree8484c3bb65d40af0743b44a24a788dc2d5cf7d48 /sql
parent254df5fdd66989c404ff2f4253bf05afc2df53fa (diff)
downloadmariadb-git-e90a57aa49c79d75cabef38c764b5f81ba0288dc.tar.gz
Many files:
Merge InnoDB-3.23.50
Diffstat (limited to 'sql')
-rw-r--r--sql/ha_innobase.cc500
-rw-r--r--sql/ha_innobase.h3
2 files changed, 194 insertions, 309 deletions
diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc
index 2cdf15ce974..9159ef3f1c1 100644
--- a/sql/ha_innobase.cc
+++ b/sql/ha_innobase.cc
@@ -76,20 +76,34 @@ bool innodb_skip = 0;
uint innobase_init_flags = 0;
ulong innobase_cache_size = 0;
+/* The default values for the following, type long, start-up parameters
+are declared in mysqld.cc: */
+
long innobase_mirrored_log_groups, innobase_log_files_in_group,
innobase_log_file_size, innobase_log_buffer_size,
innobase_buffer_pool_size, innobase_additional_mem_pool_size,
innobase_file_io_threads, innobase_lock_wait_timeout,
- innobase_thread_concurrency, innobase_force_recovery;
+ innobase_thread_concurrency, innobase_force_recovery;
-char *innobase_data_home_dir, *innobase_data_file_path;
-char *innobase_log_group_home_dir, *innobase_log_arch_dir;
-char *innobase_unix_file_flush_method;
-my_bool innobase_flush_log_at_trx_commit, innobase_log_archive,
- innobase_use_native_aio, innobase_fast_shutdown;
+/* The default values for the following char* start-up parameters
+are determined in innobase_init below: */
/* innobase_data_file_path=ibdata:15,idata2:1,... */
+char* innobase_data_home_dir = NULL;
+char* innobase_data_file_path = NULL;
+char* innobase_log_group_home_dir = NULL;
+char* innobase_log_arch_dir = NULL;
+char* innobase_unix_file_flush_method = NULL;
+
+/* Below we have boolean-valued start-up parameters, and their default
+values */
+
+my_bool innobase_flush_log_at_trx_commit = FALSE;
+my_bool innobase_log_archive = FALSE;
+my_bool innobase_use_native_aio = FALSE;
+my_bool innobase_fast_shutdown = TRUE;
+
/* 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
@@ -332,227 +346,6 @@ ha_innobase::update_thd(
}
/*************************************************************************
-Reads the data files and their sizes from a character string given in
-the .cnf file. */
-static
-bool
-innobase_parse_data_file_paths_and_sizes(void)
-/*==========================================*/
- /* out: TRUE if ok, FALSE if parsing
- error */
-{
- char* str;
- char* endp;
- char* path;
- ulint size;
- ulint i = 0;
-
- str = innobase_data_file_path;
-
- /* First calculate the number of data files and check syntax:
- path:size[M];path:size[M]... . Note that a Windows path may
- contain a drive name and a ':'. */
-
- while (*str != '\0') {
- path = str;
-
- while ((*str != ':' && *str != '\0')
- || (*str == ':'
- && (*(str + 1) == '\\' || *(str + 1) == '/'))) {
- str++;
- }
-
- if (*str == '\0') {
- return(FALSE);
- }
-
- str++;
-
- size = strtoul(str, &endp, 10);
-
- str = endp;
-
- if ((*str != 'M') && (*str != 'G')) {
- size = size / (1024 * 1024);
- } else if (*str == 'G') {
- size = size * 1024;
- str++;
- } else {
- str++;
- }
-
- if (strlen(str) >= 6
- && *str == 'n'
- && *(str + 1) == 'e'
- && *(str + 2) == 'w') {
- str += 3;
- }
-
- if (strlen(str) >= 3
- && *str == 'r'
- && *(str + 1) == 'a'
- && *(str + 2) == 'w') {
- str += 3;
- }
-
- if (size == 0) {
- return(FALSE);
- }
-
- i++;
-
- if (*str == ';') {
- str++;
- } else if (*str != '\0') {
-
- return(FALSE);
- }
- }
-
- srv_data_file_names = (char**)ut_malloc(i * sizeof(void*));
- srv_data_file_sizes = (ulint*)ut_malloc(i * sizeof(ulint));
- srv_data_file_is_raw_partition = (ulint*)ut_malloc(i * sizeof(ulint));
-
- srv_n_data_files = i;
-
- /* Then store the actual values to our arrays */
-
- str = innobase_data_file_path;
- i = 0;
-
- while (*str != '\0') {
- path = str;
-
- /* Note that we must ignore the ':' in a Windows path */
-
- while ((*str != ':' && *str != '\0')
- || (*str == ':'
- && (*(str + 1) == '\\' || *(str + 1) == '/'))) {
- str++;
- }
-
- if (*str == ':') {
- /* Make path a null-terminated string */
- *str = '\0';
- str++;
- }
-
- size = strtoul(str, &endp, 10);
-
- str = endp;
-
- if ((*str != 'M') && (*str != 'G')) {
- size = size / (1024 * 1024);
- } else if (*str == 'G') {
- size = size * 1024;
- str++;
- } else {
- str++;
- }
-
- srv_data_file_is_raw_partition[i] = 0;
-
- if (strlen(str) >= 6
- && *str == 'n'
- && *(str + 1) == 'e'
- && *(str + 2) == 'w') {
- str += 3;
- srv_data_file_is_raw_partition[i] = SRV_NEW_RAW;
- }
-
- if (strlen(str) >= 3
- && *str == 'r'
- && *(str + 1) == 'a'
- && *(str + 2) == 'w') {
- str += 3;
-
- if (srv_data_file_is_raw_partition[i] == 0) {
- srv_data_file_is_raw_partition[i] = SRV_OLD_RAW;
- }
- }
-
- srv_data_file_names[i] = path;
- srv_data_file_sizes[i] = size;
-
- i++;
-
- if (*str == ';') {
- str++;
- }
- }
-
- return(TRUE);
-}
-
-/*************************************************************************
-Reads log group home directories from a character string given in
-the .cnf file. */
-static
-bool
-innobase_parse_log_group_home_dirs(void)
-/*====================================*/
- /* out: TRUE if ok, FALSE if parsing
- error */
-{
- char* str;
- char* path;
- ulint i = 0;
-
- str = innobase_log_group_home_dir;
-
- /* First calculate the number of directories and check syntax:
- path;path;... */
-
- while (*str != '\0') {
- path = str;
-
- while (*str != ';' && *str != '\0') {
- str++;
- }
-
- i++;
-
- if (*str == ';') {
- str++;
- } else if (*str != '\0') {
-
- return(FALSE);
- }
- }
-
- if (i != (ulint) innobase_mirrored_log_groups) {
-
- return(FALSE);
- }
-
- srv_log_group_home_dirs = (char**) ut_malloc(i * sizeof(void*));
-
- /* Then store the actual values to our array */
-
- str = innobase_log_group_home_dir;
- i = 0;
-
- while (*str != '\0') {
- path = str;
-
- while (*str != ';' && *str != '\0') {
- str++;
- }
-
- if (*str == ';') {
- *str = '\0';
- str++;
- }
-
- srv_log_group_home_dirs[i] = path;
-
- i++;
- }
-
- return(TRUE);
-}
-
-/*************************************************************************
Opens an InnoDB database. */
bool
@@ -565,7 +358,7 @@ innobase_init(void)
bool ret;
DBUG_ENTER("innobase_init");
-
+
if (specialflag & SPECIAL_NO_PRIOR) {
srv_set_thread_priorities = FALSE;
} else {
@@ -574,49 +367,62 @@ innobase_init(void)
}
/* Use current_dir if no paths are set */
- current_dir[0]=FN_CURLIB;
- current_dir[1]=FN_LIBCHAR;
- current_dir[2]=0;
+ current_dir[0] = FN_CURLIB;
+ current_dir[1] = FN_LIBCHAR;
+ current_dir[2] = 0;
/* Set InnoDB initialization parameters according to the values
read from MySQL .cnf file */
- if (!innobase_data_file_path)
- {
- fprintf(stderr,
+ if (!innobase_data_file_path) {
+ fprintf(stderr,
"Cannot initialize InnoDB as 'innodb_data_file_path' is not set.\n"
"If you do not want to use transactional InnoDB tables, add a line\n"
"skip-innodb\n"
"to the [mysqld] section of init parameters in your my.cnf\n"
"or my.ini. If you want to use InnoDB tables, add for example,\n"
- "innodb_data_file_path = ibdata1:30M\n"
+ "innodb_data_file_path = ibdata1:30M:autoextend\n"
"But to get good performance you should adjust for your hardware\n"
"the InnoDB startup options listed in section 2 at\n"
"http://www.innodb.com/ibman.html\n");
- innodb_skip=1;
- DBUG_RETURN(FALSE); // Continue without innobase
+ innodb_skip=1;
+ DBUG_RETURN(FALSE); /* Continue without InnoDB */
}
srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
current_dir);
- srv_logs_home = (char*) "";
srv_arch_dir = (innobase_log_arch_dir ? innobase_log_arch_dir :
current_dir);
- ret = innobase_parse_data_file_paths_and_sizes();
-
+ ret = (bool)
+ srv_parse_data_file_paths_and_sizes(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) {
- fprintf(stderr, "InnoDB: syntax error in innodb_data_file_path\n");
- DBUG_RETURN(TRUE);
+ fprintf(stderr,
+ "InnoDB: syntax error in innodb_data_file_path\n");
+ DBUG_RETURN(TRUE);
+ }
+
+ if (!innobase_log_group_home_dir) {
+ innobase_log_group_home_dir = current_dir;
}
- if (!innobase_log_group_home_dir)
- innobase_log_group_home_dir= current_dir;
- ret = innobase_parse_log_group_home_dirs();
+ ret = (bool)
+ srv_parse_log_group_home_dirs(innobase_log_group_home_dir,
+ &srv_log_group_home_dirs);
- if (ret == FALSE) {
- DBUG_RETURN(TRUE);
+ if (ret == FALSE || innobase_mirrored_log_groups != 1) {
+ fprintf(stderr,
+ "InnoDB: syntax error in innodb_log_group_home_dir\n"
+ "InnoDB: or a wrong number of mirrored log groups\n");
+
+ DBUG_RETURN(TRUE);
}
srv_unix_file_flush_method_str = (innobase_unix_file_flush_method ?
@@ -658,10 +464,11 @@ innobase_init(void)
if (err != DB_SUCCESS) {
- DBUG_RETURN(1);
+ DBUG_RETURN(1);
}
+
(void) hash_init(&innobase_open_tables,32,0,0,
- (hash_get_key) innobase_get_key,0,0);
+ (hash_get_key) innobase_get_key,0,0);
pthread_mutex_init(&innobase_mutex,MY_MUTEX_INIT_FAST);
DBUG_RETURN(0);
}
@@ -1340,33 +1147,43 @@ build_template(
clust_index = dict_table_get_first_index_noninline(prebuilt->table);
- if (!prebuilt->in_update_remember_pos) {
+ if (!prebuilt->hint_no_need_to_fetch_extra_cols) {
+ /* We have a hint that we should at least fetch all
+ columns in the key, or all columns in the table */
+
if (prebuilt->read_just_key) {
+ /* MySQL has instructed us that it is enough to
+ fetch the columns in the key */
+
fetch_all_in_key = TRUE;
} else {
/* We are building a temporary table: fetch all
- columns */
+ 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;
}
}
if (prebuilt->select_lock_type == LOCK_X) {
- /* TODO: should fix the code in sql_update so that we could do
- with fetching only the needed columns */
+ /* 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. */
templ_type = ROW_MYSQL_WHOLE_ROW;
}
if (templ_type == ROW_MYSQL_REC_FIELDS) {
+ /* In versions < 3.23.50 we always retrieved the clustered
+ index record if prebuilt->select_lock_type == LOCK_S,
+ but there is really not need for that, and in some cases
+ performance could be seriously degraded because the MySQL
+ optimizer did not know about our convention! */
- if (prebuilt->select_lock_type != LOCK_NONE) {
- /* Let index be the clustered index */
-
- index = clust_index;
- } else {
- index = prebuilt->index;
- }
+ index = prebuilt->index;
} else {
index = clust_index;
}
@@ -1462,12 +1279,6 @@ skip_field:
(index->table->cols + templ->col_no)->clust_pos;
}
}
-
- if (templ_type == ROW_MYSQL_REC_FIELDS
- && prebuilt->select_lock_type != LOCK_NONE) {
-
- prebuilt->need_to_access_clustered = TRUE;
- }
}
/************************************************************************
@@ -1500,7 +1311,9 @@ ha_innobase::write_row(
}
if (table->next_number_field && record == table->record[0]) {
-
+ /* This is the case where the table has an
+ auto-increment column */
+
/* Fetch the value the user possibly has set in the
autoincrement field */
@@ -1584,12 +1397,6 @@ ha_innobase::write_row(
}
}
- /* Set the 'in_update_remember_pos' flag to FALSE to
- make sure all columns are fetched in the select done by
- update_auto_increment */
-
- prebuilt->in_update_remember_pos = FALSE;
-
update_auto_increment();
if (auto_inc == 0) {
@@ -1613,7 +1420,7 @@ ha_innobase::write_row(
}
/* We have to set sql_stat_start to TRUE because
- update_auto_increment has called a select, and
+ update_auto_increment may have called a select, and
has reset that flag; row_insert_for_mysql has to
know to set the IX intention lock on the table, something
it only does at the start of each statement */
@@ -1853,9 +1660,7 @@ ha_innobase::update_row(
/* This is not a delete */
prebuilt->upd_node->is_delete = FALSE;
- if (!prebuilt->in_update_remember_pos) {
- assert(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
- }
+ assert(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
srv_conc_enter_innodb(prebuilt->trx);
@@ -1901,7 +1706,6 @@ ha_innobase::delete_row(
/* This is a delete */
prebuilt->upd_node->is_delete = TRUE;
- prebuilt->in_update_remember_pos = TRUE;
srv_conc_enter_innodb(prebuilt->trx);
@@ -2616,7 +2420,9 @@ ha_innobase::create(
/* Create the table definition in InnoDB */
- if (error = create_table_def(trx, form, norm_name)) {
+ error = create_table_def(trx, form, norm_name);
+
+ if (error) {
trx_commit_for_mysql(trx);
@@ -3203,14 +3009,60 @@ ha_innobase::update_table_comment(
pos += sprintf(pos, "InnoDB free: %lu kB",
(ulong) innobase_get_free_space());
- /* We assume 150 bytes of space to print info */
+ /* We assume 450 - length bytes of space to print info */
- dict_print_info_on_foreign_keys(pos, 500, prebuilt->table);
+ if (length < 450) {
+ dict_print_info_on_foreign_keys(FALSE, pos, 450 - length,
+ prebuilt->table);
+ }
return(str);
}
/***********************************************************************
+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 */
+{
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
+ char* str;
+
+ if (prebuilt == NULL) {
+ fprintf(stderr,
+"InnoDB: Error: cannot get create info for foreign keys\n");
+
+ return(NULL);
+ }
+
+ str = (char*)ut_malloc(10000);
+
+ str[0] = '\0';
+
+ dict_print_info_on_foreign_keys(TRUE, str, 9000, prebuilt->table);
+
+ return(str);
+}
+
+/***********************************************************************
+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(
+/*======================================*/
+ char* str) /* in, own: create info string to free */
+{
+ if (str) {
+ ut_free(str);
+ }
+}
+
+/***********************************************************************
Tells something additional to the handler about how to do things. */
int
@@ -3235,7 +3087,7 @@ ha_innobase::extra(
prebuilt->read_just_key = 0;
break;
case HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE:
- prebuilt->in_update_remember_pos = FALSE;
+ prebuilt->hint_no_need_to_fetch_extra_cols = FALSE;
break;
case HA_EXTRA_KEYREAD:
prebuilt->read_just_key = 1;
@@ -3282,7 +3134,7 @@ ha_innobase::external_lock(
trx = prebuilt->trx;
prebuilt->sql_stat_start = TRUE;
- prebuilt->in_update_remember_pos = TRUE;
+ prebuilt->hint_no_need_to_fetch_extra_cols = TRUE;
prebuilt->read_just_key = 0;
@@ -3301,6 +3153,16 @@ ha_innobase::external_lock(
thd->transaction.all.innodb_active_trans = 1;
trx->n_mysql_tables_in_use++;
+ if (thd->tx_isolation == 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_S;
+ }
+
if (prebuilt->select_lock_type != LOCK_NONE) {
trx->mysql_n_tables_locked++;
@@ -3407,8 +3269,8 @@ ha_innobase::store_lock(
lock_type == TL_READ_NO_INSERT) {
/* This is a SELECT ... IN SHARE MODE, or
we are doing a complex SQL statement like
- INSERT INTO ... SELECT ... and the logical logging
- requires the use of a locking read */
+ INSERT INTO ... SELECT ... and the logical logging (MySQL
+ binlog) requires the use of a locking read */
prebuilt->select_lock_type = LOCK_S;
} else {
@@ -3448,37 +3310,59 @@ ha_innobase::get_auto_increment()
/*=============================*/
/* out: the next auto-increment column value */
{
- row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
- longlong nr;
- int error;
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+ longlong nr;
+ int error;
+
+ /* Also SHOW TABLE STATUS calls this function. Previously, when we did
+ always read the max autoinc key value, setting x-locks, users were
+ surprised that SHOW TABLE STATUS could end up in a deadlock with
+ ordinary SQL queries. We avoid these deadlocks if the auto-inc
+ counter for the table has been initialized by fetching the value
+ from the table struct in dictionary cache. */
+
+ assert(prebuilt->table);
+
+ nr = dict_table_autoinc_read(prebuilt->table);
+
+ if (nr != 0) {
+
+ return(nr + 1);
+ }
+
+ (void) extra(HA_EXTRA_KEYREAD);
+ index_init(table->next_number_index);
+
+ /* We use an exclusive lock when we read the max key value from the
+ auto-increment column index. This is because then build_template will
+ advise InnoDB to fetch all columns. In SHOW TABLE STATUS the query
+ id of the auto-increment column is not changed, and previously InnoDB
+ did not fetch it, causing SHOW TABLE STATUS to show wrong values
+ for the autoinc column. */
- (void) extra(HA_EXTRA_KEYREAD);
- index_init(table->next_number_index);
+ prebuilt->select_lock_type = LOCK_X;
- /* We use an exclusive lock when we read the max key value from the
- auto-increment column index. This is because then build_template will
- advise InnoDB to fetch all columns. In SHOW TABLE STATUS the query
- id of the auto-increment column is not changed, and previously InnoDB
- did not fetch it, causing SHOW TABLE STATUS to show wrong values
- for the autoinc column. */
+ /* 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->select_lock_type = LOCK_X;
- prebuilt->trx->mysql_n_tables_locked += 1;
+ prebuilt->trx->mysql_n_tables_locked += 1;
- error=index_last(table->record[1]);
+ error = index_last(table->record[1]);
- if (error) {
- nr = 1;
- } else {
- nr = (longlong) table->next_number_field->
- val_int_offset(table->rec_buff_length) + 1;
- }
+ if (error) {
+ nr = 1;
+ } else {
+ nr = (longlong) table->next_number_field->
+ val_int_offset(table->rec_buff_length) + 1;
+ }
- (void) extra(HA_EXTRA_NO_KEYREAD);
+ (void) extra(HA_EXTRA_NO_KEYREAD);
- index_end();
+ index_end();
- return(nr);
+ return(nr);
}
#endif /* HAVE_INNOBASE_DB */
diff --git a/sql/ha_innobase.h b/sql/ha_innobase.h
index ec77cd1a70f..9f752dd2eda 100644
--- a/sql/ha_innobase.h
+++ b/sql/ha_innobase.h
@@ -154,7 +154,8 @@ class ha_innobase: public handler
int rename_table(const char* from, const char* to);
int check(THD* thd, HA_CHECK_OPT* check_opt);
char* update_table_comment(const char* comment);
-
+ char* get_foreign_key_create_info();
+ void free_foreign_key_create_info(char* str);
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
longlong get_auto_increment();