From ec921065357282c8c850a8286297733675e4bf44 Mon Sep 17 00:00:00 2001
From: "pem@mysql.comhem.se" <>
Date: Fri, 14 May 2004 16:00:57 +0200
Subject: [PATCH] Post-merge fixes. Note: One sp.test still fails (prime), and
 rpl_server_id2.test fails (will be fixed by guilhem ASAP).

---
 mysql-test/r/index_merge.result         |   4 +-
 mysql-test/r/index_merge_bdb.result     |   2 +-
 mysql-test/r/index_merge_innodb.result  |   2 +-
 mysql-test/r/index_merge_innodb2.result |   2 +-
 mysql-test/r/rpl_server_id1.result      |   2 +-
 mysql-test/r/sp-error.result            |   4 +-
 mysql-test/r/variables.result           |   2 +-
 mysql-test/t/index_merge.test           |   4 +-
 mysql-test/t/index_merge_bdb.test       |   2 +-
 mysql-test/t/index_merge_innodb.test    |   2 +-
 mysql-test/t/index_merge_innodb2.test   |   2 +-
 mysql-test/t/sp-error.test              |  98 +++---
 sql/opt_range.cc                        | 408 +++++++++++++-----------
 sql/opt_range.h                         |  14 +-
 sql/slave.cc                            |  39 ++-
 sql/slave.h                             |   8 +-
 sql/sp_head.cc                          |   4 +-
 sql/sql_parse.cc                        |   4 +
 tests/client_test.c                     |   2 +-
 19 files changed, 340 insertions(+), 265 deletions(-)

diff --git a/mysql-test/r/index_merge.result b/mysql-test/r/index_merge.result
index 6859d9db728..15e909c5af9 100644
--- a/mysql-test/r/index_merge.result
+++ b/mysql-test/r/index_merge.result
@@ -2,7 +2,7 @@ drop table if exists t0, t1, t2, t3,t4;
 create table t0
 (
 key1 int not null, 
-INDEX i1(key1),
+INDEX i1(key1)
 );
 alter table t0 add key2 int not null, add index i2(key2);
 alter table t0 add key3 int not null, add index i3(key3);
@@ -217,7 +217,7 @@ key3  int not null,
 index i1a (key1a, key1b),
 index i1b (key1b, key1a),
 index i2_1(key2, key2_1),
-index i2_2(key2, key2_1),  
+index i2_2(key2, key2_1)
 );
 insert into t4 select key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 from t0;
 select * from t4 where key1a = 3 or key1b = 4;
diff --git a/mysql-test/r/index_merge_bdb.result b/mysql-test/r/index_merge_bdb.result
index 77d5ba31e53..3113bf95d3a 100644
--- a/mysql-test/r/index_merge_bdb.result
+++ b/mysql-test/r/index_merge_bdb.result
@@ -6,7 +6,7 @@ key2 int,
 filler char(200),
 filler2 char(200),  
 index(key1),
-index(key2),  
+index(key2)
 ) engine=bdb;
 select * from t1 where (key1 >= 2 and key1 <= 10) or (pk >= 4 and pk <=8 );
 pk	key1	key2	filler	filler2
diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result
index 91718f00f9b..70dd3d4f4f0 100644
--- a/mysql-test/r/index_merge_innodb.result
+++ b/mysql-test/r/index_merge_innodb.result
@@ -4,7 +4,7 @@ create table t1
 key1 int not null, 
 key2 int not null, 
 INDEX i1(key1),
-INDEX i2(key2),
+INDEX i2(key2)
 ) engine=innodb;
 explain select * from t1 where key1 < 5 or key2 > 197;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
diff --git a/mysql-test/r/index_merge_innodb2.result b/mysql-test/r/index_merge_innodb2.result
index ee0439a7660..91dd989fe90 100644
--- a/mysql-test/r/index_merge_innodb2.result
+++ b/mysql-test/r/index_merge_innodb2.result
@@ -6,7 +6,7 @@ key2 int,
 filler char(200),
 filler2 char(200),  
 index(key1),
-index(key2),  
+index(key2)
 ) engine=innodb;
 select * from t1 where (key1 >= 2 and key1 <= 10) or (pk >= 4 and pk <=8 );
 pk	key1	key2	filler	filler2
diff --git a/mysql-test/r/rpl_server_id1.result b/mysql-test/r/rpl_server_id1.result
index 8c383802de4..b51022b0017 100644
--- a/mysql-test/r/rpl_server_id1.result
+++ b/mysql-test/r/rpl_server_id1.result
@@ -10,7 +10,7 @@ stop slave;
 change master to master_port=SLAVE_PORT;
 show slave status;
 Slave_IO_State	Master_Host	Master_User	Master_Port	Connect_Retry	Master_Log_File	Read_Master_Log_Pos	Relay_Log_File	Relay_Log_Pos	Relay_Master_Log_File	Slave_IO_Running	Slave_SQL_Running	Replicate_Do_DB	Replicate_Ignore_DB	Replicate_Do_Table	Replicate_Ignore_Table	Replicate_Wild_Do_Table	Replicate_Wild_Ignore_Table	Last_Errno	Last_Error	Skip_Counter	Exec_Master_Log_Pos	Relay_Log_Space	Until_Condition	Until_Log_File	Until_Log_Pos	Master_SSL_Allowed	Master_SSL_CA_File	Master_SSL_CA_Path	Master_SSL_Cert	Master_SSL_Cipher	Master_SSL_Key	Seconds_Behind_Master
-	127.0.0.1	root	SLAVE_PORT	1		4	slave-relay-bin.000001	4		No	No						#	0		0	0	4	None		0	No						NULL
+	127.0.0.1	root	SLAVE_PORT	1		4	slave-relay-bin.000001	4		No	No						#	0		0	0	95	None		0	No						NULL
 start slave;
 insert into t1 values (1);
 show status like "slave_running";
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index b2bba71ea6d..1231c6398ee 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -35,7 +35,7 @@ call foo()|
 ERROR 42000: PROCEDURE foo does not exist
 drop procedure if exists foo|
 Warnings:
