diff --git a/.bzrignore b/.bzrignore
index faedfa2b48e642004e4479f4f2abc7e9ece21a82..d19b005a03e9b3c1a37e9ace93901ea7a4a8c6fe 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1052,3 +1052,4 @@ ndb/tools/ndb_drop_index.dsp
 ndb/tools/ndb_show_tables.dsp
 ndb/tools/ndb_select_all.dsp
 ndb/tools/ndb_select_count.dsp
+support-files/ndb-config-2-node.ini
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c
index 186f3be2f31a614d2ef88f4bdfc58a1fc2604774..a73dd8b9dd9c047e7951398f1521996151e0a682 100644
--- a/innobase/dict/dict0dict.c
+++ b/innobase/dict/dict0dict.c
@@ -2671,7 +2671,8 @@ dict_strip_comments(
 			/* Starting quote: remember the quote character. */
 			quote = *sptr;
 		} else if (*sptr == '#'
-		    || (0 == memcmp("-- ", sptr, 3))) {
+                           || (sptr[0] == '-' && sptr[1] == '-' &&
+                               sptr[2] == ' ')) {
 			for (;;) {
 				/* In Unix a newline is 0x0A while in Windows
 				it is 0x0D followed by 0x0A */
diff --git a/mysql-test/r/select_found.result b/mysql-test/r/select_found.result
index 665277f68f2653cb397e400008ec84dfc8e694e8..39a949ef86bb2583c7ad6e65296d3b8b10336432 100644
--- a/mysql-test/r/select_found.result
+++ b/mysql-test/r/select_found.result
@@ -254,3 +254,4 @@ a
 SELECT FOUND_ROWS();
 FOUND_ROWS()
 1
+DROP TABLE t1;
diff --git a/mysql-test/r/type_set.result b/mysql-test/r/type_set.result
index 9c82f59fc69005b19ab76add07bf8e8b56f834bb..5aedefda2839972f45711be35dd3b87563d399f5 100644
--- a/mysql-test/r/type_set.result
+++ b/mysql-test/r/type_set.result
@@ -29,6 +29,12 @@ a
 A
 a,A
 a,A
+select s from t1 order by concat(s);
+s
+A
+a
+a,A
+a,A
 drop table t1;
 CREATE TABLE t1 (c set('ae','oe','ue','ss') collate latin1_german2_ci);
 INSERT INTO t1 VALUES ('ä'),('ö'),('ü'),('ß');
@@ -47,4 +53,16 @@ ss
 ss
 ae,oe,ue,ss
 ae,oe,ue,ss
+SELECT c FROM t1 ORDER BY concat(c);
+c
+ae
+ae
+ae,oe,ue,ss
+ae,oe,ue,ss
+oe
+oe
+ss
+ss
+ue
+ue
 DROP TABLE t1;
diff --git a/mysql-test/t/select_found.test b/mysql-test/t/select_found.test
index d31d7d0b02e601b33af0ca8141e081b499d59638..5bd068eb0e6f5772d09c6a8cdbc4d9274edb6694 100644
--- a/mysql-test/t/select_found.test
+++ b/mysql-test/t/select_found.test
@@ -175,3 +175,4 @@ CREATE TABLE t1 (a int, b int);
 INSERT INTO t1 VALUES (1,2), (1,3), (1,4), (1,5);
 SELECT SQL_CALC_FOUND_ROWS DISTINCT 'a' FROM t1 GROUP BY b LIMIT 2;
 SELECT FOUND_ROWS();
+DROP TABLE t1;
diff --git a/mysql-test/t/type_set.test b/mysql-test/t/type_set.test
index e4aeecb2c796318814a3081984d9dd7aefdb52d0..b6410a9ea3d47562b7fe86b3dc7e65399b0f6010 100644
--- a/mysql-test/t/type_set.test
+++ b/mysql-test/t/type_set.test
@@ -23,6 +23,7 @@ create table t1 (s set ('a','A') character set latin1 collate latin1_bin);
 show create table t1;
 insert into t1 values ('a'),('a,A'),('A,a'),('A');
 select s from t1 order by s;
+select s from t1 order by concat(s);
 drop table t1;
 
 #
@@ -34,4 +35,5 @@ INSERT INTO t1 VALUES ('ae'),('oe'),('ue'),('ss');
 INSERT INTO t1 VALUES ('ä,ö,ü,ß');
 INSERT INTO t1 VALUES ('ae,oe,ue,ss');
 SELECT c FROM t1 ORDER BY c;
+SELECT c FROM t1 ORDER BY concat(c);
 DROP TABLE t1;
diff --git a/mysys/my_init.c b/mysys/my_init.c
index c32fcfe6a09fb77b976231abbd31df6ce4215341..bee485c3bedab3441b26f64e6343d2a8022fbd84 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -145,6 +145,10 @@ void my_end(int infoflag)
   {
 #ifdef HAVE_GETRUSAGE
     struct rusage rus;
+#ifdef HAVE_purify
+    /* Purify assumes that rus is uninitialized after getrusage call */
+    bzero((char*) &rus, sizeof(rus));
+#endif
     if (!getrusage(RUSAGE_SELF, &rus))
       fprintf(info_file,"\n\
 User time %.2f, System time %.2f\n\
diff --git a/sql/field.h b/sql/field.h
index fd0f2f9c2f11ca2494419966569841730f1dda33..b5d885049398c6c99a1ed0bf15b7c308ff04ad86 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -277,6 +277,7 @@ class Field
   virtual bool get_date(TIME *ltime,uint fuzzydate);
   virtual bool get_time(TIME *ltime);
   virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
+  virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
   virtual bool has_charset(void) const { return FALSE; }
   virtual void set_charset(CHARSET_INFO *charset) { }
   bool set_warning(const unsigned int level, const unsigned int code, 
@@ -1152,6 +1153,8 @@ class Field_enum :public Field_str {
   bool optimize_range(uint idx, uint part) { return 0; }
   bool eq_def(Field *field);
   bool has_charset(void) const { return TRUE; }
+  /* enum and set are sorted as integers */
+  CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
   field_cast_enum field_cast_type() { return FIELD_CAST_ENUM; }
 };
 
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 24088210f1a5de701b58c133db1d9a9e7c532025..76ce9ac4ce2b911eda1f42e3e30d3ce133811ea4 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1127,7 +1127,7 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
       else
       {
 	sortorder->length=sortorder->field->pack_length();
-	if (use_strnxfrm((cs=sortorder->field->charset())))
+	if (use_strnxfrm((cs=sortorder->field->sort_charset())))
 	{
 	  sortorder->need_strxnfrm= 1;
 	  *multi_byte_charset= 1;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index aff11ac7b25d60291e1acf1d3ad62a4738431eb0..690da1be18c242e82cc8a116b7065bbd5afbd1f1 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -265,7 +265,7 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
       comparators= 0;
       return 1;
     }
-    if (!(comparators= (Arg_comparator *) sql_alloc(sizeof(Arg_comparator)*n)))
+    if (!(comparators= new Arg_comparator[n]))
       return 1;
     for (uint i=0; i < n; i++)
     {
@@ -1528,6 +1528,12 @@ in_row::in_row(uint elements, Item * item)
   size= sizeof(cmp_item_row);
   compare= (qsort2_cmp) cmp_row;
   tmp.store_value(item);
+  /*
+    We need to reset these as otherwise we will call sort() with
+    uninitialized (even if not used) elements
+  */
+  used_count= elements;
+  collation= 0;
 }
 
 in_row::~in_row()
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 1591b205d46d46f30ff1a6f1a1eca0bcaeb25d23..f1b1d8a7d86654990d342cb0efa1ee77f80e1fc0 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -530,6 +530,7 @@ extern "C" pthread_handler_decl(handle_slave,arg);
 static ulong find_bit_type(const char *x, TYPELIB *bit_lib);
 static void clean_up(bool print_message);
 static void clean_up_mutexes(void);
+static void wait_for_signal_thread_to_end(void);
 static int test_if_case_insensitive(const char *dir_name);
 static void create_pid_file();
 
@@ -918,6 +919,7 @@ extern "C" void unireg_abort(int exit_code)
     sql_print_error("Aborting\n");
   clean_up(exit_code || !opt_bootstrap); /* purecov: inspected */
   DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
+  wait_for_signal_thread_to_end();
   clean_up_mutexes();
   my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
   exit(exit_code); /* purecov: inspected */
@@ -1023,6 +1025,29 @@ void clean_up(bool print_message)
 } /* clean_up */
 
 
+/*
+  This is mainly needed when running with purify, but it's still nice to
+  know that all child threads have died when mysqld exits
+*/
+
+static void wait_for_signal_thread_to_end()
+{
+#ifndef __NETWARE__
+  uint i;
+  /*
+    Wait up to 10 seconds for signal thread to die. We use this mainly to
+    avoid getting warnings that my_thread_end has not been called
+  */
+  for (i= 0 ; i < 100 && signal_thread_in_use; i++)
+  {
+    if (pthread_kill(signal_thread, MYSQL_KILL_SIGNAL))
+      break;
+    my_sleep(100);				// Give it time to die
+  }
+#endif
+}
+
+
 static void clean_up_mutexes()
 {
   (void) pthread_mutex_destroy(&LOCK_mysql_create_db);
@@ -2117,6 +2142,7 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
       while ((error=my_sigwait(&set,&sig)) == EINTR) ;
     if (cleanup_done)
     {
+      DBUG_PRINT("quit",("signal_handler: calling my_thread_end()"));
       my_thread_end();
       signal_thread_in_use= 0;
       pthread_exit(0);				// Safety
@@ -3111,21 +3137,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
       CloseHandle(hEventShutdown);
   }
 #endif
-#ifndef __NETWARE__
-  {
-    uint i;
-    /*
-      Wait up to 10 seconds for signal thread to die. We use this mainly to
-      avoid getting warnings that my_thread_end has not been called
-    */
-    for (i= 0 ; i < 100 && signal_thread_in_use; i++)
-    {
-      if (pthread_kill(signal_thread, MYSQL_KILL_SIGNAL))
-	break;
-      my_sleep(100);				// Give it time to die
-    }
-  }
-#endif
+  wait_for_signal_thread_to_end();
   clean_up_mutexes();
   my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
  
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 844e5e7dac253bf2d8116de79589d0da70a06e6f..1f190a450dec4f2f934e756044e1692cb67e93aa 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -688,7 +688,8 @@ class delayed_insert :public ilink {
     thd.current_tablenr=0;
     thd.version=refresh_version;
     thd.command=COM_DELAYED_INSERT;
-    thd.lex->current_select= 0; /* for my_message_sql */
+    thd.lex->current_select= 0; 		// for my_message_sql
+    thd.lex->sql_command= SQLCOM_INSERT;        // For innodb::store_lock()
 
     bzero((char*) &thd.net, sizeof(thd.net));		// Safety
     bzero((char*) &table_list, sizeof(table_list));	// Safety
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 3e2f6a3f2b57fe8249ea571ca0ba5918d489f6bf..f48ff42bbf8944c7c9ec9110255af7462a7af028 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -125,27 +125,46 @@ enum tablespace_op_type
 /* 
   The state of the lex parsing for selects 
    
+   master and slaves are pointers to select_lex.
+   master is pointer to upper level node.
+   slave is pointer to lower level node
+   select_lex is a SELECT without union
+   unit is container of either
+     - One SELECT
+     - UNION of selects
+   select_lex and unit are both inherited form select_lex_node
+   neighbors are two select_lex or units on the same level
+
    All select describing structures linked with following pointers:
-   - list of neighbors (next/prev) (prev of first element point to slave 
+   - list of neighbors (next/prev) (prev of first element point to slave
      pointer of upper structure)
-     - one level units for unit (union) structure
-     - member of one union(unit) for ordinary select_lex
-   - pointer to master
-     - outer select_lex for unit (union)
-     - unit structure for ordinary select_lex
-   - pointer to slave
-     - first list element of select_lex belonged to this unit for unit
-     - first unit in list of units that belong to this select_lex (as
-       subselects or derived tables) for ordinary select_lex
-   - list of all select_lex (for group operation like correcting list of opened
-     tables)
-   - if unit contain several selects (union) then it have special 
-     select_lex called fake_select_lex. It used for storing global parameters
-     and executing union. subqueries of global ORDER BY clause will be
-     attached to this fake_select_lex, which will allow them correctly
-     resolve fields of 'upper' union and other more outer selects. 
-
-   for example for following query:
+     - For select this is a list of UNION's (or one element list)
+     - For units this is a list of sub queries for the upper level select
+
+   - pointer to master (master), which is
+     If this is a unit
+       - pointer to outer select_lex
+     If this is a select_lex
+       - pointer to outer unit structure for select
+
+   - pointer to slave (slave), which is either:
+     If this is a unit:
+       - first SELECT that belong to this unit
+     If this is a select_lex
+       - first unit that belong to this SELECT (subquries or derived tables)
+
+   - list of all select_lex (link_next/link_prev)
+     This is to be used for things like derived tables creation, where we
+     go through this list and create the derived tables.
+
+   If unit contain several selects (UNION now, INTERSECT etc later)
+   then it have special select_lex called fake_select_lex. It used for
+   storing global parameters (like ORDER BY, LIMIT) and executing union.
+   Subqueries used in global ORDER BY clause will be attached to this
+   fake_select_lex, which will allow them correctly resolve fields of
+   'upper' UNION and outer selects.
+
+   For example for following query:
 
    select *
      from table1
@@ -163,6 +182,11 @@ enum tablespace_op_type
 
    we will have following structure:
 
+   select1: (select * from table1 ...)
+   select2: (select * from table2 ...)
+   select3: (select * from table3)
+   select1.1.1: (select * from table1_1_1)
+   ...
 
      main unit
      fake0
@@ -185,7 +209,12 @@ enum tablespace_op_type
 
 
    relation in main unit will be following:
-                          
+   (bigger picture for:
+      main unit
+      fake0
+      select1 select2 select3
+   in the above picture)
+
          main unit
          |^^^^|fake_select_lex
          |||||+--------------------------------------------+
@@ -382,7 +411,7 @@ class st_select_lex_unit: public st_select_lex_node {
 typedef class st_select_lex_unit SELECT_LEX_UNIT;
 
 /*
-  SELECT_LEX - store information of parsed SELECT_LEX statment
+  SELECT_LEX - store information of parsed SELECT statment
 */
 class st_select_lex: public st_select_lex_node
 {
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index fd165ad1fa5c9daa6cea1d0731a3ad08f2656387..d02bb5ff0a35e10055867fb8fee58a8921b05156 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -246,7 +246,7 @@ bool log_in_use(const char* log_name)
     if ((linfo = tmp->current_linfo))
     {
       pthread_mutex_lock(&linfo->lock);
-      result = !memcmp(log_name, linfo->log_file_name, log_name_len);
+      result = !bcmp(log_name, linfo->log_file_name, log_name_len);
       pthread_mutex_unlock(&linfo->lock);
       if (result)
 	break;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 05314097ca388706d9a62bf3f12563b83e4a6a6d..a210fbbbe024cbe8173b573bebdb65eb5071efb0 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -7622,8 +7622,8 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
 {
   byte *key_buffer, *key_pos, *record=table->record[0];
   int error;
-  handler *file=table->file;
-  ulong extra_length=ALIGN_SIZE(key_length)-key_length;
+  handler *file= table->file;
+  ulong extra_length= ALIGN_SIZE(key_length)-key_length;
   uint *field_lengths,*field_length;
   HASH hash;
   DBUG_ENTER("remove_dup_with_hash_index");
@@ -7637,22 +7637,34 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
 		       NullS))
     DBUG_RETURN(1);
 
+  {
+    Field **ptr;
+    ulong total_length= 0;
+    for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++)
+    {
+      uint length= (*ptr)->pack_length();
+      (*field_length++)= length;
+      total_length+= length;
+    }
+    DBUG_PRINT("info",("field_count: %u  key_length: %lu  total_length: %lu",
+                       field_count, key_length, total_length));
+    DBUG_ASSERT(total_length <= key_length);
+    key_length= total_length;
+    extra_length= ALIGN_SIZE(key_length)-key_length;
+  }
+
   if (hash_init(&hash, &my_charset_bin, (uint) file->records, 0, 
-		key_length,(hash_get_key) 0, 0, 0))
+		key_length, (hash_get_key) 0, 0, 0))
   {
     my_free((char*) key_buffer,MYF(0));
     DBUG_RETURN(1);
   }
-  {
-    Field **ptr;
-    for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++)
-      (*field_length++)= (*ptr)->pack_length();
-  }
 
   file->ha_rnd_init(1);
   key_pos=key_buffer;
   for (;;)
   {
+    byte *org_key_pos;
     if (thd->killed)
     {
       my_error(ER_SERVER_SHUTDOWN,MYF(0));
@@ -7675,6 +7687,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
     }
 
     /* copy fields to key buffer */
+    org_key_pos= key_pos;
     field_length=field_lengths;
     for (Field **ptr= first_field ; *ptr ; ptr++)
     {
@@ -7682,14 +7695,14 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
       key_pos+= *field_length++;
     }
     /* Check if it exists before */
-    if (hash_search(&hash,key_pos-key_length,key_length))
+    if (hash_search(&hash, org_key_pos, key_length))
     {
       /* Duplicated found ; Remove the row */
       if ((error=file->delete_row(record)))
 	goto err;
     }
     else
-      (void) my_hash_insert(&hash, key_pos-key_length);
+      (void) my_hash_insert(&hash, org_key_pos);
     key_pos+=extra_length;
   }
   my_free((char*) key_buffer,MYF(0));
diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c
index c2a6aa4e17fd502b073ea3f7e48ca57e800022e3..080e0b780b770be8be2dc213c9892e322c6dceff 100644
--- a/strings/ctype-simple.c
+++ b/strings/ctype-simple.c
@@ -518,7 +518,6 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)),
   register unsigned int cutlim;
   register ulonglong i;
   register const char *s, *e;
-  register unsigned char c;
   const char *save;
   int overflow;
 
@@ -581,8 +580,9 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)),
 
   overflow = 0;
   i = 0;
-  for (c = *s; s != e; c = *++s)
+  for ( ; s != e; s++)
   {
+    register unsigned char c= *s;
     if (c>='0' && c<='9')
       c -= '0';
     else if (c>='A' && c<='Z')
@@ -641,7 +641,6 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs,
   register unsigned int cutlim;
   register ulonglong i;
   register const char *s, *e;
-  register unsigned char c;
   const char *save;
   int overflow;
 
@@ -704,8 +703,10 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs,
 
   overflow = 0;
   i = 0;
-  for (c = *s; s != e; c = *++s)
+  for ( ; s != e; s++)
   {
+    register unsigned char c= *s;
+
     if (c>='0' && c<='9')
       c -= '0';
     else if (c>='A' && c<='Z')