diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index d0c586de8d4..0a2cb61b18d 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -3218,3 +3218,16 @@ a 2 DROP TABLE t1; DROP TABLE t2; +create table t1 (i int, j int) engine=innodb; +insert into t1 (i, j) values (1, 1), (2, 2); +update t1 set j = 2; +affected rows: 1 +info: Rows matched: 2 Changed: 1 Warnings: 0 +drop table t1; +create table t1 (id int) comment='this is a comment' engine=innodb; +select table_comment, data_free > 0 as data_free_is_set +from information_schema.tables +where table_schema='test' and table_name = 't1'; +table_comment data_free_is_set +this is a comment 1 +drop table t1; diff --git a/mysql-test/r/partition_innodb.result b/mysql-test/r/partition_innodb.result index 5cbe34c94ca..8cb8bc7c13f 100644 --- a/mysql-test/r/partition_innodb.result +++ b/mysql-test/r/partition_innodb.result @@ -13,33 +13,33 @@ DROP TABLE t1; create table t1 (a int) engine=innodb partition by hash(a) ; show table status like 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 InnoDB 10 Compact 2 8192 16384 0 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL partitioned +t1 InnoDB 10 Compact 2 8192 16384 0 0 # NULL NULL NULL NULL latin1_swedish_ci NULL partitioned drop table t1; create table t1 (a int) engine = innodb partition by key (a); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 InnoDB 10 Compact 2 8192 16384 0 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL partitioned +t1 InnoDB 10 Compact 2 8192 16384 0 0 # NULL NULL NULL NULL latin1_swedish_ci NULL partitioned insert into t1 values (0), (1), (2), (3); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 InnoDB 10 Compact 4 4096 16384 0 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL partitioned +t1 InnoDB 10 Compact 4 4096 16384 0 0 # NULL NULL NULL NULL latin1_swedish_ci NULL partitioned drop table t1; create table t1 (a int auto_increment primary key) engine = innodb partition by key (a); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 InnoDB 10 Compact 2 8192 16384 0 0 0 1 NULL NULL NULL latin1_swedish_ci NULL partitioned +t1 InnoDB 10 Compact 2 8192 16384 0 0 # 1 NULL NULL NULL latin1_swedish_ci NULL partitioned insert into t1 values (NULL), (NULL), (NULL), (NULL); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 InnoDB 10 Compact 4 4096 16384 0 0 0 5 NULL NULL NULL latin1_swedish_ci NULL partitioned +t1 InnoDB 10 Compact 4 4096 16384 0 0 # 5 NULL NULL NULL latin1_swedish_ci NULL partitioned insert into t1 values (NULL), (NULL), (NULL), (NULL); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 InnoDB 10 Compact 8 2048 16384 0 0 0 9 NULL NULL NULL latin1_swedish_ci NULL partitioned +t1 InnoDB 10 Compact 8 2048 16384 0 0 # 9 NULL NULL NULL latin1_swedish_ci NULL partitioned drop table t1; create table t1 (a int) partition by key (a) diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 8fdbbfcde79..bfe7d4ea9b4 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -2382,6 +2382,27 @@ DROP TABLE t1; DROP TABLE t2; DISCONNECT c1; DISCONNECT c2; +CONNECTION default; + +# +# Bug #29157 UPDATE, changed rows incorrect +# +create table t1 (i int, j int) engine=innodb; +insert into t1 (i, j) values (1, 1), (2, 2); +--enable_info +update t1 set j = 2; +--disable_info +drop table t1; + +# +# Bug #32440 InnoDB free space info does not appear in SHOW TABLE STATUS or +# I_S +# +create table t1 (id int) comment='this is a comment' engine=innodb; +select table_comment, data_free > 0 as data_free_is_set + from information_schema.tables + where table_schema='test' and table_name = 't1'; +drop table t1; ####################################################################### # # diff --git a/mysql-test/t/partition_innodb.test b/mysql-test/t/partition_innodb.test index 58010f85ecf..76a54b36942 100644 --- a/mysql-test/t/partition_innodb.test +++ b/mysql-test/t/partition_innodb.test @@ -20,6 +20,9 @@ DROP TABLE t1; # Bug #14673: Wrong InnoDB default row format # create table t1 (a int) engine=innodb partition by hash(a) ; +# Data_free for InnoDB tablespace varies depending on which +# tests have been run before this one +--replace_column 10 # show table status like 't1'; drop table t1; @@ -29,18 +32,33 @@ drop table t1; create table t1 (a int) engine = innodb partition by key (a); +# Data_free for InnoDB tablespace varies depending on which +# tests have been run before this one +--replace_column 10 # show table status; insert into t1 values (0), (1), (2), (3); +# Data_free for InnoDB tablespace varies depending on which +# tests have been run before this one +--replace_column 10 # show table status; drop table t1; create table t1 (a int auto_increment primary key) engine = innodb partition by key (a); +# Data_free for InnoDB tablespace varies depending on which +# tests have been run before this one +--replace_column 10 # show table status; insert into t1 values (NULL), (NULL), (NULL), (NULL); +# Data_free for InnoDB tablespace varies depending on which +# tests have been run before this one +--replace_column 10 # show table status; insert into t1 values (NULL), (NULL), (NULL), (NULL); +# Data_free for InnoDB tablespace varies depending on which +# tests have been run before this one +--replace_column 10 # show table status; drop table t1; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 205cfc91e52..e66d5b84d19 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -600,7 +600,9 @@ convert_error_code_to_mysql( tell it also to MySQL so that MySQL knows to empty the cached binlog for this transaction */ - thd_mark_transaction_to_rollback(thd, TRUE); + if (thd) { + thd_mark_transaction_to_rollback(thd, TRUE); + } return(HA_ERR_LOCK_DEADLOCK); } else if (error == (int) DB_LOCK_WAIT_TIMEOUT) { @@ -609,8 +611,10 @@ convert_error_code_to_mysql( latest SQL statement in a lock wait timeout. Previously, we rolled back the whole transaction. */ - thd_mark_transaction_to_rollback(thd, - (bool)row_rollback_on_timeout); + if (thd) { + thd_mark_transaction_to_rollback( + thd, (bool)row_rollback_on_timeout); + } return(HA_ERR_LOCK_WAIT_TIMEOUT); @@ -662,7 +666,9 @@ convert_error_code_to_mysql( tell it also to MySQL so that MySQL knows to empty the cached binlog for this transaction */ - thd_mark_transaction_to_rollback(thd, TRUE); + if (thd) { + thd_mark_transaction_to_rollback(thd, TRUE); + } return(HA_ERR_LOCK_TABLE_FULL); } else if (error == DB_TOO_MANY_CONCURRENT_TRXS) { @@ -3769,6 +3775,16 @@ ha_innobase::update_row( error = convert_error_code_to_mysql(error, user_thd); + if (error == 0 /* success */ + && uvect->n_fields == 0 /* no columns were updated */) { + + /* This is the same as success, but instructs + MySQL that the row is not really updated and it + should not increase the count of updated rows. + This is fix for http://bugs.mysql.com/29157 */ + error = HA_ERR_RECORD_IS_THE_SAME; + } + /* Tell InnoDB server that there might be work for utility threads: */ @@ -5720,7 +5736,9 @@ ha_innobase::info( stats.index_file_length = ((ulonglong) ib_table->stat_sum_of_other_index_sizes) * UNIV_PAGE_SIZE; - stats.delete_length = 0; + stats.delete_length = + fsp_get_available_space_in_free_extents( + ib_table->space); stats.check_time = 0; if (stats.records == 0) { @@ -7246,6 +7264,7 @@ On return if there is no error then the tables AUTOINC lock is locked.*/ ulong ha_innobase::innobase_get_auto_increment( +/*=====================================*/ ulonglong* value) /* out: autoinc value */ { ulong error; diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index b3cf20b78b8..9348cfa7342 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -3312,6 +3312,66 @@ funct_exit: return((int) err); } +/*********************************************************************** +Drop all foreign keys in a database, see Bug#18942. +Called at the end of row_drop_database_for_mysql(). */ +static +ulint +drop_all_foreign_keys_in_db( +/*========================*/ + /* out: error code or DB_SUCCESS */ + const char* name, /* in: database name which ends to '/' */ + trx_t* trx) /* in: transaction handle */ +{ + pars_info_t* pinfo; + ulint err; + + ut_a(name[strlen(name) - 1] == '/'); + + pinfo = pars_info_create(); + + pars_info_add_str_literal(pinfo, "dbname", name); + +/* true if for_name is not prefixed with dbname */ +#define TABLE_NOT_IN_THIS_DB \ +"SUBSTR(for_name, 0, LENGTH(:dbname)) <> :dbname" + + err = que_eval_sql(pinfo, + "PROCEDURE DROP_ALL_FOREIGN_KEYS_PROC () IS\n" + "foreign_id CHAR;\n" + "for_name CHAR;\n" + "found INT;\n" + "DECLARE CURSOR cur IS\n" + "SELECT ID, FOR_NAME FROM SYS_FOREIGN\n" + "WHERE FOR_NAME >= :dbname\n" + "LOCK IN SHARE MODE\n" + "ORDER BY FOR_NAME;\n" + "BEGIN\n" + "found := 1;\n" + "OPEN cur;\n" + "WHILE found = 1 LOOP\n" + " FETCH cur INTO foreign_id, for_name;\n" + " IF (SQL % NOTFOUND) THEN\n" + " found := 0;\n" + " ELSIF (" TABLE_NOT_IN_THIS_DB ") THEN\n" + " found := 0;\n" + " ELSIF (1=1) THEN\n" + " DELETE FROM SYS_FOREIGN_COLS\n" + " WHERE ID = foreign_id;\n" + " DELETE FROM SYS_FOREIGN\n" + " WHERE ID = foreign_id;\n" + " END IF;\n" + "END LOOP;\n" + "CLOSE cur;\n" + "COMMIT WORK;\n" + "END;\n", + FALSE, /* do not reserve dict mutex, + we are already holding it */ + trx); + + return(err); +} + /************************************************************************* Drops a database for MySQL. */ @@ -3382,6 +3442,19 @@ loop: } } + if (err == DB_SUCCESS) { + /* after dropping all tables try to drop all leftover + foreign keys in case orphaned ones exist */ + err = (int) drop_all_foreign_keys_in_db(name, trx); + + if (err != DB_SUCCESS) { + fputs("InnoDB: DROP DATABASE ", stderr); + ut_print_name(stderr, trx, TRUE, name); + fprintf(stderr, " failed with error %d while " + "dropping all foreign keys", err); + } + } + trx_commit_for_mysql(trx); row_mysql_unlock_data_dictionary(trx); diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index a278ad51984..55b244abb0a 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -933,6 +933,7 @@ trx_commit_off_kernel( trx->rseg = NULL; trx->undo_no = ut_dulint_zero; trx->last_sql_stat_start.least_undo_no = ut_dulint_zero; + trx->mysql_query_str = NULL; ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0); ut_ad(UT_LIST_GET_LEN(trx->trx_locks) == 0);