summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Docs/manual.texi14
-rw-r--r--include/errmsg.h1
-rw-r--r--include/violite.h3
-rw-r--r--innobase/dict/dict0crea.c18
-rw-r--r--innobase/dict/dict0dict.c219
-rw-r--r--innobase/include/log0recv.h1
-rw-r--r--innobase/include/row0mysql.h39
-rw-r--r--innobase/include/srv0srv.h3
-rw-r--r--innobase/include/trx0trx.h63
-rw-r--r--innobase/log/log0recv.c20
-rw-r--r--innobase/os/os0sync.c10
-rw-r--r--innobase/os/os0thread.c13
-rw-r--r--innobase/row/row0ins.c13
-rw-r--r--innobase/row/row0mysql.c98
-rw-r--r--innobase/row/row0purge.c30
-rw-r--r--innobase/row/row0undo.c20
-rw-r--r--innobase/row/row0upd.c28
-rw-r--r--innobase/srv/srv0srv.c17
-rw-r--r--innobase/srv/srv0start.c16
-rw-r--r--innobase/trx/trx0roll.c8
-rw-r--r--innobase/trx/trx0trx.c4
-rw-r--r--libmysql/errmsg.c9
-rw-r--r--libmysql/libmysql.c13
-rw-r--r--mysql-test/mysql-test-run.sh2
-rw-r--r--mysql-test/r/bdb_cache.result100
-rw-r--r--mysql-test/r/func_test.result14
-rw-r--r--mysql-test/r/func_time.result17
-rw-r--r--mysql-test/t/bdb_cache-master.opt1
-rw-r--r--mysql-test/t/bdb_cache.test50
-rw-r--r--mysql-test/t/func_test.test10
-rw-r--r--mysql-test/t/func_time.test19
-rw-r--r--sql/field.h1
-rw-r--r--sql/ha_innodb.cc64
-rw-r--r--sql/handler.cc3
-rw-r--r--sql/item_cmpfunc.cc1
-rw-r--r--sql/lock.cc7
-rw-r--r--sql/mysqld.cc15
-rw-r--r--sql/set_var.cc2
-rw-r--r--sql/sql_base.cc2
-rw-r--r--sql/sql_parse.cc8
-rw-r--r--vio/viossl.c46
-rw-r--r--vio/viosslfactories.c6
42 files changed, 769 insertions, 259 deletions
diff --git a/Docs/manual.texi b/Docs/manual.texi
index f3c790c8fb2..283ad00d80f 100644
--- a/Docs/manual.texi
+++ b/Docs/manual.texi
@@ -23510,17 +23510,21 @@ will be logged in the execution order.
Updates to non-transactional tables are stored in the binary log
immediately after execution. For transactional tables such as @code{BDB}
or @code{InnoDB} tables, all updates (@code{UPDATE}, @code{DELETE}
-or @code{INSERT}) that change tables are cached until a @code{COMMIT}.
+or @code{INSERT}) that change tables are cached until a @code{COMMIT} command
+is sent to the server. At this point mysqld writes the whole transaction to
+the binary log before the @code{COMMIT} is executed.
Every thread will, on start, allocate a buffer of @code{binlog_cache_size}
to buffer queries. If a query is bigger than this, the thread will open
-a temporary file to handle the bigger cache. The temporary file will
+a temporary file to store the transcation. The temporary file will
be deleted when the thread ends.
-The @code{max_binlog_cache_size} can be used to restrict the total size used
-to cache a multi-query transaction.
+The @code{max_binlog_cache_size} (default 4G) can be used to restrict
+the total size used to cache a multi-query transaction. If a transaction is
+bigger than this it will fail and roll back.
If you are using the update or binary log, concurrent inserts will
-not work together with @code{CREATE ... SELECT} and @code{INSERT ... SELECT}.
+be converted to normal inserts when using @code{CREATE ... SELECT} and
+@code{INSERT ... SELECT}.
This is to ensure that you can recreate an exact copy of your tables by
applying the log on a backup.
diff --git a/include/errmsg.h b/include/errmsg.h
index 76a57f47611..842d53c9303 100644
--- a/include/errmsg.h
+++ b/include/errmsg.h
@@ -61,3 +61,4 @@ extern const char *client_errors[]; /* Error messages */
#define CR_PROBE_SLAVE_HOSTS 2023
#define CR_PROBE_SLAVE_CONNECT 2024
#define CR_PROBE_MASTER_CONNECT 2025
+#define CR_SSL_CONNECTION_ERROR 2026
diff --git a/include/violite.h b/include/violite.h
index f4f40dcb64b..6c8ad1f4b69 100644
--- a/include/violite.h
+++ b/include/violite.h
@@ -174,7 +174,7 @@ struct st_VioSSLConnectorFd
SSL_METHOD* ssl_method_;
};
-void sslaccept(struct st_VioSSLAcceptorFd*, Vio*, long timeout);
+int sslaccept(struct st_VioSSLAcceptorFd*, Vio*, long timeout);
int sslconnect(struct st_VioSSLConnectorFd*, Vio*, long timeout);
struct st_VioSSLConnectorFd
@@ -231,7 +231,6 @@ struct st_vio
#ifdef HAVE_OPENSSL
SSL* ssl_;
- my_bool open_;
#endif /* HAVE_OPENSSL */
#endif /* HAVE_VIO */
};
diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c
index 60beeacf435..b0f84e5663a 100644
--- a/innobase/dict/dict0crea.c
+++ b/innobase/dict/dict0crea.c
@@ -1041,7 +1041,7 @@ dict_create_or_check_foreign_constraint_tables(void)
que_t* graph;
ulint error;
trx_t* trx;
- char* str;
+ char* str;
mutex_enter(&(dict_sys->mutex));
@@ -1060,20 +1060,24 @@ dict_create_or_check_foreign_constraint_tables(void)
return(DB_SUCCESS);
}
+ mutex_exit(&(dict_sys->mutex));
+
trx = trx_allocate_for_mysql();
trx->op_info = (char *) "creating foreign key sys tables";
+ row_mysql_lock_data_dictionary(trx);
+
if (table1) {
fprintf(stderr,
"InnoDB: dropping incompletely created SYS_FOREIGN table\n");
- row_drop_table_for_mysql((char *) "SYS_FOREIGN", trx, TRUE);
+ row_drop_table_for_mysql((char *) "SYS_FOREIGN", trx);
}
if (table2) {
fprintf(stderr,
"InnoDB: dropping incompletely created SYS_FOREIGN_COLS table\n");
- row_drop_table_for_mysql((char *) "SYS_FOREIGN_COLS",trx,TRUE);
+ row_drop_table_for_mysql((char *) "SYS_FOREIGN_COLS", trx);
}
fprintf(stderr,
@@ -1122,8 +1126,8 @@ dict_create_or_check_foreign_constraint_tables(void)
fprintf(stderr,
"InnoDB: dropping incompletely created SYS_FOREIGN tables\n");
- row_drop_table_for_mysql((char *) "SYS_FOREIGN", trx, TRUE);
- row_drop_table_for_mysql((char *) "SYS_FOREIGN_COLS",trx,TRUE);
+ row_drop_table_for_mysql((char *) "SYS_FOREIGN", trx);
+ row_drop_table_for_mysql((char *) "SYS_FOREIGN_COLS", trx);
error = DB_MUST_GET_MORE_FILE_SPACE;
}
@@ -1132,6 +1136,8 @@ dict_create_or_check_foreign_constraint_tables(void)
trx->op_info = (char *) "";
+ row_mysql_unlock_data_dictionary(trx);
+
trx_free_for_mysql(trx);
if (error == DB_SUCCESS) {
@@ -1139,8 +1145,6 @@ dict_create_or_check_foreign_constraint_tables(void)
"InnoDB: Foreign key constraint system tables created\n");
}
- mutex_exit(&(dict_sys->mutex));
-
return(error);
}
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c
index 2ee2c9d18a9..18f27602cf0 100644
--- a/innobase/dict/dict0dict.c
+++ b/innobase/dict/dict0dict.c
@@ -30,13 +30,16 @@ Created 1/8/1996 Heikki Tuuri
dict_sys_t* dict_sys = NULL; /* the dictionary system */
rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve
- this in X-mode, implicit or backround
+ this in X-mode; implicit or backround
operations purge, rollback, foreign
key checks reserve this in S-mode; we
cannot trust that MySQL protects
implicit or background operations
- from dropping a table: this is our
- mechanism */
+ a table drop since MySQL does not
+ know of them; therefore we need this;
+ NOTE: a transaction which reserves
+ this must keep book on the mode in
+ trx->dict_operation_lock_mode */
#define DICT_HEAP_SIZE 100 /* initial memory heap size when
creating a table or index object */
@@ -183,6 +186,58 @@ dict_foreign_free(
dict_foreign_t* foreign); /* in, own: foreign key struct */
/************************************************************************
+Checks if the database name in two table names is the same. */
+static
+ibool
+dict_tables_have_same_db(
+/*=====================*/
+ /* out: TRUE if same db name */
+ char* name1, /* in: table name in the form dbname '/' tablename */
+ char* name2) /* in: table name in the form dbname '/' tablename */
+{
+ ulint i;
+
+ for (i = 0; i < 100000; i++) {
+ if (name1[i] == '/' && name2[i] == '/') {
+
+ return(TRUE);
+ }
+
+ if (name1[i] != name2[i]) {
+
+ return(FALSE);
+ }
+ }
+
+ ut_a(0);
+
+ return(FALSE);
+}
+
+/************************************************************************
+Return the end of table name where we have removed dbname and '/'. */
+static
+char*
+dict_remove_db_name(
+/*================*/
+ /* out: table name */
+ char* name) /* in: table name in the form dbname '/' tablename */
+{
+ ulint i;
+
+ for (i = 0; i < 100000 ; i++) {
+ if (name[i] == '/') {
+
+ return(name + i + 1);
+ }
+ }
+
+ ut_a(0);
+
+ return(NULL);
+}
+
+/************************************************************************
Reserves the dictionary system mutex for MySQL. */
void
@@ -1926,7 +1981,8 @@ dict_scan_col(
old_ptr = ptr;
- while (!isspace(*ptr) && *ptr != ',' && *ptr != ')' && *ptr != '`') {
+ while (!isspace(*ptr) && *ptr != ',' && *ptr != ')' && *ptr != '`'
+ && *ptr != '\0') {
ptr++;
}
@@ -2000,7 +2056,7 @@ dict_scan_table_name(
old_ptr = ptr;
- while (!isspace(*ptr) && *ptr != '(' && *ptr != '`') {
+ while (!isspace(*ptr) && *ptr != '(' && *ptr != '`' && *ptr != '\0') {
if (*ptr == '.') {
dot_ptr = ptr;
}
@@ -2023,17 +2079,28 @@ dict_scan_table_name(
}
#ifdef __WIN__
ut_cpy_in_lower_case(second_table_name + i, old_ptr,
- ptr - old_ptr);
+ ptr - old_ptr);
#else
- ut_memcpy(second_table_name + i, old_ptr, ptr - old_ptr);
+ if (srv_lower_case_table_names) {
+ ut_cpy_in_lower_case(second_table_name + i, old_ptr,
+ ptr - old_ptr);
+ } else {
+ ut_memcpy(second_table_name + i, old_ptr,
+ ptr - old_ptr);
+ }
#endif
second_table_name[i + (ptr - old_ptr)] = '\0';
} else {
#ifdef __WIN__
ut_cpy_in_lower_case(second_table_name, old_ptr,
- ptr - old_ptr);
+ ptr - old_ptr);
#else
- ut_memcpy(second_table_name, old_ptr, ptr - old_ptr);
+ if (srv_lower_case_table_names) {
+ ut_cpy_in_lower_case(second_table_name, old_ptr,
+ ptr - old_ptr);
+ } else {
+ ut_memcpy(second_table_name, old_ptr, ptr - old_ptr);
+ }
#endif
second_table_name[dot_ptr - old_ptr] = '/';
second_table_name[ptr - old_ptr] = '\0';
@@ -2051,6 +2118,44 @@ dict_scan_table_name(
}
/*************************************************************************
+Skips one 'word', like an id. For the lexical definition of 'word', see the
+code below. */
+static
+char*
+dict_skip_word(
+/*===========*/
+ /* out: scanned to */
+ char* ptr, /* in: scanned to */
+ ibool* success)/* out: TRUE if success, FALSE if just spaces left in
+ string */
+{
+ *success = FALSE;
+
+ while (isspace(*ptr)) {
+ ptr++;
+ }
+
+ if (*ptr == '\0') {
+
+ return(ptr);
+ }
+
+ if (*ptr == '`') {
+ ptr++;
+ }
+
+ while (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && *ptr != '`'
+ && *ptr != '\0') {
+
+ ptr++;
+ }
+
+ *success = TRUE;
+
+ return(ptr);
+}
+
+/*************************************************************************
Returns the number of opening brackets '(' subtracted by the number
of closing brackets ')' between string and ptr. */
static
@@ -2119,7 +2224,6 @@ dict_create_foreign_constraints(
if (table == NULL) {
return(DB_ERROR);
}
-
loop:
ptr = dict_scan_to(ptr, (char *) "FOREIGN");
@@ -2148,7 +2252,19 @@ loop:
ptr = dict_accept(ptr, (char *) "(", &success);
if (!success) {
- goto loop;
+ /* MySQL allows also an index id before the '('; we
+ skip it */
+ ptr = dict_skip_word(ptr, &success);
+
+ if (!success) {
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ ptr = dict_accept(ptr, (char *) "(", &success);
+
+ if (!success) {
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
}
i = 0;
@@ -2223,6 +2339,7 @@ col_loop1:
if (!success) {
dict_foreign_free(foreign);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -2236,6 +2353,7 @@ col_loop2:
if (!success) {
dict_foreign_free(foreign);
+
return(DB_CANNOT_ADD_CONSTRAINT);
}
@@ -2263,14 +2381,20 @@ col_loop2:
ptr = dict_accept(ptr, "DELETE", &success);
if (!success) {
+ dict_foreign_free(foreign);
+
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ ptr = dict_accept(ptr, "RESTRICT", &success);
+ if (success) {
goto try_find_index;
}
ptr = dict_accept(ptr, "CASCADE", &success);
if (success) {
-
foreign->type = DICT_FOREIGN_ON_DELETE_CASCADE;
goto try_find_index;
@@ -2279,32 +2403,47 @@ col_loop2:
ptr = dict_accept(ptr, "SET", &success);
if (!success) {
-
- goto try_find_index;
+ dict_foreign_free(foreign);
+
+ return(DB_CANNOT_ADD_CONSTRAINT);
}
ptr = dict_accept(ptr, "NULL", &success);
- if (success) {
- for (j = 0; j < foreign->n_fields; j++) {
- if ((dict_index_get_nth_type(
+ if (!success) {
+ dict_foreign_free(foreign);
+
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
+ for (j = 0; j < foreign->n_fields; j++) {
+ if ((dict_index_get_nth_type(
foreign->foreign_index, j)->prtype)
& DATA_NOT_NULL) {
- /* It is not sensible to define SET NULL
- if the column is not allowed to be NULL! */
+ /* It is not sensible to define SET NULL
+ if the column is not allowed to be NULL! */
- dict_foreign_free(foreign);
- return(DB_CANNOT_ADD_CONSTRAINT);
- }
+ dict_foreign_free(foreign);
+
+ return(DB_CANNOT_ADD_CONSTRAINT);
}
+ }
- foreign->type = DICT_FOREIGN_ON_DELETE_SET_NULL;
+ foreign->type = DICT_FOREIGN_ON_DELETE_SET_NULL;
+
+try_find_index:
+ /* We check that there are no superfluous words like 'ON UPDATE ...'
+ which we do not support yet. */
- goto try_find_index;
+ ptr = dict_accept(ptr, (char *) "ON", &success);
+
+ if (success) {
+ dict_foreign_free(foreign);
+
+ return(DB_CANNOT_ADD_CONSTRAINT);
}
-try_find_index:
/* Try to find an index which contains the columns as the first fields
and in the right order, and the types are the same as in
foreign->foreign_index */
@@ -2351,6 +2490,7 @@ try_find_index:
referenced_table->referenced_list,
foreign);
}
+
goto loop;
}
@@ -2849,6 +2989,14 @@ dict_update_statistics_low(
ulint size;
ulint sum_of_index_sizes = 0;
+ /* If we have set a high innodb_force_recovery level, do not calculate
+ statistics, as a badly corrupted index can cause a crash in it. */
+
+ if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
+
+ return;
+ }
+
/* Find out the sizes of the indexes and how many different values
for the key they approximately have */
@@ -3152,16 +3300,25 @@ dict_print_info_on_foreign_keys_in_create_format(
}
}
- buf2 += sprintf(buf2, ") REFERENCES `%s` (",
+ if (dict_tables_have_same_db(table->name,
+ foreign->referenced_table_name)) {
+ /* Do not print the database name of the referenced
+ table */
+ buf2 += sprintf(buf2, ") REFERENCES `%s` (",
+ dict_remove_db_name(
+ foreign->referenced_table_name));
+ } else {
+ buf2 += sprintf(buf2, ") REFERENCES `%s` (",
foreign->referenced_table_name);
- /* Change the '/' in the table name to '.' */
+ /* Change the '/' in the table name to '.' */
- for (i = ut_strlen(buf); i > 0; i--) {
- if (buf[i] == '/') {
+ for (i = ut_strlen(buf); i > 0; i--) {
+ if (buf[i] == '/') {
- buf[i] = '.';
+ buf[i] = '.';
- break;
+ break;
+ }
}
}
diff --git a/innobase/include/log0recv.h b/innobase/include/log0recv.h
index baa2ba50c7d..7418e4abf1b 100644
--- a/innobase/include/log0recv.h
+++ b/innobase/include/log0recv.h
@@ -334,6 +334,7 @@ extern ibool recv_no_ibuf_operations;
extern ibool recv_needed_recovery;
extern ibool recv_is_making_a_backup;
+extern ulint recv_max_parsed_page_no;
/* Size of the parsing buffer; it must accommodate RECV_SCAN_SIZE many
times! */
diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h
index 8152c534f48..c72c905edf5 100644
--- a/innobase/include/row0mysql.h
+++ b/innobase/include/row0mysql.h
@@ -230,18 +230,35 @@ row_update_cascade_for_mysql(
or set null operation */
dict_table_t* table); /* in: table where we do the operation */
/*************************************************************************
-Locks the data dictionary exclusively for performing a table create
-operation. */
+Locks the data dictionary exclusively for performing a table create or other
+data dictionary modification operation. */
void
-row_mysql_lock_data_dictionary(void);
-/*================================*/
+row_mysql_lock_data_dictionary(
+/*===========================*/
+ trx_t* trx); /* in: transaction */
/*************************************************************************
-Unlocks the data dictionary exclusively lock. */
+Unlocks the data dictionary exclusive lock. */
void
-row_mysql_unlock_data_dictionary(void);
-/*==================================*/
+row_mysql_unlock_data_dictionary(
+/*=============================*/
+ trx_t* trx); /* in: transaction */
+/*************************************************************************
+Locks the data dictionary in shared mode from modifications, for performing
+foreign key check, rollback, or other operation invisible to MySQL. */
+
+void
+row_mysql_freeze_data_dictionary(
+/*=============================*/
+ trx_t* trx); /* in: transaction */
+/*************************************************************************
+Unlocks the data dictionary shared lock. */
+
+void
+row_mysql_unfreeze_data_dictionary(
+/*===============================*/
+ trx_t* trx); /* in: transaction */
/*************************************************************************
Does a table creation operation for MySQL. If the name of the created
table ends to characters INNODB_MONITOR, then this also starts
@@ -310,11 +327,9 @@ output by the master thread. */
int
row_drop_table_for_mysql(
/*=====================*/
- /* out: error code or DB_SUCCESS */
- char* name, /* in: table name */
- trx_t* trx, /* in: transaction handle */
- ibool has_dict_mutex);/* in: TRUE if the caller already owns the
- dictionary system mutex */
+ /* out: error code or DB_SUCCESS */
+ char* name, /* in: table name */
+ trx_t* trx); /* in: transaction handle */
/*************************************************************************
Drops a database for MySQL. */
diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h
index 4d2768cf109..ad6f71f7a3a 100644
--- a/innobase/include/srv0srv.h
+++ b/innobase/include/srv0srv.h
@@ -28,6 +28,9 @@ extern os_event_t srv_lock_timeout_thread_event;
at a time */
#define SRV_AUTO_EXTEND_INCREMENT (8 * ((1024 * 1024) / UNIV_PAGE_SIZE))
+/* This is set to TRUE if the MySQL user has set it in MySQL */
+extern ibool srv_lower_case_table_names;
+
/* Server parameters which are read from the initfile */
extern char* srv_data_home;
diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h
index 874b126e47c..1468ef449e7 100644
--- a/innobase/include/trx0trx.h
+++ b/innobase/include/trx0trx.h
@@ -386,9 +386,10 @@ struct trx_struct{
/* how many tables the current SQL
statement uses, except those
in consistent read */
- ibool has_dict_operation_lock;
- /* TRUE if the trx currently holds
- an s-lock on dict_operation_lock */
+ ibool dict_operation_lock_mode;
+ /* 0, RW_S_LATCH, or RW_X_LATCH:
+ the latch mode trx currently holds
+ on dict_operation_lock */
ibool has_search_latch;
/* TRUE if this trx has latched the
search system latch in S-mode */
@@ -427,34 +428,6 @@ struct trx_struct{
mysql_trx_list; /* list of transactions created for
MySQL */
/*------------------------------*/
- mutex_t undo_mutex; /* mutex protecting the fields in this
- section (down to undo_no_arr), EXCEPT
- last_sql_stat_start, which can be
- accessed only when we know that there
- cannot be any activity in the undo
- logs! */
- dulint undo_no; /* next undo log record number to
- assign */
- trx_savept_t last_sql_stat_start;
- /* undo_no when the last sql statement
- was started: in case of an error, trx
- is rolled back down to this undo
- number; see note at undo_mutex! */
- trx_rseg_t* rseg; /* rollback segment assigned to the
- transaction, or NULL if not assigned
- yet */
- trx_undo_t* insert_undo; /* pointer to the insert undo log, or
- NULL if no inserts performed yet */
- trx_undo_t* update_undo; /* pointer to the update undo log, or
- NULL if no update performed yet */
- dulint roll_limit; /* least undo number to undo during
- a rollback */
- ulint pages_undone; /* number of undo log pages undone
- since the last undo log truncation */
- trx_undo_arr_t* undo_no_arr; /* array of undo numbers of undo log
- records which are currently processed
- by a rollback operation */
- /*------------------------------*/
ulint error_state; /* 0 if no error, otherwise error
number */
void* error_info; /* if the error number indicates a
@@ -508,6 +481,34 @@ struct trx_struct{
/*------------------------------*/
mem_heap_t* read_view_heap; /* memory heap for the read view */
read_view_t* read_view; /* consistent read view or NULL */
+ /*------------------------------*/
+ mutex_t undo_mutex; /* mutex protecting the fields in this
+ section (down to undo_no_arr), EXCEPT
+ last_sql_stat_start, which can be
+ accessed only when we know that there
+ cannot be any activity in the undo
+ logs! */
+ dulint undo_no; /* next undo log record number to
+ assign */
+ trx_savept_t last_sql_stat_start;
+ /* undo_no when the last sql statement
+ was started: in case of an error, trx
+ is rolled back down to this undo
+ number; see note at undo_mutex! */
+ trx_rseg_t* rseg; /* rollback segment assigned to the
+ transaction, or NULL if not assigned
+ yet */
+ trx_undo_t* insert_undo; /* pointer to the insert undo log, or
+ NULL if no inserts performed yet */
+ trx_undo_t* update_undo; /* pointer to the update undo log, or
+ NULL if no update performed yet */
+ dulint roll_limit; /* least undo number to undo during
+ a rollback */
+ ulint pages_undone; /* number of undo log pages undone
+ since the last undo log truncation */
+ trx_undo_arr_t* undo_no_arr; /* array of undo numbers of undo log
+ records which are currently processed
+ by a rollback operation */
};
#define TRX_MAX_N_THREADS 32 /* maximum number of concurrent
diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c
index 1223f9b6041..0fcf32ad99e 100644
--- a/innobase/log/log0recv.c
+++ b/innobase/log/log0recv.c
@@ -69,6 +69,8 @@ ulint recv_previous_parsed_rec_type = 999999;
ulint recv_previous_parsed_rec_offset = 0;
ulint recv_previous_parsed_rec_is_multi = 0;
+ulint recv_max_parsed_page_no = 0;
+
/************************************************************
Creates the recovery system. */
@@ -141,7 +143,13 @@ recv_sys_empty_hash(void)
/*=====================*/
{
ut_ad(mutex_own(&(recv_sys->mutex)));
- ut_a(recv_sys->n_addrs == 0);
+ if (recv_sys->n_addrs != 0) {
+ fprintf(stderr,
+"InnoDB: Error: %lu pages with log records were left unprocessed!\n"
+"InnoDB: Maximum page number with log records on it %lu\n",
+ recv_sys->n_addrs, recv_max_parsed_page_no);
+ ut_a(0);
+ }
hash_table_free(recv_sys->addr_hash);
mem_heap_empty(recv_sys->heap);
@@ -1361,6 +1369,12 @@ recv_apply_log_recs_for_backup(
n_pages_total += file_sizes[i];
}
+ if (recv_max_parsed_page_no >= n_pages_total) {
+ printf(
+"InnoDB: Error: tablespace size %lu pages, but a log record on page %lu!\n",
+ n_pages_total, recv_max_parsed_page_no);
+ }
+
printf(
"InnoDB: Starting an apply batch of log records to the database...\n"
"InnoDB: Progress in percents: ");
@@ -1701,6 +1715,10 @@ recv_parse_log_rec(
return(0);
}
+ if (*page_no > recv_max_parsed_page_no) {
+ recv_max_parsed_page_no = *page_no;
+ }
+
return(new_ptr - ptr);
}
diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c
index 14677ede20f..bac1f23a1af 100644
--- a/innobase/os/os0sync.c
+++ b/innobase/os/os0sync.c
@@ -66,8 +66,12 @@ os_event_create(
event = ut_malloc(sizeof(struct os_event_struct));
os_fast_mutex_init(&(event->os_mutex));
- pthread_cond_init(&(event->cond_var), NULL);
+#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
+ pthread_cond_init(&(event->cond_var), pthread_condattr_default);
+#else
+ pthread_cond_init(&(event->cond_var), NULL);
+#endif
event->is_set = FALSE;
return(event);
@@ -441,8 +445,12 @@ os_fast_mutex_init(
InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
#else
+#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
+ pthread_mutex_init(fast_mutex, pthread_mutexattr_default);
+#else
pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST);
#endif
+#endif
}
/**************************************************************
diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c
index 48aea4b8abb..30404c4e66b 100644
--- a/innobase/os/os0thread.c
+++ b/innobase/os/os0thread.c
@@ -126,8 +126,10 @@ os_thread_create(
os_thread_t pthread;
pthread_attr_t attr;
+#if !(defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10))
pthread_attr_init(&attr);
-
+#endif
+
#ifdef UNIV_AIX
/* We must make sure a thread stack is at least 32 kB, otherwise
InnoDB might crash; we do not know if the default stack size on
@@ -142,16 +144,21 @@ os_thread_create(
exit(1);
}
#endif
- ret = pthread_create(&pthread, &attr, start_f, arg);
+#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
+ ret = pthread_create(&pthread, pthread_attr_default, start_f, arg);
+#else
+ ret = pthread_create(&pthread, &attr, start_f, arg);
+#endif
if (ret) {
fprintf(stderr,
"InnoDB: Error: pthread_create returned %d\n", ret);
exit(1);
}
+#if !(defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10))
pthread_attr_destroy(&attr);
-
+#endif
if (srv_set_thread_priorities) {
my_pthread_setprio(pthread, srv_query_thread_priority);
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index 4e8b487a0f1..d0a5cfec604 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -643,7 +643,7 @@ row_ins_check_foreign_constraint(
run_again:
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_SHARED));
-
+
err = DB_SUCCESS;
if (thr_get_trx(thr)->check_foreigns == FALSE) {
@@ -880,21 +880,16 @@ row_ins_check_foreign_constraints(
trx);
}
- if (!trx->has_dict_operation_lock) {
+ if (0 == trx->dict_operation_lock_mode) {
got_s_lock = TRUE;
- rw_lock_s_lock(&dict_operation_lock);
-
- trx->has_dict_operation_lock = TRUE;
+ row_mysql_freeze_data_dictionary(trx);
}
err = row_ins_check_foreign_constraint(TRUE, foreign,
table, index, entry, thr);
if (got_s_lock) {
-
- rw_lock_s_unlock(&dict_operation_lock);
-
- trx->has_dict_operation_lock = FALSE;
+ row_mysql_unfreeze_data_dictionary(trx);
}
if (err != DB_SUCCESS) {
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 6fde57eb75a..b109b785a45 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -1134,32 +1134,73 @@ row_mysql_recover_tmp_table(
}
/*************************************************************************
-Locks the data dictionary exclusively for performing a table create
-operation. */
+Locks the data dictionary in shared mode from modifications, for performing
+foreign key check, rollback, or other operation invisible to MySQL. */
void
-row_mysql_lock_data_dictionary(void)
-/*================================*/
+row_mysql_freeze_data_dictionary(
+/*=============================*/
+ trx_t* trx) /* in: transaction */
+{
+ ut_a(trx->dict_operation_lock_mode == 0);
+
+ rw_lock_s_lock(&dict_operation_lock);
+
+ trx->dict_operation_lock_mode = RW_S_LATCH;
+}
+
+/*************************************************************************
+Unlocks the data dictionary shared lock. */
+
+void
+row_mysql_unfreeze_data_dictionary(
+/*===============================*/
+ trx_t* trx) /* in: transaction */
{
+ ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
+
+ rw_lock_s_unlock(&dict_operation_lock);
+
+ trx->dict_operation_lock_mode = 0;
+}
+
+/*************************************************************************
+Locks the data dictionary exclusively for performing a table create or other
+data dictionary modification operation. */
+
+void
+row_mysql_lock_data_dictionary(
+/*===========================*/
+ trx_t* trx) /* in: transaction */
+{
+ ut_a(trx->dict_operation_lock_mode == 0);
+
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks or lock waits can occur then in these operations */
rw_lock_x_lock(&dict_operation_lock);
+ trx->dict_operation_lock_mode = RW_X_LATCH;
+
mutex_enter(&(dict_sys->mutex));
}
/*************************************************************************
-Unlocks the data dictionary exclusively lock. */
+Unlocks the data dictionary exclusive lock. */
void
-row_mysql_unlock_data_dictionary(void)
-/*==================================*/
+row_mysql_unlock_data_dictionary(
+/*=============================*/
+ trx_t* trx) /* in: transaction */
{
+ ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
+
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
mutex_exit(&(dict_sys->mutex));
rw_lock_x_unlock(&dict_operation_lock);
+
+ trx->dict_operation_lock_mode = 0;
}
/*************************************************************************
@@ -1183,6 +1224,7 @@ row_create_table_for_mysql(
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
+ ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
ut_ad(mutex_own(&(dict_sys->mutex)));
if (srv_created_new_raw) {
@@ -1331,7 +1373,7 @@ row_create_table_for_mysql(
fprintf(stderr,
"InnoDB: Warning: cannot create table %s because tablespace full\n",
table->name);
- row_drop_table_for_mysql(table->name, trx, TRUE);
+ row_drop_table_for_mysql(table->name, trx);
} else {
ut_a(err == DB_DUPLICATE_KEY);
@@ -1425,7 +1467,7 @@ row_create_index_for_mysql(
trx_general_rollback_for_mysql(trx, FALSE, NULL);
- row_drop_table_for_mysql(index->table_name, trx, TRUE);
+ row_drop_table_for_mysql(index->table_name, trx);
trx->error_state = DB_SUCCESS;
}
@@ -1499,7 +1541,7 @@ row_table_add_foreign_constraints(
trx_general_rollback_for_mysql(trx, FALSE, NULL);
- row_drop_table_for_mysql(name, trx, TRUE);
+ row_drop_table_for_mysql(name, trx);
trx->error_state = DB_SUCCESS;
}
@@ -1530,7 +1572,7 @@ row_drop_table_for_mysql_in_background(
name); */
/* Drop the table in InnoDB */
- error = row_drop_table_for_mysql(name, trx, FALSE);
+ error = row_drop_table_for_mysql(name, trx);
if (error != DB_SUCCESS) {
fprintf(stderr,
@@ -1689,9 +1731,7 @@ row_drop_table_for_mysql(
/*=====================*/
/* out: error code or DB_SUCCESS */
char* name, /* in: table name */
- trx_t* trx, /* in: transaction handle */
- ibool has_dict_mutex) /* in: TRUE if the caller already owns the
- dictionary system mutex */
+ trx_t* trx) /* in: transaction handle */
{
dict_table_t* table;
que_thr_t* thr;
@@ -1703,6 +1743,7 @@ row_drop_table_for_mysql(
ulint namelen;
ulint keywordlen;
ulint rounds = 0;
+ ibool locked_dictionary = FALSE;
char buf[10000];
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
@@ -1846,12 +1887,13 @@ row_drop_table_for_mysql(
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
- if (!has_dict_mutex) {
+ if (trx->dict_operation_lock_mode != RW_X_LATCH) {
/* Prevent foreign key checks etc. while we are dropping the
table */
- rw_lock_x_lock(&dict_operation_lock);
- mutex_enter(&(dict_sys->mutex));
+ row_mysql_lock_data_dictionary(trx);
+
+ locked_dictionary = TRUE;
}
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -1948,9 +1990,8 @@ row_drop_table_for_mysql(
}
funct_exit:
- if (!has_dict_mutex) {
- mutex_exit(&(dict_sys->mutex));
- rw_lock_x_unlock(&dict_operation_lock);
+ if (locked_dictionary) {
+ row_mysql_unlock_data_dictionary(trx);
}
que_graph_free(graph);
@@ -1986,8 +2027,7 @@ row_drop_database_for_mysql(
trx_start_if_not_started(trx);
loop:
- rw_lock_x_lock(&dict_operation_lock);
- mutex_enter(&(dict_sys->mutex));
+ row_mysql_lock_data_dictionary(trx);
while ((table_name = dict_get_first_table_name_in_db(name))) {
ut_a(memcmp(table_name, name, strlen(name)) == 0);
@@ -2000,8 +2040,7 @@ loop:
the table */
if (table->n_mysql_handles_opened > 0) {
- mutex_exit(&(dict_sys->mutex));
- rw_lock_x_unlock(&dict_operation_lock);
+ row_mysql_unlock_data_dictionary(trx);
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -2016,7 +2055,7 @@ loop:
goto loop;
}
- err = row_drop_table_for_mysql(table_name, trx, TRUE);
+ err = row_drop_table_for_mysql(table_name, trx);
mem_free(table_name);
@@ -2028,8 +2067,7 @@ loop:
}
}
- mutex_exit(&(dict_sys->mutex));
- rw_lock_x_unlock(&dict_operation_lock);
+ row_mysql_unlock_data_dictionary(trx);
trx_commit_for_mysql(trx);
@@ -2166,8 +2204,7 @@ row_rename_table_for_mysql(
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
- rw_lock_x_lock(&dict_operation_lock);
- mutex_enter(&(dict_sys->mutex));
+ row_mysql_lock_data_dictionary(trx);
table = dict_table_get_low(old_name);
@@ -2249,8 +2286,7 @@ row_rename_table_for_mysql(
}
}
funct_exit:
- mutex_exit(&(dict_sys->mutex));
- rw_lock_x_unlock(&dict_operation_lock);
+ row_mysql_unlock_data_dictionary(trx);
que_graph_free(graph);
diff --git a/innobase/row/row0purge.c b/innobase/row/row0purge.c
index 3d9ae6aad8b..b64003f22d4 100644
--- a/innobase/row/row0purge.c
+++ b/innobase/row/row0purge.c
@@ -24,6 +24,7 @@ Created 3/14/1997 Heikki Tuuri
#include "row0row.h"
#include "row0upd.h"
#include "row0vers.h"
+#include "row0mysql.h"
#include "log0log.h"
/************************************************************************
@@ -454,8 +455,8 @@ ibool
row_purge_parse_undo_rec(
/*=====================*/
/* out: TRUE if purge operation required:
- NOTE that then the CALLER must s-unlock
- dict_operation_lock! */
+ NOTE that then the CALLER must unfreeze
+ data dictionary! */
purge_node_t* node, /* in: row undo node */
ibool* updated_extern,
/* out: TRUE if an externally stored field
@@ -464,6 +465,7 @@ row_purge_parse_undo_rec(
{
dict_index_t* clust_index;
byte* ptr;
+ trx_t* trx;
dulint undo_no;
dulint table_id;
dulint trx_id;
@@ -473,6 +475,8 @@ row_purge_parse_undo_rec(
ulint cmpl_info;
ut_ad(node && thr);
+
+ trx = thr_get_trx(thr);
ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info,
updated_extern, &undo_no, &table_id);
@@ -498,17 +502,18 @@ row_purge_parse_undo_rec(
/* Prevent DROP TABLE etc. from running when we are doing the purge
for this row */
- rw_lock_s_lock(&dict_operation_lock);
- mutex_enter(&(dict_sys->mutex));
+ row_mysql_freeze_data_dictionary(trx);
- node->table = dict_table_get_on_id_low(table_id, thr_get_trx(thr));
+ mutex_enter(&(dict_sys->mutex));
- mutex_exit(&(dict_sys->mutex));
+ node->table = dict_table_get_on_id_low(table_id, thr_get_trx(thr));
+ mutex_exit(&(dict_sys->mutex));
+
if (node->table == NULL) {
/* The table has been dropped: no need to do purge */
- rw_lock_s_unlock(&dict_operation_lock);
+ row_mysql_unfreeze_data_dictionary(trx);
return(FALSE);
}
@@ -518,7 +523,7 @@ row_purge_parse_undo_rec(
if (clust_index == NULL) {
/* The table was corrupt in the data dictionary */
- rw_lock_s_unlock(&dict_operation_lock);
+ row_mysql_unfreeze_data_dictionary(trx);
return(FALSE);
}
@@ -556,9 +561,12 @@ row_purge(
dulint roll_ptr;
ibool purge_needed;
ibool updated_extern;
+ trx_t* trx;
ut_ad(node && thr);
+ trx = thr_get_trx(thr);
+
node->undo_rec = trx_purge_fetch_next_rec(&roll_ptr,
&(node->reservation),
node->heap);
@@ -577,8 +585,8 @@ row_purge(
} else {
purge_needed = row_purge_parse_undo_rec(node, &updated_extern,
thr);
- /* If purge_needed == TRUE, we must also remember to unlock
- dict_operation_lock! */
+ /* If purge_needed == TRUE, we must also remember to unfreeze
+ data dictionary! */
}
if (purge_needed) {
@@ -600,7 +608,7 @@ row_purge(
btr_pcur_close(&(node->pcur));
}
- rw_lock_s_unlock(&dict_operation_lock);
+ row_mysql_unfreeze_data_dictionary(trx);
}
/* Do some cleanup */
diff --git a/innobase/row/row0undo.c b/innobase/row/row0undo.c
index 6f1cfc4db9f..01b0b1ab41e 100644
--- a/innobase/row/row0undo.c
+++ b/innobase/row/row0undo.c
@@ -24,6 +24,7 @@ Created 1/8/1997 Heikki Tuuri
#include "row0row.h"
#include "row0uins.h"
#include "row0umod.h"
+#include "row0mysql.h"
#include "srv0srv.h"
/* How to undo row operations?
@@ -204,6 +205,7 @@ row_undo(
ulint err;
trx_t* trx;
dulint roll_ptr;
+ ibool froze_data_dict = FALSE;
ut_ad(node && thr);
@@ -256,13 +258,13 @@ row_undo(
/* Prevent DROP TABLE etc. while we are rolling back this row.
If we are doing a TABLE CREATE or some other dictionary operation,
then we already have dict_operation_lock locked in x-mode. Do not
- try to lock again in s-mode, because that would cause a hang.
-
- TODO: keep track when trx exactly has the latch locked!!!
- TODO: trx->dict_operation tells it only in some cases!!! */
-
- if (!trx->dict_operation) {
- rw_lock_s_lock(&dict_operation_lock);
+ try to lock again in s-mode, because that would cause a hang. */
+
+ if (trx->dict_operation_lock_mode == 0) {
+
+ row_mysql_freeze_data_dictionary(trx);
+
+ froze_data_dict = TRUE;
}
if (node->state == UNDO_NODE_INSERT) {
@@ -275,9 +277,9 @@ row_undo(
err = row_undo_mod(node, thr);
}
- if (!trx->dict_operation) {
+ if (froze_data_dict) {
- rw_lock_s_unlock(&dict_operation_lock);
+ row_mysql_unfreeze_data_dictionary(trx);
}
/* Do some cleanup */
diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c
index 0be4f901d16..1231c94da63 100644
--- a/innobase/row/row0upd.c
+++ b/innobase/row/row0upd.c
@@ -89,14 +89,16 @@ row_upd_index_is_referenced(
{
dict_table_t* table = index->table;
dict_foreign_t* foreign;
+ ibool froze_data_dict = FALSE;
if (!UT_LIST_GET_FIRST(table->referenced_list)) {
return(FALSE);
}
- if (!trx->has_dict_operation_lock) {
- rw_lock_s_lock(&dict_operation_lock);
+ if (trx->dict_operation_lock_mode == 0) {
+ row_mysql_freeze_data_dictionary(trx);
+ froze_data_dict = TRUE;
}
foreign = UT_LIST_GET_FIRST(table->referenced_list);
@@ -104,8 +106,8 @@ row_upd_index_is_referenced(
while (foreign) {
if (foreign->referenced_index == index) {
- if (!trx->has_dict_operation_lock) {
- rw_lock_s_unlock(&dict_operation_lock);
+ if (froze_data_dict) {
+ row_mysql_unfreeze_data_dictionary(trx);
}
return(TRUE);
@@ -114,8 +116,8 @@ row_upd_index_is_referenced(
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
}
- if (!trx->has_dict_operation_lock) {
- rw_lock_s_unlock(&dict_operation_lock);
+ if (froze_data_dict) {
+ row_mysql_unfreeze_data_dictionary(trx);
}
return(FALSE);
@@ -162,12 +164,10 @@ row_upd_check_references_constraints(
mtr_start(mtr);
- if (!trx->has_dict_operation_lock) {
+ if (trx->dict_operation_lock_mode == 0) {
got_s_lock = TRUE;
- rw_lock_s_lock(&dict_operation_lock);
-
- trx->has_dict_operation_lock = TRUE;
+ row_mysql_freeze_data_dictionary(trx);
}
foreign = UT_LIST_GET_FIRST(table->referenced_list);
@@ -211,10 +211,7 @@ row_upd_check_references_constraints(
if (err != DB_SUCCESS) {
if (got_s_lock) {
- rw_lock_s_unlock(
- &dict_operation_lock);
- trx->has_dict_operation_lock
- = FALSE;
+ row_mysql_unfreeze_data_dictionary(trx);
}
mem_heap_free(heap);
@@ -227,8 +224,7 @@ row_upd_check_references_constraints(
}
if (got_s_lock) {
- rw_lock_s_unlock(&dict_operation_lock);
- trx->has_dict_operation_lock = FALSE;
+ row_mysql_unfreeze_data_dictionary(trx);
}
mem_heap_free(heap);
diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c
index 11e45df4ce3..51d7878fd29 100644
--- a/innobase/srv/srv0srv.c
+++ b/innobase/srv/srv0srv.c
@@ -51,6 +51,10 @@ Created 10/8/1995 Heikki Tuuri
#include "srv0start.h"
#include "row0mysql.h"
+/* This is set to TRUE if the MySQL user has set it in MySQL; currently
+affects only FOREIGN KEY definition parsing */
+ibool srv_lower_case_table_names = FALSE;
+
/* Buffer which can be used in printing fatal error messages */
char srv_fatal_errbuf[5000];
@@ -2064,6 +2068,7 @@ srv_suspend_mysql_thread(
os_event_t event;
double wait_time;
trx_t* trx;
+ ibool had_dict_lock = FALSE;
ut_ad(!mutex_own(&kernel_mutex));
@@ -2107,18 +2112,22 @@ srv_suspend_mysql_thread(
srv_conc_force_exit_innodb(thr_get_trx(thr));
/* Release possible foreign key check latch */
- if (trx->has_dict_operation_lock) {
+ if (trx->dict_operation_lock_mode == RW_S_LATCH) {
+
+ had_dict_lock = TRUE;
- rw_lock_s_unlock(&dict_operation_lock);
+ row_mysql_unfreeze_data_dictionary(trx);
}
+ ut_a(trx->dict_operation_lock_mode == 0);
+
/* Wait for the release */
os_event_wait(event);
- if (trx->has_dict_operation_lock) {
+ if (had_dict_lock) {
- rw_lock_s_lock(&dict_operation_lock);
+ row_mysql_freeze_data_dictionary(trx);
}
/* Return back inside InnoDB */
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c
index cad946b1e54..d006b4ec915 100644
--- a/innobase/srv/srv0start.c
+++ b/innobase/srv/srv0start.c
@@ -1380,7 +1380,7 @@ innobase_start_or_create_for_mysql(void)
if (0 != os_fast_mutex_trylock(&srv_os_test_mutex)) {
fprintf(stderr,
"InnoDB: Error: pthread_mutex_trylock returns an unexpected value on\n"
- "InnoDB: success! Cannot continue.\n");
+"InnoDB: success! Cannot continue.\n");
exit(1);
}
@@ -1390,11 +1390,17 @@ innobase_start_or_create_for_mysql(void)
os_fast_mutex_unlock(&srv_os_test_mutex);
- if (srv_print_verbose_log)
- {
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: Started\n");
+ if (srv_print_verbose_log) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Started\n");
}
+
+ if (srv_force_recovery > 0) {
+ fprintf(stderr,
+ "InnoDB: !!! innodb_force_recovery is set to %lu !!!\n",
+ srv_force_recovery);
+ }
+
return((int) DB_SUCCESS);
}
diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c
index 4c2ee5dc9be..1f0e0c58ac7 100644
--- a/innobase/trx/trx0roll.c
+++ b/innobase/trx/trx0roll.c
@@ -254,7 +254,7 @@ loop:
mutex_exit(&kernel_mutex);
if (trx->dict_operation) {
- mutex_enter(&(dict_sys->mutex));
+ row_mysql_lock_data_dictionary(trx);
}
que_run_threads(thr);
@@ -290,14 +290,14 @@ loop:
fprintf(stderr,
"InnoDB: Table found: dropping table %s in recovery\n", table->name);
- err = row_drop_table_for_mysql(table->name, trx,
- TRUE);
+ err = row_drop_table_for_mysql(table->name, trx);
+
ut_a(err == (int) DB_SUCCESS);
}
}
if (trx->dict_operation) {
- mutex_exit(&(dict_sys->mutex));
+ row_mysql_unlock_data_dictionary(trx);
}
fprintf(stderr, "InnoDB: Rolling back of trx id %lu %lu completed\n",
diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c
index 7566fe1839e..9f711890f60 100644
--- a/innobase/trx/trx0trx.c
+++ b/innobase/trx/trx0trx.c
@@ -134,7 +134,7 @@ trx_create(
trx->lock_heap = mem_heap_create_in_buffer(256);
UT_LIST_INIT(trx->trx_locks);
- trx->has_dict_operation_lock = FALSE;
+ trx->dict_operation_lock_mode = 0;
trx->has_search_latch = FALSE;
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
@@ -261,6 +261,8 @@ trx_free(
ut_a(!trx->has_search_latch);
ut_a(!trx->auto_inc_lock);
+ ut_a(trx->dict_operation_lock_mode == 0);
+
if (trx->lock_heap) {
mem_heap_free(trx->lock_heap);
}
diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c
index 3fdb9c0ddc6..47d19281a04 100644
--- a/libmysql/errmsg.c
+++ b/libmysql/errmsg.c
@@ -49,7 +49,8 @@ const char *client_errors[]=
"Error on SHOW SLAVE STATUS:",
"Error on SHOW SLAVE HOSTS:",
"Error connecting to slave:",
- "Error connecting to master:"
+ "Error connecting to master:",
+ "SSL connection error"
};
/* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */
@@ -82,7 +83,8 @@ const char *client_errors[]=
"Error on SHOW SLAVE STATUS:",
"Error on SHOW SLAVE HOSTS:",
"Error connecting to slave:",
- "Error connecting to master:"
+ "Error connecting to master:",
+ "SSL connection error"
};
#else /* ENGLISH */
@@ -113,7 +115,8 @@ const char *client_errors[]=
"Error on SHOW SLAVE STATUS:",
"Error on SHOW SLAVE HOSTS:",
"Error connecting to slave:",
- "Error connecting to master:"
+ "Error connecting to master:",
+ "SSL connection error"
};
#endif
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index c1d8dd6283f..c9fb2f84a3c 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -1872,15 +1872,18 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
options->ssl_capath,
options->ssl_cipher)))
{
- /* TODO: Change to SSL error */
- net->last_errno= CR_SERVER_LOST;
+ net->last_errno= CR_SSL_CONNECTION_ERROR;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
DBUG_PRINT("info", ("IO layer change in progress..."));
- /* TODO: Add proper error checking here, with return error message */
- sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd),
- mysql->net.vio, (long) (mysql->options.connect_timeout));
+ if(sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd),
+ mysql->net.vio, (long) (mysql->options.connect_timeout)))
+ {
+ net->last_errno= CR_SSL_CONNECTION_ERROR;
+ strmov(net->last_error,ER(net->last_errno));
+ goto error;
+ }
DBUG_PRINT("info", ("IO layer change done!"));
}
#endif /* HAVE_OPENSSL */
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index ac312af02cb..4317ba0e749 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -468,7 +468,7 @@ fi
MYSQL_TEST_ARGS="--no-defaults --socket=$MASTER_MYSOCK --database=$DB \
--user=$DBUSER --password=$DBPASSWD --silent -v --skip-safemalloc \
- --tmpdir=$MYSQL_TMP_DIR"
+ --tmpdir=$MYSQL_TMP_DIR --port=$MASTER_MYPORT"
MYSQL_TEST_BIN=$MYSQL_TEST
MYSQL_TEST="$MYSQL_TEST $MYSQL_TEST_ARGS"
GDB_CLIENT_INIT=$MYSQL_TMP_DIR/gdbinit.client
diff --git a/mysql-test/r/bdb_cache.result b/mysql-test/r/bdb_cache.result
new file mode 100644
index 00000000000..e5c6923162a
--- /dev/null
+++ b/mysql-test/r/bdb_cache.result
@@ -0,0 +1,100 @@
+drop table if exists t1, t2, t3;
+flush status;
+set autocommit=0;
+create table t1 (a int not null) type=bdb;
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+drop table t1;
+commit;
+set autocommit=1;
+begin;
+create table t1 (a int not null) type=bdb;
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+drop table t1;
+commit;
+create table t1 (a int not null) type=bdb;
+create table t2 (a int not null) type=bdb;
+create table t3 (a int not null) type=bdb;
+insert into t1 values (1),(2);
+insert into t2 values (1),(2);
+insert into t3 values (1),(2);
+select * from t1;
+a
+1
+2
+select * from t2;
+a
+1
+2
+select * from t3;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+begin;
+select * from t1;
+a
+1
+2
+select * from t2;
+a
+1
+2
+select * from t3;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+insert into t1 values (3);
+insert into t2 values (3);
+insert into t1 values (4);
+select * from t1;
+a
+1
+2
+3
+4
+select * from t2;
+a
+1
+2
+3
+select * from t3;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+commit;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result
index ef93096478f..8cfae44b9dd 100644
--- a/mysql-test/r/func_test.result
+++ b/mysql-test/r/func_test.result
@@ -46,20 +46,6 @@ select 3 ^ 11, 1 ^ 1, 1 ^ 0, 1 ^ NULL, NULL ^ 1;
select 1 XOR 1, 1 XOR 0, 0 XOR 1, 0 XOR 0, NULL XOR 1, 1 XOR NULL, 0 XOR NULL;
1 XOR 1 1 XOR 0 0 XOR 1 0 XOR 0 NULL XOR 1 1 XOR NULL 0 XOR NULL
0 1 1 0 NULL NULL NULL
-drop table if exists t1,t2;
-CREATE TABLE t1 ( start datetime default NULL) TYPE=MyISAM;
-INSERT INTO t1 VALUES ('2002-10-21 00:00:00');
-INSERT INTO t1 VALUES ('2002-10-28 00:00:00');
-INSERT INTO t1 VALUES ('2002-11-04 00:00:00');
-CREATE TABLE t2 ( ctime1 timestamp(14) NOT NULL, ctime2 timestamp(14) NOT NULL) TYPE=MyISAM;
-INSERT INTO t2 VALUES (20021029165106,20021105164731);
-select * from t1, t2 where t1.start between t2.ctime1 and t2.ctime2;
-start ctime1 ctime2
-2002-11-04 00:00:00 20021029165106 20021105164731
-select * from t1, t2 where t1.start >= t2.ctime1 and t1.start <= t2.ctime2;
-start ctime1 ctime2
-2002-11-04 00:00:00 20021029165106 20021105164731
-drop table if exists t1,t2;
select 5 between 0 and 10 between 0 and 1,(5 between 0 and 10) between 0 and 1;
5 between 0 and 10 between 0 and 1 (5 between 0 and 10) between 0 and 1
0 1
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result
index 5433194c719..671b56ef005 100644
--- a/mysql-test/r/func_time.result
+++ b/mysql-test/r/func_time.result
@@ -1,4 +1,4 @@
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
select from_days(to_days("960101")),to_days(960201)-to_days("19960101"),to_days(date_add(curdate(), interval 1 day))-to_days(curdate()),weekday("1997-11-29");
from_days(to_days("960101")) to_days(960201)-to_days("19960101") to_days(date_add(curdate(), interval 1 day))-to_days(curdate()) weekday("1997-11-29")
1996-01-01 31 1 5
@@ -372,3 +372,18 @@ select extract(MONTH FROM "0000-00-00"),extract(MONTH FROM d),extract(MONTH FROM
extract(MONTH FROM "0000-00-00") extract(MONTH FROM d) extract(MONTH FROM dt) extract(MONTH FROM t) extract(MONTH FROM c)
0 0 0 0 0
drop table t1;
+CREATE TABLE t1 ( start datetime default NULL);
+INSERT INTO t1 VALUES ('2002-10-21 00:00:00'),('2002-10-28 00:00:00'),('2002-11-04 00:00:00');
+CREATE TABLE t2 ( ctime1 timestamp(14) NOT NULL, ctime2 timestamp(14) NOT NULL);
+INSERT INTO t2 VALUES (20021029165106,20021105164731);
+CREATE TABLE t3 (ctime1 char(19) NOT NULL, ctime2 char(19) NOT NULL);
+INSERT INTO t3 VALUES ("2002-10-29 16:51:06","2002-11-05 16:47:31");
+select * from t1, t2 where t1.start between t2.ctime1 and t2.ctime2;
+start ctime1 ctime2
+select * from t1, t2 where t1.start >= t2.ctime1 and t1.start <= t2.ctime2;
+start ctime1 ctime2
+2002-11-04 00:00:00 20021029165106 20021105164731
+select * from t1, t3 where t1.start between t3.ctime1 and t3.ctime2;
+start ctime1 ctime2
+2002-11-04 00:00:00 2002-10-29 16:51:06 2002-11-05 16:47:31
+drop table t1,t2,t3;
diff --git a/mysql-test/t/bdb_cache-master.opt b/mysql-test/t/bdb_cache-master.opt
new file mode 100644
index 00000000000..5f0ebff98f6
--- /dev/null
+++ b/mysql-test/t/bdb_cache-master.opt
@@ -0,0 +1 @@
+--set-variable=query_cache_size=1M
diff --git a/mysql-test/t/bdb_cache.test b/mysql-test/t/bdb_cache.test
new file mode 100644
index 00000000000..aa5572886c5
--- /dev/null
+++ b/mysql-test/t/bdb_cache.test
@@ -0,0 +1,50 @@
+-- source include/have_bdb.inc
+-- source include/have_query_cache.inc
+
+#
+# Without auto_commit.
+#
+drop table if exists t1, t2, t3;
+flush status;
+set autocommit=0;
+create table t1 (a int not null) type=bdb;
+insert into t1 values (1),(2),(3);
+select * from t1;
+show status like "Qcache_queries_in_cache";
+drop table t1;
+commit;
+set autocommit=1;
+begin;
+create table t1 (a int not null) type=bdb;
+insert into t1 values (1),(2),(3);
+select * from t1;
+show status like "Qcache_queries_in_cache";
+drop table t1;
+commit;
+create table t1 (a int not null) type=bdb;
+create table t2 (a int not null) type=bdb;
+create table t3 (a int not null) type=bdb;
+insert into t1 values (1),(2);
+insert into t2 values (1),(2);
+insert into t3 values (1),(2);
+select * from t1;
+select * from t2;
+select * from t3;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+begin;
+select * from t1;
+select * from t2;
+select * from t3;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+insert into t1 values (3);
+insert into t2 values (3);
+insert into t1 values (4);
+select * from t1;
+select * from t2;
+select * from t3;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+commit;
+show status like "Qcache_queries_in_cache"; \ No newline at end of file
diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test
index 1486e5bcca8..f5ad2e21c73 100644
--- a/mysql-test/t/func_test.test
+++ b/mysql-test/t/func_test.test
@@ -17,16 +17,6 @@ select 2 in (3,2,5,9,5,1),"monty" in ("david","monty","allan"), 1.2 in (1.4,1.2,
select -1.49 or -1.49,0.6 or 0.6;
select 3 ^ 11, 1 ^ 1, 1 ^ 0, 1 ^ NULL, NULL ^ 1;
select 1 XOR 1, 1 XOR 0, 0 XOR 1, 0 XOR 0, NULL XOR 1, 1 XOR NULL, 0 XOR NULL;
-drop table if exists t1,t2;
-CREATE TABLE t1 ( start datetime default NULL) TYPE=MyISAM;
-INSERT INTO t1 VALUES ('2002-10-21 00:00:00');
-INSERT INTO t1 VALUES ('2002-10-28 00:00:00');
-INSERT INTO t1 VALUES ('2002-11-04 00:00:00');
-CREATE TABLE t2 ( ctime1 timestamp(14) NOT NULL, ctime2 timestamp(14) NOT NULL) TYPE=MyISAM;
-INSERT INTO t2 VALUES (20021029165106,20021105164731);
-select * from t1, t2 where t1.start between t2.ctime1 and t2.ctime2;
-select * from t1, t2 where t1.start >= t2.ctime1 and t1.start <= t2.ctime2;
-drop table if exists t1,t2;
#
# Wrong usage of functions
diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test
index a052f5f2d92..7d5ab73fa4c 100644
--- a/mysql-test/t/func_time.test
+++ b/mysql-test/t/func_time.test
@@ -1,7 +1,7 @@
#
# time functions
#
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
select from_days(to_days("960101")),to_days(960201)-to_days("19960101"),to_days(date_add(curdate(), interval 1 day))-to_days(curdate()),weekday("1997-11-29");
select period_add("9602",-12),period_diff(199505,"9404") ;
@@ -160,3 +160,20 @@ select yearweek("0000-00-00"),yearweek(d),yearweek(dt),yearweek(t),yearweek(c) f
select to_days("0000-00-00"),to_days(d),to_days(dt),to_days(t),to_days(c) from t1;
select extract(MONTH FROM "0000-00-00"),extract(MONTH FROM d),extract(MONTH FROM dt),extract(MONTH FROM t),extract(MONTH FROM c) from t1;
drop table t1;
+
+#
+# Test problem with TIMESTAMP and BETWEEN
+#
+
+CREATE TABLE t1 ( start datetime default NULL);
+INSERT INTO t1 VALUES ('2002-10-21 00:00:00'),('2002-10-28 00:00:00'),('2002-11-04 00:00:00');
+CREATE TABLE t2 ( ctime1 timestamp(14) NOT NULL, ctime2 timestamp(14) NOT NULL);
+INSERT INTO t2 VALUES (20021029165106,20021105164731);
+CREATE TABLE t3 (ctime1 char(19) NOT NULL, ctime2 char(19) NOT NULL);
+INSERT INTO t3 VALUES ("2002-10-29 16:51:06","2002-11-05 16:47:31");
+
+# The following statement should be fixed to return a row in 4.1
+select * from t1, t2 where t1.start between t2.ctime1 and t2.ctime2;
+select * from t1, t2 where t1.start >= t2.ctime1 and t1.start <= t2.ctime2;
+select * from t1, t3 where t1.start between t3.ctime1 and t3.ctime2;
+drop table t1,t2,t3;
diff --git a/sql/field.h b/sql/field.h
index de9e98290e7..4290f99ea3e 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -544,7 +544,6 @@ public:
enum Item_result result_type () const { return field_length == 8 || field_length == 14 ? INT_RESULT : STRING_RESULT; }
enum_field_types type() const { return FIELD_TYPE_TIMESTAMP;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
- enum Item_result cmp_type () const { return INT_RESULT; }
void store(const char *to,uint length);
void store(double nr);
void store(longlong nr);
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index b849bbb76b2..17ac47eefd4 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -1153,15 +1153,15 @@ ha_innobase::open(
ib_table = dict_table_get_and_increment_handle_count(
norm_name, NULL);
if (NULL == ib_table) {
-
- sql_print_error("InnoDB error:\n\
-Cannot find table %s from the internal data dictionary\n\
-of InnoDB though the .frm file for the table exists. Maybe you\n\
-have deleted and recreated InnoDB data files but have forgotten\n\
-to delete the corresponding .frm files of InnoDB tables, or you\n\
-have moved .frm files to another database?\n\
-Look from section 15.1 of http://www.innodb.com/ibman.html\n\
-how you can resolve the problem.\n",
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB error:\n"
+"Cannot find table %s from the internal data dictionary\n"
+"of InnoDB though the .frm file for the table exists. Maybe you\n"
+"have deleted and recreated InnoDB data files but have forgotten\n"
+"to delete the corresponding .frm files of InnoDB tables, or you\n"
+"have moved .frm files to another database?\n"
+"Look from section 15.1 of http://www.innodb.com/ibman.html\n"
+"how you can resolve the problem.\n",
norm_name);
free_share(share);
@@ -2961,16 +2961,21 @@ ha_innobase::create(
trx->check_unique_secondary = FALSE;
}
+ if (lower_case_table_names) {
+ srv_lower_case_table_names = TRUE;
+ } else {
+ srv_lower_case_table_names = FALSE;
+ }
fn_format(name2, name, "", "",2); // Remove the .frm extension
normalize_table_name(norm_name, name2);
- /* Latch the InnoDB data dictionary exclusive so that no deadlocks
+ /* 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.) */
+ Drop table etc. do this latching in row0mysql.c. */
- row_mysql_lock_data_dictionary();
+ row_mysql_lock_data_dictionary(trx);
/* Create the table definition in InnoDB */
@@ -2979,7 +2984,7 @@ ha_innobase::create(
if (error) {
innobase_commit_low(trx);
- row_mysql_unlock_data_dictionary();
+ row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
@@ -3009,7 +3014,7 @@ ha_innobase::create(
if (error) {
innobase_commit_low(trx);
- row_mysql_unlock_data_dictionary();
+ row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
@@ -3024,7 +3029,7 @@ ha_innobase::create(
(uint) primary_key_no))) {
innobase_commit_low(trx);
- row_mysql_unlock_data_dictionary();
+ row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
@@ -3040,7 +3045,7 @@ ha_innobase::create(
innobase_commit_low(trx);
- row_mysql_unlock_data_dictionary();
+ row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
@@ -3057,7 +3062,7 @@ ha_innobase::create(
if (error) {
innobase_commit_low(trx);
- row_mysql_unlock_data_dictionary();
+ row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
@@ -3066,7 +3071,7 @@ ha_innobase::create(
innobase_commit_low(trx);
- row_mysql_unlock_data_dictionary();
+ 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
@@ -3108,6 +3113,12 @@ ha_innobase::delete_table(
DBUG_ENTER("ha_innobase::delete_table");
+ if (lower_case_table_names) {
+ srv_lower_case_table_names = TRUE;
+ } else {
+ srv_lower_case_table_names = FALSE;
+ }
+
trx = trx_allocate_for_mysql();
name_len = strlen(name);
@@ -3121,7 +3132,7 @@ ha_innobase::delete_table(
/* Drop the table in InnoDB */
- error = row_drop_table_for_mysql(norm_name, trx, FALSE);
+ error = row_drop_table_for_mysql(norm_name, trx);
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs
@@ -3218,6 +3229,12 @@ ha_innobase::rename_table(
DBUG_ENTER("ha_innobase::rename_table");
+ if (lower_case_table_names) {
+ srv_lower_case_table_names = TRUE;
+ } else {
+ srv_lower_case_table_names = FALSE;
+ }
+
trx = trx_allocate_for_mysql();
name_len1 = strlen(from);
@@ -3406,6 +3423,15 @@ ha_innobase::info(
DBUG_ENTER("info");
+ /* If we are forcing recovery at a high level, we will suppress
+ statistics calculation on tables, because that may crash the
+ server if an index is badly corrupted. */
+
+ if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
+
+ return;
+ }
+
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function, the trx field in prebuilt can be
obsolete! */
diff --git a/sql/handler.cc b/sql/handler.cc
index 4a43186103c..f2e3e531854 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -311,7 +311,8 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
error=1;
}
else
- transaction_commited= 1;
+ if (!(thd->options & OPTION_BEGIN))
+ transaction_commited= 1;
trans->bdb_tid=0;
}
#endif
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 42cd0a2ee4f..79d695eea1e 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -360,7 +360,6 @@ void Item_func_between::fix_length_and_dec()
if (args[0]->type() == FIELD_ITEM)
{
Field *field=((Item_field*) args[0])->field;
- cmp_type=field->cmp_type();
if (field->store_for_compare())
{
if (convert_constant_item(field,&args[1]))
diff --git a/sql/lock.cc b/sql/lock.cc
index aed0e1988ea..9063b1273e0 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -74,7 +74,7 @@ extern HASH open_cache;
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
bool unlock, TABLE **write_locked);
-static int lock_external(TABLE **table,uint count);
+static int lock_external(THD *thd, TABLE **table,uint count);
static int unlock_external(THD *thd, TABLE **table,uint count);
static void print_lock_error(int error);
@@ -110,7 +110,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
}
thd->proc_info="System lock";
- if (lock_external(tables,count))
+ if (lock_external(thd, tables, count))
{
my_free((gptr) sql_lock,MYF(0));
sql_lock=0;
@@ -159,11 +159,10 @@ retry:
}
-static int lock_external(TABLE **tables,uint count)
+static int lock_external(THD *thd, TABLE **tables, uint count)
{
reg1 uint i;
int lock_type,error;
- THD *thd=current_thd;
DBUG_ENTER("lock_external");
for (i=1 ; i <= count ; i++, tables++)
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d1c92592fca..0ffd213b2f4 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -339,7 +339,7 @@ volatile ulong cached_thread_count=0;
my_string master_user = (char*) "test", master_password = 0, master_host=0,
master_info_file = (char*) "master.info",
relay_log_info_file = (char*) "relay-log.info",
- master_ssl_key=0, master_ssl_cert=0;
+ master_ssl_key=0, master_ssl_cert=0, master_ssl_capath=0, master_ssl_cipher=0;
my_string report_user = 0, report_password = 0, report_host=0;
const char *localhost=LOCAL_HOST;
@@ -2823,8 +2823,9 @@ enum options {
OPT_MASTER_PASSWORD, OPT_MASTER_PORT,
OPT_MASTER_INFO_FILE, OPT_MASTER_CONNECT_RETRY,
OPT_MASTER_RETRY_COUNT,
- OPT_MASTER_SSL, OPT_MASTER_SSL_KEY,
- OPT_MASTER_SSL_CERT,
+ OPT_MASTER_SSL, OPT_MASTER_SSL_KEY,
+ OPT_MASTER_SSL_CERT, OPT_MASTER_SSL_CAPATH,
+ OPT_MASTER_SSL_CIPHER,
OPT_SQL_BIN_UPDATE_SAME, OPT_REPLICATE_DO_DB,
OPT_REPLICATE_IGNORE_DB, OPT_LOG_SLAVE_UPDATES,
OPT_BINLOG_DO_DB, OPT_BINLOG_IGNORE_DB,
@@ -3133,6 +3134,14 @@ struct my_option my_long_options[] =
"Master SSL certificate file name. Only applies if you have enabled master-ssl.",
(gptr*) &master_ssl_cert, (gptr*) &master_ssl_cert, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
+ {"master-ssl-capath", OPT_MASTER_SSL_CAPATH,
+ "Master SSL CA path. Only applies if you have enabled master-ssl.",
+ (gptr*) &master_ssl_capath, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG,
+ 0, 0, 0, 0, 0, 0},
+ {"master-ssl-cipher", OPT_MASTER_SSL_CIPHER,
+ "Master SSL cipher. Only applies if you have enabled master-ssl.",
+ (gptr*) &master_ssl_cipher, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG,
+ 0, 0, 0, 0, 0, 0},
{"myisam-recover", OPT_MYISAM_RECOVER,
"Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP or FORCE.",
(gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0,
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 80a0e0625cb..a992ddf6044 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -502,7 +502,9 @@ struct show_var_st init_vars[]= {
{"skip_networking", (char*) &opt_disable_networking, SHOW_BOOL},
{"skip_show_database", (char*) &opt_skip_show_db, SHOW_BOOL},
{sys_slow_launch_time.name, (char*) &sys_slow_launch_time, SHOW_SYS},
+#ifdef HAVE_SYS_UN_H
{"socket", (char*) &mysql_unix_port, SHOW_CHAR_PTR},
+#endif
{sys_sort_buffer.name, (char*) &sys_sort_buffer, SHOW_SYS},
{"sql_mode", (char*) &opt_sql_mode, SHOW_LONG},
{"table_cache", (char*) &table_cache_size, SHOW_LONG},
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index fa967d645ef..3b46c53f75c 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1275,7 +1275,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
int error;
DBUG_ENTER("open_unireg_entry");
- (void) sprintf(path,"%s/%s/%s",mysql_data_home,db,name);
+ strxmov(path, mysql_data_home, "/", db, "/", name, NullS);
if (openfrm(path,alias,
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
HA_TRY_READ_ONLY),
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 7416506fd02..924fe76fe21 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -554,7 +554,13 @@ check_connections(THD *thd)
{
/* Do the SSL layering. */
DBUG_PRINT("info", ("IO layer change in progress..."));
- sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout);
+ if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
+ {
+ DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
+ pkt_len));
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
DBUG_PRINT("info", ("Reading user information over SSL layer"));
if ((pkt_len=my_net_read(net)) == packet_error ||
pkt_len < NORMAL_HANDSHAKE_SIZE)
diff --git a/vio/viossl.c b/vio/viossl.c
index 56d3da8a1ac..cf1c98b5382 100644
--- a/vio/viossl.c
+++ b/vio/viossl.c
@@ -249,35 +249,48 @@ void vio_ssl_in_addr(Vio *vio, struct in_addr *in)
/*
- TODO: Add documentation and error handling
+ TODO: Add documentation
*/
-void sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio, long timeout)
+int sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio, long timeout)
{
char *str;
char buf[1024];
X509* client_cert;
my_bool unused;
+ my_bool net_blocking;
+ enum enum_vio_type old_type;
DBUG_ENTER("sslaccept");
DBUG_PRINT("enter", ("sd=%d ptr=%p", vio->sd,ptr));
+ old_type= vio->type;
+ net_blocking = vio_is_blocking(vio);
vio_blocking(vio, 1, &unused); /* Must be called before reset */
vio_reset(vio,VIO_TYPE_SSL,vio->sd,0,FALSE);
vio->ssl_=0;
- vio->open_=FALSE;
if (!(vio->ssl_ = SSL_new(ptr->ssl_context_)))
{
DBUG_PRINT("error", ("SSL_new failure"));
report_errors();
- DBUG_VOID_RETURN;
+ vio_reset(vio, old_type,vio->sd,0,FALSE);
+ vio_blocking(vio, net_blocking, &unused);
+ DBUG_RETURN(1);
}
DBUG_PRINT("info", ("ssl_=%p timeout=%ld",vio->ssl_, timeout));
SSL_clear(vio->ssl_);
SSL_SESSION_set_timeout(SSL_get_session(vio->ssl_), timeout);
SSL_set_fd(vio->ssl_,vio->sd);
SSL_set_accept_state(vio->ssl_);
- SSL_do_handshake(vio->ssl_);
- vio->open_ = TRUE;
+ if (SSL_do_handshake(vio->ssl_) < 1)
+ {
+ DBUG_PRINT("error", ("SSL_do_handshake failure"));
+ report_errors();
+ SSL_free(vio->ssl_);
+ vio->ssl_=0;
+ vio_reset(vio, old_type,vio->sd,0,FALSE);
+ vio_blocking(vio, net_blocking, &unused);
+ DBUG_RETURN(1);
+ }
#ifndef DBUF_OFF
DBUG_PRINT("info",("SSL_get_cipher_name() = '%s'"
,SSL_get_cipher_name(vio->ssl_)));
@@ -309,7 +322,7 @@ void sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio, long timeout)
}
#endif
- DBUG_VOID_RETURN;
+ DBUG_RETURN(0);
}
@@ -318,17 +331,22 @@ int sslconnect(struct st_VioSSLConnectorFd* ptr, Vio* vio, long timeout)
char *str;
X509* server_cert;
my_bool unused;
+ my_bool net_blocking;
+ enum enum_vio_type old_type;
DBUG_ENTER("sslconnect");
DBUG_PRINT("enter", ("sd=%d ptr=%p ctx: %p", vio->sd,ptr,ptr->ssl_context_));
+ old_type= vio->type;
+ net_blocking = vio_is_blocking(vio);
vio_blocking(vio, 1, &unused); /* Must be called before reset */
vio_reset(vio,VIO_TYPE_SSL,vio->sd,0,FALSE);
vio->ssl_=0;
- vio->open_=FALSE;
if (!(vio->ssl_ = SSL_new(ptr->ssl_context_)))
{
DBUG_PRINT("error", ("SSL_new failure"));
report_errors();
+ vio_reset(vio, old_type,vio->sd,0,FALSE);
+ vio_blocking(vio, net_blocking, &unused);
DBUG_RETURN(1);
}
DBUG_PRINT("info", ("ssl_=%p timeout=%ld",vio->ssl_, timeout));
@@ -336,8 +354,16 @@ int sslconnect(struct st_VioSSLConnectorFd* ptr, Vio* vio, long timeout)
SSL_SESSION_set_timeout(SSL_get_session(vio->ssl_), timeout);
SSL_set_fd (vio->ssl_, vio->sd);
SSL_set_connect_state(vio->ssl_);
- SSL_do_handshake(vio->ssl_);
- vio->open_ = TRUE;
+ if (SSL_do_handshake(vio->ssl_) < 1)
+ {
+ DBUG_PRINT("error", ("SSL_do_handshake failure"));
+ report_errors();
+ SSL_free(vio->ssl_);
+ vio->ssl_=0;
+ vio_reset(vio, old_type,vio->sd,0,FALSE);
+ vio_blocking(vio, net_blocking, &unused);
+ DBUG_RETURN(1);
+ }
#ifndef DBUG_OFF
DBUG_PRINT("info",("SSL_get_cipher_name() = '%s'"
,SSL_get_cipher_name(vio->ssl_)));
diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c
index 9e7a1475951..31bc457d1ae 100644
--- a/vio/viosslfactories.c
+++ b/vio/viosslfactories.c
@@ -93,7 +93,10 @@ vio_set_cert_stuff(SSL_CTX *ctx, const char *cert_file, const char *key_file)
{
DBUG_PRINT("error",("unable to get certificate from '%s'\n",cert_file));
/* FIX stderr */
+ fprintf(stderr,"Error when connection to server using SSL:");
ERR_print_errors_fp(stderr);
+ fprintf(stderr,"Unable to get certificate from '%s'\n", cert_file);
+ fflush(stderr);
DBUG_RETURN(0);
}
if (key_file == NULL)
@@ -103,7 +106,10 @@ vio_set_cert_stuff(SSL_CTX *ctx, const char *cert_file, const char *key_file)
{
DBUG_PRINT("error", ("unable to get private key from '%s'\n",key_file));
/* FIX stderr */
+ fprintf(stderr,"Error when connection to server using SSL:");
ERR_print_errors_fp(stderr);
+ fprintf(stderr,"Unable to get private key from '%s'\n", cert_file);
+ fflush(stderr);
DBUG_RETURN(0);
}