diff --git a/.bzrignore b/.bzrignore
index 978926c8c37..88995ac7c65 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -562,3 +562,8 @@ bkpull.log.2
 bkpull.log.3
 build.log
 sql/safe_to_cache_query.txt
+bkpull.log.4
+bkpull.log.5
+bkpull.log.6
+bkpush.log
+sql/sql_yacc.output
diff --git a/client/insert_test.c b/client/insert_test.c
index 42691df6875..fb4890faf73 100644
--- a/client/insert_test.c
+++ b/client/insert_test.c
@@ -16,6 +16,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <my_global.h>
 #include "mysql.h"
 
 #define INSERT_QUERY "insert into test (name,num) values ('item %d', %d)"
diff --git a/client/select_test.c b/client/select_test.c
index ee2a9192865..d7f18c0f1f0 100644
--- a/client/select_test.c
+++ b/client/select_test.c
@@ -19,6 +19,7 @@
 #endif
 #include <stdio.h>
 #include <stdlib.h>
+#include "my_global.h"
 #include "mysql.h"
 
 #define SELECT_QUERY "select name from test where num = %d"
diff --git a/include/mysql.h b/include/mysql.h
index 230c0aad9df..67558e39cdb 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -61,6 +61,8 @@ typedef int my_socket;
 #define CHECK_EXTRA_ARGUMENTS
 #endif
 
+#include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */
+
 extern unsigned int mysql_port;
 extern char *mysql_unix_port;
 
@@ -213,6 +215,8 @@ typedef struct st_mysql
   struct st_mysql* last_used_slave; /* needed for round-robin slave pick */
  /* needed for send/read/store/use result to work correctly with replication */
   struct st_mysql* last_used_con;
+
+  LIST  *stmts;                     /* list of all statements */
 } MYSQL;
 
 
@@ -457,6 +461,7 @@ typedef struct st_mysql_stmt
   MYSQL_RES	*result;		/* resultset */
   MYSQL_BIND	*bind;			/* row binding */
   MYSQL_FIELD	*fields;		/* prepare meta info */
+  LIST          list;                   /* list to keep track of all stmts */
   char		*query;			/* query buffer */
   MEM_ROOT	mem_root;		/* root allocations */
   MYSQL_RES	tmp_result;		/* Used by mysql_prepare_result */
@@ -469,8 +474,8 @@ typedef struct st_mysql_stmt
   char		last_error[MYSQL_ERRMSG_SIZE]; /* error message */
   my_bool	long_alloced;		/* flag to indicate long alloced */
   my_bool	send_types_to_server;	/* to indicate types supply to server */
-  my_bool param_buffers;    /* to indicate the param bound buffers */
-  my_bool res_buffers;      /* to indicate the result bound buffers */
+  my_bool       param_buffers;          /* to indicate the param bound buffers */
+  my_bool       res_buffers;            /* to indicate the output bound buffers */
 } MYSQL_STMT;
 
 
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 410be65660f..352ac520fed 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -114,6 +114,7 @@ static my_bool send_file_to_server(MYSQL *mysql,const char *filename);
 static sig_handler pipe_sig_handler(int sig);
 static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
 				     const char *from, ulong length);
+static my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list);
 
 static my_bool org_my_init_done=0;
 
@@ -2436,6 +2437,16 @@ mysql_close(MYSQL *mysql)
       }
       mysql->rpl_pivot=0;
     }
+    if (mysql->stmts)
+    {
+      /* Free any open prepared statements */
+      LIST *element, *next_element;
+      for (element= mysql->stmts; element; element= next_element)
+      {
+        next_element= element->next;
+        stmt_close((MYSQL_STMT *)element->data, 0);
+      }      
+    }
     if (mysql != mysql->master)
       mysql_close(mysql->master);
     if (mysql->free_me)
@@ -3675,18 +3686,20 @@ mysql_prepare(MYSQL  *mysql, const char *query, ulong length)
   }
   if (simple_command(mysql, COM_PREPARE, query, length, 1))
   {
-    mysql_stmt_close(stmt);
+    stmt_close(stmt, 1);
     DBUG_RETURN(0);
   }
 
   init_alloc_root(&stmt->mem_root,8192,0);
   if (read_prepare_result(mysql, stmt))
   {
-    mysql_stmt_close(stmt);
+    stmt_close(stmt, 1);
     DBUG_RETURN(0);
   }
   stmt->state= MY_ST_PREPARE;
   stmt->mysql= mysql;
+  mysql->stmts= list_add(mysql->stmts, &stmt->list);
+  stmt->list.data= stmt;
   DBUG_PRINT("info", ("Parameter count: %ld", stmt->param_count));
   DBUG_RETURN(stmt);
 }
@@ -4304,7 +4317,6 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
   DBUG_RETURN(0);
 }
 
-
 /*
   Fetch row data to bind buffers
 */
@@ -4387,27 +4399,42 @@ int STDCALL mysql_fetch(MYSQL_STMT *stmt)
 *********************************************************************/
 
 /*
-  Close the statement handle by freeing all resources
-*/
+  Close the statement handle by freeing all alloced resources
 