-Warning	1297	PROCEDURE foo does not exist
+Warning	1298	PROCEDURE foo does not exist
 show create procedure foo|
 ERROR 42000: PROCEDURE foo does not exist
 create procedure foo()
@@ -71,7 +71,7 @@ declare y int;
 set x = y;
 end|
 Warnings:
-Warning	1303	Referring to uninitialized variable y
+Warning	1304	Referring to uninitialized variable y
 drop procedure foo|
 create procedure foo()
 return 42|
diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result
index f25a48525bb..67c1d5b3e33 100644
--- a/mysql-test/r/variables.result
+++ b/mysql-test/r/variables.result
@@ -364,7 +364,7 @@ set sql_log_bin=1;
 set sql_log_off=1;
 set sql_log_update=1;
 Warnings:
-Note	1307	The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored.
+Note	1308	The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored.
 set sql_low_priority_updates=1;
 set sql_max_join_size=200;
 select @@sql_max_join_size,@@max_join_size;
diff --git a/mysql-test/t/index_merge.test b/mysql-test/t/index_merge.test
index 9745723ca59..a4f7b71e5a3 100644
--- a/mysql-test/t/index_merge.test
+++ b/mysql-test/t/index_merge.test
@@ -10,7 +10,7 @@ drop table if exists t0, t1, t2, t3,t4;
 create table t0
 (
   key1 int not null, 
-  INDEX i1(key1),
+  INDEX i1(key1)
 );
 
 --disable_query_log
@@ -192,7 +192,7 @@ create table t4 (
   index i1b (key1b, key1a),
   
   index i2_1(key2, key2_1),
-  index i2_2(key2, key2_1),  
+  index i2_2(key2, key2_1)
 );
 
 insert into t4 select key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 from t0;
diff --git a/mysql-test/t/index_merge_bdb.test b/mysql-test/t/index_merge_bdb.test
index 23e2d7a8f63..c49e6ab3175 100644
--- a/mysql-test/t/index_merge_bdb.test
+++ b/mysql-test/t/index_merge_bdb.test
@@ -14,7 +14,7 @@ create table t1 (
   filler char(200),
   filler2 char(200),  
   index(key1),
-  index(key2),  
+  index(key2)
 ) engine=bdb;
 
 
diff --git a/mysql-test/t/index_merge_innodb.test b/mysql-test/t/index_merge_innodb.test
index 657b9498f00..2da40c5719a 100644
--- a/mysql-test/t/index_merge_innodb.test
+++ b/mysql-test/t/index_merge_innodb.test
@@ -13,7 +13,7 @@ create table t1
   key2 int not null, 
   
   INDEX i1(key1),
-  INDEX i2(key2),
+  INDEX i2(key2)
 ) engine=innodb;
 
 --disable_query_log
diff --git a/mysql-test/t/index_merge_innodb2.test b/mysql-test/t/index_merge_innodb2.test
index 125e9142105..ec4ea672bc1 100644
--- a/mysql-test/t/index_merge_innodb2.test
+++ b/mysql-test/t/index_merge_innodb2.test
@@ -14,7 +14,7 @@ create table t1 (
   filler char(200),
   filler2 char(200),  
   index(key1),
-  index(key2),  
+  index(key2)
 ) engine=innodb;
 
 
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index 5c300647d27..5bddc8b204e 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -32,18 +32,18 @@ create function func1() returns int
   return 42|
 
 # Can't create recursively
---error 1295
+--error 1296
 create procedure foo()
   create procedure bar() set @x=3|
---error 1295
+--error 1296
 create procedure foo()
   create function bar() returns double return 2.3|
 
 # Already exists
---error 1296
+--error 1297
 create procedure proc1()
   set @x = 42|
---error 1296
+--error 1297
 create function func1() returns int
   return 42|
 
@@ -51,39 +51,39 @@ drop procedure proc1|
 drop function func1|
 
 # Does not exist
---error 1297
+--error 1298
 alter procedure foo|
---error 1297
+--error 1298
 alter function foo|
---error 1297
+--error 1298
 drop procedure foo|
---error 1297
+--error 1298
 drop function foo|
---error 1297
+--error 1298
 call foo()|
 drop procedure if exists foo|
---error 1297
+--error 1298
 show create procedure foo|
 
 # LEAVE/ITERATE with no match
---error 1300
+--error 1301
 create procedure foo()
 foo: loop
   leave bar;
 end loop|
---error 1300
+--error 1301
 create procedure foo()
 foo: loop
   iterate bar;
 end loop|
---error 1300
+--error 1301
 create procedure foo()
 foo: begin
   iterate foo;
 end|
 
 # Redefining label
---error 1301
+--error 1302
 create procedure foo()
 foo: loop
   foo: loop
@@ -92,7 +92,7 @@ foo: loop
 end loop foo|
 
 # End label mismatch
---error 1302
+--error 1303
 create procedure foo()
 foo: loop
   set @x=2;
@@ -107,12 +107,12 @@ end|
 drop procedure foo|
 
 # RETURN in FUNCTION only
---error 1305
+--error 1306
 create procedure foo()
   return 42|
 
 # Doesn't allow queries in FUNCTIONs (for now :-( )
---error 1306
+--error 1307
 create function foo() returns int
 begin
   declare x int;
@@ -126,19 +126,19 @@ create procedure p(x int)
 create function f(x int) returns int
   return x+42|
 
---error 1310
+--error 1311
 call p()|
---error 1310
+--error 1311
 call p(1, 2)|
---error 1310
+--error 1311
 select f()|
---error 1310
+--error 1311
 select f(1, 2)|
 
 drop procedure p|
 drop function f|
 
---error 1311
+--error 1312
 create procedure p(val int, out res int)
 begin
   declare x int default 0;
@@ -152,7 +152,7 @@ begin
   end if;
 end|
 
---error 1311
+--error 1312
 create procedure p(val int, out res int)
 begin
   declare x int default 0;
@@ -167,7 +167,7 @@ begin
   end if;
 end|
 
---error 1312
+--error 1313
 create function f(val int) returns int
 begin
   declare x int;
