From ffad1562542a72f41912ef1edd55b3a49e7fe89d Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich <svoj@sun.com> Date: Fri, 26 Feb 2010 13:01:31 +0400 Subject: [PATCH 1/8] Applying InnoDB snapshot Detailed revision comments: r6535 | sunny | 2010-01-30 00:08:40 +0200 (Sat, 30 Jan 2010) | 11 lines branches/5.1: Undo the change from r6424. We need to return DB_SUCCESS even if we were unable to initialize the tabe autoinc value. This is required for the open to succeed. The only condition we currently treat as a hard error is if the autoinc field instance passed in by MySQL is NULL. Previously if the table autoinc value was 0 and the next value was requested we had an assertion that would fail. Change that assertion and treat a value of 0 to mean that the autoinc system is unavailable. Generation of next value will now return failure. rb://237 --- storage/innobase/handler/ha_innodb.cc | 38 ++++++++++++++++++++------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 9b6c2cf9895..e3aa5fb4f5b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2652,9 +2652,9 @@ ha_innobase::innobase_initialize_autoinc() auto_inc = innobase_get_int_col_max_value(field); } else { /* We have no idea what's been passed in to us as the - autoinc column. We set it to the MAX_INT of our table - autoinc type. */ - auto_inc = 0xFFFFFFFFFFFFFFFFULL; + autoinc column. We set it to the 0, effectively disabling + updates to the table. */ + auto_inc = 0; ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Unable to determine the AUTOINC " @@ -2663,7 +2663,7 @@ ha_innobase::innobase_initialize_autoinc() if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { /* If the recovery level is set so high that writes - are disabled we force the AUTOINC counter to the MAX + are disabled we force the AUTOINC counter to 0 value effectively disabling writes to the table. Secondly, we avoid reading the table in case the read results in failure due to a corrupted table/index. @@ -2672,7 +2672,10 @@ ha_innobase::innobase_initialize_autoinc() tables can be dumped with minimal hassle. If an error were returned in this case, the first attempt to read the table would fail and subsequent SELECTs would succeed. */ + auto_inc = 0; } else if (field == NULL) { + /* This is a far more serious error, best to avoid + opening the table and return failure. */ my_error(ER_AUTOINC_READ_FAILED, MYF(0)); } else { dict_index_t* index; @@ -2701,7 +2704,7 @@ ha_innobase::innobase_initialize_autoinc() "InnoDB: Unable to find the AUTOINC column " "%s in the InnoDB table %s.\n" "InnoDB: We set the next AUTOINC column " - "value to the maximum possible value,\n" + "value to 0,\n" "InnoDB: in effect disabling the AUTOINC " "next value generation.\n" "InnoDB: You can either set the next " @@ -2710,7 +2713,13 @@ ha_innobase::innobase_initialize_autoinc() "recreating the table.\n", col_name, index->table->name); - my_error(ER_AUTOINC_READ_FAILED, MYF(0)); + /* This will disable the AUTOINC generation. */ + auto_inc = 0; + + /* We want the open to succeed, so that the user can + take corrective action. ie. reads should succeed but + updates should fail. */ + err = DB_SUCCESS; break; default: /* row_search_max_autoinc() should only return @@ -3968,11 +3977,17 @@ no_commit: prebuilt->autoinc_error = DB_SUCCESS; if ((error = update_auto_increment())) { - /* We don't want to mask autoinc overflow errors. */ - if (prebuilt->autoinc_error != DB_SUCCESS) { - error = (int) prebuilt->autoinc_error; + /* Handle the case where the AUTOINC sub-system + failed during initialization. */ + if (prebuilt->autoinc_error == DB_UNSUPPORTED) { + error_result = ER_AUTOINC_READ_FAILED; + /* Set the error message to report too. */ + my_error(ER_AUTOINC_READ_FAILED, MYF(0)); + goto func_exit; + } else if (prebuilt->autoinc_error != DB_SUCCESS) { + error = (int) prebuilt->autoinc_error; goto report_error; } @@ -7883,7 +7898,10 @@ ha_innobase::innobase_get_autoinc( *value = dict_table_autoinc_read(prebuilt->table); /* It should have been initialized during open. */ - ut_a(*value != 0); + if (*value == 0) { + prebuilt->autoinc_error = DB_UNSUPPORTED; + dict_table_autoinc_unlock(prebuilt->table); + } } return(ulong(prebuilt->autoinc_error)); From 91c42548c8685bcebecf19c960b2ab99c173b02d Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich <svoj@sun.com> Date: Fri, 26 Feb 2010 13:02:05 +0400 Subject: [PATCH 2/8] Applying InnoDB snapshot Detailed revision comments: r6536 | sunny | 2010-01-30 00:13:42 +0200 (Sat, 30 Jan 2010) | 6 lines branches/5.1: Check *first_value everytime against the column max value and set *first_value to next autoinc if it's > col max value. ie. not rely on what is passed in from MySQL. [49497] Error 1467 (ER_AUTOINC_READ_FAILED) on inserting a negative value rb://236 --- mysql-test/r/innodb-autoinc.result | 83 +++++++++++++++++++++++++++ mysql-test/t/innodb-autoinc.test | 31 ++++++++++ storage/innobase/handler/ha_innodb.cc | 54 +++++++---------- 3 files changed, 134 insertions(+), 34 deletions(-) diff --git a/mysql-test/r/innodb-autoinc.result b/mysql-test/r/innodb-autoinc.result index c03daa3565e..a36b3a1a865 100644 --- a/mysql-test/r/innodb-autoinc.result +++ b/mysql-test/r/innodb-autoinc.result @@ -1161,3 +1161,86 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`c1`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 DROP TABLE t1; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (-685113344), (1), (NULL), (NULL); +SELECT * FROM t1; +c1 +-685113344 +1 +2 +3 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (-685113344), (2), (NULL), (NULL); +SELECT * FROM t1; +c1 +-685113344 +2 +3 +4 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL), (2), (-685113344), (NULL); +INSERT INTO t1 VALUES (4), (5), (6), (NULL); +SELECT * FROM t1; +c1 +-685113344 +1 +2 +3 +4 +5 +6 +7 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL), (2), (-685113344), (5); +SELECT * FROM t1; +c1 +-685113344 +1 +2 +5 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1), (2), (-685113344), (NULL); +SELECT * FROM t1; +c1 +-685113344 +1 +2 +3 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/t/innodb-autoinc.test b/mysql-test/t/innodb-autoinc.test index bb431408937..ef0359b78b0 100644 --- a/mysql-test/t/innodb-autoinc.test +++ b/mysql-test/t/innodb-autoinc.test @@ -631,3 +631,34 @@ REPLACE INTO t1 VALUES (-1); SELECT * FROM t1; SHOW CREATE TABLE t1; DROP TABLE t1; + +## +# 49497: Error 1467 (ER_AUTOINC_READ_FAILED) on inserting a negative value +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (-685113344), (1), (NULL), (NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (-685113344), (2), (NULL), (NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL), (2), (-685113344), (NULL); +INSERT INTO t1 VALUES (4), (5), (6), (NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL), (2), (-685113344), (5); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1), (2), (-685113344), (NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index e3aa5fb4f5b..7b501a23d21 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2652,9 +2652,9 @@ ha_innobase::innobase_initialize_autoinc() auto_inc = innobase_get_int_col_max_value(field); } else { /* We have no idea what's been passed in to us as the - autoinc column. We set it to the 0, effectively disabling - updates to the table. */ - auto_inc = 0; + autoinc column. We set it to the MAX_INT of our table + autoinc type. */ + auto_inc = 0xFFFFFFFFFFFFFFFFULL; ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Unable to determine the AUTOINC " @@ -2663,7 +2663,7 @@ ha_innobase::innobase_initialize_autoinc() if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { /* If the recovery level is set so high that writes - are disabled we force the AUTOINC counter to 0 + are disabled we force the AUTOINC counter to the MAX value effectively disabling writes to the table. Secondly, we avoid reading the table in case the read results in failure due to a corrupted table/index. @@ -2672,10 +2672,7 @@ ha_innobase::innobase_initialize_autoinc() tables can be dumped with minimal hassle. If an error were returned in this case, the first attempt to read the table would fail and subsequent SELECTs would succeed. */ - auto_inc = 0; } else if (field == NULL) { - /* This is a far more serious error, best to avoid - opening the table and return failure. */ my_error(ER_AUTOINC_READ_FAILED, MYF(0)); } else { dict_index_t* index; @@ -2704,7 +2701,7 @@ ha_innobase::innobase_initialize_autoinc() "InnoDB: Unable to find the AUTOINC column " "%s in the InnoDB table %s.\n" "InnoDB: We set the next AUTOINC column " - "value to 0,\n" + "value to the maximum possible value,\n" "InnoDB: in effect disabling the AUTOINC " "next value generation.\n" "InnoDB: You can either set the next " @@ -2713,13 +2710,7 @@ ha_innobase::innobase_initialize_autoinc() "recreating the table.\n", col_name, index->table->name); - /* This will disable the AUTOINC generation. */ - auto_inc = 0; - - /* We want the open to succeed, so that the user can - take corrective action. ie. reads should succeed but - updates should fail. */ - err = DB_SUCCESS; + my_error(ER_AUTOINC_READ_FAILED, MYF(0)); break; default: /* row_search_max_autoinc() should only return @@ -3977,17 +3968,11 @@ no_commit: prebuilt->autoinc_error = DB_SUCCESS; if ((error = update_auto_increment())) { - /* We don't want to mask autoinc overflow errors. */ - /* Handle the case where the AUTOINC sub-system - failed during initialization. */ - if (prebuilt->autoinc_error == DB_UNSUPPORTED) { - error_result = ER_AUTOINC_READ_FAILED; - /* Set the error message to report too. */ - my_error(ER_AUTOINC_READ_FAILED, MYF(0)); - goto func_exit; - } else if (prebuilt->autoinc_error != DB_SUCCESS) { + /* We don't want to mask autoinc overflow errors. */ + if (prebuilt->autoinc_error != DB_SUCCESS) { error = (int) prebuilt->autoinc_error; + goto report_error; } @@ -7898,10 +7883,7 @@ ha_innobase::innobase_get_autoinc( *value = dict_table_autoinc_read(prebuilt->table); /* It should have been initialized during open. */ - if (*value == 0) { - prebuilt->autoinc_error = DB_UNSUPPORTED; - dict_table_autoinc_unlock(prebuilt->table); - } + ut_a(*value != 0); } return(ulong(prebuilt->autoinc_error)); @@ -7981,6 +7963,11 @@ ha_innobase::get_auto_increment( invoking this method. So we are not sure if it's guaranteed to be 0 or not. */ + /* We need the upper limit of the col type to check for + whether we update the table autoinc counter or not. */ + ulonglong col_max_value = innobase_get_int_col_max_value( + table->next_number_field); + /* Called for the first time ? */ if (trx->n_autoinc_rows == 0) { @@ -7997,6 +7984,11 @@ ha_innobase::get_auto_increment( /* Not in the middle of a mult-row INSERT. */ } else if (prebuilt->autoinc_last_value == 0) { set_if_bigger(*first_value, autoinc); + /* Check for -ve values. */ + } else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) { + /* Set to next logical value. */ + ut_a(autoinc > trx->n_autoinc_rows); + *first_value = (autoinc - trx->n_autoinc_rows) - 1; } *nb_reserved_values = trx->n_autoinc_rows; @@ -8007,12 +7999,6 @@ ha_innobase::get_auto_increment( ulonglong need; ulonglong current; ulonglong next_value; - ulonglong col_max_value; - - /* We need the upper limit of the col type to check for - whether we update the table autoinc counter or not. */ - col_max_value = innobase_get_int_col_max_value( - table->next_number_field); current = *first_value > col_max_value ? autoinc : *first_value; need = *nb_reserved_values * increment; From ac68d90faa138ced5f8441bd35874a7297a8236e Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich <svoj@sun.com> Date: Fri, 26 Feb 2010 13:02:26 +0400 Subject: [PATCH 3/8] Applying InnoDB snapshot Detailed revision comments: r6537 | sunny | 2010-01-30 00:35:00 +0200 (Sat, 30 Jan 2010) | 2 lines branches/5.1: Undo r6536. --- mysql-test/r/innodb-autoinc.result | 83 --------------------------- mysql-test/t/innodb-autoinc.test | 31 ---------- storage/innobase/handler/ha_innodb.cc | 54 ++++++++++------- 3 files changed, 34 insertions(+), 134 deletions(-) diff --git a/mysql-test/r/innodb-autoinc.result b/mysql-test/r/innodb-autoinc.result index a36b3a1a865..c03daa3565e 100644 --- a/mysql-test/r/innodb-autoinc.result +++ b/mysql-test/r/innodb-autoinc.result @@ -1161,86 +1161,3 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`c1`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 DROP TABLE t1; -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (-685113344), (1), (NULL), (NULL); -SELECT * FROM t1; -c1 --685113344 -1 -2 -3 -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`c1`) -) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 -DROP TABLE t1; -CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (-685113344), (2), (NULL), (NULL); -SELECT * FROM t1; -c1 --685113344 -2 -3 -4 -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`c1`) -) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 -DROP TABLE t1; -CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (NULL), (2), (-685113344), (NULL); -INSERT INTO t1 VALUES (4), (5), (6), (NULL); -SELECT * FROM t1; -c1 --685113344 -1 -2 -3 -4 -5 -6 -7 -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`c1`) -) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1 -DROP TABLE t1; -CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (NULL), (2), (-685113344), (5); -SELECT * FROM t1; -c1 --685113344 -1 -2 -5 -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`c1`) -) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 -DROP TABLE t1; -CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (1), (2), (-685113344), (NULL); -SELECT * FROM t1; -c1 --685113344 -1 -2 -3 -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`c1`) -) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 -DROP TABLE t1; diff --git a/mysql-test/t/innodb-autoinc.test b/mysql-test/t/innodb-autoinc.test index ef0359b78b0..bb431408937 100644 --- a/mysql-test/t/innodb-autoinc.test +++ b/mysql-test/t/innodb-autoinc.test @@ -631,34 +631,3 @@ REPLACE INTO t1 VALUES (-1); SELECT * FROM t1; SHOW CREATE TABLE t1; DROP TABLE t1; - -## -# 49497: Error 1467 (ER_AUTOINC_READ_FAILED) on inserting a negative value -# -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (-685113344), (1), (NULL), (NULL); -SELECT * FROM t1; -SHOW CREATE TABLE t1; -DROP TABLE t1; -CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (-685113344), (2), (NULL), (NULL); -SELECT * FROM t1; -SHOW CREATE TABLE t1; -DROP TABLE t1; -CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (NULL), (2), (-685113344), (NULL); -INSERT INTO t1 VALUES (4), (5), (6), (NULL); -SELECT * FROM t1; -SHOW CREATE TABLE t1; -DROP TABLE t1; -CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (NULL), (2), (-685113344), (5); -SELECT * FROM t1; -SHOW CREATE TABLE t1; -DROP TABLE t1; -CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (1), (2), (-685113344), (NULL); -SELECT * FROM t1; -SHOW CREATE TABLE t1; -DROP TABLE t1; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 7b501a23d21..e3aa5fb4f5b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2652,9 +2652,9 @@ ha_innobase::innobase_initialize_autoinc() auto_inc = innobase_get_int_col_max_value(field); } else { /* We have no idea what's been passed in to us as the - autoinc column. We set it to the MAX_INT of our table - autoinc type. */ - auto_inc = 0xFFFFFFFFFFFFFFFFULL; + autoinc column. We set it to the 0, effectively disabling + updates to the table. */ + auto_inc = 0; ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Unable to determine the AUTOINC " @@ -2663,7 +2663,7 @@ ha_innobase::innobase_initialize_autoinc() if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { /* If the recovery level is set so high that writes - are disabled we force the AUTOINC counter to the MAX + are disabled we force the AUTOINC counter to 0 value effectively disabling writes to the table. Secondly, we avoid reading the table in case the read results in failure due to a corrupted table/index. @@ -2672,7 +2672,10 @@ ha_innobase::innobase_initialize_autoinc() tables can be dumped with minimal hassle. If an error were returned in this case, the first attempt to read the table would fail and subsequent SELECTs would succeed. */ + auto_inc = 0; } else if (field == NULL) { + /* This is a far more serious error, best to avoid + opening the table and return failure. */ my_error(ER_AUTOINC_READ_FAILED, MYF(0)); } else { dict_index_t* index; @@ -2701,7 +2704,7 @@ ha_innobase::innobase_initialize_autoinc() "InnoDB: Unable to find the AUTOINC column " "%s in the InnoDB table %s.\n" "InnoDB: We set the next AUTOINC column " - "value to the maximum possible value,\n" + "value to 0,\n" "InnoDB: in effect disabling the AUTOINC " "next value generation.\n" "InnoDB: You can either set the next " @@ -2710,7 +2713,13 @@ ha_innobase::innobase_initialize_autoinc() "recreating the table.\n", col_name, index->table->name); - my_error(ER_AUTOINC_READ_FAILED, MYF(0)); + /* This will disable the AUTOINC generation. */ + auto_inc = 0; + + /* We want the open to succeed, so that the user can + take corrective action. ie. reads should succeed but + updates should fail. */ + err = DB_SUCCESS; break; default: /* row_search_max_autoinc() should only return @@ -3968,11 +3977,17 @@ no_commit: prebuilt->autoinc_error = DB_SUCCESS; if ((error = update_auto_increment())) { - /* We don't want to mask autoinc overflow errors. */ - if (prebuilt->autoinc_error != DB_SUCCESS) { - error = (int) prebuilt->autoinc_error; + /* Handle the case where the AUTOINC sub-system + failed during initialization. */ + if (prebuilt->autoinc_error == DB_UNSUPPORTED) { + error_result = ER_AUTOINC_READ_FAILED; + /* Set the error message to report too. */ + my_error(ER_AUTOINC_READ_FAILED, MYF(0)); + goto func_exit; + } else if (prebuilt->autoinc_error != DB_SUCCESS) { + error = (int) prebuilt->autoinc_error; goto report_error; } @@ -7883,7 +7898,10 @@ ha_innobase::innobase_get_autoinc( *value = dict_table_autoinc_read(prebuilt->table); /* It should have been initialized during open. */ - ut_a(*value != 0); + if (*value == 0) { + prebuilt->autoinc_error = DB_UNSUPPORTED; + dict_table_autoinc_unlock(prebuilt->table); + } } return(ulong(prebuilt->autoinc_error)); @@ -7963,11 +7981,6 @@ ha_innobase::get_auto_increment( invoking this method. So we are not sure if it's guaranteed to be 0 or not. */ - /* We need the upper limit of the col type to check for - whether we update the table autoinc counter or not. */ - ulonglong col_max_value = innobase_get_int_col_max_value( - table->next_number_field); - /* Called for the first time ? */ if (trx->n_autoinc_rows == 0) { @@ -7984,11 +7997,6 @@ ha_innobase::get_auto_increment( /* Not in the middle of a mult-row INSERT. */ } else if (prebuilt->autoinc_last_value == 0) { set_if_bigger(*first_value, autoinc); - /* Check for -ve values. */ - } else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) { - /* Set to next logical value. */ - ut_a(autoinc > trx->n_autoinc_rows); - *first_value = (autoinc - trx->n_autoinc_rows) - 1; } *nb_reserved_values = trx->n_autoinc_rows; @@ -7999,6 +8007,12 @@ ha_innobase::get_auto_increment( ulonglong need; ulonglong current; ulonglong next_value; + ulonglong col_max_value; + + /* We need the upper limit of the col type to check for + whether we update the table autoinc counter or not. */ + col_max_value = innobase_get_int_col_max_value( + table->next_number_field); current = *first_value > col_max_value ? autoinc : *first_value; need = *nb_reserved_values * increment; From 6d4e34cabbccbfe75537060e9fafed9c041d1c8d Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich <svoj@sun.com> Date: Fri, 26 Feb 2010 13:02:57 +0400 Subject: [PATCH 4/8] Applying InnoDB snapshot Detailed revision comments: r6538 | sunny | 2010-01-30 00:43:06 +0200 (Sat, 30 Jan 2010) | 6 lines branches/5.1: Check *first_value every time against the column max value and set *first_value to next autoinc if it's > col max value. ie. not rely on what is passed in from MySQL. [49497] Error 1467 (ER_AUTOINC_READ_FAILED) on inserting a negative value rb://236 --- mysql-test/r/innodb-autoinc.result | 83 +++++++++++++++++++++++++++ mysql-test/t/innodb-autoinc.test | 31 ++++++++++ storage/innobase/handler/ha_innodb.cc | 16 ++++-- 3 files changed, 124 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/innodb-autoinc.result b/mysql-test/r/innodb-autoinc.result index c03daa3565e..a36b3a1a865 100644 --- a/mysql-test/r/innodb-autoinc.result +++ b/mysql-test/r/innodb-autoinc.result @@ -1161,3 +1161,86 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`c1`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 DROP TABLE t1; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (-685113344), (1), (NULL), (NULL); +SELECT * FROM t1; +c1 +-685113344 +1 +2 +3 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (-685113344), (2), (NULL), (NULL); +SELECT * FROM t1; +c1 +-685113344 +2 +3 +4 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL), (2), (-685113344), (NULL); +INSERT INTO t1 VALUES (4), (5), (6), (NULL); +SELECT * FROM t1; +c1 +-685113344 +1 +2 +3 +4 +5 +6 +7 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL), (2), (-685113344), (5); +SELECT * FROM t1; +c1 +-685113344 +1 +2 +5 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1), (2), (-685113344), (NULL); +SELECT * FROM t1; +c1 +-685113344 +1 +2 +3 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/t/innodb-autoinc.test b/mysql-test/t/innodb-autoinc.test index bb431408937..ef0359b78b0 100644 --- a/mysql-test/t/innodb-autoinc.test +++ b/mysql-test/t/innodb-autoinc.test @@ -631,3 +631,34 @@ REPLACE INTO t1 VALUES (-1); SELECT * FROM t1; SHOW CREATE TABLE t1; DROP TABLE t1; + +## +# 49497: Error 1467 (ER_AUTOINC_READ_FAILED) on inserting a negative value +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (-685113344), (1), (NULL), (NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (-685113344), (2), (NULL), (NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL), (2), (-685113344), (NULL); +INSERT INTO t1 VALUES (4), (5), (6), (NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL), (2), (-685113344), (5); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1), (2), (-685113344), (NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index e3aa5fb4f5b..b037fa0d0fd 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -7981,6 +7981,11 @@ ha_innobase::get_auto_increment( invoking this method. So we are not sure if it's guaranteed to be 0 or not. */ + /* We need the upper limit of the col type to check for + whether we update the table autoinc counter or not. */ + ulonglong col_max_value = innobase_get_int_col_max_value( + table->next_number_field); + /* Called for the first time ? */ if (trx->n_autoinc_rows == 0) { @@ -7997,6 +8002,11 @@ ha_innobase::get_auto_increment( /* Not in the middle of a mult-row INSERT. */ } else if (prebuilt->autoinc_last_value == 0) { set_if_bigger(*first_value, autoinc); + /* Check for -ve values. */ + } else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) { + /* Set to next logical value. */ + ut_a(autoinc > trx->n_autoinc_rows); + *first_value = (autoinc - trx->n_autoinc_rows) - 1; } *nb_reserved_values = trx->n_autoinc_rows; @@ -8007,12 +8017,6 @@ ha_innobase::get_auto_increment( ulonglong need; ulonglong current; ulonglong next_value; - ulonglong col_max_value; - - /* We need the upper limit of the col type to check for - whether we update the table autoinc counter or not. */ - col_max_value = innobase_get_int_col_max_value( - table->next_number_field); current = *first_value > col_max_value ? autoinc : *first_value; need = *nb_reserved_values * increment; From 167888c6c3aa8a3caea24a1325b22ff02da902ae Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich <svoj@sun.com> Date: Fri, 26 Feb 2010 13:03:23 +0400 Subject: [PATCH 5/8] Applying InnoDB snapshot, fixes BUG#49001 Detailed revision comments: r6545 | jyang | 2010-02-03 03:57:32 +0200 (Wed, 03 Feb 2010) | 8 lines branches/5.1: Fix bug #49001, "SHOW INNODB STATUS deadlock info incorrect when deadlock detection aborts". Print the correct lock owner when recursive function lock_deadlock_recursive() exceeds its maximum depth LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK. rb://217, approved by Marko. --- storage/innobase/lock/lock0lock.c | 98 ++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 35 deletions(-) diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c index 4cc10931060..8f4b64cda96 100644 --- a/storage/innobase/lock/lock0lock.c +++ b/storage/innobase/lock/lock0lock.c @@ -306,6 +306,7 @@ FILE* lock_latest_err_file; /* Flags for recursive deadlock search */ #define LOCK_VICTIM_IS_START 1 #define LOCK_VICTIM_IS_OTHER 2 +#define LOCK_EXCEED_MAX_DEPTH 3 /************************************************************************ Checks if a lock request results in a deadlock. */ @@ -332,16 +333,18 @@ lock_deadlock_recursive( was found and we chose some other trx as a victim: we must do the search again in this last case because there may be another - deadlock! */ + deadlock! + LOCK_EXCEED_MAX_DEPTH if the lock search + exceeds max steps and/or max depth. */ trx_t* start, /* in: recursion starting point */ trx_t* trx, /* in: a transaction waiting for a lock */ lock_t* wait_lock, /* in: the lock trx is waiting to be granted */ ulint* cost, /* in/out: number of calculation steps thus far: if this exceeds LOCK_MAX_N_STEPS_... - we return LOCK_VICTIM_IS_START */ + we return LOCK_EXCEED_MAX_DEPTH */ ulint depth); /* in: recursion depth: if this exceeds LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK, we - return LOCK_VICTIM_IS_START */ + return LOCK_EXCEED_MAX_DEPTH */ /************************************************************************* Gets the nth bit of a record lock. */ @@ -3084,8 +3087,6 @@ lock_deadlock_occurs( lock_t* lock, /* in: lock the transaction is requesting */ trx_t* trx) /* in: transaction */ { - dict_table_t* table; - dict_index_t* index; trx_t* mark_trx; ulint ret; ulint cost = 0; @@ -3107,31 +3108,50 @@ retry: ret = lock_deadlock_recursive(trx, trx, lock, &cost, 0); - if (ret == LOCK_VICTIM_IS_OTHER) { + switch (ret) { + case LOCK_VICTIM_IS_OTHER: /* We chose some other trx as a victim: retry if there still is a deadlock */ - goto retry; - } - if (ret == LOCK_VICTIM_IS_START) { - if (lock_get_type(lock) & LOCK_TABLE) { - table = lock->un_member.tab_lock.table; - index = NULL; - } else { - index = lock->index; - table = index->table; - } + case LOCK_EXCEED_MAX_DEPTH: + /* If the lock search exceeds the max step + or the max depth, the current trx will be + the victim. Print its information. */ + rewind(lock_latest_err_file); + ut_print_timestamp(lock_latest_err_file); - lock_deadlock_found = TRUE; - - fputs("*** WE ROLL BACK TRANSACTION (2)\n", + fputs("TOO DEEP OR LONG SEARCH IN THE LOCK TABLE" + " WAITS-FOR GRAPH, WE WILL ROLL BACK" + " FOLLOWING TRANSACTION \n", lock_latest_err_file); - return(TRUE); + fputs("\n*** TRANSACTION:\n", lock_latest_err_file); + trx_print(lock_latest_err_file, trx, 3000); + + fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n", + lock_latest_err_file); + + if (lock_get_type(lock) == LOCK_REC) { + lock_rec_print(lock_latest_err_file, lock); + } else { + lock_table_print(lock_latest_err_file, lock); + } + break; + + case LOCK_VICTIM_IS_START: + fputs("*** WE ROLL BACK TRANSACTION (2)\n", + lock_latest_err_file); + break; + + default: + /* No deadlock detected*/ + return(FALSE); } - return(FALSE); + lock_deadlock_found = TRUE; + + return(TRUE); } /************************************************************************ @@ -3147,16 +3167,18 @@ lock_deadlock_recursive( was found and we chose some other trx as a victim: we must do the search again in this last case because there may be another - deadlock! */ + deadlock! + LOCK_EXCEED_MAX_DEPTH if the lock search + exceeds max steps and/or max depth. */ trx_t* start, /* in: recursion starting point */ trx_t* trx, /* in: a transaction waiting for a lock */ lock_t* wait_lock, /* in: the lock trx is waiting to be granted */ ulint* cost, /* in/out: number of calculation steps thus far: if this exceeds LOCK_MAX_N_STEPS_... - we return LOCK_VICTIM_IS_START */ + we return LOCK_EXCEED_MAX_DEPTH */ ulint depth) /* in: recursion depth: if this exceeds LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK, we - return LOCK_VICTIM_IS_START */ + return LOCK_EXCEED_MAX_DEPTH */ { lock_t* lock; ulint bit_no = ULINT_UNDEFINED; @@ -3215,7 +3237,7 @@ lock_deadlock_recursive( lock_trx = lock->trx; - if (lock_trx == start || too_far) { + if (lock_trx == start) { /* We came back to the recursion starting point: a deadlock detected; or we have @@ -3262,19 +3284,10 @@ lock_deadlock_recursive( } #ifdef UNIV_DEBUG if (lock_print_waits) { - fputs("Deadlock detected" - " or too long search\n", + fputs("Deadlock detected\n", stderr); } #endif /* UNIV_DEBUG */ - if (too_far) { - - fputs("TOO DEEP OR LONG SEARCH" - " IN THE LOCK TABLE" - " WAITS-FOR GRAPH\n", ef); - - return(LOCK_VICTIM_IS_START); - } if (trx_weight_cmp(wait_lock->trx, start) >= 0) { @@ -3310,6 +3323,21 @@ lock_deadlock_recursive( return(LOCK_VICTIM_IS_OTHER); } + if (too_far) { + +#ifdef UNIV_DEBUG + if (lock_print_waits) { + fputs("Deadlock search exceeds" + " max steps or depth.\n", + stderr); + } +#endif /* UNIV_DEBUG */ + /* The information about transaction/lock + to be rolled back is available in the top + level. Do not print anything here. */ + return(LOCK_EXCEED_MAX_DEPTH); + } + if (lock_trx->que_state == TRX_QUE_LOCK_WAIT) { /* Another trx ahead has requested lock in an From 757a1ff33acc48f4466cc1b720a6d45356963d43 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich <svoj@sun.com> Date: Fri, 26 Feb 2010 13:03:58 +0400 Subject: [PATCH 6/8] Applying InnoDB snapshot, fixes BUG#38901 Detailed revision comments: r6613 | inaam | 2010-02-09 20:23:09 +0200 (Tue, 09 Feb 2010) | 11 lines branches/5.1: Fix Bug #38901 InnoDB logs error repeatedly when trying to load page into buffer pool In buf_page_get_gen() if we are unable to read a page (because of corruption or some other reason) we keep on retrying. This fills up error log with millions of entries in no time and we'd eventually run out of disk space. This patch limits the number of attempts that we make (currently set to 100) and after that we abort with a message. rb://241 Approved by: Heikki --- storage/innobase/buf/buf0buf.c | 28 +++++++++++++++++++++++++++- storage/innobase/buf/buf0rea.c | 15 ++++++--------- storage/innobase/include/buf0rea.h | 6 ++---- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 901ce8e0fef..45867388a61 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -224,6 +224,9 @@ in the free list to the frames. /* Value in microseconds */ static const int WAIT_FOR_READ = 20000; +/* Number of attemtps made to read in a page in the buffer pool */ +static const ulint BUF_PAGE_READ_MAX_RETRIES = 100; + buf_pool_t* buf_pool = NULL; /* The buffer buf_pool of the database */ #ifdef UNIV_DEBUG @@ -1160,6 +1163,7 @@ buf_page_get_gen( ulint fix_type; ibool success; ibool must_read; + ulint retries = 0; ut_ad(mtr); ut_ad((rw_latch == RW_S_LATCH) @@ -1200,7 +1204,29 @@ loop: return(NULL); } - buf_read_page(space, offset); + if (buf_read_page(space, offset)) { + retries = 0; + } else if (retries < BUF_PAGE_READ_MAX_RETRIES) { + ++retries; + } else { + fprintf(stderr, "InnoDB: Error: Unable" + " to read tablespace %lu page no" + " %lu into the buffer pool after" + " %lu attempts\n" + "InnoDB: The most probable cause" + " of this error may be that the" + " table has been corrupted.\n" + "InnoDB: You can try to fix this" + " problem by using" + " innodb_force_recovery.\n" + "InnoDB: Please see reference manual" + " for more details.\n" + "InnoDB: Aborting...\n", + space, offset, + BUF_PAGE_READ_MAX_RETRIES); + + ut_error; + } #ifdef UNIV_DEBUG buf_dbg_counter++; diff --git a/storage/innobase/buf/buf0rea.c b/storage/innobase/buf/buf0rea.c index fdec0206990..451436ef75b 100644 --- a/storage/innobase/buf/buf0rea.c +++ b/storage/innobase/buf/buf0rea.c @@ -299,30 +299,27 @@ buffer buf_pool if it is not already there. Sets the io_fix flag and sets an exclusive lock on the buffer frame. The flag is cleared and the x-lock released by the i/o-handler thread. Does a random read-ahead if it seems sensible. */ - -ulint +ibool buf_read_page( /*==========*/ - /* out: number of page read requests issued: this can - be > 1 if read-ahead occurred */ + /* out: TRUE if success, FALSE otherwise */ ulint space, /* in: space id */ ulint offset) /* in: page number */ { ib_longlong tablespace_version; ulint count; - ulint count2; ulint err; tablespace_version = fil_space_get_version(space); - count = buf_read_ahead_random(space, offset); + buf_read_ahead_random(space, offset); /* We do the i/o in the synchronous aio mode to save thread switches: hence TRUE */ - count2 = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space, + count = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space, tablespace_version, offset); - srv_buf_pool_reads+= count2; + srv_buf_pool_reads+= count; if (err == DB_TABLESPACE_DELETED) { ut_print_timestamp(stderr); fprintf(stderr, @@ -336,7 +333,7 @@ buf_read_page( /* Flush pages from the end of the LRU list if necessary */ buf_flush_free_margin(); - return(count + count2); + return(count > 0); } /************************************************************************ diff --git a/storage/innobase/include/buf0rea.h b/storage/innobase/include/buf0rea.h index e4620172860..015f30fe6c2 100644 --- a/storage/innobase/include/buf0rea.h +++ b/storage/innobase/include/buf0rea.h @@ -18,12 +18,10 @@ buffer buf_pool if it is not already there. Sets the io_fix flag and sets an exclusive lock on the buffer frame. The flag is cleared and the x-lock released by the i/o-handler thread. Does a random read-ahead if it seems sensible. */ - -ulint +ibool buf_read_page( /*==========*/ - /* out: number of page read requests issued: this can - be > 1 if read-ahead occurred */ + /* out: TRUE if success, FALSE otherwise */ ulint space, /* in: space id */ ulint offset);/* in: page number */ /************************************************************************ From 42d56179506b8d8a289d0bfa7b112c54b15e4b6e Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich <svoj@sun.com> Date: Fri, 26 Feb 2010 13:04:24 +0400 Subject: [PATCH 7/8] Applying InnoDB snapshot, fixes BUG#50691 Detailed revision comments: r6669 | jyang | 2010-02-11 12:24:19 +0200 (Thu, 11 Feb 2010) | 7 lines branches/5.1: Fix bug #50691, AIX implementation of readdir_r causes InnoDB errors. readdir_r() returns an non-NULL value in the case of reaching the end of a directory. It should not be treated as an error return. rb://238 approved by Marko --- storage/innobase/os/os0file.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c index 085f62daacc..7373a97cfb0 100644 --- a/storage/innobase/os/os0file.c +++ b/storage/innobase/os/os0file.c @@ -759,7 +759,15 @@ next_file: #ifdef HAVE_READDIR_R ret = readdir_r(dir, (struct dirent*)dirent_buf, &ent); - if (ret != 0) { + if (ret != 0 +#ifdef UNIV_AIX + /* On AIX, only if we got non-NULL 'ent' (result) value and + a non-zero 'ret' (return) value, it indicates a failed + readdir_r() call. An NULL 'ent' with an non-zero 'ret' + would indicate the "end of the directory" is reached. */ + && ent != NULL +#endif + ) { fprintf(stderr, "InnoDB: cannot read directory %s, error %lu\n", dirname, (ulong)ret); From fe94dec6799b81ddc6660b3d9301deff5ac82507 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov <Sergey.Glukhov@sun.com> Date: Fri, 26 Feb 2010 15:39:25 +0400 Subject: [PATCH 8/8] Bug#50995 Having clause on subquery result produces incorrect results. The problem is that cond->fix_fields(thd, 0) breaks condition(cuts off 'having'). The reason of that is that NULL valued Item pointer is present in the middle of Item list and it breaks the Item processing loop. --- mysql-test/r/having.result | 20 ++++++++++++++++++++ mysql-test/t/having.test | 26 ++++++++++++++++++++++++++ sql/item_cmpfunc.h | 18 +++++++++++++++--- sql/sql_select.cc | 8 +++++--- 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result index 9c3cc8fc89e..68ba34e353c 100644 --- a/mysql-test/r/having.result +++ b/mysql-test/r/having.result @@ -430,4 +430,24 @@ SELECT b, COUNT(DISTINCT a) FROM t1 GROUP BY b HAVING b is NULL; b COUNT(DISTINCT a) NULL 1 DROP TABLE t1; +# +# Bug#50995 Having clause on subquery result produces incorrect results. +# +CREATE TABLE t1 +( +id1 INT, +id2 INT NOT NULL, +INDEX id1(id2) +); +INSERT INTO t1 SET id1=1, id2=1; +INSERT INTO t1 SET id1=2, id2=1; +INSERT INTO t1 SET id1=3, id2=1; +SELECT t1.id1, +(SELECT 0 FROM DUAL +WHERE t1.id1=t1.id1) AS amount FROM t1 +WHERE t1.id2 = 1 +HAVING amount > 0 +ORDER BY t1.id1; +id1 amount +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test index af9af4fe1fc..185ca4bdddb 100644 --- a/mysql-test/t/having.test +++ b/mysql-test/t/having.test @@ -442,4 +442,30 @@ INSERT INTO t1 VALUES (1, 1), (2,2), (3, NULL); SELECT b, COUNT(DISTINCT a) FROM t1 GROUP BY b HAVING b is NULL; DROP TABLE t1; + +--echo # +--echo # Bug#50995 Having clause on subquery result produces incorrect results. +--echo # + +CREATE TABLE t1 +( + id1 INT, + id2 INT NOT NULL, + INDEX id1(id2) +); + +INSERT INTO t1 SET id1=1, id2=1; +INSERT INTO t1 SET id1=2, id2=1; +INSERT INTO t1 SET id1=3, id2=1; + +SELECT t1.id1, +(SELECT 0 FROM DUAL + WHERE t1.id1=t1.id1) AS amount FROM t1 +WHERE t1.id2 = 1 +HAVING amount > 0 +ORDER BY t1.id1; + +DROP TABLE t1; + + --echo End of 5.0 tests diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 38025ff0af5..425f54fb079 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1474,9 +1474,21 @@ public: Item_cond(THD *thd, Item_cond *item); Item_cond(List<Item> &nlist) :Item_bool_func(), list(nlist), abort_on_null(0) {} - bool add(Item *item) { return list.push_back(item); } - bool add_at_head(Item *item) { return list.push_front(item); } - void add_at_head(List<Item> *nlist) { list.prepand(nlist); } + bool add(Item *item) + { + DBUG_ASSERT(item); + return list.push_back(item); + } + bool add_at_head(Item *item) + { + DBUG_ASSERT(item); + return list.push_front(item); + } + void add_at_head(List<Item> *nlist) + { + DBUG_ASSERT(nlist->elements); + list.prepand(nlist); + } bool fix_fields(THD *, Item **ref); enum Type type() const { return COND_ITEM; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b9f59fac4d6..1d88343ad6d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8200,7 +8200,8 @@ static Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, else { DBUG_ASSERT(cond->type() == Item::COND_ITEM); - ((Item_cond *) cond)->add_at_head(&eq_list); + if (eq_list.elements) + ((Item_cond *) cond)->add_at_head(&eq_list); } cond->quick_fix_field(); @@ -15657,7 +15658,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) Item_cond_and *cond=new Item_cond_and(); TABLE *table=join_tab->table; - int error; + int error= 0; if (!cond) DBUG_RETURN(TRUE); @@ -15675,7 +15676,8 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) cond->fix_fields(thd, (Item**)&cond); if (join_tab->select) { - error=(int) cond->add(join_tab->select->cond); + if (join_tab->select->cond) + error=(int) cond->add(join_tab->select->cond); join_tab->select_cond=join_tab->select->cond=cond; } else if ((join_tab->select= make_select(join_tab->table, 0, 0, cond, 0,