-my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
+  SYNOPSIS
+    mysql_stmt_close()
+    stmt	       Statement handle
+    skip_list    Flag to indicate delete from list or not
+  RETURN VALUES
+    0	ok
+    1	error
+*/
+static my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list)
 {
   my_bool error=0;
   DBUG_ENTER("mysql_stmt_close");
 
-  if (stmt->state != MY_ST_UNKNOWN)
+  DBUG_ASSERT(stmt != 0);
+  if (stmt->state == MY_ST_PREPARE || stmt->state == MY_ST_EXECUTE)
   {
     char buff[4];
     int4store(buff, stmt->stmt_id);
-    error= simple_command(stmt->mysql, COM_CLOSE_STMT, buff, 4, 0);
+    error= simple_command(stmt->mysql, COM_CLOSE_STMT, buff, 4, 1);
   }
   mysql_free_result(stmt->result);
   free_root(&stmt->mem_root, MYF(0));
   my_free((gptr) stmt->query, MYF(MY_WME | MY_ALLOW_ZERO_PTR));
+  if (!skip_list)
+    stmt->mysql->stmts= list_delete(stmt->mysql->stmts, &stmt->list);
   my_free((gptr) stmt, MYF(MY_WME));
   DBUG_RETURN(error);
 }
 
+my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
+{
+  return stmt_close(stmt, 0);
+}
+
 /*
   Return statement error code
 */
diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh
index 02e3072a3f9..5fa67773566 100644
--- a/sql-bench/crash-me.sh
+++ b/sql-bench/crash-me.sh
@@ -38,7 +38,7 @@
 # as such, and clarify ones such as "mediumint" with comments such as
 # "3-byte int" or "same as xxx".
 
-$version="1.58";
+$version="1.59";
 
 use DBI;
 use Getopt::Long;
@@ -253,6 +253,9 @@ check_and_report("\` as identifier quote",'quote_ident_with_`',[],
 		 'select `A` from crash_me',[],"1",0);
 check_and_report("[] as identifier quote",'quote_ident_with_[',[],
 		 'select [A] from crash_me',[],"1",0);
+report('Double "" in identifiers as "','quote_ident_with_dbl_"',
+        'create table crash_me1 ("abc""d" integer)',
+	'drop table crash_me1');		 
 
 report("Column alias","column_alias","select a as ab from crash_me");
 report("Table alias","table_alias","select b.a from crash_me as b");
@@ -301,6 +304,7 @@ try_and_report("LIMIT number of rows","select_limit",
 	       ["with TOP",
 		"select TOP 1 * from crash_me"]);
 report("SELECT with LIMIT #,#","select_limit2", "select * from crash_me limit 1,1");
+report("SELECT with LIMIT # OFFSET #","select_limit3", "select * from crash_me limit 1 offset 1");
 
 # The following alter table commands MUST be kept together!
 if ($dbh->do("create table crash_q (a integer, b integer,c1 CHAR(10))"))
@@ -434,6 +438,9 @@ report("hex strings (x'1ace')","hex_strings","select x'1ace' $end_query");
 report_result("Value of logical operation (1=1)","logical_value",
 	      "select (1=1) $end_query");
 
+report_result("Value of TRUE","value_of_true","select TRUE $end_query");
+report_result("Value of FALSE","value_of_false","select FALSE $end_query");
+
 $logical_value= $limits{'logical_value'};
 
 $false=0;
@@ -584,7 +591,7 @@ print "$limits{'query_size'}\n";
 	      "int not null identity,unique(q)",
 	      # postgres types
 	      "box","bool","circle","polygon","point","line","lseg","path",
-	      "interval", "serial", "inet", "cidr", "macaddr",
+	      "interval", "inet", "cidr", "macaddr",
 
 	      # oracle types
 	      "varchar2(16)","nvarchar2(16)","number(9,2)","number(9)",