@@ -185,12 +185,12 @@ begin
   end if;
 end|
 
---error 1313
+--error 1314
 select f(10)|
 
 drop function f|
 
---error 1314
+--error 1315
 create procedure p()
 begin
   declare c cursor for insert into test.t1 values ("foo", 42);
@@ -199,7 +199,7 @@ begin
   close c;
 end|
 
---error 1315
+--error 1316
 create procedure p()
 begin
   declare x int;
@@ -209,7 +209,7 @@ begin
   close c;
 end|
 
---error 1316
+--error 1317
 create procedure p()
 begin
   declare c cursor for select * from test.t;
@@ -231,7 +231,7 @@ begin
   open c;
   close c;
 end|
---error 1317
+--error 1318
 call p()|
 drop procedure p|
 
@@ -243,11 +243,11 @@ begin
   close c;
   close c;
 end|
---error 1318
+--error 1319
 call p()|
 drop procedure p|
 
---error 1297
+--error 1298
 alter procedure bar3 sql security invoker|
 --error 1059
 alter procedure bar3 name
@@ -261,7 +261,7 @@ drop table if exists t1|
 create table t1 (val int, x float)|
 insert into t1 values (42, 3.1), (19, 1.2)|
 
---error 1319
+--error 1320
 create procedure p()
 begin
   declare x int;
@@ -281,7 +281,7 @@ begin
   fetch c into x;
   close c;
 end|
---error 1320
+--error 1321
 call p()|
 drop procedure p|
 
@@ -296,34 +296,34 @@ begin
   fetch c into x, y, z;
   close c;
 end|
---error 1320
+--error 1321
 call p()|
 drop procedure p|
 
---error 1322
+--error 1323
 create procedure p(in x int, x char(10))
 begin
 end|
---error 1322
+--error 1323
 create function p(x int, x char(10))
 begin
 end|
 
---error 1323
+--error 1324
 create procedure p()
 begin
   declare x float;
   declare x int;
 end|
 
---error 1324	
+--error 1325	
 create procedure p()
 begin
   declare c condition for 1064;
   declare c condition for 1065;
 end|
 
---error 1325
+--error 1326
 create procedure p()
 begin
   declare c cursor for select * from t1;
@@ -331,18 +331,18 @@ begin
 end|
 
 # USE is not allowed
---error 1328
+--error 1329
 create procedure u()
   use sptmp|
 
 # Enforced standard order of declarations
---error 1329
+--error 1330
 create procedure p()
 begin
   declare c cursor for select * from t1;
   declare x int;
 end|
---error 1329
+--error 1330
 create procedure p()
 begin
   declare x int;
@@ -350,7 +350,7 @@ begin
   declare foo condition for sqlstate '42S99';
 end|
 
---error 1330
+--error 1331
 create procedure p()
 begin
   declare x int;
@@ -375,13 +375,13 @@ drop procedure bug1965|
 #
 # BUG#1966
 #
---error 1319
+--error 1320
 select 1 into a|
 
 #
 # BUG#336
 #
---error 1327
+--error 1328
 create procedure bug336(id char(16))
 begin
   declare x int;
@@ -391,7 +391,7 @@ end|
 #
 # BUG#1654
 #
---error 1306
+--error 1307
 create function bug1654()
   returns int
 return (select sum(t.data) from test.t2 t)|
@@ -429,7 +429,7 @@ begin
   fetch c1 into v1;
 end|
 
---error 1318
+--error 1319
 call bug2259()|
 drop procedure bug2259|
 
@@ -485,7 +485,7 @@ begin
   end case;
   return 2;
 end|
---error 1331
+--error 1332
 select bug3287()|
 drop function bug3287|
 
@@ -496,7 +496,7 @@ when 0 then
 when 1 then
   insert into test.t1 values (x, 1.1);
 end case|
---error 1331
+--error 1332
 call bug3287(2)|
 drop procedure bug3287|
 
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 3907ba866fe..28b9cd79fdd 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -177,11 +177,11 @@ class SEL_ARG :public Sql_alloc
       if (maybe_null && *min_value)
       {
 	**min_key=1;
-	bzero(*min_key+1,length);
+	bzero(*min_key+1,length-1);
       }
       else
-	memcpy(*min_key,min_value,length+(int) maybe_null);
-      (*min_key)+= length+(int) maybe_null;
+	memcpy(*min_key,min_value,length);
+      (*min_key)+= length;
     }
     if (!(max_flag & NO_MAX_RANGE) &&
 	!(max_key_flag & (NO_MAX_RANGE | NEAR_MAX)))
@@ -189,18 +189,18 @@ class SEL_ARG :public Sql_alloc
       if (maybe_null && *max_value)
       {
 	**max_key=1;
-	bzero(*max_key+1,length);
+	bzero(*max_key+1,length-1);
       }
       else
