From 901737c9782215e409ae6f7869f5d0adbe215ad6 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Mon, 26 Aug 2013 12:55:58 -0700 Subject: [PATCH 1/2] Fixed bug mdev-4944. The patch to fix mdev-4418 turned out to be incorrect. At the substitution of single row tables in make_join_statistics() the used multiple equalities may change and references to the new multiple equalities must be updated. The function remove_eq_conds() takes care of it and it should be called right after the substitution of single row tables. Calling it after the call of make_join_statistics was a mistake. --- mysql-test/r/join_outer.result | 2 +- mysql-test/r/join_outer_jcl6.result | 2 +- mysql-test/r/select.result | 19 ++++++++++++++++ mysql-test/r/select_jcl6.result | 19 ++++++++++++++++ mysql-test/r/select_pkeycache.result | 19 ++++++++++++++++ mysql-test/r/subselect.result | 2 +- mysql-test/r/subselect_no_mat.result | 2 +- mysql-test/r/subselect_no_opts.result | 2 +- mysql-test/r/subselect_no_scache.result | 2 +- mysql-test/r/subselect_no_semijoin.result | 2 +- mysql-test/r/table_elim.result | 4 ++-- mysql-test/t/select.test | 19 ++++++++++++++++ sql/sql_select.cc | 27 ++++++++++++++--------- sql/sql_select.h | 5 +++++ 14 files changed, 107 insertions(+), 19 deletions(-) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index b73edc8c52e..6e92d47a145 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1649,7 +1649,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 100.00 Using where 2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t1` left join `test`.`t2` on((6,(select `test`.`t3`.`a` from `test`.`t3` where (6 = `test`.`t3`.`a`)))) +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t1` left join `test`.`t2` on((6,(select `test`.`t3`.`a` from `test`.`t3` where (6 = `test`.`t3`.`a`)))) where 1 DROP TABLE t1,t2,t3; # # LP bug #817384 Wrong result with outer join + subquery in ON diff --git a/mysql-test/r/join_outer_jcl6.result b/mysql-test/r/join_outer_jcl6.result index a588767d754..a78a7352f2d 100644 --- a/mysql-test/r/join_outer_jcl6.result +++ b/mysql-test/r/join_outer_jcl6.result @@ -1660,7 +1660,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 1 100.00 Using where 2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00 Using where Warnings: -Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t1` left join `test`.`t2` on((6,(select `test`.`t3`.`a` from `test`.`t3` where (6 = `test`.`t3`.`a`)))) +Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t1` left join `test`.`t2` on((6,(select `test`.`t3`.`a` from `test`.`t3` where (6 = `test`.`t3`.`a`)))) where 1 DROP TABLE t1,t2,t3; # # LP bug #817384 Wrong result with outer join + subquery in ON diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 56a4a8d2bdc..f5744c8e3d0 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -5235,4 +5235,23 @@ Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,'k' AS `c`,'k' AS SELECT * FROM t1, t2 WHERE c=b AND (1=2 OR ((b='h' OR a=136) AND d=b)); a b c d DROP TABLE t1,t2; +# +# Bug mdev-4944: range conditition in OR formula with fields +# belonging to multiple equalities +# +CREATE TABLE t1 (i1 int, j1 int) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,8); +CREATE TABLE t2 (i2 int, INDEX idx (i2)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (8), (9); +EXPLAIN EXTENDED +SELECT * FROM t1, t2 +WHERE i1 = i2 AND ( FALSE OR ( j1 > 27 AND j1 < 100 OR j1 <= 3 ) AND j1 = i2 ); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select 1 AS `i1`,8 AS `j1`,`test`.`t2`.`i2` AS `i2` from `test`.`t1` join `test`.`t2` where 0 +SELECT * FROM t1, t2 +WHERE i1 = i2 AND ( FALSE OR ( j1 > 27 AND j1 < 100 OR j1 <= 3 ) AND j1 = i2 ); +i1 j1 i2 +DROP TABLE t1,t2; End of 5.3 tests diff --git a/mysql-test/r/select_jcl6.result b/mysql-test/r/select_jcl6.result index 1a735299e0e..eea9d318f04 100644 --- a/mysql-test/r/select_jcl6.result +++ b/mysql-test/r/select_jcl6.result @@ -5246,6 +5246,25 @@ Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,'k' AS `c`,'k' AS SELECT * FROM t1, t2 WHERE c=b AND (1=2 OR ((b='h' OR a=136) AND d=b)); a b c d DROP TABLE t1,t2; +# +# Bug mdev-4944: range conditition in OR formula with fields +# belonging to multiple equalities +# +CREATE TABLE t1 (i1 int, j1 int) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,8); +CREATE TABLE t2 (i2 int, INDEX idx (i2)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (8), (9); +EXPLAIN EXTENDED +SELECT * FROM t1, t2 +WHERE i1 = i2 AND ( FALSE OR ( j1 > 27 AND j1 < 100 OR j1 <= 3 ) AND j1 = i2 ); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select 1 AS `i1`,8 AS `j1`,`test`.`t2`.`i2` AS `i2` from `test`.`t1` join `test`.`t2` where 0 +SELECT * FROM t1, t2 +WHERE i1 = i2 AND ( FALSE OR ( j1 > 27 AND j1 < 100 OR j1 <= 3 ) AND j1 = i2 ); +i1 j1 i2 +DROP TABLE t1,t2; End of 5.3 tests set join_cache_level=default; show variables like 'join_cache_level'; diff --git a/mysql-test/r/select_pkeycache.result b/mysql-test/r/select_pkeycache.result index 56a4a8d2bdc..f5744c8e3d0 100644 --- a/mysql-test/r/select_pkeycache.result +++ b/mysql-test/r/select_pkeycache.result @@ -5235,4 +5235,23 @@ Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,'k' AS `c`,'k' AS SELECT * FROM t1, t2 WHERE c=b AND (1=2 OR ((b='h' OR a=136) AND d=b)); a b c d DROP TABLE t1,t2; +# +# Bug mdev-4944: range conditition in OR formula with fields +# belonging to multiple equalities +# +CREATE TABLE t1 (i1 int, j1 int) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,8); +CREATE TABLE t2 (i2 int, INDEX idx (i2)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (8), (9); +EXPLAIN EXTENDED +SELECT * FROM t1, t2 +WHERE i1 = i2 AND ( FALSE OR ( j1 > 27 AND j1 < 100 OR j1 <= 3 ) AND j1 = i2 ); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select 1 AS `i1`,8 AS `j1`,`test`.`t2`.`i2` AS `i2` from `test`.`t1` join `test`.`t2` where 0 +SELECT * FROM t1, t2 +WHERE i1 = i2 AND ( FALSE OR ( j1 > 27 AND j1 < 100 OR j1 <= 3 ) AND j1 = i2 ); +i1 j1 i2 +DROP TABLE t1,t2; End of 5.3 tests diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index e4448d96657..8503164dde2 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1322,7 +1322,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables Warnings: -Note 1003 select (0,(select 1 from `test`.`t1` `a` where 0)) AS `0 IN (SELECT 1 FROM t1 a)` +Note 1003 select (0,(select 1 from `test`.`t1` `a` where (0 = 1))) AS `0 IN (SELECT 1 FROM t1 a)` INSERT INTO t1 (pseudo) VALUES ('test1'); SELECT 0 IN (SELECT 1 FROM t1 a); 0 IN (SELECT 1 FROM t1 a) diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index df6b884fbe0..d0c9555d976 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -1329,7 +1329,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables Warnings: -Note 1003 select (0,(select 1 from `test`.`t1` `a` where 0)) AS `0 IN (SELECT 1 FROM t1 a)` +Note 1003 select (0,(select 1 from `test`.`t1` `a` where (0 = 1))) AS `0 IN (SELECT 1 FROM t1 a)` INSERT INTO t1 (pseudo) VALUES ('test1'); SELECT 0 IN (SELECT 1 FROM t1 a); 0 IN (SELECT 1 FROM t1 a) diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index f9df463f6aa..47f6d3a0ed4 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -1325,7 +1325,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables Warnings: -Note 1003 select (0,(select 1 from `test`.`t1` `a` where 0)) AS `0 IN (SELECT 1 FROM t1 a)` +Note 1003 select (0,(select 1 from `test`.`t1` `a` where (0 = 1))) AS `0 IN (SELECT 1 FROM t1 a)` INSERT INTO t1 (pseudo) VALUES ('test1'); SELECT 0 IN (SELECT 1 FROM t1 a); 0 IN (SELECT 1 FROM t1 a) diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index 70de4b26743..f3a01618eff 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -1328,7 +1328,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables Warnings: -Note 1003 select (0,(select 1 from `test`.`t1` `a` where 0)) AS `0 IN (SELECT 1 FROM t1 a)` +Note 1003 select (0,(select 1 from `test`.`t1` `a` where (0 = 1))) AS `0 IN (SELECT 1 FROM t1 a)` INSERT INTO t1 (pseudo) VALUES ('test1'); SELECT 0 IN (SELECT 1 FROM t1 a); 0 IN (SELECT 1 FROM t1 a) diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 91071c98777..964704e0695 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -1325,7 +1325,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables Warnings: -Note 1003 select (0,(select 1 from `test`.`t1` `a` where 0)) AS `0 IN (SELECT 1 FROM t1 a)` +Note 1003 select (0,(select 1 from `test`.`t1` `a` where (0 = 1))) AS `0 IN (SELECT 1 FROM t1 a)` INSERT INTO t1 (pseudo) VALUES ('test1'); SELECT 0 IN (SELECT 1 FROM t1 a); 0 IN (SELECT 1 FROM t1 a) diff --git a/mysql-test/r/table_elim.result b/mysql-test/r/table_elim.result index 86e5bbe0060..35acd30d76d 100644 --- a/mysql-test/r/table_elim.result +++ b/mysql-test/r/table_elim.result @@ -17,7 +17,7 @@ explain extended select t1.a from t1 left join t2 on t2.a=t1.a; id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Warnings: -Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where 1 select t1.a from t1 left join t2 on t2.a=t1.a; a 0 @@ -62,7 +62,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t0 ALL NULL NULL NULL NULL 4 100.00 1 SIMPLE t1 ALL NULL NULL NULL NULL 4 100.00 Using where Warnings: -Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t0` left join (`test`.`t1`) on((`test`.`t1`.`a` = `test`.`t0`.`a`)) +Note 1003 select `test`.`t0`.`a` AS `a` from `test`.`t0` left join (`test`.`t1`) on((`test`.`t1`.`a` = `test`.`t0`.`a`)) where 1 # Elimination with aggregate functions explain select count(*) from t1 left join t2 on t2.a=t1.a; id select_type table type possible_keys key key_len ref rows Extra diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index c0e22cb8f4e..bb5a6b9c2fc 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -4389,4 +4389,23 @@ SELECT * FROM t1, t2 WHERE c=b AND (1=2 OR ((b='h' OR a=136) AND d=b)); DROP TABLE t1,t2; +--echo # +--echo # Bug mdev-4944: range conditition in OR formula with fields +--echo # belonging to multiple equalities +--echo # + +CREATE TABLE t1 (i1 int, j1 int) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,8); + +CREATE TABLE t2 (i2 int, INDEX idx (i2)) ENGINE=MyISAM; +INSERT INTO t2 VALUES (8), (9); + +EXPLAIN EXTENDED +SELECT * FROM t1, t2 + WHERE i1 = i2 AND ( FALSE OR ( j1 > 27 AND j1 < 100 OR j1 <= 3 ) AND j1 = i2 ); +SELECT * FROM t1, t2 + WHERE i1 = i2 AND ( FALSE OR ( j1 > 27 AND j1 < 100 OR j1 <= 3 ) AND j1 = i2 ); + +DROP TABLE t1,t2; + --echo End of 5.3 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 52c7283b2d9..c35dea5bd20 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1211,17 +1211,12 @@ JOIN::optimize() conds=new Item_int((longlong) 1,1); // Always true } - if (const_tables && conds) + if (impossible_where) { - conds= remove_eq_conds(thd, conds, &cond_value); - if (cond_value == Item::COND_FALSE) - { - zero_result_cause= - "Impossible WHERE noticed after reading const tables"; - select_lex->mark_const_derived(zero_result_cause); - conds=new Item_int((longlong) 0,1); - goto setup_subq_exit; - } + zero_result_cause= + "Impossible WHERE noticed after reading const tables"; + select_lex->mark_const_derived(zero_result_cause); + goto setup_subq_exit; } select= make_select(*table, const_table_map, @@ -3528,6 +3523,18 @@ make_join_statistics(JOIN *join, List &tables_list, } } + join->impossible_where= false; + if (conds && const_count) + { + conds= remove_eq_conds(join->thd, conds, &join->cond_value); + if (join->cond_value == Item::COND_FALSE) + { + join->impossible_where= true; + conds=new Item_int((longlong) 0,1); + } + join->conds= conds; + } + /* Calc how many (possible) matched records in each table */ for (s=stat ; s < stat_end ; s++) diff --git a/sql/sql_select.h b/sql/sql_select.h index eb064b39f22..083302d1e4c 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1139,6 +1139,11 @@ public: bool need_tmp, hidden_group_fields; DYNAMIC_ARRAY keyuse; Item::cond_result cond_value, having_value; + /** + Impossible where after reading const tables + (set in make_join_statistics()) + */ + bool impossible_where; List all_fields; ///< to store all fields that used in query ///Above list changed to use temporary table List tmp_all_fields1, tmp_all_fields2, tmp_all_fields3; From 650d3266bb788552b9ac8dce6f5fed0cf53f480c Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Mon, 26 Aug 2013 15:51:47 -0700 Subject: [PATCH 2/2] Fixed bug mdev-4952 When in function remove_eq_conds() a sub-formula of the processed condition is replaced for another formula we should ensure that in the resulting formula AND/OR levels must alternate. --- mysql-test/r/join_outer.result | 14 ++++++++++++++ mysql-test/r/join_outer_jcl6.result | 14 ++++++++++++++ mysql-test/t/join_outer.test | 18 ++++++++++++++++++ sql/sql_select.cc | 15 ++++++++++++++- 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 6e92d47a145..c30f1584607 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1848,4 +1848,18 @@ INSERT INTO t2 VALUES (3,'2000-03-06'), (4,'2007-09-25'); SELECT * FROM t1 LEFT JOIN t2 ON i1 = i2 WHERE d1 IS NULL AND d2 IS NULL; i1 d1 i2 d2 DROP TABLE t1,t2; +# +# Bug mdev-4952: LEFT JOIN with disjunctive +# IS NULL in WHERE +# causes an assert failure +# +CREATE TABLE t1 (a1 int, b1 int NOT NULL) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1, 10), (2, 11); +CREATE TABLE t2 (dt datetime NOT NULL, a2 int, b2 int) ENGINE=MyISAM; +INSERT INTO t2 VALUES +('2006-10-08 09:34:54', 1, 100), ('2001-01-19 01:04:43', 2, 200); +SELECT * FROM t1 LEFT JOIN t2 ON a1 = a2 +WHERE ( dt IS NULL OR FALSE ) AND b2 IS NULL; +a1 b1 dt a2 b2 +DROP TABLE t1,t2; SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/join_outer_jcl6.result b/mysql-test/r/join_outer_jcl6.result index a78a7352f2d..ccb402a642c 100644 --- a/mysql-test/r/join_outer_jcl6.result +++ b/mysql-test/r/join_outer_jcl6.result @@ -1859,6 +1859,20 @@ INSERT INTO t2 VALUES (3,'2000-03-06'), (4,'2007-09-25'); SELECT * FROM t1 LEFT JOIN t2 ON i1 = i2 WHERE d1 IS NULL AND d2 IS NULL; i1 d1 i2 d2 DROP TABLE t1,t2; +# +# Bug mdev-4952: LEFT JOIN with disjunctive +# IS NULL in WHERE +# causes an assert failure +# +CREATE TABLE t1 (a1 int, b1 int NOT NULL) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1, 10), (2, 11); +CREATE TABLE t2 (dt datetime NOT NULL, a2 int, b2 int) ENGINE=MyISAM; +INSERT INTO t2 VALUES +('2006-10-08 09:34:54', 1, 100), ('2001-01-19 01:04:43', 2, 200); +SELECT * FROM t1 LEFT JOIN t2 ON a1 = a2 +WHERE ( dt IS NULL OR FALSE ) AND b2 IS NULL; +a1 b1 dt a2 b2 +DROP TABLE t1,t2; SET optimizer_switch=@save_optimizer_switch; set join_cache_level=default; show variables like 'join_cache_level'; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 99f4b1e1315..ec48818f57f 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -1392,4 +1392,22 @@ SELECT * FROM t1 LEFT JOIN t2 ON i1 = i2 WHERE d1 IS NULL AND d2 IS NULL; DROP TABLE t1,t2; +--echo # +--echo # Bug mdev-4952: LEFT JOIN with disjunctive +--echo # IS NULL in WHERE +--echo # causes an assert failure +--echo # + +CREATE TABLE t1 (a1 int, b1 int NOT NULL) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1, 10), (2, 11); + +CREATE TABLE t2 (dt datetime NOT NULL, a2 int, b2 int) ENGINE=MyISAM; +INSERT INTO t2 VALUES +('2006-10-08 09:34:54', 1, 100), ('2001-01-19 01:04:43', 2, 200); + +SELECT * FROM t1 LEFT JOIN t2 ON a1 = a2 + WHERE ( dt IS NULL OR FALSE ) AND b2 IS NULL; + +DROP TABLE t1,t2; + SET optimizer_switch=@save_optimizer_switch; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c35dea5bd20..79c7925dbcf 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13407,7 +13407,20 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) } else { - li.replace(new_item); + if (new_item->type() == Item::COND_ITEM && + ((Item_cond*) new_item)->functype() == + ((Item_cond*) cond)->functype()) + { + List *new_item_arg_list= + ((Item_cond *) new_item)->argument_list(); + uint cnt= new_item_arg_list->elements; + li.replace(*new_item_arg_list); + /* Make iterator li ignore new items */ + for (cnt--; cnt; cnt--) + li++; + } + else + li.replace(new_item); should_fix_fields= 1; } }