From 87eccd78a791ff3acfa00914254f0bf858a14aa4 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 13 Dec 2022 12:40:53 +0200 Subject: [PATCH 01/23] MDEV-30218: Incorrect optimization for rowid_filtering (Patch from Monty, slightly amended) Fix rowid filtering optimization in best_access_path(): == Ref access + rowid filtering == The cost computations compare #records and index-only scan cost (keyread_tmp) to find out the per-record advantage one will get if they skip reading full table record. The computations produce wrong result when: - the #records are "clipped down" with s->worst_seeks or thd->variables.max_seeks_for_key. keyread_tmp is not clipped this way so the numbers are not comparable. - access_factor is negative. This means index_only read is cheaper than non-index-only read. This patch makes the optimizer not to consider Rowid Filtering in such cases. The decision is logged in the Optimizer Trace using "rowid_filter_skipped" name. == Range access + rowid filtering == when considering to use Rowid Filter with range access, do multiply keyread_tmp by record_count. That way, it is comparable with the range access's estimate, which is multiplied by record_count. --- mysql-test/main/join_cache.result | 24 ++-- mysql-test/main/opt_trace.result | 11 ++ .../main/opt_trace_index_merge_innodb.result | 1 + mysql-test/main/range.result | 2 +- mysql-test/main/rowid_filter.result | 133 ++++-------------- mysql-test/main/rowid_filter_innodb.result | 102 ++++---------- .../main/rowid_filter_innodb_debug.result | 36 ----- .../main/rowid_filter_innodb_debug.test | 52 ------- mysql-test/main/selectivity.result | 2 +- mysql-test/main/selectivity_innodb.result | 2 +- sql/sql_select.cc | 87 ++++++++---- 11 files changed, 146 insertions(+), 306 deletions(-) diff --git a/mysql-test/main/join_cache.result b/mysql-test/main/join_cache.result index f337ab6509b..1837576e719 100644 --- a/mysql-test/main/join_cache.result +++ b/mysql-test/main/join_cache.result @@ -853,7 +853,7 @@ LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE City ALL Country NULL NULL NULL 4079 Using where 1 SIMPLE Country hash_ALL PRIMARY #hash#PRIMARY 3 world.City.Country 239 Using where; Using join buffer (flat, BNLH join) -1 SIMPLE CountryLanguage hash_ALL PRIMARY,Percentage #hash#PRIMARY 3 world.City.Country 984 Using where; Using join buffer (flat, BNLH join) +1 SIMPLE CountryLanguage hash_ALL|filter PRIMARY,Percentage #hash#PRIMARY|Percentage 3|4 world.City.Country 984 (19%) Using where; Using join buffer (flat, BNLH join); Using rowid filter SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND @@ -1053,7 +1053,7 @@ LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE City ALL Country NULL NULL NULL 4079 Using where 1 SIMPLE Country hash_ALL PRIMARY #hash#PRIMARY 3 world.City.Country 239 Using where; Using join buffer (flat, BNLH join) -1 SIMPLE CountryLanguage hash_ALL PRIMARY,Percentage #hash#PRIMARY 3 world.City.Country 984 Using where; Using join buffer (incremental, BNLH join) +1 SIMPLE CountryLanguage hash_ALL|filter PRIMARY,Percentage #hash#PRIMARY|Percentage 3|4 world.City.Country 984 (19%) Using where; Using join buffer (incremental, BNLH join); Using rowid filter SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND @@ -1312,7 +1312,7 @@ LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE City ALL Country NULL NULL NULL 4079 Using where 1 SIMPLE Country eq_ref PRIMARY PRIMARY 3 world.City.Country 1 Using where; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -1 SIMPLE CountryLanguage ref PRIMARY,Percentage PRIMARY 3 world.City.Country 4 Using index condition(BKA); Using where; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +1 SIMPLE CountryLanguage ref|filter PRIMARY,Percentage PRIMARY|Percentage 3|4 world.City.Country 4 (19%) Using index condition(BKA); Using where; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan; Using rowid filter SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND @@ -1509,7 +1509,7 @@ LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE City ALL Country NULL NULL NULL 4079 Using where 1 SIMPLE Country eq_ref PRIMARY PRIMARY 3 world.City.Country 1 Using where; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -1 SIMPLE CountryLanguage ref PRIMARY,Percentage PRIMARY 3 world.City.Country 4 Using index condition(BKA); Using where; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan +1 SIMPLE CountryLanguage ref|filter PRIMARY,Percentage PRIMARY|Percentage 3|4 world.City.Country 4 (19%) Using index condition(BKA); Using where; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan; Using rowid filter SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND @@ -1706,7 +1706,7 @@ LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE City ALL Country NULL NULL NULL 4079 Using where 1 SIMPLE Country eq_ref PRIMARY PRIMARY 3 world.City.Country 1 Using where; Using join buffer (flat, BKAH join); Key-ordered Rowid-ordered scan -1 SIMPLE CountryLanguage ref PRIMARY,Percentage PRIMARY 3 world.City.Country 4 Using index condition(BKA); Using where; Using join buffer (flat, BKAH join); Key-ordered Rowid-ordered scan +1 SIMPLE CountryLanguage ref|filter PRIMARY,Percentage PRIMARY|Percentage 3|4 world.City.Country 4 (19%) Using index condition(BKA); Using where; Using join buffer (flat, BKAH join); Key-ordered Rowid-ordered scan; Using rowid filter SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND @@ -1903,7 +1903,7 @@ LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE City ALL Country NULL NULL NULL 4079 Using where 1 SIMPLE Country eq_ref PRIMARY PRIMARY 3 world.City.Country 1 Using where; Using join buffer (flat, BKAH join); Key-ordered Rowid-ordered scan -1 SIMPLE CountryLanguage ref PRIMARY,Percentage PRIMARY 3 world.City.Country 4 Using index condition(BKA); Using where; Using join buffer (incremental, BKAH join); Key-ordered Rowid-ordered scan +1 SIMPLE CountryLanguage ref|filter PRIMARY,Percentage PRIMARY|Percentage 3|4 world.City.Country 4 (19%) Using index condition(BKA); Using where; Using join buffer (incremental, BKAH join); Key-ordered Rowid-ordered scan; Using rowid filter SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND @@ -2104,7 +2104,7 @@ LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE City ALL Country NULL NULL NULL 4079 Using where 1 SIMPLE Country hash_ALL PRIMARY #hash#PRIMARY 3 world.City.Country 239 Using where; Using join buffer (flat, BNLH join) -1 SIMPLE CountryLanguage hash_ALL PRIMARY,Percentage #hash#PRIMARY 3 world.City.Country 984 Using where; Using join buffer (flat, BNLH join) +1 SIMPLE CountryLanguage hash_ALL|filter PRIMARY,Percentage #hash#PRIMARY|Percentage 3|4 world.City.Country 984 (19%) Using where; Using join buffer (flat, BNLH join); Using rowid filter SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND @@ -2208,7 +2208,7 @@ LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE City ALL Country NULL NULL NULL 4079 Using where 1 SIMPLE Country hash_ALL PRIMARY #hash#PRIMARY 3 world.City.Country 239 Using where; Using join buffer (flat, BNLH join) -1 SIMPLE CountryLanguage hash_ALL PRIMARY,Percentage #hash#PRIMARY 3 world.City.Country 984 Using where; Using join buffer (incremental, BNLH join) +1 SIMPLE CountryLanguage hash_ALL|filter PRIMARY,Percentage #hash#PRIMARY|Percentage 3|4 world.City.Country 984 (19%) Using where; Using join buffer (incremental, BNLH join); Using rowid filter SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND @@ -2312,7 +2312,7 @@ LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE City ALL Country NULL NULL NULL 4079 Using where 1 SIMPLE Country eq_ref PRIMARY PRIMARY 3 world.City.Country 1 Using where; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -1 SIMPLE CountryLanguage ref PRIMARY,Percentage PRIMARY 3 world.City.Country 4 Using index condition(BKA); Using where; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan +1 SIMPLE CountryLanguage ref|filter PRIMARY,Percentage PRIMARY|Percentage 3|4 world.City.Country 4 (19%) Using index condition(BKA); Using where; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan; Using rowid filter SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND @@ -2416,7 +2416,7 @@ LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE City ALL Country NULL NULL NULL 4079 Using where 1 SIMPLE Country eq_ref PRIMARY PRIMARY 3 world.City.Country 1 Using where; Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan -1 SIMPLE CountryLanguage ref PRIMARY,Percentage PRIMARY 3 world.City.Country 4 Using index condition(BKA); Using where; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan +1 SIMPLE CountryLanguage ref|filter PRIMARY,Percentage PRIMARY|Percentage 3|4 world.City.Country 4 (19%) Using index condition(BKA); Using where; Using join buffer (incremental, BKA join); Key-ordered Rowid-ordered scan; Using rowid filter SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND @@ -2520,7 +2520,7 @@ LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE City ALL Country NULL NULL NULL 4079 Using where 1 SIMPLE Country eq_ref PRIMARY PRIMARY 3 world.City.Country 1 Using where; Using join buffer (flat, BKAH join); Key-ordered Rowid-ordered scan -1 SIMPLE CountryLanguage ref PRIMARY,Percentage PRIMARY 3 world.City.Country 4 Using index condition(BKA); Using where; Using join buffer (flat, BKAH join); Key-ordered Rowid-ordered scan +1 SIMPLE CountryLanguage ref|filter PRIMARY,Percentage PRIMARY|Percentage 3|4 world.City.Country 4 (19%) Using index condition(BKA); Using where; Using join buffer (flat, BKAH join); Key-ordered Rowid-ordered scan; Using rowid filter SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND @@ -2624,7 +2624,7 @@ LENGTH(Language) < LENGTH(City.Name) - 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE City ALL Country NULL NULL NULL 4079 Using where 1 SIMPLE Country eq_ref PRIMARY PRIMARY 3 world.City.Country 1 Using where; Using join buffer (flat, BKAH join); Key-ordered Rowid-ordered scan -1 SIMPLE CountryLanguage ref PRIMARY,Percentage PRIMARY 3 world.City.Country 4 Using index condition(BKA); Using where; Using join buffer (incremental, BKAH join); Key-ordered Rowid-ordered scan +1 SIMPLE CountryLanguage ref|filter PRIMARY,Percentage PRIMARY|Percentage 3|4 world.City.Country 4 (19%) Using index condition(BKA); Using where; Using join buffer (incremental, BKAH join); Key-ordered Rowid-ordered scan; Using rowid filter SELECT City.Name, Country.Name, CountryLanguage.Language FROM City,Country,CountryLanguage WHERE City.Country=Country.Code AND diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result index f6e2140def6..79201d49474 100644 --- a/mysql-test/main/opt_trace.result +++ b/mysql-test/main/opt_trace.result @@ -1016,6 +1016,7 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b { "index": "a", "used_range_estimates": false, "cause": "not available", + "rowid_filter_skipped": "cost_factor <= 0", "rows": 1, "cost": 200, "chosen": true @@ -1072,6 +1073,7 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b { "index": "a", "used_range_estimates": false, "cause": "not available", + "rowid_filter_skipped": "cost_factor <= 0", "rows": 1, "cost": 200, "chosen": true @@ -2118,6 +2120,7 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 { "access_type": "ref", "index": "a_c", "used_range_estimates": true, + "rowid_filter_skipped": "worst/max seeks clipping", "rows": 180, "cost": 92, "chosen": true @@ -3343,6 +3346,7 @@ explain select * from t1 where pk = 2 and a=5 and b=1 { "access_type": "ref", "index": "pk", "used_range_estimates": true, + "rowid_filter_skipped": "cost_factor <= 0", "rows": 1, "cost": 2, "chosen": true @@ -3351,6 +3355,7 @@ explain select * from t1 where pk = 2 and a=5 and b=1 { "access_type": "ref", "index": "pk_a", "used_range_estimates": true, + "rowid_filter_skipped": "cost_factor <= 0", "rows": 1, "cost": 2, "chosen": false, @@ -3360,6 +3365,7 @@ explain select * from t1 where pk = 2 and a=5 and b=1 { "access_type": "ref", "index": "pk_a_b", "used_range_estimates": true, + "rowid_filter_skipped": "cost_factor <= 0", "rows": 1, "cost": 1.0043, "chosen": true @@ -3994,6 +4000,7 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 { "index": "a", "used_range_estimates": false, "cause": "not better than ref estimates", + "rowid_filter_skipped": "cost_factor <= 0", "rows": 1, "cost": 3.007, "chosen": true @@ -4049,6 +4056,7 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 { "index": "a", "used_range_estimates": false, "cause": "not better than ref estimates", + "rowid_filter_skipped": "worst/max seeks clipping", "rows": 2, "cost": 3.014, "chosen": true @@ -8145,6 +8153,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans')) "index": "b", "used_range_estimates": false, "cause": "not available", + "rowid_filter_skipped": "cost_factor <= 0", "rows": 1, "cost": 20, "chosen": true @@ -8370,6 +8379,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans')) "index": "a", "used_range_estimates": false, "cause": "not available", + "rowid_filter_skipped": "cost_factor <= 0", "rows": 1, "cost": 20, "chosen": true @@ -8445,6 +8455,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans')) "index": "a", "used_range_estimates": false, "cause": "not available", + "rowid_filter_skipped": "cost_factor <= 0", "rows": 1, "cost": 200, "chosen": true diff --git a/mysql-test/main/opt_trace_index_merge_innodb.result b/mysql-test/main/opt_trace_index_merge_innodb.result index 5786f741996..82f09dffa14 100644 --- a/mysql-test/main/opt_trace_index_merge_innodb.result +++ b/mysql-test/main/opt_trace_index_merge_innodb.result @@ -208,6 +208,7 @@ explain select * from t1 where pk1 != 0 and key1 = 1 { "access_type": "ref", "index": "key1", "used_range_estimates": true, + "rowid_filter_skipped": "cost_factor <= 0", "rows": 1, "cost": 2, "chosen": true diff --git a/mysql-test/main/range.result b/mysql-test/main/range.result index 0e728d76a3e..a3ce10fe38a 100644 --- a/mysql-test/main/range.result +++ b/mysql-test/main/range.result @@ -281,7 +281,7 @@ INSERT INTO t1 VALUES (33,5),(33,5),(33,5),(33,5),(34,5),(35,5); EXPLAIN SELECT * FROM t1 WHERE a IN(1,2) AND b=5; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref|filter a,b b|a 5|5 const 15 (5%) Using where; Using rowid filter +1 SIMPLE t1 range a,b a 5 NULL 2 Using index condition; Using where SELECT * FROM t1 WHERE a IN(1,2) AND b=5; a b DROP TABLE t1; diff --git a/mysql-test/main/rowid_filter.result b/mysql-test/main/rowid_filter.result index 0a7497f1055..2bfc5b1f20c 100644 --- a/mysql-test/main/rowid_filter.result +++ b/mysql-test/main/rowid_filter.result @@ -336,7 +336,7 @@ WHERE l_shipdate BETWEEN '1997-01-01' AND '1997-01-31' AND o_totalprice between 200000 and 230000; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE lineitem range PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate 4 NULL 98 Using index condition -1 SIMPLE orders eq_ref|filter PRIMARY,i_o_totalprice PRIMARY|i_o_totalprice 4|9 dbt3_s001.lineitem.l_orderkey 1 (5%) Using where; Using rowid filter +1 SIMPLE orders eq_ref PRIMARY,i_o_totalprice PRIMARY 4 dbt3_s001.lineitem.l_orderkey 1 Using where set statement optimizer_switch='rowid_filter=on' for EXPLAIN FORMAT=JSON SELECT o_orderkey, l_linenumber, l_shipdate, o_totalprice FROM orders JOIN lineitem ON o_orderkey=l_orderkey WHERE l_shipdate BETWEEN '1997-01-01' AND '1997-01-31' AND @@ -369,14 +369,6 @@ EXPLAIN "key_length": "4", "used_key_parts": ["o_orderkey"], "ref": ["dbt3_s001.lineitem.l_orderkey"], - "rowid_filter": { - "range": { - "key": "i_o_totalprice", - "used_key_parts": ["o_totalprice"] - }, - "rows": 69, - "selectivity_pct": 4.6 - }, "rows": 1, "filtered": 4.6, "attached_condition": "orders.o_totalprice between 200000 and 230000" @@ -389,7 +381,7 @@ WHERE l_shipdate BETWEEN '1997-01-01' AND '1997-01-31' AND o_totalprice between 200000 and 230000; id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra 1 SIMPLE lineitem range PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate 4 NULL 98 98.00 100.00 100.00 Using index condition -1 SIMPLE orders eq_ref|filter PRIMARY,i_o_totalprice PRIMARY|i_o_totalprice 4|9 dbt3_s001.lineitem.l_orderkey 1 (5%) 0.11 (10%) 4.60 100.00 Using where; Using rowid filter +1 SIMPLE orders eq_ref PRIMARY,i_o_totalprice PRIMARY 4 dbt3_s001.lineitem.l_orderkey 1 1.00 4.60 11.22 Using where set statement optimizer_switch='rowid_filter=on' for ANALYZE FORMAT=JSON SELECT o_orderkey, l_linenumber, l_shipdate, o_totalprice FROM orders JOIN lineitem ON o_orderkey=l_orderkey WHERE l_shipdate BETWEEN '1997-01-01' AND '1997-01-31' AND @@ -428,25 +420,12 @@ ANALYZE "key_length": "4", "used_key_parts": ["o_orderkey"], "ref": ["dbt3_s001.lineitem.l_orderkey"], - "rowid_filter": { - "range": { - "key": "i_o_totalprice", - "used_key_parts": ["o_totalprice"] - }, - "rows": 69, - "selectivity_pct": 4.6, - "r_rows": 71, - "r_lookups": 96, - "r_selectivity_pct": 10.417, - "r_buffer_size": "REPLACED", - "r_filling_time_ms": "REPLACED" - }, "r_loops": 98, "rows": 1, - "r_rows": 0.1122, + "r_rows": 1, "r_total_time_ms": "REPLACED", "filtered": 4.6, - "r_filtered": 100, + "r_filtered": 11.224, "attached_condition": "orders.o_totalprice between 200000 and 230000" } } @@ -590,7 +569,7 @@ l_quantity > 45 AND o_totalprice between 180000 and 230000; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE lineitem range|filter PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity,i_l_quantity i_l_shipdate|i_l_quantity 4|9 NULL 509 (12%) Using index condition; Using where; Using rowid filter -1 SIMPLE orders eq_ref|filter PRIMARY,i_o_totalprice PRIMARY|i_o_totalprice 4|9 dbt3_s001.lineitem.l_orderkey 1 (9%) Using where; Using rowid filter +1 SIMPLE orders eq_ref PRIMARY,i_o_totalprice PRIMARY 4 dbt3_s001.lineitem.l_orderkey 1 Using where set statement optimizer_switch='rowid_filter=on' for EXPLAIN FORMAT=JSON SELECT o_orderkey, l_linenumber, l_shipdate, l_quantity, o_totalprice FROM orders JOIN lineitem ON o_orderkey=l_orderkey WHERE l_shipdate BETWEEN '1997-01-01' AND '1997-06-30' AND @@ -634,14 +613,6 @@ EXPLAIN "key_length": "4", "used_key_parts": ["o_orderkey"], "ref": ["dbt3_s001.lineitem.l_orderkey"], - "rowid_filter": { - "range": { - "key": "i_o_totalprice", - "used_key_parts": ["o_totalprice"] - }, - "rows": 139, - "selectivity_pct": 9.2667 - }, "rows": 1, "filtered": 9.2667, "attached_condition": "orders.o_totalprice between 180000 and 230000" @@ -655,7 +626,7 @@ l_quantity > 45 AND o_totalprice between 180000 and 230000; id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra 1 SIMPLE lineitem range|filter PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity,i_l_quantity i_l_shipdate|i_l_quantity 4|9 NULL 509 (12%) 60.00 (11%) 11.69 100.00 Using index condition; Using where; Using rowid filter -1 SIMPLE orders eq_ref|filter PRIMARY,i_o_totalprice PRIMARY|i_o_totalprice 4|9 dbt3_s001.lineitem.l_orderkey 1 (9%) 0.27 (25%) 9.27 100.00 Using where; Using rowid filter +1 SIMPLE orders eq_ref PRIMARY,i_o_totalprice PRIMARY 4 dbt3_s001.lineitem.l_orderkey 1 1.00 9.27 26.67 Using where set statement optimizer_switch='rowid_filter=on' for ANALYZE FORMAT=JSON SELECT o_orderkey, l_linenumber, l_shipdate, l_quantity, o_totalprice FROM orders JOIN lineitem ON o_orderkey=l_orderkey WHERE l_shipdate BETWEEN '1997-01-01' AND '1997-06-30' AND @@ -710,25 +681,12 @@ ANALYZE "key_length": "4", "used_key_parts": ["o_orderkey"], "ref": ["dbt3_s001.lineitem.l_orderkey"], - "rowid_filter": { - "range": { - "key": "i_o_totalprice", - "used_key_parts": ["o_totalprice"] - }, - "rows": 139, - "selectivity_pct": 9.2667, - "r_rows": 144, - "r_lookups": 59, - "r_selectivity_pct": 25.424, - "r_buffer_size": "REPLACED", - "r_filling_time_ms": "REPLACED" - }, "r_loops": 60, "rows": 1, - "r_rows": 0.2667, + "r_rows": 1, "r_total_time_ms": "REPLACED", "filtered": 9.2667, - "r_filtered": 100, + "r_filtered": 26.667, "attached_condition": "orders.o_totalprice between 180000 and 230000" } } @@ -2072,7 +2030,7 @@ EXPLAIN EXTENDED SELECT * FROM t1 INNER JOIN t2 ON ( pk1+1 = pk2+2 AND a1 = a2 ) WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 ); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 101 100.00 Using where -1 PRIMARY t1 ref|filter a1,b1 a1|b1 5|4 test.t2.a2 36 (29%) 28.75 Using where; Using rowid filter +1 PRIMARY t1 ref a1,b1 a1 5 test.t2.a2 36 28.75 Using where 2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 1 100.00 Using index condition Warnings: Note 1003 /* select#1 */ select `test`.`t1`.`pk1` AS `pk1`,`test`.`t1`.`a1` AS `a1`,`test`.`t1`.`b1` AS `b1`,`test`.`t2`.`pk2` AS `pk2`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`b2` AS `b2` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`a1` = `test`.`t2`.`a2` and `test`.`t1`.`b1` <= (/* select#2 */ select max(`test`.`t2`.`b2`) from `test`.`t2` where `test`.`t2`.`pk2` <= 1) and `test`.`t1`.`pk1` + 1 = `test`.`t2`.`pk2` + 2 @@ -2097,14 +2055,6 @@ EXPLAIN "key_length": "5", "used_key_parts": ["a1"], "ref": ["test.t2.a2"], - "rowid_filter": { - "range": { - "key": "b1", - "used_key_parts": ["b1"] - }, - "rows": 115, - "selectivity_pct": 28.75 - }, "rows": 36, "filtered": 28.75, "attached_condition": "t1.b1 <= (subquery#2) and t1.pk1 + 1 = t2.pk2 + 2" @@ -2187,7 +2137,7 @@ test.t1 analyze status OK explain SELECT * FROM t1 WHERE a > 0 AND b=0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref|filter a,b b|a 5|5 const 151 (17%) Using where; Using rowid filter +1 SIMPLE t1 ref a,b b 5 const 151 Using where SELECT * FROM t1 WHERE a > 0 AND b=0; a b 1 0 @@ -2522,32 +2472,19 @@ ANALYZE "r_total_time_ms": "REPLACED", "table": { "table_name": "t1", - "access_type": "ref", + "access_type": "range", "possible_keys": ["idx1", "idx2"], - "key": "idx2", - "key_length": "5", - "used_key_parts": ["fl2"], - "ref": ["const"], - "rowid_filter": { - "range": { - "key": "idx1", - "used_key_parts": ["nm"] - }, - "rows": 44, - "selectivity_pct": 0.44, - "r_rows": 44, - "r_lookups": 1000, - "r_selectivity_pct": 0, - "r_buffer_size": "REPLACED", - "r_filling_time_ms": "REPLACED" - }, + "key": "idx1", + "key_length": "35", + "used_key_parts": ["nm"], "r_loops": 1, - "rows": 921, - "r_rows": 0, + "rows": 44, + "r_rows": 44, "r_total_time_ms": "REPLACED", - "filtered": 0.44, - "r_filtered": 100, - "attached_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'" + "filtered": 9.21, + "r_filtered": 0, + "index_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'", + "attached_condition": "t1.fl2 = 0" } } } @@ -2580,31 +2517,19 @@ ANALYZE "r_total_time_ms": "REPLACED", "table": { "table_name": "t1", - "access_type": "ref", + "access_type": "range", "possible_keys": ["idx1", "idx2"], - "key": "idx2", - "key_length": "5", - "used_key_parts": ["fl2"], - "ref": ["const"], - "rowid_filter": { - "range": { - "key": "idx1", - "used_key_parts": ["nm"] - }, - "rows": 44, - "selectivity_pct": 0.44, - "r_rows": 0, - "r_lookups": 0, - "r_selectivity_pct": 0, - "r_buffer_size": "REPLACED", - "r_filling_time_ms": "REPLACED" - }, + "key": "idx1", + "key_length": "35", + "used_key_parts": ["nm"], "r_loops": 1, - "rows": 911, + "rows": 44, "r_rows": 0, - "filtered": 0.44, + "r_total_time_ms": "REPLACED", + "filtered": 9.11, "r_filtered": 100, - "attached_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'" + "index_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'", + "attached_condition": "t1.fl2 = 0" } } } diff --git a/mysql-test/main/rowid_filter_innodb.result b/mysql-test/main/rowid_filter_innodb.result index d7f1fe4a0d3..1bf63d9a378 100644 --- a/mysql-test/main/rowid_filter_innodb.result +++ b/mysql-test/main/rowid_filter_innodb.result @@ -1997,7 +1997,7 @@ EXPLAIN EXTENDED SELECT * FROM t1 INNER JOIN t2 ON ( pk1+1 = pk2+2 AND a1 = a2 ) WHERE b1 <= ( SELECT MAX(b2) FROM t2 WHERE pk2 <= 1 ); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 101 100.00 Using where -1 PRIMARY t1 ref|filter a1,b1 a1|b1 5|4 test.t2.a2 36 (29%) 28.75 Using where; Using rowid filter +1 PRIMARY t1 ref a1,b1 a1 5 test.t2.a2 36 28.75 Using where 2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 1 100.00 Using index condition Warnings: Note 1003 /* select#1 */ select `test`.`t1`.`pk1` AS `pk1`,`test`.`t1`.`a1` AS `a1`,`test`.`t1`.`b1` AS `b1`,`test`.`t2`.`pk2` AS `pk2`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`b2` AS `b2` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`a1` = `test`.`t2`.`a2` and `test`.`t1`.`b1` <= (/* select#2 */ select max(`test`.`t2`.`b2`) from `test`.`t2` where `test`.`t2`.`pk2` <= 1) and `test`.`t1`.`pk1` + 1 = `test`.`t2`.`pk2` + 2 @@ -2022,14 +2022,6 @@ EXPLAIN "key_length": "5", "used_key_parts": ["a1"], "ref": ["test.t2.a2"], - "rowid_filter": { - "range": { - "key": "b1", - "used_key_parts": ["b1"] - }, - "rows": 115, - "selectivity_pct": 28.75 - }, "rows": 36, "filtered": 28.75, "attached_condition": "t1.b1 <= (subquery#2) and t1.pk1 + 1 = t2.pk2 + 2" @@ -2112,7 +2104,7 @@ test.t1 analyze status OK explain SELECT * FROM t1 WHERE a > 0 AND b=0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref|filter a,b b|a 5|5 const 128 (14%) Using where; Using rowid filter +1 SIMPLE t1 ref a,b b 5 const 128 Using where SELECT * FROM t1 WHERE a > 0 AND b=0; a b 1 0 @@ -2447,32 +2439,19 @@ ANALYZE "r_total_time_ms": "REPLACED", "table": { "table_name": "t1", - "access_type": "ref", + "access_type": "range", "possible_keys": ["idx1", "idx2"], - "key": "idx2", - "key_length": "5", - "used_key_parts": ["fl2"], - "ref": ["const"], - "rowid_filter": { - "range": { - "key": "idx1", - "used_key_parts": ["nm"] - }, - "rows": 44, - "selectivity_pct": 0.44, - "r_rows": 44, - "r_lookups": 1000, - "r_selectivity_pct": 0, - "r_buffer_size": "REPLACED", - "r_filling_time_ms": "REPLACED" - }, + "key": "idx1", + "key_length": "35", + "used_key_parts": ["nm"], "r_loops": 1, - "rows": 921, - "r_rows": 0, + "rows": 44, + "r_rows": 44, "r_total_time_ms": "REPLACED", - "filtered": 0.44, - "r_filtered": 100, - "attached_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'" + "filtered": 9.21, + "r_filtered": 0, + "index_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'", + "attached_condition": "t1.fl2 = 0" } } } @@ -2505,31 +2484,19 @@ ANALYZE "r_total_time_ms": "REPLACED", "table": { "table_name": "t1", - "access_type": "ref", + "access_type": "range", "possible_keys": ["idx1", "idx2"], - "key": "idx2", - "key_length": "5", - "used_key_parts": ["fl2"], - "ref": ["const"], - "rowid_filter": { - "range": { - "key": "idx1", - "used_key_parts": ["nm"] - }, - "rows": 44, - "selectivity_pct": 0.44, - "r_rows": 0, - "r_lookups": 0, - "r_selectivity_pct": 0, - "r_buffer_size": "REPLACED", - "r_filling_time_ms": "REPLACED" - }, + "key": "idx1", + "key_length": "35", + "used_key_parts": ["nm"], "r_loops": 1, - "rows": 911, + "rows": 44, "r_rows": 0, - "filtered": 0.44, + "r_total_time_ms": "REPLACED", + "filtered": 9.11, "r_filtered": 100, - "attached_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'" + "index_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'", + "attached_condition": "t1.fl2 = 0" } } } @@ -2704,7 +2671,7 @@ count(*) 5 explain extended select count(*) from t1 where a between 21 and 30 and b=2; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 ref|filter b,a b|a 5|5 const 24 (10%) 9.60 Using where; Using rowid filter +1 SIMPLE t1 ref b,a b 5 const 24 9.60 Using where Warnings: Note 1003 select count(0) AS `count(*)` from `test`.`t1` where `test`.`t1`.`b` = 2 and `test`.`t1`.`a` between 21 and 30 select * from t1 where a between 21 and 30 and b=2; @@ -3166,7 +3133,7 @@ WHERE 1 = 1 AND domain = 'www.mailhost.i-dev.fr' AND timestamp >= DATE_ADD('2017-01-30 08:24:51', INTERVAL -1 MONTH) ORDER BY timestamp DESC; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 ref|filter ixEventWhoisDomainDomain,ixEventWhoisDomainTimestamp ixEventWhoisDomainDomain|ixEventWhoisDomainTimestamp 98|4 const 40 (33%) 33.33 Using index condition; Using where; Using filesort; Using rowid filter +1 SIMPLE t1 ref ixEventWhoisDomainDomain,ixEventWhoisDomainTimestamp ixEventWhoisDomainDomain 98 const 40 33.33 Using index condition; Using where; Using filesort Warnings: Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`domain` AS `domain`,`test`.`t1`.`registrant_name` AS `registrant_name`,`test`.`t1`.`registrant_organization` AS `registrant_organization`,`test`.`t1`.`registrant_street1` AS `registrant_street1`,`test`.`t1`.`registrant_street2` AS `registrant_street2`,`test`.`t1`.`registrant_street3` AS `registrant_street3`,`test`.`t1`.`registrant_street4` AS `registrant_street4`,`test`.`t1`.`registrant_street5` AS `registrant_street5`,`test`.`t1`.`registrant_city` AS `registrant_city`,`test`.`t1`.`registrant_postal_code` AS `registrant_postal_code`,`test`.`t1`.`registrant_country` AS `registrant_country`,`test`.`t1`.`registrant_email` AS `registrant_email`,`test`.`t1`.`registrant_telephone` AS `registrant_telephone`,`test`.`t1`.`administrative_name` AS `administrative_name`,`test`.`t1`.`administrative_organization` AS `administrative_organization`,`test`.`t1`.`administrative_street1` AS `administrative_street1`,`test`.`t1`.`administrative_street2` AS `administrative_street2`,`test`.`t1`.`administrative_street3` AS `administrative_street3`,`test`.`t1`.`administrative_street4` AS `administrative_street4`,`test`.`t1`.`administrative_street5` AS `administrative_street5`,`test`.`t1`.`administrative_city` AS `administrative_city`,`test`.`t1`.`administrative_postal_code` AS `administrative_postal_code`,`test`.`t1`.`administrative_country` AS `administrative_country`,`test`.`t1`.`administrative_email` AS `administrative_email`,`test`.`t1`.`administrative_telephone` AS `administrative_telephone`,`test`.`t1`.`technical_name` AS `technical_name`,`test`.`t1`.`technical_organization` AS `technical_organization`,`test`.`t1`.`technical_street1` AS `technical_street1`,`test`.`t1`.`technical_street2` AS `technical_street2`,`test`.`t1`.`technical_street3` AS `technical_street3`,`test`.`t1`.`technical_street4` AS `technical_street4`,`test`.`t1`.`technical_street5` AS `technical_street5`,`test`.`t1`.`technical_city` AS `technical_city`,`test`.`t1`.`technical_postal_code` AS `technical_postal_code`,`test`.`t1`.`technical_country` AS `technical_country`,`test`.`t1`.`technical_email` AS `technical_email`,`test`.`t1`.`technical_telephone` AS `technical_telephone`,`test`.`t1`.`json` AS `json`,`test`.`t1`.`timestamp` AS `timestamp` from `test`.`t1` where `test`.`t1`.`domain` = 'www.mailhost.i-dev.fr' and `test`.`t1`.`timestamp` >= ('2017-01-30 08:24:51' + interval -1 month) order by `test`.`t1`.`timestamp` desc SET optimizer_switch=@save_optimizer_switch; @@ -3415,7 +3382,7 @@ fi.fh in (6311439873746261694,-397087483897438286, id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t index_merge PRIMARY,acli_rid,acli_tp acli_tp,acli_rid 2,767 NULL 2 100.00 Using intersect(acli_tp,acli_rid); Using where; Using index 1 SIMPLE a ref PRIMARY,acei_aclid acei_aclid 8 test.t.id 1 100.00 Using where -1 SIMPLE fi ref|filter filt_aceid,filt_fh filt_aceid|filt_fh 8|8 test.a.id 24 (14%) 14.46 Using where; Using rowid filter +1 SIMPLE fi ref filt_aceid,filt_fh filt_aceid 8 test.a.id 24 14.46 Using where Warnings: Note 1003 select `test`.`t`.`id` AS `id`,`test`.`fi`.`id` AS `id`,`test`.`fi`.`aceid` AS `aceid`,`test`.`fi`.`clid` AS `clid`,`test`.`fi`.`fh` AS `fh` from `test`.`acli` `t` join `test`.`acei` `a` join `test`.`filt` `fi` where `test`.`t`.`tp` = 121 and `test`.`a`.`atp` = 1 and `test`.`fi`.`aceid` = `test`.`a`.`id` and `test`.`a`.`aclid` = `test`.`t`.`id` and `test`.`t`.`rid` = 'B5FCC8C7111E4E3CBC21AAF5012F59C2' and `test`.`fi`.`fh` in (6311439873746261694,-397087483897438286,8518228073041491534,-5420422472375069774) set statement optimizer_switch='rowid_filter=on' for select t.id, fi.* @@ -3531,7 +3498,7 @@ fi.fh in (6311439873746261694,-397087483897438286, id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t index_merge PRIMARY,acli_rid,acli_tp acli_tp,acli_rid 2,767 NULL 2 100.00 Using intersect(acli_tp,acli_rid); Using where; Using index 1 SIMPLE a ref PRIMARY,acei_aclid acei_aclid 8 test.t.id 1 100.00 Using where; Using join buffer (flat, BKA join); Rowid-ordered scan -1 SIMPLE fi ref|filter filt_aceid,filt_fh filt_aceid|filt_fh 8|8 test.a.id 24 (14%) 14.46 Using where; Using join buffer (incremental, BKA join); Rowid-ordered scan; Using rowid filter +1 SIMPLE fi ref filt_aceid,filt_fh filt_aceid 8 test.a.id 24 14.46 Using where; Using join buffer (incremental, BKA join); Rowid-ordered scan Warnings: Note 1003 select `test`.`t`.`id` AS `id`,`test`.`fi`.`id` AS `id`,`test`.`fi`.`aceid` AS `aceid`,`test`.`fi`.`clid` AS `clid`,`test`.`fi`.`fh` AS `fh` from `test`.`acli` `t` join `test`.`acei` `a` join `test`.`filt` `fi` where `test`.`t`.`tp` = 121 and `test`.`a`.`atp` = 1 and `test`.`fi`.`aceid` = `test`.`a`.`id` and `test`.`a`.`aclid` = `test`.`t`.`id` and `test`.`t`.`rid` = 'B5FCC8C7111E4E3CBC21AAF5012F59C2' and `test`.`fi`.`fh` in (6311439873746261694,-397087483897438286,8518228073041491534,-5420422472375069774) set statement optimizer_switch='rowid_filter=on' for select t.id, fi.* @@ -3649,22 +3616,9 @@ ANALYZE "key_length": "8", "used_key_parts": ["aceid"], "ref": ["test.a.id"], - "rowid_filter": { - "range": { - "key": "filt_fh", - "used_key_parts": ["fh"] - }, - "rows": 81, - "selectivity_pct": 14.464, - "r_rows": 80, - "r_lookups": 80, - "r_selectivity_pct": 40, - "r_buffer_size": "REPLACED", - "r_filling_time_ms": "REPLACED" - }, "r_loops": 1, "rows": 24, - "r_rows": 32, + "r_rows": 80, "r_total_time_ms": "REPLACED", "filtered": 14.464, "r_filtered": 100 @@ -3674,7 +3628,7 @@ ANALYZE "join_type": "BKA", "mrr_type": "Rowid-ordered scan", "attached_condition": "fi.fh in (6311439873746261694,-397087483897438286,8518228073041491534,-5420422472375069774)", - "r_filtered": 100 + "r_filtered": 40 } } } @@ -3778,7 +3732,7 @@ WHERE t1.c1 NOT IN (SELECT t2.c1 FROM t2, t1 AS a1 WHERE t2.i1 = t1.pk AND t2.i1 BETWEEN 3 AND 5); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 60 100.00 Using where -2 DEPENDENT SUBQUERY t2 ref|filter c1,i1 c1|i1 3|5 func 38 (25%) 25.00 Using where; Full scan on NULL key; Using rowid filter +2 DEPENDENT SUBQUERY t2 ref c1,i1 i1 5 test.t1.pk 20 100.00 Using index condition; Using where 2 DEPENDENT SUBQUERY a1 ALL NULL NULL NULL NULL 60 100.00 Using join buffer (flat, BNL join) Warnings: Note 1276 Field or reference 'test.t1.pk' of SELECT #2 was resolved in SELECT #1 diff --git a/mysql-test/main/rowid_filter_innodb_debug.result b/mysql-test/main/rowid_filter_innodb_debug.result index 7741a949e7d..f82b29aa1e6 100644 --- a/mysql-test/main/rowid_filter_innodb_debug.result +++ b/mysql-test/main/rowid_filter_innodb_debug.result @@ -48,39 +48,3 @@ ERROR 70100: Query execution was interrupted set debug_sync='RESET'; drop table t2,t3; set default_storage_engine=default; -set @save_optimizer_switch= @@optimizer_switch; -set @save_use_stat_tables= @@use_stat_tables; -set @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; -set @@use_stat_tables=preferably; -set optimizer_use_condition_selectivity=2; -set optimizer_switch='rowid_filter=on'; -# -# MDEV-22761 KILL QUERY during rowid_filter, crashes -# (The smaller testcase) -# -CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4); -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -ANALYZE TABLE t1 PERSISTENT FOR ALL; -Table Op Msg_type Msg_text -test.t1 analyze status Engine-independent statistics collected -test.t1 analyze status OK -set debug_sync='handler_rowid_filter_check SIGNAL killme WAIT_FOR go'; -SELECT * FROM t1 WHERE a > 0 AND b=0; -connect con1, localhost, root,,; -set debug_sync='now WAIT_FOR killme'; -kill query @id; -set debug_sync='now SIGNAL go'; -connection default; -ERROR 70100: Query execution was interrupted -set debug_sync='RESET'; -disconnect con1; -drop table t1; -set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; -set @@optimizer_switch=@save_optimizer_switch; -set @@use_stat_tables=@save_use_stat_tables; diff --git a/mysql-test/main/rowid_filter_innodb_debug.test b/mysql-test/main/rowid_filter_innodb_debug.test index 6353ffa335e..60381658eaf 100644 --- a/mysql-test/main/rowid_filter_innodb_debug.test +++ b/mysql-test/main/rowid_filter_innodb_debug.test @@ -5,55 +5,3 @@ set default_storage_engine=innodb; --source include/rowid_filter_debug_kill.inc set default_storage_engine=default; ---source include/default_optimizer_switch.inc ---source include/count_sessions.inc - -set @save_optimizer_switch= @@optimizer_switch; -set @save_use_stat_tables= @@use_stat_tables; -set @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; - -set @@use_stat_tables=preferably; - -set optimizer_use_condition_selectivity=2; -set optimizer_switch='rowid_filter=on'; - ---echo # ---echo # MDEV-22761 KILL QUERY during rowid_filter, crashes ---echo # (The smaller testcase) ---echo # - -CREATE TABLE t1 (a INT, b INT, INDEX(a), INDEX(b)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (0,0),(1,0),(-1,1), (-2,1), (-2,3), (-3,4), (-2,4); -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; - -ANALYZE TABLE t1 PERSISTENT FOR ALL; - -let $ID= `SELECT @id := CONNECTION_ID()`; - -set debug_sync='handler_rowid_filter_check SIGNAL killme WAIT_FOR go'; -send SELECT * FROM t1 WHERE a > 0 AND b=0; - -connect (con1, localhost, root,,); -let $ignore= `SELECT @id := $ID`; -set debug_sync='now WAIT_FOR killme'; -kill query @id; -set debug_sync='now SIGNAL go'; - -connection default; ---error ER_QUERY_INTERRUPTED -reap; -set debug_sync='RESET'; - -disconnect con1; -drop table t1; - -set @@optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; -set @@optimizer_switch=@save_optimizer_switch; -set @@use_stat_tables=@save_use_stat_tables; - ---source include/wait_until_count_sessions.inc diff --git a/mysql-test/main/selectivity.result b/mysql-test/main/selectivity.result index 7e3202337ec..4113779a11e 100644 --- a/mysql-test/main/selectivity.result +++ b/mysql-test/main/selectivity.result @@ -1661,7 +1661,7 @@ Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` # gives selectivity data explain extended select * from t1 where a in (17,51,5) and b=2; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 ref|filter b,a b|a 5|5 const 58 (3%) 2.90 Using where; Using rowid filter +1 SIMPLE t1 ref b,a b 5 const 58 2.90 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where `test`.`t1`.`b` = 2 and `test`.`t1`.`a` in (17,51,5) drop table t1; diff --git a/mysql-test/main/selectivity_innodb.result b/mysql-test/main/selectivity_innodb.result index 2159989597a..6c6811f9754 100644 --- a/mysql-test/main/selectivity_innodb.result +++ b/mysql-test/main/selectivity_innodb.result @@ -1671,7 +1671,7 @@ Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` # gives selectivity data explain extended select * from t1 where a in (17,51,5) and b=2; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 ref|filter b,a b|a 5|5 const 59 (3%) 2.90 Using where; Using rowid filter +1 SIMPLE t1 ref b,a b 5 const 59 2.90 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where `test`.`t1`.`b` = 2 and `test`.`t1`.`a` in (17,51,5) drop table t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8e956e3075b..f313d571b5b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7887,7 +7887,9 @@ best_access_path(JOIN *join, } /* not ft_key */ if (records < DBL_MAX && - (found_part & 1)) // start_key->key can be used for index access + (found_part & 1) && // start_key->key can be used for index access + (s->table->file->index_flags(start_key->key,0,1) & + HA_DO_RANGE_FILTER_PUSHDOWN)) { double rows= record_count * records; @@ -7912,23 +7914,50 @@ best_access_path(JOIN *join, cost_of_fetching_1_row = tmp/rows cost_of_fetching_1_key_tuple = keyread_tmp/rows - Note that access_cost_factor may be greater than 1.0. In this case - we still can expect a gain of using rowid filter due to smaller number - of checks for conditions pushed to the joined table. + access_cost_factor is the gain we expect for using rowid filter. + An access_cost_factor of 1.0 means that keyread_tmp is 0 + (using key read is infinitely fast) and the gain for each row when + using filter is great. + An access_cost_factor if 0.0 means that using keyread has the + same cost as reading rows, so there is no gain to get with + filter. + access_cost_factor should never be bigger than 1.0 (if all + calculations are correct) as the cost of keyread should always be + smaller than the cost of fetching the same number of keys + rows. + access_cost_factor should also never be smaller than 0.0. + The one exception is if number of records is 1 (eq_ref), then + because we are comparing rows to cost of keyread_tmp, keyread_tmp + is higher by 1.0. This is a big that will be fixed in a later + version. + + If we have limited the cost (=tmp) of reading rows with 'worst_seek' + we cannot use filters as the cost calculation below would cause + tmp to become negative. The future resultion is to not limit + cost with worst_seek. + + We cannot use filter with JT_EQ_REF as in this case 'tmp' is + number of rows from prev_record_read() and keyread_tmp is 0. These + numbers are not usable with rowid filter code. */ - double rows_access_cost= MY_MIN(rows, s->worst_seeks); - double access_cost_factor= MY_MIN((rows_access_cost - keyread_tmp) / - rows, 1.0); - filter= - table->best_range_rowid_filter_for_partial_join(start_key->key, rows, - access_cost_factor); - if (filter) - { - filter->get_cmp_gain(rows); - tmp-= filter->get_adjusted_gain(rows) - filter->get_cmp_gain(rows); - DBUG_ASSERT(tmp >= 0); - trace_access_idx.add("rowid_filter_key", - s->table->key_info[filter->key_no].name); + double access_cost_factor= MY_MIN((rows - keyread_tmp) / rows, 1.0); + if (!(records < s->worst_seeks && + records <= thd->variables.max_seeks_for_key)) + trace_access_idx.add("rowid_filter_skipped", "worst/max seeks clipping"); + else if (access_cost_factor <= 0.0) + trace_access_idx.add("rowid_filter_skipped", "cost_factor <= 0"); + else if (type != JT_EQ_REF) + { + filter= + table->best_range_rowid_filter_for_partial_join(start_key->key, + rows, + access_cost_factor); + if (filter) + { + tmp-= filter->get_adjusted_gain(rows) - filter->get_cmp_gain(rows); + DBUG_ASSERT(tmp >= 0); + trace_access_idx.add("rowid_filter_key", + s->table->key_info[filter->key_no].name); + } } } trace_access_idx.add("rows", records).add("cost", tmp); @@ -8070,7 +8099,8 @@ best_access_path(JOIN *join, access (see first else-branch below), but we don't take it into account here for range/index_merge access. Find out why this is so. */ - double cmp_time= (s->found_records - rnd_records)/(double) TIME_FOR_COMPARE; + double cmp_time= ((s->found_records - rnd_records)/ + (double) TIME_FOR_COMPARE); tmp= COST_MULT(record_count, COST_ADD(s->quick->read_time, cmp_time)); @@ -8080,16 +8110,23 @@ best_access_path(JOIN *join, uint key_no= s->quick->index; /* See the comment concerning using rowid filter for with ref access */ - keyread_tmp= s->table->quick_index_only_costs[key_no]; + keyread_tmp= s->table->quick_index_only_costs[key_no] * record_count; double access_cost_factor= MY_MIN((rows - keyread_tmp) / rows, 1.0); - filter= - s->table->best_range_rowid_filter_for_partial_join(key_no, rows, - access_cost_factor); - if (filter) + if (access_cost_factor > 0.0) { - tmp-= filter->get_adjusted_gain(rows); - DBUG_ASSERT(tmp >= 0); + filter= + s->table-> + best_range_rowid_filter_for_partial_join(key_no, rows, + access_cost_factor); + if (filter) + { + tmp-= filter->get_adjusted_gain(rows); + DBUG_ASSERT(tmp >= 0); + } } + else + trace_access_scan.add("rowid_filter_skipped", "cost_factor <= 0"); + type= JT_RANGE; } else From acfaa0458725708aa58970a34072d08c184d7856 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Wed, 14 Dec 2022 01:17:44 +1100 Subject: [PATCH 02/23] MDEV-18591: mysql_install_db - pass --log-error to mysqld in install (#2363) Previously we parsed it out in mysql_install_db for use in the error message, but failed to pass it to mysqld in the bootstrap. Also match log_error as it might appear in the .cnf files. Thanks Michal Schorm for the test case. Reviewed by: Faustin Lammler --- scripts/mysql_install_db.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index 4c6376142cc..67d9f683b35 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -148,7 +148,9 @@ parse_arguments() --builddir=*) builddir=`parse_arg "$arg"` ;; --srcdir=*) srcdir=`parse_arg "$arg"` ;; --ldata=*|--datadir=*|--data=*) ldata=`parse_arg "$arg"` ;; - --log-error=*) + --log[-_]error=*) + # Keep in the arguments passed to the server + args="$args $arg" log_error=`parse_arg "$arg"` ;; # Note that the user will be passed to mysqld so that it runs # as 'user' (crucial e.g. if log-bin=/some_other_path/ From 697dbd15e0102f33fba1d1d6d9aa964b638f9534 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sun, 4 Dec 2022 10:47:31 +1100 Subject: [PATCH 03/23] MDEV-21187: log_slow_filter="" logs queries not using indexes Consistent with MDEV-4206 and empty log_slow_filter still means no explict filtering. Since 21518ab2e453 however the log_queries_not_using_indexes became stored in the same variable. As we need to test for the absense of log_queries_not_using_indexes the SERVER_QUERY_NO_INDEX USED part of log_slow_statement, the empty criteria resulted in an always true to log queries not using indexes if log_slow_filter was set to empty. Adjusted the log_slow.test for MDEV-4206 as slow_log_query has been global and session for a while and it was relying on the MDEV-21187 buggy behavior to detect a slow query. Reviewer: Monty --- mysql-test/main/log_slow.result | 22 ++++++++++++++++++++-- mysql-test/main/log_slow.test | 21 +++++++++++++++++++-- sql/sql_parse.cc | 2 +- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/log_slow.result b/mysql-test/main/log_slow.result index 31d52ff0323..6b9fddb7fb6 100644 --- a/mysql-test/main/log_slow.result +++ b/mysql-test/main/log_slow.result @@ -64,7 +64,7 @@ rows_affected int(11) NO NULL flush slow logs; set long_query_time=0.1; set log_slow_filter=''; -set global slow_query_log=1; +set slow_query_log=1; set global log_output='TABLE'; select sleep(0.5); sleep(0.5) @@ -73,7 +73,7 @@ select count(*) FROM mysql.slow_log; count(*) 1 set @@long_query_time=default; -set global slow_query_log= @org_slow_query_log; +set @@slow_query_log=default; set @@log_slow_filter=default; set @@log_slow_verbosity=default; set global log_output= default; @@ -115,3 +115,21 @@ Slow_queries_increment SET log_slow_filter=DEFAULT; SET @@long_query_time=default; SET GLOBAL slow_query_log= @org_slow_query_log; +# +# MDEV-21187: log_slow_filter="" logs queries not using indexes +# +flush status; +create table t (id int); +insert into t values (1),(4); +set log_slow_filter=''; +select * from t; +id +1 +4 +show session status like 'Slow_queries'; +Variable_name Value +Slow_queries 0 +drop table t; +# +# End of 10.3 tests +# diff --git a/mysql-test/main/log_slow.test b/mysql-test/main/log_slow.test index b51777d859e..d2e314cf667 100644 --- a/mysql-test/main/log_slow.test +++ b/mysql-test/main/log_slow.test @@ -50,14 +50,14 @@ flush slow logs; # MDEV-4206 (empty filter should be no filter) set long_query_time=0.1; set log_slow_filter=''; -set global slow_query_log=1; +set slow_query_log=1; set global log_output='TABLE'; select sleep(0.5); select count(*) FROM mysql.slow_log; # Reset used variables set @@long_query_time=default; -set global slow_query_log= @org_slow_query_log; +set @@slow_query_log=default; set @@log_slow_filter=default; set @@log_slow_verbosity=default; set global log_output= default; @@ -102,3 +102,20 @@ SET log_slow_filter=DEFAULT; SET @@long_query_time=default; SET GLOBAL slow_query_log= @org_slow_query_log; + +--echo # +--echo # MDEV-21187: log_slow_filter="" logs queries not using indexes +--echo # + +flush status; +create table t (id int); +insert into t values (1),(4); +set log_slow_filter=''; +select * from t; +show session status like 'Slow_queries'; + +drop table t; + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 385360168a1..cf316c8cc1c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2513,7 +2513,7 @@ void log_slow_statement(THD *thd) if ((thd->server_status & (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && !(thd->query_plan_flags & QPLAN_STATUS) && - !slow_filter_masked(thd, QPLAN_NOT_USING_INDEX)) + (thd->variables.log_slow_filter & QPLAN_NOT_USING_INDEX)) { thd->query_plan_flags|= QPLAN_NOT_USING_INDEX; /* We are always logging no index queries if enabled in filter */ From c562ccf796c085211461386510ea5f7a8137cb96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 15 Dec 2022 11:14:23 +0200 Subject: [PATCH 04/23] MDEV-30233 DROP DATABASE test fails: Directory not empty Some tests drop the default mtr database "test". This may fail due to the directory not being empty. InnoDB may not delete all tables immediately, due to the "background drop table queue" or its replacement in commit 1bd681c8b3c5213ce1f7976940a7dc38b48a0d39 (the purge of history would clean up after a DDL operation during which the server was killed). Let us try to avoid "drop database test" whenever it is easily possible. Where it is not, SET GLOBAL innodb_max_purge_lag_wait=0 will ensure that the replacement of the "background drop table queue" will have completed its job. --- mysql-test/main/cte_recursive.result | 5 +++-- mysql-test/main/cte_recursive.test | 5 +++-- mysql-test/main/information_schema.result | 5 +++-- mysql-test/main/information_schema.test | 5 +++-- mysql-test/main/mysqldump.result | 1 + mysql-test/main/mysqldump.test | 2 ++ mysql-test/main/view.result | 5 +++-- mysql-test/main/view.test | 5 +++-- mysql-test/suite/funcs_2/r/innodb_charset.result | 1 + mysql-test/suite/funcs_2/t/innodb_charset.test | 4 ++++ mysql-test/suite/innodb/r/information_schema_grants.result | 1 + mysql-test/suite/innodb/t/information_schema_grants.test | 2 ++ mysql-test/suite/innodb/t/innodb-mdev7046.test | 2 ++ 13 files changed, 31 insertions(+), 12 deletions(-) diff --git a/mysql-test/main/cte_recursive.result b/mysql-test/main/cte_recursive.result index 7f535fc3125..c4b66794e3d 100644 --- a/mysql-test/main/cte_recursive.result +++ b/mysql-test/main/cte_recursive.result @@ -4235,7 +4235,9 @@ drop table t1; # # MDEV-24019: query with recursive CTE when no default database is set # -drop database test; +create database dummy; +use dummy; +drop database dummy; with recursive a as (select 1 from dual union select * from a as r) select * from a; @@ -4274,7 +4276,6 @@ a 1 deallocate prepare stmt; drop database db1; -create database test; use test; # # MDEV-23406: query with mutually recursive CTEs when big_tables=1 diff --git a/mysql-test/main/cte_recursive.test b/mysql-test/main/cte_recursive.test index f5babc6cb65..270a5023d31 100644 --- a/mysql-test/main/cte_recursive.test +++ b/mysql-test/main/cte_recursive.test @@ -2729,7 +2729,9 @@ drop table t1; --echo # MDEV-24019: query with recursive CTE when no default database is set --echo # -drop database test; +create database dummy; +use dummy; +drop database dummy; let $q= with recursive a as @@ -2757,7 +2759,6 @@ deallocate prepare stmt; drop database db1; -create database test; use test; --echo # diff --git a/mysql-test/main/information_schema.result b/mysql-test/main/information_schema.result index fba61b354f3..82d34002617 100644 --- a/mysql-test/main/information_schema.result +++ b/mysql-test/main/information_schema.result @@ -2217,8 +2217,9 @@ Warning 1931 Query execution was interrupted. The query examined at least ### ro # m_status == DA_OK_BULK' failed in Diagnostics_area::message() # call mtr.add_suppression("Sort aborted.*"); -DROP DATABASE test; -CREATE DATABASE test; +create database dummy; +use dummy; +drop database dummy; USE test; CREATE VIEW v AS SELECT table_schema AS object_schema, table_name AS object_name, table_type AS object_type FROM information_schema.tables ORDER BY object_schema; SELECT * FROM v LIMIT ROWS EXAMINED 9; diff --git a/mysql-test/main/information_schema.test b/mysql-test/main/information_schema.test index 2fac02d2fe0..469be44ef94 100644 --- a/mysql-test/main/information_schema.test +++ b/mysql-test/main/information_schema.test @@ -1940,8 +1940,9 @@ SELECT * FROM INFORMATION_SCHEMA.`COLUMNS` LIMIT ROWS EXAMINED 10; call mtr.add_suppression("Sort aborted.*"); -DROP DATABASE test; -CREATE DATABASE test; +create database dummy; +use dummy; +drop database dummy; USE test; CREATE VIEW v AS SELECT table_schema AS object_schema, table_name AS object_name, table_type AS object_type FROM information_schema.tables ORDER BY object_schema; diff --git a/mysql-test/main/mysqldump.result b/mysql-test/main/mysqldump.result index afaafb4907c..a517a5e3c48 100644 --- a/mysql-test/main/mysqldump.result +++ b/mysql-test/main/mysqldump.result @@ -4469,6 +4469,7 @@ Db Name Definer Time zone Type Execute at Interval value Interval field Starts E # MDEV-13336: add ignore-database option # with --all-databases # +SET GLOBAL innodb_max_purge_lag_wait=0; DROP DATABASE test; SHOW DATABASES LIKE 'test'; Database (test) diff --git a/mysql-test/main/mysqldump.test b/mysql-test/main/mysqldump.test index 89155a435b1..a099727ba38 100644 --- a/mysql-test/main/mysqldump.test +++ b/mysql-test/main/mysqldump.test @@ -1921,6 +1921,8 @@ SHOW EVENTS; --echo # with --all-databases --echo # --exec $MYSQL_DUMP --default-character-set=utf8mb4 --ignore-database test --all-databases > $MYSQLTEST_VARDIR/tmp/mysqldump-MDEV-13336.sql +# Starting with MariaDB 10.6, ensure that DDL recovery will have completed. +SET GLOBAL innodb_max_purge_lag_wait=0; DROP DATABASE test; --exec $MYSQL < $MYSQLTEST_VARDIR/tmp/mysqldump-MDEV-13336.sql SHOW DATABASES LIKE 'test'; diff --git a/mysql-test/main/view.result b/mysql-test/main/view.result index 7354e1dbb91..b042e27997f 100644 --- a/mysql-test/main/view.result +++ b/mysql-test/main/view.result @@ -6723,7 +6723,9 @@ DROP TABLE t1; # # MDEV-24314: create view with derived table without default database # -drop database test; +create database dummy; +use dummy; +drop database dummy; create database db1; create table db1.t1 (a int); insert into db1.t1 values (3),(7),(1); @@ -6753,7 +6755,6 @@ a drop view db1.v1; drop table db1.t1; drop database db1; -create database test; use test; # # MDEV-16940: update of multi-table view returning error used in SP diff --git a/mysql-test/main/view.test b/mysql-test/main/view.test index 987e96fc79d..11355c211ca 100644 --- a/mysql-test/main/view.test +++ b/mysql-test/main/view.test @@ -6437,7 +6437,9 @@ DROP TABLE t1; --echo # MDEV-24314: create view with derived table without default database --echo # -drop database test; +create database dummy; +use dummy; +drop database dummy; create database db1; create table db1.t1 (a int); @@ -6460,7 +6462,6 @@ drop view db1.v1; drop table db1.t1; drop database db1; -create database test; use test; --echo # diff --git a/mysql-test/suite/funcs_2/r/innodb_charset.result b/mysql-test/suite/funcs_2/r/innodb_charset.result index 1ce5972eccc..6333e8739e3 100644 --- a/mysql-test/suite/funcs_2/r/innodb_charset.result +++ b/mysql-test/suite/funcs_2/r/innodb_charset.result @@ -1,3 +1,4 @@ +SET GLOBAL innodb_max_purge_lag_wait=0; set @save_character_set_database= @@character_set_database; DROP TABLE IF EXISTS test.t1; SET NAMES armscii8; diff --git a/mysql-test/suite/funcs_2/t/innodb_charset.test b/mysql-test/suite/funcs_2/t/innodb_charset.test index da4dea44ad7..631c20352d4 100644 --- a/mysql-test/suite/funcs_2/t/innodb_charset.test +++ b/mysql-test/suite/funcs_2/t/innodb_charset.test @@ -9,6 +9,10 @@ --source include/no_valgrind_without_big.inc --source include/have_innodb.inc +# Starting with MariaDB 10.6, ensure that DDL recovery will have completed +# before DROP DATABASE test. +SET GLOBAL innodb_max_purge_lag_wait=0; + let $engine_type= InnoDB; --source suite/funcs_2/charset/charset_master.test diff --git a/mysql-test/suite/innodb/r/information_schema_grants.result b/mysql-test/suite/innodb/r/information_schema_grants.result index 04550bfa114..b2bd8b657a6 100644 --- a/mysql-test/suite/innodb/r/information_schema_grants.result +++ b/mysql-test/suite/innodb/r/information_schema_grants.result @@ -299,6 +299,7 @@ select count(*) > -1 from d_trx; count(*) > -1 1 connection default; +SET GLOBAL innodb_max_purge_lag_wait=0; drop database test; create database test; drop user select_only@localhost; diff --git a/mysql-test/suite/innodb/t/information_schema_grants.test b/mysql-test/suite/innodb/t/information_schema_grants.test index 34565f76352..32eaefdacb3 100644 --- a/mysql-test/suite/innodb/t/information_schema_grants.test +++ b/mysql-test/suite/innodb/t/information_schema_grants.test @@ -306,6 +306,8 @@ select count(*) > -1 from i_trx; select count(*) > -1 from d_trx; connection default; +# Starting with MariaDB 10.6, ensure that DDL recovery will have completed. +SET GLOBAL innodb_max_purge_lag_wait=0; drop database test; create database test; drop user select_only@localhost; diff --git a/mysql-test/suite/innodb/t/innodb-mdev7046.test b/mysql-test/suite/innodb/t/innodb-mdev7046.test index 27c140689c1..52b8e83695a 100644 --- a/mysql-test/suite/innodb/t/innodb-mdev7046.test +++ b/mysql-test/suite/innodb/t/innodb-mdev7046.test @@ -31,6 +31,8 @@ RENAME TABLE t1 TO `t2_new..............................................end`; show warnings; drop table t1; +# Starting with MariaDB 10.6, ensure that DDL recovery will have completed. +SET GLOBAL innodb_max_purge_lag_wait=0; drop database test; create database test; use test; From d0f6d467045591176ec5e229e2b0562c61c29358 Mon Sep 17 00:00:00 2001 From: musvaage Date: Fri, 25 Nov 2022 17:32:16 -0600 Subject: [PATCH 05/23] debian typos --- debian/additions/innotop/innotop | 2 +- debian/additions/mysqlreport | 4 ++-- debian/mariadb-server-10.3.postinst | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/debian/additions/innotop/innotop b/debian/additions/innotop/innotop index 5ffd8180c34..15ab47c8fc6 100644 --- a/debian/additions/innotop/innotop +++ b/debian/additions/innotop/innotop @@ -4937,7 +4937,7 @@ sub noecho_password { }; if ( $EVAL_ERROR ) { - die "Cannot read respose; is Term::ReadKey installed? $EVAL_ERROR"; + die "Cannot read response; is Term::ReadKey installed? $EVAL_ERROR"; } return $response; } diff --git a/debian/additions/mysqlreport b/debian/additions/mysqlreport index 61fef3f89ee..2d9b04c7eac 100755 --- a/debian/additions/mysqlreport +++ b/debian/additions/mysqlreport @@ -705,7 +705,7 @@ sub set_myisam_vals { print "set_myisam_vals\n" if $op{debug}; -# should be moved elsewere +# should be moved elsewhere $questions = $stats{'Questions'}; $key_read_ratio = sprintf "%.2f", @@ -1366,7 +1366,7 @@ format QCACHE = __ Query Cache _________________________________________________________ Memory usage @>>>>>> of @>>>>>> %Usage: @>>>>> make_short($qc_mem_used, 1), make_short($vars{'query_cache_size'}, 1), perc($qc_mem_used, $vars{'query_cache_size'}) -Block Fragmnt @>>>>>% +Block Fragment @>>>>>% perc($stats{'Qcache_free_blocks'}, $stats{'Qcache_total_blocks'}) Hits @>>>>>> @>>>>>/s make_short($stats{'Qcache_hits'}), t($stats{'Qcache_hits'}) diff --git a/debian/mariadb-server-10.3.postinst b/debian/mariadb-server-10.3.postinst index 38f20ec4774..51366a9f6fd 100644 --- a/debian/mariadb-server-10.3.postinst +++ b/debian/mariadb-server-10.3.postinst @@ -129,7 +129,7 @@ EOF # This is important to avoid dataloss when there is a removed # mysql-server version from Woody lying around which used the same - # data directory and then somewhen gets purged by the admin. + # data directory and then somehow gets purged by the admin. db_set mariadb-server/postrm_remove_database false || true # Clean up old flags before setting new one From 9f8fc983d5fe23698f8fd6f7457568cd689ed0e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 16 Dec 2022 09:59:09 +0200 Subject: [PATCH 06/23] MDEV-30242 MTR fails to report stack traces of all threads by default An unfortunate change to the default behavior of the handling of core dumps was implemented in commit e9be5428a27eaaccf142f2bd53f4d30e8e368484 by making MTR_PRINT_CORE=small the default value, that is, to only display the stack trace of one thread in crash reports. Many if not most failures that occur in regression tests are sporadic and involve race conditions or deadlocks. To be able to analyze such failures, having the stack traces of all active threads is a must, because CI environments typically do not save any core dumps. While the environment variable MTR_PRINT_CORE could be set in CI environments to compensate for the unfortunate change, it is better to revert to the old default (dumping all threads) so that no explicit action will be required from maintainers of independent CI systems. In that case, if something fails once in a blue moon, we can have some hope of diagnosing it based on the output. We fix this regression by defaulting the unset environment variable MTR_PRINT_CORE to "medium". --- mysql-test/lib/My/CoreDump.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/lib/My/CoreDump.pm b/mysql-test/lib/My/CoreDump.pm index 298cf9ef877..05b6edf1385 100644 --- a/mysql-test/lib/My/CoreDump.pm +++ b/mysql-test/lib/My/CoreDump.pm @@ -108,7 +108,7 @@ for my $f (keys %print_formats) register_opt('print-core|C', ':s', "Print core dump format: ". $print_formats. " (for not printing cores). ". - "Defaults to value of MTR_PRINT_CORE or 'short'"); + "Defaults to value of MTR_PRINT_CORE or 'medium'"); if (!IS_WINDOWS) { register_opt('print-method', '=s', @@ -134,7 +134,7 @@ sub env_or_default($$) { } sub pre_setup() { - $config{print_core}= env_or_default('short', 'MTR_PRINT_CORE') + $config{print_core}= env_or_default('medium', 'MTR_PRINT_CORE') if not defined $config{print_core}; $config{print_method}= (IS_WINDOWS) ? 'cdb' : 'auto' if not defined $config{print_method}; From 0ca3aaa75fe084daabacfed0924598621dffec15 Mon Sep 17 00:00:00 2001 From: Lena Startseva Date: Thu, 15 Dec 2022 16:12:49 +0000 Subject: [PATCH 07/23] MDEV-27691: make working view-protocol Excluded one case from view-protocol in gis.test --- mysql-test/main/gis.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mysql-test/main/gis.test b/mysql-test/main/gis.test index 716fab9bfeb..72b4661ad24 100644 --- a/mysql-test/main/gis.test +++ b/mysql-test/main/gis.test @@ -3093,12 +3093,15 @@ SELECT IS_USED_LOCK(POINT(1,1)); --echo # --echo # MDEV-26161 crash in Gis_point::calculate_haversine --echo # +#enable after fix MDEV-30229 +--disable_view_protocol --error ER_CANT_CREATE_GEOMETRY_OBJECT select st_distance_sphere(x'01030000000400000004000000000000', multipoint(point(124,204)), 10); --error ER_CANT_CREATE_GEOMETRY_OBJECT select st_distance_sphere(x'010300000004000000040000', multipoint(point(124,204)), 10); --error ER_CANT_CREATE_GEOMETRY_OBJECT select st_distance_sphere(x'010300000001000000040000', multipoint(point(124,204)), 10); +--enable_view_protocol --echo # --echo # End of 10.3 tests From e9e6c7a3c5e11ac2c8c0c77053961a698eb4a7d8 Mon Sep 17 00:00:00 2001 From: musvaage Date: Mon, 19 Dec 2022 15:08:20 -0600 Subject: [PATCH 08/23] header typos --- include/heap.h | 6 +++--- include/json_lib.h | 4 ++-- include/m_ctype.h | 8 ++++---- include/ma_dyncol.h | 2 +- include/my_base.h | 12 ++++++------ include/my_decimal_limits.h | 2 +- include/my_dir.h | 2 +- include/my_global.h | 4 ++-- include/my_sys.h | 6 +++--- include/myisam.h | 4 ++-- include/myisammrg.h | 4 ++-- include/mysql.h | 2 +- include/mysql/plugin_ftparser.h | 2 +- include/mysql/psi/mysql_thread.h | 2 +- include/mysql/service_base64.h | 2 +- include/mysql/service_my_snprintf.h | 2 +- include/mysql/service_thd_timezone.h | 2 +- include/queues.h | 2 +- include/waiting_threads.h | 2 +- 19 files changed, 35 insertions(+), 35 deletions(-) diff --git a/include/heap.h b/include/heap.h index ca6efa48f1b..b1ce42970e0 100644 --- a/include/heap.h +++ b/include/heap.h @@ -33,12 +33,12 @@ extern "C" { #include "my_compare.h" #include "my_tree.h" - /* defines used by heap-funktions */ + /* defines used by heap-functions */ #define HP_MAX_LEVELS 4 /* 128^5 records is enough */ #define HP_PTRS_IN_NOD 128 - /* struct used with heap_funktions */ + /* struct used with heap_functions */ typedef struct st_heapinfo /* Struct from heap_info */ { @@ -107,7 +107,7 @@ typedef struct st_heap_block ulong last_allocated; /* number of records there is allocated space for */ } HP_BLOCK; -struct st_heap_info; /* For referense */ +struct st_heap_info; /* For reference */ typedef struct st_hp_keydef /* Key definition with open */ { diff --git a/include/json_lib.h b/include/json_lib.h index fed85b516d9..b79a55e65d0 100644 --- a/include/json_lib.h +++ b/include/json_lib.h @@ -371,7 +371,7 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state); /* - Converst JSON string constant into ordinary string constant + Convert JSON string constant into ordinary string constant which can involve unpacking json escapes and changing character set. Returns negative integer in the case of an error, the length of the result otherwise. @@ -382,7 +382,7 @@ int json_unescape(CHARSET_INFO *json_cs, uchar *res, uchar *res_end); /* - Converst ordinary string constant into JSON string constant. + Convert ordinary string constant into JSON string constant. which can involve appropriate escaping and changing character set. Returns negative integer in the case of an error, the length of the result otherwise. diff --git a/include/m_ctype.h b/include/m_ctype.h index 1cdff1f54cc..e773b0394e5 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -14,7 +14,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* - A better inplementation of the UNIX ctype(3) library. + A better implementation of the UNIX ctype(3) library. */ #ifndef _m_ctype_h @@ -123,7 +123,7 @@ uint16 *my_uca_contraction2_weight(const MY_CONTRACTIONS *c, my_wc_t wc1, my_wc_t wc2); -/* Collation weights on a single level (e.g. primary, secondary, tertiarty) */ +/* Collation weights on a single level (e.g. primary, secondary, tertiary) */ typedef struct my_uca_level_info_st { my_wc_t maxchar; @@ -953,7 +953,7 @@ uint32 my_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, An extended version of my_convert(), to pass non-default mb_wc() and wc_mb(). For example, String::copy_printable() which is used in Protocol::store_warning() uses this to escape control - and non-convertable characters. + and non-convertible characters. */ uint32 my_convert_using_func(char *to, size_t to_length, CHARSET_INFO *to_cs, my_charset_conv_wc_mb mb_wc, @@ -1041,7 +1041,7 @@ size_t my_convert_fix(CHARSET_INFO *dstcs, char *dst, size_t dst_length, @param str - the beginning of the string @param end - the string end (the next byte after the string) @return >0, for a multi-byte character - @rerurn 0, for a single byte character, broken sequence, empty string. + @return 0, for a single byte character, broken sequence, empty string. */ static inline uint my_ismbchar(CHARSET_INFO *cs, const char *str, const char *end) diff --git a/include/ma_dyncol.h b/include/ma_dyncol.h index 4f05b425afd..4468e23c4c4 100644 --- a/include/ma_dyncol.h +++ b/include/ma_dyncol.h @@ -78,7 +78,7 @@ enum enum_dyncol_func_result ER_DYNCOL_YES= 1, /* For functions returning 0/1 */ ER_DYNCOL_FORMAT= -1, /* Wrong format of the encoded string */ ER_DYNCOL_LIMIT= -2, /* Some limit reached */ - ER_DYNCOL_RESOURCE= -3, /* Out of resourses */ + ER_DYNCOL_RESOURCE= -3, /* Out of resources */ ER_DYNCOL_DATA= -4, /* Incorrect input data */ ER_DYNCOL_UNKNOWN_CHARSET= -5, /* Unknown character set */ ER_DYNCOL_TRUNCATED= 2 /* OK, but data was truncated */ diff --git a/include/my_base.h b/include/my_base.h index 8f4efec10bd..1516adfc690 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -125,7 +125,7 @@ enum ha_extra_function { HA_EXTRA_NO_USER_CHANGE=9, /* No user is allowed to write */ HA_EXTRA_KEY_CACHE=10, HA_EXTRA_NO_KEY_CACHE=11, - HA_EXTRA_WAIT_LOCK=12, /* Wait until file is avalably (def) */ + HA_EXTRA_WAIT_LOCK=12, /* Wait until file is available (def) */ HA_EXTRA_NO_WAIT_LOCK=13, /* If file is locked, return quickly */ HA_EXTRA_WRITE_CACHE=14, /* Use write cache in ha_write() */ HA_EXTRA_FLUSH_CACHE=15, /* flush write_record_cache */ @@ -288,7 +288,7 @@ enum ha_base_keytype { This flag can be calculated -- it's based on key lengths comparison. */ #define HA_KEY_HAS_PART_KEY_SEG 65536 -/* Internal Flag Can be calcaluted */ +/* Internal Flag Can be calculated */ #define HA_INVISIBLE_KEY 2<<18 /* Automatic bits in key-flag */ @@ -435,9 +435,9 @@ enum ha_base_keytype { #define HA_ERR_FIRST 120 /* Copy of first error nr.*/ #define HA_ERR_KEY_NOT_FOUND 120 /* Didn't find key on read or update */ -#define HA_ERR_FOUND_DUPP_KEY 121 /* Dupplicate key on write */ +#define HA_ERR_FOUND_DUPP_KEY 121 /* Duplicate key on write */ #define HA_ERR_INTERNAL_ERROR 122 /* Internal error */ -#define HA_ERR_RECORD_CHANGED 123 /* Uppdate with is recoverable */ +#define HA_ERR_RECORD_CHANGED 123 /* Update with is recoverable */ #define HA_ERR_WRONG_INDEX 124 /* Wrong index given to function */ #define HA_ERR_CRASHED 126 /* Indexfile is crashed */ #define HA_ERR_WRONG_IN_RECORD 127 /* Record-file is crashed */ @@ -453,7 +453,7 @@ enum ha_base_keytype { #define HA_ERR_UNSUPPORTED 138 /* unsupported extension used */ #define HA_ERR_TO_BIG_ROW 139 /* Too big row */ #define HA_WRONG_CREATE_OPTION 140 /* Wrong create option */ -#define HA_ERR_FOUND_DUPP_UNIQUE 141 /* Dupplicate unique on write */ +#define HA_ERR_FOUND_DUPP_UNIQUE 141 /* Duplicate unique on write */ #define HA_ERR_UNKNOWN_CHARSET 142 /* Can't open charset */ #define HA_ERR_WRONG_MRG_TABLE_DEF 143 /* conflicting tables in MERGE */ #define HA_ERR_CRASHED_ON_REPAIR 144 /* Last (automatic?) repair failed */ @@ -497,7 +497,7 @@ enum ha_base_keytype { illegal data being read */ #define HA_ERR_NEW_FILE 172 /* New file format */ #define HA_ERR_ROWS_EVENT_APPLY 173 /* The event could not be processed - no other hanlder error happened */ + no other handler error happened */ #define HA_ERR_INITIALIZATION 174 /* Error during initialization */ #define HA_ERR_FILE_TOO_SHORT 175 /* File too short */ #define HA_ERR_WRONG_CRC 176 /* Wrong CRC on page */ diff --git a/include/my_decimal_limits.h b/include/my_decimal_limits.h index ac1df83bb62..5bfd54d6748 100644 --- a/include/my_decimal_limits.h +++ b/include/my_decimal_limits.h @@ -32,7 +32,7 @@ digits in one our big digit decreased by 1 (because we always put decimal point on the border of our big digits)) - With normal precession we can handle 65 digits. MariaDB can store in + With normal precision we can handle 65 digits. MariaDB can store in the .frm up to 63 digits. By default we use DECIMAL_NOT_SPECIFIED digits when converting strings to decimal, so we don't want to set this too high. To not use up all digits for the scale we limit the number of decimals to diff --git a/include/my_dir.h b/include/my_dir.h index 930d54ca72f..861599d8fc0 100644 --- a/include/my_dir.h +++ b/include/my_dir.h @@ -70,7 +70,7 @@ typedef struct my_stat dev_t st_rdev; /* more major & minor device numbers (???) */ off_t st_size; /* size of file */ time_t st_atime; /* time for last read */ - time_t st_mtime; /* time for last contens modify */ + time_t st_mtime; /* time for last contents modify */ time_t st_ctime; /* time for last inode or contents modify */ } MY_STAT; diff --git a/include/my_global.h b/include/my_global.h index 06e8cf4b1bb..29b307de4d5 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -675,7 +675,7 @@ typedef SOCKET_SIZE_TYPE size_socket; the mismatch of CRT and mysys file IO usage on Windows at runtime. CRT file descriptors can be in the range 0-2047, whereas descriptors returned by my_open() will start with 2048. If a file descriptor with value less then - MY_FILE_MIN is passed to mysys IO function, chances are it stemms from + MY_FILE_MIN is passed to mysys IO function, chances are it stems from open()/fileno() and not my_open()/my_fileno. For Posix, mysys functions are light wrappers around libc, and MY_FILE_MIN @@ -896,7 +896,7 @@ typedef long long my_ptrdiff_t; #define STDCALL #endif -/* Typdefs for easyier portability */ +/* Typdefs for easier portability */ #ifndef HAVE_UCHAR typedef unsigned char uchar; /* Short for unsigned char */ diff --git a/include/my_sys.h b/include/my_sys.h index a32a0c09234..5d67df26ca6 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -444,7 +444,7 @@ typedef struct st_io_cache /* Used when caching files */ /* A caller will use my_b_read() macro to read from the cache if the data is already in cache, it will be simply copied with - memcpy() and internal variables will be accordinging updated with + memcpy() and internal variables will be accordingly updated with no functions invoked. However, if the data is not fully in the cache, my_b_read() will call read_function to fetch the data. read_function must never be invoked directly. @@ -488,7 +488,7 @@ typedef struct st_io_cache /* Used when caching files */ myf myflags; /* Flags used to my_read/my_write */ /* alloced_buffer is set to the size of the buffer allocated for the IO_CACHE. - Includes the overhead(storing key to ecnrypt and decrypt) for encryption. + Includes the overhead(storing key to encrypt and decrypt) for encryption. Set to 0 if nothing is allocated. Currently READ_NET is the only one that will use a buffer allocated somewhere else @@ -997,7 +997,7 @@ static inline my_hrtime_t make_hr_time(my_time_t time, ulong time_sec_part) #define my_munmap(a,b) munmap((a),(b)) #else -/* not a complete set of mmap() flags, but only those that nesessary */ +/* not a complete set of mmap() flags, but only those that necessary */ #define PROT_READ 1 #define PROT_WRITE 2 #define MAP_NORESERVE 0 diff --git a/include/myisam.h b/include/myisam.h index 3138dc832f7..79002c2b74c 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ -/* This file should be included when using myisam_funktions */ +/* This file should be included when using myisam_functions */ #ifndef _myisam_h #define _myisam_h @@ -159,7 +159,7 @@ typedef struct st_mi_create_info my_bool with_auto_increment; } MI_CREATE_INFO; -struct st_myisam_info; /* For referense */ +struct st_myisam_info; /* For reference */ struct st_mi_isam_share; typedef struct st_myisam_info MI_INFO; struct st_mi_s_param; diff --git a/include/myisammrg.h b/include/myisammrg.h index fe229a85cb0..d0a4c603faa 100644 --- a/include/myisammrg.h +++ b/include/myisammrg.h @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ -/* This file should be included when using merge_isam_funktions */ +/* This file should be included when using merge_isam_functions */ #ifndef _myisammrg_h #define _myisammrg_h @@ -51,7 +51,7 @@ typedef struct st_mymerge_info /* Struct from h_info */ ulonglong data_file_length; ulonglong dupp_key_pos; /* Offset of the Duplicate key in the merge table */ uint reclength; /* Recordlength */ - int errkey; /* With key was dupplicated on err */ + int errkey; /* With key was duplicated on err */ uint options; /* HA_OPTION_... used */ ulong *rec_per_key; /* for sql optimizing */ } MYMERGE_INFO; diff --git a/include/mysql.h b/include/mysql.h index 114d763e58c..2a96effcf93 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -655,7 +655,7 @@ enum enum_mysql_stmt_state length - On input: in case when lengths of input values are different for each execute, you can set this to - point at a variable containining value length. This + point at a variable containing value length. This way the value length can be different in each execute. If length is not NULL, buffer_length is not used. Note, length can even point at buffer_length if diff --git a/include/mysql/plugin_ftparser.h b/include/mysql/plugin_ftparser.h index 8db8712926f..511b34bb234 100644 --- a/include/mysql/plugin_ftparser.h +++ b/include/mysql/plugin_ftparser.h @@ -101,7 +101,7 @@ enum enum_ft_token_type <0 Must not be present 0 Neither; the word is optional but its presence increases the relevance With the default settings of the ft_boolean_syntax system variable, - >0 corresponds to the '+' operator, <0 corrresponds to the '-' operator, + >0 corresponds to the '+' operator, <0 corresponds to the '-' operator, and 0 means neither operator was used. weight_adjust: A weighting factor that determines how much a match diff --git a/include/mysql/psi/mysql_thread.h b/include/mysql/psi/mysql_thread.h index eab87402140..06db6890882 100644 --- a/include/mysql/psi/mysql_thread.h +++ b/include/mysql/psi/mysql_thread.h @@ -588,7 +588,7 @@ typedef struct st_mysql_cond mysql_cond_t; This function creates both the thread instrumentation and a thread. @c mysql_thread_create is a replacement for @c pthread_create. The parameter P4 (or, if it is NULL, P1) will be used as the - instrumented thread "indentity". + instrumented thread "identity". Providing a P1 / P4 parameter with a different value for each call will on average improve performances, since this thread identity value is used internally to randomize access to data and prevent contention. diff --git a/include/mysql/service_base64.h b/include/mysql/service_base64.h index 43b5ba323ba..fa54b4923d4 100644 --- a/include/mysql/service_base64.h +++ b/include/mysql/service_base64.h @@ -29,7 +29,7 @@ extern "C" { #include #endif -/* Allow multuple chunks 'AAA= AA== AA==', binlog uses this */ +/* Allow multiple chunks 'AAA= AA== AA==', binlog uses this */ #define MY_BASE64_DECODE_ALLOW_MULTIPLE_CHUNKS 1 extern struct base64_service_st { diff --git a/include/mysql/service_my_snprintf.h b/include/mysql/service_my_snprintf.h index 6757a658fb6..fcc832fc1f1 100644 --- a/include/mysql/service_my_snprintf.h +++ b/include/mysql/service_my_snprintf.h @@ -40,7 +40,7 @@ @post The syntax of a format string is generally the same: % - where everithing but the format is optional. + where everything but the format is optional. Three one-character flags are recognized: '0' has the standard zero-padding semantics; diff --git a/include/mysql/service_thd_timezone.h b/include/mysql/service_thd_timezone.h index 89e75274cf0..667137745f4 100644 --- a/include/mysql/service_thd_timezone.h +++ b/include/mysql/service_thd_timezone.h @@ -16,7 +16,7 @@ /** @file - This service provdes functions to convert between my_time_t and + This service provides functions to convert between my_time_t and MYSQL_TIME taking into account the current value of the time_zone session variable. diff --git a/include/queues.h b/include/queues.h index e9948857dde..9cc7c15a980 100644 --- a/include/queues.h +++ b/include/queues.h @@ -24,7 +24,7 @@ */ /* - Code for generell handling of priority Queues. + Code for general handling of priority Queues. Implementation of queues from "Algorithms in C" by Robert Sedgewick. */ diff --git a/include/waiting_threads.h b/include/waiting_threads.h index f785cc8988b..5f708f42f96 100644 --- a/include/waiting_threads.h +++ b/include/waiting_threads.h @@ -81,7 +81,7 @@ typedef struct st_wt_thd { 1. Latest Keep all weights equal. 2. Random - Assight weights at random. + Assign weights at random. (variant: modify a weight randomly before every lock request) 3. Youngest Set weight to -NOW() From c21566a78a0fbdd6c1634f82aa9baa61a9c98388 Mon Sep 17 00:00:00 2001 From: musvaage Date: Mon, 19 Dec 2022 16:54:15 -0600 Subject: [PATCH 09/23] header typos --- include/my_compare.h | 2 +- include/my_rdtsc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/my_compare.h b/include/my_compare.h index bd5dc418f8c..2274b666be6 100644 --- a/include/my_compare.h +++ b/include/my_compare.h @@ -132,7 +132,7 @@ extern HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, const uchar *a); 0=CHECK_NEG - The filter is not satisfied. The engine should discard this index tuple and continue the scan. - 1=CHECK_POS - The filter is statisfied. Current index tuple should be + 1=CHECK_POS - The filter is satisfied. Current index tuple should be returned to the SQL layer. 2=CHECK_OUT_OF_RANGE - the index tuple is outside of the range that we're scanning. (Example: if we're scanning "t.key BETWEEN 10 AND diff --git a/include/my_rdtsc.h b/include/my_rdtsc.h index 33d722764d4..e81015166d2 100644 --- a/include/my_rdtsc.h +++ b/include/my_rdtsc.h @@ -90,7 +90,7 @@ C_MODE_START how to ensure that it can be accessed. On AARCH64, we use the generic timer base register. We override clang implementation for aarch64 as it access a PMU register which is not - guarenteed to be active. + guaranteed to be active. Sadly, we have nothing for the Digital Alpha, MIPS, Motorola m68k, HP PA-RISC or other non-mainstream (or obsolete) processors. From 3f63aa18a7f81540049c8414308c6c04fdc4a5ad Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Wed, 7 Dec 2022 20:19:05 +1100 Subject: [PATCH 10/23] MDEV-29562 Spider table charset error should happen correctly. When trying to create a spider table with banned charsets including utf32, utf16, ucs2 and utf16le[1], spider should emit an error immediately, rather than wait until a separate statement that establishes a connection (e.g. SELECT). This also applies to ALTER TABLE statement that changes charsets. [1] https://mariadb.com/kb/en/server-system-variables/#character_set_client Signed-off-by: Yuchen Pei Reviewed-by: Nayuta Yanagisawa --- storage/spider/ha_spider.cc | 10 ++++ .../spider/bugfix/r/mdev_29562.result | 47 ++++++++++++++++ .../mysql-test/spider/bugfix/t/mdev_29562.cnf | 3 ++ .../spider/bugfix/t/mdev_29562.test | 54 +++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_29562.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_29562.cnf create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_29562.test diff --git a/storage/spider/ha_spider.cc b/storage/spider/ha_spider.cc index 7f283560af5..27daa205fc7 100644 --- a/storage/spider/ha_spider.cc +++ b/storage/spider/ha_spider.cc @@ -11450,6 +11450,15 @@ int ha_spider::create( sql_command == SQLCOM_DROP_INDEX ) DBUG_RETURN(0); + if (!is_supported_parser_charset(info->default_table_charset)) + { + String charset_option; + charset_option.append("CHARSET "); + charset_option.append(info->default_table_charset->csname); + my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), "SPIDER", charset_option.c_ptr()); + error_num = ER_ILLEGAL_HA_CREATE_OPTION; + goto error_charset; + } if (!(trx = spider_get_trx(thd, TRUE, &error_num))) goto error_get_trx; if ( @@ -11624,6 +11633,7 @@ error: spider_free_share_alloc(&tmp_share); error_alter_before_unlock: error_get_trx: +error_charset: DBUG_RETURN(error_num); } diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_29562.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_29562.result new file mode 100644 index 00000000000..561ce18a603 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_29562.result @@ -0,0 +1,47 @@ +# +# MDEV-29562 Spider table with charset utf32/utf16/ucs2 tries to set client charset to unsupported value +# +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 +connection child2_1; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; +CREATE TABLE tbl_a ( +a INT +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +CREATE TABLE tbl_a ( +a INT +) ENGINE=Spider CHARSET utf32 COMMENT='table "tbl_a", srv "s_2_1"'; +ERROR HY000: Table storage engine 'SPIDER' does not support the create option 'CHARSET utf32' +ALTER DATABASE auto_test_local CHARSET="ucs2"; +CREATE TABLE tbl_a ( +a INT +) ENGINE=Spider COMMENT='table "tbl_a", srv "s_2_1"'; +ERROR HY000: Table storage engine 'SPIDER' does not support the create option 'CHARSET ucs2' +CREATE TABLE tbl_a ( +a INT +) ENGINE=Spider CHARSET utf8 COMMENT='table "tbl_a", srv "s_2_1"'; +SELECT * FROM tbl_a; +a +ALTER TABLE tbl_a CONVERT TO CHARACTER SET utf16; +ERROR HY000: Table storage engine 'SPIDER' does not support the create option 'CHARSET utf16' +ALTER TABLE tbl_a CONVERT TO CHARACTER SET utf16le; +ERROR HY000: Table storage engine 'SPIDER' does not support the create option 'CHARSET utf16le' +ALTER TABLE tbl_a CONVERT TO CHARACTER SET latin1; +connection master_1; +DROP DATABASE IF EXISTS auto_test_local; +connection child2_1; +DROP DATABASE IF EXISTS auto_test_remote; +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_29562.cnf b/storage/spider/mysql-test/spider/bugfix/t/mdev_29562.cnf new file mode 100644 index 00000000000..05dfd8a0bce --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_29562.cnf @@ -0,0 +1,3 @@ +!include include/default_mysqld.cnf +!include ../my_1_1.cnf +!include ../my_2_1.cnf diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_29562.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_29562.test new file mode 100644 index 00000000000..5ddb2cef492 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_29562.test @@ -0,0 +1,54 @@ +--echo # +--echo # MDEV-29562 Spider table with charset utf32/utf16/ucs2 tries to set client charset to unsupported value +--echo # + +--disable_query_log +--disable_result_log +--source ../../t/test_init.inc +--enable_result_log +--enable_query_log + +--connection child2_1 +CREATE DATABASE auto_test_remote; +USE auto_test_remote; +eval CREATE TABLE tbl_a ( + a INT +) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; + +--connection master_1 +CREATE DATABASE auto_test_local; +USE auto_test_local; +--error ER_ILLEGAL_HA_CREATE_OPTION +eval CREATE TABLE tbl_a ( + a INT +) $MASTER_1_ENGINE CHARSET utf32 COMMENT='table "tbl_a", srv "s_2_1"'; + +ALTER DATABASE auto_test_local CHARSET="ucs2"; +--error ER_ILLEGAL_HA_CREATE_OPTION +eval CREATE TABLE tbl_a ( + a INT +) $MASTER_1_ENGINE COMMENT='table "tbl_a", srv "s_2_1"'; + +eval CREATE TABLE tbl_a ( + a INT +) $MASTER_1_ENGINE CHARSET utf8 COMMENT='table "tbl_a", srv "s_2_1"'; +SELECT * FROM tbl_a; + +--error ER_ILLEGAL_HA_CREATE_OPTION +ALTER TABLE tbl_a CONVERT TO CHARACTER SET utf16; +--error ER_ILLEGAL_HA_CREATE_OPTION +ALTER TABLE tbl_a CONVERT TO CHARACTER SET utf16le; + +ALTER TABLE tbl_a CONVERT TO CHARACTER SET latin1; + +--connection master_1 +DROP DATABASE IF EXISTS auto_test_local; + +--connection child2_1 +DROP DATABASE IF EXISTS auto_test_remote; + +--disable_query_log +--disable_result_log +--source ../t/test_deinit.inc +--enable_query_log +--enable_result_log From 3ddc00dc3bf29f7cf326268265e47fda61e6a83e Mon Sep 17 00:00:00 2001 From: Vlad Lesin Date: Tue, 13 Dec 2022 16:06:13 +0300 Subject: [PATCH 11/23] MDEV-30225 RR isolation violation with locking unique search Before the fix next-key lock was requested only if a record was delete-marked for locking unique search in RR isolation level. There can be several delete-marked records for the same unique key, that's why InnoDB scans the records until eighter non-delete-marked record is reached or all delete-marked records with the same unique key are scanned. For range scan next-key locks are used for RR to protect scanned range from inserting new records by other transactions. And this is the reason of why next-key locks are used for delete-marked records for unique searches. If a record is not delete-marked, the requested lock type was "not-gap". When a record is not delete-marked during lock request by trx 1, and some other transaction holds conflicting lock, trx 1 creates waiting not-gap lock on the record and suspends. During trx 1 suspending the record can be delete-marked. And when the lock is granted on conflicting transaction commit or rollback, its type is still "not-gap". So we have "not-gap" lock on delete-marked record for RR. And this let some other transaction to insert some record with the same unique key when trx 1 is not committed, what can cause isolation level violation. The fix is to set next-key locks for both delete-marked and non-delete-marked records for unique search in RR. --- .../innodb/r/cursor-restore-locking.result | 1 + .../innodb/r/insert-before-delete.result | 35 +++++++++ mysql-test/suite/innodb/r/monitor.result | 2 +- .../innodb/t/cursor-restore-locking.test | 4 ++ .../suite/innodb/t/insert-before-delete.test | 72 +++++++++++++++++++ mysql-test/suite/innodb/t/monitor.test | 3 + storage/innobase/row/row0sel.cc | 4 +- 7 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 mysql-test/suite/innodb/r/insert-before-delete.result create mode 100644 mysql-test/suite/innodb/t/insert-before-delete.test diff --git a/mysql-test/suite/innodb/r/cursor-restore-locking.result b/mysql-test/suite/innodb/r/cursor-restore-locking.result index bc1127f57b3..da95c57ce64 100644 --- a/mysql-test/suite/innodb/r/cursor-restore-locking.result +++ b/mysql-test/suite/innodb/r/cursor-restore-locking.result @@ -11,6 +11,7 @@ SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL first_ins_locked'; SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL first_ins_row_inserted WAIT_FOR first_ins_cont'; INSERT INTO t VALUES(10, 20); connect con_del_2,localhost,root,,; +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET DEBUG_SYNC = 'now WAIT_FOR first_ins_locked'; SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL second_del_locked'; DELETE FROM t WHERE b = 20; diff --git a/mysql-test/suite/innodb/r/insert-before-delete.result b/mysql-test/suite/innodb/r/insert-before-delete.result new file mode 100644 index 00000000000..11e8fcea9d6 --- /dev/null +++ b/mysql-test/suite/innodb/r/insert-before-delete.result @@ -0,0 +1,35 @@ +connect pause_purge,localhost,root; +START TRANSACTION WITH CONSISTENT SNAPSHOT; +connection default; +CREATE TABLE t (pk int PRIMARY KEY, sk INT UNIQUE) ENGINE=InnoDB; +INSERT INTO t VALUES (10, 100); +connect con1,localhost,root; +BEGIN; +SELECT * FROM t WHERE sk = 100 FOR UPDATE; +pk sk +10 100 +connect con2,localhost,root; +SET DEBUG_SYNC="lock_wait_suspend_thread_enter SIGNAL insert_wait_started"; +INSERT INTO t VALUES (5, 100) # trx 1; +connect con3,localhost,root; +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +SET DEBUG_SYNC="now WAIT_FOR insert_wait_started"; +SET DEBUG_SYNC="lock_wait_suspend_thread_enter SIGNAL delete_started_waiting"; +DELETE FROM t WHERE sk = 100 # trx 2; +connection con1; +SET DEBUG_SYNC="now WAIT_FOR delete_started_waiting"; +DELETE FROM t WHERE sk=100; +COMMIT; +disconnect con1; +connection con2; +disconnect con2; +connection con3; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +disconnect con3; +connection default; +SELECT * FROM t; +pk sk +5 100 +disconnect pause_purge; +SET DEBUG_SYNC="RESET"; +DROP TABLE t; diff --git a/mysql-test/suite/innodb/r/monitor.result b/mysql-test/suite/innodb/r/monitor.result index b65bba276f0..9143ea33a02 100644 --- a/mysql-test/suite/innodb/r/monitor.result +++ b/mysql-test/suite/innodb/r/monitor.result @@ -673,7 +673,7 @@ SET @end = (SELECT COUNT FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME = 'lock_rec_lock_created'); SELECT @end - @start; @end - @start -0 +1 DROP TABLE t1; SET GLOBAL innodb_monitor_enable=default; SET GLOBAL innodb_monitor_disable=default; diff --git a/mysql-test/suite/innodb/t/cursor-restore-locking.test b/mysql-test/suite/innodb/t/cursor-restore-locking.test index d032d8a8def..f3a60f25568 100644 --- a/mysql-test/suite/innodb/t/cursor-restore-locking.test +++ b/mysql-test/suite/innodb/t/cursor-restore-locking.test @@ -27,6 +27,10 @@ SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL first_ins_row_inserted WAIT_FOR fir --send INSERT INTO t VALUES(10, 20) --connect(con_del_2,localhost,root,,) +# After MDEV-30225 is fixed, the following DELETE creates next-key lock for +# unqique search for RR, and the above INSERT kills it as deadlock victim. +# But it still requests not-gap lock for RC. +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET DEBUG_SYNC = 'now WAIT_FOR first_ins_locked'; SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL second_del_locked'; ############################################################################### diff --git a/mysql-test/suite/innodb/t/insert-before-delete.test b/mysql-test/suite/innodb/t/insert-before-delete.test new file mode 100644 index 00000000000..17a885c7bd8 --- /dev/null +++ b/mysql-test/suite/innodb/t/insert-before-delete.test @@ -0,0 +1,72 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/count_sessions.inc + +--connect (pause_purge,localhost,root) +START TRANSACTION WITH CONSISTENT SNAPSHOT; + +--connection default +CREATE TABLE t (pk int PRIMARY KEY, sk INT UNIQUE) ENGINE=InnoDB; +INSERT INTO t VALUES (10, 100); + +--connect (con1,localhost,root) +BEGIN; # trx 0 +SELECT * FROM t WHERE sk = 100 FOR UPDATE; + +--connect (con2,localhost,root) +SET DEBUG_SYNC="lock_wait_suspend_thread_enter SIGNAL insert_wait_started"; +# trx 1 is locked on try to read the record in secondary index during duplicates +# check. It's the first in waiting queue, that's why it will be woken up firstly +# when trx 0 commits. +--send INSERT INTO t VALUES (5, 100) # trx 1 + +--connect (con3,localhost,root) +# MDEV-30225 is fixed only for RR +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +SET DEBUG_SYNC="now WAIT_FOR insert_wait_started"; +SET DEBUG_SYNC="lock_wait_suspend_thread_enter SIGNAL delete_started_waiting"; +# trx 2 can delete (5, 100) on master, but not on slave, as on slave trx 1 +# can insert (5, 100) after trx 2 positioned it's cursor. Trx 2 lock is placed +# in waiting queue after trx 1 lock, but its persistent cursor position was +# stored on (100, 10) record in secondary index before suspending. After trx 1 +# is committed, trx 2 will restore persistent cursor position on (100, 10). As +# (100, 5) secondary index record was inserted before (100, 10) in logical +# order, and (100, 10) record is delete-marked, trx 2 just continues scanning. +# +# Note. There can be several records with the same key in unique secondary +# index, but only one of them must be non-delete-marked. That's why when we do +# point query, cursor position is set in the first record in logical order, and +# then records are iterated until either non-delete-marked record is found or +# all records with the same unique fields are iterated. +--send DELETE FROM t WHERE sk = 100 # trx 2 + +--connection con1 +SET DEBUG_SYNC="now WAIT_FOR delete_started_waiting"; +DELETE FROM t WHERE sk=100; # trx 0 +COMMIT; +--disconnect con1 + +--connection con2 +--reap +--disconnect con2 + +--connection con3 +# If the bug is fixed, deadlock error will be there, as trx 2 owns +# next-key lock waiting for trx 1, and trx 1 requests +# insert-intention lock, conflicting with trx 2 next-key lock. +--error ER_LOCK_DEADLOCK +--reap +--disconnect con3 + +--connection default +# If the bug is not fixed, we will see the row inserted by trx 1 here. This can +# cause duplicate key error on slave, when some other trx tries in insert row +# with the same secondary key, as was inserted by trx 1, and not deleted by trx +# 2. +SELECT * FROM t; + +--disconnect pause_purge +SET DEBUG_SYNC="RESET"; +DROP TABLE t; +--source include/wait_until_count_sessions.inc diff --git a/mysql-test/suite/innodb/t/monitor.test b/mysql-test/suite/innodb/t/monitor.test index 3535c9c85ad..f1cf4b0c39e 100644 --- a/mysql-test/suite/innodb/t/monitor.test +++ b/mysql-test/suite/innodb/t/monitor.test @@ -435,6 +435,9 @@ INSERT INTO t1 VALUES(1,1,'a'),(2,9999,'b'),(3,10000,'c'),(4,4,'d'); DELETE FROM t1 WHERE a = 9999 AND b='b'; COMMIT; +# After MDEV-30225 is fixed, the above DELETE creates next-key lock during +# secondary index unique search. That's why the result of the following must +# be 1. SET @end = (SELECT COUNT FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME = 'lock_rec_lock_created'); SELECT @end - @start; diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index ff0f9d47892..395739e4b4e 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -5114,8 +5114,10 @@ wrong_offs: goto no_gap_lock; } + /* Set next-key lock both for delete- and non-delete-marked + records for unique search, because non-delete-marked record can + be marked as deleted while transaction suspends. */ if (!set_also_gap_locks - || (unique_search && !rec_get_deleted_flag(rec, comp)) || dict_index_is_spatial(index)) { goto no_gap_lock; From 7c5609fb647b7b013694a16acae7c5c5739b394b Mon Sep 17 00:00:00 2001 From: musvaage Date: Tue, 20 Dec 2022 17:41:24 -0600 Subject: [PATCH 12/23] typos --- .../suite/innodb_fts/t/innodb-fts-stopword.test | 16 ++++++++-------- mysql-test/suite/innodb_fts/t/stopword.test | 16 ++++++++-------- .../suite/parts/t/partition_repair_myisam.test | 2 +- storage/connect/value.cpp | 8 ++++---- storage/innobase/row/row0row.cc | 4 ++-- storage/maria/ma_locking.c | 2 +- storage/maria/ma_loghandler.c | 2 +- storage/myisam/mi_locking.c | 2 +- storage/rocksdb/ha_rocksdb.cc | 2 +- 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/mysql-test/suite/innodb_fts/t/innodb-fts-stopword.test b/mysql-test/suite/innodb_fts/t/innodb-fts-stopword.test index 0f29d092541..de14deab328 100644 --- a/mysql-test/suite/innodb_fts/t/innodb-fts-stopword.test +++ b/mysql-test/suite/innodb_fts/t/innodb-fts-stopword.test @@ -39,7 +39,7 @@ select @@innodb_ft_user_stopword_table; --error 1231 set global innodb_ft_server_stopword_table = "not_defined"; -# Define a correct formated user stopword table +# Define a correct formatted user stopword table create table user_stopword(value varchar(30)) engine = innodb; # The set operation should be successful @@ -319,11 +319,11 @@ INSERT INTO articles (title,body) VALUES # No records expeced for select SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -# Define a correct formated user stopword table +# Define a correct formatted user stopword table create table user_stopword(value varchar(30)) engine = innodb; # The set operation should be successful set session innodb_ft_user_stopword_table = "test/user_stopword"; -# Define a correct formated server stopword table +# Define a correct formatted server stopword table create table server_stopword(value varchar(30)) engine = innodb; # The set operation should be successful set global innodb_ft_server_stopword_table = "test/server_stopword"; @@ -422,7 +422,7 @@ INSERT INTO articles (title,body) VALUES # No records expeced for select SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -# Define a correct formated user stopword table +# Define a correct formatted user stopword table create table user_stopword(value varchar(30)) engine = innodb; # The set operation should be successful set session innodb_ft_user_stopword_table = "test/user_stopword"; @@ -444,7 +444,7 @@ SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysqld'); # set user stopword list empty set session innodb_ft_user_stopword_table = default; -# Define a correct formated user stopword table +# Define a correct formatted user stopword table create table server_stopword(value varchar(30)) engine = innodb; # The set operation should be successful set global innodb_ft_server_stopword_table = "test/server_stopword"; @@ -580,7 +580,7 @@ SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOL --connection con1 SET SESSION innodb_ft_enable_stopword = 1; -# Define a correct formated user stopword table +# Define a correct formatted user stopword table create table user_stopword(value varchar(30)) engine = innodb; # The set operation should be successful set session innodb_ft_user_stopword_table = "test/user_stopword"; @@ -599,7 +599,7 @@ SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); select @@innodb_ft_user_stopword_table; -# Define a correct formated user stopword table +# Define a correct formatted user stopword table create table user_stopword_1(value varchar(30)) engine = innodb; # The set operation should be successful set session innodb_ft_user_stopword_table = "test/user_stopword_1"; @@ -620,7 +620,7 @@ SET SESSION innodb_ft_enable_stopword = 1; SET SESSION innodb_ft_user_stopword_table=default; select @@innodb_ft_user_stopword_table; select @@innodb_ft_server_stopword_table; -# Define a correct formated server stopword table +# Define a correct formatted server stopword table create table server_stopword(value varchar(30)) engine = innodb; # The set operation should be successful SET GLOBAL innodb_ft_server_stopword_table = "test/server_stopword"; diff --git a/mysql-test/suite/innodb_fts/t/stopword.test b/mysql-test/suite/innodb_fts/t/stopword.test index 5105a6d2fec..ca01da80734 100644 --- a/mysql-test/suite/innodb_fts/t/stopword.test +++ b/mysql-test/suite/innodb_fts/t/stopword.test @@ -38,7 +38,7 @@ SET @innodb_ft_user_stopword_table_orig=@@innodb_ft_user_stopword_table; set global innodb_ft_server_stopword_table = "not_defined"; set global innodb_ft_server_stopword_table = NULL; -# Define a correct formated user stopword table +# Define a correct formatted user stopword table create table user_stopword(value varchar(30)) engine = innodb; # The set operation should be successful @@ -311,11 +311,11 @@ INSERT INTO articles (title,body) VALUES # No records expeced for select SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -# Define a correct formated user stopword table +# Define a correct formatted user stopword table create table user_stopword(value varchar(30)) engine = innodb; # The set operation should be successful set session innodb_ft_user_stopword_table = "test/user_stopword"; -# Define a correct formated server stopword table +# Define a correct formatted server stopword table create table server_stopword(value varchar(30)) engine = innodb; # The set operation should be successful set global innodb_ft_server_stopword_table = "test/server_stopword"; @@ -411,7 +411,7 @@ INSERT INTO articles (title,body) VALUES # No records expeced for select SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -# Define a correct formated user stopword table +# Define a correct formatted user stopword table create table user_stopword(value varchar(30)) engine = innodb; # The set operation should be successful set session innodb_ft_user_stopword_table = "test/user_stopword"; @@ -433,7 +433,7 @@ SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysqld'); # set user stopword list empty set session innodb_ft_user_stopword_table = default; -# Define a correct formated user stopword table +# Define a correct formatted user stopword table create table server_stopword(value varchar(30)) engine = innodb; # The set operation should be successful set global innodb_ft_server_stopword_table = "test/server_stopword"; @@ -572,7 +572,7 @@ SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOL --echo "In connection 1" --connection con1 SET SESSION innodb_ft_enable_stopword = 1; -# Define a correct formated user stopword table +# Define a correct formatted user stopword table create table user_stopword(value varchar(30)) engine = innodb; # The set operation should be successful set session innodb_ft_user_stopword_table = "test/user_stopword"; @@ -592,7 +592,7 @@ SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); select @@innodb_ft_user_stopword_table; -# Define a correct formated user stopword table +# Define a correct formatted user stopword table create table user_stopword_1(value varchar(30)) engine = innodb; # The set operation should be successful set session innodb_ft_user_stopword_table = "test/user_stopword_1"; @@ -614,7 +614,7 @@ SET SESSION innodb_ft_enable_stopword = 1; SET SESSION innodb_ft_user_stopword_table=default; select @@innodb_ft_user_stopword_table; select @@innodb_ft_server_stopword_table; -# Define a correct formated server stopword table +# Define a correct formatted server stopword table create table server_stopword(value varchar(30)) engine = innodb; # The set operation should be successful SET GLOBAL innodb_ft_server_stopword_table = "test/server_stopword"; diff --git a/mysql-test/suite/parts/t/partition_repair_myisam.test b/mysql-test/suite/parts/t/partition_repair_myisam.test index a21493ca03d..daa57b99211 100644 --- a/mysql-test/suite/parts/t/partition_repair_myisam.test +++ b/mysql-test/suite/parts/t/partition_repair_myisam.test @@ -150,7 +150,7 @@ while ($i) # 2 - after _mi_mark_file_changed (only marked index as opened) # 3 - after write_record (updated datafile + not closed/updated index) # 4 - after flush_cached_blocks (updated index/datafiles, not closed index) -# 5 - (Not used) after mi_state_info_write (fully uppdated/closed index file) +# 5 - (Not used) after mi_state_info_write (fully updated/closed index file) # (this was verified to be a harmless crash, since everything was written) # 6 - partly updated datafile (insert 6 small records, delete 5,3,1, # insert one larger record (2.5 X small) and break in gdb before it has diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index cc68c8694c7..9783d33b896 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -1199,7 +1199,7 @@ bool TYPVAL::Compall(PGLOBAL g, PVAL *vp, int np, OPVAL op) /***********************************************************************/ /* FormatValue: This function set vp (a STRING value) to the string */ -/* constructed from its own value formated using the fmt format. */ +/* constructed from its own value formatted using the fmt format. */ /* This function assumes that the format matches the value type. */ /***********************************************************************/ template @@ -1711,7 +1711,7 @@ bool TYPVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) /***********************************************************************/ /* FormatValue: This function set vp (a STRING value) to the string */ -/* constructed from its own value formated using the fmt format. */ +/* constructed from its own value formatted using the fmt format. */ /* This function assumes that the format matches the value type. */ /***********************************************************************/ bool TYPVAL::FormatValue(PVAL vp, PCSZ fmt) @@ -2325,7 +2325,7 @@ bool BINVAL::IsEqual(PVAL vp, bool chktype) /***********************************************************************/ /* FormatValue: This function set vp (a STRING value) to the string */ -/* constructed from its own value formated using the fmt format. */ +/* constructed from its own value formatted using the fmt format. */ /* This function assumes that the format matches the value type. */ /***********************************************************************/ bool BINVAL::FormatValue(PVAL vp, PCSZ fmt) @@ -2864,7 +2864,7 @@ bool DTVAL::WeekNum(PGLOBAL g, int& nval) /***********************************************************************/ /* FormatValue: This function set vp (a STRING value) to the string */ -/* constructed from its own value formated using the fmt format. */ +/* constructed from its own value formatted using the fmt format. */ /* This function assumes that the format matches the value type. */ /***********************************************************************/ bool DTVAL::FormatValue(PVAL vp, PCSZ fmt) diff --git a/storage/innobase/row/row0row.cc b/storage/innobase/row/row0row.cc index 6f34c9fcc9b..729baa369c8 100644 --- a/storage/innobase/row/row0row.cc +++ b/storage/innobase/row/row0row.cc @@ -1191,7 +1191,7 @@ row_raw_format_int( ulint buf_size, /*!< in: output buffer size in bytes */ ibool* format_in_hex) /*!< out: should the data be - formated in hex */ + formatted in hex */ { ulint ret; @@ -1239,7 +1239,7 @@ row_raw_format_str( ulint buf_size, /*!< in: output buffer size in bytes */ ibool* format_in_hex) /*!< out: should the data be - formated in hex */ + formatted in hex */ { ulint charset_coll; diff --git a/storage/maria/ma_locking.c b/storage/maria/ma_locking.c index a8cf936c873..c2a0f22d614 100644 --- a/storage/maria/ma_locking.c +++ b/storage/maria/ma_locking.c @@ -280,7 +280,7 @@ int _ma_readinfo(register MARIA_HA *info __attribute__ ((unused)), /* - Every isam-function that uppdates the isam-database MUST end with this + Every isam-function that updates the isam-database MUST end with this request NOTES diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c index 7e4fb5a8263..d6d2d5d6864 100644 --- a/storage/maria/ma_loghandler.c +++ b/storage/maria/ma_loghandler.c @@ -956,7 +956,7 @@ char *translog_filename_by_fileno(uint32 file_no, char *path) DBUG_ENTER("translog_filename_by_fileno"); DBUG_ASSERT(file_no <= 0xfffffff); - /* log_descriptor.directory is already formated */ + /* log_descriptor.directory is already formatted */ end= strxmov(path, log_descriptor.directory, "aria_log.0000000", NullS); length= (uint) (int10_to_str(file_no, buff, 10) - buff); strmov(end - length +1, buff); diff --git a/storage/myisam/mi_locking.c b/storage/myisam/mi_locking.c index 55185b67535..2039f572852 100644 --- a/storage/myisam/mi_locking.c +++ b/storage/myisam/mi_locking.c @@ -506,7 +506,7 @@ int _mi_readinfo(register MI_INFO *info, int lock_type, int check_keybuffer) /* - Every isam-function that uppdates the isam-database MUST end with this + Every isam-function that updates the isam-database MUST end with this request */ diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc index aa934695322..b1a64b4aec0 100644 --- a/storage/rocksdb/ha_rocksdb.cc +++ b/storage/rocksdb/ha_rocksdb.cc @@ -7696,7 +7696,7 @@ int rdb_split_normalized_tablename(const std::string &fullname, into MyRocks Data Dictionary The method is called during create table/partition, truncate table/partition - @param table_name IN table's name formated as + @param table_name IN table's name formatted as 'dbname.tablename' @param table_arg IN sql table @param auto_increment_value IN specified table's auto increment value From fb41117c907a99d051ac09c229762978373d7eb0 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Tue, 20 Dec 2022 10:38:35 +1100 Subject: [PATCH 13/23] MDEV-29653 Make sure Item_cache_row has the correct type handler. The incorrect type handler caused an incorrect result_type() for Item_cache_row (STRING_RESULT rather than ROW_RESULT). By updating the constructor of Item_cache_row with the correct type handler, it fixes this problem. Signed-off-by: Yuchen Pei Reviewed-by: Sergei Golubchik --- sql/item.h | 2 +- .../spider/bugfix/r/mdev_29653.result | 33 +++++++++++++++++ .../mysql-test/spider/bugfix/t/mdev_29653.cnf | 3 ++ .../spider/bugfix/t/mdev_29653.test | 37 +++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_29653.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_29653.cnf create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_29653.test diff --git a/sql/item.h b/sql/item.h index 083bc2261ce..9389250d6ec 100644 --- a/sql/item.h +++ b/sql/item.h @@ -7305,7 +7305,7 @@ class Item_cache_row: public Item_cache bool save_array; public: Item_cache_row(THD *thd): - Item_cache(thd), values(0), item_count(2), + Item_cache(thd, &type_handler_row), values(0), item_count(2), save_array(0) {} /* diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_29653.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_29653.result new file mode 100644 index 00000000000..abbcfcb74cc --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_29653.result @@ -0,0 +1,33 @@ +# +# MDEV-29653 Assertion `0' failed in Item_cache_row::illegal_method_call on SELECT from Spider table +# +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 +connection child2_1; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; +CREATE TABLE t ( +c INT +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +CREATE TABLE ts ( +c INT +) ENGINE=Spider COMMENT='table "t", srv "s_2_1"'; +SELECT 1 FROM ts WHERE ROW(c, c) NOT IN ((0,0),(1,1)); +1 +connection master_1; +DROP DATABASE IF EXISTS auto_test_local; +connection child2_1; +DROP DATABASE IF EXISTS auto_test_remote; +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_29653.cnf b/storage/spider/mysql-test/spider/bugfix/t/mdev_29653.cnf new file mode 100644 index 00000000000..05dfd8a0bce --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_29653.cnf @@ -0,0 +1,3 @@ +!include include/default_mysqld.cnf +!include ../my_1_1.cnf +!include ../my_2_1.cnf diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_29653.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_29653.test new file mode 100644 index 00000000000..6accaed38fe --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_29653.test @@ -0,0 +1,37 @@ +--echo # +--echo # MDEV-29653 Assertion `0' failed in Item_cache_row::illegal_method_call on SELECT from Spider table +--echo # + +--disable_query_log +--disable_result_log +--source ../../t/test_init.inc +--enable_result_log +--enable_query_log + +--connection child2_1 +CREATE DATABASE auto_test_remote; +USE auto_test_remote; +eval CREATE TABLE t ( + c INT +) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; + +--connection master_1 +CREATE DATABASE auto_test_local; +USE auto_test_local; +eval CREATE TABLE ts ( + c INT +) $MASTER_1_ENGINE COMMENT='table "t", srv "s_2_1"'; + +SELECT 1 FROM ts WHERE ROW(c, c) NOT IN ((0,0),(1,1)); + +--connection master_1 +DROP DATABASE IF EXISTS auto_test_local; + +--connection child2_1 +DROP DATABASE IF EXISTS auto_test_remote; + +--disable_query_log +--disable_result_log +--source ../t/test_deinit.inc +--enable_query_log +--enable_result_log From 5d506ac201b2bce35448fe9fe714e068bd6be487 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 27 Dec 2022 00:02:01 +0300 Subject: [PATCH 14/23] MDEV-25004 vers_force_trx option to force transactional System Versioning Works like vers_force but forces trx_id-based system-versioned tables if the storage supports it (currently InnoDB-only). Otherwise creates timestamp-based system-versioned table. --- sql/handler.cc | 47 +++++++++++++++++++------------ sql/handler.h | 14 ++++++--- sql/sql_table.cc | 1 + storage/innobase/row/row0mysql.cc | 2 +- 4 files changed, 41 insertions(+), 23 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 66a932cc70e..bb90e6bc7e4 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6976,7 +6976,6 @@ static Create_field *vers_init_sys_field(THD *thd, const char *field_name, int f f->flags= flags | NOT_NULL_FLAG; if (integer) { - DBUG_ASSERT(0); // Not implemented yet f->set_handler(&type_handler_vers_trx_id); f->length= MY_INT64_NUM_DECIMAL_DIGITS - 1; f->flags|= UNSIGNED_FLAG; @@ -6994,10 +6993,13 @@ static Create_field *vers_init_sys_field(THD *thd, const char *field_name, int f return f; } -static bool vers_create_sys_field(THD *thd, const char *field_name, - Alter_info *alter_info, int flags) +bool Vers_parse_info::create_sys_field(THD *thd, const char *field_name, + Alter_info *alter_info, int flags) { - Create_field *f= vers_init_sys_field(thd, field_name, flags, false); + DBUG_ASSERT(can_native >= 0); /* Requires vers_check_native() called */ + Create_field *f= vers_init_sys_field(thd, field_name, flags, + DBUG_EVALUATE_IF("sysvers_force_trx", + (bool) can_native, false)); if (!f) return true; @@ -7021,8 +7023,8 @@ bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info) system_time= start_end_t(default_start, default_end); as_row= system_time; - if (vers_create_sys_field(thd, default_start, alter_info, VERS_ROW_START) || - vers_create_sys_field(thd, default_end, alter_info, VERS_ROW_END)) + if (create_sys_field(thd, default_start, alter_info, VERS_ROW_START) || + create_sys_field(thd, default_end, alter_info, VERS_ROW_END)) { return true; } @@ -7030,14 +7032,25 @@ bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info) } +void Table_scope_and_contents_source_st::vers_check_native() +{ + vers_info.can_native= (db_type->db_type == DB_TYPE_PARTITION_DB || + ha_check_storage_engine_flag(db_type, + HTON_NATIVE_SYS_VERSIONING)); +} + + bool Table_scope_and_contents_source_st::vers_fix_system_fields( THD *thd, Alter_info *alter_info, const TABLE_LIST &create_table) { DBUG_ASSERT(!(alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING)); - DBUG_EXECUTE_IF("sysvers_force", if (!tmp_table()) { - alter_info->flags|= ALTER_ADD_SYSTEM_VERSIONING; - options|= HA_VERSIONED_TABLE; }); + if (DBUG_EVALUATE_IF("sysvers_force", true, false) || + DBUG_EVALUATE_IF("sysvers_force_trx", true, false)) + { + alter_info->flags|= ALTER_ADD_SYSTEM_VERSIONING; + options|= HA_VERSIONED_TABLE; + } if (!vers_info.need_check(alter_info)) return false; @@ -7068,7 +7081,9 @@ bool Table_scope_and_contents_source_st::vers_fix_system_fields( { f->flags|= VERS_UPDATE_UNVERSIONED_FLAG; } - } // while (Create_field *f= it++) + } // while + + vers_check_native(); if (vers_info.fix_implicit(thd, alter_info)) return true; @@ -7121,11 +7136,7 @@ bool Table_scope_and_contents_source_st::vers_check_system_fields( if (!(alter_info->flags & ALTER_ADD_SYSTEM_VERSIONING) && !versioned_fields) return false; - bool can_native= ha_check_storage_engine_flag(db_type, - HTON_NATIVE_SYS_VERSIONING) - || db_type->db_type == DB_TYPE_PARTITION_DB; - - return vers_info.check_sys_fields(table_name, db, alter_info, can_native); + return vers_info.check_sys_fields(table_name, db, alter_info); } @@ -7138,7 +7149,8 @@ bool Vers_parse_info::fix_alter_info(THD *thd, Alter_info *alter_info, if (!need_check(alter_info) && !share->versioned) return false; - if (DBUG_EVALUATE_IF("sysvers_force", 0, share->tmp_table)) + if (DBUG_EVALUATE_IF("sysvers_force", 0, share->tmp_table) || + DBUG_EVALUATE_IF("sysvers_force_trx", 0, share->tmp_table)) { my_error(ER_VERS_TEMPORARY, MYF(0)); return true; @@ -7383,8 +7395,7 @@ bool Create_field::vers_check_bigint(const Lex_table_name &table_name) const bool Vers_parse_info::check_sys_fields(const Lex_table_name &table_name, const Lex_table_name &db, - Alter_info *alter_info, - bool can_native) const + Alter_info *alter_info) const { if (check_conditions(table_name, db)) return true; diff --git a/sql/handler.h b/sql/handler.h index 1c971b2f831..9dde78d22d0 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1881,7 +1881,8 @@ struct Vers_parse_info { Vers_parse_info() : versioned_fields(false), - unversioned_fields(false) + unversioned_fields(false), + can_native(-1) {} void init() // Deep initialization @@ -1890,6 +1891,7 @@ struct Vers_parse_info as_row= start_end_t(null_clex_str, null_clex_str); versioned_fields= false; unversioned_fields= false; + can_native= -1; } struct start_end_t @@ -1936,6 +1938,9 @@ protected: bool need_check(const Alter_info *alter_info) const; bool check_conditions(const Lex_table_name &table_name, const Lex_table_name &db) const; + bool create_sys_field(THD *thd, const char *field_name, + Alter_info *alter_info, int flags); + public: static const Lex_ident default_start; static const Lex_ident default_end; @@ -1945,8 +1950,7 @@ public: bool fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_info, TABLE_LIST &src_table, TABLE_LIST &table); bool check_sys_fields(const Lex_table_name &table_name, - const Lex_table_name &db, Alter_info *alter_info, - bool can_native) const; + const Lex_table_name &db, Alter_info *alter_info) const; /** At least one field was specified 'WITH/WITHOUT SYSTEM VERSIONING'. @@ -1954,6 +1958,7 @@ public: */ bool versioned_fields : 1; bool unversioned_fields : 1; + int can_native; }; /** @@ -2059,6 +2064,8 @@ struct Table_scope_and_contents_source_st: vers_info.init(); } + void vers_check_native(); + bool vers_fix_system_fields(THD *thd, Alter_info *alter_info, const TABLE_LIST &create_table); @@ -2066,7 +2073,6 @@ struct Table_scope_and_contents_source_st: const Lex_table_name &table_name, const Lex_table_name &db, int select_count= 0); - }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 62a46dbf430..700ba824106 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9637,6 +9637,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, if (check_engine(thd, alter_ctx.new_db.str, alter_ctx.new_name.str, create_info)) DBUG_RETURN(true); + create_info->vers_check_native(); if (create_info->vers_info.fix_alter_info(thd, alter_info, create_info, table)) { DBUG_RETURN(true); diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index e79264d3fb8..8eeaa62b29e 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1672,7 +1672,7 @@ row_fts_update_or_delete( if (new_doc_id == 0) { ib::error() << "InnoDB FTS: Doc ID cannot be 0"; - return(DB_FTS_INVALID_DOCID); + DBUG_RETURN(DB_FTS_INVALID_DOCID); } row_fts_do_update(trx, table, old_doc_id, new_doc_id); } From 68c437bad6b6a47ee534aac0411fae83947fbfbf Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 27 Dec 2022 00:02:01 +0300 Subject: [PATCH 15/23] MDEV-25004 restart_bindir option to restart server from different location Adds new parameter $restart_bindir for restart_mysqld.inc. Example: let $restart_bindir= /home/midenok/src/mariadb/10.3b/build; --source include/restart_mysqld.inc It is good to return back original server before check_mysqld will be run at the test end: let $restart_bindir=; --source include/restart_mysqld.inc --- mysql-test/include/start_mysqld.inc | 36 ++++++++++++++++++++++++++--- mysql-test/mysql-test-run.pl | 13 ++++++++--- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/mysql-test/include/start_mysqld.inc b/mysql-test/include/start_mysqld.inc index e31f26aad8c..14a0b088fc0 100644 --- a/mysql-test/include/start_mysqld.inc +++ b/mysql-test/include/start_mysqld.inc @@ -1,13 +1,44 @@ # Include this script only after using shutdown_mysqld.inc # where $_expect_file_name was initialized. # Write file to make mysql-test-run.pl start up the server again + +# restart_noprint defines how much is printed to the .result file +# if 0 (default) then '# result' and restart_parameters are printed +# if 1 then print #result but not the content of restart_parameters +# if 2 then nothing is printed + +if (!$restart_noprint) +{ + --let $restart_noprint= 2 +} + +--let $restart_cmd= restart + +if ($restart_bindir) +{ + --let $restart_cmd= restart_bindir $restart_bindir +} + if ($restart_parameters) { - --exec echo "restart: $restart_parameters" > $_expect_file_name + --exec echo "$restart_cmd: $restart_parameters" > $_expect_file_name + if (!$restart_noprint) + { + --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MYSQLTEST_VARDIR MYSQLTEST_VARDIR + --exec echo "# $restart_cmd: $restart_parameters" + } + if ($restart_noprint == 1) + { + --exec echo "# $restart_cmd: with restart_parameters" + } } if (!$restart_parameters) { - --exec echo "restart" > $_expect_file_name + --exec echo "$restart_cmd" > $_expect_file_name + if ($restart_noprint < 2) + { + --exec echo "# $restart_cmd" + } } # Turn on reconnect @@ -18,4 +49,3 @@ if (!$restart_parameters) # Turn off reconnect again --disable_reconnect - diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 12afab4d28c..af2e71ea17d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1963,7 +1963,7 @@ sub collect_mysqld_features_from_running_server () sub find_mysqld { - my ($mysqld_basedir)= $ENV{MTR_BINDIR}|| @_; + my ($mysqld_basedir)= $ENV{MTR_BINDIR_FORCED} || $ENV{MTR_BINDIR} || @_; my @mysqld_names= ("mysqld", "mysqld-max-nt", "mysqld-max", "mysqld-nt"); @@ -1974,7 +1974,7 @@ sub find_mysqld { unshift(@mysqld_names, "mysqld-debug"); } - return my_find_bin($bindir, + return my_find_bin($mysqld_basedir, ["sql", "libexec", "sbin", "bin"], [@mysqld_names]); } @@ -4789,6 +4789,7 @@ sub check_expected_crash_and_restart { mtr_verbose("Test says wait before restart") if $waits == 0; next; } + delete $ENV{MTR_BINDIR_FORCED}; # Ignore any partial or unknown command next unless $last_line =~ /^restart/; @@ -4796,7 +4797,13 @@ sub check_expected_crash_and_restart { # extra command line options to add to the restarted mysqld. # Anything other than 'wait' or 'restart:' (with a colon) will # result in a restart with original mysqld options. - if ($last_line =~ /restart:(.+)/) { + if ($last_line =~ /restart_bindir\s+(\S+)(:.+)?/) { + $ENV{MTR_BINDIR_FORCED}= $1; + if ($2) { + my @rest_opt= split(' ', $2); + $mysqld->{'restart_opts'}= \@rest_opt; + } + } elsif ($last_line =~ /restart:(.+)/) { my @rest_opt= split(' ', $1); $mysqld->{'restart_opts'}= \@rest_opt; } else { From e056efdd6cfa62cc4c978fce5730af0b8d4c3c6b Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 27 Dec 2022 00:02:02 +0300 Subject: [PATCH 16/23] MDEV-25004 Missing row in FTS_DOC_ID_INDEX during DELETE HISTORY 1. In case of system-versioned table add row_end into FTS_DOC_ID index in fts_create_common_tables() and innobase_create_key_defs(). fts_n_uniq() returns 1 or 2 depending on whether the table is system-versioned. After this patch recreate of FTS_DOC_ID index is required for existing system-versioned tables. If you see this message in error log or server warnings: "InnoDB: Table db/t1 contains 2 indexes inside InnoDB, which is different from the number of indexes 1 defined in the MariaDB" use this command to fix the table: ALTER TABLE db.t1 FORCE; 2. Fix duplicate history for secondary unique index like it was done in MDEV-23644 for clustered index (932ec586aad). In case of existing history row which conflicts with currently inseted row we check in row_ins_scan_sec_index_for_duplicate() whether that row was inserted as part of current transaction. In that case we indicate with DB_FOREIGN_DUPLICATE_KEY that new history row is not needed and should be silently skipped. 3. Some parts of MDEV-21138 (7410ff436e9) reverted. Skipping of FTS_DOC_ID index for history rows made problems with purge system. Now this is fixed differently by p.2. 4. wait_all_purged.inc checks that we didn't affect non-history rows so they are deleted and purged correctly. Additional FTS fixes fts_init_get_doc_id(): exclude history rows from max_doc_id calculation. fts_init_get_doc_id() callback is used only for crash recovery. fts_add_doc_by_id(): set max value for row_end field. fts_read_stopword(): stopwords table can be system-versioned too. We now read stopwords only for current data. row_insert_for_mysql(): exclude history rows from doc_id validation. row_merge_read_clustered_index(): exclude history_rows from doc_id processing. fts_load_user_stopword(): for versioned table retrieve row_end field and skip history rows. For non-versioned table we retrieve 'value' field twice (just for uniformity). FTS tests for System Versioning now include maybe_versioning.inc which adds 3 combinations: 'vers' for debug build sets sysvers_force and sysvers_hide. sysvers_force makes every created table system-versioned, sysvers_hide hides WITH SYSTEM VERSIONING for SHOW CREATE. Note: basic.test, stopword.test and versioning.test do not require debug for 'vers' combination. This is controlled by $modify_create_table in maybe_versioning.inc and these tests run WITH SYSTEM VERSIONING explicitly which allows to test 'vers' combination on non-debug builds. 'vers_trx' like 'vers' sets sysvers_force_trx and sysvers_hide. That tests FTS with trx_id-based System Versioning. 'orig' works like before: no System Versioning is added, no debug is required. Upgrade/downgrade test for System Versioning is done by innodb_fts.versioning. It has 2 combinations: 'prepare' makes binaries in std_data (requires old server and OLD_BINDIR). It tests upgrade/downgrade against old server as well. 'upgrade' tests upgrade against binaries in std_data. Cleanups: Removed innodb-fts-stopword.test as it duplicates stopword.test --- mysql-test/include/have_gzip.inc | 6 + .../include/maybe_versioning.combinations | 7 + mysql-test/include/maybe_versioning.inc | 47 ++ .../std_data/versioning/articles.frm.gz | Bin 0 -> 287 bytes .../std_data/versioning/articles2.frm.gz | Bin 0 -> 291 bytes mysql-test/std_data/versioning/ibdata1.gz | Bin 0 -> 51165 bytes .../std_data/versioning/user_stopword.frm.gz | Bin 0 -> 199 bytes mysql-test/suite/innodb_fts/r/basic.result | 6 - .../innodb_fts/r/innodb-fts-stopword.result | 757 ------------------ .../suite/innodb_fts/r/stopword,vers.rdiff | 192 +++++ mysql-test/suite/innodb_fts/r/stopword.result | 12 +- .../innodb_fts/r/versioning,prepare.result | 695 ++++++++++++++++ .../suite/innodb_fts/r/versioning.result | 303 +++++++ mysql-test/suite/innodb_fts/t/basic.inc | 264 ++++++ mysql-test/suite/innodb_fts/t/basic.test | 251 +----- .../suite/innodb_fts/t/crash_recovery.test | 34 + mysql-test/suite/innodb_fts/t/create.test | 1 + mysql-test/suite/innodb_fts/t/fulltext2.test | 1 + mysql-test/suite/innodb_fts/t/fulltext3.test | 1 + .../suite/innodb_fts/t/fulltext_cache.test | 1 + .../suite/innodb_fts/t/fulltext_distinct.test | 1 + .../innodb_fts/t/fulltext_left_join.test | 1 + .../suite/innodb_fts/t/fulltext_multi.test | 1 + .../suite/innodb_fts/t/fulltext_order_by.test | 1 + .../suite/innodb_fts/t/fulltext_update.test | 1 + .../suite/innodb_fts/t/fulltext_var.test | 1 + .../suite/innodb_fts/t/innodb-fts-ddl.test | 1 + .../suite/innodb_fts/t/innodb-fts-fic.test | 1 + .../innodb_fts/t/innodb-fts-stopword.opt | 1 - .../innodb_fts/t/innodb-fts-stopword.test | 664 --------------- .../innodb_fts/t/innodb_ft_aux_table.test | 1 + .../t/innodb_fts_large_records.test | 1 + .../t/innodb_fts_multiple_index.test | 1 + .../innodb_fts/t/innodb_fts_proximity.test | 1 + .../t/innodb_fts_result_cache_limit.test | 1 + .../t/innodb_fts_stopword_charset.test | 1 + .../innodb_fts/t/innodb_fts_transaction.test | 1 + mysql-test/suite/innodb_fts/t/misc_debug.test | 1 + mysql-test/suite/innodb_fts/t/stopword.inc | 55 ++ mysql-test/suite/innodb_fts/t/stopword.test | 100 +-- mysql-test/suite/innodb_fts/t/sync.test | 1 + mysql-test/suite/innodb_fts/t/sync_block.test | 1 + mysql-test/suite/innodb_fts/t/sync_ddl.test | 1 + .../innodb_fts/t/versioning.combinations | 2 + mysql-test/suite/innodb_fts/t/versioning.opt | 2 + mysql-test/suite/innodb_fts/t/versioning.test | 126 +++ mysql-test/suite/versioning/r/alter.result | 5 + mysql-test/suite/versioning/r/debug.result | 4 +- mysql-test/suite/versioning/r/delete.result | 1 - .../suite/versioning/r/delete_history.result | 22 + mysql-test/suite/versioning/r/foreign.result | 37 + mysql-test/suite/versioning/t/alter.test | 2 + .../suite/versioning/t/delete_history.test | 25 + mysql-test/suite/versioning/t/foreign.test | 33 + sql/sql_show.cc | 2 +- storage/innobase/dict/dict0mem.cc | 14 + storage/innobase/fts/fts0fts.cc | 147 +++- storage/innobase/handler/ha_innodb.cc | 48 +- storage/innobase/handler/handler0alter.cc | 32 +- storage/innobase/include/dict0mem.h | 3 + storage/innobase/include/fts0fts.h | 17 +- storage/innobase/include/row0ins.h | 1 - storage/innobase/include/row0upd.h | 16 +- storage/innobase/row/row0ins.cc | 107 ++- storage/innobase/row/row0merge.cc | 33 +- storage/innobase/row/row0mysql.cc | 9 +- storage/innobase/row/row0upd.cc | 13 + 67 files changed, 2269 insertions(+), 1849 deletions(-) create mode 100644 mysql-test/include/have_gzip.inc create mode 100644 mysql-test/include/maybe_versioning.combinations create mode 100644 mysql-test/include/maybe_versioning.inc create mode 100644 mysql-test/std_data/versioning/articles.frm.gz create mode 100644 mysql-test/std_data/versioning/articles2.frm.gz create mode 100644 mysql-test/std_data/versioning/ibdata1.gz create mode 100644 mysql-test/std_data/versioning/user_stopword.frm.gz delete mode 100644 mysql-test/suite/innodb_fts/r/innodb-fts-stopword.result create mode 100644 mysql-test/suite/innodb_fts/r/stopword,vers.rdiff create mode 100644 mysql-test/suite/innodb_fts/r/versioning,prepare.result create mode 100644 mysql-test/suite/innodb_fts/r/versioning.result create mode 100644 mysql-test/suite/innodb_fts/t/basic.inc delete mode 100644 mysql-test/suite/innodb_fts/t/innodb-fts-stopword.opt delete mode 100644 mysql-test/suite/innodb_fts/t/innodb-fts-stopword.test create mode 100644 mysql-test/suite/innodb_fts/t/stopword.inc create mode 100644 mysql-test/suite/innodb_fts/t/versioning.combinations create mode 100644 mysql-test/suite/innodb_fts/t/versioning.opt create mode 100644 mysql-test/suite/innodb_fts/t/versioning.test diff --git a/mysql-test/include/have_gzip.inc b/mysql-test/include/have_gzip.inc new file mode 100644 index 00000000000..09f282b73de --- /dev/null +++ b/mysql-test/include/have_gzip.inc @@ -0,0 +1,6 @@ +--error 0,1,127 +--exec gzip --version > /dev/null 2> /dev/null +if ($sys_errno) +{ + --skip Requires gzip executable +} diff --git a/mysql-test/include/maybe_versioning.combinations b/mysql-test/include/maybe_versioning.combinations new file mode 100644 index 00000000000..246ad30ce7e --- /dev/null +++ b/mysql-test/include/maybe_versioning.combinations @@ -0,0 +1,7 @@ +[orig] + +[vers] +system_versioning_alter_history=keep + +[vers_trx] +system_versioning_alter_history=keep diff --git a/mysql-test/include/maybe_versioning.inc b/mysql-test/include/maybe_versioning.inc new file mode 100644 index 00000000000..8a7d7dad44f --- /dev/null +++ b/mysql-test/include/maybe_versioning.inc @@ -0,0 +1,47 @@ +# include file for test files that can be run with and without debug +# having debug and non-debug tests. + +# If $modify_create_table is true CREATE statement must be evaluated with +# $create_options that adds WITH SYSTEM VERSIONING to the statement. Otherwise +# system versioning is added implicitly via debug options. The second variant +# can easily be added to any test but works only for debug builds. + +if ($modify_create_table) +{ + if ($MTR_COMBINATION_VERS) + { + let $create_options= `select ' WITH SYSTEM VERSIONING'`; + } + + if ($MTR_COMBINATION_VERS_TRX) + { + --skip Not tested + } +} + +if (!$modify_create_table) +{ + let $have_debug=`select version() like '%debug%'`; + + if ($MTR_COMBINATION_VERS) + { + if (!$have_debug) + { + --skip Requires debug + } + --disable_query_log + set debug_dbug="d,sysvers_force_trx,sysvers_hide"; + --enable_query_log + } + + if ($MTR_COMBINATION_VERS_TRX) + { + if (!$have_debug) + { + --skip Requires debug + } + --disable_query_log + set debug_dbug="d,sysvers_force,sysvers_hide"; + --enable_query_log + } +} diff --git a/mysql-test/std_data/versioning/articles.frm.gz b/mysql-test/std_data/versioning/articles.frm.gz new file mode 100644 index 0000000000000000000000000000000000000000..fd3a0a8c0d4bb79cb9084b872f25649f51b36b45 GIT binary patch literal 287 zcmV+)0pR{0iwFo0`&(lI17UJ>X=7|XtOib25 ziiw2*te%^J2}m+F07)sJ3f6`P3=CZi>D&zTpVepJW2`(1E zAO;Ibab`U4S=Vz>#a7Jxud5i0NiN#K8G l3bZyz%1^2MUzA@SUtE${R03wD=B4~+003?WMN`rS006iX=7|Ja&ydW($Z&~`f#DJJGX^+d z@?hX(U|C#8wlgvaz*Pxse_P=lc0=%OgG0$NYrmgKEG*0nEDVhxeN0T& zK#GZlfq@Um<7Qw2l8g;NQVOVowc!B+Ll+x6!%BveU>T+cpbHopPB1VxoCliQ!pQJH zAjs3#F(~qXW=h3>hEXsIM!{eNBPDOLF?iS25?yqWc`5%NHN?5RSQ6tAWYx^k^rzO p_+OG)l9T#BDLeOkXf!VR+md~D>I-6cQvYtv~ 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

C2)~{vK2P!}8B_X5Z<3 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 yN&qE*5Ja%aF*x$RNYSz#zb& z#{dUR91NTc46Gm~2TV)=h(ES7f@!G8_LqjNVK)TdHaL_Vv-bO$#KOYJz{JqV%)rF7 z9%d55f4F)Ci#Wi>;F*_~@8SgEU7#e_> z9};a+42ld4T_BdAB2+*FN#K83Voqu5|Dycz_~Mepq7pDGH815q0{{gFMB*F*0085C BR?Pqa literal 0 HcmV?d00001 diff --git a/mysql-test/suite/innodb_fts/r/basic.result b/mysql-test/suite/innodb_fts/r/basic.result index a98de60674a..a8ab0c043e4 100644 --- a/mysql-test/suite/innodb_fts/r/basic.result +++ b/mysql-test/suite/innodb_fts/r/basic.result @@ -5,12 +5,6 @@ body TEXT, FULLTEXT (title,body) ) ENGINE=InnoDB; ERROR HY000: Cannot create FULLTEXT index on temporary InnoDB table -CREATE TABLE articles ( -id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, -title VARCHAR(200), -body TEXT, -FULLTEXT (title,body) -) ENGINE=InnoDB; INSERT INTO articles (title,body) VALUES ('MySQL Tutorial','DBMS stands for DataBase ...') , ('How To Use MySQL Well','After you went through a ...'), diff --git a/mysql-test/suite/innodb_fts/r/innodb-fts-stopword.result b/mysql-test/suite/innodb_fts/r/innodb-fts-stopword.result deleted file mode 100644 index 8cc3cbe5ae3..00000000000 --- a/mysql-test/suite/innodb_fts/r/innodb-fts-stopword.result +++ /dev/null @@ -1,757 +0,0 @@ -select * from information_schema.innodb_ft_default_stopword; -value -a -about -an -are -as -at -be -by -com -de -en -for -from -how -i -in -is -it -la -of -on -or -that -the -this -to -was -what -when -where -who -will -with -und -the -www -CREATE TABLE articles ( -id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, -title VARCHAR(200), -body TEXT, -FULLTEXT (title,body) -) ENGINE=InnoDB; -INSERT INTO articles (title,body) VALUES -('MySQL Tutorial','DBMS stands for DataBase ...') , -('How To Use MySQL Well','After you went through a ...'), -('Optimizing MySQL','In this tutorial we will show ...'), -('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), -('MySQL vs. YourSQL','In the following database comparison ...'), -('MySQL Security','When configured properly, MySQL ...'); -SELECT * FROM articles WHERE MATCH (title,body) -AGAINST ('the' IN NATURAL LANGUAGE MODE); -id title body -select @@innodb_ft_server_stopword_table; -@@innodb_ft_server_stopword_table -NULL -select @@innodb_ft_enable_stopword; -@@innodb_ft_enable_stopword -1 -select @@innodb_ft_user_stopword_table; -@@innodb_ft_user_stopword_table -NULL -set global innodb_ft_server_stopword_table = "not_defined"; -ERROR 42000: Variable 'innodb_ft_server_stopword_table' can't be set to the value of 'not_defined' -create table user_stopword(value varchar(30)) engine = innodb; -set global innodb_ft_server_stopword_table = "test/user_stopword"; -drop index title on articles; -create fulltext index idx on articles(title, body); -SELECT * FROM articles WHERE MATCH (title,body) -AGAINST ('the' IN NATURAL LANGUAGE MODE); -id title body -5 MySQL vs. YourSQL In the following database comparison ... -CREATE TABLE articles_2 ( -id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, -title VARCHAR(200), -body TEXT, -FULLTEXT (title,body) -) ENGINE=InnoDB; -INSERT INTO articles_2 (title, body) -VALUES ('test for stopwords','this is it...'); -SELECT * FROM articles_2 WHERE MATCH (title,body) -AGAINST ('this' IN NATURAL LANGUAGE MODE); -id title body -1 test for stopwords this is it... -insert into user_stopword values("this"); -CREATE TABLE articles_3 ( -id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, -title VARCHAR(200), -body TEXT, -FULLTEXT (title,body) -) ENGINE=InnoDB; -INSERT INTO articles_3 (title, body) -VALUES ('test for stopwords','this is it...'); -SELECT * FROM articles_3 WHERE MATCH (title,body) -AGAINST ('this' IN NATURAL LANGUAGE MODE); -id title body -create table user_stopword_session(value varchar(30)) engine = innodb; -insert into user_stopword_session values("session"); -set session innodb_ft_user_stopword_table="test/user_stopword_session"; -CREATE TABLE articles_4 ( -id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, -title VARCHAR(200), -body TEXT, -FULLTEXT (title,body) -) ENGINE=InnoDB; -INSERT INTO articles_4 (title, body) -VALUES ('test for session stopwords','this should also be excluded...'); -SELECT * FROM articles_4 WHERE MATCH (title,body) -AGAINST ('session' IN NATURAL LANGUAGE MODE); -id title body -SELECT * FROM articles_4 WHERE MATCH (title,body) -AGAINST ('this' IN NATURAL LANGUAGE MODE); -id title body -1 test for session stopwords this should also be excluded... -connect con1,localhost,root,,; -CREATE TABLE articles_5 ( -id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, -title VARCHAR(200), -body TEXT, -FULLTEXT (title,body) -) ENGINE=InnoDB; -INSERT INTO articles_5 (title, body) -VALUES ('test for session stopwords','this should also be excluded...'); -SELECT * FROM articles_5 WHERE MATCH (title,body) -AGAINST ('session' IN NATURAL LANGUAGE MODE); -id title body -1 test for session stopwords this should also be excluded... -connection default; -drop table articles; -drop table articles_2; -drop table articles_3; -drop table articles_4; -drop table articles_5; -drop table user_stopword; -drop table user_stopword_session; -SET GLOBAL innodb_ft_enable_stopword=1; -SET GLOBAL innodb_ft_server_stopword_table=default; -CREATE TABLE articles ( -id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, -title VARCHAR(200), -body TEXT, -FULLTEXT `idx` (title,body) -) ENGINE=InnoDB; -SHOW CREATE TABLE articles; -Table Create Table -articles CREATE TABLE `articles` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(200) DEFAULT NULL, - `body` text DEFAULT NULL, - PRIMARY KEY (`id`), - FULLTEXT KEY `idx` (`title`,`body`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci -INSERT INTO articles (title,body) VALUES -('MySQL from Tutorial','DBMS stands for DataBase ...') , -('when To Use MySQL Well','After that you went through a ...'), -('where will Optimizing MySQL','In what tutorial we will show ...'), -('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), -('MySQL vs. YourSQL','In the following database comparison ...'), -('MySQL Security','When configured properly, MySQL ...'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will"); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("when"); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("what" WITH QUERY EXPANSION); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("whe*" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+what +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+from" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+where +(show what)" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@6' IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@9' IN BOOLEAN MODE); -id title body -INSERT INTO articles(title,body) values ('the record will' , 'not index the , will words'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOLEAN MODE); -id title body -UPDATE articles SET title = "update the record" , body = 'to see will is indexed or not' -WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -UPDATE articles SET title = "update the record" , body = 'to see will is indexed or not' -WHERE id = 7; -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -id title body -DELETE FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE id = 7; -id title body -7 update the record to see will is indexed or not -DELETE FROM articles WHERE id = 7; -SET SESSION innodb_ft_enable_stopword = 0; -select @@innodb_ft_enable_stopword; -@@innodb_ft_enable_stopword -0 -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will"); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("when"); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("what" WITH QUERY EXPANSION); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("whe*" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+what +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+from" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+where +(show what)" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@6' IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@9' IN BOOLEAN MODE); -id title body -INSERT INTO articles(title,body) values ('the record will' , 'not index the , will words'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOLEAN MODE); -id title body -UPDATE articles SET title = "update the record" , body = 'to see will is indexed or not' -WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -UPDATE articles SET title = "update the record" , body = 'to see will is indexed or not' -WHERE id = 8; -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -id title body -SELECT * FROM articles WHERE id = 8; -id title body -8 update the record to see will is indexed or not -DELETE FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE id = 8; -id title body -8 update the record to see will is indexed or not -DELETE FROM articles WHERE id = 8; -ALTER TABLE articles DROP INDEX idx; -SHOW CREATE TABLE articles; -Table Create Table -articles CREATE TABLE `articles` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(200) DEFAULT NULL, - `body` text DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -ANALYZE TABLE articles; -Table Op Msg_type Msg_text -test.articles analyze status OK -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will"); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("when"); -id title body -2 when To Use MySQL Well After that you went through a ... -6 MySQL Security When configured properly, MySQL ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("what" WITH QUERY EXPANSION); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -1 MySQL from Tutorial DBMS stands for DataBase ... -6 MySQL Security When configured properly, MySQL ... -2 when To Use MySQL Well After that you went through a ... -4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... -5 MySQL vs. YourSQL In the following database comparison ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("whe*" IN BOOLEAN MODE); -id title body -2 when To Use MySQL Well After that you went through a ... -3 where will Optimizing MySQL In what tutorial we will show ... -6 MySQL Security When configured properly, MySQL ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+what +will" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+from" IN BOOLEAN MODE); -id title body -1 MySQL from Tutorial DBMS stands for DataBase ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+where +(show what)" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@6' IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@9' IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -INSERT INTO articles(title,body) values ('the record will' , 'not index the , will words'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -id title body -9 the record will not index the , will words -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOLEAN MODE); -id title body -9 the record will not index the , will words -UPDATE articles SET title = "update the record" , body = 'to see will is indexed or not' -WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT COUNT(*),max(id) FROM articles; -COUNT(*) max(id) -7 9 -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -id title body -9 update the record to see will is indexed or not -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -9 update the record to see will is indexed or not -DELETE FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE id = 9; -id title body -DROP TABLE articles; -SET SESSION innodb_ft_enable_stopword=1; -SET GLOBAL innodb_ft_server_stopword_table=default; -SET SESSION innodb_ft_user_stopword_table=default; -select @@innodb_ft_server_stopword_table; -@@innodb_ft_server_stopword_table -NULL -select @@innodb_ft_enable_stopword; -@@innodb_ft_enable_stopword -1 -select @@innodb_ft_user_stopword_table; -@@innodb_ft_user_stopword_table -NULL -CREATE TABLE articles ( -id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, -title VARCHAR(200), -body TEXT, -FULLTEXT `idx` (title,body) -) ENGINE=InnoDB; -INSERT INTO articles (title,body) VALUES -('MySQL from Tutorial','DBMS stands for DataBase ...') , -('when To Use MySQL Well','After that you went through a ...'), -('where will Optimizing MySQL','In what tutorial we will show ...'), -('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), -('MySQL vs. YourSQL','In the following database comparison ...'), -('MySQL Security','When configured properly, MySQL ...'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -id title body -create table user_stopword(value varchar(30)) engine = innodb; -set session innodb_ft_user_stopword_table = "test/user_stopword"; -create table server_stopword(value varchar(30)) engine = innodb; -set global innodb_ft_server_stopword_table = "test/server_stopword"; -insert into user_stopword values("this"),("will"),("the"); -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -id title body -insert into server_stopword values("what"),("where"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -DELETE FROM user_stopword; -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -insert into user_stopword values("this"),("will"),("the"); -ALTER TABLE articles DROP INDEX idx; -SET SESSION innodb_ft_enable_stopword = 0; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SET SESSION innodb_ft_enable_stopword = 1; -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -id title body -SET SESSION innodb_ft_enable_stopword = 1; -SET SESSION innodb_ft_user_stopword_table = default; -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -DROP TABLE articles,user_stopword,server_stopword; -SET SESSION innodb_ft_enable_stopword=1; -SET GLOBAL innodb_ft_server_stopword_table=default; -SET SESSION innodb_ft_user_stopword_table=default; -select @@innodb_ft_server_stopword_table; -@@innodb_ft_server_stopword_table -NULL -select @@innodb_ft_enable_stopword; -@@innodb_ft_enable_stopword -1 -select @@innodb_ft_user_stopword_table; -@@innodb_ft_user_stopword_table -NULL -CREATE TABLE articles ( -id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, -title VARCHAR(200), -body TEXT, -FULLTEXT `idx` (title,body) -) ENGINE=InnoDB; -SHOW CREATE TABLE articles; -Table Create Table -articles CREATE TABLE `articles` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(200) DEFAULT NULL, - `body` text DEFAULT NULL, - PRIMARY KEY (`id`), - FULLTEXT KEY `idx` (`title`,`body`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci -INSERT INTO articles (title,body) VALUES -('MySQL from Tutorial','DBMS stands for DataBase ...') , -('when To Use MySQL Well','After that you went through a ...'), -('where will Optimizing MySQL','In what tutorial we will show ...'), -('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), -('MySQL vs. YourSQL','In the following database comparison ...'), -('MySQL Security','When configured properly, MySQL ...'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -id title body -create table user_stopword(value varchar(30)) engine = innodb; -set session innodb_ft_user_stopword_table = "test/user_stopword"; -insert into user_stopword values("mysqld"),("DBMS"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+DBMS +mysql" IN BOOLEAN MODE); -id title body -1 MySQL from Tutorial DBMS stands for DataBase ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysqld'); -id title body -4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+DBMS +mysql" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysqld'); -id title body -set session innodb_ft_user_stopword_table = default; -create table server_stopword(value varchar(30)) engine = innodb; -set global innodb_ft_server_stopword_table = "test/server_stopword"; -insert into server_stopword values("root"),("properly"); -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+root +mysql" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('properly'); -id title body -set session innodb_ft_user_stopword_table = "test/user_stopword"; -set global innodb_ft_server_stopword_table = "test/server_stopword"; -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+root +mysql" IN BOOLEAN MODE); -id title body -4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('properly'); -id title body -6 MySQL Security When configured properly, MySQL ... -set session innodb_ft_user_stopword_table = "test/user_stopword"; -DELETE FROM user_stopword; -set global innodb_ft_server_stopword_table = "test/server_stopword"; -DELETE FROM server_stopword; -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+root +mysql" IN BOOLEAN MODE); -id title body -4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('properly'); -id title body -6 MySQL Security When configured properly, MySQL ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+DBMS +mysql" IN BOOLEAN MODE); -id title body -1 MySQL from Tutorial DBMS stands for DataBase ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysqld'); -id title body -4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... -DROP TABLE articles,user_stopword,server_stopword; -SET SESSION innodb_ft_enable_stopword=1; -SET GLOBAL innodb_ft_server_stopword_table=default; -SET SESSION innodb_ft_user_stopword_table=default; -CREATE TABLE articles ( -id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, -title VARCHAR(200), -body TEXT, -FULLTEXT `idx` (title,body) -) ENGINE=InnoDB; -SHOW CREATE TABLE articles; -Table Create Table -articles CREATE TABLE `articles` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(200) DEFAULT NULL, - `body` text DEFAULT NULL, - PRIMARY KEY (`id`), - FULLTEXT KEY `idx` (`title`,`body`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci -INSERT INTO articles (title,body) VALUES -('MySQL from Tutorial','DBMS stands for DataBase ...') , -('when To Use MySQL Well','After that you went through a ...'), -('where will Optimizing MySQL','In what tutorial we will show ...'), -('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), -('MySQL vs. YourSQL','In the following database comparison ...'), -('MySQL Security','When configured properly, MySQL ...'); -SET SESSION innodb_ft_enable_stopword = 0; -select @@innodb_ft_enable_stopword; -@@innodb_ft_enable_stopword -0 -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -connection con1; -select @@innodb_ft_enable_stopword; -@@innodb_ft_enable_stopword -1 -ANALYZE TABLE articles; -Table Op Msg_type Msg_text -test.articles analyze status OK -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will"); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("when"); -id title body -2 when To Use MySQL Well After that you went through a ... -6 MySQL Security When configured properly, MySQL ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("what" WITH QUERY EXPANSION); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -1 MySQL from Tutorial DBMS stands for DataBase ... -6 MySQL Security When configured properly, MySQL ... -2 when To Use MySQL Well After that you went through a ... -4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... -5 MySQL vs. YourSQL In the following database comparison ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("whe*" IN BOOLEAN MODE); -id title body -2 when To Use MySQL Well After that you went through a ... -3 where will Optimizing MySQL In what tutorial we will show ... -6 MySQL Security When configured properly, MySQL ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+what +will" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+from" IN BOOLEAN MODE); -id title body -1 MySQL from Tutorial DBMS stands for DataBase ... -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+where +(show what)" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@6' IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@9' IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SET SESSION innodb_ft_enable_stopword = 1; -select @@innodb_ft_enable_stopword; -@@innodb_ft_enable_stopword -1 -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will"); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("when"); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("what" WITH QUERY EXPANSION); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("whe*" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+what +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+from" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+where +(show what)" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@6' IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@9' IN BOOLEAN MODE); -id title body -connection default; -select @@innodb_ft_enable_stopword; -@@innodb_ft_enable_stopword -0 -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will"); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("when"); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("what" WITH QUERY EXPANSION); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("whe*" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+what +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+from" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+where +(show what)" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@6' IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@9' IN BOOLEAN MODE); -id title body -INSERT INTO articles(title,body) values ('the record will' , 'not index the , will words'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOLEAN MODE); -id title body -SET SESSION innodb_ft_enable_stopword = 1; -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOLEAN MODE); -id title body -connection con1; -SET SESSION innodb_ft_enable_stopword = 1; -create table user_stopword(value varchar(30)) engine = innodb; -set session innodb_ft_user_stopword_table = "test/user_stopword"; -insert into user_stopword values("this"),("will"),("the"); -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -id title body -connection default; -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -id title body -select @@innodb_ft_user_stopword_table; -@@innodb_ft_user_stopword_table -NULL -create table user_stopword_1(value varchar(30)) engine = innodb; -set session innodb_ft_user_stopword_table = "test/user_stopword_1"; -insert into user_stopword_1 values("when"); -SET SESSION innodb_ft_enable_stopword = 1; -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+when" IN BOOLEAN MODE); -id title body -2 when To Use MySQL Well After that you went through a ... -6 MySQL Security When configured properly, MySQL ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('when'); -id title body -2 when To Use MySQL Well After that you went through a ... -6 MySQL Security When configured properly, MySQL ... -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+when" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('when'); -id title body -connection con1; -SET SESSION innodb_ft_enable_stopword = 1; -SET SESSION innodb_ft_user_stopword_table=default; -select @@innodb_ft_user_stopword_table; -@@innodb_ft_user_stopword_table -NULL -select @@innodb_ft_server_stopword_table; -@@innodb_ft_server_stopword_table -NULL -create table server_stopword(value varchar(30)) engine = innodb; -SET GLOBAL innodb_ft_server_stopword_table = "test/server_stopword"; -select @@innodb_ft_server_stopword_table; -@@innodb_ft_server_stopword_table -test/server_stopword -insert into server_stopword values("when"),("the"); -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+when" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('the'); -id title body -disconnect con1; -connection default; -SET SESSION innodb_ft_enable_stopword = 1; -SET SESSION innodb_ft_user_stopword_table=default; -select @@innodb_ft_server_stopword_table; -@@innodb_ft_server_stopword_table -test/server_stopword -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+will +where" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('where'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -insert into server_stopword values("where"),("will"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+will +where" IN BOOLEAN MODE); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('where'); -id title body -3 where will Optimizing MySQL In what tutorial we will show ... -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+when" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('the'); -id title body -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+will +where" IN BOOLEAN MODE); -id title body -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('where'); -id title body -DROP TABLE articles,user_stopword,user_stopword_1,server_stopword; -SET SESSION innodb_ft_enable_stopword=1; -SET GLOBAL innodb_ft_server_stopword_table=default; -SET SESSION innodb_ft_user_stopword_table=default; diff --git a/mysql-test/suite/innodb_fts/r/stopword,vers.rdiff b/mysql-test/suite/innodb_fts/r/stopword,vers.rdiff new file mode 100644 index 00000000000..7405c47c41d --- /dev/null +++ b/mysql-test/suite/innodb_fts/r/stopword,vers.rdiff @@ -0,0 +1,192 @@ +--- stopword.result ++++ stopword,vers.reject +@@ -46,7 +46,7 @@ + title VARCHAR(200), + body TEXT, + FULLTEXT (title,body) +-) ENGINE=InnoDB; ++) WITH SYSTEM VERSIONING ENGINE=InnoDB; + INSERT INTO articles (title,body) VALUES + ('MySQL Tutorial','DBMS stands for DataBase ...') , + ('How To Use MySQL Well','After you went through a ...'), +@@ -60,7 +60,7 @@ + set global innodb_ft_server_stopword_table = "not_defined"; + ERROR 42000: Variable 'innodb_ft_server_stopword_table' can't be set to the value of 'not_defined' + set global innodb_ft_server_stopword_table = NULL; +-create table user_stopword(value varchar(30)) engine = innodb; ++create table user_stopword(value varchar(30)) WITH SYSTEM VERSIONING engine = innodb; + set global innodb_ft_server_stopword_table = "test/user_stopword"; + drop index title on articles; + create fulltext index idx on articles(title, body); +@@ -73,7 +73,7 @@ + title VARCHAR(200), + body TEXT, + FULLTEXT (title,body) +-) ENGINE=InnoDB; ++) WITH SYSTEM VERSIONING ENGINE=InnoDB; + INSERT INTO articles_2 (title, body) + VALUES ('test for stopwords','this is it...'); + SELECT * FROM articles_2 WHERE MATCH (title,body) +@@ -88,13 +88,13 @@ + title VARCHAR(200), + body TEXT, + FULLTEXT (title,body) +-) ENGINE=InnoDB; ++) WITH SYSTEM VERSIONING ENGINE=InnoDB; + INSERT INTO articles_3 (title, body) + VALUES ('test for stopwords','this is it...'); + SELECT * FROM articles_3 WHERE MATCH (title,body) + AGAINST ('this' IN NATURAL LANGUAGE MODE); + id title body +-create table user_stopword_session(value varchar(30)) engine = innodb; ++create table user_stopword_session(value varchar(30)) WITH SYSTEM VERSIONING engine = innodb; + insert into user_stopword values("this"); + delete from user_stopword; + insert into user_stopword_session values("session"); +@@ -104,7 +104,7 @@ + title VARCHAR(200), + body TEXT, + FULLTEXT (title,body) +-) ENGINE=InnoDB; ++) WITH SYSTEM VERSIONING ENGINE=InnoDB; + INSERT INTO articles_4 (title, body) + VALUES ('test for session stopwords','this should also be excluded...'); + SELECT * FROM articles_4 WHERE MATCH (title,body) +@@ -120,7 +120,7 @@ + title VARCHAR(200), + body TEXT, + FULLTEXT (title,body) +-) ENGINE=InnoDB; ++) WITH SYSTEM VERSIONING ENGINE=InnoDB; + INSERT INTO articles_5 (title, body) + VALUES ('test for session stopwords','this should also be excluded...'); + SELECT * FROM articles_5 WHERE MATCH (title,body) +@@ -142,7 +142,7 @@ + title VARCHAR(200), + body TEXT, + FULLTEXT `idx` (title,body) +-) ENGINE=InnoDB; ++) WITH SYSTEM VERSIONING ENGINE=InnoDB; + SHOW CREATE TABLE articles; + Table Create Table + articles CREATE TABLE `articles` ( +@@ -151,7 +151,7 @@ + `body` text DEFAULT NULL, + PRIMARY KEY (`id`), + FULLTEXT KEY `idx` (`title`,`body`) +-) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ++) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci WITH SYSTEM VERSIONING + INSERT INTO articles (title,body) VALUES + ('MySQL from Tutorial','DBMS stands for DataBase ...') , + ('when To Use MySQL Well','After that you went through a ...'), +@@ -248,7 +248,7 @@ + `title` varchar(200) DEFAULT NULL, + `body` text DEFAULT NULL, + PRIMARY KEY (`id`) +-) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ++) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci WITH SYSTEM VERSIONING + ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); + ANALYZE TABLE articles; + Table Op Msg_type Msg_text +@@ -320,7 +320,7 @@ + title VARCHAR(200), + body TEXT, + FULLTEXT `idx` (title,body) +-) ENGINE=InnoDB; ++) WITH SYSTEM VERSIONING ENGINE=InnoDB; + INSERT INTO articles (title,body) VALUES + ('MySQL from Tutorial','DBMS stands for DataBase ...') , + ('when To Use MySQL Well','After that you went through a ...'), +@@ -332,9 +332,9 @@ + id title body + SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); + id title body +-create table user_stopword(value varchar(30)) engine = innodb; ++create table user_stopword(value varchar(30)) WITH SYSTEM VERSIONING engine = innodb; + set session innodb_ft_user_stopword_table = "test/user_stopword"; +-create table server_stopword(value varchar(30)) engine = innodb; ++create table server_stopword(value varchar(30)) WITH SYSTEM VERSIONING engine = innodb; + set global innodb_ft_server_stopword_table = "test/server_stopword"; + insert into user_stopword values("when"),("where"); + delete from user_stopword; +@@ -419,7 +419,7 @@ + title VARCHAR(200), + body TEXT, + FULLTEXT `idx` (title,body) +-) ENGINE=InnoDB; ++) WITH SYSTEM VERSIONING ENGINE=InnoDB; + SHOW CREATE TABLE articles; + Table Create Table + articles CREATE TABLE `articles` ( +@@ -428,7 +428,7 @@ + `body` text DEFAULT NULL, + PRIMARY KEY (`id`), + FULLTEXT KEY `idx` (`title`,`body`) +-) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ++) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci WITH SYSTEM VERSIONING + INSERT INTO articles (title,body) VALUES + ('MySQL from Tutorial','DBMS stands for DataBase ...') , + ('when To Use MySQL Well','After that you went through a ...'), +@@ -440,7 +440,7 @@ + id title body + SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); + id title body +-create table user_stopword(value varchar(30)) engine = innodb; ++create table user_stopword(value varchar(30)) WITH SYSTEM VERSIONING engine = innodb; + set session innodb_ft_user_stopword_table = "test/user_stopword"; + insert into user_stopword values("mysqld"),("DBMS"); + SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); +@@ -466,7 +466,7 @@ + SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysqld'); + id title body + set session innodb_ft_user_stopword_table = default; +-create table server_stopword(value varchar(30)) engine = innodb; ++create table server_stopword(value varchar(30)) WITH SYSTEM VERSIONING engine = innodb; + set global innodb_ft_server_stopword_table = "test/server_stopword"; + insert into server_stopword values("root"),("properly"); + ALTER TABLE articles DROP INDEX idx; +@@ -530,7 +530,7 @@ + title VARCHAR(200), + body TEXT, + FULLTEXT `idx` (title,body) +-) ENGINE=InnoDB; ++) WITH SYSTEM VERSIONING ENGINE=InnoDB; + SHOW CREATE TABLE articles; + Table Create Table + articles CREATE TABLE `articles` ( +@@ -539,7 +539,7 @@ + `body` text DEFAULT NULL, + PRIMARY KEY (`id`), + FULLTEXT KEY `idx` (`title`,`body`) +-) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ++) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci WITH SYSTEM VERSIONING + INSERT INTO articles (title,body) VALUES + ('MySQL from Tutorial','DBMS stands for DataBase ...') , + ('when To Use MySQL Well','After that you went through a ...'), +@@ -656,7 +656,7 @@ + "In connection 1" + connection con1; + SET SESSION innodb_ft_enable_stopword = 1; +-create table user_stopword(value varchar(30)) engine = innodb; ++create table user_stopword(value varchar(30)) WITH SYSTEM VERSIONING engine = innodb; + set session innodb_ft_user_stopword_table = "test/user_stopword"; + insert into user_stopword values("this"),("will"),("the"); + ALTER TABLE articles DROP INDEX idx; +@@ -674,7 +674,7 @@ + select @@innodb_ft_user_stopword_table; + @@innodb_ft_user_stopword_table + NULL +-create table user_stopword_1(value varchar(30)) engine = innodb; ++create table user_stopword_1(value varchar(30)) WITH SYSTEM VERSIONING engine = innodb; + set session innodb_ft_user_stopword_table = "test/user_stopword_1"; + insert into user_stopword_1 values("when"); + SET SESSION innodb_ft_enable_stopword = 1; +@@ -702,7 +702,7 @@ + select @@innodb_ft_server_stopword_table; + @@innodb_ft_server_stopword_table + NULL +-create table server_stopword(value varchar(30)) engine = innodb; ++create table server_stopword(value varchar(30)) WITH SYSTEM VERSIONING engine = innodb; + SET GLOBAL innodb_ft_server_stopword_table = "test/server_stopword"; + select @@innodb_ft_server_stopword_table; + @@innodb_ft_server_stopword_table diff --git a/mysql-test/suite/innodb_fts/r/stopword.result b/mysql-test/suite/innodb_fts/r/stopword.result index 1465e1713fd..8f3cf9d6a20 100644 --- a/mysql-test/suite/innodb_fts/r/stopword.result +++ b/mysql-test/suite/innodb_fts/r/stopword.result @@ -1,3 +1,6 @@ +SET @innodb_ft_server_stopword_table_orig=@@innodb_ft_server_stopword_table; +SET @innodb_ft_enable_stopword_orig=@@innodb_ft_enable_stopword; +SET @innodb_ft_user_stopword_table_orig=@@innodb_ft_user_stopword_table; call mtr.add_suppression("\\[ERROR\\] InnoDB: user stopword table not_defined does not exist."); call mtr.add_suppression("\\[ERROR\\] InnoDB: user stopword table test/user_stopword_session does not exist."); select * from information_schema.innodb_ft_default_stopword; @@ -54,9 +57,6 @@ INSERT INTO articles (title,body) VALUES SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('the' IN NATURAL LANGUAGE MODE); id title body -SET @innodb_ft_server_stopword_table_orig=@@innodb_ft_server_stopword_table; -SET @innodb_ft_enable_stopword_orig=@@innodb_ft_enable_stopword; -SET @innodb_ft_user_stopword_table_orig=@@innodb_ft_user_stopword_table; set global innodb_ft_server_stopword_table = "not_defined"; ERROR 42000: Variable 'innodb_ft_server_stopword_table' can't be set to the value of 'not_defined' set global innodb_ft_server_stopword_table = NULL; @@ -80,6 +80,8 @@ SELECT * FROM articles_2 WHERE MATCH (title,body) AGAINST ('this' IN NATURAL LANGUAGE MODE); id title body 1 test for stopwords this is it... +insert into user_stopword values("the"); +delete from user_stopword; insert into user_stopword values("this"); CREATE TABLE articles_3 ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, @@ -93,6 +95,8 @@ SELECT * FROM articles_3 WHERE MATCH (title,body) AGAINST ('this' IN NATURAL LANGUAGE MODE); id title body create table user_stopword_session(value varchar(30)) engine = innodb; +insert into user_stopword values("this"); +delete from user_stopword; insert into user_stopword_session values("session"); set session innodb_ft_user_stopword_table="test/user_stopword_session"; CREATE TABLE articles_4 ( @@ -332,6 +336,8 @@ create table user_stopword(value varchar(30)) engine = innodb; set session innodb_ft_user_stopword_table = "test/user_stopword"; create table server_stopword(value varchar(30)) engine = innodb; set global innodb_ft_server_stopword_table = "test/server_stopword"; +insert into user_stopword values("when"),("where"); +delete from user_stopword; insert into user_stopword values("this"),("will"),("the"); ALTER TABLE articles DROP INDEX idx; ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); diff --git a/mysql-test/suite/innodb_fts/r/versioning,prepare.result b/mysql-test/suite/innodb_fts/r/versioning,prepare.result new file mode 100644 index 00000000000..ada4f30d80c --- /dev/null +++ b/mysql-test/suite/innodb_fts/r/versioning,prepare.result @@ -0,0 +1,695 @@ +# Upgrade test +CREATE TEMPORARY TABLE articles ( +id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, +title VARCHAR(200), +body TEXT, +FULLTEXT (title,body) +) ENGINE=InnoDB; +ERROR HY000: Cannot create FULLTEXT index on temporary InnoDB table +CREATE TABLE articles ( +id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, +title VARCHAR(200), +body TEXT, +FULLTEXT (title,body) +)with system versioning ENGINE=InnoDB; +INSERT INTO articles (title,body) VALUES +('MySQL Tutorial','DBMS stands for DataBase ...') , +('How To Use MySQL Well','After you went through a ...'), +('Optimizing MySQL','In this tutorial we will show ...'), +('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), +('MySQL vs. YourSQL','In the following database comparison ...'), +('MySQL Security','When configured properly, MySQL ...'); +INSERT INTO articles (title,body) VALUES +('test query expansion','for database ...'); +INSERT INTO articles (title,body) VALUES +('test proximity search, test, proximity and phrase', +'search, with proximity innodb'); +INSERT INTO articles (title,body) VALUES +('test my proximity fts new search, test, proximity and phrase', +'search, with proximity innodb'); +INSERT INTO articles (title,body) VALUES +('test more of proximity fts search, test, more proximity and phrase', +'search, with proximity innodb'); +call mtr.add_suppression("\\[ERROR\\] InnoDB: user stopword table not_defined does not exist."); +call mtr.add_suppression("\\[ERROR\\] InnoDB: user stopword table test/user_stopword_session does not exist."); +select * from information_schema.innodb_ft_default_stopword; +value +a +about +an +are +as +at +be +by +com +de +en +for +from +how +i +in +is +it +la +of +on +or +that +the +this +to +was +what +when +where +who +will +with +und +the +www +CREATE TABLE articles2 ( +id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, +title VARCHAR(200), +body TEXT, +FULLTEXT (title,body) +)with system versioning ENGINE=InnoDB; +INSERT INTO articles2 (title,body) VALUES +('MySQL Tutorial','DBMS stands for DataBase ...') , +('How To Use MySQL Well','After you went through a ...'), +('Optimizing MySQL','In this tutorial we will show ...'), +('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), +('MySQL vs. YourSQL','In the following database comparison ...'), +('MySQL Security','When configured properly, MySQL ...'); +SELECT * FROM articles2 WHERE MATCH (title,body) +AGAINST ('the' IN NATURAL LANGUAGE MODE); +id title body +set global innodb_ft_server_stopword_table = "not_defined"; +ERROR 42000: Variable 'innodb_ft_server_stopword_table' can't be set to the value of 'not_defined' +set global innodb_ft_server_stopword_table = NULL; +create table user_stopword(value varchar(30)) engine = innodb; +set global innodb_ft_server_stopword_table = "test/user_stopword"; +drop index title on articles2; +create fulltext index idx on articles2(title, body); +insert into articles2 (title, body) +values ('test for stopwords','this is it...'); +insert into user_stopword values("the"); +delete from user_stopword; +insert into user_stopword values("this"); +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); +ERROR HY000: Index articles is corrupted +call mtr.add_suppression("test/articles.? contains 3 indexes inside InnoDB"); +alter table articles force; +Warnings: +Warning 1082 InnoDB: Table test/articles contains 3 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB +flush tables; +show create table articles; +Table Create Table +articles CREATE TABLE `articles` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `title` varchar(200) DEFAULT NULL, + `body` text DEFAULT NULL, + PRIMARY KEY (`id`), + FULLTEXT KEY `title` (`title`,`body`) +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci WITH SYSTEM VERSIONING +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); +id title body +1 MySQL Tutorial DBMS stands for DataBase ... +5 MySQL vs. YourSQL In the following database comparison ... +7 test query expansion for database ... +SELECT COUNT(*) FROM articles +WHERE MATCH (title,body) +AGAINST ('database' IN NATURAL LANGUAGE MODE); +COUNT(*) +3 +SELECT * FROM articles +WHERE MATCH (title, body) +AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE); +id title body +1 MySQL Tutorial DBMS stands for DataBase ... +3 Optimizing MySQL In this tutorial we will show ... +SELECT COUNT(IF(MATCH (title,body) +AGAINST ('database' IN NATURAL LANGUAGE MODE), 1, NULL)) +AS count FROM articles; +count +3 +SELECT id, body, MATCH (title,body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE) AS score +FROM articles; +id body score +1 DBMS stands for DataBase ... 0.2734021842479706 +2 After you went through a ... 0 +3 In this tutorial we will show ... 0 +4 1. Never run mysqld as root. 2. ... 0 +5 In the following database comparison ... 0.2734021842479706 +6 When configured properly, MySQL ... 0 +7 for database ... 0.2734021842479706 +8 search, with proximity innodb 0 +9 search, with proximity innodb 0 +10 search, with proximity innodb 0 +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('MySQL' IN NATURAL LANGUAGE MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('DBMS Security' IN BOOLEAN MODE); +id title body +1 MySQL Tutorial DBMS stands for DataBase ... +6 MySQL Security When configured properly, MySQL ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+MySQL +YourSQL' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+MySQL YourSQL' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+MySQL ~YourSQL' IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('t*' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +7 test query expansion for database ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('MY*' IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('ru*' IN BOOLEAN MODE); +id title body +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+ MySQL >Well < stands' IN BOOLEAN MODE); +id title body +2 How To Use MySQL Well After you went through a ... +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+ MySQL - (Well stands)' IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +ERROR HY000: Table handler out of memory +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((vs))))))))))))))))))))))))))))))),(((to)))' + IN BOOLEAN MODE); +id title body +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +ERROR 42000: syntax error, unexpected $end +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +ERROR 42000: syntax error, unexpected $end +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+ MySQL + (>Well < stands)' IN BOOLEAN MODE); +id title body +2 How To Use MySQL Well After you went through a ... +1 MySQL Tutorial DBMS stands for DataBase ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('YourSQL + (+MySQL - (Tricks Security))' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('(+MySQL - (Tricks Security)) - YourSQL' IN BOOLEAN MODE); +id title body +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysql - Security&DBMS' IN BOOLEAN MODE); +id title body +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysql - (Security DBMS)' IN BOOLEAN MODE); +id title body +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST (' - Security&DBMS + YourSQL' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('+YourSQL - Security&DBMS' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT COUNT(*) FROM articles +WHERE MATCH (title,body) +AGAINST ('database' WITH QUERY EXPANSION); +COUNT(*) +10 +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('test' WITH QUERY EXPANSION); +id title body +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +8 test proximity search, test, proximity and phrase search, with proximity innodb +7 test query expansion for database ... +1 MySQL Tutorial DBMS stands for DataBase ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"following comparison"@3' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"following comparison"@2' IN BOOLEAN MODE); +id title body +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"following database"' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"proximity search"@3' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"proximity search"@2' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"proximity search"@5' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"test proximity"@5' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"test proximity"@1' IN BOOLEAN MODE); +id title body +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"test proximity"@4' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"test proximity"@3' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"more test proximity"@4' IN BOOLEAN MODE); +id title body +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"more test proximity"@3' IN BOOLEAN MODE); +id title body +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"more test proximity"' IN BOOLEAN MODE); +id title body +set global innodb_ft_server_stopword_table= "test/user_stopword"; +SELECT * FROM articles2 WHERE MATCH (title,body) +AGAINST ('the' IN NATURAL LANGUAGE MODE); +SELECT * FROM articles2 WHERE MATCH (title,body) +AGAINST ('this' IN NATURAL LANGUAGE MODE); +drop index idx on articles2; +Warnings: +Warning 1082 InnoDB: Table test/articles2 contains 3 indexes inside InnoDB, which is different from the number of indexes 1 defined in the MariaDB +create fulltext index idx on articles2(title, body); +SELECT * FROM articles2 WHERE MATCH (title,body) +AGAINST ('the' IN NATURAL LANGUAGE MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles2 WHERE MATCH (title,body) +AGAINST ('this' IN NATURAL LANGUAGE MODE); +id title body +# Downgrade test +alter table articles force; +Warnings: +Warning 1082 InnoDB: Table test/articles contains 3 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB +Warning 1082 InnoDB: Table test/articles contains 3 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB +flush tables; +show create table articles; +Table Create Table +articles CREATE TABLE `articles` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `title` varchar(200) DEFAULT NULL, + `body` text DEFAULT NULL, + PRIMARY KEY (`id`), + FULLTEXT KEY `title` (`title`,`body`) +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci WITH SYSTEM VERSIONING +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); +id title body +1 MySQL Tutorial DBMS stands for DataBase ... +5 MySQL vs. YourSQL In the following database comparison ... +7 test query expansion for database ... +SELECT COUNT(*) FROM articles +WHERE MATCH (title,body) +AGAINST ('database' IN NATURAL LANGUAGE MODE); +COUNT(*) +3 +SELECT * FROM articles +WHERE MATCH (title, body) +AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE); +id title body +1 MySQL Tutorial DBMS stands for DataBase ... +3 Optimizing MySQL In this tutorial we will show ... +SELECT COUNT(IF(MATCH (title,body) +AGAINST ('database' IN NATURAL LANGUAGE MODE), 1, NULL)) +AS count FROM articles; +count +3 +SELECT id, body, MATCH (title,body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE) AS score +FROM articles; +id body score +1 DBMS stands for DataBase ... 0.2734021842479706 +2 After you went through a ... 0 +3 In this tutorial we will show ... 0 +4 1. Never run mysqld as root. 2. ... 0 +5 In the following database comparison ... 0.2734021842479706 +6 When configured properly, MySQL ... 0 +7 for database ... 0.2734021842479706 +8 search, with proximity innodb 0 +9 search, with proximity innodb 0 +10 search, with proximity innodb 0 +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('MySQL' IN NATURAL LANGUAGE MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('DBMS Security' IN BOOLEAN MODE); +id title body +1 MySQL Tutorial DBMS stands for DataBase ... +6 MySQL Security When configured properly, MySQL ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+MySQL +YourSQL' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+MySQL YourSQL' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+MySQL ~YourSQL' IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('t*' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +7 test query expansion for database ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('MY*' IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('ru*' IN BOOLEAN MODE); +id title body +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+ MySQL >Well < stands' IN BOOLEAN MODE); +id title body +2 How To Use MySQL Well After you went through a ... +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+ MySQL - (Well stands)' IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +ERROR HY000: Table handler out of memory +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((vs))))))))))))))))))))))))))))))),(((to)))' + IN BOOLEAN MODE); +id title body +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +ERROR 42000: syntax error, unexpected $end +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +ERROR 42000: syntax error, unexpected $end +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+ MySQL + (>Well < stands)' IN BOOLEAN MODE); +id title body +2 How To Use MySQL Well After you went through a ... +1 MySQL Tutorial DBMS stands for DataBase ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('YourSQL + (+MySQL - (Tricks Security))' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('(+MySQL - (Tricks Security)) - YourSQL' IN BOOLEAN MODE); +id title body +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysql - Security&DBMS' IN BOOLEAN MODE); +id title body +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysql - (Security DBMS)' IN BOOLEAN MODE); +id title body +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST (' - Security&DBMS + YourSQL' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('+YourSQL - Security&DBMS' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT COUNT(*) FROM articles +WHERE MATCH (title,body) +AGAINST ('database' WITH QUERY EXPANSION); +COUNT(*) +10 +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('test' WITH QUERY EXPANSION); +id title body +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +8 test proximity search, test, proximity and phrase search, with proximity innodb +7 test query expansion for database ... +1 MySQL Tutorial DBMS stands for DataBase ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"following comparison"@3' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"following comparison"@2' IN BOOLEAN MODE); +id title body +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"following database"' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"proximity search"@3' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"proximity search"@2' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"proximity search"@5' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"test proximity"@5' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"test proximity"@1' IN BOOLEAN MODE); +id title body +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"test proximity"@4' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"test proximity"@3' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"more test proximity"@4' IN BOOLEAN MODE); +id title body +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"more test proximity"@3' IN BOOLEAN MODE); +id title body +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"more test proximity"' IN BOOLEAN MODE); +id title body +set global innodb_ft_server_stopword_table= "test/user_stopword"; +drop index idx on articles2; +Warnings: +Warning 1082 InnoDB: Table test/articles2 contains 3 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB +Warning 1082 InnoDB: Table test/articles2 contains 3 indexes inside InnoDB, which is different from the number of indexes 1 defined in the MariaDB +create fulltext index idx on articles2(title, body); +SELECT * FROM articles2 WHERE MATCH (title,body) +AGAINST ('the' IN NATURAL LANGUAGE MODE); +id title body +SELECT * FROM articles2 WHERE MATCH (title,body) +AGAINST ('this' IN NATURAL LANGUAGE MODE); +id title body +# Cleanup +drop tables articles, articles2, user_stopword; +set global innodb_ft_server_stopword_table= default; diff --git a/mysql-test/suite/innodb_fts/r/versioning.result b/mysql-test/suite/innodb_fts/r/versioning.result new file mode 100644 index 00000000000..73ce8f838fd --- /dev/null +++ b/mysql-test/suite/innodb_fts/r/versioning.result @@ -0,0 +1,303 @@ +# Upgrade test +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); +ERROR HY000: Index articles is corrupted +call mtr.add_suppression("test/articles.? contains 3 indexes inside InnoDB"); +alter table articles force; +Warnings: +Warning 1082 InnoDB: Table test/articles contains 3 indexes inside InnoDB, which is different from the number of indexes 2 defined in the MariaDB +flush tables; +show create table articles; +Table Create Table +articles CREATE TABLE `articles` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `title` varchar(200) DEFAULT NULL, + `body` text DEFAULT NULL, + PRIMARY KEY (`id`), + FULLTEXT KEY `title` (`title`,`body`) +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci WITH SYSTEM VERSIONING +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); +id title body +1 MySQL Tutorial DBMS stands for DataBase ... +5 MySQL vs. YourSQL In the following database comparison ... +7 test query expansion for database ... +SELECT COUNT(*) FROM articles +WHERE MATCH (title,body) +AGAINST ('database' IN NATURAL LANGUAGE MODE); +COUNT(*) +3 +SELECT * FROM articles +WHERE MATCH (title, body) +AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE); +id title body +1 MySQL Tutorial DBMS stands for DataBase ... +3 Optimizing MySQL In this tutorial we will show ... +SELECT COUNT(IF(MATCH (title,body) +AGAINST ('database' IN NATURAL LANGUAGE MODE), 1, NULL)) +AS count FROM articles; +count +3 +SELECT id, body, MATCH (title,body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE) AS score +FROM articles; +id body score +1 DBMS stands for DataBase ... 0.2734021842479706 +2 After you went through a ... 0 +3 In this tutorial we will show ... 0 +4 1. Never run mysqld as root. 2. ... 0 +5 In the following database comparison ... 0.2734021842479706 +6 When configured properly, MySQL ... 0 +7 for database ... 0.2734021842479706 +8 search, with proximity innodb 0 +9 search, with proximity innodb 0 +10 search, with proximity innodb 0 +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('MySQL' IN NATURAL LANGUAGE MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('DBMS Security' IN BOOLEAN MODE); +id title body +1 MySQL Tutorial DBMS stands for DataBase ... +6 MySQL Security When configured properly, MySQL ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+MySQL +YourSQL' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+MySQL YourSQL' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+MySQL ~YourSQL' IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('t*' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +7 test query expansion for database ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('MY*' IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('ru*' IN BOOLEAN MODE); +id title body +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+ MySQL >Well < stands' IN BOOLEAN MODE); +id title body +2 How To Use MySQL Well After you went through a ... +6 MySQL Security When configured properly, MySQL ... +1 MySQL Tutorial DBMS stands for DataBase ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+ MySQL - (Well stands)' IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +ERROR HY000: Table handler out of memory +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +id title body +6 MySQL Security When configured properly, MySQL ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((vs))))))))))))))))))))))))))))))),(((to)))' + IN BOOLEAN MODE); +id title body +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +ERROR 42000: syntax error, unexpected $end +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +ERROR 42000: syntax error, unexpected $end +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('+ MySQL + (>Well < stands)' IN BOOLEAN MODE); +id title body +2 How To Use MySQL Well After you went through a ... +1 MySQL Tutorial DBMS stands for DataBase ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('YourSQL + (+MySQL - (Tricks Security))' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('(+MySQL - (Tricks Security)) - YourSQL' IN BOOLEAN MODE); +id title body +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysql - Security&DBMS' IN BOOLEAN MODE); +id title body +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysql - (Security DBMS)' IN BOOLEAN MODE); +id title body +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks 1. Never run mysqld as root. 2. ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST (' - Security&DBMS + YourSQL' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('+YourSQL - Security&DBMS' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT COUNT(*) FROM articles +WHERE MATCH (title,body) +AGAINST ('database' WITH QUERY EXPANSION); +COUNT(*) +10 +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('test' WITH QUERY EXPANSION); +id title body +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +8 test proximity search, test, proximity and phrase search, with proximity innodb +7 test query expansion for database ... +1 MySQL Tutorial DBMS stands for DataBase ... +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"following comparison"@3' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"following comparison"@2' IN BOOLEAN MODE); +id title body +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"following database"' IN BOOLEAN MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"proximity search"@3' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"proximity search"@2' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"proximity search"@5' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"test proximity"@5' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"test proximity"@1' IN BOOLEAN MODE); +id title body +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"test proximity"@4' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"test proximity"@3' IN BOOLEAN MODE); +id title body +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test my proximity fts new search, test, proximity and phrase search, with proximity innodb +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"more test proximity"@4' IN BOOLEAN MODE); +id title body +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"more test proximity"@3' IN BOOLEAN MODE); +id title body +10 test more of proximity fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM articles +WHERE MATCH (title,body) +AGAINST ('"more test proximity"' IN BOOLEAN MODE); +id title body +set global innodb_ft_server_stopword_table= "test/user_stopword"; +SELECT * FROM articles2 WHERE MATCH (title,body) +AGAINST ('the' IN NATURAL LANGUAGE MODE); +SELECT * FROM articles2 WHERE MATCH (title,body) +AGAINST ('this' IN NATURAL LANGUAGE MODE); +drop index idx on articles2; +Warnings: +Warning 1082 InnoDB: Table test/articles2 contains 3 indexes inside InnoDB, which is different from the number of indexes 1 defined in the MariaDB +create fulltext index idx on articles2(title, body); +SELECT * FROM articles2 WHERE MATCH (title,body) +AGAINST ('the' IN NATURAL LANGUAGE MODE); +id title body +5 MySQL vs. YourSQL In the following database comparison ... +SELECT * FROM articles2 WHERE MATCH (title,body) +AGAINST ('this' IN NATURAL LANGUAGE MODE); +id title body +# Cleanup +drop tables articles, articles2, user_stopword; +set global innodb_ft_server_stopword_table= default; diff --git a/mysql-test/suite/innodb_fts/t/basic.inc b/mysql-test/suite/innodb_fts/t/basic.inc new file mode 100644 index 00000000000..fd7d09208bc --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/basic.inc @@ -0,0 +1,264 @@ +if ($basic_stage == create_table) +{ +# Create FTS table +--error ER_INNODB_NO_FT_TEMP_TABLE +CREATE TEMPORARY TABLE articles ( + id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, + title VARCHAR(200), + body TEXT, + FULLTEXT (title,body) + ) ENGINE=InnoDB; + +--disable_query_log +eval CREATE TABLE articles ( + id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, + title VARCHAR(200), + body TEXT, + FULLTEXT (title,body) + )$create_options ENGINE=InnoDB; +--enable_query_log +} + +if ($basic_stage == insert_1) +{ +# Insert six rows +INSERT INTO articles (title,body) VALUES + ('MySQL Tutorial','DBMS stands for DataBase ...') , + ('How To Use MySQL Well','After you went through a ...'), + ('Optimizing MySQL','In this tutorial we will show ...'), + ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), + ('MySQL vs. YourSQL','In the following database comparison ...'), + ('MySQL Security','When configured properly, MySQL ...'); +} + +if ($basic_stage == select_1) +{ +# Look for 'Database' in table article +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('Database' IN NATURAL LANGUAGE MODE); + +SELECT COUNT(*) FROM articles + WHERE MATCH (title,body) + AGAINST ('database' IN NATURAL LANGUAGE MODE); + +SELECT * FROM articles + WHERE MATCH (title, body) + AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE); + + +SELECT COUNT(IF(MATCH (title,body) + AGAINST ('database' IN NATURAL LANGUAGE MODE), 1, NULL)) + AS count FROM articles; + +# Select Relevance Ranking +SELECT id, body, MATCH (title,body) + AGAINST ('Database' IN NATURAL LANGUAGE MODE) AS score + FROM articles; + +# 'MySQL' treated as stopword (stopword functionality not yet supported) +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('MySQL' IN NATURAL LANGUAGE MODE); + +# Boolean search +# Select rows contain "MySQL" but not "YourSQL" +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE); + +# Select rows contain at least one of the two words +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('DBMS Security' IN BOOLEAN MODE); + +# Select rows contain both "MySQL" and "YourSQL" +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('+MySQL +YourSQL' IN BOOLEAN MODE); + +# Select rows contain "MySQL" but rank rows with "YourSQL" higher +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('+MySQL YourSQL' IN BOOLEAN MODE); + +# Test negation operator. Select rows contain MySQL, +# if the row contains "YourSQL", rank it lower +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('+MySQL ~YourSQL' IN BOOLEAN MODE); + +# Test wild card search operator +# Notice row with "the" will not get fetched due to +# stopword filtering +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('t*' IN BOOLEAN MODE); + +# Test wild card search, notice row 6 with 2 "MySQL" rank first +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('MY*' IN BOOLEAN MODE); + +# Another wild card search +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('ru*' IN BOOLEAN MODE); + +# Test ">" and "<" Operator, the ">" operator increases +# the word relevance rank and the "<" operator decreases it +# Following test puts rows with "Well" on top and rows +# with "stands" at the bottom +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('+ MySQL >Well < stands' IN BOOLEAN MODE); + +# Test sub-expression boolean search. Find rows contain +# "MySQL" but not "Well" or "stands". +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('+ MySQL - (Well stands)' IN BOOLEAN MODE); + +--error 128 +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((vs))))))))))))))))))))))))))))))),(((to)))' + IN BOOLEAN MODE); + +--error ER_PARSE_ERROR +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); +--error ER_PARSE_ERROR +SELECT * FROM articles WHERE MATCH (title,body) AGAINST +('(((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' + IN BOOLEAN MODE); + +# Test sub-expression boolean search. Find rows contain +# "MySQL" and "Well" or "MySQL" and "stands". But rank the +# doc with "Well" higher, and doc with "stands" lower. +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('+ MySQL + (>Well < stands)' IN BOOLEAN MODE); + +# Test nested sub-expression. +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('YourSQL + (+MySQL - (Tricks Security))' IN BOOLEAN MODE); + +# Find rows with "MySQL" but not "Tricks", "Security" nor "YourSQL" +SELECT * FROM articles WHERE MATCH (title,body) + AGAINST ('(+MySQL - (Tricks Security)) - YourSQL' IN BOOLEAN MODE); + +# Test non-word delimiter combined with negate "-" operator +# This should return the same result as 'mysql - (Security DBMS)' +SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysql - Security&DBMS' IN BOOLEAN MODE); +SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysql - (Security DBMS)' IN BOOLEAN MODE); + +# Again, the operator sequence should not matter +SELECT * FROM articles WHERE MATCH (title,body) AGAINST (' - Security&DBMS + YourSQL' IN BOOLEAN MODE); + +SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('+YourSQL - Security&DBMS' IN BOOLEAN MODE); + +# Test query expansion +SELECT COUNT(*) FROM articles + WHERE MATCH (title,body) + AGAINST ('database' WITH QUERY EXPANSION); +} + +if ($basic_stage == insert_2) +{ +INSERT INTO articles (title,body) VALUES + ('test query expansion','for database ...'); +} + +if ($basic_stage == select_2) +{ +# This query will return result containing word "database" as +# the query expand from "test" to words in document just +# inserted above +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('test' WITH QUERY EXPANSION); + +# This is to test the proximity search, search two word +# "following" and "comparison" within 19 character space +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"following comparison"@3' IN BOOLEAN MODE); + +# This is to test the proximity search, search two word +# "following" and "comparison" within 19 character space +# This search should come with no return result +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"following comparison"@2' IN BOOLEAN MODE); + +# This is to test the phrase search, searching phrase +# "following database" +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"following database"' IN BOOLEAN MODE); +} + +if ($basic_stage == insert_3) +{ +# Insert into table with similar word of different distances +INSERT INTO articles (title,body) VALUES + ('test proximity search, test, proximity and phrase', + 'search, with proximity innodb'); + +INSERT INTO articles (title,body) VALUES + ('test my proximity fts new search, test, proximity and phrase', + 'search, with proximity innodb'); + +INSERT INTO articles (title,body) VALUES + ('test more of proximity fts search, test, more proximity and phrase', + 'search, with proximity innodb'); +} + +if ($basic_stage == select_3) +{ +# This should only return the first document +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"proximity search"@3' IN BOOLEAN MODE); + +# This would return no document +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"proximity search"@2' IN BOOLEAN MODE); + +# This give you all three documents +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"proximity search"@5' IN BOOLEAN MODE); + +# Similar boundary testing for the words +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"test proximity"@5' IN BOOLEAN MODE); + +# No document will be returned +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"test proximity"@1' IN BOOLEAN MODE); + +# All three documents will be returned +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"test proximity"@4' IN BOOLEAN MODE); + +# Only two document will be returned. +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"test proximity"@3' IN BOOLEAN MODE); + +# Test with more word The last document will return, please notice there +# is no ordering requirement for proximity search. +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"more test proximity"@4' IN BOOLEAN MODE); + +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"more test proximity"@3' IN BOOLEAN MODE); + +# The phrase search will not require exact word ordering +SELECT * FROM articles + WHERE MATCH (title,body) + AGAINST ('"more test proximity"' IN BOOLEAN MODE); +} diff --git a/mysql-test/suite/innodb_fts/t/basic.test b/mysql-test/suite/innodb_fts/t/basic.test index 53ad978a5b1..df2e24fae8e 100644 --- a/mysql-test/suite/innodb_fts/t/basic.test +++ b/mysql-test/suite/innodb_fts/t/basic.test @@ -1,252 +1,33 @@ # This is the basic function tests for innodb FTS -- source include/have_innodb.inc +--let $modify_create_table= 1 +-- source include/maybe_versioning.inc -# Create FTS table ---error ER_INNODB_NO_FT_TEMP_TABLE -CREATE TEMPORARY TABLE articles ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, - title VARCHAR(200), - body TEXT, - FULLTEXT (title,body) - ) ENGINE=InnoDB; +let $basic_stage= create_table; +--source basic.inc -CREATE TABLE articles ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, - title VARCHAR(200), - body TEXT, - FULLTEXT (title,body) - ) ENGINE=InnoDB; - -# Insert six rows -INSERT INTO articles (title,body) VALUES - ('MySQL Tutorial','DBMS stands for DataBase ...') , - ('How To Use MySQL Well','After you went through a ...'), - ('Optimizing MySQL','In this tutorial we will show ...'), - ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), - ('MySQL vs. YourSQL','In the following database comparison ...'), - ('MySQL Security','When configured properly, MySQL ...'); +let $basic_stage= insert_1; +--source basic.inc -- disable_result_log ANALYZE TABLE articles; -- enable_result_log -# Look for 'Database' in table article -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('Database' IN NATURAL LANGUAGE MODE); +let $basic_stage= select_1; +--source basic.inc -SELECT COUNT(*) FROM articles - WHERE MATCH (title,body) - AGAINST ('database' IN NATURAL LANGUAGE MODE); +let $basic_stage= insert_2; +--source basic.inc -SELECT * FROM articles - WHERE MATCH (title, body) - AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE); +let $basic_stage= select_2; +--source basic.inc +let $basic_stage= insert_3; +--source basic.inc -SELECT COUNT(IF(MATCH (title,body) - AGAINST ('database' IN NATURAL LANGUAGE MODE), 1, NULL)) - AS count FROM articles; - -# Select Relevance Ranking -SELECT id, body, MATCH (title,body) - AGAINST ('Database' IN NATURAL LANGUAGE MODE) AS score - FROM articles; - -# 'MySQL' treated as stopword (stopword functionality not yet supported) -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('MySQL' IN NATURAL LANGUAGE MODE); - -# Boolean search -# Select rows contain "MySQL" but not "YourSQL" -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE); - -# Select rows contain at least one of the two words -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('DBMS Security' IN BOOLEAN MODE); - -# Select rows contain both "MySQL" and "YourSQL" -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('+MySQL +YourSQL' IN BOOLEAN MODE); - -# Select rows contain "MySQL" but rank rows with "YourSQL" higher -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('+MySQL YourSQL' IN BOOLEAN MODE); - -# Test negation operator. Select rows contain MySQL, -# if the row contains "YourSQL", rank it lower -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('+MySQL ~YourSQL' IN BOOLEAN MODE); - -# Test wild card search operator -# Notice row with "the" will not get fetched due to -# stopword filtering -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('t*' IN BOOLEAN MODE); - -# Test wild card search, notice row 6 with 2 "MySQL" rank first -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('MY*' IN BOOLEAN MODE); - -# Another wild card search -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('ru*' IN BOOLEAN MODE); - -# Test ">" and "<" Operator, the ">" operator increases -# the word relevance rank and the "<" operator decreases it -# Following test puts rows with "Well" on top and rows -# with "stands" at the bottom -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('+ MySQL >Well < stands' IN BOOLEAN MODE); - -# Test sub-expression boolean search. Find rows contain -# "MySQL" but not "Well" or "stands". -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('+ MySQL - (Well stands)' IN BOOLEAN MODE); - ---error 128 -SELECT * FROM articles WHERE MATCH (title,body) AGAINST -('(((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))))' - IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST -('((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' - IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST -('(((((((((((((((((((((((((((((((vs))))))))))))))))))))))))))))))),(((to)))' - IN BOOLEAN MODE); - ---error ER_PARSE_ERROR -SELECT * FROM articles WHERE MATCH (title,body) AGAINST -('((((((((((((((((((((((((((((((((Security)))))))))))))))))))))))))))))))' - IN BOOLEAN MODE); ---error ER_PARSE_ERROR -SELECT * FROM articles WHERE MATCH (title,body) AGAINST -('(((((((((((((((((((((((((((((((((Security))))))))))))))))))))))))))))))))' - IN BOOLEAN MODE); - -# Test sub-expression boolean search. Find rows contain -# "MySQL" and "Well" or "MySQL" and "stands". But rank the -# doc with "Well" higher, and doc with "stands" lower. -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('+ MySQL + (>Well < stands)' IN BOOLEAN MODE); - -# Test nested sub-expression. -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('YourSQL + (+MySQL - (Tricks Security))' IN BOOLEAN MODE); - -# Find rows with "MySQL" but not "Tricks", "Security" nor "YourSQL" -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('(+MySQL - (Tricks Security)) - YourSQL' IN BOOLEAN MODE); - -# Test non-word delimiter combined with negate "-" operator -# This should return the same result as 'mysql - (Security DBMS)' -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysql - Security&DBMS' IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysql - (Security DBMS)' IN BOOLEAN MODE); - -# Again, the operator sequence should not matter -SELECT * FROM articles WHERE MATCH (title,body) AGAINST (' - Security&DBMS + YourSQL' IN BOOLEAN MODE); - -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('+YourSQL - Security&DBMS' IN BOOLEAN MODE); - -# Test query expansion -SELECT COUNT(*) FROM articles - WHERE MATCH (title,body) - AGAINST ('database' WITH QUERY EXPANSION); - -INSERT INTO articles (title,body) VALUES - ('test query expansion','for database ...'); - -# This query will return result containing word "database" as -# the query expand from "test" to words in document just -# inserted above -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('test' WITH QUERY EXPANSION); - -# This is to test the proximity search, search two word -# "following" and "comparison" within 19 character space -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"following comparison"@3' IN BOOLEAN MODE); - -# This is to test the proximity search, search two word -# "following" and "comparison" within 19 character space -# This search should come with no return result -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"following comparison"@2' IN BOOLEAN MODE); - -# This is to test the phrase search, searching phrase -# "following database" -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"following database"' IN BOOLEAN MODE); - -# Insert into table with similar word of different distances -INSERT INTO articles (title,body) VALUES - ('test proximity search, test, proximity and phrase', - 'search, with proximity innodb'); - -INSERT INTO articles (title,body) VALUES - ('test my proximity fts new search, test, proximity and phrase', - 'search, with proximity innodb'); - -INSERT INTO articles (title,body) VALUES - ('test more of proximity fts search, test, more proximity and phrase', - 'search, with proximity innodb'); - -# This should only return the first document -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"proximity search"@3' IN BOOLEAN MODE); - -# This would return no document -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"proximity search"@2' IN BOOLEAN MODE); - -# This give you all three documents -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"proximity search"@5' IN BOOLEAN MODE); - -# Similar boundary testing for the words -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"test proximity"@5' IN BOOLEAN MODE); - -# No document will be returned -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"test proximity"@1' IN BOOLEAN MODE); - -# All three documents will be returned -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"test proximity"@4' IN BOOLEAN MODE); - -# Only two document will be returned. -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"test proximity"@3' IN BOOLEAN MODE); - -# Test with more word The last document will return, please notice there -# is no ordering requirement for proximity search. -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"more test proximity"@4' IN BOOLEAN MODE); - -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"more test proximity"@3' IN BOOLEAN MODE); - -# The phrase search will not require exact word ordering -SELECT * FROM articles - WHERE MATCH (title,body) - AGAINST ('"more test proximity"' IN BOOLEAN MODE); +let $basic_stage= select_3; +--source basic.inc drop table articles; diff --git a/mysql-test/suite/innodb_fts/t/crash_recovery.test b/mysql-test/suite/innodb_fts/t/crash_recovery.test index 0e32608a81a..7bece572827 100644 --- a/mysql-test/suite/innodb_fts/t/crash_recovery.test +++ b/mysql-test/suite/innodb_fts/t/crash_recovery.test @@ -7,6 +7,7 @@ # The embedded server tests do not support restarting. --source include/not_embedded.inc --source include/maybe_debug.inc +--source include/maybe_versioning.inc FLUSH TABLES; # Following are test for crash recovery on FTS index, the first scenario @@ -22,6 +23,16 @@ CREATE TABLE articles ( FULLTEXT (title,body) ) ENGINE=InnoDB; +let $vers= $MTR_COMBINATION_VERS + $MTR_COMBINATION_VERS_TRX; +if ($vers) +{ + --disable_query_log + INSERT INTO articles (title,body) VALUES + ('history','Deleted row ...'); + DELETE FROM articles; + --enable_query_log +} + # Drop the FTS index before more insertion. The FTS_DOC_ID should # be kept DROP INDEX title ON articles; @@ -59,6 +70,13 @@ INSERT INTO articles (title,body) VALUES # Recreate fulltext index to see if everything is OK CREATE FULLTEXT INDEX idx ON articles (title,body); +if ($vers) +{ + --disable_query_log + UPDATE articles SET id= id - 1; + --enable_query_log +} + # Should return 3 rows SELECT * FROM articles WHERE MATCH (title,body) @@ -98,6 +116,13 @@ disconnect dml; INSERT INTO articles (title,body) VALUES ('MySQL Tutorial','DBMS stands for DataBase ...'); +if ($vers) +{ + --disable_query_log + UPDATE articles SET id= id - 1 WHERE id > 8; + --enable_query_log +} + # Should return 6 rows SELECT * FROM articles WHERE MATCH (title,body) @@ -134,6 +159,15 @@ BEGIN; INSERT INTO articles VALUES (100, 200, 'MySQL Tutorial','DBMS stands for DataBase ...'); +if ($vers) +{ + --disable_query_log + DELETE FROM articles WHERE id = 100; + INSERT INTO articles VALUES + (100, 200, 'MySQL Tutorial','DBMS stands for DataBase ...'); + --enable_query_log +} + connect(dml2, localhost, root,,); --echo # diff --git a/mysql-test/suite/innodb_fts/t/create.test b/mysql-test/suite/innodb_fts/t/create.test index 38c93de4982..710fd9cb99b 100644 --- a/mysql-test/suite/innodb_fts/t/create.test +++ b/mysql-test/suite/innodb_fts/t/create.test @@ -1,4 +1,5 @@ --source include/have_innodb.inc +--source include/maybe_versioning.inc SET NAMES utf8mb4; --echo # diff --git a/mysql-test/suite/innodb_fts/t/fulltext2.test b/mysql-test/suite/innodb_fts/t/fulltext2.test index 25a4d5b24f9..a66f804b7ff 100644 --- a/mysql-test/suite/innodb_fts/t/fulltext2.test +++ b/mysql-test/suite/innodb_fts/t/fulltext2.test @@ -7,6 +7,7 @@ # --source include/have_innodb.inc +--source include/maybe_versioning.inc CREATE TABLE t1 ( i int(10) unsigned not null auto_increment primary key, diff --git a/mysql-test/suite/innodb_fts/t/fulltext3.test b/mysql-test/suite/innodb_fts/t/fulltext3.test index 9c7941d7b5c..f28ca2c7d77 100644 --- a/mysql-test/suite/innodb_fts/t/fulltext3.test +++ b/mysql-test/suite/innodb_fts/t/fulltext3.test @@ -3,6 +3,7 @@ # test of new fulltext search features # --source include/have_innodb.inc +--source include/maybe_versioning.inc --disable_warnings DROP TABLE IF EXISTS t1; diff --git a/mysql-test/suite/innodb_fts/t/fulltext_cache.test b/mysql-test/suite/innodb_fts/t/fulltext_cache.test index fa7ad49e881..37926c1e7f1 100644 --- a/mysql-test/suite/innodb_fts/t/fulltext_cache.test +++ b/mysql-test/suite/innodb_fts/t/fulltext_cache.test @@ -2,6 +2,7 @@ # Bugreport due to Roy Nasser # --source include/have_innodb.inc +--source include/maybe_versioning.inc --disable_warnings drop table if exists t1, t2; diff --git a/mysql-test/suite/innodb_fts/t/fulltext_distinct.test b/mysql-test/suite/innodb_fts/t/fulltext_distinct.test index f6232704543..bb390a08384 100644 --- a/mysql-test/suite/innodb_fts/t/fulltext_distinct.test +++ b/mysql-test/suite/innodb_fts/t/fulltext_distinct.test @@ -3,6 +3,7 @@ # bug reported by Tibor Simko # --source include/have_innodb.inc +--source include/maybe_versioning.inc --disable_warnings DROP TABLE IF EXISTS t1, t2; diff --git a/mysql-test/suite/innodb_fts/t/fulltext_left_join.test b/mysql-test/suite/innodb_fts/t/fulltext_left_join.test index 23bbd5ddc10..0a1e1748769 100644 --- a/mysql-test/suite/innodb_fts/t/fulltext_left_join.test +++ b/mysql-test/suite/innodb_fts/t/fulltext_left_join.test @@ -2,6 +2,7 @@ # Test for bug from Jean-Cédric COSTA # --source include/have_innodb.inc +--source include/maybe_versioning.inc --disable_warnings drop table if exists t1, t2; diff --git a/mysql-test/suite/innodb_fts/t/fulltext_multi.test b/mysql-test/suite/innodb_fts/t/fulltext_multi.test index 274027ea10b..81ab7e1b071 100644 --- a/mysql-test/suite/innodb_fts/t/fulltext_multi.test +++ b/mysql-test/suite/innodb_fts/t/fulltext_multi.test @@ -1,5 +1,6 @@ # several FULLTEXT indexes in one table test --source include/have_innodb.inc +--source include/maybe_versioning.inc --disable_warnings DROP TABLE IF EXISTS t1; diff --git a/mysql-test/suite/innodb_fts/t/fulltext_order_by.test b/mysql-test/suite/innodb_fts/t/fulltext_order_by.test index d2194f22e2a..f14681b934d 100644 --- a/mysql-test/suite/innodb_fts/t/fulltext_order_by.test +++ b/mysql-test/suite/innodb_fts/t/fulltext_order_by.test @@ -1,5 +1,6 @@ --source include/have_innodb.inc +--source include/maybe_versioning.inc --disable_warnings DROP TABLE IF EXISTS t1,t2,t3; diff --git a/mysql-test/suite/innodb_fts/t/fulltext_update.test b/mysql-test/suite/innodb_fts/t/fulltext_update.test index 336e8de1d1b..bda97cd4a21 100644 --- a/mysql-test/suite/innodb_fts/t/fulltext_update.test +++ b/mysql-test/suite/innodb_fts/t/fulltext_update.test @@ -2,6 +2,7 @@ # Test for bug by voi@ims.at # --source include/have_innodb.inc +--source include/maybe_versioning.inc --disable_warnings drop table if exists test; diff --git a/mysql-test/suite/innodb_fts/t/fulltext_var.test b/mysql-test/suite/innodb_fts/t/fulltext_var.test index 2b94aa58424..e8e4bf93303 100644 --- a/mysql-test/suite/innodb_fts/t/fulltext_var.test +++ b/mysql-test/suite/innodb_fts/t/fulltext_var.test @@ -2,6 +2,7 @@ # Fulltext configurable parameters # --source include/have_innodb.inc +--source include/maybe_versioning.inc # Save ft_boolean_syntax variable let $saved_ft_boolean_syntax=`select @@global.ft_boolean_syntax`; diff --git a/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test b/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test index 1ed164492d5..17a800c7663 100644 --- a/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test +++ b/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test @@ -1,6 +1,7 @@ # This is the DDL function tests for innodb FTS -- source include/have_innodb.inc +-- source include/maybe_versioning.inc # Create FTS table CREATE TABLE fts_test ( diff --git a/mysql-test/suite/innodb_fts/t/innodb-fts-fic.test b/mysql-test/suite/innodb_fts/t/innodb-fts-fic.test index 669aa69e835..2d94c21398c 100644 --- a/mysql-test/suite/innodb_fts/t/innodb-fts-fic.test +++ b/mysql-test/suite/innodb_fts/t/innodb-fts-fic.test @@ -1,6 +1,7 @@ # This is the basic function tests for innodb FTS -- source include/have_innodb.inc +-- source include/maybe_versioning.inc call mtr.add_suppression("\\[Warning\\] InnoDB: A new Doc ID must be supplied while updating FTS indexed columns."); call mtr.add_suppression("\\[Warning\\] InnoDB: FTS Doc ID must be larger than [0-9]+ for table `test`.`articles`"); diff --git a/mysql-test/suite/innodb_fts/t/innodb-fts-stopword.opt b/mysql-test/suite/innodb_fts/t/innodb-fts-stopword.opt deleted file mode 100644 index 2b0652d08c3..00000000000 --- a/mysql-test/suite/innodb_fts/t/innodb-fts-stopword.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-innodb-ft-default-stopword diff --git a/mysql-test/suite/innodb_fts/t/innodb-fts-stopword.test b/mysql-test/suite/innodb_fts/t/innodb-fts-stopword.test deleted file mode 100644 index de14deab328..00000000000 --- a/mysql-test/suite/innodb_fts/t/innodb-fts-stopword.test +++ /dev/null @@ -1,664 +0,0 @@ -# This is the basic function tests for innodb FTS - --- source include/have_innodb.inc - - -select * from information_schema.innodb_ft_default_stopword; - -# Create FTS table -CREATE TABLE articles ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, - title VARCHAR(200), - body TEXT, - FULLTEXT (title,body) - ) ENGINE=InnoDB; - -# Insert six rows -INSERT INTO articles (title,body) VALUES - ('MySQL Tutorial','DBMS stands for DataBase ...') , - ('How To Use MySQL Well','After you went through a ...'), - ('Optimizing MySQL','In this tutorial we will show ...'), - ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), - ('MySQL vs. YourSQL','In the following database comparison ...'), - ('MySQL Security','When configured properly, MySQL ...'); - -# "the" is in the default stopword, it would not be selected -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('the' IN NATURAL LANGUAGE MODE); - -let $innodb_ft_server_stopword_table_orig=`select @@innodb_ft_server_stopword_table`; -let $innodb_ft_enable_stopword_orig=`select @@innodb_ft_enable_stopword`; -let $innodb_ft_user_stopword_table_orig=`select @@innodb_ft_user_stopword_table`; - -select @@innodb_ft_server_stopword_table; -select @@innodb_ft_enable_stopword; -select @@innodb_ft_user_stopword_table; - -# Provide user defined stopword table, if not (correctly) defined, -# it will be rejected ---error 1231 -set global innodb_ft_server_stopword_table = "not_defined"; - -# Define a correct formatted user stopword table -create table user_stopword(value varchar(30)) engine = innodb; - -# The set operation should be successful -set global innodb_ft_server_stopword_table = "test/user_stopword"; - -drop index title on articles; - -create fulltext index idx on articles(title, body); - -# Now we should be able to find "the" -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('the' IN NATURAL LANGUAGE MODE); - -# Nothing inserted into the default stopword, so essentially -# nothing get screened. The new stopword could only be -# effective for table created thereafter -CREATE TABLE articles_2 ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, - title VARCHAR(200), - body TEXT, - FULLTEXT (title,body) - ) ENGINE=InnoDB; - -INSERT INTO articles_2 (title, body) - VALUES ('test for stopwords','this is it...'); - -# Now we can find record with "this" -SELECT * FROM articles_2 WHERE MATCH (title,body) - AGAINST ('this' IN NATURAL LANGUAGE MODE); - -# Ok, let's instantiate some value into user supplied stop word -# table -insert into user_stopword values("this"); - -# Ok, let's repeat with the new table again. -CREATE TABLE articles_3 ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, - title VARCHAR(200), - body TEXT, - FULLTEXT (title,body) - ) ENGINE=InnoDB; - -INSERT INTO articles_3 (title, body) - VALUES ('test for stopwords','this is it...'); - -# Now we should NOT find record with "this" -SELECT * FROM articles_3 WHERE MATCH (title,body) - AGAINST ('this' IN NATURAL LANGUAGE MODE); - -# Test session level stopword control "innodb_user_stopword_table" -create table user_stopword_session(value varchar(30)) engine = innodb; - -insert into user_stopword_session values("session"); - -set session innodb_ft_user_stopword_table="test/user_stopword_session"; - -CREATE TABLE articles_4 ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, - title VARCHAR(200), - body TEXT, - FULLTEXT (title,body) - ) ENGINE=InnoDB; - -INSERT INTO articles_4 (title, body) - VALUES ('test for session stopwords','this should also be excluded...'); - -# "session" is excluded -SELECT * FROM articles_4 WHERE MATCH (title,body) - AGAINST ('session' IN NATURAL LANGUAGE MODE); - -# But we can find record with "this" -SELECT * FROM articles_4 WHERE MATCH (title,body) - AGAINST ('this' IN NATURAL LANGUAGE MODE); - ---connect (con1,localhost,root,,) -CREATE TABLE articles_5 ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, - title VARCHAR(200), - body TEXT, - FULLTEXT (title,body) - ) ENGINE=InnoDB; - -INSERT INTO articles_5 (title, body) - VALUES ('test for session stopwords','this should also be excluded...'); - -# "session" should be found since the stopword table is session specific -SELECT * FROM articles_5 WHERE MATCH (title,body) - AGAINST ('session' IN NATURAL LANGUAGE MODE); - ---connection default -drop table articles; -drop table articles_2; -drop table articles_3; -drop table articles_4; -drop table articles_5; -drop table user_stopword; -drop table user_stopword_session; - -eval SET GLOBAL innodb_ft_enable_stopword=$innodb_ft_enable_stopword_orig; -eval SET GLOBAL innodb_ft_server_stopword_table=default; - -#--------------------------------------------------------------------------------------- -# Behavior : -# The stopword is loaded into memory at -# 1) create fulltext index time, -# 2) boot server, -# 3) first time FTs is used -# So if you already created a FTS index, and then turn off stopword -# or change stopword table content it won't affect the FTS -# that already created since the stopword list are already loaded. -# It will only affect the new FTS index created after you changed -# the settings. - -# Create FTS table -CREATE TABLE articles ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, - title VARCHAR(200), - body TEXT, - FULLTEXT `idx` (title,body) - ) ENGINE=InnoDB; - -SHOW CREATE TABLE articles; - -# Insert six rows -INSERT INTO articles (title,body) VALUES - ('MySQL from Tutorial','DBMS stands for DataBase ...') , - ('when To Use MySQL Well','After that you went through a ...'), - ('where will Optimizing MySQL','In what tutorial we will show ...'), - ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), - ('MySQL vs. YourSQL','In the following database comparison ...'), - ('MySQL Security','When configured properly, MySQL ...'); - -# Case : server_stopword=default -# Try to Search default stopword from innodb, "where", "will", "what" -# and "when" are all stopwords -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("when"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("what" WITH QUERY EXPANSION); -# boolean No result expected -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("whe*" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+what +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+from" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+where +(show what)" IN BOOLEAN MODE); -# no result expected -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@6' IN BOOLEAN MODE); -# no result expected -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@9' IN BOOLEAN MODE); - -INSERT INTO articles(title,body) values ('the record will' , 'not index the , will words'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOLEAN MODE); -# Not going to update as where condition can not find record -UPDATE articles SET title = "update the record" , body = 'to see will is indexed or not' -WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -# Update the record -UPDATE articles SET title = "update the record" , body = 'to see will is indexed or not' -WHERE id = 7; -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -# Delete will not work as where condition do not return -DELETE FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE id = 7; -DELETE FROM articles WHERE id = 7; - - - -# Case : Turn OFF stopword list variable and search stopword on OLD index. -# disable stopword list -#SET global innodb_ft_server_stopword_table = ""; -SET SESSION innodb_ft_enable_stopword = 0; -select @@innodb_ft_enable_stopword; -#SET global innodb_ft_user_stopword_table = ""; - -# search default stopword with innodb_ft_enable_stopword is OFF. -# No records expected even though we turned OFF stopwod filtering -# (refer Behavior (at the top of the test) for explanation ) -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("when"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("what" WITH QUERY EXPANSION); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("whe*" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+what +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+from" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+where +(show what)" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@6' IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@9' IN BOOLEAN MODE); - -INSERT INTO articles(title,body) values ('the record will' , 'not index the , will words'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOLEAN MODE); -# Not going to update as where condition can not find record -UPDATE articles SET title = "update the record" , body = 'to see will is indexed or not' -WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -# Update the record -UPDATE articles SET title = "update the record" , body = 'to see will is indexed or not' -WHERE id = 8; -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -SELECT * FROM articles WHERE id = 8; -# Delete will not work as where condition do not return -DELETE FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE id = 8; -DELETE FROM articles WHERE id = 8; - -# Case : Turn OFF stopword list variable and search stopword on NEW index. -# Drop index -ALTER TABLE articles DROP INDEX idx; -SHOW CREATE TABLE articles; - -# Create the FTS index Using Alter Table. -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); - -ANALYZE TABLE articles; - -# search default stopword with innodb_ft_enable_stopword is OFF. -# All records expected as stopwod filtering is OFF and we created -# new FTS index. -# (refer Behavior (at the top of the test) for explanation ) -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("when"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("what" WITH QUERY EXPANSION); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("whe*" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+what +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+from" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+where +(show what)" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@6' IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@9' IN BOOLEAN MODE); - -INSERT INTO articles(title,body) values ('the record will' , 'not index the , will words'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOLEAN MODE); -# Update will succeed. -UPDATE articles SET title = "update the record" , body = 'to see will is indexed or not' -WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); - -SELECT COUNT(*),max(id) FROM articles; -# Update the record - uncommet on fix -#UPDATE articles SET title = "update the record" , body = 'to see will is indexed or not' -#WHERE id = 9; -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -# Delete will succeed. -DELETE FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE id = 9; - - -DROP TABLE articles; - -eval SET SESSION innodb_ft_enable_stopword=$innodb_ft_enable_stopword_orig; -#eval SET GLOBAL innodb_ft_server_stopword_table=$innodb_ft_server_stopword_table_orig; -eval SET GLOBAL innodb_ft_server_stopword_table=default; -#eval SET GLOBAL innodb_ft_user_stopword_table=$innodb_ft_user_stopword_table_orig; -eval SET SESSION innodb_ft_user_stopword_table=default; - -#--------------------------------------------------------------------------------------- - -select @@innodb_ft_server_stopword_table; -select @@innodb_ft_enable_stopword; -select @@innodb_ft_user_stopword_table; - -# Create FTS table -CREATE TABLE articles ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, - title VARCHAR(200), - body TEXT, - FULLTEXT `idx` (title,body) - ) ENGINE=InnoDB; - -# Insert six rows -INSERT INTO articles (title,body) VALUES - ('MySQL from Tutorial','DBMS stands for DataBase ...') , - ('when To Use MySQL Well','After that you went through a ...'), - ('where will Optimizing MySQL','In what tutorial we will show ...'), - ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), - ('MySQL vs. YourSQL','In the following database comparison ...'), - ('MySQL Security','When configured properly, MySQL ...'); - -# No records expeced for select -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -# Define a correct formatted user stopword table -create table user_stopword(value varchar(30)) engine = innodb; -# The set operation should be successful -set session innodb_ft_user_stopword_table = "test/user_stopword"; -# Define a correct formatted server stopword table -create table server_stopword(value varchar(30)) engine = innodb; -# The set operation should be successful -set global innodb_ft_server_stopword_table = "test/server_stopword"; -# Add values into user supplied stop word table -insert into user_stopword values("this"),("will"),("the"); - -# Drop existing index and create the FTS index Using Alter Table. -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); - -# Add values into server supplied stop word table -insert into server_stopword values("what"),("where"); -# Follwoing should return result as server stopword list was empty at create index time -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); - -# Delete stopword from user list -DELETE FROM user_stopword; -# Drop existing index and create the FTS index Using Alter Table. -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -# Follwoing should return result even though to server stopword list -# conatin these words. Session level stopword list takes priority -# Here user_stopword is set using innodb_ft_user_stopword_table -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); - -# Follwoing should return result as user stopword list was empty at create index time -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); - -# Add values into user supplied stop word table -insert into user_stopword values("this"),("will"),("the"); - -# Drop existing index and create the FTS index Using Alter Table. -ALTER TABLE articles DROP INDEX idx; -SET SESSION innodb_ft_enable_stopword = 0; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); - -# Session level stopword list takes priority -SET SESSION innodb_ft_enable_stopword = 1; -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); - -# Make user stopword list deafult so as to server stopword list takes priority -SET SESSION innodb_ft_enable_stopword = 1; -SET SESSION innodb_ft_user_stopword_table = default; -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); - - -DROP TABLE articles,user_stopword,server_stopword; - -# Restore Defaults -eval SET SESSION innodb_ft_enable_stopword=$innodb_ft_enable_stopword_orig; -eval SET GLOBAL innodb_ft_server_stopword_table=default; -eval SET SESSION innodb_ft_user_stopword_table=default; -select @@innodb_ft_server_stopword_table; -select @@innodb_ft_enable_stopword; -select @@innodb_ft_user_stopword_table; - -#--------------------------------------------------------------------------------------- -# Create FTS table -CREATE TABLE articles ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, - title VARCHAR(200), - body TEXT, - FULLTEXT `idx` (title,body) - ) ENGINE=InnoDB; - -SHOW CREATE TABLE articles; - -# Insert six rows -INSERT INTO articles (title,body) VALUES - ('MySQL from Tutorial','DBMS stands for DataBase ...') , - ('when To Use MySQL Well','After that you went through a ...'), - ('where will Optimizing MySQL','In what tutorial we will show ...'), - ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), - ('MySQL vs. YourSQL','In the following database comparison ...'), - ('MySQL Security','When configured properly, MySQL ...'); - -# No records expeced for select -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -# Define a correct formatted user stopword table -create table user_stopword(value varchar(30)) engine = innodb; -# The set operation should be successful -set session innodb_ft_user_stopword_table = "test/user_stopword"; -insert into user_stopword values("mysqld"),("DBMS"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+DBMS +mysql" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysqld'); - - -# Drop existing index and create the FTS index Using Alter Table. -# user stopword list will take effect. -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+DBMS +mysql" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysqld'); - -# set user stopword list empty -set session innodb_ft_user_stopword_table = default; -# Define a correct formatted user stopword table -create table server_stopword(value varchar(30)) engine = innodb; -# The set operation should be successful -set global innodb_ft_server_stopword_table = "test/server_stopword"; -insert into server_stopword values("root"),("properly"); -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+root +mysql" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('properly'); - - -# set user stopword list empty -set session innodb_ft_user_stopword_table = "test/user_stopword"; -# The set operation should be successful -set global innodb_ft_server_stopword_table = "test/server_stopword"; -# user stopword list take effect as its session level -# Result expected for select -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+root +mysql" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('properly'); - -# set user stopword list -set session innodb_ft_user_stopword_table = "test/user_stopword"; -DELETE FROM user_stopword; -# The set operation should be successful -set global innodb_ft_server_stopword_table = "test/server_stopword"; -DELETE FROM server_stopword; -# user stopword list take affect as its session level -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+wha* +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('what'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+root +mysql" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('properly'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+DBMS +mysql" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysqld'); - -DROP TABLE articles,user_stopword,server_stopword; - -# Restore Values -eval SET SESSION innodb_ft_enable_stopword=$innodb_ft_enable_stopword_orig; -eval SET GLOBAL innodb_ft_server_stopword_table=default; -eval SET SESSION innodb_ft_user_stopword_table=default; - - -#------------------------------------------------------------------------------ -# FTS stopword list test - check varaibles across sessions - -# Create FTS table -CREATE TABLE articles ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, - title VARCHAR(200), - body TEXT, - FULLTEXT `idx` (title,body) - ) ENGINE=InnoDB; - -SHOW CREATE TABLE articles; - -# Insert six rows -INSERT INTO articles (title,body) VALUES - ('MySQL from Tutorial','DBMS stands for DataBase ...') , - ('when To Use MySQL Well','After that you went through a ...'), - ('where will Optimizing MySQL','In what tutorial we will show ...'), - ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), - ('MySQL vs. YourSQL','In the following database comparison ...'), - ('MySQL Security','When configured properly, MySQL ...'); - -# session varaible innodb_ft_enable_stopword=0 will take effect for new FTS index -SET SESSION innodb_ft_enable_stopword = 0; -select @@innodb_ft_enable_stopword; - -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); - - ---connection con1 -select @@innodb_ft_enable_stopword; - -ANALYZE TABLE articles; - -# result expected as index created before setting innodb_ft_enable_stopword varaible off -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("when"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("what" WITH QUERY EXPANSION); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("whe*" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+what +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+from" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+where +(show what)" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@6' IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@9' IN BOOLEAN MODE); - -SET SESSION innodb_ft_enable_stopword = 1; -select @@innodb_ft_enable_stopword; -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -# no result expected turned innodb_ft_enable_stopword is ON -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("when"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("what" WITH QUERY EXPANSION); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("whe*" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+what +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+from" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+where +(show what)" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@6' IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@9' IN BOOLEAN MODE); - - ---connection default -select @@innodb_ft_enable_stopword; -# no result expected as word not indexed from connection 1 -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("where will"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("when"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST ("what" WITH QUERY EXPANSION); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("whe*" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+what +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+from" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+where +(show what)" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@6' IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"where will"@9' IN BOOLEAN MODE); - -INSERT INTO articles(title,body) values ('the record will' , 'not index the , will words'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOLEAN MODE); - -SET SESSION innodb_ft_enable_stopword = 1; -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+the +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOLEAN MODE); - - ---connection con1 -SET SESSION innodb_ft_enable_stopword = 1; -# Define a correct formatted user stopword table -create table user_stopword(value varchar(30)) engine = innodb; -# The set operation should be successful -set session innodb_ft_user_stopword_table = "test/user_stopword"; -# Add values into user supplied stop word table -insert into user_stopword values("this"),("will"),("the"); -# Drop existing index and create the FTS index Using Alter Table. -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -# no result expected as innodb_ft_user_stopword_table filter it -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); - - ---connection default -# no result expected as innodb_ft_user_stopword_table filter it from connection1 -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); -select @@innodb_ft_user_stopword_table; -# Define a correct formatted user stopword table -create table user_stopword_1(value varchar(30)) engine = innodb; -# The set operation should be successful -set session innodb_ft_user_stopword_table = "test/user_stopword_1"; -insert into user_stopword_1 values("when"); -SET SESSION innodb_ft_enable_stopword = 1; -# result expected -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+when" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('when'); -# Drop existing index and create the FTS index Using Alter Table. -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -# no result expected -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+when" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('when'); - ---connection con1 -SET SESSION innodb_ft_enable_stopword = 1; -SET SESSION innodb_ft_user_stopword_table=default; -select @@innodb_ft_user_stopword_table; -select @@innodb_ft_server_stopword_table; -# Define a correct formatted server stopword table -create table server_stopword(value varchar(30)) engine = innodb; -# The set operation should be successful -SET GLOBAL innodb_ft_server_stopword_table = "test/server_stopword"; -select @@innodb_ft_server_stopword_table; -insert into server_stopword values("when"),("the"); -# Drop existing index and create the FTS index Using Alter Table. -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -# no result expected -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+when" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('the'); - -disconnect con1; ---source include/wait_until_disconnected.inc - ---connection default -SET SESSION innodb_ft_enable_stopword = 1; -SET SESSION innodb_ft_user_stopword_table=default; -select @@innodb_ft_server_stopword_table; -# result expected -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+will +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('where'); -insert into server_stopword values("where"),("will"); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+will +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('where'); -ALTER TABLE articles DROP INDEX idx; -ALTER TABLE articles ADD FULLTEXT INDEX idx (title,body); -# no result expected -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+when" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('the'); -SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+will +where" IN BOOLEAN MODE); -SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('where'); - - -DROP TABLE articles,user_stopword,user_stopword_1,server_stopword; - -# Restore Values -eval SET SESSION innodb_ft_enable_stopword=$innodb_ft_enable_stopword_orig; -eval SET GLOBAL innodb_ft_server_stopword_table=default; -eval SET SESSION innodb_ft_user_stopword_table=default; - diff --git a/mysql-test/suite/innodb_fts/t/innodb_ft_aux_table.test b/mysql-test/suite/innodb_fts/t/innodb_ft_aux_table.test index 48964aef4fd..f9447aada60 100644 --- a/mysql-test/suite/innodb_fts/t/innodb_ft_aux_table.test +++ b/mysql-test/suite/innodb_fts/t/innodb_ft_aux_table.test @@ -1,4 +1,5 @@ --source include/have_innodb.inc +--source include/maybe_versioning.inc CREATE TABLE t1 (v VARCHAR(100), FULLTEXT INDEX (v)) ENGINE=InnoDB; diff --git a/mysql-test/suite/innodb_fts/t/innodb_fts_large_records.test b/mysql-test/suite/innodb_fts/t/innodb_fts_large_records.test index e200cff6c39..c84cd0685ed 100644 --- a/mysql-test/suite/innodb_fts/t/innodb_fts_large_records.test +++ b/mysql-test/suite/innodb_fts/t/innodb_fts_large_records.test @@ -3,6 +3,7 @@ # b) more words across records --source include/have_innodb.inc +--source include/maybe_versioning.inc --disable_warnings DROP TABLE IF EXISTS t1; diff --git a/mysql-test/suite/innodb_fts/t/innodb_fts_multiple_index.test b/mysql-test/suite/innodb_fts/t/innodb_fts_multiple_index.test index c8293655d1b..f9535c729ff 100644 --- a/mysql-test/suite/innodb_fts/t/innodb_fts_multiple_index.test +++ b/mysql-test/suite/innodb_fts/t/innodb_fts_multiple_index.test @@ -2,6 +2,7 @@ # Test With two FTS index on same table + alter/create/drop index + tnx #------------------------------------------------------------------------------ --source include/have_innodb.inc +--source include/maybe_versioning.inc --disable_warnings drop table if exists t1; diff --git a/mysql-test/suite/innodb_fts/t/innodb_fts_proximity.test b/mysql-test/suite/innodb_fts/t/innodb_fts_proximity.test index 20eee3fac23..e3d8eb0c13b 100644 --- a/mysql-test/suite/innodb_fts/t/innodb_fts_proximity.test +++ b/mysql-test/suite/innodb_fts/t/innodb_fts_proximity.test @@ -1,4 +1,5 @@ --source include/have_innodb.inc +--source include/maybe_versioning.inc # This is the DDL function tests for innodb FTS # Functional testing with FTS proximity search using '@' diff --git a/mysql-test/suite/innodb_fts/t/innodb_fts_result_cache_limit.test b/mysql-test/suite/innodb_fts/t/innodb_fts_result_cache_limit.test index 669808edbf6..1ec37532a71 100644 --- a/mysql-test/suite/innodb_fts/t/innodb_fts_result_cache_limit.test +++ b/mysql-test/suite/innodb_fts/t/innodb_fts_result_cache_limit.test @@ -4,6 +4,7 @@ # Must have debug code to use SET SESSION debug --source include/have_debug.inc +--source include/maybe_versioning.inc # Create FTS table CREATE TABLE t1 ( diff --git a/mysql-test/suite/innodb_fts/t/innodb_fts_stopword_charset.test b/mysql-test/suite/innodb_fts/t/innodb_fts_stopword_charset.test index 16ee91c30f4..3fe99dab2c3 100644 --- a/mysql-test/suite/innodb_fts/t/innodb_fts_stopword_charset.test +++ b/mysql-test/suite/innodb_fts/t/innodb_fts_stopword_charset.test @@ -4,6 +4,7 @@ # Embedded server tests do not support restarting --source include/not_embedded.inc +--source include/maybe_versioning.inc SELECT @@innodb_ft_server_stopword_table; SELECT @@innodb_ft_enable_stopword; diff --git a/mysql-test/suite/innodb_fts/t/innodb_fts_transaction.test b/mysql-test/suite/innodb_fts/t/innodb_fts_transaction.test index 11571f346a2..026aeb635cd 100644 --- a/mysql-test/suite/innodb_fts/t/innodb_fts_transaction.test +++ b/mysql-test/suite/innodb_fts/t/innodb_fts_transaction.test @@ -5,6 +5,7 @@ # 3) UNCOMMITTED RECORDS CAN BE SEEN WITH QURIES WHICH DO NOT USE FTS INDEX # this behavior do not break integratity of tables and "select" which do not use FTS still can view them. --source include/have_innodb.inc +--source include/maybe_versioning.inc --disable_warnings diff --git a/mysql-test/suite/innodb_fts/t/misc_debug.test b/mysql-test/suite/innodb_fts/t/misc_debug.test index cf3651e14a2..5e59ae6aba1 100644 --- a/mysql-test/suite/innodb_fts/t/misc_debug.test +++ b/mysql-test/suite/innodb_fts/t/misc_debug.test @@ -7,6 +7,7 @@ --source include/have_debug.inc --source include/have_debug_sync.inc --source include/count_sessions.inc +--source include/maybe_versioning.inc # Following test is for Bug 14668777 - ASSERT ON IB_VECTOR_SIZE( # TABLE->FTS->INDEXES, ALTER TABLE diff --git a/mysql-test/suite/innodb_fts/t/stopword.inc b/mysql-test/suite/innodb_fts/t/stopword.inc new file mode 100644 index 00000000000..774501ade85 --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/stopword.inc @@ -0,0 +1,55 @@ +if ($stopword_stage == create_table) +{ +call mtr.add_suppression("\\[ERROR\\] InnoDB: user stopword table not_defined does not exist."); +call mtr.add_suppression("\\[ERROR\\] InnoDB: user stopword table test/user_stopword_session does not exist."); + +select * from information_schema.innodb_ft_default_stopword; + +# Create FTS table +eval CREATE TABLE $stopword_table ( + id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, + title VARCHAR(200), + body TEXT, + FULLTEXT (title,body) + )$create_options ENGINE=InnoDB; + +# Insert six rows +eval INSERT INTO $stopword_table (title,body) VALUES + ('MySQL Tutorial','DBMS stands for DataBase ...') , + ('How To Use MySQL Well','After you went through a ...'), + ('Optimizing MySQL','In this tutorial we will show ...'), + ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), + ('MySQL vs. YourSQL','In the following database comparison ...'), + ('MySQL Security','When configured properly, MySQL ...'); + +# "the" is in the default stopword, it would not be selected +eval SELECT * FROM $stopword_table WHERE MATCH (title,body) + AGAINST ('the' IN NATURAL LANGUAGE MODE); + +# Provide user defined stopword table, if not (correctly) defined, +# it will be rejected +--error ER_WRONG_VALUE_FOR_VAR +set global innodb_ft_server_stopword_table = "not_defined"; +set global innodb_ft_server_stopword_table = NULL; + +# Define a correct formatted user stopword table +eval create table user_stopword(value varchar(30))$create_options engine = innodb; + +# The set operation should be successful +set global innodb_ft_server_stopword_table = "test/user_stopword"; + +eval drop index title on $stopword_table; + +eval create fulltext index idx on $stopword_table(title, body); +} + +if ($stopword_stage == select_1) +{ +--error 0, ER_INDEX_CORRUPT +eval SELECT * FROM $stopword_table WHERE MATCH (title,body) + AGAINST ('the' IN NATURAL LANGUAGE MODE); +--error 0, ER_INDEX_CORRUPT +eval SELECT * FROM $stopword_table WHERE MATCH (title,body) + AGAINST ('this' IN NATURAL LANGUAGE MODE); + +} diff --git a/mysql-test/suite/innodb_fts/t/stopword.test b/mysql-test/suite/innodb_fts/t/stopword.test index ca01da80734..9f8bd89b816 100644 --- a/mysql-test/suite/innodb_fts/t/stopword.test +++ b/mysql-test/suite/innodb_fts/t/stopword.test @@ -1,52 +1,16 @@ # This is the basic function tests for innodb FTS -- source include/have_innodb.inc - -call mtr.add_suppression("\\[ERROR\\] InnoDB: user stopword table not_defined does not exist."); -call mtr.add_suppression("\\[ERROR\\] InnoDB: user stopword table test/user_stopword_session does not exist."); - -select * from information_schema.innodb_ft_default_stopword; - -# Create FTS table -CREATE TABLE articles ( - id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, - title VARCHAR(200), - body TEXT, - FULLTEXT (title,body) - ) ENGINE=InnoDB; - -# Insert six rows -INSERT INTO articles (title,body) VALUES - ('MySQL Tutorial','DBMS stands for DataBase ...') , - ('How To Use MySQL Well','After you went through a ...'), - ('Optimizing MySQL','In this tutorial we will show ...'), - ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), - ('MySQL vs. YourSQL','In the following database comparison ...'), - ('MySQL Security','When configured properly, MySQL ...'); - -# "the" is in the default stopword, it would not be selected -SELECT * FROM articles WHERE MATCH (title,body) - AGAINST ('the' IN NATURAL LANGUAGE MODE); +-- let $modify_create_table= 1 +-- source include/maybe_versioning.inc SET @innodb_ft_server_stopword_table_orig=@@innodb_ft_server_stopword_table; SET @innodb_ft_enable_stopword_orig=@@innodb_ft_enable_stopword; SET @innodb_ft_user_stopword_table_orig=@@innodb_ft_user_stopword_table; -# Provide user defined stopword table, if not (correctly) defined, -# it will be rejected ---error ER_WRONG_VALUE_FOR_VAR -set global innodb_ft_server_stopword_table = "not_defined"; -set global innodb_ft_server_stopword_table = NULL; - -# Define a correct formatted user stopword table -create table user_stopword(value varchar(30)) engine = innodb; - -# The set operation should be successful -set global innodb_ft_server_stopword_table = "test/user_stopword"; - -drop index title on articles; - -create fulltext index idx on articles(title, body); +let $stopword_table= articles; +let $stopword_stage= create_table; +--source stopword.inc # Now we should be able to find "the" SELECT * FROM articles WHERE MATCH (title,body) @@ -55,12 +19,12 @@ SELECT * FROM articles WHERE MATCH (title,body) # Nothing inserted into the default stopword, so essentially # nothing get screened. The new stopword could only be # effective for table created thereafter -CREATE TABLE articles_2 ( +eval CREATE TABLE articles_2 ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT (title,body) - ) ENGINE=InnoDB; + )$create_options ENGINE=InnoDB; INSERT INTO articles_2 (title, body) VALUES ('test for stopwords','this is it...'); @@ -71,15 +35,17 @@ SELECT * FROM articles_2 WHERE MATCH (title,body) # Ok, let's instantiate some value into user supplied stop word # table +insert into user_stopword values("the"); +delete from user_stopword; insert into user_stopword values("this"); # Ok, let's repeat with the new table again. -CREATE TABLE articles_3 ( +eval CREATE TABLE articles_3 ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT (title,body) - ) ENGINE=InnoDB; + )$create_options ENGINE=InnoDB; INSERT INTO articles_3 (title, body) VALUES ('test for stopwords','this is it...'); @@ -89,18 +55,20 @@ SELECT * FROM articles_3 WHERE MATCH (title,body) AGAINST ('this' IN NATURAL LANGUAGE MODE); # Test session level stopword control "innodb_user_stopword_table" -create table user_stopword_session(value varchar(30)) engine = innodb; +eval create table user_stopword_session(value varchar(30))$create_options engine = innodb; +insert into user_stopword values("this"); +delete from user_stopword; insert into user_stopword_session values("session"); set session innodb_ft_user_stopword_table="test/user_stopword_session"; -CREATE TABLE articles_4 ( +eval CREATE TABLE articles_4 ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT (title,body) - ) ENGINE=InnoDB; + )$create_options ENGINE=InnoDB; INSERT INTO articles_4 (title, body) VALUES ('test for session stopwords','this should also be excluded...'); @@ -114,12 +82,12 @@ SELECT * FROM articles_4 WHERE MATCH (title,body) AGAINST ('this' IN NATURAL LANGUAGE MODE); --connect (con1,localhost,root,,) -CREATE TABLE articles_5 ( +eval CREATE TABLE articles_5 ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT (title,body) - ) ENGINE=InnoDB; + )$create_options ENGINE=InnoDB; INSERT INTO articles_5 (title, body) VALUES ('test for session stopwords','this should also be excluded...'); @@ -153,12 +121,12 @@ SET GLOBAL innodb_ft_server_stopword_table=default; # the settings. # Create FTS table -CREATE TABLE articles ( +eval CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT `idx` (title,body) - ) ENGINE=InnoDB; + )$create_options ENGINE=InnoDB; SHOW CREATE TABLE articles; @@ -292,12 +260,12 @@ SET GLOBAL innodb_ft_user_stopword_table=@innodb_ft_user_stopword_table_orig; SET SESSION innodb_ft_user_stopword_table=default; # Create FTS table -CREATE TABLE articles ( +eval CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT `idx` (title,body) - ) ENGINE=InnoDB; + )$create_options ENGINE=InnoDB; # Insert six rows INSERT INTO articles (title,body) VALUES @@ -312,14 +280,16 @@ INSERT INTO articles (title,body) VALUES SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); # Define a correct formatted user stopword table -create table user_stopword(value varchar(30)) engine = innodb; +eval create table user_stopword(value varchar(30))$create_options engine = innodb; # The set operation should be successful set session innodb_ft_user_stopword_table = "test/user_stopword"; # Define a correct formatted server stopword table -create table server_stopword(value varchar(30)) engine = innodb; +eval create table server_stopword(value varchar(30))$create_options engine = innodb; # The set operation should be successful set global innodb_ft_server_stopword_table = "test/server_stopword"; # Add values into user supplied stop word table +insert into user_stopword values("when"),("where"); +delete from user_stopword; insert into user_stopword values("this"),("will"),("the"); # Drop existing index and create the FTS index Using Alter Table. @@ -390,12 +360,12 @@ SET SESSION innodb_ft_user_stopword_table=default; #--------------------------------------------------------------------------------------- # Create FTS table -CREATE TABLE articles ( +eval CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT `idx` (title,body) - ) ENGINE=InnoDB; + )$create_options ENGINE=InnoDB; SHOW CREATE TABLE articles; @@ -412,7 +382,7 @@ INSERT INTO articles (title,body) VALUES SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN MODE); SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); # Define a correct formatted user stopword table -create table user_stopword(value varchar(30)) engine = innodb; +eval create table user_stopword(value varchar(30))$create_options engine = innodb; # The set operation should be successful set session innodb_ft_user_stopword_table = "test/user_stopword"; insert into user_stopword values("mysqld"),("DBMS"); @@ -434,7 +404,7 @@ SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('mysqld'); # set user stopword list empty set session innodb_ft_user_stopword_table = default; # Define a correct formatted user stopword table -create table server_stopword(value varchar(30)) engine = innodb; +eval create table server_stopword(value varchar(30))$create_options engine = innodb; # The set operation should be successful set global innodb_ft_server_stopword_table = "test/server_stopword"; insert into server_stopword values("root"),("properly"); @@ -487,12 +457,12 @@ SET SESSION innodb_ft_user_stopword_table=default; # FTS stopword list test - check varaibles across sessions # Create FTS table -CREATE TABLE articles ( +eval CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT `idx` (title,body) - ) ENGINE=InnoDB; + )$create_options ENGINE=InnoDB; SHOW CREATE TABLE articles; @@ -573,7 +543,7 @@ SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('"the will"@11' IN BOOL --connection con1 SET SESSION innodb_ft_enable_stopword = 1; # Define a correct formatted user stopword table -create table user_stopword(value varchar(30)) engine = innodb; +eval create table user_stopword(value varchar(30))$create_options engine = innodb; # The set operation should be successful set session innodb_ft_user_stopword_table = "test/user_stopword"; # Add values into user supplied stop word table @@ -593,7 +563,7 @@ SELECT * FROM articles WHERE MATCH(title,body) AGAINST("+show +will" IN BOOLEAN SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('will'); select @@innodb_ft_user_stopword_table; # Define a correct formatted user stopword table -create table user_stopword_1(value varchar(30)) engine = innodb; +eval create table user_stopword_1(value varchar(30))$create_options engine = innodb; # The set operation should be successful set session innodb_ft_user_stopword_table = "test/user_stopword_1"; insert into user_stopword_1 values("when"); @@ -615,7 +585,7 @@ SET SESSION innodb_ft_user_stopword_table=default; select @@innodb_ft_user_stopword_table; select @@innodb_ft_server_stopword_table; # Define a correct formatted server stopword table -create table server_stopword(value varchar(30)) engine = innodb; +eval create table server_stopword(value varchar(30))$create_options engine = innodb; # The set operation should be successful SET GLOBAL innodb_ft_server_stopword_table = "test/server_stopword"; select @@innodb_ft_server_stopword_table; diff --git a/mysql-test/suite/innodb_fts/t/sync.test b/mysql-test/suite/innodb_fts/t/sync.test index 6929dce31b8..3bd5b56a21b 100644 --- a/mysql-test/suite/innodb_fts/t/sync.test +++ b/mysql-test/suite/innodb_fts/t/sync.test @@ -7,6 +7,7 @@ --source include/not_valgrind.inc --source include/not_embedded.inc --source include/not_crashrep.inc +--source include/maybe_versioning.inc connect (con1,localhost,root,,); connection default; diff --git a/mysql-test/suite/innodb_fts/t/sync_block.test b/mysql-test/suite/innodb_fts/t/sync_block.test index 895d2ba8a59..593c8fd9176 100644 --- a/mysql-test/suite/innodb_fts/t/sync_block.test +++ b/mysql-test/suite/innodb_fts/t/sync_block.test @@ -7,6 +7,7 @@ --source include/have_debug_sync.inc --source include/have_log_bin.inc --source include/count_sessions.inc +--source include/maybe_versioning.inc SET @old_log_output = @@global.log_output; SET @old_slow_query_log = @@global.slow_query_log; diff --git a/mysql-test/suite/innodb_fts/t/sync_ddl.test b/mysql-test/suite/innodb_fts/t/sync_ddl.test index 2950297d5bb..f3919ba1c94 100644 --- a/mysql-test/suite/innodb_fts/t/sync_ddl.test +++ b/mysql-test/suite/innodb_fts/t/sync_ddl.test @@ -4,6 +4,7 @@ --source include/have_innodb.inc --source include/have_debug.inc +--source include/maybe_versioning.inc #-------------------------------------- # Check FTS_sync vs TRUNCATE (1) diff --git a/mysql-test/suite/innodb_fts/t/versioning.combinations b/mysql-test/suite/innodb_fts/t/versioning.combinations new file mode 100644 index 00000000000..42842ba51a6 --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/versioning.combinations @@ -0,0 +1,2 @@ +[prepare] +[upgrade] diff --git a/mysql-test/suite/innodb_fts/t/versioning.opt b/mysql-test/suite/innodb_fts/t/versioning.opt new file mode 100644 index 00000000000..df323743314 --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/versioning.opt @@ -0,0 +1,2 @@ +--innodb-file-per-table=0 +--innodb-doublewrite=0 diff --git a/mysql-test/suite/innodb_fts/t/versioning.test b/mysql-test/suite/innodb_fts/t/versioning.test new file mode 100644 index 00000000000..b492f9c9d98 --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/versioning.test @@ -0,0 +1,126 @@ +--source include/have_innodb.inc +--source include/have_gzip.inc +--source include/not_embedded.inc + +# Combinations +# +# upgrade: test upgrade on prepared databases from std_data. +# prepare: requires $OLD_BINDIR, test upgrade and downgrade with old-version +# server. Also prepare std_data files during the run in the source +# directory (you just have to commit or reject them). +# +# Examples +# +# export OLD_BINDIR="/home/midenok/src/mariadb/10.3b/build" +# mtr innodb_fts.versioning,orig_stopword,prepare +# + +if ($MTR_COMBINATION_PREPARE) +{ + if (!$OLD_BINDIR) + { + --skip Requires OLD_BINDIR parameter (see test comment) + } +} + +--let $server_id= `select @@server_id` +--let $datadir= `select @@datadir` +--let $std_dir= $MYSQL_TEST_DIR/std_data/versioning +--let $restart_noprint= 3 + +--echo # Upgrade test +let $stopword_table= articles2; + +if ($MTR_COMBINATION_PREPARE) +{ + let $restart_bindir= $OLD_BINDIR; + --source include/restart_mysqld.inc + + let $create_options= with system versioning; + let $basic_stage= create_table; + --source basic.inc + let $basic_stage= insert_1; + --source basic.inc + let $basic_stage= insert_2; + --source basic.inc + let $basic_stage= insert_3; + --source basic.inc + let $stopword_stage= create_table; + --source stopword.inc + eval insert into $stopword_table (title, body) + values ('test for stopwords','this is it...'); + insert into user_stopword values("the"); + delete from user_stopword; + insert into user_stopword values("this"); + --source include/shutdown_mysqld.inc + + --exec mkdir -p $std_dir + --exec cp -af $datadir/ibdata1 $datadir/test/*.frm $std_dir + --exec gzip -9f $std_dir/ibdata1 $std_dir/*.frm +} + +if ($MTR_COMBINATION_UPGRADE) +{ + --source include/shutdown_mysqld.inc + --exec rm -f $datadir/test/*.ibd $datadir/ib* + --exec cp -af $std_dir/ibdata1.gz $datadir + --exec cp -af $std_dir/*.frm.gz $datadir/test + --exec gzip -df $datadir/ibdata1.gz $datadir/test/*.frm.gz +} +let $restart_bindir=; +--source include/start_mysqld.inc + +--error ER_INDEX_CORRUPT +SELECT * FROM articles WHERE MATCH (title,body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); + +call mtr.add_suppression("test/articles.? contains 3 indexes inside InnoDB"); +alter table articles force; +flush tables; +show create table articles; + +let $basic_stage= select_1; +source basic.inc; +let $basic_stage= select_2; +source basic.inc; +let $basic_stage= select_3; +source basic.inc; + +set global innodb_ft_server_stopword_table= "test/user_stopword"; +let $stopword_stage= select_1; +--source stopword.inc +eval drop index idx on $stopword_table; +eval create fulltext index idx on $stopword_table(title, body); +--source stopword.inc + +if ($MTR_COMBINATION_PREPARE) +{ + --echo # Downgrade test + let $restart_bindir= $OLD_BINDIR; + --source include/restart_mysqld.inc + + alter table articles force; + flush tables; + show create table articles; + let $basic_stage= select_1; + source basic.inc; + let $basic_stage= select_2; + source basic.inc; + let $basic_stage= select_3; + source basic.inc; + + set global innodb_ft_server_stopword_table= "test/user_stopword"; + let $stopword_stage= select_1; + # Downgrade faults with assertion "dict_index_get_n_unique(index) == 1" + # until we rebuilt the index: + eval drop index idx on $stopword_table; + eval create fulltext index idx on $stopword_table(title, body); + source stopword.inc; + + let $restart_bindir=; + --source include/restart_mysqld.inc +} + +--echo # Cleanup +eval drop tables articles, $stopword_table, user_stopword; +set global innodb_ft_server_stopword_table= default; diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 9242f713de3..61ea06368a5 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -375,6 +375,11 @@ a b 2 NULL 3 1 4 2 +alter table t add c int, drop system versioning; +select * from t; +a b c +3 1 NULL +4 2 NULL create or replace table t (a int) with system versioning; insert into t values (1), (2), (3); delete from t where a<3; diff --git a/mysql-test/suite/versioning/r/debug.result b/mysql-test/suite/versioning/r/debug.result index 3f1367cf3cb..27ba8ee0e12 100644 --- a/mysql-test/suite/versioning/r/debug.result +++ b/mysql-test/suite/versioning/r/debug.result @@ -19,7 +19,7 @@ show create table tt2; Table Create Table tt2 CREATE TEMPORARY TABLE `tt2` ( `a` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci WITH SYSTEM VERSIONING connect con1, localhost, root; create table t3 (a int); show create table t3; @@ -32,7 +32,7 @@ show create table tt3; Table Create Table tt3 CREATE TEMPORARY TABLE `tt3` ( `a` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci WITH SYSTEM VERSIONING disconnect con1; connection default; set debug_dbug='+d,sysvers_show'; diff --git a/mysql-test/suite/versioning/r/delete.result b/mysql-test/suite/versioning/r/delete.result index 0f9e2c22130..6f8c8921790 100644 --- a/mysql-test/suite/versioning/r/delete.result +++ b/mysql-test/suite/versioning/r/delete.result @@ -146,6 +146,5 @@ delete from t1; select f1, f3, check_row_ts(row_start, row_end) from t1 for system_time all; f1 f3 check_row_ts(row_start, row_end) 1 1 HISTORICAL ROW -1 NULL ERROR: row_end == row_start 1 1 HISTORICAL ROW drop table t1; diff --git a/mysql-test/suite/versioning/r/delete_history.result b/mysql-test/suite/versioning/r/delete_history.result index 065b1f00876..64a05ff6867 100644 --- a/mysql-test/suite/versioning/r/delete_history.result +++ b/mysql-test/suite/versioning/r/delete_history.result @@ -1,3 +1,5 @@ +set @saved_frequency= @@global.innodb_purge_rseg_truncate_frequency; +set global innodb_purge_rseg_truncate_frequency= 1; create table t (a int); delete history from t before system_time now(); ERROR HY000: Table `t` is not system-versioned @@ -165,3 +167,23 @@ x 1 drop prepare stmt; drop table t1; +# +# MDEV-25004 Missing row in FTS_DOC_ID_INDEX during DELETE HISTORY +# +create table t1 (a integer, c0 varchar(255), fulltext key (c0)) +with system versioning engine innodb; +set system_versioning_alter_history= keep; +alter table t1 drop system versioning; +alter table t1 add system versioning; +insert into t1 values (1, 'politician'); +update t1 set c0= 'criminal'; +InnoDB 0 transactions not purged +delete history from t1; +drop table t1; +create table t1 (id int primary key, ftx varchar(255)) +with system versioning engine innodb; +insert into t1 values (1, 'c'); +delete from t1; +alter table t1 add fulltext key(ftx); +drop table t1; +set global innodb_purge_rseg_truncate_frequency= @saved_frequency; diff --git a/mysql-test/suite/versioning/r/foreign.result b/mysql-test/suite/versioning/r/foreign.result index d157916c60c..3eb968f1a33 100644 --- a/mysql-test/suite/versioning/r/foreign.result +++ b/mysql-test/suite/versioning/r/foreign.result @@ -443,6 +443,43 @@ pk f1 f2 left(f3, 4) check_row_ts(row_start, row_end) 1 8 8 SHOR HISTORICAL ROW 2 8 8 LONG HISTORICAL ROW drop table t1; +# Shorter case for clustered index (MDEV-25004) +create table t1 ( +y int primary key, r int, f int, key (r), +foreign key (f) references t1 (r) on delete set null) +with system versioning engine innodb; +insert into t1 values (1, 6, 6), (2, 6, 6); +delete from t1; +select *, check_row_ts(row_start, row_end) from t1 for system_time all; +y r f check_row_ts(row_start, row_end) +1 6 6 HISTORICAL ROW +2 6 6 HISTORICAL ROW +drop tables t1; +# Secondary unique index +create table t1 ( +y int unique null, r int, f int, key (r), +foreign key (f) references t1 (r) on delete set null) +with system versioning engine innodb; +insert into t1 values (1, 6, 6), (2, 6, 6); +delete from t1; +select *, check_row_ts(row_start, row_end) from t1 for system_time all; +y r f check_row_ts(row_start, row_end) +1 6 6 HISTORICAL ROW +2 6 6 HISTORICAL ROW +drop tables t1; +# Non-unique index cannot be fixed because it does not trigger duplicate error +create table t1 ( +y int, r int, f int, key (y), key (r), +foreign key (f) references t1 (r) on delete set null) +with system versioning engine innodb; +insert into t1 values (1, 6, 6), (2, 6, 6); +delete from t1; +select *, check_row_ts(row_start, row_end) from t1 for system_time all; +y r f check_row_ts(row_start, row_end) +1 6 6 HISTORICAL ROW +2 6 NULL ERROR: row_end == row_start +2 6 6 HISTORICAL ROW +drop tables t1; # # MDEV-21555 Assertion secondary index is out of sync on delete from versioned table # diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test index 0900e424bd0..b6562818880 100644 --- a/mysql-test/suite/versioning/t/alter.test +++ b/mysql-test/suite/versioning/t/alter.test @@ -264,6 +264,8 @@ select * from t; select * from t for system_time all; insert into t values (4, 0); select * from t for system_time all; +alter table t add c int, drop system versioning; +select * from t; create or replace table t (a int) with system versioning; insert into t values (1), (2), (3); diff --git a/mysql-test/suite/versioning/t/delete_history.test b/mysql-test/suite/versioning/t/delete_history.test index dae7ff2db9b..f636b5a22fe 100644 --- a/mysql-test/suite/versioning/t/delete_history.test +++ b/mysql-test/suite/versioning/t/delete_history.test @@ -2,6 +2,9 @@ --source include/have_partition.inc --source suite/versioning/engines.inc +set @saved_frequency= @@global.innodb_purge_rseg_truncate_frequency; +set global innodb_purge_rseg_truncate_frequency= 1; + create table t (a int); --error ER_VERS_NOT_VERSIONED delete history from t before system_time now(); @@ -164,4 +167,26 @@ select * from t1; drop prepare stmt; drop table t1; +--echo # +--echo # MDEV-25004 Missing row in FTS_DOC_ID_INDEX during DELETE HISTORY +--echo # +create table t1 (a integer, c0 varchar(255), fulltext key (c0)) +with system versioning engine innodb; +set system_versioning_alter_history= keep; +alter table t1 drop system versioning; +alter table t1 add system versioning; +insert into t1 values (1, 'politician'); +update t1 set c0= 'criminal'; +--source suite/innodb/include/wait_all_purged.inc +delete history from t1; +drop table t1; + +create table t1 (id int primary key, ftx varchar(255)) +with system versioning engine innodb; +insert into t1 values (1, 'c'); +delete from t1; +alter table t1 add fulltext key(ftx); +drop table t1; + +set global innodb_purge_rseg_truncate_frequency= @saved_frequency; --source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/foreign.test b/mysql-test/suite/versioning/t/foreign.test index 1c834719e0f..f4e4fa7a354 100644 --- a/mysql-test/suite/versioning/t/foreign.test +++ b/mysql-test/suite/versioning/t/foreign.test @@ -476,6 +476,39 @@ select pk, f1, f2, left(f3, 4), check_row_ts(row_start, row_end) from t1 for sys # cleanup drop table t1; +--echo # Shorter case for clustered index (MDEV-25004) +create table t1 ( + y int primary key, r int, f int, key (r), + foreign key (f) references t1 (r) on delete set null) +with system versioning engine innodb; + +insert into t1 values (1, 6, 6), (2, 6, 6); +delete from t1; +select *, check_row_ts(row_start, row_end) from t1 for system_time all; +drop tables t1; + +--echo # Secondary unique index +create table t1 ( + y int unique null, r int, f int, key (r), + foreign key (f) references t1 (r) on delete set null) +with system versioning engine innodb; + +insert into t1 values (1, 6, 6), (2, 6, 6); +delete from t1; +select *, check_row_ts(row_start, row_end) from t1 for system_time all; +drop tables t1; + +--echo # Non-unique index cannot be fixed because it does not trigger duplicate error +create table t1 ( + y int, r int, f int, key (y), key (r), + foreign key (f) references t1 (r) on delete set null) +with system versioning engine innodb; + +insert into t1 values (1, 6, 6), (2, 6, 6); +delete from t1; +select *, check_row_ts(row_start, row_end) from t1 for system_time all; +drop tables t1; + --echo # --echo # MDEV-21555 Assertion secondary index is out of sync on delete from versioned table --echo # diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 17437e683f4..7b0967b4461 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2477,7 +2477,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, add_table_options(thd, table, create_info_arg, table_list->schema_table != 0, 0, packet); - if (table->versioned()) + if (DBUG_EVALUATE_IF("sysvers_hide", 0, table->versioned())) packet->append(STRING_WITH_LEN(" WITH SYSTEM VERSIONING")); #ifdef WITH_PARTITION_STORAGE_ENGINE diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 265642ef210..6366efd2248 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -1531,6 +1531,20 @@ dict_index_t::vers_history_row( { ut_ad(!is_primary()); + /* + Get row_end from clustered index + + TODO (optimization): row_end can be taken from unique secondary index + as well. For that dict_index_t::vers_end member should be added and + updated at index init (dict_index_build_internal_non_clust()). + + Test case: + + create or replace table t1 (x int unique, y int unique, + foreign key r (y) references t1 (x)) + with system versioning engine innodb; + insert into t1 values (1, 1); + */ bool error = false; mem_heap_t* heap = NULL; dict_index_t* clust_index = NULL; diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index dc8d529d79c..6a44b8882a7 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -398,8 +398,10 @@ fts_read_stopword( fts_string_t str; mem_heap_t* heap; ib_rbt_bound_t parent; + dict_table_t* table; sel_node = static_cast(row); + table = sel_node->table_list->table; stopword_info = static_cast(user_arg); stop_words = stopword_info->cached_stopword; @@ -414,6 +416,27 @@ fts_read_stopword( str.f_n_char = 0; str.f_str = static_cast(dfield_get_data(dfield)); str.f_len = dfield_get_len(dfield); + exp = que_node_get_next(exp); + ut_ad(exp); + + if (table->versioned()) { + dfield = que_node_get_val(exp); + ut_ad(dfield_get_type(dfield)->vers_sys_end()); + void* data = dfield_get_data(dfield); + ulint len = dfield_get_len(dfield); + if (table->versioned_by_id()) { + ut_ad(len == sizeof trx_id_max_bytes); + if (0 != memcmp(data, trx_id_max_bytes, len)) { + return true; + } + } else { + ut_ad(len == sizeof timestamp_max_bytes); + if (0 != memcmp(data, timestamp_max_bytes, len)) { + return true; + } + } + } + ut_ad(!que_node_get_next(exp)); /* Only create new node if it is a value not already existed */ if (str.f_len != UNIV_SQL_NULL @@ -457,7 +480,9 @@ fts_load_user_stopword( /* Validate the user table existence in the right format */ bool ret= false; - stopword_info->charset = fts_valid_stopword_table(stopword_table_name); + const char* row_end; + stopword_info->charset = fts_valid_stopword_table(stopword_table_name, + &row_end); if (!stopword_info->charset) { cleanup: if (!fts->dict_locked) { @@ -482,6 +507,7 @@ cleanup: pars_info_t* info = pars_info_create(); pars_info_bind_id(info, "table_stopword", stopword_table_name); + pars_info_bind_id(info, "row_end", row_end); pars_info_bind_function(info, "my_func", fts_read_stopword, stopword_info); @@ -490,7 +516,7 @@ cleanup: info, "DECLARE FUNCTION my_func;\n" "DECLARE CURSOR c IS" - " SELECT value" + " SELECT value, $row_end" " FROM $table_stopword;\n" "BEGIN\n" "\n" @@ -1925,9 +1951,16 @@ fts_create_common_tables( goto func_exit; } - index = dict_mem_index_create(table, FTS_DOC_ID_INDEX_NAME, - DICT_UNIQUE, 1); - dict_mem_index_add_field(index, FTS_DOC_ID_COL_NAME, 0); + if (table->versioned()) { + index = dict_mem_index_create(table, FTS_DOC_ID_INDEX_NAME, + DICT_UNIQUE, 2); + dict_mem_index_add_field(index, FTS_DOC_ID_COL_NAME, 0); + dict_mem_index_add_field(index, table->cols[table->vers_end].name(*table), 0); + } else { + index = dict_mem_index_create(table, FTS_DOC_ID_INDEX_NAME, + DICT_UNIQUE, 1); + dict_mem_index_add_field(index, FTS_DOC_ID_COL_NAME, 0); + } op = trx_get_dict_operation(trx); @@ -3427,7 +3460,8 @@ fts_add_doc_by_id( /* Search based on Doc ID. Here, we'll need to consider the case when there is no primary index on Doc ID */ - tuple = dtuple_create(heap, 1); + const ulint n_uniq = table->fts_n_uniq(); + tuple = dtuple_create(heap, n_uniq); dfield = dtuple_get_nth_field(tuple, 0); dfield->type.mtype = DATA_INT; dfield->type.prtype = DATA_NOT_NULL | DATA_UNSIGNED | DATA_BINARY_TYPE; @@ -3435,12 +3469,27 @@ fts_add_doc_by_id( mach_write_to_8((byte*) &temp_doc_id, doc_id); dfield_set_data(dfield, &temp_doc_id, sizeof(temp_doc_id)); + if (n_uniq == 2) { + ut_ad(table->versioned()); + ut_ad(fts_id_index->fields[1].col->vers_sys_end()); + dfield = dtuple_get_nth_field(tuple, 1); + dfield->type.mtype = fts_id_index->fields[1].col->mtype; + dfield->type.prtype = fts_id_index->fields[1].col->prtype; + if (table->versioned_by_id()) { + dfield_set_data(dfield, trx_id_max_bytes, + sizeof(trx_id_max_bytes)); + } else { + dfield_set_data(dfield, timestamp_max_bytes, + sizeof(timestamp_max_bytes)); + } + } + btr_pcur_open_with_no_init( fts_id_index, tuple, PAGE_CUR_LE, BTR_SEARCH_LEAF, &pcur, &mtr); /* If we have a match, add the data to doc structure */ - if (btr_pcur_get_low_match(&pcur) == 1) { + if (btr_pcur_get_low_match(&pcur) == n_uniq) { const rec_t* rec; btr_pcur_t* doc_pcur; const rec_t* clust_rec; @@ -3637,20 +3686,34 @@ fts_get_max_doc_id( if (!page_is_empty(btr_pcur_get_page(&pcur))) { const rec_t* rec = NULL; - rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; - rec_offs* offsets = offsets_; - mem_heap_t* heap = NULL; - ulint len; - const void* data; - - rec_offs_init(offsets_); + const ulint doc_id_len= 8; do { rec = btr_pcur_get_rec(&pcur); - if (page_rec_is_user_rec(rec)) { + if (!page_rec_is_user_rec(rec)) { + continue; + } + + if (index->n_uniq == 1) { break; } + + ut_ad(table->versioned()); + ut_ad(index->n_uniq == 2); + + const byte *data = rec + doc_id_len; + if (table->versioned_by_id()) { + if (0 == memcmp(data, trx_id_max_bytes, + sizeof trx_id_max_bytes)) { + break; + } + } else { + if (0 == memcmp(data, timestamp_max_bytes, + sizeof timestamp_max_bytes)) { + break; + } + } } while (btr_pcur_move_to_prev(&pcur, &mtr)); if (!rec) { @@ -3658,14 +3721,8 @@ fts_get_max_doc_id( } ut_ad(!rec_is_metadata(rec, index)); - offsets = rec_get_offsets( - rec, index, offsets, index->n_core_fields, - ULINT_UNDEFINED, &heap); - data = rec_get_nth_field(rec, offsets, 0, &len); - - doc_id = static_cast(fts_read_doc_id( - static_cast(data))); + doc_id = fts_read_doc_id(rec); } func_exit: @@ -5967,12 +6024,16 @@ void fts_drop_orphaned_tables() /**********************************************************************//** Check whether user supplied stopword table is of the right format. Caller is responsible to hold dictionary locks. -@return the stopword column charset if qualifies */ +@param stopword_table_name table name +@param row_end name of the system-versioning end column, or "value" +@return the stopword column charset +@retval NULL if the table does not exist or qualify */ CHARSET_INFO* fts_valid_stopword_table( /*=====================*/ - const char* stopword_table_name) /*!< in: Stopword table + const char* stopword_table_name, /*!< in: Stopword table name */ + const char** row_end) /* row_end value of system-versioned table */ { dict_table_t* table; dict_col_t* col = NULL; @@ -6014,6 +6075,13 @@ fts_valid_stopword_table( } ut_ad(col); + ut_ad(!table->versioned() || col->ind != table->vers_end); + + if (row_end) { + *row_end = table->versioned() + ? dict_table_get_col_name(table, table->vers_end) + : "value"; /* for fts_load_user_stopword() */ + } return(fts_get_charset(col->prtype)); } @@ -6149,18 +6217,20 @@ cleanup: /**********************************************************************//** Callback function when we initialize the FTS at the start up time. It recovers the maximum Doc IDs presented in the current table. +Tested by innodb_fts.crash_recovery @return: always returns TRUE */ static ibool fts_init_get_doc_id( /*================*/ void* row, /*!< in: sel_node_t* */ - void* user_arg) /*!< in: fts cache */ + void* user_arg) /*!< in: table with fts */ { doc_id_t doc_id = FTS_NULL_DOC_ID; sel_node_t* node = static_cast(row); que_node_t* exp = node->select_list; - fts_cache_t* cache = static_cast(user_arg); + dict_table_t* table = static_cast(user_arg); + fts_cache_t* cache = table->fts->cache; ut_ad(ib_vector_is_empty(cache->get_docs)); @@ -6175,6 +6245,29 @@ fts_init_get_doc_id( doc_id = static_cast(mach_read_from_8( static_cast(data))); + exp = que_node_get_next(que_node_get_next(exp)); + if (exp) { + ut_ad(table->versioned()); + dfield = que_node_get_val(exp); + type = dfield_get_type(dfield); + ut_ad(type->vers_sys_end()); + data = dfield_get_data(dfield); + ulint len = dfield_get_len(dfield); + if (table->versioned_by_id()) { + ut_ad(len == sizeof trx_id_max_bytes); + if (0 != memcmp(data, trx_id_max_bytes, len)) { + return true; + } + } else { + ut_ad(len == sizeof timestamp_max_bytes); + if (0 != memcmp(data, timestamp_max_bytes, len)) { + return true; + } + } + ut_ad(!(exp = que_node_get_next(exp))); + } + ut_ad(!exp); + if (doc_id >= cache->next_doc_id) { cache->next_doc_id = doc_id + 1; } @@ -6340,7 +6433,7 @@ fts_init_index( fts_doc_fetch_by_doc_id(NULL, start_doc, index, FTS_FETCH_DOC_BY_ID_LARGE, - fts_init_get_doc_id, cache); + fts_init_get_doc_id, table); } else { if (table->fts->cache->stopword_info.status & STOPWORD_NOT_INIT) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index a1f58091a90..58b2068b56f 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8967,6 +8967,9 @@ ha_innobase::update_row( innobase_srv_conc_enter_innodb(m_prebuilt); + if (m_prebuilt->upd_node->is_delete) { + trx->fts_next_doc_id = 0; + } error = row_update_for_mysql(m_prebuilt); if (error == DB_SUCCESS && vers_ins_row @@ -9084,6 +9087,7 @@ ha_innobase::delete_row( && trx->id != table->vers_start_id() ? VERSIONED_DELETE : PLAIN_DELETE; + trx->fts_next_doc_id = 0; innobase_srv_conc_enter_innodb(m_prebuilt); @@ -10079,9 +10083,12 @@ ha_innobase::ft_init_ext( /*****************************************************************//** Set up search tuple for a query through FTS_DOC_ID_INDEX on supplied Doc ID. This is used by MySQL to retrieve the documents -once the search result (Doc IDs) is available */ +once the search result (Doc IDs) is available + +@return DB_SUCCESS or DB_INDEX_CORRUPT +*/ static -void +dberr_t innobase_fts_create_doc_id_key( /*===========================*/ dtuple_t* tuple, /* in/out: m_prebuilt->search_tuple */ @@ -10093,8 +10100,10 @@ innobase_fts_create_doc_id_key( { doc_id_t temp_doc_id; dfield_t* dfield = dtuple_get_nth_field(tuple, 0); + const ulint n_uniq = index->table->fts_n_uniq(); - ut_a(dict_index_get_n_unique(index) == 1); + if (dict_index_get_n_unique(index) != n_uniq) + return DB_INDEX_CORRUPT; dtuple_set_n_fields(tuple, index->n_fields); dict_index_copy_types(tuple, index, index->n_fields); @@ -10112,12 +10121,25 @@ innobase_fts_create_doc_id_key( *doc_id = temp_doc_id; dfield_set_data(dfield, doc_id, sizeof(*doc_id)); - dtuple_set_n_fields_cmp(tuple, 1); + if (n_uniq == 2) { + ut_ad(index->table->versioned()); + dfield = dtuple_get_nth_field(tuple, 1); + if (index->table->versioned_by_id()) { + dfield_set_data(dfield, trx_id_max_bytes, + sizeof(trx_id_max_bytes)); + } else { + dfield_set_data(dfield, timestamp_max_bytes, + sizeof(timestamp_max_bytes)); + } + } - for (ulint i = 1; i < index->n_fields; i++) { + dtuple_set_n_fields_cmp(tuple, n_uniq); + + for (ulint i = n_uniq; i < index->n_fields; i++) { dfield = dtuple_get_nth_field(tuple, i); dfield_set_null(dfield); } + return DB_SUCCESS; } /**********************************************************************//** @@ -10199,14 +10221,18 @@ next_record: /* We pass a pointer of search_doc_id because it will be converted to storage byte order used in the search tuple. */ - innobase_fts_create_doc_id_key(tuple, index, &search_doc_id); + dberr_t ret = innobase_fts_create_doc_id_key( + tuple, index, &search_doc_id); - innobase_srv_conc_enter_innodb(m_prebuilt); + if (ret == DB_SUCCESS) { + innobase_srv_conc_enter_innodb(m_prebuilt); - dberr_t ret = row_search_for_mysql( - (byte*) buf, PAGE_CUR_GE, m_prebuilt, ROW_SEL_EXACT, 0); + ret = row_search_for_mysql( + (byte*) buf, PAGE_CUR_GE, m_prebuilt, + ROW_SEL_EXACT, 0); - innobase_srv_conc_exit_innodb(m_prebuilt); + innobase_srv_conc_exit_innodb(m_prebuilt); + } int error; @@ -17537,7 +17563,7 @@ innodb_stopword_table_validate( /* Validate the stopword table's (if supplied) existence and of the right format */ int ret = stopword_table_name && !fts_valid_stopword_table( - stopword_table_name); + stopword_table_name, NULL); row_mysql_unlock_data_dictionary(trx); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 19c90fed74c..fdfc347f8db 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -1341,6 +1341,11 @@ ha_innobase::check_if_supported_inplace_alter( < dict_table_get_n_user_cols(m_prebuilt->table))); if (fulltext_indexes && m_prebuilt->table->fts) { + /* FTS index of versioned table has row_end, need rebuild */ + if (table->versioned() != altered_table->versioned()) { + need_rebuild= true; + } + /* FULLTEXT indexes are supposed to remain. */ /* Disallow DROP INDEX FTS_DOC_ID_INDEX */ @@ -2762,6 +2767,8 @@ innobase_fts_check_doc_id_index( /* Check if a unique index with the name of FTS_DOC_ID_INDEX_NAME is being created. */ + const ulint fts_n_uniq= altered_table->versioned() ? 2 : 1; + for (uint i = 0; i < altered_table->s->keys; i++) { const KEY& key = altered_table->key_info[i]; @@ -2771,7 +2778,7 @@ innobase_fts_check_doc_id_index( } if ((key.flags & HA_NOSAME) - && key.user_defined_key_parts == 1 + && key.user_defined_key_parts == fts_n_uniq && !strcmp(key.name.str, FTS_DOC_ID_INDEX_NAME) && !strcmp(key.key_part[0].field->field_name.str, FTS_DOC_ID_COL_NAME)) { @@ -2801,7 +2808,7 @@ innobase_fts_check_doc_id_index( } if (!dict_index_is_unique(index) - || dict_index_get_n_unique(index) > 1 + || dict_index_get_n_unique(index) != table->fts_n_uniq() || strcmp(index->name, FTS_DOC_ID_INDEX_NAME)) { return(FTS_INCORRECT_DOC_ID_INDEX); } @@ -2842,6 +2849,7 @@ innobase_fts_check_doc_id_index_in_def( { /* Check whether there is a "FTS_DOC_ID_INDEX" in the to be built index list */ + const uint fts_n_uniq= key_info->table->versioned() ? 2 : 1; for (ulint j = 0; j < n_key; j++) { const KEY* key = &key_info[j]; @@ -2852,7 +2860,7 @@ innobase_fts_check_doc_id_index_in_def( /* Do a check on FTS DOC ID_INDEX, it must be unique, named as "FTS_DOC_ID_INDEX" and on column "FTS_DOC_ID" */ if (!(key->flags & HA_NOSAME) - || key->user_defined_key_parts != 1 + || key->user_defined_key_parts != fts_n_uniq || strcmp(key->name.str, FTS_DOC_ID_INDEX_NAME) || strcmp(key->key_part[0].field->field_name.str, FTS_DOC_ID_COL_NAME)) { @@ -3050,13 +3058,21 @@ created_clustered: if (add_fts_doc_idx) { index_def_t* index = indexdef++; + uint nfields = 1; + if (altered_table->versioned()) + ++nfields; index->fields = static_cast( - mem_heap_alloc(heap, sizeof *index->fields)); - index->n_fields = 1; - index->fields->col_no = fts_doc_id_col; - index->fields->prefix_len = 0; - index->fields->is_v_col = false; + mem_heap_alloc(heap, sizeof(*index->fields) * nfields)); + index->n_fields = nfields; + index->fields[0].col_no = fts_doc_id_col; + index->fields[0].prefix_len = 0; + index->fields[0].is_v_col = false; + if (nfields == 2) { + index->fields[1].col_no = altered_table->s->row_end_field; + index->fields[1].prefix_len = 0; + index->fields[1].is_v_col = false; + } index->ind_type = DICT_UNIQUE; ut_ad(!rebuild || !add_fts_doc_id diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index bf7d9931bed..82d0b70b17c 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -2120,6 +2120,9 @@ public: or mysql/innodb_index_stats. @return true if the table name is same as stats table */ bool is_stats_table() const; + + /** @return number of unique columns in FTS_DOC_ID index */ + unsigned fts_n_uniq() const { return versioned() ? 2 : 1; } }; inline void dict_index_t::set_modified(mtr_t& mtr) const diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h index 326734c84c9..2c75fdf66e7 100644 --- a/storage/innobase/include/fts0fts.h +++ b/storage/innobase/include/fts0fts.h @@ -832,15 +832,14 @@ fts_get_max_doc_id( /*===============*/ dict_table_t* table); /*!< in: user table */ -/******************************************************************//** -Check whether user supplied stopword table exists and is of -the right format. -@return the stopword column charset if qualifies */ -CHARSET_INFO* -fts_valid_stopword_table( -/*=====================*/ - const char* stopword_table_name); /*!< in: Stopword table - name */ +/** Check whether a stopword table is in the right format. +@param stopword_table_name table name +@param row_end name of the system-versioning end column, or "value" +@return the stopword column charset +@retval NULL if the table does not exist or qualify */ +CHARSET_INFO *fts_valid_stopword_table(const char *stopword_table_name, + const char **row_end= NULL); + /****************************************************************//** This function loads specified stopword into FTS cache @return true if success */ diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h index 9a16394a052..34427dc6dc7 100644 --- a/storage/innobase/include/row0ins.h +++ b/storage/innobase/include/row0ins.h @@ -206,7 +206,6 @@ struct ins_node_t if this is NULL, entry list should be created and buffers for sys fields in row allocated */ void vers_update_end(row_prebuilt_t *prebuilt, bool history_row); - bool vers_history_row() const; /* true if 'row' is historical */ }; /** Create an insert object. diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h index 9721e975a0a..8fa93467490 100644 --- a/storage/innobase/include/row0upd.h +++ b/storage/innobase/include/row0upd.h @@ -617,17 +617,13 @@ public: void vers_make_update(const trx_t *trx) { vers_update_fields(trx, table->vers_start); - } + } - /** Only set row_end = CURRENT_TIMESTAMP/trx->id. - Do not touch other fields at all. - @param[in] trx transaction */ - void vers_make_delete(const trx_t *trx) - { - update->n_fields = 0; - is_delete = VERSIONED_DELETE; - vers_update_fields(trx, table->vers_end); - } + /** Prepare update vector for versioned delete. + Set row_end to CURRENT_TIMESTAMP or trx->id. + Initialize fts_next_doc_id for versioned delete. + @param[in] trx transaction */ + void vers_make_delete(trx_t *trx); }; #define UPD_NODE_MAGIC_N 1579975 diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 2683ad8251f..f4302a1eca3 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -2059,6 +2059,65 @@ row_ins_dupl_error_with_rec( return(!rec_get_deleted_flag(rec, rec_offs_comp(offsets))); } +/** @return true if history row was inserted by this transaction + (row TRX_ID is the same as current TRX_ID). */ +static +dberr_t vers_row_same_trx(dict_index_t* index, const rec_t* rec, + que_thr_t* thr, bool *same_trx) +{ + mtr_t mtr; + dberr_t ret= DB_SUCCESS; + ulint trx_id_len; + const byte *trx_id_bytes; + trx_id_t trx_id; + dict_index_t *clust_index= dict_table_get_first_index(index->table); + ut_ad(index != clust_index); + + mtr.start(); + + rec_t *clust_rec= + row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr); + rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; + rec_offs *clust_offs= offsets_; + rec_offs_init(offsets_); + mem_heap_t *heap= NULL; + + if (clust_rec) + { + clust_offs= + rec_get_offsets(clust_rec, clust_index, clust_offs, + clust_index->n_core_fields, ULINT_UNDEFINED, &heap); + if (!clust_index->vers_history_row(clust_rec, clust_offs)) + { + *same_trx= false; + goto end; + } + } + else + { + ib::error() << "foreign constraints: secondary index " << index->name << + " of table " << index->table->name << " is out of sync"; + ut_ad("secondary index is out of sync" == 0); + ret= DB_TABLE_CORRUPT; + goto end; + } + + trx_id_bytes= rec_get_nth_field(clust_rec, clust_offs, + clust_index->n_uniq, &trx_id_len); + ut_ad(trx_id_len == DATA_TRX_ID_LEN); + + trx_id= trx_read_trx_id(trx_id_bytes); + + if (UNIV_LIKELY_NULL(heap)) + mem_heap_free(heap); + + *same_trx= thr_get_trx(thr)->id == trx_id; + +end: + mtr.commit(); + return ret; +} + /***************************************************************//** Scans a unique non-clustered index at a given index entry to determine whether a uniqueness violation has occurred for the key value of the entry. @@ -2082,6 +2141,8 @@ row_ins_scan_sec_index_for_duplicate( ulint n_fields_cmp; btr_pcur_t pcur; dberr_t err = DB_SUCCESS; + dberr_t err2; + bool same_trx; ulint allow_duplicates; rec_offs offsets_[REC_OFFS_SEC_INDEX_SIZE]; rec_offs* offsets = offsets_; @@ -2175,10 +2236,25 @@ row_ins_scan_sec_index_for_duplicate( if (cmp == 0) { if (row_ins_dupl_error_with_rec(rec, entry, index, offsets)) { + err = DB_DUPLICATE_KEY; thr_get_trx(thr)->error_info = index; + if (index->table->versioned()) { + err2 = vers_row_same_trx(index, rec, + thr, &same_trx); + if (err2 != DB_SUCCESS) { + err = err2; + goto end_scan; + } + + if (same_trx) { + err = DB_FOREIGN_DUPLICATE_KEY; + goto end_scan; + } + } + /* If the duplicate is on hidden FTS_DOC_ID, state so in the error log */ if (index == index->table->fts_doc_id_index @@ -3580,16 +3656,6 @@ row_ins_get_row_from_select( } } -inline -bool ins_node_t::vers_history_row() const -{ - if (!table->versioned()) - return false; - dfield_t* row_end = dtuple_get_nth_field(row, table->vers_end); - return row_end->vers_history_row(); -} - - /***********************************************************//** Inserts a row to a table. @return DB_SUCCESS if operation successfully completed, else error @@ -3628,31 +3694,12 @@ row_ins( ut_ad(node->state == INS_NODE_INSERT_ENTRIES); while (node->index != NULL) { - dict_index_t *index = node->index; - /* - We do not insert history rows into FTS_DOC_ID_INDEX because - it is unique by FTS_DOC_ID only and we do not want to add - row_end to unique key. Fulltext field works the way new - FTS_DOC_ID is created on every fulltext UPDATE, so holding only - FTS_DOC_ID for history is enough. - */ - const unsigned type = index->type; - if (index->type & DICT_FTS) { - } else if (!(type & DICT_UNIQUE) || index->n_uniq > 1 - || !node->vers_history_row()) { - + if (!(node->index->type & DICT_FTS)) { dberr_t err = row_ins_index_entry_step(node, thr); if (err != DB_SUCCESS) { DBUG_RETURN(err); } - } else { - /* Unique indexes with system versioning must contain - the version end column. The only exception is a hidden - FTS_DOC_ID_INDEX that InnoDB may create on a hidden or - user-created FTS_DOC_ID column. */ - ut_ad(!strcmp(index->name, FTS_DOC_ID_INDEX_NAME)); - ut_ad(!strcmp(index->fields[0].name, FTS_DOC_ID_COL_NAME)); } node->index = dict_table_get_next_index(node->index); diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 7bd15177dad..415c93a9f6f 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -455,6 +455,7 @@ row_merge_buf_redundant_convert( @param[in] new_table new table @param[in,out] psort_info parallel sort info @param[in,out] row table row +@param[in] history_row row is historical in a system-versioned table @param[in] ext cache of externally stored column prefixes, or NULL @param[in,out] doc_id Doc ID if we are creating @@ -477,6 +478,7 @@ row_merge_buf_add( const dict_table_t* new_table, fts_psort_t* psort_info, dtuple_t* row, + const bool history_row, const row_ext_t* ext, doc_id_t* doc_id, mem_heap_t* conv_heap, @@ -540,7 +542,7 @@ error: : NULL; /* Process the Doc ID column */ - if (!v_col && *doc_id + if (!v_col && index->table->fts && (*doc_id || history_row) && col->ind == index->table->fts->doc_col) { fts_write_doc_id((byte*) &write_doc_id, *doc_id); @@ -592,7 +594,7 @@ error: /* Tokenize and process data for FTS */ - if (index->type & DICT_FTS) { + if (!history_row && (index->type & DICT_FTS)) { fts_doc_item_t* doc_item; byte* value; void* ptr; @@ -1705,6 +1707,7 @@ row_merge_read_clustered_index( char new_sys_trx_end[8]; byte any_autoinc_data[8] = {0}; bool vers_update_trt = false; + bool history_row = false; DBUG_ENTER("row_merge_read_clustered_index"); @@ -2132,6 +2135,12 @@ end_of_index: row_heap); ut_ad(row); + if (new_table->versioned()) { + const dfield_t* dfield = dtuple_get_nth_field( + row, new_table->vers_end); + history_row = dfield->vers_history_row(); + } + for (ulint i = 0; i < n_nonnull; i++) { dfield_t* field = &row->fields[nonnull[i]]; @@ -2161,7 +2170,7 @@ end_of_index: } /* Get the next Doc ID */ - if (add_doc_id) { + if (add_doc_id && !history_row) { doc_id++; } else { doc_id = 0; @@ -2197,13 +2206,6 @@ end_of_index: ut_ad(add_autoinc < dict_table_get_n_user_cols(new_table)); - bool history_row = false; - if (new_table->versioned()) { - const dfield_t* dfield = dtuple_get_nth_field( - row, new_table->vers_end); - history_row = dfield->vers_history_row(); - } - dfield_t* dfield = dtuple_get_nth_field(row, add_autoinc); @@ -2327,8 +2329,8 @@ write_buffers: if (UNIV_LIKELY (row && (rows_added = row_merge_buf_add( buf, fts_index, old_table, new_table, - psort_info, row, ext, &doc_id, - conv_heap, &err, + psort_info, row, history_row, ext, + &doc_id, conv_heap, &err, &v_heap, eval_table, trx)))) { /* Set the page flush observer for the @@ -2660,9 +2662,10 @@ write_buffers: if (UNIV_UNLIKELY (!(rows_added = row_merge_buf_add( buf, fts_index, old_table, - new_table, psort_info, row, ext, - &doc_id, conv_heap, - &err, &v_heap, eval_table, trx)))) { + new_table, psort_info, row, + history_row, ext, &doc_id, + conv_heap, &err, &v_heap, + eval_table, trx)))) { /* An empty buffer should have enough room for at least one record. */ ut_ad(err == DB_COMPUTE_VALUE_FAILED diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 8eeaa62b29e..dfc5393a8b3 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1449,7 +1449,10 @@ error_exit: return(err); } - if (dict_table_has_fts_index(table)) { + if (dict_table_has_fts_index(table) + && (!table->versioned() + || !node->row->fields[table->vers_end].vers_history_row())) { + doc_id_t doc_id; /* Extract the doc id from the hidden FTS column */ @@ -1663,7 +1666,7 @@ row_fts_update_or_delete( ut_a(dict_table_has_fts_index(prebuilt->table)); /* Deletes are simple; get them out of the way first. */ - if (node->is_delete == PLAIN_DELETE) { + if (node->is_delete) { /* A delete affects all FTS indexes, so we pass NULL */ fts_trx_add_op(trx, table, old_doc_id, FTS_DELETE, NULL); } else { @@ -2228,7 +2231,7 @@ row_update_cascade_for_mysql( return(DB_FOREIGN_EXCEED_MAX_CASCADE); } - const trx_t* trx = thr_get_trx(thr); + trx_t* trx = thr_get_trx(thr); if (table->versioned()) { if (node->is_delete == PLAIN_DELETE) { diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 599aece23f5..ef780e7ccb0 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -3545,3 +3545,16 @@ skip_append: } } } + + +/** Prepare update vector for versioned delete. +Set row_end to CURRENT_TIMESTAMP or trx->id. +Initialize fts_next_doc_id for versioned delete. +@param[in] trx transaction */ +void upd_node_t::vers_make_delete(trx_t* trx) +{ + update->n_fields= 0; + is_delete= VERSIONED_DELETE; + vers_update_fields(trx, table->vers_end); + trx->fts_next_doc_id= table->fts ? UINT64_UNDEFINED : 0; +} From 72e2d1d2201c2da23777d8fb89e078475e0c1371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 27 Dec 2022 00:02:02 +0300 Subject: [PATCH 17/23] MDEV-25004 Refactorings * Avoid some pessimization * Slightly smaller upgrade dataset * Simplify vers_row_same_trx() and its caller --- mysql-test/std_data/versioning/ibdata1.gz | Bin 51165 -> 41597 bytes mysql-test/suite/innodb_fts/t/versioning.test | 7 +- storage/innobase/row/row0ins.cc | 91 ++++++++---------- storage/innobase/row/row0merge.cc | 28 +++--- 4 files changed, 59 insertions(+), 67 deletions(-) diff --git a/mysql-test/std_data/versioning/ibdata1.gz b/mysql-test/std_data/versioning/ibdata1.gz index bddd23071818c9ca92dc141700240b2d4242b247..345217ba5931bd8a61f5c2dbc03d65059892a8d6 100644 GIT binary patch literal 41597 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 literal 51165 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

C2)~{vK2P!}8B_X5Z<3 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 yN&qE*5table); ut_ad(index != clust_index); mtr.start(); - rec_t *clust_rec= - row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr); - rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; - rec_offs *clust_offs= offsets_; - rec_offs_init(offsets_); - mem_heap_t *heap= NULL; - - if (clust_rec) + if (const rec_t *clust_rec= + row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr)) { + rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; + rec_offs *clust_offs= offsets_; + rec_offs_init(offsets_); + mem_heap_t *heap= NULL; + clust_offs= - rec_get_offsets(clust_rec, clust_index, clust_offs, - clust_index->n_core_fields, ULINT_UNDEFINED, &heap); - if (!clust_index->vers_history_row(clust_rec, clust_offs)) + rec_get_offsets(clust_rec, clust_index, clust_offs, + clust_index->n_core_fields, ULINT_UNDEFINED, &heap); + if (clust_index->vers_history_row(clust_rec, clust_offs)) { - *same_trx= false; - goto end; + ulint trx_id_len; + const byte *trx_id= rec_get_nth_field(clust_rec, clust_offs, + clust_index->n_uniq, &trx_id_len); + ut_ad(trx_id_len == DATA_TRX_ID_LEN); + + if (trx.id == trx_read_trx_id(trx_id)) + ret= DB_FOREIGN_DUPLICATE_KEY; } + + if (UNIV_LIKELY_NULL(heap)) + mem_heap_free(heap); } else { @@ -2099,21 +2108,8 @@ dberr_t vers_row_same_trx(dict_index_t* index, const rec_t* rec, " of table " << index->table->name << " is out of sync"; ut_ad("secondary index is out of sync" == 0); ret= DB_TABLE_CORRUPT; - goto end; } - trx_id_bytes= rec_get_nth_field(clust_rec, clust_offs, - clust_index->n_uniq, &trx_id_len); - ut_ad(trx_id_len == DATA_TRX_ID_LEN); - - trx_id= trx_read_trx_id(trx_id_bytes); - - if (UNIV_LIKELY_NULL(heap)) - mem_heap_free(heap); - - *same_trx= thr_get_trx(thr)->id == trx_id; - -end: mtr.commit(); return ret; } @@ -2141,9 +2137,6 @@ row_ins_scan_sec_index_for_duplicate( ulint n_fields_cmp; btr_pcur_t pcur; dberr_t err = DB_SUCCESS; - dberr_t err2; - bool same_trx; - ulint allow_duplicates; rec_offs offsets_[REC_OFFS_SEC_INDEX_SIZE]; rec_offs* offsets = offsets_; DBUG_ENTER("row_ins_scan_sec_index_for_duplicate"); @@ -2181,7 +2174,7 @@ row_ins_scan_sec_index_for_duplicate( : BTR_SEARCH_LEAF, &pcur, mtr); - allow_duplicates = thr_get_trx(thr)->duplicates; + trx_t* const trx = thr_get_trx(thr); /* Scan index records and check if there is a duplicate */ @@ -2202,7 +2195,7 @@ row_ins_scan_sec_index_for_duplicate( if (flags & BTR_NO_LOCKING_FLAG) { /* Set no locks when applying log in online table rebuild. */ - } else if (allow_duplicates) { + } else if (trx->duplicates) { /* If the SQL-query will update or replace duplicate key we will take X-lock for @@ -2239,20 +2232,14 @@ row_ins_scan_sec_index_for_duplicate( err = DB_DUPLICATE_KEY; - thr_get_trx(thr)->error_info = index; + trx->error_info = index; - if (index->table->versioned()) { - err2 = vers_row_same_trx(index, rec, - thr, &same_trx); - if (err2 != DB_SUCCESS) { - err = err2; - goto end_scan; - } - - if (same_trx) { - err = DB_FOREIGN_DUPLICATE_KEY; - goto end_scan; - } + if (!index->table->versioned()) { + } else if (dberr_t e = + vers_row_same_trx(index, rec, + *trx)) { + err = e; + goto end_scan; } /* If the duplicate is on hidden FTS_DOC_ID, diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 415c93a9f6f..89c10320365 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -455,9 +455,10 @@ row_merge_buf_redundant_convert( @param[in] new_table new table @param[in,out] psort_info parallel sort info @param[in,out] row table row -@param[in] history_row row is historical in a system-versioned table @param[in] ext cache of externally stored column prefixes, or NULL +@param[in] history_fts row is historical in a system-versioned table + on which a FTS_DOC_ID_INDEX(FTS_DOC_ID) exists @param[in,out] doc_id Doc ID if we are creating FTS index @param[in,out] conv_heap memory heap where to allocate data when @@ -478,8 +479,8 @@ row_merge_buf_add( const dict_table_t* new_table, fts_psort_t* psort_info, dtuple_t* row, - const bool history_row, const row_ext_t* ext, + const bool history_fts, doc_id_t* doc_id, mem_heap_t* conv_heap, dberr_t* err, @@ -542,7 +543,7 @@ error: : NULL; /* Process the Doc ID column */ - if (!v_col && index->table->fts && (*doc_id || history_row) + if (!v_col && (history_fts || *doc_id) && col->ind == index->table->fts->doc_col) { fts_write_doc_id((byte*) &write_doc_id, *doc_id); @@ -594,7 +595,7 @@ error: /* Tokenize and process data for FTS */ - if (!history_row && (index->type & DICT_FTS)) { + if (!history_fts && (index->type & DICT_FTS)) { fts_doc_item_t* doc_item; byte* value; void* ptr; @@ -1707,7 +1708,6 @@ row_merge_read_clustered_index( char new_sys_trx_end[8]; byte any_autoinc_data[8] = {0}; bool vers_update_trt = false; - bool history_row = false; DBUG_ENTER("row_merge_read_clustered_index"); @@ -1897,6 +1897,7 @@ row_merge_read_clustered_index( dtuple_t* row; row_ext_t* ext; page_cur_t* cur = btr_pcur_get_page_cur(&pcur); + bool history_row, history_fts = false; page_cur_move_to_next(cur); @@ -2135,11 +2136,10 @@ end_of_index: row_heap); ut_ad(row); - if (new_table->versioned()) { - const dfield_t* dfield = dtuple_get_nth_field( - row, new_table->vers_end); - history_row = dfield->vers_history_row(); - } + history_row = new_table->versioned() + && dtuple_get_nth_field(row, new_table->vers_end) + ->vers_history_row(); + history_fts = history_row && new_table->fts; for (ulint i = 0; i < n_nonnull; i++) { dfield_t* field = &row->fields[nonnull[i]]; @@ -2170,7 +2170,7 @@ end_of_index: } /* Get the next Doc ID */ - if (add_doc_id && !history_row) { + if (add_doc_id && !history_fts) { doc_id++; } else { doc_id = 0; @@ -2329,7 +2329,7 @@ write_buffers: if (UNIV_LIKELY (row && (rows_added = row_merge_buf_add( buf, fts_index, old_table, new_table, - psort_info, row, history_row, ext, + psort_info, row, ext, history_fts, &doc_id, conv_heap, &err, &v_heap, eval_table, trx)))) { @@ -2662,8 +2662,8 @@ write_buffers: if (UNIV_UNLIKELY (!(rows_added = row_merge_buf_add( buf, fts_index, old_table, - new_table, psort_info, row, - history_row, ext, &doc_id, + new_table, psort_info, + row, ext, history_fts, &doc_id, conv_heap, &err, &v_heap, eval_table, trx)))) { /* An empty buffer should have enough From 6710fe4b42a0909072ff8b9fb243e73bcf740ffb Mon Sep 17 00:00:00 2001 From: Julius Goryavsky Date: Mon, 26 Dec 2022 08:23:16 +0100 Subject: [PATCH 18/23] MDEV-30293: mariabackup fail with --galera-info option without Galera Without Galera, mariabackup should ignore the --galera-info option and not fail with rc != 0 like it does now. This commit fixes this flaw. --- extra/mariabackup/backup_copy.cc | 2 -- extra/mariabackup/backup_mysql.cc | 8 ++++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index b1655c95998..23ade2a46be 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -1544,8 +1544,6 @@ bool backup_start(CorruptedPages &corrupted_pages) if (!write_galera_info(mysql_connection)) { return(false); } - // copied from xtrabackup. what is it needed for here? - write_current_binlog_file(mysql_connection); } if (opt_binlog_info == BINLOG_INFO_ON) { diff --git a/extra/mariabackup/backup_mysql.cc b/extra/mariabackup/backup_mysql.cc index 05fc01305b7..b646bbd4ffe 100644 --- a/extra/mariabackup/backup_mysql.cc +++ b/extra/mariabackup/backup_mysql.cc @@ -1558,14 +1558,18 @@ write_galera_info(MYSQL *connection) if ((state_uuid == NULL && state_uuid55 == NULL) || (last_committed == NULL && last_committed55 == NULL)) { - msg("Failed to get master wsrep state from SHOW STATUS."); - result = false; + msg("Warning: failed to get master wsrep state from SHOW STATUS."); + result = true; goto cleanup; } result = backup_file_printf(XTRABACKUP_GALERA_INFO, "%s:%s\n", state_uuid ? state_uuid : state_uuid55, last_committed ? last_committed : last_committed55); + if (result) + { + write_current_binlog_file(connection); + } cleanup: free_mysql_variables(status); From f8adc47b698ef8d347fd36bffff90b237491eceb Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 6 Dec 2022 15:48:13 +0100 Subject: [PATCH 19/23] MDEV-19071 Wrong results when using STDDEV_SAMP() and view --- mysql-test/main/func_group.result | 14 ++++++++++++++ mysql-test/main/func_group.test | 11 +++++++++++ .../gcol/r/gcol_blocked_sql_funcs_innodb.result | 2 +- .../gcol/r/gcol_blocked_sql_funcs_myisam.result | 2 +- .../suite/vcol/r/vcol_blocked_sql_funcs.result | 2 +- sql/item_sum.h | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/mysql-test/main/func_group.result b/mysql-test/main/func_group.result index 0f3169e330f..0f80d14b603 100644 --- a/mysql-test/main/func_group.result +++ b/mysql-test/main/func_group.result @@ -2552,5 +2552,19 @@ DROP TABLE t1; # SET STATEMENT sql_mode=ONLY_FULL_GROUP_BY FOR EXECUTE IMMEDIATE 'ALTER TABLE mysql.time_zone_transition ORDER BY Time_zone_id, Transition_time'; # +# MDEV-19071 Wrong results when using STDDEV_SAMP() and view +# +create table t1(i int); +insert into t1 values (1),(2),(3),(4),(5); +create view v1 as select stddev_samp(i),stddev_pop(i),stddev(i),std(i) from t1; +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select stddev_samp(`t1`.`i`) AS `stddev_samp(i)`,std(`t1`.`i`) AS `stddev_pop(i)`,std(`t1`.`i`) AS `stddev(i)`,std(`t1`.`i`) AS `std(i)` from `t1` latin1 latin1_swedish_ci +select * from v1; +stddev_samp(i) stddev_pop(i) stddev(i) std(i) +1.5811 1.4142 1.4142 1.4142 +drop view v1; +drop table t1; +# # End of 10.3 tests # diff --git a/mysql-test/main/func_group.test b/mysql-test/main/func_group.test index 862ea453b46..6b3a15fd45e 100644 --- a/mysql-test/main/func_group.test +++ b/mysql-test/main/func_group.test @@ -1789,6 +1789,17 @@ DROP TABLE t1; SET STATEMENT sql_mode=ONLY_FULL_GROUP_BY FOR EXECUTE IMMEDIATE 'ALTER TABLE mysql.time_zone_transition ORDER BY Time_zone_id, Transition_time'; +--echo # +--echo # MDEV-19071 Wrong results when using STDDEV_SAMP() and view +--echo # +create table t1(i int); +insert into t1 values (1),(2),(3),(4),(5); +create view v1 as select stddev_samp(i),stddev_pop(i),stddev(i),std(i) from t1; +show create view v1; +select * from v1; +drop view v1; +drop table t1; + --echo # --echo # End of 10.3 tests --echo # diff --git a/mysql-test/suite/gcol/r/gcol_blocked_sql_funcs_innodb.result b/mysql-test/suite/gcol/r/gcol_blocked_sql_funcs_innodb.result index b9fe877b0f2..6b7faa18da8 100644 --- a/mysql-test/suite/gcol/r/gcol_blocked_sql_funcs_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_blocked_sql_funcs_innodb.result @@ -129,7 +129,7 @@ create table t1 (a int, b int generated always as (stddev_pop(a)) virtual); ERROR HY000: Function or expression 'std()' cannot be used in the GENERATED ALWAYS AS clause of `b` # STDDEV_SAMP() create table t1 (a int, b int generated always as (stddev_samp(a)) virtual); -ERROR HY000: Function or expression 'std()' cannot be used in the GENERATED ALWAYS AS clause of `b` +ERROR HY000: Function or expression 'stddev_samp()' cannot be used in the GENERATED ALWAYS AS clause of `b` # STDDEV() create table t1 (a int, b int generated always as (stddev(a)) virtual); ERROR HY000: Function or expression 'std()' cannot be used in the GENERATED ALWAYS AS clause of `b` diff --git a/mysql-test/suite/gcol/r/gcol_blocked_sql_funcs_myisam.result b/mysql-test/suite/gcol/r/gcol_blocked_sql_funcs_myisam.result index 23fdea42488..99921c658b3 100644 --- a/mysql-test/suite/gcol/r/gcol_blocked_sql_funcs_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_blocked_sql_funcs_myisam.result @@ -131,7 +131,7 @@ create table t1 (a int, b int generated always as (stddev_pop(a)) virtual); ERROR HY000: Function or expression 'std()' cannot be used in the GENERATED ALWAYS AS clause of `b` # STDDEV_SAMP() create table t1 (a int, b int generated always as (stddev_samp(a)) virtual); -ERROR HY000: Function or expression 'std()' cannot be used in the GENERATED ALWAYS AS clause of `b` +ERROR HY000: Function or expression 'stddev_samp()' cannot be used in the GENERATED ALWAYS AS clause of `b` # STDDEV() create table t1 (a int, b int generated always as (stddev(a)) virtual); ERROR HY000: Function or expression 'std()' cannot be used in the GENERATED ALWAYS AS clause of `b` diff --git a/mysql-test/suite/vcol/r/vcol_blocked_sql_funcs.result b/mysql-test/suite/vcol/r/vcol_blocked_sql_funcs.result index 19e8efb06ad..1cf24194c5b 100644 --- a/mysql-test/suite/vcol/r/vcol_blocked_sql_funcs.result +++ b/mysql-test/suite/vcol/r/vcol_blocked_sql_funcs.result @@ -191,7 +191,7 @@ create or replace table t1 (a int, b int as (stddev_pop(a))); ERROR HY000: Function or expression 'std()' cannot be used in the GENERATED ALWAYS AS clause of `b` # STDDEV_SAMP() create or replace table t1 (a int, b int as (stddev_samp(a))); -ERROR HY000: Function or expression 'std()' cannot be used in the GENERATED ALWAYS AS clause of `b` +ERROR HY000: Function or expression 'stddev_samp()' cannot be used in the GENERATED ALWAYS AS clause of `b` # STDDEV() create or replace table t1 (a int, b int as (stddev(a))); ERROR HY000: Function or expression 'std()' cannot be used in the GENERATED ALWAYS AS clause of `b` diff --git a/sql/item_sum.h b/sql/item_sum.h index 48565ece5a8..c93332b320f 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1038,7 +1038,7 @@ class Item_sum_std :public Item_sum_variance enum Sumfunctype sum_func () const { return STD_FUNC; } double val_real(); Item *result_item(THD *thd, Field *field); - const char *func_name() const { return "std("; } + const char *func_name() const { return sample ? "stddev_samp(" : "std("; } Item *copy_or_same(THD* thd); Item *get_copy(THD *thd) { return get_item_copy(thd, this); } From eba099184e1f6704894694ea41f97f216eae5f21 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 5 Dec 2022 00:21:28 +0100 Subject: [PATCH 20/23] MDEV-30151 parse error 1=2 not between/in the parser couldn't parse `1=2 not between 3 and 5` after `2` it expected only NOT2_SYM, but not NOT_SYM (visible from the sql_yacc.output file), which resulted in Syntax error ... near 'not between 3 and 4' The parser was confused by a rather low NOT_SYM precedence and %prec BETWEEN_SYM didn't resolve this confusion. As a fix, let's remove any %precedence from NOT_SYM and specify %prec explicitly in the only place where it matters for NOT_SYM. In other places, such as for NOT BETWEEN, NOT_SYM won't have a precedence, so bison won't be confused about it. --- mysql-test/main/parser.result | 11 +++++++++++ mysql-test/main/parser.test | 8 ++++++++ sql/sql_yacc.yy | 6 +++--- sql/sql_yacc_ora.yy | 6 +++--- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/mysql-test/main/parser.result b/mysql-test/main/parser.result index 0bb4e82c8b8..f44478727ae 100644 --- a/mysql-test/main/parser.result +++ b/mysql-test/main/parser.result @@ -1866,4 +1866,15 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp EXECUTE IMMEDIATE 'CREATE PROCEDURE p() UPDATE t SET c=\'\'"abc'; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '"abc' at line 1 SET @@sql_mode=@save_sql_mode; +# +# MDEV-30151 parse error 1=2 not between/in +# +select 1=2 not in (3,4); +1=2 not in (3,4) +1 +select 1=2 not between 3 and 4; +1=2 not between 3 and 4 +1 +# # End of 10.3 tests +# diff --git a/mysql-test/main/parser.test b/mysql-test/main/parser.test index 9df18c50ee3..cfe4f9d6f53 100644 --- a/mysql-test/main/parser.test +++ b/mysql-test/main/parser.test @@ -1673,4 +1673,12 @@ EXECUTE IMMEDIATE 'CREATE PROCEDURE p() UPDATE t SET c=\'\'"abc'; SET @@sql_mode=@save_sql_mode; +--echo # +--echo # MDEV-30151 parse error 1=2 not between/in +--echo # +select 1=2 not in (3,4); +select 1=2 not between 3 and 4; + +--echo # --echo # End of 10.3 tests +--echo # diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1f6485dac6a..73922ceb4f4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -899,7 +899,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); /* We should not introduce any further shift/reduce conflicts. */ -%expect 85 +%expect 96 /* Comments for TOKENS. @@ -1687,7 +1687,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %left PREC_BELOW_NOT -%nonassoc NOT_SYM +%nonassoc LOW_PRIORITY_NOT %left '=' EQUAL_SYM GE '>' LE '<' NE %nonassoc IS %right BETWEEN_SYM @@ -9840,7 +9840,7 @@ expr: MYSQL_YYABORT; } } - | NOT_SYM expr %prec NOT_SYM + | NOT_SYM expr %prec LOW_PRIORITY_NOT { $$= negate_expression(thd, $2); if (unlikely($$ == NULL)) diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index ec8e4f4c946..3a1b0c0e077 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -293,7 +293,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); /* We should not introduce any further shift/reduce conflicts. */ -%expect 87 +%expect 98 /* Comments for TOKENS. @@ -1081,7 +1081,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %left PREC_BELOW_NOT -%nonassoc NOT_SYM +%nonassoc LOW_PRIORITY_NOT %left '=' EQUAL_SYM GE '>' LE '<' NE %nonassoc IS %right BETWEEN_SYM @@ -9797,7 +9797,7 @@ expr: MYSQL_YYABORT; } } - | NOT_SYM expr %prec NOT_SYM + | NOT_SYM expr %prec LOW_PRIORITY_NOT { $$= negate_expression(thd, $2); if (unlikely($$ == NULL)) From d78ac04ee609b0b63bb688be2a837a6ca7670392 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 9 Dec 2022 14:32:58 +0100 Subject: [PATCH 21/23] ignore changes in submodules when committing everything covers `git commit -a` and `git citool` (`git add`, `git status`, etc). they can still be added explicitly --- .gitmodules | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitmodules b/.gitmodules index 6419657e501..748c0ffe11c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,8 @@ [submodule "libmariadb"] path = libmariadb url = https://github.com/MariaDB/mariadb-connector-c + ignore = all [submodule "storage/rocksdb/rocksdb"] path = storage/rocksdb/rocksdb url = https://github.com/facebook/rocksdb.git + ignore = all From ca23558a0561856cc7f3c1ab5db4025102482380 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 12 Dec 2022 13:18:46 +0100 Subject: [PATCH 22/23] --skip-name-resolve=0 didn't work custom code in `case OPT_SKIP_RESOLVE` was overriding the correct value from handle_options(). --- sql/mysqld.cc | 6 ------ sql/mysqld.h | 1 - sql/sql_acl.cc | 18 ++++++++---------- sql/sql_connect.cc | 2 +- sql/sql_parse.cc | 2 +- sql/sys_vars.cc | 2 +- sql/unireg.h | 2 +- 7 files changed, 12 insertions(+), 21 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d58f2ed557f..b1cf5ab2796 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -9484,12 +9484,6 @@ mysqld_get_one_option(int optid, const struct my_option *opt, char *argument) case (int) OPT_SKIP_HOST_CACHE: opt_specialflag|= SPECIAL_NO_HOST_CACHE; break; - case (int) OPT_SKIP_RESOLVE: - if ((opt_skip_name_resolve= (argument != disabled_my_option))) - opt_specialflag|= SPECIAL_NO_RESOLVE; - else - opt_specialflag&= ~SPECIAL_NO_RESOLVE; - break; case (int) OPT_WANT_CORE: test_flags |= TEST_CORE_ON_SIGNAL; break; diff --git a/sql/mysqld.h b/sql/mysqld.h index d40e1d170d0..f7d0fce910f 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -680,7 +680,6 @@ enum options_mysqld OPT_SERVER_ID, OPT_SILENT, OPT_SKIP_HOST_CACHE, - OPT_SKIP_RESOLVE, OPT_SLAVE_PARALLEL_MODE, OPT_SSL_CA, OPT_SSL_CAPATH, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index f4a3ab14f57..7a01da3fa76 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -315,9 +315,9 @@ public: update_hostname(&host, safe_strdup_root(mem, host_arg)); } - bool check_validity(bool check_no_resolve) + bool check_validity() { - if (check_no_resolve && + if (opt_skip_name_resolve && (hostname_requires_resolving(host.hostname) || hostname_requires_resolving(proxied_host.hostname))) { @@ -1781,7 +1781,6 @@ static bool set_user_plugin (ACL_USER *user, size_t password_len) static bool acl_load(THD *thd, const Grant_tables& tables) { READ_RECORD read_record_info; - bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; char tmp_name[SAFE_NAME_LEN+1]; int password_length; Sql_mode_save old_mode_save(thd); @@ -1825,7 +1824,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) host.access= host_table.get_access(); host.access= fix_rights_for_db(host.access); host.sort= get_sort(2, host.host.hostname, host.db); - if (check_no_resolve && hostname_requires_resolving(host.host.hostname)) + if (opt_skip_name_resolve && hostname_requires_resolving(host.host.hostname)) { sql_print_warning("'host' entry '%s|%s' " "ignored in --skip-name-resolve mode.", @@ -1929,7 +1928,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) continue; } - if (!is_role && check_no_resolve && + if (!is_role && opt_skip_name_resolve && hostname_requires_resolving(user.host.hostname)) { sql_print_warning("'user' entry '%s@%s' " @@ -2105,7 +2104,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) sql_print_warning("Found an entry in the 'db' table with empty database name; Skipped"); continue; } - if (check_no_resolve && hostname_requires_resolving(db.host.hostname)) + if (opt_skip_name_resolve && hostname_requires_resolving(db.host.hostname)) { sql_print_warning("'db' entry '%s %s@%s' " "ignored in --skip-name-resolve mode.", @@ -2160,7 +2159,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) { ACL_PROXY_USER proxy; proxy.init(proxies_priv_table, &acl_memroot); - if (proxy.check_validity(check_no_resolve)) + if (proxy.check_validity()) continue; if (push_dynamic(&acl_proxy_users, (uchar*) &proxy)) DBUG_RETURN(TRUE); @@ -7348,7 +7347,6 @@ static bool grant_load(THD *thd, { bool return_val= 1; TABLE *t_table, *c_table, *p_table; - bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; MEM_ROOT *save_mem_root= thd->mem_root; sql_mode_t old_sql_mode= thd->variables.sql_mode; DBUG_ENTER("grant_load"); @@ -7392,7 +7390,7 @@ static bool grant_load(THD *thd, goto end_unlock; } - if (check_no_resolve) + if (opt_skip_name_resolve) { if (hostname_requires_resolving(mem_check->host.hostname)) { @@ -7437,7 +7435,7 @@ static bool grant_load(THD *thd, goto end_unlock_p; } - if (check_no_resolve) + if (opt_skip_name_resolve) { if (hostname_requires_resolving(mem_check->host.hostname)) { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 91a99e0aded..b4b742f6c0b 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -887,7 +887,7 @@ int thd_set_peer_addr(THD *thd, return 1; /* The error is set by my_strdup(). */ } thd->main_security_ctx.host_or_ip = thd->main_security_ctx.ip; - if (!(specialflag & SPECIAL_NO_RESOLVE)) + if (!opt_skip_name_resolve) { int rc; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index cf316c8cc1c..3102aa69b86 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5248,7 +5248,7 @@ mysql_execute_command(THD *thd) List_iterator user_list(lex->users_list); while ((user= user_list++)) { - if (specialflag & SPECIAL_NO_RESOLVE && + if (opt_skip_name_resolve && hostname_requires_resolving(user->host.str)) push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_WARN_HOSTNAME_WONT_WORK, diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 0e24fc56529..d5164587900 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2811,7 +2811,7 @@ static Sys_var_mybool Sys_skip_name_resolve( "skip_name_resolve", "Don't resolve hostnames. All hostnames are IP's or 'localhost'.", READ_ONLY GLOBAL_VAR(opt_skip_name_resolve), - CMD_LINE(OPT_ARG, OPT_SKIP_RESOLVE), + CMD_LINE(OPT_ARG), DEFAULT(FALSE)); static Sys_var_mybool Sys_skip_show_database( diff --git a/sql/unireg.h b/sql/unireg.h index 03d63d0fd06..3b51bc06ff4 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -67,7 +67,7 @@ #define SPECIAL_WAIT_IF_LOCKED 8 /* Wait if locked database */ #define SPECIAL_SAME_DB_NAME 16 /* form name = file name */ #define SPECIAL_ENGLISH 32 /* English error messages */ -#define SPECIAL_NO_RESOLVE 64 /* Don't use gethostname */ +#define SPECIAL_NO_RESOLVE 64 /* Obsolete */ #define SPECIAL_NO_PRIOR 128 /* Obsolete */ #define SPECIAL_BIG_SELECTS 256 /* Don't use heap tables */ #define SPECIAL_NO_HOST_CACHE 512 /* Don't cache hosts */ From 8760f6907c51e0e20242a53188be5b62029d6f1a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 28 Dec 2022 12:10:38 +0100 Subject: [PATCH 23/23] MDEV-30102 file missing in development libraries move mariadb_capi_rename.h out of private server headers, because it's included by mysql.h which is not private. --- include/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index a7b98a11050..9a3f820e62f 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -25,6 +25,7 @@ SET(HEADERS mysql.h mysql_com.h mysql_com_server.h + mariadb_capi_rename.h pack.h my_byteorder.h byte_order_generic.h