-	memcpy(*max_key,max_value,length+(int) maybe_null);
-      (*max_key)+= length+(int) maybe_null;
+	memcpy(*max_key,max_value,length);
+      (*max_key)+= length;
     }
   }
 
   void store_min_key(KEY_PART *key,char **range_key, uint *range_key_flag)
   {
     SEL_ARG *key_tree= first();
-    key_tree->store(key[key_tree->part].part_length,
+    key_tree->store(key[key_tree->part].store_length,
 		    range_key,*range_key_flag,range_key,NO_MAX_RANGE);
     *range_key_flag|= key_tree->min_flag;
     if (key_tree->next_key_part &&
@@ -213,7 +213,7 @@ class SEL_ARG :public Sql_alloc
   void store_max_key(KEY_PART *key,char **range_key, uint *range_key_flag)
   {
     SEL_ARG *key_tree= last();
-    key_tree->store(key[key_tree->part].part_length,
+    key_tree->store(key[key_tree->part].store_length,
 		    range_key, NO_MIN_RANGE, range_key,*range_key_flag);
     (*range_key_flag)|= key_tree->max_flag;
     if (key_tree->next_key_part &&
@@ -959,6 +959,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
     MEM_ROOT *old_root,alloc;
     SEL_TREE *tree;
     KEY_PART *key_parts;
+    KEY *key_info;
     PARAM param;
 
     /* set up parameter that is passed to all functions */
@@ -985,24 +986,26 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
     old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
     my_pthread_setspecific_ptr(THR_MALLOC,&alloc);
 
-    for (idx=0 ; idx < head->keys ; idx++)
+    key_info= head->key_info;
+    for (idx=0 ; idx < head->keys ; idx++, key_info++)
     {
+      KEY_PART_INFO *key_part_info;
       if (!keys_to_use.is_set(idx))
 	continue;
-      KEY *key_info= &head->key_info[idx];
       if (key_info->flags & HA_FULLTEXT)
 	continue;    // ToDo: ft-keys in non-ft ranges, if possible   SerG
 
       param.key[param.keys]=key_parts;
-      for (uint part=0 ; part < key_info->key_parts ; part++,key_parts++)
+      key_part_info= key_info->key_part;
+      for (uint part=0 ; part < key_info->key_parts ;
+	   part++, key_parts++, key_part_info++)
       {
-	key_parts->key=param.keys;
-	key_parts->part=part;
-	key_parts->part_length= key_info->key_part[part].length;
-	key_parts->field=    key_info->key_part[part].field;
-	key_parts->null_bit= key_info->key_part[part].null_bit;
-	if (key_parts->field->type() == FIELD_TYPE_BLOB)
-	  key_parts->part_length+=HA_KEY_BLOB_LENGTH;
+	key_parts->key=		 param.keys;
+	key_parts->part=	 part;
+	key_parts->length=       key_part_info->length;
+	key_parts->store_length= key_part_info->store_length;
+	key_parts->field=	 key_part_info->field;
+	key_parts->null_bit=	 key_part_info->null_bit;
         key_parts->image_type =
           (key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW;
       }
@@ -1348,7 +1351,7 @@ static int get_index_merge_params(PARAM *param, key_map& needed_reg,
   else
   {    
     double n_blocks=
-      ceil((double)(longlong)param->table->file->data_file_length / IO_SIZE);
+      ceil((double) ((longlong)param->table->file->data_file_length / IO_SIZE));
     double busy_blocks=
        n_blocks * (1.0 - pow(1.0 - 1.0/n_blocks, (double) records_for_unique));
     
@@ -1776,18 +1779,26 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
       DBUG_RETURN(0);				// Can only optimize strings
 
     offset=maybe_null;
-    length=key_part->part_length;
-    if (field->type() == FIELD_TYPE_BLOB)
+    length=key_part->store_length;
+
+    if (length != key_part->length  + maybe_null)
     {
-      offset+=HA_KEY_BLOB_LENGTH;
-      field_length=key_part->part_length-HA_KEY_BLOB_LENGTH;
+      /* key packed with length prefix */
+      offset+= HA_KEY_BLOB_LENGTH;
+      field_length= length - HA_KEY_BLOB_LENGTH;
     }
     else
     {
-      if (length < field_length)
-	length=field_length;			// Only if overlapping key
+      if (unlikely(length < field_length))
+      {
+	/*
+	  This can only happen in a table created with UNIREG where one key
+	  overlaps many fields
+	*/
+	length= field_length;
+      }
       else
-	field_length=length;
+	field_length= length;
     }
     length+=offset;
     if (!(min_str= (char*) alloc_root(param->mem_root, length*2)))
@@ -1800,7 +1811,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
 			      res->ptr(), res->length(),
 			      ((Item_func_like*)(param->cond))->escape,
 			      wild_one, wild_many,
-			      field_length, 
+			      field_length-maybe_null,
 			      min_str+offset, max_str+offset,
 			      &min_length, &max_length);
     if (like_error)				// Can't optimize with LIKE
@@ -1838,13 +1849,13 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
   if (field->key_type() == HA_KEYTYPE_VARTEXT)
     copies= 2;
   str= str2= (char*) alloc_root(param->mem_root,
-				(key_part->part_length+maybe_null)*copies+1);
+				(key_part->store_length)*copies+1);
   if (!str)
     DBUG_RETURN(0);
   if (maybe_null)
     *str= (char) field->is_real_null();		// Set to 1 if null
-  field->get_key_image(str+maybe_null,key_part->part_length,
-		       field->charset(),key_part->image_type);
+  field->get_key_image(str+maybe_null, key_part->length,
+		       field->charset(), key_part->image_type);
   if (copies == 2)
   {
     /*
@@ -1853,16 +1864,17 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
       all rows between 'X' and 'X           ...'
     */
     uint length= uint2korr(str+maybe_null);
-    str2= str+ key_part->part_length + maybe_null;
+    str2= str+ key_part->store_length;
     /* remove end space */
     while (length > 0 && str[length+HA_KEY_BLOB_LENGTH+maybe_null-1] == ' ')
       length--;
     int2store(str+maybe_null, length);
     /* Create key that is space filled */
     memcpy(str2, str, length + HA_KEY_BLOB_LENGTH + maybe_null);
-    bfill(str2+ length+ HA_KEY_BLOB_LENGTH +maybe_null,
-	  key_part->part_length-length - HA_KEY_BLOB_LENGTH, ' ');
-    int2store(str2+maybe_null, key_part->part_length - HA_KEY_BLOB_LENGTH);
+    my_fill_8bit(field->charset(),
+		 str2+ length+ HA_KEY_BLOB_LENGTH +maybe_null,
+		 key_part->length-length, ' ');
+    int2store(str2+maybe_null, key_part->length);
   }
   if (!(tree=new SEL_ARG(field,str,str2)))
     DBUG_RETURN(0);		// out of memory
@@ -1889,39 +1901,39 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
     tree->max_flag=NO_MAX_RANGE;
     break;
   case Item_func::SP_EQUALS_FUNC:
-      tree->min_flag=GEOM_FLAG | HA_READ_MBR_EQUAL;// NEAR_MIN;//512;
-      tree->max_flag=NO_MAX_RANGE;
-      break;
+    tree->min_flag=GEOM_FLAG | HA_READ_MBR_EQUAL;// NEAR_MIN;//512;
+    tree->max_flag=NO_MAX_RANGE;
+    break;
   case Item_func::SP_DISJOINT_FUNC:
-      tree->min_flag=GEOM_FLAG | HA_READ_MBR_DISJOINT;// NEAR_MIN;//512;
-      tree->max_flag=NO_MAX_RANGE;
-      break;
+    tree->min_flag=GEOM_FLAG | HA_READ_MBR_DISJOINT;// NEAR_MIN;//512;
+    tree->max_flag=NO_MAX_RANGE;
+    break;
   case Item_func::SP_INTERSECTS_FUNC:
-      tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
-      tree->max_flag=NO_MAX_RANGE;
-      break;
+    tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+    tree->max_flag=NO_MAX_RANGE;
+    break;
   case Item_func::SP_TOUCHES_FUNC:
-      tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
-      tree->max_flag=NO_MAX_RANGE;
-      break;
+    tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+    tree->max_flag=NO_MAX_RANGE;
+    break;
 
   case Item_func::SP_CROSSES_FUNC:
-      tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
-      tree->max_flag=NO_MAX_RANGE;
-      break;
+    tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+    tree->max_flag=NO_MAX_RANGE;
+    break;
   case Item_func::SP_WITHIN_FUNC:
-      tree->min_flag=GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512;
-      tree->max_flag=NO_MAX_RANGE;
-      break;
+    tree->min_flag=GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512;
+    tree->max_flag=NO_MAX_RANGE;
+    break;
 
   case Item_func::SP_CONTAINS_FUNC:
-      tree->min_flag=GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512;
-      tree->max_flag=NO_MAX_RANGE;
-      break;
+    tree->min_flag=GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512;
+    tree->max_flag=NO_MAX_RANGE;
+    break;
   case Item_func::SP_OVERLAPS_FUNC:
-      tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
-      tree->max_flag=NO_MAX_RANGE;
-      break;
+    tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+    tree->max_flag=NO_MAX_RANGE;
+    break;
 
   default:
     break;
@@ -3055,7 +3067,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
   uint tmp_min_flag,tmp_max_flag,keynr;
   char *tmp_min_key=min_key,*tmp_max_key=max_key;
 
-  key_tree->store(param->key[idx][key_tree->part].part_length,
+  key_tree->store(param->key[idx][key_tree->part].store_length,
 		  &tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
   uint min_key_length= (uint) (tmp_min_key- param->min_key);
   uint max_key_length= (uint) (tmp_max_key- param->max_key);
@@ -3152,9 +3164,20 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree,
 {
   QUICK_RANGE_SELECT *quick;
   DBUG_ENTER("get_quick_select");
-  if ((quick=new QUICK_RANGE_SELECT(param->thd, param->table,
-                                    param->real_keynr[idx],test(parent_alloc),
-                                    parent_alloc)))
+
+
+
+  if (param->table->key_info[param->real_keynr[idx]].flags & HA_SPATIAL)
+    quick=new QUICK_RANGE_SELECT_GEOM(param->thd, param->table,
+                                      param->real_keynr[idx],
+                                      test(parent_alloc),
+                                      parent_alloc);
+  else
+    quick=new QUICK_RANGE_SELECT(param->thd, param->table,
+                                 param->real_keynr[idx],
+                                 test(parent_alloc), parent_alloc);
+                           
+  if (quick)
   {
     if (quick->error ||
 	get_quick_keys(param,quick,param->key[idx],key_tree,param->min_key,0,
@@ -3194,7 +3217,7 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
       return 1;
   }
   char *tmp_min_key=min_key,*tmp_max_key=max_key;
-  key_tree->store(key[key_tree->part].part_length,
+  key_tree->store(key[key_tree->part].store_length,
 		  &tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
 
   if (key_tree->next_key_part &&
@@ -3314,19 +3337,17 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length)
 {
   for (const char *end=key+length ; 
        key < end;
-       key+= key_part++->part_length)
+       key+= key_part++->store_length)
   {
-    if (key_part->null_bit)
-    {
-      if (*key++)
-	return 1;
-    }
+    if (key_part->null_bit && *key)
+      return 1;
   }
   return 0;
 }
 
+
 /****************************************************************************
-** Create a QUICK RANGE based on a key
+  Create a QUICK RANGE based on a key
 ****************************************************************************/
 
 QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, 
@@ -3370,9 +3391,8 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
   {
     key_part->part=part;
     key_part->field=        key_info->key_part[part].field;
-    key_part->part_length=  key_info->key_part[part].length;
-    if (key_part->field->type() == FIELD_TYPE_BLOB)
-      key_part->part_length+=HA_KEY_BLOB_LENGTH;
+    key_part->length=  	    key_info->key_part[part].length;
+    key_part->store_length= key_info->key_part[part].store_length;
     key_part->null_bit=     key_info->key_part[part].null_bit;
   }
   if (insert_dynamic(&quick->ranges,(gptr)&range))
@@ -3539,117 +3559,88 @@ int QUICK_RANGE_SELECT::get_next()
   for (;;)
   {
     int result;
+    key_range start_key, end_key;
     if (range)
-    {						// Already read through key
-       result=((range->flag & (EQ_RANGE | GEOM_FLAG)) ?
-	       file->index_next_same(record, (byte*) range->min_key,
-				     range->min_length) :
-	       file->index_next(record));
-
-      if (!result)
-      {
-	if ((range->flag & GEOM_FLAG) || !cmp_next(*cur_range))
-	  DBUG_RETURN(0);
-      }
-      else if (result != HA_ERR_END_OF_FILE)
+    {
+      // Already read through key
+      result= file->read_range_next(test(range->flag & EQ_RANGE));
+      if (result != HA_ERR_END_OF_FILE)
 	DBUG_RETURN(result);
     }
-    
+
     if (!cur_range)
-      range= *(cur_range= (QUICK_RANGE**)ranges.buffer);
+      range= *(cur_range= (QUICK_RANGE**) ranges.buffer);
     else 
       range=
-        (cur_range == ((QUICK_RANGE**)ranges.buffer + ranges.elements - 1))?
-         NULL: *(++cur_range);
+        (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ?
+        (QUICK_RANGE*) 0 : *(++cur_range);
 
     if (!range)
       DBUG_RETURN(HA_ERR_END_OF_FILE);		// All ranges used
-    if (range->flag & GEOM_FLAG)
-    {
-      if ((result = file->index_read(record,
-				     (byte*) (range->min_key),
-				     range->min_length,
-				     (ha_rkey_function)(range->flag ^
-							GEOM_FLAG))))
-      {
-        if (result != HA_ERR_KEY_NOT_FOUND)
-	  DBUG_RETURN(result);
-        range=0;				// Not found, to next range
-        continue;
-      }
-      DBUG_RETURN(0);
-    }
 
-    if (range->flag & NO_MIN_RANGE)		// Read first record
-    {
-      int local_error;
-      if ((local_error=file->index_first(record)))
-	DBUG_RETURN(local_error);		// Empty table
-      if (cmp_next(range) == 0)
-	DBUG_RETURN(0);
-      range=0;			// No matching records; go to next range
-      continue;
-    }
-    if ((result = file->index_read(record,
-				   (byte*) (range->min_key +
-					    test(range->flag & GEOM_FLAG)),
-				   range->min_length,
-				   (range->flag & NEAR_MIN) ?
-				   HA_READ_AFTER_KEY:
-				   (range->flag & EQ_RANGE) ?
-				   HA_READ_KEY_EXACT :
-				   HA_READ_KEY_OR_NEXT)))
+    start_key.key=    (const byte*) range->min_key;
+    start_key.length= range->min_length;
+    start_key.flag=   ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
+		       (range->flag & EQ_RANGE) ?
+		       HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
+    end_key.key=      (const byte*) range->max_key;
+    end_key.length=   range->max_length;
+    /*
+      We use READ_AFTER_KEY here because if we are reading on a key
+      prefix we want to find all keys with this prefix
+    */
+    end_key.flag=     (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
+		       HA_READ_AFTER_KEY);
 
-    {
-      if (result != HA_ERR_KEY_NOT_FOUND)
-	DBUG_RETURN(result);
-      range=0;					// Not found, to next range
-      continue;
-    }
-    if (cmp_next(range) == 0)
-    {
-      if (range->flag == (UNIQUE_RANGE | EQ_RANGE))
-	range=0;				// Stop searching
-      DBUG_RETURN(0);				// Found key is in range
-    }
-    range=0;					// To next range
+    result= file->read_range_first(range->min_length ? &start_key : 0,
+				   range->max_length ? &end_key : 0,
+				   sorted);
+    if (range->flag == (UNIQUE_RANGE | EQ_RANGE))
+      range=0;				// Stop searching
+
+    if (result != HA_ERR_END_OF_FILE)
+      DBUG_RETURN(result);
+    range=0;				// No matching rows; go to next range
   }
 }
 
 
-/*
-  Compare if found key is over max-value
-  Returns 0 if key <= range->max_key
-*/
+/* Get next for geometrical indexes */
 
-int QUICK_RANGE_SELECT::cmp_next(QUICK_RANGE *range_arg)
+int QUICK_RANGE_SELECT_GEOM::get_next()
 {
-  if (range_arg->flag & NO_MAX_RANGE)
-    return 0;					/* key can't be to large */
+  DBUG_ENTER("QUICK_RANGE_SELECT_GEOM::get_next");
 
-  KEY_PART *key_part=key_parts;
-  for (char *key=range_arg->max_key, *end=key+range_arg->max_length;
-       key < end;
-       key+= key_part++->part_length)
+  for (;;)
   {
-    int cmp;
-    if (key_part->null_bit)
+    int result;
+    if (range)
     {
-      if (*key++)
-      {
-	if (!key_part->field->is_null())
-	  return 1;
-	continue;
-      }
-      else if (key_part->field->is_null())
-	return 0;
+      // Already read through key
+      result= file->index_next_same(record, (byte*) range->min_key,
+				    range->min_length);
+      if (result != HA_ERR_END_OF_FILE)
+	DBUG_RETURN(result);
     }
-    if ((cmp=key_part->field->key_cmp((byte*) key, key_part->part_length)) < 0)
-      return 0;
-    if (cmp > 0)
-      return 1;
+
+   if (!cur_range)
+      range= *(cur_range= (QUICK_RANGE**) ranges.buffer);
+    else
+      range=
+        (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ?
+        (QUICK_RANGE*) 0 : *(++cur_range);
+
+    if (!range)
+      DBUG_RETURN(HA_ERR_END_OF_FILE);		// All ranges used
+
+    result= file->index_read(record,
+			     (byte*) range->min_key,
+			     range->min_length,
+			     (ha_rkey_function)(range->flag ^ GEOM_FLAG));
+    if (result != HA_ERR_KEY_NOT_FOUND)
+      DBUG_RETURN(result);
+    range=0;				// Not found, to next range
   }
-  return (range_arg->flag & NEAR_MAX) ? 1 : 0;		// Exact match
 }
 
 
@@ -3833,6 +3824,47 @@ int QUICK_SELECT_DESC::get_next()
 }
 
 
+/*
+  Compare if found key is over max-value
+  Returns 0 if key <= range->max_key
+*/
+
+int QUICK_RANGE_SELECT::cmp_next(QUICK_RANGE *range_arg)
+{
+  if (range_arg->flag & NO_MAX_RANGE)
+    return 0;                                   /* key can't be to large */
+
+  KEY_PART *key_part=key_parts;
+  uint store_length;
+
+  for (char *key=range_arg->max_key, *end=key+range_arg->max_length;
+       key < end;
+       key+= store_length, key_part++)
+  {
+    int cmp;
+    store_length= key_part->store_length;
+    if (key_part->null_bit)
+    {
+      if (*key)
+      {
+        if (!key_part->field->is_null())
+          return 1;
+        continue;
+      }
+      else if (key_part->field->is_null())
+        return 0;
+      key++;					// Skip null byte
+      store_length--;
+    }
+    if ((cmp=key_part->field->key_cmp((byte*) key, key_part->length)) < 0)
+      return 0;
+    if (cmp > 0)
+      return 1;
+  }
+  return (range_arg->flag & NEAR_MAX) ? 1 : 0;          // Exact match
+}
+
+
 /*
   Returns 0 if found key is inside range (found key >= range->min_key).
 */
@@ -3843,15 +3875,18 @@ int QUICK_RANGE_SELECT::cmp_prev(QUICK_RANGE *range_arg)
     return 0;					/* key can't be to small */
 
   KEY_PART *key_part = key_parts;
+  uint store_length;
+
   for (char *key = range_arg->min_key, *end = key + range_arg->min_length;
        key < end;
-       key += key_part++->part_length)
+       key += store_length, key_part++)
   {
     int cmp;
+    store_length= key_part->store_length;
     if (key_part->null_bit)
     {
       // this key part allows null values; NULL is lower than everything else
-      if (*key++)
+      if (*key)
       {
 	// the range is expecting a null value
 	if (!key_part->field->is_null())
@@ -3860,9 +3895,11 @@ int QUICK_RANGE_SELECT::cmp_prev(QUICK_RANGE *range_arg)
       }
       else if (key_part->field->is_null())
 	return 1;	// null -- outside the range
+      key++;
+      store_length--;
     }
     if ((cmp = key_part->field->key_cmp((byte*) key,
-					key_part->part_length)) > 0)
+					key_part->length)) > 0)
       return 0;
     if (cmp < 0)
       return 1;
@@ -3890,23 +3927,20 @@ bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range_arg)
 bool QUICK_SELECT_DESC::test_if_null_range(QUICK_RANGE *range_arg,
 					   uint used_key_parts)
 {
-  uint offset,end;
+  uint offset, end;
   KEY_PART *key_part = key_parts,
            *key_part_end= key_part+used_key_parts;
 
   for (offset= 0,  end = min(range_arg->min_length, range_arg->max_length) ;
        offset < end && key_part != key_part_end ;
-       offset += key_part++->part_length)
+       offset+= key_part++->store_length)
   {
-    uint null_length=test(key_part->null_bit);
     if (!memcmp((char*) range_arg->min_key+offset,
 		(char*) range_arg->max_key+offset,
-		key_part->part_length + null_length))
-    {
-      offset+=null_length;
+		key_part->store_length))
       continue;
-    }
-    if (null_length && range_arg->min_key[offset])
+
+    if (key_part->null_bit && range_arg->min_key[offset])
       return 1;				// min_key is null and max_key isn't
     // Range doesn't cover NULL. This is ok if there is no more null parts
     break;
@@ -3948,33 +3982,34 @@ static void
 print_key(KEY_PART *key_part,const char *key,uint used_length)
 {
   char buff[1024];
+  const char *key_end= key+used_length;
   String tmp(buff,sizeof(buff),&my_charset_bin);
+  uint store_length;
 
-  for (uint length=0;
-       length < used_length ;
-       length+=key_part->part_length, key+=key_part->part_length, key_part++)
+  for (; key < key_end; key+=store_length, key_part++)
   {
-    Field *field=key_part->field;
-    if (length != 0)
-      fputc('/',DBUG_FILE);
+    Field *field=      key_part->field;
+    store_length= key_part->store_length;
+
     if (field->real_maybe_null())
     {
-      length++;				// null byte is not in part_length
-      if (*key++)
+      if (*key)
       {
 	fwrite("NULL",sizeof(char),4,DBUG_FILE);
 	continue;
       }
+      key++;					// Skip null byte
+      store_length--;
     }
-    field->set_key_image((char*) key,key_part->part_length -
-			 ((field->type() == FIELD_TYPE_BLOB) ?
-			  HA_KEY_BLOB_LENGTH : 0),
-			 field->charset());
-    field->val_str(&tmp,&tmp);
+    field->set_key_image((char*) key, key_part->length, field->charset());
+    field->val_str(&tmp);
     fwrite(tmp.ptr(),sizeof(char),tmp.length(),DBUG_FILE);
+    if (key+store_length < key_end)
+      fputc('/',DBUG_FILE);
   }
 }
 
+
 static void print_quick_sel_imerge(QUICK_INDEX_MERGE_SELECT *quick, 
                             const key_map *needed_reg)
 {
@@ -3994,6 +4029,7 @@ static void print_quick_sel_imerge(QUICK_INDEX_MERGE_SELECT *quick,
   DBUG_VOID_RETURN;
 }
 
+
 void print_quick_sel_range(QUICK_RANGE_SELECT *quick,
                            const key_map *needed_reg)
 {
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 3c528719b29..30e0fcd7be5 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -35,7 +35,7 @@
 
 
 typedef struct st_key_part {
-  uint16           key,part,part_length;
+  uint16           key,part, store_length, length;
   uint8            null_bit;
   Field            *field;
   Field::imagetype image_type;
@@ -74,6 +74,7 @@ class QUICK_RANGE :public Sql_alloc {
 class QUICK_SELECT_I
 {
 public:
+  bool sorted;
   ha_rows records;  /* estimate of # of records to be retrieved */
   double  read_time; /* time to perform this retrieval          */
   TABLE   *head;
@@ -170,6 +171,17 @@ class QUICK_RANGE_SELECT : public QUICK_SELECT_I
 };
 
 
+class QUICK_RANGE_SELECT_GEOM: public QUICK_RANGE_SELECT
+{
+public:
+  QUICK_RANGE_SELECT_GEOM(THD *thd, TABLE *table, uint index_arg,
+                          bool no_alloc, MEM_ROOT *parent_alloc)
+    :QUICK_RANGE_SELECT(thd, table, index_arg, no_alloc, parent_alloc)
+    {};
+  virtual int get_next();
+};
+
+
 /*
   QUICK_INDEX_MERGE_SELECT - index_merge access method quick select.
 
diff --git a/sql/slave.cc b/sql/slave.cc
index 3fddc4dc783..1fe4aa40f8e 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -464,16 +464,15 @@ void init_slave_skip_errors(const char* arg)
 }
 
 
-void st_relay_log_info::inc_group_relay_log_pos(ulonglong val,
-                                                ulonglong log_pos,
-                                                bool skip_lock)
+void st_relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
+						bool skip_lock=0)  
 {
   if (!skip_lock)
     pthread_mutex_lock(&data_lock);
-  inc_event_relay_log_pos(val);
+  inc_event_relay_log_pos();
   group_relay_log_pos= event_relay_log_pos;
   strmake(group_relay_log_name,event_relay_log_name,
-          sizeof(group_relay_log_name)-1);
+	  sizeof(group_relay_log_name)-1);
 
   notify_group_relay_log_name_update();
         
@@ -487,6 +486,28 @@ void st_relay_log_info::inc_group_relay_log_pos(ulonglong val,
     not advance as it should on the non-transactional slave (it advances by
     big leaps, whereas it should advance by small leaps).
   */
+  /*
+    In 4.x we used the event's len to compute the positions here. This is
+    wrong if the event was 3.23/4.0 and has been converted to 5.0, because
+    then the event's len is not what is was in the master's binlog, so this
+    will make a wrong group_master_log_pos (yes it's a bug in 3.23->4.0
+    replication: Exec_master_log_pos is wrong). Only way to solve this is to
+    have the original offset of the end of the event the relay log. This is
+    what we do in 5.0: log_pos has become "end_log_pos" (because the real use
+    of log_pos in 4.0 was to compute the end_log_pos; so better to store
+    end_log_pos instead of begin_log_pos.
+    If we had not done this fix here, the problem would also have appeared
+    when the slave and master are 5.0 but with different event length (for
+    example the slave is more recent than the master and features the event
+    UID). It would give false MASTER_POS_WAIT, false Exec_master_log_pos in
+    SHOW SLAVE STATUS, and so the user would do some CHANGE MASTER using this
+    value which would lead to badly broken replication.
+    Even the relay_log_pos will be corrupted in this case, because the len is
+    the relay log is not "val".
+    With the end_log_pos solution, we avoid computations involving lengthes.
+  */
+  DBUG_PRINT("info", ("log_pos=%lld group_master_log_pos=%lld",
+		      log_pos,group_master_log_pos));
   if (log_pos) // 3.23 binlogs don't have log_posx
   {
 #if MYSQL_VERSION_ID < 50000
@@ -500,10 +521,10 @@ void st_relay_log_info::inc_group_relay_log_pos(ulonglong val,
       Yes this is a hack but it's just to make 3.23->4.x replication work;
       3.23->5.0 replication is working much better.
     */
-    group_master_log_pos= log_pos + val -
+    group_master_log_pos= log_pos -
       (mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0);
 #else
-    group_master_log_pos= log_pos+ val;
+    group_master_log_pos= log_pos;
 #endif /* MYSQL_VERSION_ID < 5000 */
   }
   pthread_cond_broadcast(&data_cond);
@@ -2540,13 +2561,13 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
     goto err;
   }    
 
-  int cmp_result;
-
   /* The "compare and wait" main loop */
   while (!thd->killed &&
          init_abort_pos_wait == abort_pos_wait &&
          slave_running)
   {
+    bool pos_reached;
+    int cmp_result= 0;
 
     /*
       group_master_log_name can be "", if we are just after a fresh
diff --git a/sql/slave.h b/sql/slave.h
index 157111e54f0..46fe58e1976 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -283,12 +283,14 @@ typedef struct st_relay_log_info
       until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_UNKNOWN;
   }
   
-  inline void inc_event_relay_log_pos(ulonglong val)
+  inline void inc_event_relay_log_pos()
   {
-    event_relay_log_pos+= val;
+    event_relay_log_pos= future_event_relay_log_pos;
   }
 
-  void inc_group_relay_log_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0);
+  void inc_group_relay_log_pos(ulonglong log_pos,
+			       bool skip_lock=0);
+
   int wait_for_pos(THD* thd, String* log_name, longlong log_pos, 
 		   longlong timeout);
   void close_temporary_tables();
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 063474fc960..96e340fa745 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -206,8 +206,8 @@ sp_head::operator delete(void *ptr, size_t size)
 }
 
 sp_head::sp_head()
-  : Sql_alloc(), m_has_return(FALSE), m_simple_case(FALSE),
-    m_multi_results(FALSE), m_free_list(NULL), m_returns_cs(NULL)
+  : Sql_alloc(), m_returns_cs(NULL), m_has_return(FALSE), m_simple_case(FALSE),
+    m_multi_results(FALSE), m_free_list(NULL)
 {
   DBUG_ENTER("sp_head::sp_head");
 
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 057ea6e8bd5..598f131985c 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3434,6 +3434,7 @@ mysql_execute_command(THD *thd)
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
 	st_sp_security_context save_ctx;
 #endif
+	ha_rows select_limit;
 	uint smrx;
 	LINT_INIT(smrx);
 
@@ -3468,9 +3469,12 @@ mysql_execute_command(THD *thd)
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
 	sp_change_security_context(thd, sp, &save_ctx);
 #endif
+	select_limit= thd->variables.select_limit;
+	thd->variables.select_limit= HA_POS_ERROR;
 
 	res= sp->execute_procedure(thd, &lex->value_list);
 
+	thd->variables.select_limit= select_limit;
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
 	sp_restore_security_context(thd, sp, &save_ctx);
 #endif
diff --git a/tests/client_test.c b/tests/client_test.c
index e8fc5c0ecc7..af9818b7f23 100644
--- a/tests/client_test.c
+++ b/tests/client_test.c
@@ -6976,7 +6976,7 @@ static void test_explain_bug()
                        "","","",NAME_LEN,0);
 
   verify_prepare_field(result,6,"key_len","",MYSQL_TYPE_VAR_STRING,
-                       "","","",NAME_LEN*32,0);
+                       "","","",NAME_LEN*64,0);
 
   verify_prepare_field(result,7,"ref","",MYSQL_TYPE_VAR_STRING,
                        "","","",NAME_LEN*16,0);
-- 
2.30.9