From da3a1c815689d81bd0ef720202536d7180825435 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 28 Aug 2012 13:51:01 +0400 Subject: [PATCH 01/21] Fix bugs in BatchedKeyAccess that show up when working with a storage engine in HA_MRR_NO_ASSOCIATION mode. (there is no testcase because we don't ship any such engines currently) --- sql/sql_join_cache.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc index d49be2e446c..5c803f85c49 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -3875,8 +3875,9 @@ int JOIN_TAB_SCAN_MRR::next() If a record in in an incremental cache contains no fields then the association for the last record in cache will be equal to cache->end_pos */ - DBUG_ASSERT(cache->buff <= (uchar *) (*ptr) && - (uchar *) (*ptr) <= cache->end_pos); + DBUG_ASSERT((!(mrr_mode & HA_MRR_NO_ASSOCIATION))? + (cache->buff <= (uchar *) (*ptr) && + (uchar *) (*ptr) <= cache->end_pos): TRUE); if (join_tab->table->vfield) update_virtual_fields(join->thd, join_tab->table); } @@ -4542,7 +4543,7 @@ bool JOIN_CACHE_BKAH::prepare_look_for_matches(bool skip_last) { last_matching_rec_ref_ptr= next_matching_rec_ref_ptr= 0; if (no_association && - (curr_matching_chain= get_matching_chain_by_join_key())) + !(curr_matching_chain= get_matching_chain_by_join_key())) return 1; last_matching_rec_ref_ptr= get_next_rec_ref(curr_matching_chain); return 0; From 95ee3fbf306d28ba315992ea4af458a4fcfb081b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 29 Aug 2012 11:35:42 +0300 Subject: [PATCH 02/21] MDEV-492: fixed incorrect error check. --- mysql-test/r/errors.result | 8 ++++++++ mysql-test/t/errors.test | 9 +++++++++ sql/sql_update.cc | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/errors.result b/mysql-test/r/errors.result index e52bdcf336c..62c9a86a46c 100644 --- a/mysql-test/r/errors.result +++ b/mysql-test/r/errors.result @@ -69,3 +69,11 @@ ERROR 42S22: Unknown column '' in 'VALUES() function' INSERT INTO t2(a,b) VALUES (1,0) ON DUPLICATE KEY UPDATE b=(SELECT VALUES(a)+2 FROM t1); DROP TABLE t1, t2; +# +# MDEV-492: incorrect error check before sending OK in mysql_update +# +CREATE TABLE t1 (a CHAR(3), b BLOB); +UPDATE t1 SET a = 'new' +WHERE COLUMN_CREATE( 1, 'v', 1, 'w' ) IS NULL; +ERROR 22007: Illegal value used as argument of dynamic column function +drop table t1; diff --git a/mysql-test/t/errors.test b/mysql-test/t/errors.test index b426d9fd5b0..b6aeee63677 100644 --- a/mysql-test/t/errors.test +++ b/mysql-test/t/errors.test @@ -85,3 +85,12 @@ INSERT INTO t2 VALUES (1,0) ON DUPLICATE KEY UPDATE INSERT INTO t2(a,b) VALUES (1,0) ON DUPLICATE KEY UPDATE b=(SELECT VALUES(a)+2 FROM t1); DROP TABLE t1, t2; + +--echo # +--echo # MDEV-492: incorrect error check before sending OK in mysql_update +--echo # +CREATE TABLE t1 (a CHAR(3), b BLOB); +--error ER_DYN_COL_DATA +UPDATE t1 SET a = 'new' +WHERE COLUMN_CREATE( 1, 'v', 1, 'w' ) IS NULL; +drop table t1; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 4f816e5f032..7d6eb62f57d 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -359,7 +359,7 @@ int mysql_update(THD *thd, table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); select= make_select(table, 0, 0, conds, 0, &error); - if (error || !limit || + if (error || !limit || thd->is_error() || (select && select->check_quick(thd, safe_update, limit))) { delete select; From a44331ab3407488368c9984258ce4c3160872816 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 29 Aug 2012 10:59:51 +0200 Subject: [PATCH 03/21] MDEV-456 An out-of-range datetime value (with a 5-digit year) can be created and cause troubles fix Item_func_add_time::get_date() to generate valid dates. Move the validity check inside get_date_from_daynr() instead of relying on callers (5 that had it, and 2 that did not, but should've) --- mysql-test/r/datetime_456.result | 8 ++++ mysql-test/t/datetime_456.test | 8 ++++ sql/item_timefunc.cc | 35 ++++++++------- sql/mysql_priv.h | 2 +- sql/time.cc | 75 +++++++++++++++----------------- 5 files changed, 68 insertions(+), 60 deletions(-) create mode 100644 mysql-test/r/datetime_456.result create mode 100644 mysql-test/t/datetime_456.test diff --git a/mysql-test/r/datetime_456.result b/mysql-test/r/datetime_456.result new file mode 100644 index 00000000000..ba020a250b7 --- /dev/null +++ b/mysql-test/r/datetime_456.result @@ -0,0 +1,8 @@ +create table t1 (d datetime); +insert t1 values (addtime('9999-12-31 23:59:59', '00:00:01')), +(from_days(3652499)); +select * from t1; +d +NULL +NULL +drop table t1; diff --git a/mysql-test/t/datetime_456.test b/mysql-test/t/datetime_456.test new file mode 100644 index 00000000000..0c187959d52 --- /dev/null +++ b/mysql-test/t/datetime_456.test @@ -0,0 +1,8 @@ +# +# MDEV-456 An out-of-range datetime value (with a 5-digit year) can be created and cause troubles +# +create table t1 (d datetime); +insert t1 values (addtime('9999-12-31 23:59:59', '00:00:01')), + (from_days(3652499)); +select * from t1; +drop table t1; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index eec8dde080c..2cd8b3215c4 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -341,9 +341,8 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, { uint days; days= calc_daynr(l_time->year,1,1) + yearday - 1; - if (days <= 0 || days > MAX_DAY_NUMBER) + if (get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day)) goto err; - get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); } if (week_number >= 0 && weekday) @@ -388,9 +387,8 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, (weekday - 1); } - if (days <= 0 || days > MAX_DAY_NUMBER) + if (get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day)) goto err; - get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); } if (l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || @@ -1385,13 +1383,16 @@ bool Item_func_from_days::get_date(MYSQL_TIME *ltime, uint fuzzy_date) if ((null_value=args[0]->null_value)) return 1; bzero(ltime, sizeof(MYSQL_TIME)); - get_date_from_daynr((long) value, <ime->year, <ime->month, <ime->day); - if ((null_value= ((fuzzy_date & TIME_NO_ZERO_DATE) && ltime->year == 0))) - return TRUE; + if (get_date_from_daynr((long) value, <ime->year, <ime->month, + <ime->day)) + return (null_value= 1); + + if ((fuzzy_date & TIME_NO_ZERO_DATE) && ltime->year == 0) + return (null_value= 1); ltime->time_type= MYSQL_TIMESTAMP_DATE; - return 0; + return (null_value= 0); } @@ -2388,14 +2389,12 @@ bool Item_func_makedate::get_date(MYSQL_TIME *ltime, uint fuzzy_date) year= year_2000_handling(year); days= calc_daynr(year,1,1) + daynr - 1; - /* Day number from year 0 to 9999-12-31 */ - if (days >= 0 && days <= MAX_DAY_NUMBER) - { - bzero(ltime, sizeof(*ltime)); - ltime->time_type= MYSQL_TIMESTAMP_DATE; - get_date_from_daynr(days, <ime->year, <ime->month, <ime->day); - return (null_value= 0); - } + if (get_date_from_daynr(days, <ime->year, <ime->month, <ime->day)) + goto err; + ltime->time_type= MYSQL_TIMESTAMP_DATE; + ltime->neg= 0; + ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; + return (null_value= 0); err: return (null_value= 1); @@ -2489,8 +2488,8 @@ bool Item_func_add_time::get_date(MYSQL_TIME *ltime, uint fuzzy_date) if (!is_time) { - get_date_from_daynr(days,<ime->year,<ime->month,<ime->day); - if (!ltime->day) + if (get_date_from_daynr(days,<ime->year,<ime->month,<ime->day) || + !ltime->day) return (null_value= 1); return (null_value= 0); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 605d9353cae..14810fc7119 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -2445,7 +2445,7 @@ void free_field_buffers_larger_than(TABLE *table, uint32 size); int set_zone(int nr,int min_zone,int max_zone); ulong convert_period_to_month(ulong period); ulong convert_month_to_period(ulong month); -void get_date_from_daynr(long daynr,uint *year, uint *month, +bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day); my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error); bool str_to_time_with_warn(const char *str,uint length,MYSQL_TIME *l_time, diff --git a/sql/time.cc b/sql/time.cc index 778f8b8f313..21ecc3f8050 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -24,9 +24,9 @@ #include - /* Some functions to calculate dates */ +#define MAX_DAY_NUMBER 3652424L -#ifndef TESTTIME + /* Some functions to calculate dates */ /* Name description of interval names used in statements. @@ -146,46 +146,42 @@ uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year) /* Change a daynr to year, month and day */ /* Daynr 0 is returned as date 00.00.00 */ -void get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month, +bool get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month, uint *ret_day) { uint year,temp,leap_day,day_of_year,days_in_year; uchar *month_pos; DBUG_ENTER("get_date_from_daynr"); - if (daynr <= 365L || daynr >= 3652500) - { /* Fix if wrong daynr */ - *ret_year= *ret_month = *ret_day =0; - } - else + if (daynr < 365 || daynr > MAX_DAY_NUMBER) + DBUG_RETURN(1); + + year= (uint) (daynr*100 / 36525L); + temp=(((year-1)/100+1)*3)/4; + day_of_year=(uint) (daynr - (long) year * 365L) - (year-1)/4 +temp; + while (day_of_year > (days_in_year= calc_days_in_year(year))) { - year= (uint) (daynr*100 / 36525L); - temp=(((year-1)/100+1)*3)/4; - day_of_year=(uint) (daynr - (long) year * 365L) - (year-1)/4 +temp; - while (day_of_year > (days_in_year= calc_days_in_year(year))) - { - day_of_year-=days_in_year; - (year)++; - } - leap_day=0; - if (days_in_year == 366) - { - if (day_of_year > 31+28) - { - day_of_year--; - if (day_of_year == 31+28) - leap_day=1; /* Handle leapyears leapday */ - } - } - *ret_month=1; - for (month_pos= days_in_month ; - day_of_year > (uint) *month_pos ; - day_of_year-= *(month_pos++), (*ret_month)++) - ; - *ret_year=year; - *ret_day=day_of_year+leap_day; + day_of_year-=days_in_year; + (year)++; } - DBUG_VOID_RETURN; + leap_day=0; + if (days_in_year == 366) + { + if (day_of_year > 31+28) + { + day_of_year--; + if (day_of_year == 31+28) + leap_day=1; /* Handle leapyears leapday */ + } + } + *ret_month=1; + for (month_pos= days_in_month ; + day_of_year > (uint) *month_pos ; + day_of_year-= *(month_pos++), (*ret_month)++) + ; + *ret_year=year; + *ret_day=day_of_year+leap_day; + DBUG_RETURN(0); } /* Functions to handle periods */ @@ -805,7 +801,6 @@ void make_truncated_value_warning(THD *thd, /* Daynumber from year 0 to 9999-12-31 */ -#define MAX_DAY_NUMBER 3652424L #define COMBINE(X) \ (((((X)->day * 24LL + (X)->hour) * 60LL + \ (X)->minute) * 60LL + (X)->second)*1000000LL + \ @@ -872,19 +867,18 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, daynr= usec; /* Day number from year 0 to 9999-12-31 */ - if ((ulonglong) daynr > MAX_DAY_NUMBER) + if (get_date_from_daynr((long) daynr, <ime->year, <ime->month, + <ime->day)) goto invalid_date; - get_date_from_daynr((long) daynr, <ime->year, <ime->month, - <ime->day); break; } case INTERVAL_WEEK: period= (calc_daynr(ltime->year,ltime->month,ltime->day) + sign * (long) interval.day); /* Daynumber from year 0 to 9999-12-31 */ - if ((ulong) period > MAX_DAY_NUMBER) + if (get_date_from_daynr((long) period,<ime->year,<ime->month, + <ime->day)) goto invalid_date; - get_date_from_daynr((long) period,<ime->year,<ime->month,<ime->day); break; case INTERVAL_YEAR: ltime->year+= sign * (long) interval.year; @@ -1034,4 +1028,3 @@ int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b) return 0; } -#endif From 3444e8e9254070f836488dae12b5c825cc9c563f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 29 Aug 2012 17:55:59 +0200 Subject: [PATCH 04/21] MDEV-454 Addition of a time interval reduces the resulting value 1. Field_newdate::get_date should refuse to return a date with zeros when TIME_NO_ZERO_IN_DATE is set, not when TIME_FUZZY_DATE is unset 2. Item_func_to_days and Item_date_add_interval can only work with valid dates, no zeros allowed. --- mysql-test/r/adddate_454.result | 10 ++++++++++ mysql-test/t/adddate_454.test | 9 +++++++++ sql/field.cc | 2 +- sql/item_timefunc.cc | 4 ++-- 4 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 mysql-test/r/adddate_454.result create mode 100644 mysql-test/t/adddate_454.test diff --git a/mysql-test/r/adddate_454.result b/mysql-test/r/adddate_454.result new file mode 100644 index 00000000000..0993cdce32c --- /dev/null +++ b/mysql-test/r/adddate_454.result @@ -0,0 +1,10 @@ +create table t1 (d date); +insert into t1 values ('2012-00-00'); +select * from t1; +d +2012-00-00 +update t1 set d = adddate(d, interval 1 day); +select * from t1; +d +NULL +drop table t1; diff --git a/mysql-test/t/adddate_454.test b/mysql-test/t/adddate_454.test new file mode 100644 index 00000000000..1d69cdc9558 --- /dev/null +++ b/mysql-test/t/adddate_454.test @@ -0,0 +1,9 @@ +# +# MDEV-454 Addition of a time interval reduces the resulting value +# +create table t1 (d date); +insert into t1 values ('2012-00-00'); +select * from t1; +update t1 set d = adddate(d, interval 1 day); +select * from t1; +drop table t1; diff --git a/sql/field.cc b/sql/field.cc index cf5b6cf2ff9..9b0f6a7dfcd 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5789,7 +5789,7 @@ bool Field_newdate::get_date(MYSQL_TIME *ltime,uint fuzzydate) if (!tmp) return fuzzydate & TIME_NO_ZERO_DATE; if (!ltime->month || !ltime->day) - return !(fuzzydate & TIME_FUZZY_DATE); + return fuzzydate & TIME_NO_ZERO_IN_DATE; return 0; } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 2cd8b3215c4..bdad96f12ef 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -751,7 +751,7 @@ longlong Item_func_to_days::val_int() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; - if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) + if (get_arg0_date(<ime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)) return 0; return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day); } @@ -1932,7 +1932,7 @@ bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, uint fuzzy_date) { INTERVAL interval; - if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE | TIME_FUZZY_DATE) || + if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE | TIME_FUZZY_DATE | TIME_NO_ZERO_IN_DATE) || get_interval_value(args[1], int_type, &value, &interval)) return (null_value=1); From 2de4f09a75ad878753bb090a4c04291113d7a0c0 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 29 Aug 2012 18:36:57 +0200 Subject: [PATCH 05/21] MDEV-438 Microseconds: Precision is ignored in CURRENT_TIMESTAMP(N) when it is given as a default column value The syntax for specifying precision in the DEFAULT clause is unintentional and unsupported. Don't allow it anymore. --- sql/sql_yacc.yy | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0f013bfb566..b1772536639 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5453,9 +5453,9 @@ attribute: NULL_SYM { Lex->type&= ~ NOT_NULL_FLAG; } | not NULL_SYM { Lex->type|= NOT_NULL_FLAG; } | DEFAULT now_or_signed_literal { Lex->default_value=$2; } - | ON UPDATE_SYM NOW_SYM opt_time_precision + | ON UPDATE_SYM NOW_SYM optional_braces { - Item *item= new (YYTHD->mem_root) Item_func_now_local($4); + Item *item= new (YYTHD->mem_root) Item_func_now_local(6); if (item == NULL) MYSQL_YYABORT; Lex->on_update_value= item; @@ -5525,9 +5525,9 @@ attribute: ; now_or_signed_literal: - NOW_SYM opt_time_precision + NOW_SYM optional_braces { - $$= new (YYTHD->mem_root) Item_func_now_local($2); + $$= new (YYTHD->mem_root) Item_func_now_local(6); if ($$ == NULL) MYSQL_YYABORT; } From 0536c506ff7c3ed261abc3d02fb787bfdd228abb Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 30 Aug 2012 09:05:27 +0200 Subject: [PATCH 06/21] MDEV-437 Microseconds: In time functions precision is calculated modulo 256 store the precision in uint, not uint8 --- mysql-test/r/func_time.result | 2 ++ mysql-test/t/func_time.test | 2 ++ sql/item.h | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index b3e2a01e2e3..2df0c691083 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -1897,3 +1897,5 @@ cast(greatest(cast("0-0-0" as date), cast("10:20:05" as time)) as datetime(6)) select microsecond('12:00:00.123456'), microsecond('2009-12-31 23:59:59.000010'); microsecond('12:00:00.123456') microsecond('2009-12-31 23:59:59.000010') 123456 10 +select now(258); +ERROR 42000: Too big precision 258 specified for 'now'. Maximum is 6. diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 07e6473bfdf..c3d1d74ec50 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -1142,3 +1142,5 @@ select cast(greatest(cast("0-0-0" as date), cast("10:20:05" as time)) as datetim select microsecond('12:00:00.123456'), microsecond('2009-12-31 23:59:59.000010'); +--error ER_TOO_BIG_PRECISION +select now(258); diff --git a/sql/item.h b/sql/item.h index ab5243a3d0a..055225a79d7 100644 --- a/sql/item.h +++ b/sql/item.h @@ -582,8 +582,8 @@ public: calls. */ uint name_length; /* Length of name */ + uint decimals; int8 marker; - uint8 decimals; bool maybe_null; /* If item may be null */ bool in_rollup; /* If used in GROUP BY list of a query with ROLLUP */ From 10802c4d9046fd54bf1a27cb7611c182ecde93fb Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 30 Aug 2012 10:53:49 +0200 Subject: [PATCH 07/21] MDEV-381: fdatasync() does not correctly flush growing binlog file. When we append data to the binlog file, we use fdatasync() to ensure the data gets to disk so that crash recovery can work. Unfortunately there seems to be a bug in ext3/ext4 on linux, so that fdatasync() does not correctly sync all data when the size of a file is increased. This causes crash recovery to not work correctly (it loses transactions from the binlog). As a work-around, use fsync() for the binlog, not fdatasync(). Since we are increasing the file size, (correct) fdatasync() will most likely not be faster than fsync() on any file system, and fsync() does work correctly on ext3/ext4. This avoids the need to try to detect if we are running on buggy ext3/ext4. --- include/my_sys.h | 1 + mysys/my_sync.c | 18 ++++++++++++++++-- sql/log.cc | 10 +++++----- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index db22f55f492..ebe643abce5 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -70,6 +70,7 @@ extern int NEAR my_errno; /* Last error in mysys */ #define MY_THREADSAFE 2048 /* my_seek(): lock fd mutex */ #define MY_SYNC 4096 /* my_copy(): sync dst file */ #define MY_SYNC_DIR 32768 /* my_create/delete/rename: sync directory */ +#define MY_SYNC_FILESIZE 65536 /* my_sync(): safe sync when file is extended */ #define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */ #define MY_GIVE_INFO 2 /* Give time info about process*/ diff --git a/mysys/my_sync.c b/mysys/my_sync.c index d8973244620..33033ff1045 100644 --- a/mysys/my_sync.c +++ b/mysys/my_sync.c @@ -39,6 +39,13 @@ ulong my_sync_count; /* Count number of sync calls */ (which is correct behaviour, if we know that the other thread synced the file before closing) + MY_SYNC_FILESIZE is useful when syncing a file after it has been extended. + On Linux, fdatasync() on ext3/ext4 file systems does not properly flush + to disk the inode data required to preserve the added data across a crash + (this looks to be a bug). But when a file is extended, inode data will most + likely need flushing in any case, so passing MY_SYNC_FILESIZE as flags + is not likely to be any slower, and will be crash safe on Linux ext3/ext4. + RETURN 0 ok -1 error @@ -67,8 +74,12 @@ int my_sync(File fd, myf my_flags) DBUG_PRINT("info",("fcntl(F_FULLFSYNC) failed, falling back")); #endif #if defined(HAVE_FDATASYNC) && HAVE_DECL_FDATASYNC - res= fdatasync(fd); -#elif defined(HAVE_FSYNC) + if (!(my_flags & MY_SYNC_FILESIZE)) + res= fdatasync(fd); + else + { +#endif +#if defined(HAVE_FSYNC) res= fsync(fd); if (res == -1 && errno == ENOLCK) res= 0; /* Result Bug in Old FreeBSD */ @@ -77,6 +88,9 @@ int my_sync(File fd, myf my_flags) #else #error Cannot find a way to sync a file, durability in danger res= 0; /* No sync (strange OS) */ +#endif +#if defined(HAVE_FDATASYNC) && HAVE_DECL_FDATASYNC + } #endif } while (res == -1 && errno == EINTR); diff --git a/sql/log.cc b/sql/log.cc index ddb12457fcd..05e8a66ed04 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2838,7 +2838,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name, bytes_written+= description_event_for_queue->data_written; } if (flush_io_cache(&log_file) || - my_sync(log_file.file, MYF(MY_WME))) + my_sync(log_file.file, MYF(MY_WME|MY_SYNC_FILESIZE))) goto err; pthread_mutex_lock(&LOCK_commit_ordered); strmake(last_commit_pos_file, log_file_name, @@ -2864,7 +2864,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name, strlen(log_file_name)) || my_b_write(&index_file, (uchar*) "\n", 1) || flush_io_cache(&index_file) || - my_sync(index_file.file, MYF(MY_WME))) + my_sync(index_file.file, MYF(MY_WME|MY_SYNC_FILESIZE))) goto err; #ifdef HAVE_REPLICATION @@ -2956,7 +2956,7 @@ static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset) } /* The following will either truncate the file or fill the end with \n' */ if (my_chsize(file, offset - init_offset, '\n', MYF(MY_WME)) || - my_sync(file, MYF(MY_WME))) + my_sync(file, MYF(MY_WME|MY_SYNC_FILESIZE))) goto err; /* Reset data in old index cache */ @@ -3549,7 +3549,7 @@ int MYSQL_BIN_LOG::sync_purge_index_file() DBUG_ENTER("MYSQL_BIN_LOG::sync_purge_index_file"); if ((error= flush_io_cache(&purge_index_file)) || - (error= my_sync(purge_index_file.file, MYF(MY_WME)))) + (error= my_sync(purge_index_file.file, MYF(MY_WME|MY_SYNC_FILESIZE)))) DBUG_RETURN(error); DBUG_RETURN(error); @@ -4139,7 +4139,7 @@ bool MYSQL_BIN_LOG::flush_and_sync() if (++sync_binlog_counter >= sync_binlog_period && sync_binlog_period) { sync_binlog_counter= 0; - err=my_sync(fd, MYF(MY_WME)); + err=my_sync(fd, MYF(MY_WME|MY_SYNC_FILESIZE)); #ifndef DBUG_OFF if (opt_binlog_dbug_fsync_sleep > 0) my_sleep(opt_binlog_dbug_fsync_sleep); From 57694d52b470cf328e7d339dc0934da2b0238841 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 30 Aug 2012 11:47:01 +0200 Subject: [PATCH 08/21] MDEV-395 PR_SET_DUMPABLE set in unreachable code --- sql/mysqld.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index aa5efe4fbe6..47be8551359 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2026,13 +2026,19 @@ static struct passwd *check_user(const char *user) if (!(tmp_user_info= getpwuid(atoi(user)))) goto err; } + return tmp_user_info; /* purecov: end */ err: sql_print_error("Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user); unireg_abort(1); +#endif + return NULL; +} +static inline void allow_coredumps() +{ #ifdef PR_SET_DUMPABLE if (test_flags & TEST_CORE_ON_SIGNAL) { @@ -2040,11 +2046,9 @@ err: (void) prctl(PR_SET_DUMPABLE, 1); } #endif - -#endif - return NULL; } + static void set_user(const char *user, struct passwd *user_info_arg) { /* purecov: begin tested */ @@ -2071,6 +2075,7 @@ static void set_user(const char *user, struct passwd *user_info_arg) sql_perror("setuid"); unireg_abort(1); } + allow_coredumps(); #endif /* purecov: end */ } @@ -2090,6 +2095,7 @@ static void set_effective_user(struct passwd *user_info_arg) sql_perror("setreuid"); unireg_abort(1); } + allow_coredumps(); #endif } From 51e14492e9410718056b0c6d9d4dabd4a96e8070 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 31 Aug 2012 12:01:52 +0200 Subject: [PATCH 09/21] compilation warning --- sql/item.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item.cc b/sql/item.cc index f10c491853e..e125e57d2fc 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -454,8 +454,8 @@ Item::Item(THD *thd, Item *item): orig_name(item->orig_name), max_length(item->max_length), name_length(item->name_length), - marker(item->marker), decimals(item->decimals), + marker(item->marker), maybe_null(item->maybe_null), in_rollup(item->in_rollup), null_value(item->null_value), From a1fd37b1fd5803188d3f8b44914cca459f6e622f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 31 Aug 2012 13:03:41 +0200 Subject: [PATCH 10/21] MDEV-414 Depending on indexes or execution plans, a warning on incorrect or out of range values in WHERE condition is sometimes produced and sometimes not use the same method that disables warnings in all relevant places, remove redundant function --- mysql-test/r/partition_pruning.result | 6 ++--- mysql-test/r/type_date.result | 12 ++-------- sql/opt_sum.cc | 2 +- sql/sql_select.cc | 33 +-------------------------- sql/sql_select.h | 2 +- 5 files changed, 8 insertions(+), 47 deletions(-) diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index 4d48b70d26a..ec7fd798d4c 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -787,7 +787,7 @@ id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t1 pNULL,p2001-01-01 index a a 4 NULL 4 Using where; Using index EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1999-02-31'; id select_type table partitions type possible_keys key key_len ref rows Extra -1 SIMPLE t1 pNULL ref a a 4 const 1 Using where; Using index +1 SIMPLE t1 pNULL ref a a 4 const 1 Using index EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1002-00-00'; id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t1 pNULL,p0001-01-01,p1001-01-01,p2001-01-01 range a a 4 NULL 4 Using where; Using index @@ -1116,7 +1116,7 @@ id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t1 p2001-01-01,pNULL index a a 4 NULL 4 Using where; Using index EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1999-02-31'; id select_type table partitions type possible_keys key key_len ref rows Extra -1 SIMPLE t1 pNULL ref a a 4 const 1 Using where; Using index +1 SIMPLE t1 pNULL ref a a 4 const 1 Using index EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1002-00-00'; id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02,p1001-01-01 range a a 4 NULL 4 Using where; Using index @@ -1445,7 +1445,7 @@ id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t1 p2001-01-01,pNULL index a a 4 NULL 4 Using where; Using index EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1999-02-31'; id select_type table partitions type possible_keys key key_len ref rows Extra -1 SIMPLE t1 pNULL ref a a 4 const 1 Using where; Using index +1 SIMPLE t1 pNULL ref a a 4 const 1 Using index EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1002-00-00'; id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02,p1001-01-01 range a a 4 NULL 4 Using where; Using index diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result index 41f590400ea..8a85cd53b2a 100644 --- a/mysql-test/r/type_date.result +++ b/mysql-test/r/type_date.result @@ -209,15 +209,11 @@ a SET SQL_MODE=TRADITIONAL; EXPLAIN SELECT * FROM t1 WHERE a = '0000-00-00'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref i i 4 const 1 Using where; Using index -Warnings: -Warning 1264 Out of range value for column 'a' at row 1 +1 SIMPLE t1 ref i i 4 const 1 Using index SELECT * FROM t1 WHERE a = '0000-00-00'; a 0000-00-00 0000-00-00 -Warnings: -Warning 1264 Out of range value for column 'a' at row 1 SELECT * FROM t2 WHERE a = '0000-00-00'; a 0000-00-00 @@ -242,15 +238,11 @@ a SET SQL_MODE=TRADITIONAL; EXPLAIN SELECT * FROM t1 WHERE a = '1000-00-00'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref i i 4 const 1 Using where; Using index -Warnings: -Warning 1265 Data truncated for column 'a' at row 1 +1 SIMPLE t1 ref i i 4 const 1 Using index SELECT * FROM t1 WHERE a = '1000-00-00'; a 1000-00-00 1000-00-00 -Warnings: -Warning 1265 Data truncated for column 'a' at row 1 SELECT * FROM t2 WHERE a = '1000-00-00'; a 1000-00-00 diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index cbec039b3e4..fa3a07b72c5 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -791,7 +791,7 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, { /* Update endpoints for MAX/MIN, see function comment. */ Item *value= args[between && max_fl ? 2 : 1]; - store_val_in_field(part->field, value, CHECK_FIELD_IGNORE); + value->save_in_field_no_warnings(part->field, 1); if (part->null_bit) *key_ptr++= (uchar) test(part->field->is_null()); part->field->get_key_image(key_ptr, part->length, Field::itRAW); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b1d1a84f5b2..0e5aa0e0aaa 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8027,37 +8027,6 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables, keyuse->val, FALSE); } -/** - This function is only called for const items on fields which are keys. - - @return - returns 1 if there was some conversion made when the field was stored. -*/ - -bool -store_val_in_field(Field *field, Item *item, enum_check_fields check_flag) -{ - bool error; - TABLE *table= field->table; - THD *thd= table->in_use; - ha_rows cuted_fields=thd->cuted_fields; - my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, - table->write_set); - - /* - we should restore old value of count_cuted_fields because - store_val_in_field can be called from mysql_insert - with select_insert, which make count_cuted_fields= 1 - */ - enum_check_fields old_count_cuted_fields= thd->count_cuted_fields; - thd->count_cuted_fields= check_flag; - error= item->save_in_field(field, 1); - thd->count_cuted_fields= old_count_cuted_fields; - dbug_tmp_restore_column_map(table->write_set, old_map); - return error || cuted_fields != thd->cuted_fields; -} - - /** @details Initialize a JOIN as a query execution plan that accesses a single table via a table scan. @@ -17698,7 +17667,7 @@ bool test_if_ref(Item *root_cond, Item_field *left_item,Item *right_item) field->real_type() != MYSQL_TYPE_VARCHAR && (field->type() != MYSQL_TYPE_FLOAT || field->decimals() == 0)) { - return !store_val_in_field(field, right_item, CHECK_FIELD_WARN); + return !right_item->save_in_field_no_warnings(field, 1); } } } diff --git a/sql/sql_select.h b/sql/sql_select.h index be5f523a7e2..118a684ab62 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1430,7 +1430,6 @@ typedef struct st_select_check { extern const char *join_type_str[]; /* Extern functions in sql_select.cc */ -bool store_val_in_field(Field *field, Item *val, enum_check_fields check_flag); void count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, List &fields, bool reset_with_sum_func); bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, @@ -1504,6 +1503,7 @@ public: enum_check_fields saved_count_cuted_fields= thd->count_cuted_fields; ulonglong sql_mode= thd->variables.sql_mode; thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE); + thd->variables.sql_mode|= MODE_INVALID_DATES; thd->count_cuted_fields= CHECK_FIELD_IGNORE; From 01ef1f0d7964b1f4c0adff290c406f7d8bd0237e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 31 Aug 2012 16:48:02 +0200 Subject: [PATCH 11/21] fix the test to work with --lower-case-table-names=1 --- mysql-test/suite/rpl/r/rpl_mdev382.result | 82 +++++++++++------------ mysql-test/suite/rpl/t/rpl_mdev382.test | 34 +++++----- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_mdev382.result b/mysql-test/suite/rpl/r/rpl_mdev382.result index 50da7e67bba..b564dd8401e 100644 --- a/mysql-test/suite/rpl/r/rpl_mdev382.result +++ b/mysql-test/suite/rpl/r/rpl_mdev382.result @@ -77,8 +77,8 @@ master-bin.000001 # Query # # use `test`; insert into t1 values(18) master-bin.000001 # Xid # # COMMIT /* XID */ *** Test correct USE statement in SHOW BINLOG EVENTS *** set sql_mode = 'ANSI_QUOTES'; -CREATE DATABASE "db1`; SELECT 'oops!'"; -use "db1`; SELECT 'oops!'"; +CREATE DATABASE "db1`; select 'oops!'"; +use "db1`; select 'oops!'"; CREATE TABLE t1 (a INT PRIMARY KEY) engine=MyISAM; INSERT INTO t1 VALUES (1); set sql_mode = ''; @@ -86,41 +86,41 @@ INSERT INTO t1 VALUES (2); set sql_mode = 'ANSI_QUOTES'; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # CREATE DATABASE "db1`; SELECT 'oops!'" -master-bin.000001 # Query # # use "db1`; SELECT 'oops!'"; CREATE TABLE t1 (a INT PRIMARY KEY) engine=MyISAM +master-bin.000001 # Query # # CREATE DATABASE "db1`; select 'oops!'" +master-bin.000001 # Query # # use "db1`; select 'oops!'"; CREATE TABLE t1 (a INT PRIMARY KEY) engine=MyISAM master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use "db1`; SELECT 'oops!'"; INSERT INTO t1 VALUES (1) +master-bin.000001 # Query # # use "db1`; select 'oops!'"; INSERT INTO t1 VALUES (1) master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use "db1`; SELECT 'oops!'"; INSERT INTO t1 VALUES (2) +master-bin.000001 # Query # # use "db1`; select 'oops!'"; INSERT INTO t1 VALUES (2) master-bin.000001 # Query # # COMMIT set sql_mode = ''; set sql_quote_show_create = 0; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # CREATE DATABASE "db1`; SELECT 'oops!'" -master-bin.000001 # Query # # use `db1``; SELECT 'oops!'`; CREATE TABLE t1 (a INT PRIMARY KEY) engine=MyISAM +master-bin.000001 # Query # # CREATE DATABASE "db1`; select 'oops!'" +master-bin.000001 # Query # # use `db1``; select 'oops!'`; CREATE TABLE t1 (a INT PRIMARY KEY) engine=MyISAM master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use `db1``; SELECT 'oops!'`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Query # # use `db1``; select 'oops!'`; INSERT INTO t1 VALUES (1) master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use `db1``; SELECT 'oops!'`; INSERT INTO t1 VALUES (2) +master-bin.000001 # Query # # use `db1``; select 'oops!'`; INSERT INTO t1 VALUES (2) master-bin.000001 # Query # # COMMIT set sql_quote_show_create = 1; show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # CREATE DATABASE "db1`; SELECT 'oops!'" -master-bin.000001 # Query # # use `db1``; SELECT 'oops!'`; CREATE TABLE t1 (a INT PRIMARY KEY) engine=MyISAM +master-bin.000001 # Query # # CREATE DATABASE "db1`; select 'oops!'" +master-bin.000001 # Query # # use `db1``; select 'oops!'`; CREATE TABLE t1 (a INT PRIMARY KEY) engine=MyISAM master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use `db1``; SELECT 'oops!'`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Query # # use `db1``; select 'oops!'`; INSERT INTO t1 VALUES (1) master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use `db1``; SELECT 'oops!'`; INSERT INTO t1 VALUES (2) +master-bin.000001 # Query # # use `db1``; select 'oops!'`; INSERT INTO t1 VALUES (2) master-bin.000001 # Query # # COMMIT DROP TABLE t1; use test; ***Test LOAD DATA INFILE with various identifiers that need correct quoting *** -use `db1``; SELECT 'oops!'`; +use `db1``; select 'oops!'`; set timestamp=1000000000; CREATE TABLE `t``1` (`a``1` VARCHAR(4) PRIMARY KEY, `b``2` VARCHAR(3), `c``3` VARCHAR(7)); @@ -134,31 +134,31 @@ fo\o bar |b"a'z! truncate `t``1`; use test; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/f''le.txt' - INTO TABLE `db1``; SELECT 'oops!'`.`t``1` + INTO TABLE `db1``; select 'oops!'`.`t``1` FIELDS TERMINATED BY ',' ESCAPED BY '\\' ENCLOSED BY '''' LINES TERMINATED BY '\n' (`a``1`, `b``2`) SET `c``3` = concat('|', "b""a'z", "!"); -SELECT * FROM `db1``; SELECT 'oops!'`.`t``1`; +SELECT * FROM `db1``; select 'oops!'`.`t``1`; a`1 b`2 c`3 fo\o bar |b"a'z! show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # use `db1``; SELECT 'oops!'`; CREATE TABLE `t``1` (`a``1` VARCHAR(4) PRIMARY KEY, `b``2` VARCHAR(3), +master-bin.000001 # Query # # use `db1``; select 'oops!'`; CREATE TABLE `t``1` (`a``1` VARCHAR(4) PRIMARY KEY, `b``2` VARCHAR(3), `c``3` VARCHAR(7)) master-bin.000001 # Query # # BEGIN master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# -master-bin.000001 # Execute_load_query # # use `db1``; SELECT 'oops!'`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/f\'le.txt' INTO TABLE `t``1` FIELDS TERMINATED BY ',' ENCLOSED BY '\'' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a``1`, @`b```) SET `b``2`= @`b```, `c``3`= concat('|', "b""a'z", "!") ;file_id=# +master-bin.000001 # Execute_load_query # # use `db1``; select 'oops!'`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/f\'le.txt' INTO TABLE `t``1` FIELDS TERMINATED BY ',' ENCLOSED BY '\'' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a``1`, @`b```) SET `b``2`= @`b```, `c``3`= concat('|', "b""a'z", "!") ;file_id=# master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # use `db1``; SELECT 'oops!'`; truncate `t``1` +master-bin.000001 # Query # # use `db1``; select 'oops!'`; truncate `t``1` master-bin.000001 # Query # # BEGIN master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# -master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/f\'le.txt' INTO TABLE `db1``; SELECT 'oops!'`.`t``1` FIELDS TERMINATED BY ',' ENCLOSED BY '\'' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a``1`, `b``2`) SET `c``3`= concat('|', "b""a'z", "!") ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/f\'le.txt' INTO TABLE `db1``; select 'oops!'`.`t``1` FIELDS TERMINATED BY ',' ENCLOSED BY '\'' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a``1`, `b``2`) SET `c``3`= concat('|', "b""a'z", "!") ;file_id=# master-bin.000001 # Query # # COMMIT /*!40019 SET @@session.max_insert_delayed_threads=0*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; ROLLBACK/*!*/; -use `db1``; SELECT 'oops!'`/*!*/; +use `db1``; select 'oops!'`/*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.pseudo_thread_id=999999999/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; @@ -188,7 +188,7 @@ BEGIN /*!*/; use `test`/*!*/; SET TIMESTAMP=1000000000/*!*/; -LOAD DATA LOCAL INFILE '' INTO TABLE `db1``; SELECT 'oops!'`.`t``1` FIELDS TERMINATED BY ',' ENCLOSED BY '\'' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a``1`, `b``2`) SET `c``3`= concat('|', "b""a'z", "!") +LOAD DATA LOCAL INFILE '' INTO TABLE `db1``; select 'oops!'`.`t``1` FIELDS TERMINATED BY ',' ENCLOSED BY '\'' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a``1`, `b``2`) SET `c``3`= concat('|', "b""a'z", "!") /*!*/; SET TIMESTAMP=1000000000/*!*/; COMMIT @@ -197,10 +197,10 @@ DELIMITER ; # End of log file ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; -SELECT * FROM `db1``; SELECT 'oops!'`.`t``1`; +SELECT * FROM `db1``; select 'oops!'`.`t``1`; a`1 b`2 c`3 fo\o bar |b"a'z! -DROP TABLE `db1``; SELECT 'oops!'`.`t``1`; +DROP TABLE `db1``; select 'oops!'`.`t``1`; drop table t1,t2; *** Test truncation of long SET expression in LOAD DATA *** CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(1000)); @@ -223,7 +223,7 @@ a b 2 A| 123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789H123456789I123456789J123456789K123456789L123456789M123456789N123456789O123456789P123456789Q123456789R123456789123456789T123456789U123456789V123456789W123456789X123456789Y123456789Z123456789|A DROP TABLE t1; *** Test user variables whose names require correct quoting *** -use `db1``; SELECT 'oops!'`; +use `db1``; select 'oops!'`; CREATE TABLE t1 (a1 BIGINT PRIMARY KEY, a2 BIGINT, a3 BIGINT, a4 BIGINT UNSIGNED, b DOUBLE, c DECIMAL(65,10), d VARCHAR(100)); INSERT INTO t1 VALUES (-9223372036854775808,42,9223372036854775807,18446744073709551615,-1234560123456789e110, -1234501234567890123456789012345678901234567890123456789.0123456789, REPEAT("x", 100)); SELECT @`a``1`:=a1, @`a``2`:=a2, @`a``3`:=a3, @`a``4`:=a4, @`b```:=b, @```c`:=c, @```d```:=d FROM t1; @@ -232,9 +232,9 @@ SELECT @`a``1`:=a1, @`a``2`:=a2, @`a``3`:=a3, @`a``4`:=a4, @`b```:=b, @```c`:=c, INSERT INTO t1 VALUES (@`a``1`+1, @`a``2`*100, @`a``3`-1, @`a``4`-1, @`b```/2, @```c`, substr(@```d```, 2, 98)); show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # use `db1``; SELECT 'oops!'`; CREATE TABLE t1 (a1 BIGINT PRIMARY KEY, a2 BIGINT, a3 BIGINT, a4 BIGINT UNSIGNED, b DOUBLE, c DECIMAL(65,10), d VARCHAR(100)) +master-bin.000001 # Query # # use `db1``; select 'oops!'`; CREATE TABLE t1 (a1 BIGINT PRIMARY KEY, a2 BIGINT, a3 BIGINT, a4 BIGINT UNSIGNED, b DOUBLE, c DECIMAL(65,10), d VARCHAR(100)) master-bin.000001 # Query # # BEGIN -master-bin.000001 # Query # # use `db1``; SELECT 'oops!'`; INSERT INTO t1 VALUES (-9223372036854775808,42,9223372036854775807,18446744073709551615,-1234560123456789e110, -1234501234567890123456789012345678901234567890123456789.0123456789, REPEAT("x", 100)) +master-bin.000001 # Query # # use `db1``; select 'oops!'`; INSERT INTO t1 VALUES (-9223372036854775808,42,9223372036854775807,18446744073709551615,-1234560123456789e110, -1234501234567890123456789012345678901234567890123456789.0123456789, REPEAT("x", 100)) master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # BEGIN master-bin.000001 # User var # # @`a``1`=-9223372036854775808 @@ -244,13 +244,13 @@ master-bin.000001 # User var # # @`a``4`=18446744073709551615 master-bin.000001 # User var # # @`b```=-1.234560123456789e125 master-bin.000001 # User var # # @```c`=-1234501234567890123456789012345678901234567890123456789.0123456789 master-bin.000001 # User var # # @```d```=_latin1 0x78787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878 COLLATE latin1_swedish_ci -master-bin.000001 # Query # # use `db1``; SELECT 'oops!'`; INSERT INTO t1 VALUES (@`a``1`+1, @`a``2`*100, @`a``3`-1, @`a``4`-1, @`b```/2, @```c`, substr(@```d```, 2, 98)) +master-bin.000001 # Query # # use `db1``; select 'oops!'`; INSERT INTO t1 VALUES (@`a``1`+1, @`a``2`*100, @`a``3`-1, @`a``4`-1, @`b```/2, @```c`, substr(@```d```, 2, 98)) master-bin.000001 # Query # # COMMIT /*!40019 SET @@session.max_insert_delayed_threads=0*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; ROLLBACK/*!*/; -use `db1``; SELECT 'oops!'`/*!*/; +use `db1``; select 'oops!'`/*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.pseudo_thread_id=999999999/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; @@ -291,46 +291,46 @@ DELIMITER ; # End of log file ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; -SELECT * FROM `db1``; SELECT 'oops!'`.t1 ORDER BY a1; +SELECT * FROM `db1``; select 'oops!'`.t1 ORDER BY a1; a1 a2 a3 a4 b c d -9223372036854775808 42 9223372036854775807 18446744073709551615 -1.234560123456789e125 -1234501234567890123456789012345678901234567890123456789.0123456789 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -9223372036854775807 4200 9223372036854775806 18446744073709551614 -6.172800617283945e124 -1234501234567890123456789012345678901234567890123456789.0123456789 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx DROP TABLE t1; *** Test correct quoting in foreign key error message *** -use `db1``; SELECT 'oops!'`; +use `db1``; select 'oops!'`; CREATE TABLE `t``1` ( `a``` INT PRIMARY KEY) ENGINE=innodb; CREATE TABLE `t``2` ( `b``` INT PRIMARY KEY, `c``` INT NOT NULL, FOREIGN KEY fk (`c```) REFERENCES `t``1`(`a```)) ENGINE=innodb; TRUNCATE `t``1`; -ERROR 42000: Cannot truncate a table referenced in a foreign key constraint (`db1``; SELECT 'oops!'`.`t``2`, CONSTRAINT `INNODB_FOREIGN_KEY_NAME` FOREIGN KEY (`c```) REFERENCES `db1``; SELECT 'oops!'`.`t``1` (`a```)) +ERROR 42000: Cannot truncate a table referenced in a foreign key constraint (`db1``; select 'oops!'`.`t``2`, CONSTRAINT `INNODB_FOREIGN_KEY_NAME` FOREIGN KEY (`c```) REFERENCES `db1``; select 'oops!'`.`t``1` (`a```)) DROP TABLE `t``2`; DROP TABLE `t``1`; *** Test correct quoting of DELETE FROM statement binlogged for HEAP table that is emptied due to server restart include/stop_slave.inc -CREATE TABLE `db1``; SELECT 'oops!'`.`t``1` (`a``` INT PRIMARY KEY) ENGINE=heap; -INSERT INTO `db1``; SELECT 'oops!'`.`t``1` VALUES (1), (2), (5); -SELECT * FROM `db1``; SELECT 'oops!'`.`t``1` ORDER BY 1; +CREATE TABLE `db1``; select 'oops!'`.`t``1` (`a``` INT PRIMARY KEY) ENGINE=heap; +INSERT INTO `db1``; select 'oops!'`.`t``1` VALUES (1), (2), (5); +SELECT * FROM `db1``; select 'oops!'`.`t``1` ORDER BY 1; a` 1 2 5 set timestamp=1000000000; # The table should be empty on the master. -SELECT * FROM `db1``; SELECT 'oops!'`.`t``1`; +SELECT * FROM `db1``; select 'oops!'`.`t``1`; a` # The DELETE statement should be correctly quoted show binlog events in 'master-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000002 # Query # # BEGIN -master-bin.000002 # Query # # use `test`; DELETE FROM `db1``; SELECT 'oops!'`.`t``1` +master-bin.000002 # Query # # use `test`; DELETE FROM `db1``; select 'oops!'`.`t``1` master-bin.000002 # Query # # COMMIT include/start_slave.inc # The table should be empty on the slave also. -SELECT * FROM `db1``; SELECT 'oops!'`.`t``1`; +SELECT * FROM `db1``; select 'oops!'`.`t``1`; a` -DROP TABLE `db1``; SELECT 'oops!'`.`t``1`; +DROP TABLE `db1``; select 'oops!'`.`t``1`; use test; -DROP DATABASE `db1``; SELECT 'oops!'`; +DROP DATABASE `db1``; select 'oops!'`; *** Test correct quoting of mysqlbinlog --rewrite-db option *** CREATE TABLE t1 (a INT PRIMARY KEY); INSERT INTO t1 VALUES(1); diff --git a/mysql-test/suite/rpl/t/rpl_mdev382.test b/mysql-test/suite/rpl/t/rpl_mdev382.test index e84a29137bc..d88eeaa463e 100644 --- a/mysql-test/suite/rpl/t/rpl_mdev382.test +++ b/mysql-test/suite/rpl/t/rpl_mdev382.test @@ -64,8 +64,8 @@ set sql_quote_show_create = 1; connection master; let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); set sql_mode = 'ANSI_QUOTES'; -CREATE DATABASE "db1`; SELECT 'oops!'"; -use "db1`; SELECT 'oops!'"; +CREATE DATABASE "db1`; select 'oops!'"; +use "db1`; select 'oops!'"; CREATE TABLE t1 (a INT PRIMARY KEY) engine=MyISAM; INSERT INTO t1 VALUES (1); set sql_mode = ''; @@ -88,7 +88,7 @@ use test; 'fo\\o','bar' EOF -use `db1``; SELECT 'oops!'`; +use `db1``; select 'oops!'`; let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); set timestamp=1000000000; CREATE TABLE `t``1` (`a``1` VARCHAR(4) PRIMARY KEY, `b``2` VARCHAR(3), @@ -105,11 +105,11 @@ truncate `t``1`; use test; --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/f''le.txt' - INTO TABLE `db1``; SELECT 'oops!'`.`t``1` + INTO TABLE `db1``; select 'oops!'`.`t``1` FIELDS TERMINATED BY ',' ESCAPED BY '\\\\' ENCLOSED BY '''' LINES TERMINATED BY '\\n' (`a``1`, `b``2`) SET `c``3` = concat('|', "b""a'z", "!"); -SELECT * FROM `db1``; SELECT 'oops!'`.`t``1`; +SELECT * FROM `db1``; select 'oops!'`.`t``1`; let $pos2= query_get_value(SHOW MASTER STATUS, Position, 1); --source include/show_binlog_events.inc @@ -119,10 +119,10 @@ let $MYSQLD_DATADIR= `select @@datadir`; sync_slave_with_master; connection slave; -SELECT * FROM `db1``; SELECT 'oops!'`.`t``1`; +SELECT * FROM `db1``; select 'oops!'`.`t``1`; connection master; -DROP TABLE `db1``; SELECT 'oops!'`.`t``1`; +DROP TABLE `db1``; select 'oops!'`.`t``1`; --remove_file $load_file connection master; @@ -158,7 +158,7 @@ DROP TABLE t1; --echo *** Test user variables whose names require correct quoting *** -use `db1``; SELECT 'oops!'`; +use `db1``; select 'oops!'`; let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); CREATE TABLE t1 (a1 BIGINT PRIMARY KEY, a2 BIGINT, a3 BIGINT, a4 BIGINT UNSIGNED, b DOUBLE, c DECIMAL(65,10), d VARCHAR(100)); INSERT INTO t1 VALUES (-9223372036854775808,42,9223372036854775807,18446744073709551615,-1234560123456789e110, -1234501234567890123456789012345678901234567890123456789.0123456789, REPEAT("x", 100)); @@ -172,13 +172,13 @@ let $pos2= query_get_value(SHOW MASTER STATUS, Position, 1); sync_slave_with_master; connection slave; -SELECT * FROM `db1``; SELECT 'oops!'`.t1 ORDER BY a1; +SELECT * FROM `db1``; select 'oops!'`.t1 ORDER BY a1; connection master; DROP TABLE t1; --echo *** Test correct quoting in foreign key error message *** -use `db1``; SELECT 'oops!'`; +use `db1``; select 'oops!'`; CREATE TABLE `t``1` ( `a``` INT PRIMARY KEY) ENGINE=innodb; CREATE TABLE `t``2` ( `b``` INT PRIMARY KEY, `c``` INT NOT NULL, FOREIGN KEY fk (`c```) REFERENCES `t``1`(`a```)) ENGINE=innodb; @@ -197,9 +197,9 @@ connection slave; --source include/stop_slave.inc connection master; -CREATE TABLE `db1``; SELECT 'oops!'`.`t``1` (`a``` INT PRIMARY KEY) ENGINE=heap; -INSERT INTO `db1``; SELECT 'oops!'`.`t``1` VALUES (1), (2), (5); -SELECT * FROM `db1``; SELECT 'oops!'`.`t``1` ORDER BY 1; +CREATE TABLE `db1``; select 'oops!'`.`t``1` (`a``` INT PRIMARY KEY) ENGINE=heap; +INSERT INTO `db1``; select 'oops!'`.`t``1` VALUES (1), (2), (5); +SELECT * FROM `db1``; select 'oops!'`.`t``1` ORDER BY 1; # Restart the master mysqld. # This will cause an implicit truncation of the memory-based table, which will @@ -230,7 +230,7 @@ set timestamp=1000000000; --echo # The table should be empty on the master. let $binlog_file= master-bin.000002; let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); -SELECT * FROM `db1``; SELECT 'oops!'`.`t``1`; +SELECT * FROM `db1``; select 'oops!'`.`t``1`; --echo # The DELETE statement should be correctly quoted --source include/show_binlog_events.inc @@ -242,16 +242,16 @@ connection master; sync_slave_with_master; connection slave; --echo # The table should be empty on the slave also. -SELECT * FROM `db1``; SELECT 'oops!'`.`t``1`; +SELECT * FROM `db1``; select 'oops!'`.`t``1`; connection master; -DROP TABLE `db1``; SELECT 'oops!'`.`t``1`; +DROP TABLE `db1``; select 'oops!'`.`t``1`; sync_slave_with_master; connection master; use test; -DROP DATABASE `db1``; SELECT 'oops!'`; +DROP DATABASE `db1``; select 'oops!'`; --echo *** Test correct quoting of mysqlbinlog --rewrite-db option *** CREATE TABLE t1 (a INT PRIMARY KEY); From 589c62fefec759a467b6dec1badb2cd283564845 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 31 Aug 2012 19:50:45 +0500 Subject: [PATCH 12/21] Bug #1043845 st_distance() results are incorrect depending on variable order. Autointersections of an object were treated as nodes, so the wrong result. per-file comments: mysql-test/r/gis.result Bug #1043845 st_distance() results are incorrect depending on variable order. test result updated. mysql-test/t/gis.test Bug #1043845 st_distance() results are incorrect depending on variable order. test case added. sql/item.cc small fix to make compilers happy. sql/item_geofunc.cc Bug #1043845 st_distance() results are incorrect depending on variable order. Skip intersection points when calculate distance. --- mysql-test/r/gis.result | 23 +++++++++++++++++++++++ mysql-test/t/gis.test | 16 ++++++++++++++++ sql/item.cc | 2 +- sql/item_geofunc.cc | 3 ++- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index eab28b23550..f29d096fc57 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -1473,3 +1473,26 @@ WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1; count(*) 1 DROP DATABASE gis_ogs; +# +# BUG #1043845 st_distance() results are incorrect depending on variable order +# +select st_distance(geomfromtext('LINESTRING(-95.9673005697771 36.13509598461, + -95.9673057475387 36.1344478941074, + -95.9673063519371 36.134484524621, + -95.9673049102515 36.1343976584193)'), +geomfromtext('point(-95.96269500000000000000 36.14181833333330000000)')) ; +st_distance(geomfromtext('LINESTRING(-95.9673005697771 36.13509598461, + -95.9673057475387 36.1344478941074, + -95.9673063519371 36.134484524621, + +0.008148695928138 +select st_distance(geomfromtext('point(-95.96269500000000000000 36.14181833333330000000)'), +geomfromtext('LINESTRING(-95.9673005697771 36.13509598461, + -95.9673057475387 36.1344478941074, + -95.9673063519371 36.134484524621, + -95.9673049102515 36.1343976584193) ')) ; +st_distance(geomfromtext('point(-95.96269500000000000000 36.14181833333330000000)'), +geomfromtext('LINESTRING(-95.9673005697771 36.13509598461, + -95.9673057475387 36.1344478941074, + -95.9673063519371 36. +0.008148695928138 diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 95b1e63b828..cdbc253869e 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -1355,3 +1355,19 @@ WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1; #WHERE lakes.name = 'Blue Lake'; DROP DATABASE gis_ogs; + +--echo # +--echo # BUG #1043845 st_distance() results are incorrect depending on variable order +--echo # + +select st_distance(geomfromtext('LINESTRING(-95.9673005697771 36.13509598461, + -95.9673057475387 36.1344478941074, + -95.9673063519371 36.134484524621, + -95.9673049102515 36.1343976584193)'), + geomfromtext('point(-95.96269500000000000000 36.14181833333330000000)')) ; +select st_distance(geomfromtext('point(-95.96269500000000000000 36.14181833333330000000)'), + geomfromtext('LINESTRING(-95.9673005697771 36.13509598461, + -95.9673057475387 36.1344478941074, + -95.9673063519371 36.134484524621, + -95.9673049102515 36.1343976584193) ')) ; + diff --git a/sql/item.cc b/sql/item.cc index e125e57d2fc..bb6360f3f73 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -8858,7 +8858,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item) item->max_length, item->decimals)); fld_type= Field::field_type_merge(fld_type, get_real_type(item)); { - int item_decimals= item->decimals; + uint item_decimals= item->decimals; /* fix variable decimals which always is NOT_FIXED_DEC */ if (Field::result_merge_type(fld_type) == INT_RESULT) item_decimals= 0; diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 172e0cbcd1f..522be28558f 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -1693,7 +1693,8 @@ count_distance: for (dist_point= collector.get_first(); dist_point; dist_point= dist_point->get_next()) { /* We only check vertices of object 2 */ - if (dist_point->shape < obj2_si) + if (dist_point->type != Gcalc_heap::nt_shape_node || + dist_point->shape < obj2_si) continue; /* if we have an edge to check */ From 4a8938f6f515a43fe2ba5e997c54982991f48f12 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 1 Sep 2012 00:23:30 +0200 Subject: [PATCH 13/21] remove the forgotten commented out piece of the old merge --- sql/sql_select.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0e5aa0e0aaa..57bb9a311d7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -21549,11 +21549,6 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, length= (longlong10_to_str(key_len, keylen_str_buf, 10) - keylen_str_buf); tmp3.append(keylen_str_buf, length, cs); -/*<<<<<<< TREE - } - if ((is_hj || tab->type==JT_RANGE || tab->type == JT_INDEX_MERGE) && - tab->select && tab->select->quick) -=======*/ } if (tab->type != JT_CONST && tab->select && tab->select->quick) tab->select->quick->add_keys_and_lengths(&tmp2, &tmp3); From 5620937c058aa9f7cd3b122b40f8b9c94fa69997 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 2 Sep 2012 19:09:17 +0200 Subject: [PATCH 14/21] don't run mdev375.test for embedded server --- mysql-test/t/mdev375.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/t/mdev375.test b/mysql-test/t/mdev375.test index 547d57aa587..fe259b37808 100644 --- a/mysql-test/t/mdev375.test +++ b/mysql-test/t/mdev375.test @@ -1,6 +1,8 @@ # # MDEV-375 Server crashes in THD::print_aborted_warning with log_warnings > 3 # +--source include/not_embedded.inc + SET GLOBAL log_warnings=4; SET GLOBAL max_connections=2; From 0b5564b86c29d00ed3b28c9112d09214ea266d23 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 4 Sep 2012 12:12:28 +0200 Subject: [PATCH 15/21] 1. fix an old typo. A purgatory must be cleaned on every LF_PURGATORY_SIZE freeing, not every time. 2. Increase purgatory size. include/lf.h: allocate larger purgatory mysys/lf_alloc-pin.c: typo. --- include/lf.h | 2 +- mysys/lf_alloc-pin.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/lf.h b/include/lf.h index cdd24c07502..07769d10943 100644 --- a/include/lf.h +++ b/include/lf.h @@ -95,7 +95,7 @@ nolock_wrap(lf_dynarray_iterate, int, */ #define LF_PINBOX_PINS 4 -#define LF_PURGATORY_SIZE 10 +#define LF_PURGATORY_SIZE 100 typedef void lf_pinbox_free_func(void *, void *, void*); diff --git a/mysys/lf_alloc-pin.c b/mysys/lf_alloc-pin.c index d23ef129aa2..6ab6ba3aae0 100644 --- a/mysys/lf_alloc-pin.c +++ b/mysys/lf_alloc-pin.c @@ -271,7 +271,7 @@ static int ptr_cmp(void **a, void **b) void _lf_pinbox_free(LF_PINS *pins, void *addr) { add_to_purgatory(pins, addr); - if (pins->purgatory_count % LF_PURGATORY_SIZE) + if (pins->purgatory_count % LF_PURGATORY_SIZE == 0) _lf_pinbox_real_free(pins); } From 1f92707978d411a051b2bfa46ed361f60861ff73 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 4 Sep 2012 19:11:06 +0200 Subject: [PATCH 16/21] MDEV-481 Assertion `pins->pin[i] == 0' failed in _lf_pinbox_put_pins on concurrent OPTIMIZE TABLE and DML with Aria tables A bug in the lock-free hash implementation! when lsearch() has not found the key, the caller needs to unpin all the three pins, because lsearch() was using all the three. --- mysys/lf_hash.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mysys/lf_hash.c b/mysys/lf_hash.c index 83cfe1a1639..38b212c65f0 100644 --- a/mysys/lf_hash.c +++ b/mysys/lf_hash.c @@ -268,8 +268,10 @@ static LF_SLIST *lsearch(LF_SLIST * volatile *head, CHARSET_INFO *cs, int res= lfind(head, cs, hashnr, key, keylen, &cursor, pins); if (res) _lf_pin(pins, 2, cursor.curr); - _lf_unpin(pins, 0); + else + _lf_unpin(pins, 2); _lf_unpin(pins, 1); + _lf_unpin(pins, 0); return res ? cursor.curr : 0; } From 0352f09a2e3e17470ab75678265b98a275cb25a0 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 5 Sep 2012 10:44:23 +0200 Subject: [PATCH 17/21] Percona-Server-5.5.27-rel28.1 --- btr/btr0btr.c | 4 + buf/buf0buf.c | 11 +- buf/buf0lru.c | 51 +++++--- buf/buf0rea.c | 47 +++++++- dict/dict0dict.c | 42 +++++-- dict/dict0mem.c | 4 +- fil/fil0fil.c | 2 + ha/ha0ha.c | 16 +-- handler/ha_innodb.cc | 51 ++++++-- handler/handler0alter.cc | 18 +-- handler/i_s.cc | 245 +++++++++++++++++++++++++++++++++++++++ handler/i_s.h | 1 + include/btr0btr.h | 3 + include/btr0types.h | 4 + include/buf0buf.h | 21 ++-- include/buf0buf.ic | 2 + include/dict0dict.h | 5 +- include/dict0dict.ic | 2 + include/ha_prototypes.h | 11 ++ include/log0log.h | 2 +- include/os0file.h | 2 +- include/srv0srv.h | 2 +- include/trx0sys.h | 4 +- mem/mem0dbg.c | 4 +- os/os0file.c | 2 + page/page0zip.c | 2 + row/row0ins.c | 6 +- row/row0merge.c | 188 +++++++++++++++++++----------- row/row0vers.c | 11 -- trx/trx0sys.c | 2 +- ut/ut0dbg.c | 6 +- ut/ut0ut.c | 8 ++ 32 files changed, 614 insertions(+), 165 deletions(-) diff --git a/btr/btr0btr.c b/btr/btr0btr.c index 1fa6df44f7c..53f2be4cabd 100644 --- a/btr/btr0btr.c +++ b/btr/btr0btr.c @@ -42,6 +42,7 @@ Created 6/2/1994 Heikki Tuuri #include "ibuf0ibuf.h" #include "trx0trx.h" +#endif /* UNIV_HOTBACKUP */ /**************************************************************//** Report that an index page is corrupted. */ UNIV_INTERN @@ -64,6 +65,7 @@ btr_corruption_report( buf_page_print(buf_block_get_frame(block), 0, 0); } +#ifndef UNIV_HOTBACKUP #ifdef UNIV_BLOB_DEBUG # include "srv0srv.h" # include "ut0rbt.h" @@ -1622,7 +1624,9 @@ btr_page_reorganize_low( dict_index_t* index, /*!< in: record descriptor */ mtr_t* mtr) /*!< in: mtr */ { +#ifndef UNIV_HOTBACKUP buf_pool_t* buf_pool = buf_pool_from_bpage(&block->page); +#endif /* !UNIV_HOTBACKUP */ page_t* page = buf_block_get_frame(block); page_zip_des_t* page_zip = buf_block_get_page_zip(block); buf_block_t* temp_block; diff --git a/buf/buf0buf.c b/buf/buf0buf.c index fd7b8959473..a2ff171e0c5 100644 --- a/buf/buf0buf.c +++ b/buf/buf0buf.c @@ -344,7 +344,6 @@ be effective only if PFS_GROUP_BUFFER_SYNC is defined. */ // was allocated for the frames */ // buf_block_t* blocks; /*!< array of buffer control blocks */ //}; -#endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Gets the smallest oldest_modification lsn for any page in the pool. Returns @@ -482,6 +481,7 @@ buf_block_alloc( return(block); } +#endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Calculates a page checksum which is stored to the page when it is written @@ -3907,9 +3907,10 @@ buf_mark_space_corrupt( /********************************************************************//** Completes an asynchronous read or write request of a file page to or from -the buffer pool. */ +the buffer pool. +@return TRUE if successful */ UNIV_INTERN -void +ibool buf_page_io_complete( /*=================*/ buf_page_t* bpage) /*!< in: pointer to the block in question */ @@ -4057,7 +4058,7 @@ corrupt: table as corrupted instead of crashing server */ if (bpage->space > TRX_SYS_SPACE && buf_mark_space_corrupt(bpage)) { - return; + return(FALSE); } else { fputs("InnoDB: Ending processing" " because of" @@ -4176,6 +4177,8 @@ retry_mutex: buf_pool_mutex_exit(buf_pool); mutex_exit(block_mutex); + + return(TRUE); } /********************************************************************//** diff --git a/buf/buf0lru.c b/buf/buf0lru.c index 132b12899b4..08536ea5270 100644 --- a/buf/buf0lru.c +++ b/buf/buf0lru.c @@ -374,7 +374,7 @@ next_page: /******************************************************************//** While flushing (or removing dirty) pages from a tablespace we don't -want to hog the CPU and resources. Release the buffer pool and block +want to hog the CPU and resources. Release the LRU list and block mutex and try to force a context switch. Then reacquire the same mutexes. The current page is "fixed" before the release of the mutexes and then "unfixed" again once we have reacquired the mutexes. */ @@ -387,7 +387,7 @@ buf_flush_yield( { mutex_t* block_mutex; - ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(mutex_own(&buf_pool->LRU_list_mutex)); ut_ad(buf_page_in_file(bpage)); block_mutex = buf_page_get_mutex(bpage); @@ -399,13 +399,13 @@ buf_flush_yield( buf_page_set_sticky(bpage); /* Now it is safe to release the buf_pool->mutex. */ - buf_pool_mutex_exit(buf_pool); + mutex_exit(&buf_pool->LRU_list_mutex); mutex_exit(block_mutex); /* Try and force a context switch. */ os_thread_yield(); - buf_pool_mutex_enter(buf_pool); + mutex_enter(&buf_pool->LRU_list_mutex); mutex_enter(block_mutex); /* "Unfix" the block now that we have both the @@ -415,9 +415,9 @@ buf_flush_yield( } /******************************************************************//** -If we have hogged the resources for too long then release the buffer -pool and flush list mutex and do a thread yield. Set the current page -to "sticky" so that it is not relocated during the yield. +If we have hogged the resources for too long then release the LRU list +and flush list mutex and do a thread yield. Set the current page to +"sticky" so that it is not relocated during the yield. @return TRUE if yielded */ static ibool @@ -439,7 +439,7 @@ buf_flush_try_yield( buf_flush_list_mutex_exit(buf_pool); - /* Release the buffer pool and block mutex + /* Release the LRU list and block mutex to give the other threads a go. */ buf_flush_yield(buf_pool, bpage); @@ -472,7 +472,7 @@ buf_flush_or_remove_page( mutex_t* block_mutex; ibool processed = FALSE; - ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(mutex_own(&buf_pool->LRU_list_mutex)); ut_ad(buf_flush_list_mutex_own(buf_pool)); block_mutex = buf_page_get_mutex(bpage); @@ -595,11 +595,11 @@ buf_flush_dirty_pages( ibool all_freed; do { - buf_pool_mutex_enter(buf_pool); + mutex_enter(&buf_pool->LRU_list_mutex); all_freed = buf_flush_or_remove_pages(buf_pool, id); - buf_pool_mutex_exit(buf_pool); + mutex_exit(&buf_pool->LRU_list_mutex); ut_ad(buf_flush_validate(buf_pool)); @@ -659,8 +659,16 @@ scan_again: goto next_page; } else { - block_mutex = buf_page_get_mutex(bpage); - mutex_enter(block_mutex); + block_mutex = buf_page_get_mutex_enter(bpage); + + if (!block_mutex) { + /* It may be impossible case... + Something wrong, so will be scan_again */ + + all_freed = FALSE; + goto next_page; + } + if (bpage->buf_fix_count > 0) { @@ -694,7 +702,8 @@ scan_again: ulint page_no; ulint zip_size; - buf_pool_mutex_exit(buf_pool); + mutex_exit(&buf_pool->LRU_list_mutex); + rw_lock_x_unlock(&buf_pool->page_hash_latch); zip_size = buf_page_get_zip_size(bpage); page_no = buf_page_get_page_no(bpage); @@ -2370,9 +2379,23 @@ buf_LRU_free_one_page( be in a state where it can be freed; there may or may not be a hash index to the page */ { +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); +#endif + mutex_t* block_mutex = buf_page_get_mutex(bpage); + + ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(mutex_own(block_mutex)); + if (buf_LRU_block_remove_hashed_page(bpage, TRUE) != BUF_BLOCK_ZIP_FREE) { buf_LRU_block_free_hashed_page((buf_block_t*) bpage, TRUE); + } else { + /* The block_mutex should have been released by + buf_LRU_block_remove_hashed_page() when it returns + BUF_BLOCK_ZIP_FREE. */ + ut_ad(block_mutex == &buf_pool->zip_mutex); + mutex_enter(block_mutex); } } diff --git a/buf/buf0rea.c b/buf/buf0rea.c index 645d5fdc2f3..4a2c96227ea 100644 --- a/buf/buf0rea.c +++ b/buf/buf0rea.c @@ -50,6 +50,44 @@ read-ahead is not done: this is to prevent flooding the buffer pool with i/o-fixed buffer blocks */ #define BUF_READ_AHEAD_PEND_LIMIT 2 +/********************************************************************//** +Unfixes the pages, unlatches the page, +removes it from page_hash and removes it from LRU. */ +static +void +buf_read_page_handle_error( +/*=======================*/ + buf_page_t* bpage) /*!< in: pointer to the block */ +{ + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + const ibool uncompressed = (buf_page_get_state(bpage) + == BUF_BLOCK_FILE_PAGE); + + /* First unfix and release lock on the bpage */ + buf_pool_mutex_enter(buf_pool); + mutex_enter(buf_page_get_mutex(bpage)); + ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ); + ut_ad(bpage->buf_fix_count == 0); + + /* Set BUF_IO_NONE before we remove the block from LRU list */ + buf_page_set_io_fix(bpage, BUF_IO_NONE); + + if (uncompressed) { + rw_lock_x_unlock_gen( + &((buf_block_t*) bpage)->lock, + BUF_IO_READ); + } + + /* remove the block from LRU list */ + buf_LRU_free_one_page(bpage); + + ut_ad(buf_pool->n_pend_reads > 0); + buf_pool->n_pend_reads--; + + mutex_exit(buf_page_get_mutex(bpage)); + buf_pool_mutex_exit(buf_pool); +} + /********************************************************************//** Low-level function which reads a page asynchronously from a file to the buffer buf_pool if it is not already there, in which case does nothing. @@ -196,6 +234,11 @@ not_to_recover: } thd_wait_end(NULL); + if (*err == DB_TABLESPACE_DELETED) { + buf_read_page_handle_error(bpage); + return(0); + } + if (srv_pass_corrupt_table) { if (*err != DB_SUCCESS) { bpage->is_corrupt = TRUE; @@ -207,7 +250,9 @@ not_to_recover: if (sync) { /* The i/o is already completed when we arrive from fil_read */ - buf_page_io_complete(bpage); + if (!buf_page_io_complete(bpage)) { + return(0); + } } return(1); diff --git a/dict/dict0dict.c b/dict/dict0dict.c index 4c84a22c4b5..89f13188d95 100644 --- a/dict/dict0dict.c +++ b/dict/dict0dict.c @@ -170,6 +170,7 @@ void dict_field_print_low( /*=================*/ const dict_field_t* field); /*!< in: field */ +#ifndef UNIV_HOTBACKUP /*********************************************************************//** Frees a foreign key struct. */ static @@ -183,7 +184,7 @@ and unique key errors */ UNIV_INTERN FILE* dict_foreign_err_file = NULL; /* mutex protecting the foreign and unique error buffers */ UNIV_INTERN mutex_t dict_foreign_err_mutex; - +#endif /* !UNIV_HOTBACKUP */ /******************************************************************//** Makes all characters in a NUL-terminated UTF-8 string lower case. */ UNIV_INTERN @@ -2315,6 +2316,7 @@ dict_index_build_internal_non_clust( return(new_index); } +#ifndef UNIV_HOTBACKUP /*====================== FOREIGN KEY PROCESSING ========================*/ /*********************************************************************//** @@ -2579,6 +2581,7 @@ dict_foreign_find_equiv_index( FALSE/* allow columns to be NULL */)); } +#endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** Returns an index object by matching on the name and column names and if more than one index matches return the index with the max id @@ -2638,6 +2641,7 @@ dict_table_get_index_by_max_id( return(found); } +#ifndef UNIV_HOTBACKUP /**********************************************************************//** Report an error in a foreign key definition. */ static @@ -2803,6 +2807,7 @@ dict_foreign_add_to_cache( return(DB_SUCCESS); } +#endif /* !UNIV_HOTBACKUP */ /*********************************************************************//** Scans from pointer onwards. Stops if is at the start of a copy of 'string' where characters are compared without case sensitivity, and @@ -3282,6 +3287,7 @@ end_of_string: } } +#ifndef UNIV_HOTBACKUP /*********************************************************************//** Finds the highest [number] for foreign key constraints of the table. Looks only at the >= 4.0.18-format id's, which are of the form @@ -4118,7 +4124,7 @@ syntax_error: } /*==================== END OF FOREIGN KEY PROCESSING ====================*/ - +#endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** Returns an index object if it is found in the dictionary cache. Assumes that dict_sys->mutex is already being held. @@ -4651,12 +4657,6 @@ next_rec: } btr_pcur_close(&pcur); mtr_commit(&mtr); - - if (rests) { - fprintf(stderr, "InnoDB: Warning: failed to store %lu stats entries" - " of %s/%s to SYS_STATS system table.\n", - rests, index->table_name, index->name); - } } /*===========================================*/ @@ -4892,6 +4892,7 @@ next_rec: } } +#ifndef UNIV_HOTBACKUP /**********************************************************************//** Prints info of a foreign key constraint. */ static @@ -4922,6 +4923,7 @@ dict_foreign_print_low( fputs(" )\n", stderr); } +#endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** Prints a table data. */ UNIV_INTERN @@ -5104,6 +5106,7 @@ dict_field_print_low( } } +#ifndef UNIV_HOTBACKUP /**********************************************************************//** Outputs info on a foreign key of a table in a format suitable for CREATE TABLE. */ @@ -5292,6 +5295,7 @@ dict_print_info_on_foreign_keys( mutex_exit(&(dict_sys->mutex)); } +#endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Displays the names of the index and the table. */ UNIV_INTERN @@ -5422,6 +5426,28 @@ dict_table_replace_index_in_foreign_list( foreign->foreign_index = new_index; } } + + + for (foreign = UT_LIST_GET_FIRST(table->referenced_list); + foreign; + foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { + + dict_index_t* new_index; + + if (foreign->referenced_index == index) { + ut_ad(foreign->referenced_table == index->table); + + new_index = dict_foreign_find_index( + foreign->referenced_table, + foreign->referenced_col_names, + foreign->n_fields, index, + /*check_charsets=*/TRUE, /*check_null=*/FALSE); + ut_ad(new_index || !trx->check_foreigns); + ut_ad(!new_index || new_index->table == index->table); + + foreign->referenced_index = new_index; + } + } } /**********************************************************************//** diff --git a/dict/dict0mem.c b/dict/dict0mem.c index 617c68925cb..6b8c11dfa7a 100644 --- a/dict/dict0mem.c +++ b/dict/dict0mem.c @@ -33,8 +33,8 @@ Created 1/8/1996 Heikki Tuuri #include "data0type.h" #include "mach0data.h" #include "dict0dict.h" -#include "ha_prototypes.h" /* innobase_casedn_str()*/ #ifndef UNIV_HOTBACKUP +# include "ha_prototypes.h" /* innobase_casedn_str()*/ # include "lock0lock.h" #endif /* !UNIV_HOTBACKUP */ #ifdef UNIV_BLOB_DEBUG @@ -274,6 +274,7 @@ dict_mem_index_create( return(index); } +#ifndef UNIV_HOTBACKUP /**********************************************************************//** Creates and initializes a foreign constraint memory object. @return own: foreign constraint struct */ @@ -348,6 +349,7 @@ dict_mem_referenced_table_name_lookup_set( } } +#endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** Adds a field definition to an index. NOTE: does not take a copy of the column name if the field is a column. The memory occupied diff --git a/fil/fil0fil.c b/fil/fil0fil.c index 32e78cf19b4..811b7583d50 100644 --- a/fil/fil0fil.c +++ b/fil/fil0fil.c @@ -867,8 +867,10 @@ fil_node_close_file( ut_a(node->open); ut_a(node->n_pending == 0 || node->space->is_being_deleted); ut_a(node->n_pending_flushes == 0); +#ifndef UNIV_HOTBACKUP ut_a(node->modification_counter == node->flush_counter || srv_fast_shutdown == 2); +#endif /* !UNIV_HOTBACKUP */ ret = os_file_close(node->handle); ut_a(ret); diff --git a/ha/ha0ha.c b/ha/ha0ha.c index 2f5051e541f..b9499607bce 100644 --- a/ha/ha0ha.c +++ b/ha/ha0ha.c @@ -28,6 +28,7 @@ Created 8/22/1994 Heikki Tuuri #include "ha0ha.ic" #endif +#ifndef UNIV_HOTBACKUP #ifdef UNIV_DEBUG # include "buf0buf.h" #endif /* UNIV_DEBUG */ @@ -51,17 +52,13 @@ ha_create_func( hash table: must be a power of 2, or 0 */ { hash_table_t* table; -#ifndef UNIV_HOTBACKUP ulint i; -#endif /* !UNIV_HOTBACKUP */ ut_ad(ut_is_2pow(n_mutexes)); table = hash_create(n); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG -# ifndef UNIV_HOTBACKUP table->adaptive = TRUE; -# endif /* !UNIV_HOTBACKUP */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ /* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail, but in practise it never should in this case, hence the asserts. */ @@ -74,7 +71,6 @@ ha_create_func( return(table); } -#ifndef UNIV_HOTBACKUP hash_create_mutexes(table, n_mutexes, mutex_level); table->heaps = mem_alloc(n_mutexes * sizeof(void*)); @@ -83,7 +79,6 @@ ha_create_func( table->heaps[i] = mem_heap_create_in_btr_search(4096); ut_a(table->heaps[i]); } -#endif /* !UNIV_HOTBACKUP */ return(table); } @@ -134,7 +129,6 @@ ha_insert_for_fold_func( while (prev_node != NULL) { if (prev_node->fold == fold) { #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG -# ifndef UNIV_HOTBACKUP if (table->adaptive) { buf_block_t* prev_block = prev_node->block; ut_a(prev_block->frame @@ -143,7 +137,6 @@ ha_insert_for_fold_func( prev_block->n_pointers--; block->n_pointers++; } -# endif /* !UNIV_HOTBACKUP */ prev_node->block = block; #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ @@ -171,11 +164,9 @@ ha_insert_for_fold_func( ha_node_set_data(node, block, data); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG -# ifndef UNIV_HOTBACKUP if (table->adaptive) { block->n_pointers++; } -# endif /* !UNIV_HOTBACKUP */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ node->fold = fold; @@ -217,13 +208,11 @@ ha_delete_hash_node( #endif /* UNIV_SYNC_DEBUG */ ut_ad(btr_search_enabled); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG -# ifndef UNIV_HOTBACKUP if (table->adaptive) { ut_a(del_node->block->frame = page_align(del_node->data)); ut_a(del_node->block->n_pointers > 0); del_node->block->n_pointers--; } -# endif /* !UNIV_HOTBACKUP */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node); @@ -264,13 +253,11 @@ ha_search_and_update_if_found_func( if (node) { #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG -# ifndef UNIV_HOTBACKUP if (table->adaptive) { ut_a(node->block->n_pointers > 0); node->block->n_pointers--; new_block->n_pointers++; } -# endif /* !UNIV_HOTBACKUP */ node->block = new_block; #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ @@ -278,7 +265,6 @@ ha_search_and_update_if_found_func( } } -#ifndef UNIV_HOTBACKUP /*****************************************************************//** Removes from the chain determined by fold all nodes whose data pointer points to the page given. */ diff --git a/handler/ha_innodb.cc b/handler/ha_innodb.cc index a1a60aa2276..f5eea6d086b 100644 --- a/handler/ha_innodb.cc +++ b/handler/ha_innodb.cc @@ -49,6 +49,7 @@ this program; if not, write to the Free Software Foundation, Inc., #include // PROCESS_ACL #include +#include // DEBUG_SYNC #include #include #include @@ -500,6 +501,9 @@ static MYSQL_THDVAR_BOOL(fake_changes, PLUGIN_VAR_OPCMDARG, "This is to cause replication prefetch IO. ATTENTION: the transaction started after enabled is affected.", NULL, NULL, FALSE); +static MYSQL_THDVAR_ULONG(merge_sort_block_size, PLUGIN_VAR_RQCMDARG, + "The block size used doing external merge-sort for secondary index creation.", + NULL, NULL, 1UL << 20, 1UL << 20, 1UL << 30, 0); static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, @@ -1018,6 +1022,20 @@ thd_expand_fast_index_creation( return((ibool) (((THD*) thd)->variables.expand_fast_index_creation)); } +/******************************************************************//** +Returns the merge-sort block size used for the secondary index creation +for the current connection. +@return the merge-sort block size, in bytes */ +extern "C" UNIV_INTERN +ulong +thd_merge_sort_block_size( +/*================================*/ + void* thd) /*!< in: thread handle (THD*), or NULL to query ++ the global merge_sort_block_size */ +{ + return(THDVAR((THD*) thd, merge_sort_block_size)); +} + /********************************************************************//** Obtain the InnoDB transaction of a MySQL thread. @return reference to transaction pointer */ @@ -2900,6 +2918,7 @@ innobase_change_buffering_inited_ok: srv_read_ahead &= 3; srv_adaptive_flushing_method %= 3; + srv_flush_neighbor_pages %= 3; srv_force_recovery = (ulint) innobase_force_recovery; @@ -6573,6 +6592,7 @@ ha_innobase::index_read( ulint ret; DBUG_ENTER("index_read"); + DEBUG_SYNC_C("ha_innobase_index_read_begin"); ut_a(prebuilt->trx == thd_to_trx(user_thd)); ut_ad(key_len != 0 || find_flag != HA_READ_KEY_EXACT); @@ -8458,6 +8478,8 @@ ha_innobase::rename_table( error = innobase_rename_table(trx, from, to, TRUE); + DEBUG_SYNC(thd, "after_innobase_rename_table"); + /* Tell the InnoDB server that there might be work for utility threads: */ @@ -8784,10 +8806,15 @@ innobase_get_mysql_key_number_for_index( } } - /* Print an error message if we cannot find the index - ** in the "index translation table". */ - sql_print_error("Cannot find index %s in InnoDB index " - "translation table.", index->name); + /* If index_count in translation table is set to 0, it + is possible we are in the process of rebuilding table, + do not spit error in this case */ + if (share->idx_trans_tbl.index_count) { + /* Print an error message if we cannot find the index + ** in the "index translation table". */ + sql_print_error("Cannot find index %s in InnoDB index " + "translation table.", index->name); + } } /* If we do not have an "index translation table", or not able @@ -12251,7 +12278,7 @@ static MYSQL_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite, static MYSQL_SYSVAR_ULONG(io_capacity, srv_io_capacity, PLUGIN_VAR_RQCMDARG, "Number of IOPs the server can do. Tunes the background IO rate", - NULL, NULL, 200, 100, ~0L, 0); + NULL, NULL, 200, 100, ~0UL, 0); static MYSQL_SYSVAR_ULONG(purge_batch_size, srv_purge_batch_size, PLUGIN_VAR_OPCMDARG, @@ -12384,7 +12411,7 @@ static MYSQL_SYSVAR_BOOL(adaptive_flushing, srv_adaptive_flushing, static MYSQL_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag, PLUGIN_VAR_RQCMDARG, "Desired maximum length of the purge queue (0 = no limit)", - NULL, NULL, 0, 0, ~0L, 0); + NULL, NULL, 0, 0, ~0UL, 0); static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, @@ -12488,7 +12515,7 @@ static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency, static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, PLUGIN_VAR_RQCMDARG, "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket", - NULL, NULL, 500L, 1L, ~0L, 0); + NULL, NULL, 500L, 1L, ~0UL, 0); static MYSQL_SYSVAR_LONG(kill_idle_transaction, srv_kill_idle_transaction, PLUGIN_VAR_RQCMDARG, @@ -12559,12 +12586,12 @@ static MYSQL_SYSVAR_LONG(open_files, innobase_open_files, static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds, PLUGIN_VAR_RQCMDARG, "Count of spin-loop rounds in InnoDB mutexes (30 by default)", - NULL, NULL, 30L, 0L, ~0L, 0); + NULL, NULL, 30L, 0L, ~0UL, 0); static MYSQL_SYSVAR_ULONG(spin_wait_delay, srv_spin_wait_delay, PLUGIN_VAR_OPCMDARG, "Maximum delay between polling for a spin lock (6 by default)", - NULL, NULL, 6L, 0L, ~0L, 0); + NULL, NULL, 6L, 0L, ~0UL, 0); static MYSQL_SYSVAR_BOOL(thread_concurrency_timer_based, innobase_thread_concurrency_timer_based, @@ -12580,7 +12607,7 @@ static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, static MYSQL_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay, PLUGIN_VAR_RQCMDARG, "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep", - NULL, NULL, 10000L, 0L, ~0L, 0); + NULL, NULL, 10000L, 0L, ~0UL, 0); static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, @@ -12755,7 +12782,7 @@ innodb_adaptive_flushing_method_update( void* var_ptr, const void* save) { - *(long *)var_ptr= (*(long *)save) % 4; + *(long *)var_ptr= (*(long *)save) % 3; } const char *adaptive_flushing_method_names[]= { @@ -12933,6 +12960,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(corrupt_table_action), MYSQL_SYSVAR(lazy_drop_table), MYSQL_SYSVAR(fake_changes), + MYSQL_SYSVAR(merge_sort_block_size), NULL }; @@ -12953,6 +12981,7 @@ mysql_declare_plugin(innobase) 0, /* flags */ }, i_s_innodb_rseg, +i_s_innodb_undo_logs, i_s_innodb_trx, i_s_innodb_locks, i_s_innodb_lock_waits, diff --git a/handler/handler0alter.cc b/handler/handler0alter.cc index 398e8bee425..46ffc28180d 100644 --- a/handler/handler0alter.cc +++ b/handler/handler0alter.cc @@ -712,6 +712,10 @@ ha_innobase::add_index( ut_a(indexed_table == prebuilt->table); + if (indexed_table->tablespace_discarded) { + DBUG_RETURN(-1); + } + /* Check that index keys are sensible */ error = innobase_check_index_keys(key_info, num_of_keys, prebuilt->table); @@ -780,7 +784,7 @@ ha_innobase::add_index( row_mysql_lock_data_dictionary(trx); dict_locked = TRUE; - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); /* If a new primary key is defined for the table we need to drop the original table and rebuild all indexes. */ @@ -816,7 +820,7 @@ ha_innobase::add_index( } ut_d(dict_table_check_for_dup_indexes(prebuilt->table, - FALSE)); + TRUE)); mem_heap_free(heap); trx_general_rollback_for_mysql(trx, NULL); row_mysql_unlock_data_dictionary(trx); @@ -1070,7 +1074,7 @@ ha_innobase::final_add_index( trx_commit_for_mysql(prebuilt->trx); } - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); row_mysql_unlock_data_dictionary(trx); trx_free_for_mysql(trx); @@ -1117,7 +1121,7 @@ ha_innobase::prepare_drop_index( /* Test and mark all the indexes to be dropped */ row_mysql_lock_data_dictionary(trx); - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); /* Check that none of the indexes have previously been flagged for deletion. */ @@ -1288,7 +1292,7 @@ func_exit: } while (index); } - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); row_mysql_unlock_data_dictionary(trx); DBUG_RETURN(err); @@ -1341,7 +1345,7 @@ ha_innobase::final_drop_index( prebuilt->table->flags, user_thd); row_mysql_lock_data_dictionary(trx); - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); if (UNIV_UNLIKELY(err)) { @@ -1385,7 +1389,7 @@ ha_innobase::final_drop_index( share->idx_trans_tbl.index_count = 0; func_exit: - ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); trx_commit_for_mysql(trx); trx_commit_for_mysql(prebuilt->trx); row_mysql_unlock_data_dictionary(trx); diff --git a/handler/i_s.cc b/handler/i_s.cc index a7b453846f7..c03ecb15e1c 100644 --- a/handler/i_s.cc +++ b/handler/i_s.cc @@ -48,6 +48,7 @@ extern "C" { #include "trx0i_s.h" #include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */ #include "trx0rseg.h" /* for trx_rseg_struct */ +#include "trx0undo.h" /* for trx_undo_struct */ #include "trx0sys.h" /* for trx_sys */ #include "dict0dict.h" /* for dict_sys */ #include "buf0lru.h" /* for XTRA_LRU_[DUMP/RESTORE] */ @@ -5144,3 +5145,247 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_buffer_pool_pages_blob = STRUCT_FLD(flags, 0UL) }; + +static ST_FIELD_INFO i_s_innodb_undo_logs_fields_info[] = +{ +#define IDX_USEG_TRX_ID 0 + {STRUCT_FLD(field_name, "trx_id"), + STRUCT_FLD(field_length, TRX_ID_MAX_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_USEG_RSEG_ID 1 + {STRUCT_FLD(field_name, "rseg_id"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_USEG_USEG_ID 2 + {STRUCT_FLD(field_name, "useg_id"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_USEG_TYPE 3 +#define USEG_TYPE_MAX_LEN 256 + {STRUCT_FLD(field_name, "type"), + STRUCT_FLD(field_length, USEG_TYPE_MAX_LEN), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + #define IDX_USEG_STATE 4 + #define USEG_STATE_MAX_LEN 256 + {STRUCT_FLD(field_name, "state"), + STRUCT_FLD(field_length, USEG_STATE_MAX_LEN), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_USEG_SIZE 5 + {STRUCT_FLD(field_name, "size"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + END_OF_ST_FIELD_INFO +}; +static +int +i_s_innodb_undo_logs_fill_store( +/*=================*/ + THD* thd, /* in: thread */ + TABLE* table, /* in/out: table to fill */ + trx_undo_t* useg) /* in: useg to fill from */ +{ + char trx_id[TRX_ID_MAX_LEN + 1]; + + DBUG_ENTER("i_s_innodb_undo_logs_fill_store"); + + switch (useg->type) { + case TRX_UNDO_INSERT: + OK(field_store_string(table->field[IDX_USEG_TYPE], "INSERT")); + break; + case TRX_UNDO_UPDATE: + OK(field_store_string(table->field[IDX_USEG_TYPE], "UPDATE")); + break; + default: + OK(field_store_string(table->field[IDX_USEG_TYPE], "UNKNOWN")); + break; + } + + ut_snprintf(trx_id, sizeof(trx_id), TRX_ID_FMT, useg->trx_id); + + switch (useg->state) { + case TRX_UNDO_ACTIVE: + OK(field_store_string(table->field[IDX_USEG_TRX_ID], trx_id)); + OK(field_store_string(table->field[IDX_USEG_STATE], "ACTIVE")); + break; + case TRX_UNDO_CACHED: + OK(field_store_string(table->field[IDX_USEG_TRX_ID], NULL)); + OK(field_store_string(table->field[IDX_USEG_STATE], "CACHED")); + break; + case TRX_UNDO_TO_FREE: + OK(field_store_string(table->field[IDX_USEG_TRX_ID], NULL)); + OK(field_store_string(table->field[IDX_USEG_STATE], "TO_FREE")); + break; + case TRX_UNDO_TO_PURGE: + OK(field_store_string(table->field[IDX_USEG_TRX_ID], NULL)); + OK(field_store_string(table->field[IDX_USEG_STATE], "TO_PURGE")); + break; + case TRX_UNDO_PREPARED: + OK(field_store_string(table->field[IDX_USEG_TRX_ID], trx_id)); + OK(field_store_string(table->field[IDX_USEG_STATE], "PREPARED")); + break; + default: + OK(field_store_string(table->field[IDX_USEG_TRX_ID], trx_id)); + OK(field_store_string(table->field[IDX_USEG_STATE], "UNKNOWN")); + break; + } + + table->field[IDX_USEG_RSEG_ID]->store(useg->rseg->id); + table->field[IDX_USEG_USEG_ID]->store(useg->id); + table->field[IDX_USEG_SIZE]->store(useg->size); + if (schema_table_store_record(thd, table)) { + DBUG_RETURN(1); + } + DBUG_RETURN(0); +} +static +int +i_s_innodb_undo_logs_fill( +/*=================*/ + THD* thd, /* in: thread */ + TABLE_LIST* tables, /* in/out: tables to fill */ + COND* cond) /* in: condition (ignored) */ +{ + TABLE* table = (TABLE *) tables->table; + int status = 0; + trx_rseg_t* rseg; + trx_undo_t* useg; + + DBUG_ENTER("i_s_innodb_undo_logs_fill"); + + /* deny access to non-superusers */ + if (check_global_access(thd, PROCESS_ACL)) { + DBUG_RETURN(0); + } + + RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name); + + rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list); + while (rseg && status == 0) { + mutex_enter(&(rseg->mutex)); + useg = UT_LIST_GET_FIRST(rseg->update_undo_list); + while (useg && status == 0) { + status = i_s_innodb_undo_logs_fill_store(thd, table, useg); + useg = UT_LIST_GET_NEXT(undo_list, useg); + } + + useg = UT_LIST_GET_FIRST(rseg->update_undo_cached); + while (useg && status == 0) { + status = i_s_innodb_undo_logs_fill_store(thd, table, useg); + useg = UT_LIST_GET_NEXT(undo_list, useg); + } + + useg = UT_LIST_GET_FIRST(rseg->insert_undo_list); + while (useg && status == 0) { + status = i_s_innodb_undo_logs_fill_store(thd, table, useg); + useg = UT_LIST_GET_NEXT(undo_list, useg); + } + + useg = UT_LIST_GET_FIRST(rseg->insert_undo_cached); + while (useg && status == 0) { + status = i_s_innodb_undo_logs_fill_store(thd, table, useg); + useg = UT_LIST_GET_NEXT(undo_list, useg); + } + mutex_exit(&(rseg->mutex)); + rseg = UT_LIST_GET_NEXT(rseg_list, rseg); + } + + DBUG_RETURN(status); +} + +static +int +i_s_innodb_undo_logs_init( +/*=================*/ + /* out: 0 on success */ + void* p) /* in/out: table schema object */ +{ + DBUG_ENTER("i_s_innodb_undo_logs_init"); + ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p; + + schema->fields_info = i_s_innodb_undo_logs_fields_info; + schema->fill_table = i_s_innodb_undo_logs_fill; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_mysql_plugin i_s_innodb_undo_logs = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_UNDO_LOGS"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, "Percona"), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB rollback undo segment information"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, i_s_innodb_undo_logs_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + STRUCT_FLD(version, 0x0100 /* 1.0 */), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + /* reserved for dependency checking */ + /* void* */ + STRUCT_FLD(__reserved1, NULL), + + /* Plugin flags */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL), +}; + diff --git a/handler/i_s.h b/handler/i_s.h index fe4f2ba6dcf..723efd6a693 100644 --- a/handler/i_s.h +++ b/handler/i_s.h @@ -43,6 +43,7 @@ extern struct st_mysql_plugin i_s_innodb_sys_fields; extern struct st_mysql_plugin i_s_innodb_sys_foreign; extern struct st_mysql_plugin i_s_innodb_sys_foreign_cols; extern struct st_mysql_plugin i_s_innodb_rseg; +extern struct st_mysql_plugin i_s_innodb_undo_logs; extern struct st_mysql_plugin i_s_innodb_sys_stats; extern struct st_mysql_plugin i_s_innodb_table_stats; extern struct st_mysql_plugin i_s_innodb_index_stats; diff --git a/include/btr0btr.h b/include/btr0btr.h index 520527d0375..03e89ae3f7d 100644 --- a/include/btr0btr.h +++ b/include/btr0btr.h @@ -92,6 +92,8 @@ insert/delete buffer when the record is not in the buffer pool. */ buffer when the record is not in the buffer pool. */ #define BTR_DELETE 8192 +#endif /* UNIV_HOTBACKUP */ + /**************************************************************//** Report that an index page is corrupted. */ UNIV_INTERN @@ -112,6 +114,7 @@ btr_corruption_report( ut_error; \ } +#ifndef UNIV_HOTBACKUP #ifdef UNIV_BLOB_DEBUG # include "ut0rbt.h" /** An index->blobs entry for keeping track of off-page column references */ diff --git a/include/btr0types.h b/include/btr0types.h index 6f515c3f58c..43c6b425688 100644 --- a/include/btr0types.h +++ b/include/btr0types.h @@ -39,6 +39,8 @@ typedef struct btr_cur_struct btr_cur_t; /** B-tree search information for the adaptive hash index */ typedef struct btr_search_struct btr_search_t; +#ifndef UNIV_HOTBACKUP + /** @brief The latch protecting the adaptive search system This latch protects the @@ -56,6 +58,8 @@ Bear in mind (3) and (4) when using the hash index. extern rw_lock_t** btr_search_latch_part; +#endif /* UNIV_HOTBACKUP */ + /** The latch protecting the adaptive search system */ //#define btr_search_latch (*btr_search_latch_temp) diff --git a/include/buf0buf.h b/include/buf0buf.h index 7502942d681..44130aa8b99 100644 --- a/include/buf0buf.h +++ b/include/buf0buf.h @@ -608,34 +608,34 @@ ib_uint64_t buf_block_get_modify_clock( /*=======================*/ buf_block_t* block); /*!< in: block */ -#else /* !UNIV_HOTBACKUP */ -# define buf_block_modify_clock_inc(block) ((void) 0) -#endif /* !UNIV_HOTBACKUP */ /*******************************************************************//** Increments the bufferfix count. */ UNIV_INLINE void buf_block_buf_fix_inc_func( /*=======================*/ -#ifdef UNIV_SYNC_DEBUG +# ifdef UNIV_SYNC_DEBUG const char* file, /*!< in: file name */ ulint line, /*!< in: line */ -#endif /* UNIV_SYNC_DEBUG */ +# endif /* UNIV_SYNC_DEBUG */ buf_block_t* block) /*!< in/out: block to bufferfix */ __attribute__((nonnull)); -#ifdef UNIV_SYNC_DEBUG +# ifdef UNIV_SYNC_DEBUG /** Increments the bufferfix count. @param b in/out: block to bufferfix @param f in: file name where requested @param l in: line number where requested */ # define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b) -#else /* UNIV_SYNC_DEBUG */ +# else /* UNIV_SYNC_DEBUG */ /** Increments the bufferfix count. @param b in/out: block to bufferfix @param f in: file name where requested @param l in: line number where requested */ # define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b) -#endif /* UNIV_SYNC_DEBUG */ +# endif /* UNIV_SYNC_DEBUG */ +#else /* !UNIV_HOTBACKUP */ +# define buf_block_modify_clock_inc(block) ((void) 0) +#endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Calculates a page checksum which is stored to the page when it is written to a file. Note that we must be careful to calculate the same value @@ -1191,9 +1191,10 @@ buf_page_init_for_read( ulint offset);/*!< in: page number */ /********************************************************************//** Completes an asynchronous read or write request of a file page to or from -the buffer pool. */ +the buffer pool. +@return TRUE if successful */ UNIV_INTERN -void +ibool buf_page_io_complete( /*=================*/ buf_page_t* bpage); /*!< in: pointer to the block in question */ diff --git a/include/buf0buf.ic b/include/buf0buf.ic index 66006d366c6..6595e86a8fe 100644 --- a/include/buf0buf.ic +++ b/include/buf0buf.ic @@ -31,6 +31,7 @@ Created 11/5/1995 Heikki Tuuri *******************************************************/ #include "mtr0mtr.h" +#ifndef UNIV_HOTBACKUP #include "buf0flu.h" #include "buf0lru.h" #include "buf0rea.h" @@ -180,6 +181,7 @@ buf_page_peek_if_too_old( return(!buf_page_peek_if_young(bpage)); } } +#endif /* !UNIV_HOTBACKUP */ /*********************************************************************//** Gets the state of a block. diff --git a/include/dict0dict.h b/include/dict0dict.h index 6ce1aed17b7..6c1c4117c05 100644 --- a/include/dict0dict.h +++ b/include/dict0dict.h @@ -750,6 +750,7 @@ ulint dict_table_zip_size( /*================*/ const dict_table_t* table); /*!< in: table */ +#ifndef UNIV_HOTBACKUP /*********************************************************************//** Obtain exclusive locks on all index trees of the table. This is to prevent accessing index trees while InnoDB is updating internal metadata for @@ -766,6 +767,7 @@ void dict_table_x_unlock_indexes( /*========================*/ dict_table_t* table); /*!< in: table */ +#endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Checks if a column is in the ordering columns of the clustered index of a table. Column prefixes are treated like whole columns. @@ -1266,7 +1268,7 @@ UNIV_INTERN void dict_close(void); /*============*/ - +#ifndef UNIV_HOTBACKUP /**********************************************************************//** Check whether the table is corrupted. @return nonzero for corrupted table, zero for valid tables */ @@ -1287,6 +1289,7 @@ dict_index_is_corrupted( const dict_index_t* index) /*!< in: index */ __attribute__((nonnull, pure, warn_unused_result)); +#endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** Flags an index and table corrupted both in the data dictionary cache and in the system table SYS_INDEXES. */ diff --git a/include/dict0dict.ic b/include/dict0dict.ic index 1c09722e8d7..eeb916fe181 100644 --- a/include/dict0dict.ic +++ b/include/dict0dict.ic @@ -491,6 +491,7 @@ dict_table_zip_size( return(dict_table_flags_to_zip_size(table->flags)); } +#ifndef UNIV_HOTBACKUP /*********************************************************************//** Obtain exclusive locks on all index trees of the table. This is to prevent accessing index trees while InnoDB is updating internal metadata for @@ -533,6 +534,7 @@ dict_table_x_unlock_indexes( rw_lock_x_unlock(dict_index_get_lock(index)); } } +#endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Gets the number of fields in the internal representation of an index, including fields added by the dictionary system. diff --git a/include/ha_prototypes.h b/include/ha_prototypes.h index 8dc968baebe..64e7003ea0a 100644 --- a/include/ha_prototypes.h +++ b/include/ha_prototypes.h @@ -314,4 +314,15 @@ thd_expand_fast_index_creation( void* thd); /*!< in: thread handle (THD*) */ +/********************************************************************//** +Returns the merge-sort block size used for the secondary index creation +for the current connection. +@return the merge-sort block size, in bytes */ + +ulong +thd_merge_sort_block_size( +/*======================*/ + void* thd); /*!< in: thread handle (THD*), or NULL to query + the global merge_sort_block_size */ + #endif diff --git a/include/log0log.h b/include/log0log.h index c39c7b0c126..31cbfe1a974 100644 --- a/include/log0log.h +++ b/include/log0log.h @@ -765,7 +765,6 @@ struct log_struct{ buffer */ #ifndef UNIV_HOTBACKUP mutex_t mutex; /*!< mutex protecting the log */ -#endif /* !UNIV_HOTBACKUP */ mutex_t log_flush_order_mutex;/*!< mutex to serialize access to the flush list when we are putting @@ -775,6 +774,7 @@ struct log_struct{ mtr_commit and still ensure that insertions in the flush_list happen in the LSN order. */ +#endif /* !UNIV_HOTBACKUP */ byte* buf_ptr; /* unaligned log buffer */ byte* buf; /*!< log buffer */ ulint buf_size; /*!< log buffer size in bytes */ diff --git a/include/os0file.h b/include/os0file.h index 366a2862e99..bbb3acca6c7 100644 --- a/include/os0file.h +++ b/include/os0file.h @@ -316,7 +316,7 @@ to original un-instrumented file I/O APIs */ os_file_create_func(name, create, purpose, type, success) # define os_file_create_simple(key, name, create, access, success) \ - os_file_create_simple_func(name, create_mode, access, success) + os_file_create_simple_func(name, create, access, success) # define os_file_create_simple_no_error_handling( \ key, name, create_mode, access, success) \ diff --git a/include/srv0srv.h b/include/srv0srv.h index 2a960089bc2..d81aa1c36df 100644 --- a/include/srv0srv.h +++ b/include/srv0srv.h @@ -114,13 +114,13 @@ extern ulint srv_max_file_format_at_startup; /** Place locks to records only i.e. do not use next-key locking except on duplicate key checking and foreign key checking */ extern ibool srv_locks_unsafe_for_binlog; -#endif /* !UNIV_HOTBACKUP */ /* If this flag is TRUE, then we will use the native aio of the OS (provided we compiled Innobase with it in), otherwise we will use simulated aio we build below with threads. Currently we support native aio on windows and linux */ extern my_bool srv_use_native_aio; +#endif /* !UNIV_HOTBACKUP */ #ifdef __WIN__ extern ibool srv_use_native_conditions; #endif diff --git a/include/trx0sys.h b/include/trx0sys.h index 976cb31563f..c933fb405e1 100644 --- a/include/trx0sys.h +++ b/include/trx0sys.h @@ -248,7 +248,6 @@ UNIV_INLINE trx_id_t trx_sys_get_new_trx_id(void); /*========================*/ -#endif /* !UNIV_HOTBACKUP */ #ifdef UNIV_DEBUG /* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ @@ -265,7 +264,6 @@ trx_write_trx_id( /*=============*/ byte* ptr, /*!< in: pointer to memory where written */ trx_id_t id); /*!< in: id */ -#ifndef UNIV_HOTBACKUP /*****************************************************************//** Reads a trx id from an index page. In case that the id size changes in some future version, this function should be used instead of @@ -603,7 +601,6 @@ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_NO. */ #define TRX_SYS_DOUBLEWRITE_BLOCK_SIZE FSP_EXTENT_SIZE /* @} */ -#ifndef UNIV_HOTBACKUP /** File format tag */ /* @{ */ /** The offset of the file format tag on the trx system header page @@ -622,6 +619,7 @@ identifier is added to this 64-bit constant. */ | TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW) /* @} */ +#ifndef UNIV_HOTBACKUP /** Doublewrite control struct */ struct trx_doublewrite_struct{ mutex_t mutex; /*!< mutex protecting the first_free field and diff --git a/mem/mem0dbg.c b/mem/mem0dbg.c index ae43d6097a6..0909b7c9a64 100644 --- a/mem/mem0dbg.c +++ b/mem/mem0dbg.c @@ -24,7 +24,9 @@ but is included in mem0mem.* ! Created 6/9/1994 Heikki Tuuri *************************************************************************/ -#include "ha_prototypes.h" +#ifndef UNIV_HOTBACKUP +# include "ha_prototypes.h" +#endif /* !UNIV_HOTBACKUP */ #ifdef UNIV_MEM_DEBUG # ifndef UNIV_HOTBACKUP diff --git a/os/os0file.c b/os/os0file.c index 26636c8a6cb..2f2e554d97c 100644 --- a/os/os0file.c +++ b/os/os0file.c @@ -307,6 +307,7 @@ UNIV_INTERN ulint os_n_pending_writes = 0; UNIV_INTERN ulint os_n_pending_reads = 0; #ifdef UNIV_DEBUG +# ifndef UNIV_HOTBACKUP /**********************************************************************//** Validates the consistency the aio system some of the time. @return TRUE if ok or the check was skipped */ @@ -333,6 +334,7 @@ os_aio_validate_skip(void) os_aio_validate_count = OS_AIO_VALIDATE_SKIP; return(os_aio_validate()); } +# endif /* !UNIV_HOTBACKUP */ #endif /* UNIV_DEBUG */ #ifdef __WIN__ diff --git a/page/page0zip.c b/page/page0zip.c index d4b0dd8339d..4751f4816a9 100644 --- a/page/page0zip.c +++ b/page/page0zip.c @@ -4437,7 +4437,9 @@ page_zip_reorganize( dict_index_t* index, /*!< in: index of the B-tree node */ mtr_t* mtr) /*!< in: mini-transaction */ { +#ifndef UNIV_HOTBACKUP buf_pool_t* buf_pool = buf_pool_from_block(block); +#endif /* !UNIV_HOTBACKUP */ page_zip_des_t* page_zip = buf_block_get_page_zip(block); page_t* page = buf_block_get_frame(block); buf_block_t* temp_block; diff --git a/row/row0ins.c b/row/row0ins.c index a629a4fb195..b21d48c7552 100644 --- a/row/row0ins.c +++ b/row/row0ins.c @@ -1281,7 +1281,8 @@ run_again: check_index = foreign->foreign_index; } - if (check_table == NULL || check_table->ibd_file_missing) { + if (check_table == NULL || check_table->ibd_file_missing + || check_index == NULL) { if (check_ref) { FILE* ef = dict_foreign_err_file; @@ -1316,9 +1317,6 @@ run_again: goto exit_func; } - ut_a(check_table); - ut_a(check_index); - if (check_table != table) { /* We already have a LOCK_IX on table, but not necessarily on check_table */ diff --git a/row/row0merge.c b/row/row0merge.c index c303a372ed0..ac11379ab58 100644 --- a/row/row0merge.c +++ b/row/row0merge.c @@ -89,8 +89,9 @@ rounded to a power of 2. When not creating a PRIMARY KEY that contains column prefixes, this can be set as small as UNIV_PAGE_SIZE / 2. See the comment above -ut_ad(data_size < sizeof(row_merge_block_t)). */ -typedef byte row_merge_block_t[1048576]; +ut_ad(data_size < sizeof(row_merge_block_t)). +1MB is the default merge-sort block size for innodb */ +typedef byte* row_merge_block_t; /** @brief Secondary buffer for I/O operations of merge records. @@ -184,7 +185,6 @@ row_merge_buf_create_low( row_merge_buf_t* buf; ut_ad(max_tuples > 0); - ut_ad(max_tuples <= sizeof(row_merge_block_t)); ut_ad(max_tuples < buf_size); buf = mem_heap_zalloc(heap, buf_size); @@ -205,19 +205,19 @@ static row_merge_buf_t* row_merge_buf_create( /*=================*/ - dict_index_t* index) /*!< in: secondary index */ + dict_index_t* index, /*!< in: secondary index */ + ulint block_size) /*!< in: merge block buffer size */ { row_merge_buf_t* buf; ulint max_tuples; ulint buf_size; mem_heap_t* heap; - max_tuples = sizeof(row_merge_block_t) - / ut_max(1, dict_index_get_min_size(index)); + max_tuples = block_size / ut_max(1, dict_index_get_min_size(index)); buf_size = (sizeof *buf) + (max_tuples - 1) * sizeof *buf->tuples; - heap = mem_heap_create(buf_size + sizeof(row_merge_block_t)); + heap = mem_heap_create(buf_size + block_size); buf = row_merge_buf_create_low(heap, index, max_tuples, buf_size); @@ -265,8 +265,10 @@ row_merge_buf_add( /*==============*/ row_merge_buf_t* buf, /*!< in/out: sort buffer */ const dtuple_t* row, /*!< in: row in clustered index */ - const row_ext_t* ext) /*!< in: cache of externally stored + const row_ext_t* ext, /*!< in: cache of externally stored column prefixes, or NULL */ + ulint block_size) + /*!< in: merge block buffer size */ { ulint i; ulint n_fields; @@ -391,10 +393,10 @@ row_merge_buf_add( page_zip_rec_needs_ext() limit. However, no further columns will be moved to external storage until the record is inserted to the clustered index B-tree. */ - ut_ad(data_size < sizeof(row_merge_block_t)); + ut_ad(data_size < block_size); /* Reserve one byte for the end marker of row_merge_block_t. */ - if (buf->total_size + data_size >= sizeof(row_merge_block_t) - 1) { + if (buf->total_size + data_size >= block_size - 1) { return(FALSE); } @@ -700,9 +702,11 @@ row_merge_read( ulint offset, /*!< in: offset where to read in number of row_merge_block_t elements */ - row_merge_block_t* buf) /*!< out: data */ + row_merge_block_t buf, /*!< out: data */ + ulint block_size) + /*!< in: merge block buffer size */ { - ib_uint64_t ofs = ((ib_uint64_t) offset) * sizeof *buf; + ib_uint64_t ofs = ((ib_uint64_t) offset) * block_size; ibool success; #ifdef UNIV_DEBUG @@ -715,7 +719,7 @@ row_merge_read( success = os_file_read_no_error_handling(OS_FILE_FROM_FD(fd), buf, (ulint) (ofs & 0xFFFFFFFF), (ulint) (ofs >> 32), - sizeof *buf); + block_size); #ifdef POSIX_FADV_DONTNEED /* Each block is read exactly once. Free up the file cache. */ posix_fadvise(fd, ofs, sizeof *buf, POSIX_FADV_DONTNEED); @@ -740,16 +744,17 @@ row_merge_write( int fd, /*!< in: file descriptor */ ulint offset, /*!< in: offset where to write, in number of row_merge_block_t elements */ - const void* buf) /*!< in: data */ + const void* buf, /*!< in: data */ + ulint block_size) + /*!< in: merge block buffer size */ { - size_t buf_len = sizeof(row_merge_block_t); - ib_uint64_t ofs = buf_len * (ib_uint64_t) offset; + ib_uint64_t ofs = block_size * (ib_uint64_t) offset; ibool ret; ret = os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf, (ulint) (ofs & 0xFFFFFFFF), (ulint) (ofs >> 32), - buf_len); + block_size); #ifdef UNIV_DEBUG if (row_merge_print_block_write) { @@ -761,7 +766,7 @@ row_merge_write( #ifdef POSIX_FADV_DONTNEED /* The block will be needed on the next merge pass, but it can be evicted from the file cache meanwhile. */ - posix_fadvise(fd, ofs, buf_len, POSIX_FADV_DONTNEED); + posix_fadvise(fd, ofs, block_size, POSIX_FADV_DONTNEED); #endif /* POSIX_FADV_DONTNEED */ return(UNIV_LIKELY(ret)); @@ -783,7 +788,9 @@ row_merge_read_rec( const mrec_t** mrec, /*!< out: pointer to merge record, or NULL on end of list (non-NULL on I/O error) */ - ulint* offsets)/*!< out: offsets of mrec */ + ulint* offsets,/*!< out: offsets of mrec */ + ulint block_size) + /*!< in: merge block buffer size */ { ulint extra_size; ulint data_size; @@ -820,7 +827,8 @@ row_merge_read_rec( /* Read another byte of extra_size. */ if (UNIV_UNLIKELY(b >= block[1])) { - if (!row_merge_read(fd, ++(*foffs), block)) { + if (!row_merge_read(fd, ++(*foffs), block[0], + block_size)) { err_exit: /* Signal I/O error. */ *mrec = b; @@ -849,7 +857,8 @@ err_exit: memcpy(*buf, b, avail_size); - if (!row_merge_read(fd, ++(*foffs), block)) { + if (!row_merge_read(fd, ++(*foffs), block[0], + block_size)) { goto err_exit; } @@ -870,7 +879,7 @@ err_exit: /* These overflows should be impossible given that records are much smaller than either buffer, and the record starts near the beginning of each buffer. */ - ut_a(extra_size + data_size < sizeof *buf); + ut_a(extra_size + data_size < block_size); ut_a(b + data_size < block[1]); /* Copy the data bytes. */ @@ -885,7 +894,7 @@ err_exit: rec_init_offsets_comp_ordinary(*mrec, 0, index, offsets); data_size = rec_offs_data_size(offsets); - ut_ad(extra_size + data_size < sizeof *buf); + ut_ad(extra_size + data_size < block_size); b += extra_size + data_size; @@ -910,7 +919,8 @@ err_exit: offsets[3] = (ulint) index; #endif /* UNIV_DEBUG */ - if (!row_merge_read(fd, ++(*foffs), block)) { + if (!row_merge_read(fd, ++(*foffs), block[0], + block_size)) { goto err_exit; } @@ -992,7 +1002,9 @@ row_merge_write_rec( int fd, /*!< in: file descriptor */ ulint* foffs, /*!< in/out: file offset */ const mrec_t* mrec, /*!< in: record to write */ - const ulint* offsets)/*!< in: offsets of mrec */ + const ulint* offsets,/*!< in: offsets of mrec */ + ulint block_size) + /*!< in: merge block buffer size */ { ulint extra_size; ulint size; @@ -1027,11 +1039,12 @@ row_merge_write_rec( record to the head of the new block. */ memcpy(b, buf[0], avail_size); - if (!row_merge_write(fd, (*foffs)++, block)) { + if (!row_merge_write(fd, (*foffs)++, block[0], + block_size)) { return(NULL); } - UNIV_MEM_INVALID(block[0], sizeof block[0]); + UNIV_MEM_INVALID(block[0], block_size); /* Copy the rest. */ b = block[0]; @@ -1056,7 +1069,9 @@ row_merge_write_eof( row_merge_block_t* block, /*!< in/out: file buffer */ byte* b, /*!< in: pointer to end of block */ int fd, /*!< in: file descriptor */ - ulint* foffs) /*!< in/out: file offset */ + ulint* foffs, /*!< in/out: file offset */ + ulint block_size) + /*!< in: merge block buffer size */ { ut_ad(block); ut_ad(b >= block[0]); @@ -1071,18 +1086,19 @@ row_merge_write_eof( *b++ = 0; UNIV_MEM_ASSERT_RW(block[0], b - block[0]); - UNIV_MEM_ASSERT_W(block[0], sizeof block[0]); + UNIV_MEM_ASSERT_W(block[0], block_size); #ifdef UNIV_DEBUG_VALGRIND /* The rest of the block is uninitialized. Initialize it to avoid bogus warnings. */ memset(b, 0xff, block[1] - b); #endif /* UNIV_DEBUG_VALGRIND */ - if (!row_merge_write(fd, (*foffs)++, block)) { + if (!row_merge_write(fd, (*foffs)++, block[0], + block_size)) { return(NULL); } - UNIV_MEM_INVALID(block[0], sizeof block[0]); + UNIV_MEM_INVALID(block[0], block_size); return(block[0]); } @@ -1140,7 +1156,9 @@ row_merge_read_clustered_index( dict_index_t** index, /*!< in: indexes to be created */ merge_file_t* files, /*!< in: temporary files */ ulint n_index,/*!< in: number of indexes to create */ - row_merge_block_t* block) /*!< in/out: file buffer */ + row_merge_block_t* block, /*!< in/out: file buffer */ + ulint block_size) + /*!< in: merge block buffer size */ { dict_index_t* clust_index; /* Clustered index */ mem_heap_t* row_heap; /* Heap memory to create @@ -1168,7 +1186,7 @@ row_merge_read_clustered_index( merge_buf = mem_alloc(n_index * sizeof *merge_buf); for (i = 0; i < n_index; i++) { - merge_buf[i] = row_merge_buf_create(index[i]); + merge_buf[i] = row_merge_buf_create(index[i], block_size); } mtr_start(&mtr); @@ -1300,7 +1318,8 @@ row_merge_read_clustered_index( const dict_index_t* index = buf->index; if (UNIV_LIKELY - (row && row_merge_buf_add(buf, row, ext))) { + (row && row_merge_buf_add(buf, row, ext, + block_size))) { file->n_rec++; continue; } @@ -1335,12 +1354,12 @@ err_exit: row_merge_buf_write(buf, file, block); if (!row_merge_write(file->fd, file->offset++, - block)) { + block[0], block_size)) { err = DB_OUT_OF_FILE_SPACE; goto err_exit; } - UNIV_MEM_INVALID(block[0], sizeof block[0]); + UNIV_MEM_INVALID(block[0], block_size); merge_buf[i] = row_merge_buf_empty(buf); if (UNIV_LIKELY(row != NULL)) { @@ -1349,7 +1368,8 @@ err_exit: and emptied. */ if (UNIV_UNLIKELY - (!row_merge_buf_add(buf, row, ext))) { + (!row_merge_buf_add(buf, row, ext, + block_size))) { /* An empty buffer should have enough room for at least one record. */ ut_error; @@ -1393,14 +1413,16 @@ func_exit: do { \ b2 = row_merge_write_rec(&block[2], &buf[2], b2, \ of->fd, &of->offset, \ - mrec##N, offsets##N); \ + mrec##N, offsets##N, \ + block_size); \ if (UNIV_UNLIKELY(!b2 || ++of->n_rec > file->n_rec)) { \ goto corrupt; \ } \ b##N = row_merge_read_rec(&block[N], &buf[N], \ b##N, index, \ file->fd, foffs##N, \ - &mrec##N, offsets##N); \ + &mrec##N, offsets##N, \ + block_size); \ if (UNIV_UNLIKELY(!b##N)) { \ if (mrec##N) { \ goto corrupt; \ @@ -1425,9 +1447,11 @@ row_merge_blocks( ulint* foffs1, /*!< in/out: offset of second source list in the file */ merge_file_t* of, /*!< in/out: output file */ - struct TABLE* table) /*!< in/out: MySQL table, for + struct TABLE* table, /*!< in/out: MySQL table, for reporting erroneous key value if applicable */ + ulint block_size) + /*!< in: merge block buffer size */ { mem_heap_t* heap; /*!< memory heap for offsets0, offsets1 */ @@ -1457,8 +1481,10 @@ row_merge_blocks( /* Write a record and read the next record. Split the output file in two halves, which can be merged on the following pass. */ - if (!row_merge_read(file->fd, *foffs0, &block[0]) - || !row_merge_read(file->fd, *foffs1, &block[1])) { + if (!row_merge_read(file->fd, *foffs0, block[0], + block_size) + || !row_merge_read(file->fd, *foffs1, block[1], + block_size)) { corrupt: mem_heap_free(heap); return(DB_CORRUPTION); @@ -1469,9 +1495,9 @@ corrupt: b2 = block[2]; b0 = row_merge_read_rec(&block[0], &buf[0], b0, index, file->fd, - foffs0, &mrec0, offsets0); + foffs0, &mrec0, offsets0, block_size); b1 = row_merge_read_rec(&block[1], &buf[1], b1, index, file->fd, - foffs1, &mrec1, offsets1); + foffs1, &mrec1, offsets1, block_size); if (UNIV_UNLIKELY(!b0 && mrec0) || UNIV_UNLIKELY(!b1 && mrec1)) { @@ -1521,7 +1547,8 @@ done0: done1: mem_heap_free(heap); - b2 = row_merge_write_eof(&block[2], b2, of->fd, &of->offset); + b2 = row_merge_write_eof(&block[2], b2, of->fd, &of->offset, + block_size); return(b2 ? DB_SUCCESS : DB_CORRUPTION); } @@ -1536,7 +1563,9 @@ row_merge_blocks_copy( const merge_file_t* file, /*!< in: input file */ row_merge_block_t* block, /*!< in/out: 3 buffers */ ulint* foffs0, /*!< in/out: input file offset */ - merge_file_t* of) /*!< in/out: output file */ + merge_file_t* of, /*!< in/out: output file */ + ulint block_size) + /*!< in: merge block buffer size */ { mem_heap_t* heap; /*!< memory heap for offsets0, offsets1 */ @@ -1563,7 +1592,7 @@ row_merge_blocks_copy( /* Write a record and read the next record. Split the output file in two halves, which can be merged on the following pass. */ - if (!row_merge_read(file->fd, *foffs0, &block[0])) { + if (!row_merge_read(file->fd, *foffs0, block[0], block_size)) { corrupt: mem_heap_free(heap); return(FALSE); @@ -1573,7 +1602,7 @@ corrupt: b2 = block[2]; b0 = row_merge_read_rec(&block[0], &buf[0], b0, index, file->fd, - foffs0, &mrec0, offsets0); + foffs0, &mrec0, offsets0, block_size); if (UNIV_UNLIKELY(!b0 && mrec0)) { goto corrupt; @@ -1592,8 +1621,8 @@ done0: (*foffs0)++; mem_heap_free(heap); - return(row_merge_write_eof(&block[2], b2, of->fd, &of->offset) - != NULL); + return(row_merge_write_eof(&block[2], b2, of->fd, &of->offset, + block_size) != NULL); } /*************************************************************//** @@ -1614,9 +1643,10 @@ row_merge( if applicable */ ulint* num_run,/*!< in/out: Number of runs remain to be merged */ - ulint* run_offset) /*!< in/out: Array contains the + ulint* run_offset, /*!< in/out: Array contains the first offset number for each merge run */ + ulint block_size) /*!< in: merge block buffer size */ { ulint foffs0; /*!< first input offset */ ulint foffs1; /*!< second input offset */ @@ -1627,7 +1657,7 @@ row_merge( ulint n_run = 0; /*!< num of runs generated from this merge */ - UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]); + UNIV_MEM_ASSERT_W(block[0], 3 * block_size); ut_ad(ihalf < file->offset); @@ -1659,7 +1689,8 @@ row_merge( run_offset[n_run++] = of.offset; error = row_merge_blocks(index, file, block, - &foffs0, &foffs1, &of, table); + &foffs0, &foffs1, &of, table, + block_size); if (error != DB_SUCCESS) { return(error); @@ -1677,7 +1708,8 @@ row_merge( /* Remember the offset number for this run */ run_offset[n_run++] = of.offset; - if (!row_merge_blocks_copy(index, file, block, &foffs0, &of)) { + if (!row_merge_blocks_copy(index, file, block, &foffs0, &of, + block_size)) { return(DB_CORRUPTION); } } @@ -1692,7 +1724,8 @@ row_merge( /* Remember the offset number for this run */ run_offset[n_run++] = of.offset; - if (!row_merge_blocks_copy(index, file, block, &foffs1, &of)) { + if (!row_merge_blocks_copy(index, file, block, &foffs1, &of, + block_size)) { return(DB_CORRUPTION); } } @@ -1721,7 +1754,7 @@ row_merge( *tmpfd = file->fd; *file = of; - UNIV_MEM_INVALID(block[0], 3 * sizeof block[0]); + UNIV_MEM_INVALID(block[0], 3 * block_size); return(DB_SUCCESS); } @@ -1739,9 +1772,11 @@ row_merge_sort( index entries */ row_merge_block_t* block, /*!< in/out: 3 buffers */ int* tmpfd, /*!< in/out: temporary file handle */ - struct TABLE* table) /*!< in/out: MySQL table, for + struct TABLE* table, /*!< in/out: MySQL table, for reporting erroneous key value if applicable */ + ulint block_size) + /*!< in: merge block buffer size */ { ulint half = file->offset / 2; ulint num_runs; @@ -1770,7 +1805,7 @@ row_merge_sort( /* Merge the runs until we have one big run */ do { error = row_merge(trx, index, file, block, tmpfd, - table, &num_runs, run_offset); + table, &num_runs, run_offset, block_size); UNIV_MEM_ASSERT_RW(run_offset, num_runs * sizeof *run_offset); @@ -1841,7 +1876,9 @@ row_merge_insert_index_tuples( ulint zip_size,/*!< in: compressed page size of the old table, or 0 if uncompressed */ int fd, /*!< in: file descriptor */ - row_merge_block_t* block) /*!< in/out: file buffer */ + row_merge_block_t* block, /*!< in/out: file buffer */ + ulint block_size) + /*! in: merge block buffer size */ { const byte* b; que_thr_t* thr; @@ -1880,7 +1917,7 @@ row_merge_insert_index_tuples( b = *block; - if (!row_merge_read(fd, foffs, block)) { + if (!row_merge_read(fd, foffs, block[0], block_size)) { error = DB_CORRUPTION; } else { mrec_buf_t* buf = mem_heap_alloc(graph_heap, sizeof *buf); @@ -1891,7 +1928,8 @@ row_merge_insert_index_tuples( ulint n_ext; b = row_merge_read_rec(block, buf, b, index, - fd, &foffs, &mrec, offsets); + fd, &foffs, &mrec, offsets, + block_size); if (UNIV_UNLIKELY(!b)) { /* End of list, or I/O error */ if (mrec) { @@ -2656,11 +2694,16 @@ row_merge_build_indexes( if applicable */ { merge_file_t* merge_files; - row_merge_block_t* block; + /* Some code uses block[1] as the synonym for block + block_size. So + we initialize block[3] to the address boundary of block[2], even + though space for 3 only buffers is allocated. */ + row_merge_block_t block[4]; ulint block_size; ulint i; ulint error; int tmpfd; + ulint merge_sort_block_size; + void* block_mem; ut_ad(trx); ut_ad(old_table); @@ -2668,14 +2711,21 @@ row_merge_build_indexes( ut_ad(indexes); ut_ad(n_indexes); + merge_sort_block_size = thd_merge_sort_block_size(trx->mysql_thd); + trx_start_if_not_started(trx); /* Allocate memory for merge file data structure and initialize fields */ merge_files = mem_alloc(n_indexes * sizeof *merge_files); - block_size = 3 * sizeof *block; - block = os_mem_alloc_large(&block_size); + block_size = 3 * merge_sort_block_size; + block_mem = os_mem_alloc_large(&block_size); + + for (i = 0; i < UT_ARR_SIZE(block); i++) { + block[i] = (row_merge_block_t ) ((byte *) block_mem + + i * merge_sort_block_size); + } for (i = 0; i < n_indexes; i++) { @@ -2693,7 +2743,7 @@ row_merge_build_indexes( error = row_merge_read_clustered_index( trx, table, old_table, new_table, indexes, - merge_files, n_indexes, block); + merge_files, n_indexes, block, merge_sort_block_size); if (error != DB_SUCCESS) { @@ -2705,13 +2755,15 @@ row_merge_build_indexes( for (i = 0; i < n_indexes; i++) { error = row_merge_sort(trx, indexes[i], &merge_files[i], - block, &tmpfd, table); + block, &tmpfd, table, + merge_sort_block_size); if (error == DB_SUCCESS) { error = row_merge_insert_index_tuples( trx, indexes[i], new_table, dict_table_zip_size(old_table), - merge_files[i].fd, block); + merge_files[i].fd, block, + merge_sort_block_size); } /* Close the temporary file to free up space. */ @@ -2734,7 +2786,7 @@ func_exit: } mem_free(merge_files); - os_mem_free_large(block, block_size); + os_mem_free_large(block_mem, block_size); return(error); } diff --git a/row/row0vers.c b/row/row0vers.c index 5fd7d082194..6d83dbaf8ee 100644 --- a/row/row0vers.c +++ b/row/row0vers.c @@ -209,17 +209,6 @@ row_vers_impl_x_locked_off_kernel( prev_trx_id = row_get_rec_trx_id(prev_version, clust_index, clust_offsets); - /* If the trx_id and prev_trx_id are different and if - the prev_version is marked deleted then the - prev_trx_id must have already committed for the trx_id - to be able to modify the row. Therefore, prev_trx_id - cannot hold any implicit lock. */ - if (vers_del && trx_id != prev_trx_id) { - - mutex_enter(&kernel_mutex); - break; - } - /* The stack of versions is locked by mtr. Thus, it is safe to fetch the prefixes for externally stored columns. */ diff --git a/trx/trx0sys.c b/trx/trx0sys.c index 89fab47a0ad..f46562eaecb 100644 --- a/trx/trx0sys.c +++ b/trx/trx0sys.c @@ -137,12 +137,12 @@ UNIV_INTERN mysql_pfs_key_t trx_doublewrite_mutex_key; UNIV_INTERN mysql_pfs_key_t file_format_max_mutex_key; #endif /* UNIV_PFS_MUTEX */ +#ifndef UNIV_HOTBACKUP #ifdef UNIV_DEBUG /* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ uint trx_rseg_n_slots_debug = 0; #endif -#ifndef UNIV_HOTBACKUP /** This is used to track the maximum file format id known to InnoDB. It's updated via SET GLOBAL innodb_file_format_max = 'x' or when we open or create a table. */ diff --git a/ut/ut0dbg.c b/ut/ut0dbg.c index 64fadd76d1c..53ed4a53044 100644 --- a/ut/ut0dbg.c +++ b/ut/ut0dbg.c @@ -25,7 +25,9 @@ Created 1/30/1994 Heikki Tuuri #include "univ.i" #include "ut0dbg.h" -#include "ha_prototypes.h" +#ifndef UNIV_HOTBACKUP +# include "ha_prototypes.h" +#endif /* !UNIV_HOTBACKUP */ #if defined(__GNUC__) && (__GNUC__ > 2) #else @@ -56,7 +58,7 @@ ut_dbg_assertion_failed( ut_print_timestamp(stderr); #ifdef UNIV_HOTBACKUP fprintf(stderr, " InnoDB: Assertion failure in file %s line %lu\n", - innobase_basename(file), line); + file, line); #else /* UNIV_HOTBACKUP */ fprintf(stderr, " InnoDB: Assertion failure in thread %lu" diff --git a/ut/ut0ut.c b/ut/ut0ut.c index 117a777cb98..2fe45aad2a7 100644 --- a/ut/ut0ut.c +++ b/ut/ut0ut.c @@ -245,7 +245,9 @@ ut_print_timestamp( (int)cal_tm.wMinute, (int)cal_tm.wSecond); #else +#ifdef HAVE_LOCALTIME_R struct tm cal_tm; +#endif struct tm* cal_tm_ptr; time_t tm; @@ -288,7 +290,9 @@ ut_sprintf_timestamp( (int)cal_tm.wMinute, (int)cal_tm.wSecond); #else +#ifdef HAVE_LOCALTIME_R struct tm cal_tm; +#endif struct tm* cal_tm_ptr; time_t tm; @@ -333,7 +337,9 @@ ut_sprintf_timestamp_without_extra_chars( (int)cal_tm.wMinute, (int)cal_tm.wSecond); #else +#ifdef HAVE_LOCALTIME_R struct tm cal_tm; +#endif struct tm* cal_tm_ptr; time_t tm; @@ -374,7 +380,9 @@ ut_get_year_month_day( *month = (ulint)cal_tm.wMonth; *day = (ulint)cal_tm.wDay; #else +#ifdef HAVE_LOCALTIME_R struct tm cal_tm; +#endif struct tm* cal_tm_ptr; time_t tm; From 24b9d7e43f8251263863f52bfefb00eacf2523ae Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 5 Sep 2012 13:15:05 +0200 Subject: [PATCH 18/21] sys_vars.expensive_subquery_limit_basic --- mysql-test/suite/sys_vars/r/all_vars.result | 1 - .../r/expensive_subquery_limit_basic.result | 52 +++++++++++++++++++ .../t/expensive_subquery_limit_basic.test | 38 ++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/sys_vars/r/expensive_subquery_limit_basic.result create mode 100644 mysql-test/suite/sys_vars/t/expensive_subquery_limit_basic.test diff --git a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result index 692545ae0fb..1bd4e394f6a 100644 --- a/mysql-test/suite/sys_vars/r/all_vars.result +++ b/mysql-test/suite/sys_vars/r/all_vars.result @@ -10,6 +10,5 @@ there should be *no* long test name listed below: select distinct variable_name as `there should be *no* variables listed below:` from t2 left join t1 on variable_name=test_name where test_name is null; there should be *no* variables listed below: -expensive_subquery_limit drop table t1; drop table t2; diff --git a/mysql-test/suite/sys_vars/r/expensive_subquery_limit_basic.result b/mysql-test/suite/sys_vars/r/expensive_subquery_limit_basic.result new file mode 100644 index 00000000000..1617de21001 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/expensive_subquery_limit_basic.result @@ -0,0 +1,52 @@ +SET @start_global_value = @@global.expensive_subquery_limit; +SELECT @start_global_value; +@start_global_value +100 +select @@global.expensive_subquery_limit; +@@global.expensive_subquery_limit +100 +select @@session.expensive_subquery_limit; +@@session.expensive_subquery_limit +100 +show global variables like 'expensive_subquery_limit'; +Variable_name Value +expensive_subquery_limit 100 +show session variables like 'expensive_subquery_limit'; +Variable_name Value +expensive_subquery_limit 100 +select * from information_schema.global_variables where variable_name='expensive_subquery_limit'; +VARIABLE_NAME VARIABLE_VALUE +EXPENSIVE_SUBQUERY_LIMIT 100 +select * from information_schema.session_variables where variable_name='expensive_subquery_limit'; +VARIABLE_NAME VARIABLE_VALUE +EXPENSIVE_SUBQUERY_LIMIT 100 +set global expensive_subquery_limit=10; +set session expensive_subquery_limit=20; +select @@global.expensive_subquery_limit; +@@global.expensive_subquery_limit +10 +select @@session.expensive_subquery_limit; +@@session.expensive_subquery_limit +20 +show global variables like 'expensive_subquery_limit'; +Variable_name Value +expensive_subquery_limit 10 +show session variables like 'expensive_subquery_limit'; +Variable_name Value +expensive_subquery_limit 20 +select * from information_schema.global_variables where variable_name='expensive_subquery_limit'; +VARIABLE_NAME VARIABLE_VALUE +EXPENSIVE_SUBQUERY_LIMIT 10 +select * from information_schema.session_variables where variable_name='expensive_subquery_limit'; +VARIABLE_NAME VARIABLE_VALUE +EXPENSIVE_SUBQUERY_LIMIT 20 +set global expensive_subquery_limit=1.1; +ERROR 42000: Incorrect argument type to variable 'expensive_subquery_limit' +set global expensive_subquery_limit=1e1; +ERROR 42000: Incorrect argument type to variable 'expensive_subquery_limit' +set global expensive_subquery_limit="foo"; +ERROR 42000: Incorrect argument type to variable 'expensive_subquery_limit' +SET @@global.expensive_subquery_limit = @start_global_value; +SELECT @@global.expensive_subquery_limit; +@@global.expensive_subquery_limit +100 diff --git a/mysql-test/suite/sys_vars/t/expensive_subquery_limit_basic.test b/mysql-test/suite/sys_vars/t/expensive_subquery_limit_basic.test new file mode 100644 index 00000000000..c86433e94f5 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/expensive_subquery_limit_basic.test @@ -0,0 +1,38 @@ +SET @start_global_value = @@global.expensive_subquery_limit; +SELECT @start_global_value; + +# +# exists as global and session +# +select @@global.expensive_subquery_limit; +select @@session.expensive_subquery_limit; +show global variables like 'expensive_subquery_limit'; +show session variables like 'expensive_subquery_limit'; +select * from information_schema.global_variables where variable_name='expensive_subquery_limit'; +select * from information_schema.session_variables where variable_name='expensive_subquery_limit'; + +# +# show that it's writable +# +set global expensive_subquery_limit=10; +set session expensive_subquery_limit=20; +select @@global.expensive_subquery_limit; +select @@session.expensive_subquery_limit; +show global variables like 'expensive_subquery_limit'; +show session variables like 'expensive_subquery_limit'; +select * from information_schema.global_variables where variable_name='expensive_subquery_limit'; +select * from information_schema.session_variables where variable_name='expensive_subquery_limit'; + +# +# incorrect types +# +--error ER_WRONG_TYPE_FOR_VAR +set global expensive_subquery_limit=1.1; +--error ER_WRONG_TYPE_FOR_VAR +set global expensive_subquery_limit=1e1; +--error ER_WRONG_TYPE_FOR_VAR +set global expensive_subquery_limit="foo"; + +SET @@global.expensive_subquery_limit = @start_global_value; +SELECT @@global.expensive_subquery_limit; + From 54bb28d4a151d0eb5c3b74edb40ddf6e118c124b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 5 Sep 2012 23:23:58 +0300 Subject: [PATCH 19/21] MDEV-486 LP BUG#1010116 fix. Link view/derived table fields to a real table to check turning the table record to null row. Item_direct_view_ref wrapper now checks if table is turned to null row. --- mysql-test/r/derived_view.result | 6 +- mysql-test/r/view.result | 33 ++++++++++ mysql-test/t/view.test | 30 +++++++++ sql/item.cc | 1 + sql/item.h | 103 ++++++++++++++++++++++++++++--- sql/table.cc | 22 +++++++ sql/table.h | 1 + 7 files changed, 184 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index a4f7a71dcb5..6061fbb8800 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -1677,7 +1677,6 @@ SELECT t.b, t.c, t1.a FROM t1, (SELECT t2.b, t2.c FROM t3 RIGHT JOIN t2 ON t2.a = t3.b) AS t WHERE t.b AND t.c = t1.a; b c a -8 c c EXPLAIN EXTENDED SELECT t.b, t.c, t1.a FROM t1, (SELECT t2.b, t2.c FROM t3 RIGHT JOIN t2 ON t2.a = t3.b) AS t @@ -1692,7 +1691,6 @@ SELECT t.b, t.c, t1.a FROM t1, (SELECT t2.b, t2.c FROM t3 RIGHT JOIN t2 ON t2.a = t3.b) AS t WHERE t.b <> 0 AND t.c = t1.a; b c a -8 c c INSERT INTO t3 VALUES (100), (200); EXPLAIN EXTENDED SELECT t.b, t.c, t1.a @@ -1708,7 +1706,7 @@ SELECT t.b, t.c, t1.a FROM t1, (SELECT t2.b, t2.c FROM t3 RIGHT JOIN t2 ON t2.a = t3.b) AS t WHERE t.b AND t.c = t1.a; b c a -8 c c +NULL NULL c EXPLAIN EXTENDED SELECT t.b, t.c, t1.a FROM t1, (SELECT t2.b, t2.c FROM t3 RIGHT JOIN t2 ON t2.a = t3.b) AS t @@ -1723,7 +1721,7 @@ SELECT t.b, t.c, t1.a FROM t1, (SELECT t2.b, t2.c FROM t3 RIGHT JOIN t2 ON t2.a = t3.b) AS t WHERE t.b <> 0 AND t.c = t1.a; b c a -8 c c +NULL NULL c SET optimizer_switch=@save_optimizer_switch; DROP TABLE t1,t2,t3; # diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 56598583bb6..fc60d70317e 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -4485,6 +4485,39 @@ a 1 drop view v2,v1; drop table t1; +# +# MDEV-486 LP BUG#1010116 Incorrect query results in +# view and derived tables +# +SELECT +`Derived1`.`id`, +`Derived2`.`Val1` +FROM (select 30631 as `id`) AS `Derived1` LEFT OUTER JOIN (SELECT +2 as `id`, +1 AS `Val1` +FROM (select 30631 as `id`) AS `Derived3`) AS `Derived2` ON `Derived1`.`id` = `Derived2`.`id`; +id Val1 +30631 NULL +create table t1 ( id int ); +insert into t1 values (30631); +create table t2 ( id int ); +insert into t2 values (30631); +create algorithm=MERGE view v2 as select 2 as id, 1 as val1 from t2; +select t1.*, v2.* from t1 left join v2 on t1.id = v2.id; +id id val1 +30631 NULL NULL +drop view v2; +drop table t1,t2; +create table t1 ( id int ); +insert into t1 values (30631); +create table t2 ( id int ); +insert into t2 values (30631); +create algorithm=MERGE view v2 as select 2 as id, id is null as bbb, id as iddqd, 1 as val1 from t2; +select t1.*, v2.* from t1 left join v2 on t1.id = v2.id; +id id bbb iddqd val1 +30631 NULL NULL NULL NULL +drop view v2; +drop table t1,t2; # ----------------------------------------------------------------- # -- End of 5.3 tests. # ----------------------------------------------------------------- diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 6f11d6909ea..bd3b485034d 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -4433,6 +4433,36 @@ select * from t1; drop view v2,v1; drop table t1; +--echo # +--echo # MDEV-486 LP BUG#1010116 Incorrect query results in +--echo # view and derived tables +--echo # + +SELECT +`Derived1`.`id`, +`Derived2`.`Val1` +FROM (select 30631 as `id`) AS `Derived1` LEFT OUTER JOIN (SELECT +2 as `id`, +1 AS `Val1` +FROM (select 30631 as `id`) AS `Derived3`) AS `Derived2` ON `Derived1`.`id` = `Derived2`.`id`; + +create table t1 ( id int ); +insert into t1 values (30631); +create table t2 ( id int ); +insert into t2 values (30631); +create algorithm=MERGE view v2 as select 2 as id, 1 as val1 from t2; +select t1.*, v2.* from t1 left join v2 on t1.id = v2.id; +drop view v2; +drop table t1,t2; + +create table t1 ( id int ); +insert into t1 values (30631); +create table t2 ( id int ); +insert into t2 values (30631); +create algorithm=MERGE view v2 as select 2 as id, id is null as bbb, id as iddqd, 1 as val1 from t2; +select t1.*, v2.* from t1 left join v2 on t1.id = v2.id; +drop view v2; +drop table t1,t2; --echo # ----------------------------------------------------------------- --echo # -- End of 5.3 tests. --echo # ----------------------------------------------------------------- diff --git a/sql/item.cc b/sql/item.cc index bb6360f3f73..18a86aa2d1a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7339,6 +7339,7 @@ Item* Item_cache_wrapper::get_tmp_table_item(THD *thd_arg) bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) { + DBUG_ASSERT(1); /* view fild reference must be defined */ DBUG_ASSERT(*ref); /* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */ diff --git a/sql/item.h b/sql/item.h index 055225a79d7..5dde9cf9a3f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2925,20 +2925,29 @@ class Item_direct_view_ref :public Item_direct_ref { Item_equal *item_equal; TABLE_LIST *view; + TABLE *null_ref_table; + + bool check_null_ref() + { + if (null_ref_table == NULL) + { + null_ref_table= view->get_real_join_table(); + } + if (null_ref_table->null_row) + { + null_value= 1; + return TRUE; + } + return FALSE; + } public: Item_direct_view_ref(Name_resolution_context *context_arg, Item **item, const char *table_name_arg, const char *field_name_arg, TABLE_LIST *view_arg) :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg), - item_equal(0), view(view_arg) {} - /* Constructor need to process subselect with temporary tables (see Item) */ - Item_direct_view_ref(THD *thd, Item_direct_ref *item) - :Item_direct_ref(thd, item), item_equal(0) {} - Item_direct_view_ref(TABLE_LIST *view_arg, Item **item, - const char *field_name_arg) - :Item_direct_ref(view_arg, item, field_name_arg), item_equal(0) - {} + item_equal(0), view(view_arg), + null_ref_table(NULL) {} bool fix_fields(THD *, Item **); bool eq(const Item *item, bool binary_cmp) const; @@ -2969,6 +2978,84 @@ public: view_arg->view_used_tables|= (*ref)->used_tables(); return 0; } + void save_val(Field *to) + { + if (check_null_ref()) + to->set_null(); + else + Item_direct_ref::save_val(to); + } + double val_real() + { + if (check_null_ref()) + return 0; + else + return Item_direct_ref::val_real(); + } + longlong val_int() + { + if (check_null_ref()) + return 0; + else + return Item_direct_ref::val_int(); + } + String *val_str(String* tmp) + { + if (check_null_ref()) + return NULL; + else + return Item_direct_ref::val_str(tmp); + } + my_decimal *val_decimal(my_decimal *tmp) + { + if (check_null_ref()) + return NULL; + else + return Item_direct_ref::val_decimal(tmp); + } + bool val_bool() + { + if (check_null_ref()) + return 0; + else + return Item_direct_ref::val_bool(); + } + bool is_null() + { + if (check_null_ref()) + return 1; + else + return Item_direct_ref::is_null(); + } + bool get_date(MYSQL_TIME *ltime, uint fuzzydate) + { + if (check_null_ref()) + { + bzero((char*) ltime,sizeof(*ltime)); + return 1; + } + return Item_direct_ref::get_date(ltime, fuzzydate); + } + bool send(Protocol *protocol, String *buffer) + { + if (check_null_ref()) + return protocol->store_null(); + return Item_direct_ref::send(protocol, buffer); + } + void save_org_in_field(Field *field) + { + if (check_null_ref()) + field->set_null(); + else + Item_direct_ref::save_val(field); + } + void save_in_result_field(bool no_conversions) + { + if (check_null_ref()) + result_field->set_null(); + else + Item_direct_ref::save_in_result_field(no_conversions); + } }; diff --git a/sql/table.cc b/sql/table.cc index 2eb7eca6fb0..2be94c55205 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4441,6 +4441,28 @@ void TABLE_LIST::set_check_materialized() } } +TABLE *TABLE_LIST::get_real_join_table() +{ + TABLE_LIST *tbl= this; + while (tbl->table == NULL || tbl->table->reginfo.join_tab == NULL) + { + if (tbl->view == NULL && tbl->derived == NULL) + break; + /* we do not support merging of union yet */ + DBUG_ASSERT(tbl->view == NULL || + tbl->view->select_lex.next_select() == NULL); + DBUG_ASSERT(tbl->derived == NULL || + tbl->derived->first_select()->next_select() == NULL); + + if (tbl->table) + table= tbl->table; + tbl= (tbl->view != NULL ? + tbl->view->select_lex.get_table_list() : + tbl->derived->first_select()->get_table_list()); + } + return tbl->table; +} + Natural_join_column::Natural_join_column(Field_translator *field_param, TABLE_LIST *tab) diff --git a/sql/table.h b/sql/table.h index 6ce6c83c604..8ce73162aaf 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1671,6 +1671,7 @@ struct TABLE_LIST TABLE_LIST *find_underlying_table(TABLE *table); TABLE_LIST *first_leaf_for_name_resolution(); TABLE_LIST *last_leaf_for_name_resolution(); + TABLE *get_real_join_table(); bool is_leaf_for_name_resolution(); inline TABLE_LIST *top_table() { return belong_to_view ? belong_to_view : this; } From a0efc4bd7779e3fe9ef664a2254e8f9c5868afeb Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 6 Sep 2012 10:08:09 +0200 Subject: [PATCH 20/21] MDEV-510 assert triggered by ./mtr --ps-protocol rpl_mdev382 The DELETE for emplicitly emptied MEMORY tables should be written directly to binlog. --- mysql-test/suite/rpl/r/rpl_mdev382.result | 4 +-- sql/sql_base.cc | 38 ++++++++--------------- 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_mdev382.result b/mysql-test/suite/rpl/r/rpl_mdev382.result index b564dd8401e..bbc57006d0d 100644 --- a/mysql-test/suite/rpl/r/rpl_mdev382.result +++ b/mysql-test/suite/rpl/r/rpl_mdev382.result @@ -321,9 +321,7 @@ a` # The DELETE statement should be correctly quoted show binlog events in 'master-bin.000002' from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000002 # Query # # BEGIN -master-bin.000002 # Query # # use `test`; DELETE FROM `db1``; select 'oops!'`.`t``1` -master-bin.000002 # Query # # COMMIT +master-bin.000002 # Query # # DELETE FROM `db1``; select 'oops!'`.`t``1` include/start_slave.inc # The table should be empty on the slave also. SELECT * FROM `db1``; select 'oops!'`.`t``1`; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 52569f193aa..a1e00b74a47 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3893,34 +3893,22 @@ static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry) { char query_buf[2*FN_REFLEN + 21]; String query(query_buf, sizeof(query_buf), system_charset_info); + query.length(0); - if (query.ptr()) - { - /* this DELETE FROM is needed even with row-based binlogging */ - query.append("DELETE FROM "); - append_identifier(thd, &query, share->db.str, share->db.length); - query.append("."); - append_identifier(thd, &query, share->table_name.str, + query.append("DELETE FROM "); + append_identifier(thd, &query, share->db.str, share->db.length); + query.append("."); + append_identifier(thd, &query, share->table_name.str, share->table_name.length); - int errcode= query_error_code(thd, TRUE); - if (thd->binlog_query(THD::STMT_QUERY_TYPE, - query.ptr(), query.length(), - FALSE, FALSE, FALSE, errcode)) - return TRUE; - } - else - { - /* - As replication is maybe going to be corrupted, we need to warn the - DBA on top of warning the client (which will automatically be done - because of MYF(MY_WME) in my_malloc() above). - */ - sql_print_error("When opening HEAP table, could not allocate memory " - "to write 'DELETE FROM %`s.%`s' to the binary log", - share->db.str, share->table_name.str); - delete entry->triggers; + + /* + we bypass thd->binlog_query() here, + as it does a lot of extra work, that is simply wrong in this case + */ + Query_log_event qinfo(thd, query.ptr(), query.length(), + FALSE, TRUE, TRUE, 0); + if (mysql_bin_log.write(&qinfo)) return TRUE; - } } } return FALSE; From 22de18ddcb97640f8f90c1c88d1dcd795ba1070f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 7 Sep 2012 09:17:31 +0300 Subject: [PATCH 21/21] Fix of MDEV-511. As far as we reopen tables so TABLE become invalid we should remove the pointer on cleanup(). --- sql/item.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sql/item.h b/sql/item.h index 9bcb913d5c5..3136bb00394 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3287,6 +3287,12 @@ public: else Item_direct_ref::save_in_result_field(no_conversions); } + + void cleanup() + { + null_ref_table= NULL; + Item_direct_ref::cleanup(); + } };