@@ -769,7 +776,6 @@ try_and_report("Automatic row id", "automatic_rowid",
    ["CURRENT_DATE","current_date","current_date",0,2],
    ["CURRENT_TIME","current_time","current_time",0,2],
    ["CURRENT_TIMESTAMP","current_timestamp","current_timestamp",0,2],
-   ["CURRENT_USER","current_user","current_user",0,2],
    ["EXTRACT","extract_sql","extract(minute from timestamp '2000-02-23 18:43:12.987')",43,0],
    ["LOCALTIME","localtime","localtime",0,2],
    ["LOCALTIMESTAMP","localtimestamp","localtimestamp",0,2],
@@ -778,11 +784,8 @@ try_and_report("Automatic row id", "automatic_rowid",
    ["NULLIF with numbers","nullif_num","NULLIF(NULLIF(1,2),1)",undef(),4],
    ["OCTET_LENGTH","octet_length","octet_length('abc')",3,0],
    ["POSITION","position","position('ll' in 'hello')",3,0],
-   ["SESSION_USER","session_user","session_user",0,2],
-   ["SYSTEM_USER","system_user","system_user",0,2],
    ["TRIM","trim","trim(trailing from trim(LEADING FROM ' abc '))","abc",3],
    ["UPPER","upper","UPPER('abc')","ABC",1],
-   ["USER","user","user"],
    ["concatenation with ||","concat_as_||","'abc' || 'def'","abcdef",1],
    );
 
@@ -960,8 +963,61 @@ try_and_report("Automatic row id", "automatic_rowid",
    ["automatic num->string convert","auto_num2string","concat('a',2)","a2",1],
    ["automatic string->num convert","auto_string2num","'1'+2",3,0],
    ["concatenation with +","concat_as_+","'abc' + 'def'","abcdef",1],
+   ["SUBSTR (2 arg)",'substr2arg',"substr('abcd',2)",'bcd',1],  #sapdb func
+   ["SUBSTR (3 arg)",'substr3arg',"substr('abcd',2,2)",'bc',1],
+   ["LFILL (3 arg)",'lfill3arg',"lfill('abcd','.',6)",'..abcd',1],
+   ["RFILL (3 arg)",'rfill3arg',"rfill('abcd','.',6)",'abcd..',1],
+   ["RPAD (4 arg)",'rpad4arg',"rpad('abcd',2,'+-',8)",'abcd+-+-',1],
+   ["LPAD (4 arg)",'rpad4arg',"lpad('abcd',2,'+-',8)",'+-+-abcd',1],
+   ["SAPDB compatible TRIM (1 arg)",'trim1arg',"trim(' abcd ')",'abcd',1],
+   ["SAPDB compatible TRIM (2 arg)",'trim2arg',"trim('..abcd..','.')",'abcd',1],
+   ["LTRIM (2 arg)",'ltrim2arg',"ltrim('..abcd..','.')",'abcd..',1],
+   ["RTRIM (2 arg)",'rtrim2arg',"rtrim('..abcd..','.')",'..abcd',1],
+   ["EXPAND",'expand2arg',"expand('abcd',6)",'abcd  ',0],
+   ["REPLACE (2 arg) ",'replace2arg',"replace('AbCd','bC')",'Ad',1],
+   ["MAPCHAR",'mapchar',"mapchar('A�')",'Aa',1],
+   ["ALPHA",'alpha',"alpha('A�',2)",'AA',1],
+   ["ASCII in string cast",'ascii_string',"ascii('a')",'a',1],
+   ["EBCDIC in string cast",'ebcdic_string',"ebcdic('a')",'a',1],
+   ["TRUNC (1 arg)",'trunc1arg',"trunc(222.6)",222,0],
+   ["NOROUND",'noround',"noround(222.6)",222.6,0],
+   ["FIXED",'fixed',"fixed(222.6666,10,2)",'222.67',0],
+   ["FLOAT",'float',"float(6666.66,4)",6667,0],
+   ["LENGTH",'length',"length(1)",2,0],
+   ["INDEX",'index',"index('abcdefg','cd',1,1)",3,0],
+   ["ADDDATE",'adddate',"ADDDATE('20021201',3)",'20021204',0],
+   ["SUBDATE",'subdate',"SUBDATE('20021204',3)",'20021201',0],
+   ["DATEDIFF (2 arg)",'datediff2arg',"DATEDIFF('20021204','20021201')",'3',0], # sapdb
+   ["DAYOFWEEK with sapdb internal date as arg",'dayofweek_sapdb',"DAYOFWEEK('19630816')",'5',0],
+   ["WEEKOFYEAR",'weekofyear',"WEEKOFYEAR('19630816')",'33',0],
+   ["DAYOFMONTH with sapdb internal date as arg",'dayofmonth_sapdb',"dayofmonth('19630816')",'16',0],
+   ["DAYOFYEAR  with sapdb internal date as arg",'dayofyear_sapdb',"DAYOFYEAR('19630816')",'228',0],
+   ["MAKEDATE",'makedate',"MAKEDATE(1963,228)",'19630816',0],
+   ["DAYNAME  with sapdb internal date as arg",'dayname_sapdb',"DAYNAME('19630816')",'Friday',0],
+   ["MONTHNAME with sapdb internal date as arg",'monthname_sapdb',"MONTHNAME('19630816')",'August',0],
+   ["ADDTIME",'addtime',"ADDTIME('00200212','00000300')",'00200215',0],
+   ["SUBTIME",'subdate',"SUBDATE('00200215','00000300')",'00200212',0],
+   ["TIMEDIFF",'timediff',"TIMEDIFF('00200215','00200212')",'00000003',0],
+   ["MAKETIME",'maketime',"MAKETIME(20,02,12)",'00200212',0],
+   ["YEAR with sapdb internal date as arg",'year_sapdb',"YEAR('20021201')",'2002',0],
+   ["MONTH with sapdb internal date as arg",'month_sapdb',"MONTH('20021201')",'12',0],
+   ["DAY",'day',"DAY('20021201')",1,0],
+   ["HOUR with sapdb internal time as arg",'hour_sapdb',"HOUR('00200212')",20,0],
+   ["MINUTE with sapdb internal time as arg",'minute_sapdb',"MINUTE('00200212')",2,0],
+   ["SECOND with sapdb internal time as arg",'second_sapdb',"SECOND('00200212')",12,0],
+   ["MICROSECOND",'microsecond',"MICROSECOND('19630816200212111111')",'111111',0],
+   ["TIMESTAMP",'timestamp',"timestamp('19630816','00200212')",'19630816200212000000',0],
+   ["TIME",'time',"time('00200212')",'00200212',0],
+   ["DATE",'date',"date('19630816')",'19630816',0],
+   ["VALUE",'value',"value(NULL,'WALRUS')",'WALRUS',0],
+   ["DECODE",'decode',"DECODE('S-103','T72',1,'S-103',2,'Leopard',3)",2,0],
+   ["NUM",'num',"NUM('2123')",2123,0],
+   ["CHAR (conversation date)",'char_date',"CHAR(DATE('19630816'),EUR)",'16.08.1963',0],
+   ["CHR (any type to string)",'chr_str',"CHR(67)",'67',0],
+   ["HEX",'hex',"HEX('A')",41,0],
    );
 
+
 @sql_group_functions=
   (
    ["AVG","avg","avg(a)",1,0],
@@ -1131,6 +1187,20 @@ else
 }
 
 
+if ($limits{'func_extra_noround'} eq 'yes')
+{
+  report("Ignoring NOROUND","ignoring_noround",
+  "create table crash_q (a int)",
+  "insert into crash_q values(noround(10.22))",
+  "drop table crash_q $drop_attr"); 
+}
+
+check_parenthesis("func_sql_","CURRENT_USER");
+check_parenthesis("func_sql_","SESSION_USER");
+check_parenthesis("func_sql_","SYSTEM_USER");
+check_parenthesis("func_sql_","USER");
+
+
 report("LIKE on numbers","like_with_number",
        "create table crash_q (a int,b int)",
        "insert into crash_q values(10,10)",
@@ -1561,19 +1631,29 @@ if (!defined($limits{"transactions"}))
 {
   my ($limit,$type);
   $limit="transactions";
+  $limit_r="rollback_metadata";
   print "$limit: ";
   foreach $type (('', 'type=bdb', 'type=innodb', 'type=gemini'))
   {
     undef($limits{$limit});
-    last if (!report_trans($limit,
+    if (!report_trans($limit,
 			   [create_table("crash_q",["a integer not null"],[],
 					 $type),
 			    "insert into crash_q values (1)"],
 			   "select * from crash_q",
 			   "drop table crash_q $drop_attr"
-			  ));
+			  ))
+     {
+       report_rollback($limit_r,
+              [create_table("crash_q",["a integer not null"],[],
+				 $type)],
+			    "insert into crash_q values (1)",
+			   "drop table crash_q $drop_attr" );
+     last;
+     };
   }
   print "$limits{$limit}\n";
+  print "$limit_r: $limits{$limit_r}\n";
 }
 
 report("atomic updates","atomic_updates",
@@ -1644,14 +1724,29 @@ report("Column constraints","constraint_check",
        "create table crash_q (a int check (a>0))",
        "drop table crash_q $drop_attr");
 
+report("Ignoring column constraints","ignoring_constraint_check",
+       "create table crash_q (a int check (a>0))",
+       "insert into crash_q values(0)",
+       "drop table crash_q $drop_attr") if ($limits{'constraint_check'} eq 'yes');
+
 report("Table constraints","constraint_check_table",
        "create table crash_q (a int ,b int, check (a>b))",
        "drop table crash_q $drop_attr");
 
-report("Named constraints","constraint_check",
+report("Ignoring table constraints","ignoring_constraint_check_table",
+       "create table crash_q (a int ,b int, check (a>b))",
+       "insert into crash_q values(0,0)",
+       "drop table crash_q $drop_attr") if ($limits{'constraint_check_table'} eq 'yes');
+
+report("Named constraints","constraint_check_named",
        "create table crash_q (a int ,b int, constraint abc check (a>b))",
        "drop table crash_q $drop_attr");
 
+report("Ignoring named constraints","ignoring_constraint_check_named",
+       "create table crash_q (a int ,b int, constraint abc check (a>b))",
+       "insert into crash_q values(0,0)",
+       "drop table crash_q $drop_attr") if ($limits{'constraint_check_named'} eq 'yes');
+
 report("NULL constraint (SyBase style)","constraint_null",
        "create table crash_q (a int null)",
        "drop table crash_q $drop_attr");
@@ -2018,7 +2113,7 @@ $key="safe_decimal_arithmetic";
 if (!defined($limits{$key}))
 {
    print "$prompt=";
-   save_incomplete($limit,$prompt);	
+   save_incomplete($key,$prompt);	
    if (!safe_query($server->create("crash_me_a",["a decimal(10,2)","b decimal(10,2)"]))) 
      {
        print DBI->errstr();
@@ -2045,6 +2140,53 @@ if (!defined($limits{$key}))
   print "$prompt=$limits{$key} (cached)\n";
 }
 
+# Check where is null values in sorted recordset
+if (!safe_query($server->create("crash_me_n",["i integer","r integer"]))) 
+ {
+   print DBI->errstr();
+   die "Can't create table 'crash_me_n' $DBI::errstr\n";
+ };
+assert("insert into crash_me_n (i) values(1)");
+assert("insert into crash_me_n values(2,2)");
+assert("insert into crash_me_n values(3,3)");
+assert("insert into crash_me_n values(4,4)");
+assert("insert into crash_me_n (i) values(5)");
+
+$key = "position_of_null";
+$prompt ="Where is null values in sorted recordset";
+if (!defined($limits{$key}))
+{
+ save_incomplete($key,$prompt);	
+ print "$prompt=";
+ $sth=$dbh->prepare("select r from crash_me_n order by r ");
+ $sth->execute;
+ $limit= detect_null_position($sth);
+ $sth->finish;
+ print "$limit\n";
+ save_config_data($key,$limit,$prompt);
+} else {
+  print "$prompt=$limits{$key} (cache)\n";
+}
+
+$key = "position_of_null_desc";
+$prompt ="Where is null values in sorted recordset (DESC)";
+if (!defined($limits{$key}))
+{
+ save_incomplete($key,$prompt);	
+ print "$prompt=";
+ $sth=$dbh->prepare("select r from crash_me_n order by r desc");
+ $sth->execute;
+ $limit= detect_null_position($sth);
+ $sth->finish;
+ print "$limit\n";
+ save_config_data($key,$limit,$prompt);
+} else {
+  print "$prompt=$limits{$key} (cache)\n";
+}
+
+
+assert("drop table  crash_me_n $drop_attr");
+
 
 #
 # End of test
@@ -2059,6 +2201,41 @@ $dbh->disconnect || warn $dbh->errstr;
 save_all_config_data();
 exit 0;
 
+# Check where is nulls in the sorted result (for)
+# it expects exactly 5 rows in the result
+
+sub detect_null_position
+{
+  my $sth = shift;
+  my ($z,$r1,$r2,$r3,$r4,$r5);
+ $r1 = $sth->fetchrow_array;
+ $r2 = $sth->fetchrow_array;
+ $r3 = $sth->fetchrow_array;
+ $r4 = $sth->fetchrow_array;
+ $r5 = $sth->fetchrow_array;
+ return "first" if ( !defined($r1) && !defined($r2) && defined($r3));
+ return "last" if ( !defined($r5) && !defined($r4) && defined($r3));
+ return "random";
+}
+
+sub check_parenthesis {
+ my $prefix=shift;
+ my $fn=shift;
+ my $resultat='no';
+ my $param_name=$prefix.lc($fn);
+ 
+ save_incomplete($param_name,$fn);
+ if (safe_query("select $fn $end_query") == 1)
+  {
+    $resultat="yes";
+  } 
+  elsif ( safe_query("select $fn() $end_query") == 1)   
+  {    
+    $resultat="with_parenthesis";
+  }
+  save_config_data($param_name,$resultat,$fn);
+}
+
 sub usage
 {
     print <<EOF;
@@ -2561,10 +2738,10 @@ sub report_result
   {
     save_incomplete($limit,$prompt);
     $error=safe_query_result($query,"1",2);
-    save_config_data($limit,$error ? "not supported" : $last_result,$prompt);
+    save_config_data($limit,$error ? "not supported" :$last_result,$prompt);
   }
   print "$limits{$limit}\n";
-  return $limits{$limit} ne "no";
+  return $limits{$limit} ne "not supported";
 }
 
 sub report_trans
@@ -2578,17 +2755,12 @@ sub report_trans
     {
       if (safe_query(\@$queries))
       {
-	  $rc = $dbh->rollback;
-	  if ($rc) {
-	    $dbh->{AutoCommit} = 1;
+	  $dbh->rollback;
+          $dbh->{AutoCommit} = 1;
 	    if (safe_query_result($check,"","")) {
 	      save_config_data($limit,"yes",$limit);
 	    }
 	    safe_query($clear);
-	  } else {
-	    $dbh->{AutoCommit} = 1;
-	    save_config_data($limit,"error",$limit);
-	  }
       } else {
         save_config_data($limit,"error",$limit);
       }
@@ -2603,6 +2775,39 @@ sub report_trans
   return $limits{$limit} ne "yes";
 }
 
+sub report_rollback
+{
+  my ($limit,$queries,$check,$clear)=@_;
+  if (!defined($limits{$limit}))
+  {
+    save_incomplete($limit,$prompt);
+    eval {undef($dbh->{AutoCommit})};
+    if (!$@)
+    {
+      if (safe_query(\@$queries))
+      {
+	  $dbh->rollback;
+           $dbh->{AutoCommit} = 1;
+           if (safe_query($check)) {
+	      save_config_data($limit,"no",$limit);
+	    }  else  {
+	      save_config_data($limit,"yes",$limit);
+	    };
+	    safe_query($clear);
+      } else {
+        save_config_data($limit,"error",$limit);
+      }
+    }
+    else
+    {
+      save_config_data($limit,"error",$limit);
+    }
+    safe_query($clear);
+  }
+  $dbh->{AutoCommit} = 1;
+  return $limits{$limit} ne "yes";
+}
+
 
 sub check_and_report
 {
@@ -2929,7 +3134,7 @@ sub read_config_data
       {
 	if ($key !~ /restart/i)
 	{
-	  $limits{$key}=$limit;
+	  $limits{$key}=$limit eq "null"? undef : $limit;
 	  $prompts{$key}=length($prompt) ? substr($prompt,2) : "";
 	  delete $limits{'restart'};
 	}
@@ -2959,7 +3164,8 @@ sub save_config_data
   return if (defined($limits{$key}) && $limits{$key} eq $limit);
   if (!defined($limit) || $limit eq "")
   {
-    die "Undefined limit for $key\n";
+#    die "Undefined limit for $key\n";
+     $limit = 'null'; 
   }
   print CONFIG_FILE "$key=$limit\t# $prompt\n";
   $limits{$key}=$limit;
@@ -3613,5 +3819,6 @@ sub check_query
 }
 
 
+
 ### TODO:
 # OID test instead of / in addition to _rowid
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 0b6c2872925..0a1b02ada40 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -516,7 +516,7 @@ int compare_prep_stmt(void *not_used, PREP_STMT *stmt, ulong *key);
 void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used);
 bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length);
 void mysql_stmt_execute(THD *thd, char *packet);
-void mysql_stm_close(THD *thd, char *packet);
+void mysql_stmt_free(THD *thd, char *packet);
 void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
 int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
 			List<Item> &values, ulong counter);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e1cf553b5a5..f9d172d8513 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -51,7 +51,7 @@
 #define TRANS_MEM_ROOT_BLOCK_SIZE 4096
 #define TRANS_MEM_ROOT_PREALLOC   4096
 
-extern int yyparse(void);
+extern int yyparse(void *thd);
 extern "C" pthread_mutex_t THR_LOCK_keycache;
 #ifdef SOLARIS
 extern "C" int gethostname(char *name, int namelen);
@@ -74,7 +74,7 @@ const char *command_name[]={
   "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
   "Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
   "Binlog Dump","Table Dump",  "Connect Out", "Register Slave",
-  "Prepare", "Prepare Execute", "Long Data"
+  "Prepare", "Prepare Execute", "Long Data", "Close stmt"
 };
 
 static char empty_c_string[1]= {0};		// Used for not defined 'db'
@@ -1004,6 +1004,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
     mysql_stmt_prepare(thd, packet, packet_length);
     break;
   }
+  case COM_CLOSE_STMT:
+  {
+    mysql_stmt_free(thd, packet);
+    break;
+  }
   case COM_QUERY:
   {
     if (alloc_query(thd, packet, packet_length))
@@ -2953,7 +2958,7 @@ mysql_parse(THD *thd, char *inBuf, uint length)
   if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
   {
     LEX *lex=lex_start(thd, (uchar*) inBuf, length);
-    if (!yyparse() && ! thd->fatal_error)
+    if (!yyparse((void *)thd) && ! thd->fatal_error)
     {
       if (mqh_used && thd->user_connect &&
 	  check_mqh(thd, lex->sql_command))
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index a3a1f93a829..f86add6c389 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -20,32 +20,47 @@ This file contains the implementation of prepare and executes.
 
 Prepare:
 
-  - Server gets the query from client with command 'COM_PREPARE'
+  - Server gets the query from client with command 'COM_PREPARE'; 
+    in the following format:
+    [COM_PREPARE:1] [query]
   - Parse the query and recognize any parameter markers '?' and 
-    store its information list lex->param_list
+    store its information list in lex->param_list
+  - Allocate a new statement for this prepare; and keep this in 
+    'thd->prepared_statements' pool.
   - Without executing the query, return back to client the total 
     number of parameters along with result-set metadata information
-    (if any)
+    (if any) in the following format:
+    [STMT_ID:4][Columns:2][Param_count:2][Columns meta info][Params meta info]
      
 Prepare-execute:
 
   - Server gets the command 'COM_EXECUTE' to execute the 
     previously prepared query. If there is any param markers; then client
     will send the data in the following format:    
-    [null_bits][types_specified(0/1)][[length][data]][[length][data] .. [length][data]. 
+    [COM_EXECUTE:1]
+    [STMT_ID:4]
+    [NULL_BITS:(param_count+7)/8)]
+    [TYPES_SUPPLIED_BY_CLIENT(0/1):1]
+    [[length]data]
+    [[length]data] .. [[length]data]. 
+    (Note: Except for string/binary types; all other types will not be 
+    supplied with length field)
   - Replace the param items with this new data. If it is a first execute 
     or types altered by client; then setup the conversion routines.
   - Execute the query without re-parsing and send back the results 
     to client
 
 Long data handling:
+
   - Server gets the long data in pieces with command type 'COM_LONG_DATA'.
   - The packet recieved will have the format as:
-    [COM_LONG_DATA:1][parameter_number:2][type:2][data]
+    [COM_LONG_DATA:1][STMT_ID:4][parameter_number:2][type:2][data]
   - Checks if the type is specified by client, and if yes reads the type, 
     and stores the data in that format.
   - It's up to the client to check for read data ended. The server doesn't
-    care.
+    care; and also server doesn't notify to the client that it got the 
+    data or not; if there is any error; then during execute; the error 
+    will be returned
 
 ***********************************************************************/
 
@@ -56,7 +71,7 @@ Long data handling:
 
 #define IS_PARAM_NULL(pos, param_no) pos[param_no/8] & (1 << param_no & 7)
 
-extern int yyparse(void);
+extern int yyparse(void *thd);
 
 /*
   Find prepared statement in thd
@@ -238,9 +253,9 @@ static void setup_param_str(Item_param *param, uchar **pos)
   *pos+=len;        
 }
 
-static void setup_param_functions(Item_param *param, uchar read_pos)
+static void setup_param_functions(Item_param *param, uchar param_type)
 {
-  switch (read_pos) {
+  switch (param_type) {
   case FIELD_TYPE_TINY:
     param->setup_param_func= setup_param_tiny;
     param->item_result_type = INT_RESULT;
@@ -286,7 +301,6 @@ static bool setup_params_data(PREP_STMT *stmt)
 
   uchar *pos=(uchar*) thd->net.read_pos+1+MYSQL_STMT_HEADER; //skip header
   uchar *read_pos= pos+(stmt->param_count+7) / 8; //skip null bits   
-  ulong param_no;
 
   if (*read_pos++) //types supplied / first execute
   {              
@@ -304,7 +318,7 @@ static bool setup_params_data(PREP_STMT *stmt)
     }
     param_iterator.rewind();
   }    
-  param_no= 0;
+  ulong param_no= 0;
   while ((param= (Item_param *)param_iterator++))
   {
     if (!param->long_data_supplied)
@@ -319,7 +333,6 @@ static bool setup_params_data(PREP_STMT *stmt)
   DBUG_RETURN(0);
 }
 
-
 /*
   Validates insert fields                                    
 */
@@ -473,7 +486,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
   List<Item>  all_fields(fields);
   DBUG_ENTER("mysql_test_select_fields");
 
-  if (!(table = open_ltable(thd,tables,tables->lock_type)))
+  if (!(table = open_ltable(thd,tables,TL_READ)))
     DBUG_RETURN(1);
   
   thd->used_tables=0;	// Updated by setup_fields
@@ -605,7 +618,7 @@ static bool parse_prepare_query(PREP_STMT *stmt,
 
   LEX *lex=lex_start(thd, (uchar*) packet, length);
   lex->safe_to_cache_query= 0;
-  if (!yyparse() && !thd->fatal_error) 
+  if (!yyparse((void *)thd) && !thd->fatal_error) 
     error= send_prepare_results(stmt);
   lex_end(lex);
   DBUG_RETURN(error);
@@ -627,8 +640,8 @@ static bool init_param_items(THD *thd, PREP_STMT *stmt)
   {
     DBUG_PRINT("info",("param: %lx", to));
   }
-  return 0;
 #endif
+  return 0;
 }
 
 /*
@@ -671,7 +684,6 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
   stmt.mem_root= thd->mem_root;  
   tree_insert(&thd->prepared_statements, (void *)&stmt, 0, (void *)0);
   thd->mem_root= thd_root; // restore main mem_root
-  thd->last_prepared_stmt= &stmt;
   DBUG_RETURN(0);
 
 err:
@@ -722,7 +734,6 @@ void mysql_stmt_execute(THD *thd, char *packet)
     have re-check on setup_* and other things ..
   */  
   mysql_execute_command(stmt->thd);
-  thd->last_prepared_stmt= stmt;
 
   if (!(specialflag & SPECIAL_NO_PRIOR))
     my_pthread_setprio(pthread_self(), WAIT_PRIOR);
@@ -775,11 +786,11 @@ void mysql_stmt_reset(THD *thd, char *packet)
   Delete a prepared statement from memory
 */
 
-void mysql_stmt_close(THD *thd, char *packet)
+void mysql_stmt_free(THD *thd, char *packet)
 {
   ulong stmt_id= uint4korr(packet);
   PREP_STMT *stmt;
-  DBUG_ENTER("mysql_stmt_close");
+  DBUG_ENTER("mysql_stmt_free");
 
   if (!(stmt=find_prepared_statement(thd, stmt_id, "close")))
   {
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 187ba63e92f..71668adf7e2 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -17,10 +17,16 @@
 /* sql_yacc.yy */
 
 %{
+/* Pass thd as an arg to yyparse(). The type will be void*, so it
+** must be  cast to (THD*) when used. Use the YYTHD macro for this.
+*/
+#define YYPARSE_PARAM yythd
+#define YYTHD ((THD *)yythd)
+
 #define MYSQL_YACC
 #define YYINITDEPTH 100
 #define YYMAXDEPTH 3200				/* Because of 64K stack */
-#define Lex current_lex
+#define Lex (&(YYTHD->lex))
 #define Select Lex->current_select
 #include "mysql_priv.h"
 #include "slave.h"
@@ -35,9 +41,9 @@ int yylex(void *yylval);
 
 #define yyoverflow(A,B,C,D,E,F) if (my_yyoverflow((B),(D),(int*) (F))) { yyerror((char*) (A)); return 2; }
 
-inline Item *or_or_concat(Item* A, Item* B)
+inline Item *or_or_concat(THD *thd, Item* A, Item* B)
 {
-  return (current_thd->sql_mode & MODE_PIPES_AS_CONCAT ?
+  return (thd->sql_mode & MODE_PIPES_AS_CONCAT ?
           (Item*) new Item_func_concat(A,B) : (Item*) new Item_cond_or(A,B));
 }
 
@@ -661,11 +667,11 @@ END_OF_INPUT
 query:
 	END_OF_INPUT
 	{
-	   THD *thd=current_thd;
+	   THD *thd= YYTHD;
 	   if (!thd->bootstrap &&
 	      (!(thd->lex.select_lex.options & OPTION_FOUND_COMMENT)))
 	   {
-	     send_error(current_thd,ER_EMPTY_QUERY);
+	     send_error(thd,ER_EMPTY_QUERY);
 	     YYABORT;
  	   }
 	   else
@@ -791,7 +797,7 @@ master_def:
 create:
 	CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident
 	{
-	  THD *thd=current_thd;
+	  THD *thd= YYTHD;
 	  LEX *lex=Lex;
 	  lex->sql_command= SQLCOM_CREATE_TABLE;
 	  if (!lex->select_lex.add_table_to_list($5,
@@ -1075,7 +1081,7 @@ type:
 	| TIME_SYM			{ $$=FIELD_TYPE_TIME; }
 	| TIMESTAMP
 	  {
-	    if (current_thd->sql_mode & MODE_SAPDB)
+	    if (YYTHD->sql_mode & MODE_SAPDB)
 	      $$=FIELD_TYPE_DATETIME;
 	    else
 	      $$=FIELD_TYPE_TIMESTAMP;	
@@ -1146,7 +1152,7 @@ int_type:
 	| BIGINT	{ $$=FIELD_TYPE_LONGLONG; };
 
 real_type:
-	REAL		{ $$= current_thd->sql_mode & MODE_REAL_AS_FLOAT ?
+	REAL		{ $$= YYTHD->sql_mode & MODE_REAL_AS_FLOAT ?
 			      FIELD_TYPE_FLOAT : FIELD_TYPE_DOUBLE; }
 	| DOUBLE_SYM	{ $$=FIELD_TYPE_DOUBLE; }
 	| DOUBLE_SYM PRECISION { $$=FIELD_TYPE_DOUBLE; };
@@ -1211,7 +1217,7 @@ charset_name:
 	{ 
 	  if (!($$=get_charset_by_name("binary",MYF(0))))
 	  {
-	    net_printf(current_thd,ER_UNKNOWN_CHARACTER_SET,"binary");
+	    net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,"binary");
 	    YYABORT;
 	  }
 	}
@@ -1219,7 +1225,7 @@ charset_name:
 	{ 
 	  if (!($$=get_charset_by_name($1.str,MYF(0))))
 	  {
-	    net_printf(current_thd,ER_UNKNOWN_CHARACTER_SET,$1.str);
+	    net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,$1.str);
 	    YYABORT;
 	  }
 	};
@@ -1247,6 +1253,7 @@ opt_binary:
 opt_primary:
 	/* empty */
 	| PRIMARY_SYM
+	;
 
 references:
 	REFERENCES table_ident
@@ -1347,7 +1354,7 @@ string_list:
 alter:
 	ALTER opt_ignore TABLE_SYM table_ident
 	{
-	  THD *thd=current_thd;
+	  THD *thd= YYTHD;
 	  LEX *lex=&thd->lex;
 	  lex->sql_command = SQLCOM_ALTER_TABLE;
 	  lex->name=0;
@@ -1776,7 +1783,7 @@ expr_expr:
 	  { $$= new Item_func_between($1,$3,$5); }
 	| expr NOT BETWEEN_SYM no_and_expr AND expr
 	  { $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
-	| expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); }
+	| expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
 	| expr OR expr		{ $$= new Item_cond_or($1,$3); }
         | expr XOR expr		{ $$= new Item_cond_xor($1,$3); }
 	| expr AND expr		{ $$= new Item_cond_and($1,$3); }
@@ -1818,7 +1825,7 @@ no_in_expr:
 	  { $$= new Item_func_between($1,$3,$5); }
 	| no_in_expr NOT BETWEEN_SYM no_and_expr AND expr
 	  { $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
-	| no_in_expr OR_OR_CONCAT expr	{ $$= or_or_concat($1,$3); }
+	| no_in_expr OR_OR_CONCAT expr	{ $$= or_or_concat(YYTHD, $1,$3); }
 	| no_in_expr OR expr		{ $$= new Item_cond_or($1,$3); }
         | no_in_expr XOR expr		{ $$= new Item_cond_xor($1,$3); }
 	| no_in_expr AND expr		{ $$= new Item_cond_and($1,$3); }
@@ -1863,7 +1870,7 @@ no_and_expr:
 	  { $$= new Item_func_between($1,$3,$5); }
 	| no_and_expr NOT BETWEEN_SYM no_and_expr AND expr
 	  { $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
-	| no_and_expr OR_OR_CONCAT expr	{ $$= or_or_concat($1,$3); }
+	| no_and_expr OR_OR_CONCAT expr	{ $$= or_or_concat(YYTHD, $1,$3); }
 	| no_and_expr OR expr		{ $$= new Item_cond_or($1,$3); }
         | no_and_expr XOR expr		{ $$= new Item_cond_xor($1,$3); }
 	| no_and_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); }
@@ -3015,7 +3022,7 @@ update_list:
 	  };
 
 opt_low_priority:
-	/* empty */	{ $$= current_thd->update_lock_default; }
+	/* empty */	{ $$= YYTHD->update_lock_default; }
 	| LOW_PRIORITY	{ $$= TL_WRITE_LOW_PRIORITY; };
 
 /* Delete rows from a table */
@@ -3199,7 +3206,7 @@ show_param:
 	  { Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;}
 	| opt_var_type VARIABLES wild
 	  {
-	    THD *thd= current_thd;
+	    THD *thd= YYTHD;
 	    thd->lex.sql_command= SQLCOM_SHOW_VARIABLES;
 	    thd->lex.option_type= (enum_var_type) $1;
 	  }
@@ -3410,7 +3417,7 @@ opt_local:
 	| LOCAL_SYM	{ $$=1;};
 
 load_data_lock:
-	/* empty */	{ $$= current_thd->update_lock_default; }
+	/* empty */	{ $$= YYTHD->update_lock_default; }
 	| CONCURRENT	{ $$= TL_WRITE_CONCURRENT_INSERT ; }
 	| LOW_PRIORITY	{ $$= TL_WRITE_LOW_PRIORITY; };
 
@@ -3459,13 +3466,13 @@ opt_ignore_lines:
 /* Common definitions */
 
 text_literal:
-	TEXT_STRING { $$ = new Item_string($1.str,$1.length,current_thd->thd_charset); }
+	TEXT_STRING { $$ = new Item_string($1.str,$1.length,YYTHD->thd_charset); }
 	| UNDERSCORE_CHARSET TEXT_STRING { $$ = new Item_string($2.str,$2.length,Lex->charset); }
 	| text_literal TEXT_STRING
 	{ ((Item_string*) $1)->append($2.str,$2.length); };
 
 text_string:
-	TEXT_STRING	{ $$=  new String($1.str,$1.length,current_thd->thd_charset); }
+	TEXT_STRING	{ $$=  new String($1.str,$1.length,YYTHD->thd_charset); }
 	| HEX_NUM
 	  {
 	    Item *tmp = new Item_varbinary($1.str,$1.length);
@@ -3475,7 +3482,7 @@ param_marker:
         '?' 
         {
 	  LEX *lex=Lex;
-          if (current_thd->prepare_command)
+          if (YYTHD->prepare_command)
           {     
             lex->param_list.push_back($$=new Item_param());      
             lex->param_count++;
@@ -3511,7 +3518,7 @@ insert_ident:
 table_wild:
 	ident '.' '*' { $$ = new Item_field(NullS,$1.str,"*"); }
 	| ident '.' ident '.' '*'
-	{ $$ = new Item_field((current_thd->client_capabilities &
+	{ $$ = new Item_field((YYTHD->client_capabilities &
    CLIENT_NO_SCHEMA ? NullS : $1.str),$3.str,"*"); };
 
 order_ident:
@@ -3536,7 +3543,7 @@ simple_ident:
 	| ident '.' ident '.' ident
 	{
 	  SELECT_LEX_NODE *sel=Select;
-	  $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str);
+	  $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field((YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str);
 	};
 
 
@@ -3819,7 +3826,7 @@ option_value:
 	}
 	| PASSWORD equal text_or_password
 	  {
-	    THD *thd=current_thd;
+	    THD *thd=YYTHD;
 	    LEX_USER *user;
 	    if (!(user=(LEX_USER*) sql_alloc(sizeof(LEX_USER))))
 	      YYABORT;
@@ -3901,7 +3908,7 @@ table_lock:
 
 lock_option:
 	READ_SYM	{ $$=TL_READ_NO_INSERT; }
-	| WRITE_SYM     { $$=current_thd->update_lock_default; }
+	| WRITE_SYM     { $$=YYTHD->update_lock_default; }
 	| LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; }
 	| READ_SYM LOCAL_SYM { $$= TL_READ; }
         ;
@@ -4338,7 +4345,7 @@ singleval_subselect:
 singleval_subselect_init:
 	select_init
 	{
-	  $$= new Item_singleval_subselect(current_thd,
+	  $$= new Item_singleval_subselect(YYTHD,
 					   Lex->current_select->master_unit()->
                                              first_select());
 	};
@@ -4353,7 +4360,7 @@ exists_subselect:
 exists_subselect_init:
 	select_init
 	{
-	  $$= new Item_exists_subselect(current_thd,
+	  $$= new Item_exists_subselect(YYTHD,
 					Lex->current_select->master_unit()->
 					  first_select());
 	};