=== modified file 'mysql-test/r/index_merge_myisam.result'
--- mysql-test/r/index_merge_myisam.result	2012-09-10 14:26:54 +0000
+++ mysql-test/r/index_merge_myisam.result	2013-06-21 17:28:21 +0000
@@ -1617,4 +1617,32 @@
 COUNT(DISTINCT t2.b)	CONCAT(t1.c)
 2	0
 DROP TABLE t1,t2,t3;
+#
+# MDEV-4556 Server crashes in SEL_ARG::rb_insert with index_merge+index_merge_sort_union, FORCE INDEX
+#
+CREATE TABLE state (
+pk int,
+code char(2),
+population_rate int,
+area_rate int,
+primary key (pk),
+index (code),
+key (population_rate),
+key (area_rate)
+);
+INSERT INTO state VALUES  (1,'WI',20, 23), (2, 'WA', 13, 18);
+EXPLAIN EXTENDED
+SELECT * FROM state FORCE INDEX ( PRIMARY, population_rate, area_rate, code ) 
+WHERE pk = 1 OR population_rate = 1 OR ( area_rate IN ( 1,2 ) OR area_rate IS NULL )
+AND (population_rate = 25 OR area_rate BETWEEN 2 AND 25 OR code BETWEEN 'MA' AND 'TX');
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	state	index_merge	PRIMARY,code,population_rate,area_rate	PRIMARY,population_rate,area_rate	4,5,5	NULL	2	100.00	Using sort_union(PRIMARY,population_rate,area_rate); Using where
+Warnings:
+Note	1003	select `test`.`state`.`pk` AS `pk`,`test`.`state`.`code` AS `code`,`test`.`state`.`population_rate` AS `population_rate`,`test`.`state`.`area_rate` AS `area_rate` from `test`.`state` FORCE INDEX (`code`) FORCE INDEX (`area_rate`) FORCE INDEX (`population_rate`) FORCE INDEX (PRIMARY) where ((`test`.`state`.`pk` = 1) or (`test`.`state`.`population_rate` = 1) or (((`test`.`state`.`area_rate` in (1,2)) or isnull(`test`.`state`.`area_rate`)) and ((`test`.`state`.`population_rate` = 25) or (`test`.`state`.`area_rate` between 2 and 25) or (`test`.`state`.`code` between 'MA' and 'TX'))))
+SELECT * FROM state FORCE INDEX ( PRIMARY, population_rate, area_rate, code ) 
+WHERE pk = 1 OR population_rate = 1 OR ( area_rate IN ( 1,2 ) OR area_rate IS NULL )
+AND (population_rate = 25 OR area_rate BETWEEN 2 AND 25 OR code BETWEEN 'MA' AND 'TX');
+pk	code	population_rate	area_rate
+1	WI	20	23
+DROP TABLE state;
 set optimizer_switch= @optimizer_switch_save;

=== modified file 'mysql-test/t/index_merge_myisam.test'
--- mysql-test/t/index_merge_myisam.test	2011-11-22 17:04:38 +0000
+++ mysql-test/t/index_merge_myisam.test	2013-06-21 17:47:00 +0000
@@ -149,5 +149,32 @@
 
 DROP TABLE t1,t2,t3;
 
+--echo #
+--echo # MDEV-4556 Server crashes in SEL_ARG::rb_insert with index_merge+index_merge_sort_union, FORCE INDEX
+--echo #
+CREATE TABLE state (
+  pk int,
+  code char(2),
+  population_rate int,
+  area_rate int,
+  primary key (pk),
+  index (code),
+  key (population_rate),
+  key (area_rate)
+);
+
+INSERT INTO state VALUES  (1,'WI',20, 23), (2, 'WA', 13, 18);
+
+EXPLAIN EXTENDED
+SELECT * FROM state FORCE INDEX ( PRIMARY, population_rate, area_rate, code ) 
+WHERE pk = 1 OR population_rate = 1 OR ( area_rate IN ( 1,2 ) OR area_rate IS NULL )
+AND (population_rate = 25 OR area_rate BETWEEN 2 AND 25 OR code BETWEEN 'MA' AND 'TX');
+
+SELECT * FROM state FORCE INDEX ( PRIMARY, population_rate, area_rate, code ) 
+WHERE pk = 1 OR population_rate = 1 OR ( area_rate IN ( 1,2 ) OR area_rate IS NULL )
+AND (population_rate = 25 OR area_rate BETWEEN 2 AND 25 OR code BETWEEN 'MA' AND 'TX');
+
+DROP TABLE state;
+
 set optimizer_switch= @optimizer_switch_save;
 

=== modified file 'sql/opt_range.cc'
--- sql/opt_range.cc	2013-06-05 20:53:35 +0000
+++ sql/opt_range.cc	2013-06-21 17:46:12 +0000
@@ -4912,12 +4912,15 @@
     else
     {
       SEL_TREE **changed_tree= imerge->trees+(*tree_idx_ptr-1);
-      SEL_ARG *key= (*changed_tree)->keys[key_idx];
+      SEL_ARG *key= (*changed_tree)->keys[key_idx], tmp, *next_arg= &tmp;
+      SEL_ARG *key_clone= key->clone(param, key->parent, &next_arg);
+      next_arg->next=0;			// Fix last link
+      tmp.next->prev=0;			// Fix first link
       bzero((*changed_tree)->keys,
             sizeof((*changed_tree)->keys[0])*param->keys);
       (*changed_tree)->keys_map.clear_all();
       if (((*changed_tree)->keys[key_idx]=
-             key_or(param, key, (*tree)->keys[key_idx])))
+             key_or(param, key_clone, (*tree)->keys[key_idx])))
         (*changed_tree)->keys_map.set_bit(key_idx);
       *tree= NULL;
       removed_cnt++;

