List:Commits« Previous MessageNext Message »
From:igor Date:December 12 2005 8:29am
Subject:bk commit into 5.1 tree (igor:1.1971)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of igor. When igor does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.1971 05/12/12 00:29:36 igor@stripped +35 -0
  Merge rurik.mysql.com:/home/igor/dev/mysql-5.0-2
  into  rurik.mysql.com:/home/igor/dev/mysql-5.1-0

  sql/sql_select.cc
    1.373 05/12/12 00:29:29 igor@stripped +6 -7
    Manual merge

  sql/sql_base.cc
    1.285 05/12/12 00:29:29 igor@stripped +1 -1
    Manual merge

  sql/sp_head.cc
    1.205 05/12/12 00:29:29 igor@stripped +2 -14
    Manual merge

  sql/field.cc
    1.295 05/12/12 00:29:29 igor@stripped +2 -1
    Manual merge

  tests/mysql_client_test.c
    1.167 05/12/12 00:11:20 igor@stripped +0 -0
    Auto merged

  sql/sql_yacc.yy
    1.429 05/12/12 00:11:19 igor@stripped +0 -0
    Auto merged

  sql/sql_update.cc
    1.179 05/12/12 00:11:19 igor@stripped +0 -0
    Auto merged

  sql/sql_trigger.cc
    1.37 05/12/12 00:11:19 igor@stripped +0 -0
    Auto merged

  sql/sql_select.h
    1.103 05/12/12 00:11:19 igor@stripped +0 -0
    Auto merged

  sql/sql_prepare.cc
    1.157 05/12/12 00:11:18 igor@stripped +0 -0
    Auto merged

  sql/sql_parse.cc
    1.495 05/12/12 00:11:18 igor@stripped +0 -0
    Auto merged

  sql/sql_lex.h
    1.210 05/12/12 00:11:18 igor@stripped +0 -0
    Auto merged

  sql/sql_lex.cc
    1.169 05/12/12 00:11:18 igor@stripped +0 -0
    Auto merged

  sql/sql_delete.cc
    1.160 05/12/12 00:11:17 igor@stripped +0 -0
    Auto merged

  sql/sql_class.h
    1.275 05/12/12 00:11:17 igor@stripped +0 -0
    Auto merged

  sql/sql_class.cc
    1.224 05/12/12 00:11:17 igor@stripped +0 -0
    Auto merged

  sql/sp_head.h
    1.79 05/12/12 00:11:17 igor@stripped +0 -0
    Auto merged

  sql/sp.cc
    1.99 05/12/12 00:11:17 igor@stripped +0 -0
    Auto merged

  sql/mysql_priv.h
    1.353 05/12/12 00:11:17 igor@stripped +0 -0
    Auto merged

  sql/item_sum.cc
    1.171 05/12/12 00:11:16 igor@stripped +0 -0
    Auto merged

  sql/item_subselect.cc
    1.121 05/12/12 00:11:16 igor@stripped +0 -0
    Auto merged

  sql/item_strfunc.h
    1.104 05/12/12 00:11:16 igor@stripped +0 -0
    Auto merged

  sql/item_strfunc.cc
    1.262 05/12/12 00:11:16 igor@stripped +0 -0
    Auto merged

  sql/item_func.cc
    1.271 05/12/12 00:11:16 igor@stripped +0 -0
    Auto merged

  sql/item_cmpfunc.cc
    1.188 05/12/12 00:11:16 igor@stripped +0 -0
    Auto merged

  sql/item.h
    1.184 05/12/12 00:11:16 igor@stripped +0 -0
    Auto merged

  sql/item.cc
    1.160 05/12/12 00:11:15 igor@stripped +0 -0
    Auto merged

  sql/field.h
    1.173 05/12/12 00:11:15 igor@stripped +0 -0
    Auto merged

  mysql-test/t/view.test
    1.129 05/12/12 00:11:15 igor@stripped +0 -0
    Auto merged

  mysql-test/t/show_check.test
    1.59 05/12/12 00:11:15 igor@stripped +0 -0
    Auto merged

  mysql-test/r/view.result
    1.141 05/12/12 00:11:15 igor@stripped +0 -0
    Auto merged

  mysql-test/r/sp.result
    1.177 05/12/12 00:11:15 igor@stripped +0 -0
    Auto merged

  mysql-test/r/show_check.result
    1.86 05/12/12 00:11:15 igor@stripped +0 -0
    Auto merged

  BitKeeper/deleted/.del-type_newdecimal-big.test
    1.3 05/12/12 00:11:14 igor@stripped +0 -0
    Auto merged

  BitKeeper/deleted/.del-type_newdecimal-big.result
    1.3 05/12/12 00:11:14 igor@stripped +0 -0
    Auto merged

  BitKeeper/deleted/.del-type_newdecimal-big.test
    1.1.1.2 05/12/12 00:11:14 igor@stripped +0 -0
    Merge rename: mysql-test/t/type_newdecimal-big.test -> BitKeeper/deleted/.del-type_newdecimal-big.test

  BitKeeper/deleted/.del-type_newdecimal-big.result
    1.1.1.2 05/12/12 00:11:14 igor@stripped +0 -0
    Merge rename: mysql-test/r/type_newdecimal-big.result -> BitKeeper/deleted/.del-type_newdecimal-big.result

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	igor
# Host:	rurik.mysql.com
# Root:	/home/igor/dev/mysql-5.1-0/RESYNC

--- 1.294/sql/field.cc	2005-12-06 18:22:47 -08:00
+++ 1.295/sql/field.cc	2005-12-12 00:29:29 -08:00
@@ -6804,7 +6804,11 @@
    packlength(blob_pack_length)
 {
   flags|= BLOB_FLAG;
-  share->blob_fields++;
+  if (table)
+  {
+    table->s->blob_fields++;
+    /* TODO: why do not fill table->s->blob_field array here? */
+  }
 }
 
 
@@ -8366,6 +8370,350 @@
               ((decimals & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) |
               (maybe_null ? FIELDFLAG_MAYBE_NULL : 0) |
               (is_unsigned ? 0 : FIELDFLAG_DECIMAL));
+}
+
+
+/*
+  Initialize field definition for create
+
+  SYNOPSIS
+    thd                   Thread handle
+    fld_name              Field name
+    fld_type              Field type
+    fld_length            Field length
+    fld_decimals          Decimal (if any)
+    fld_type_modifier     Additional type information
+    fld_default_value     Field default value (if any)
+    fld_on_update_value   The value of ON UPDATE clause
+    fld_comment           Field comment
+    fld_change            Field change
+    fld_interval_list     Interval list (if any)
+    fld_charset           Field charset
+    fld_geom_type         Field geometry type (if any)
+
+  RETURN
+    FALSE on success
+    TRUE  on error
+*/
+
+bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
+                        char *fld_length, char *fld_decimals,
+                        uint fld_type_modifier, Item *fld_default_value,
+                        Item *fld_on_update_value, LEX_STRING *fld_comment,
+                        char *fld_change, List<String> *fld_interval_list,
+                        CHARSET_INFO *fld_charset, uint fld_geom_type)
+{
+  uint sign_len, allowed_type_modifier= 0;
+  ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
+
+  DBUG_ENTER("create_field::init()");
+  
+  field= 0;
+  field_name= fld_name;
+  def= fld_default_value;
+  flags= fld_type_modifier;
+  unireg_check= (fld_type_modifier & AUTO_INCREMENT_FLAG ?
+                 Field::NEXT_NUMBER : Field::NONE);
+  decimals= fld_decimals ? (uint)atoi(fld_decimals) : 0;
+  if (decimals >= NOT_FIXED_DEC)
+  {
+    my_error(ER_TOO_BIG_SCALE, MYF(0), decimals, fld_name,
+             NOT_FIXED_DEC-1);
+    DBUG_RETURN(TRUE);
+  }
+
+  sql_type= fld_type;
+  length= 0;
+  change= fld_change;
+  interval= 0;
+  pack_length= key_length= 0;
+  charset= fld_charset;
+  geom_type= (Field::geometry_type) fld_geom_type;
+  interval_list.empty();
+
+  comment= *fld_comment;
+  /*
+    Set flag if this field doesn't have a default value
+  */
+  if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) &&
+      (fld_type_modifier & NOT_NULL_FLAG) && fld_type != FIELD_TYPE_TIMESTAMP)
+    flags|= NO_DEFAULT_VALUE_FLAG;
+
+  if (fld_length && !(length= (uint) atoi(fld_length)))
+    fld_length= 0; /* purecov: inspected */
+  sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1;
+
+  switch (fld_type) {
+  case FIELD_TYPE_TINY:
+    if (!fld_length)
+      length= MAX_TINYINT_WIDTH+sign_len;
+    allowed_type_modifier= AUTO_INCREMENT_FLAG;
+    break;
+  case FIELD_TYPE_SHORT:
+    if (!fld_length)
+      length= MAX_SMALLINT_WIDTH+sign_len;
+    allowed_type_modifier= AUTO_INCREMENT_FLAG;
+    break;
+  case FIELD_TYPE_INT24:
+    if (!fld_length)
+      length= MAX_MEDIUMINT_WIDTH+sign_len;
+    allowed_type_modifier= AUTO_INCREMENT_FLAG;
+    break;
+  case FIELD_TYPE_LONG:
+    if (!fld_length)
+      length= MAX_INT_WIDTH+sign_len;
+    allowed_type_modifier= AUTO_INCREMENT_FLAG;
+    break;
+  case FIELD_TYPE_LONGLONG:
+    if (!fld_length)
+      length= MAX_BIGINT_WIDTH;
+    allowed_type_modifier= AUTO_INCREMENT_FLAG;
+    break;
+  case FIELD_TYPE_NULL:
+    break;
+  case FIELD_TYPE_NEWDECIMAL:
+    if (!fld_length && !decimals)
+      length= 10;
+    if (length > DECIMAL_MAX_PRECISION)
+    {
+      my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
+               DECIMAL_MAX_PRECISION);
+      DBUG_RETURN(TRUE);
+    }
+    if (length < decimals)
+    {
+      my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
+      DBUG_RETURN(TRUE);
+    }
+    length=
+      my_decimal_precision_to_length(length, decimals,
+                                     fld_type_modifier & UNSIGNED_FLAG);
+    pack_length=
+      my_decimal_get_binary_size(length, decimals);
+    break;
+  case MYSQL_TYPE_VARCHAR:
+    /*
+      Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
+      if they don't have a default value
+    */
+    max_field_charlength= MAX_FIELD_VARCHARLENGTH;
+    break;
+  case MYSQL_TYPE_STRING:
+    break;
+  case FIELD_TYPE_BLOB:
+  case FIELD_TYPE_TINY_BLOB:
+  case FIELD_TYPE_LONG_BLOB:
+  case FIELD_TYPE_MEDIUM_BLOB:
+  case FIELD_TYPE_GEOMETRY:
+    if (fld_default_value)
+    {
+      /* Allow empty as default value. */
+      String str,*res;
+      res= fld_default_value->val_str(&str);
+      if (res->length())
+      {
+        my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
+                 fld_name); /* purecov: inspected */
+        DBUG_RETURN(TRUE);
+      }
+      def= 0;
+    }
+    flags|= BLOB_FLAG;
+    break;
+  case FIELD_TYPE_YEAR:
+    if (!fld_length || length != 2)
+      length= 4; /* Default length */
+    flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
+    break;
+  case FIELD_TYPE_FLOAT:
+    /* change FLOAT(precision) to FLOAT or DOUBLE */
+    allowed_type_modifier= AUTO_INCREMENT_FLAG;
+    if (fld_length && !fld_decimals)
+    {
+      uint tmp_length= length;
+      if (tmp_length > PRECISION_FOR_DOUBLE)
+      {
+        my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name);
+        DBUG_RETURN(TRUE);
+      }
+      else if (tmp_length > PRECISION_FOR_FLOAT)
+      {
+        sql_type= FIELD_TYPE_DOUBLE;
+        length= DBL_DIG+7; /* -[digits].E+### */
+      }
+      else
+        length= FLT_DIG+6; /* -[digits].E+## */
+      decimals= NOT_FIXED_DEC;
+      break;
+    }
+    if (!fld_length && !fld_decimals)
+    {
+      length=  FLT_DIG+6;
+      decimals= NOT_FIXED_DEC;
+    }
+    if (length < decimals &&
+        decimals != NOT_FIXED_DEC)
+    {
+      my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
+      DBUG_RETURN(TRUE);
+    }
+    break;
+  case FIELD_TYPE_DOUBLE:
+    allowed_type_modifier= AUTO_INCREMENT_FLAG;
+    if (!fld_length && !fld_decimals)
+    {
+      length= DBL_DIG+7;
+      decimals= NOT_FIXED_DEC;
+    }
+    if (length < decimals &&
+        decimals != NOT_FIXED_DEC)
+    {
+      my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
+      DBUG_RETURN(TRUE);
+    }
+    break;
+  case FIELD_TYPE_TIMESTAMP:
+    if (!fld_length)
+      length= 14;  /* Full date YYYYMMDDHHMMSS */
+    else if (length != 19)
+    {
+      /*
+        We support only even TIMESTAMP lengths less or equal than 14
+        and 19 as length of 4.1 compatible representation.
+      */
+      length= ((length+1)/2)*2; /* purecov: inspected */
+      length= min(length,14); /* purecov: inspected */
+    }
+    flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
+    if (fld_default_value)
+    {
+      /* Grammar allows only NOW() value for ON UPDATE clause */
+      if (fld_default_value->type() == Item::FUNC_ITEM && 
+          ((Item_func*)fld_default_value)->functype() == Item_func::NOW_FUNC)
+      {
+        unireg_check= (fld_on_update_value ? Field::TIMESTAMP_DNUN_FIELD:
+                                             Field::TIMESTAMP_DN_FIELD);
+        /*
+          We don't need default value any longer moreover it is dangerous.
+          Everything handled by unireg_check further.
+        */
+        def= 0;
+      }
+      else
+        unireg_check= (fld_on_update_value ? Field::TIMESTAMP_UN_FIELD:
+                                             Field::NONE);
+    }
+    else
+    {
+      /*
+        If we have default TIMESTAMP NOT NULL column without explicit DEFAULT
+        or ON UPDATE values then for the sake of compatiblity we should treat
+        this column as having DEFAULT NOW() ON UPDATE NOW() (when we don't
+        have another TIMESTAMP column with auto-set option before this one)
+        or DEFAULT 0 (in other cases).
+        So here we are setting TIMESTAMP_OLD_FIELD only temporary, and will
+        replace this value by TIMESTAMP_DNUN_FIELD or NONE later when
+        information about all TIMESTAMP fields in table will be availiable.
+
+        If we have TIMESTAMP NULL column without explicit DEFAULT value
+        we treat it as having DEFAULT NULL attribute.
+      */
+      unireg_check= (fld_on_update_value ? Field::TIMESTAMP_UN_FIELD :
+                     (flags & NOT_NULL_FLAG ? Field::TIMESTAMP_OLD_FIELD :
+                                              Field::NONE));
+    }
+    break;
+  case FIELD_TYPE_DATE:
+    /* Old date type. */
+    if (protocol_version != PROTOCOL_VERSION-1)
+      sql_type= FIELD_TYPE_NEWDATE;
+    /* fall trough */
+  case FIELD_TYPE_NEWDATE:
+    length= 10;
+    break;
+  case FIELD_TYPE_TIME:
+    length= 10;
+    break;
+  case FIELD_TYPE_DATETIME:
+    length= 19;
+    break;
+  case FIELD_TYPE_SET:
+    {
+      if (fld_interval_list->elements > sizeof(longlong)*8)
+      {
+        my_error(ER_TOO_BIG_SET, MYF(0), fld_name); /* purecov: inspected */
+        DBUG_RETURN(TRUE);
+      }
+      pack_length= get_set_pack_length(fld_interval_list->elements);
+
+      List_iterator<String> it(*fld_interval_list);
+      String *tmp;
+      while ((tmp= it++))
+        interval_list.push_back(tmp);
+      /*
+        Set fake length to 1 to pass the below conditions.
+        Real length will be set in mysql_prepare_table()
+        when we know the character set of the column
+      */
+      length= 1;
+      break;
+    }
+  case FIELD_TYPE_ENUM:
+    {
+      /* Should be safe. */
+      pack_length= get_enum_pack_length(fld_interval_list->elements);
+
+      List_iterator<String> it(*fld_interval_list);
+      String *tmp;
+      while ((tmp= it++))
+        interval_list.push_back(tmp);
+      length= 1; /* See comment for FIELD_TYPE_SET above. */
+      break;
+   }
+  case MYSQL_TYPE_VAR_STRING:
+    DBUG_ASSERT(0);  /* Impossible. */
+    break;
+  case MYSQL_TYPE_BIT:
+    {
+      if (!fld_length)
+        length= 1;
+      if (length > MAX_BIT_FIELD_LENGTH)
+      {
+        my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), fld_name,
+                 MAX_BIT_FIELD_LENGTH);
+        DBUG_RETURN(TRUE);
+      }
+      pack_length= (length + 7) / 8;
+      break;
+    }
+  case FIELD_TYPE_DECIMAL:
+    DBUG_ASSERT(0); /* Was obsolete */
+  }
+
+  if (!(flags & BLOB_FLAG) &&
+      ((length > max_field_charlength && fld_type != FIELD_TYPE_SET &&
+        fld_type != FIELD_TYPE_ENUM &&
+        (fld_type != MYSQL_TYPE_VARCHAR || fld_default_value)) ||
+       (!length &&
+        fld_type != MYSQL_TYPE_STRING &&
+        fld_type != MYSQL_TYPE_VARCHAR && fld_type != FIELD_TYPE_GEOMETRY)))
+  {
+    my_error((fld_type == MYSQL_TYPE_VAR_STRING ||
+              fld_type == MYSQL_TYPE_VARCHAR ||
+              fld_type == MYSQL_TYPE_STRING) ?  ER_TOO_BIG_FIELDLENGTH :
+                                                ER_TOO_BIG_DISPLAYWIDTH,
+              MYF(0),
+              fld_name, max_field_charlength); /* purecov: inspected */
+    DBUG_RETURN(TRUE);
+  }
+  fld_type_modifier&= AUTO_INCREMENT_FLAG;
+  if ((~allowed_type_modifier) & fld_type_modifier)
+  {
+    my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name);
+    DBUG_RETURN(TRUE);
+  }
+
+  DBUG_RETURN(FALSE); /* success */
 }
 
 

--- 1.172/sql/field.h	2005-11-23 12:44:54 -08:00
+++ 1.173/sql/field.h	2005-12-12 00:11:15 -08:00
@@ -134,7 +134,19 @@
             null_bit == field->null_bit);
   }
   virtual bool eq_def(Field *field);
+  
+  /*
+    pack_length() returns size (in bytes) used to store field data in memory
+    (i.e. it returns the maximum size of the field in a row of the table,
+    which is located in RAM).
+  */
   virtual uint32 pack_length() const { return (uint32) field_length; }
+
+  /*
+    pack_length_in_rec() returns size (in bytes) used to store field data on
+    storage (i.e. it returns the maximal size of the field in a row of the
+    table, which is located on disk).
+  */
   virtual uint32 pack_length_in_rec() const { return pack_length(); }
   virtual uint32 sort_length() const { return pack_length(); }
   virtual void reset(void) { bzero(ptr,pack_length()); }
@@ -1410,6 +1422,12 @@
   void init_for_tmp_table(enum_field_types sql_type_arg,
                           uint32 max_length, uint32 decimals,
                           bool maybe_null, bool is_unsigned);
+
+  bool init(THD *thd, char *field_name, enum_field_types type, char *length,
+            char *decimals, uint type_modifier, Item *default_value,
+            Item *on_update_value, LEX_STRING *comment, char *change,
+            List<String> *interval_list, CHARSET_INFO *cs,
+            uint uint_geom_type);
 };
 
 

--- 1.159/sql/item.cc	2005-12-06 22:28:10 -08:00
+++ 1.160/sql/item.cc	2005-12-12 00:11:15 -08:00
@@ -296,23 +296,6 @@
 }
 
 
-void *Item::operator new(size_t size, Item *reuse, uint *rsize)
-{
-  if (reuse && size <= reuse->rsize)
-  {
-    if (rsize)
-      (*rsize)= reuse->rsize;
-    reuse->cleanup();
-    delete reuse;
-    TRASH((void *)reuse, size);
-    return (void *)reuse;
-  }
-  if (rsize)
-    (*rsize)= (uint) size;
-  return (void *)sql_alloc((uint)size);
-}
-
-
 Item::Item():
   rsize(0), name(0), orig_name(0), name_length(0), fixed(0),
   is_autogenerated_name(TRUE),
@@ -802,9 +785,41 @@
 
 
 /*****************************************************************************
-  Item_splocal methods
+  Item_sp_variable methods
 *****************************************************************************/
-double Item_splocal::val_real()
+
+Item_sp_variable::Item_sp_variable(char *sp_var_name_str,
+                                   uint sp_var_name_length)
+  :m_thd(0)
+#ifndef DBUG_OFF
+   , m_sp(0)
+#endif
+{
+  m_name.str= sp_var_name_str;
+  m_name.length= sp_var_name_length;
+}
+
+
+bool Item_sp_variable::fix_fields(THD *thd, Item **)
+{
+  Item *it;
+
+  m_thd= thd; /* NOTE: this must be set before any this_xxx() */
+  it= this_item();
+
+  DBUG_ASSERT(it->fixed);
+
+  max_length= it->max_length;
+  decimals= it->decimals;
+  unsigned_flag= it->unsigned_flag;
+  fixed= 1;
+  collation.set(it->collation.collation, it->collation.derivation);
+
+  return FALSE;
+}
+
+
+double Item_sp_variable::val_real()
 {
   DBUG_ASSERT(fixed);
   Item *it= this_item();
@@ -814,7 +829,7 @@
 }
 
 
-longlong Item_splocal::val_int()
+longlong Item_sp_variable::val_int()
 {
   DBUG_ASSERT(fixed);
   Item *it= this_item();
@@ -824,13 +839,14 @@
 }
 
 
-String *Item_splocal::val_str(String *sp)
+String *Item_sp_variable::val_str(String *sp)
 {
   DBUG_ASSERT(fixed);
   Item *it= this_item();
   String *res= it->val_str(sp);
 
   null_value= it->null_value;
+
   if (!res)
     return NULL;
 
@@ -854,11 +870,12 @@
     str_value.set(res->ptr(), res->length(), res->charset());
   else
     res->mark_as_const();
+
   return &str_value;
 }
 
 
-my_decimal *Item_splocal::val_decimal(my_decimal *decimal_value)
+my_decimal *Item_sp_variable::val_decimal(my_decimal *decimal_value)
 {
   DBUG_ASSERT(fixed);
   Item *it= this_item();
@@ -868,73 +885,108 @@
 }
 
 
-bool Item_splocal::is_null()
+bool Item_sp_variable::is_null()
 {
-  Item *it= this_item();
-  return it->is_null();
+  return this_item()->is_null();
+}
+
+
+/*****************************************************************************
+  Item_splocal methods
+*****************************************************************************/
+
+Item_splocal::Item_splocal(const LEX_STRING &sp_var_name,
+                           uint sp_var_idx,
+                           enum_field_types sp_var_type,
+                           uint pos_in_q)
+  :Item_sp_variable(sp_var_name.str, sp_var_name.length),
+   m_var_idx(sp_var_idx), pos_in_query(pos_in_q)
+{
+  maybe_null= TRUE;
+
+  m_type= sp_map_item_type(sp_var_type);
+  m_result_type= sp_map_result_type(sp_var_type);
 }
 
 
 Item *
 Item_splocal::this_item()
 {
-  DBUG_ASSERT(owner == thd->spcont->owner);
-  return thd->spcont->get_item(m_offset);
+  DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+
+  return m_thd->spcont->get_item(m_var_idx);
+}
+
+const Item *
+Item_splocal::this_item() const
+{
+  DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+
+  return m_thd->spcont->get_item(m_var_idx);
 }
 
 
 Item **
-Item_splocal::this_item_addr(THD *thd, Item **addr)
+Item_splocal::this_item_addr(THD *thd, Item **)
 {
-  DBUG_ASSERT(owner == thd->spcont->owner);
-  return thd->spcont->get_item_addr(m_offset);
+  DBUG_ASSERT(m_sp == thd->spcont->sp);
+
+  return thd->spcont->get_item_addr(m_var_idx);
 }
 
-Item *
-Item_splocal::this_const_item() const
+
+void Item_splocal::print(String *str)
 {
-  DBUG_ASSERT(owner == thd->spcont->owner);
-  return thd->spcont->get_item(m_offset);
+  str->reserve(m_name.length+8);
+  str->append(m_name.str, m_name.length);
+  str->append('@');
+  str->qs_append(m_var_idx);
 }
 
-Item::Type
-Item_splocal::type() const
+
+/*****************************************************************************
+  Item_case_expr methods
+*****************************************************************************/
+
+Item_case_expr::Item_case_expr(int case_expr_id)
+  :Item_sp_variable(STRING_WITH_LEN("case_expr")),
+   m_case_expr_id(case_expr_id)
 {
-  if (thd && thd->spcont)
-  {
-    DBUG_ASSERT(owner == thd->spcont->owner);
-    return thd->spcont->get_item(m_offset)->type();
-  }
-  return NULL_ITEM;		// Anything but SUBSELECT_ITEM
 }
 
 
-bool Item_splocal::fix_fields(THD *thd_arg, Item **ref)
+Item *
+Item_case_expr::this_item()
 {
-  Item *it;
-  thd= thd_arg;                 // Must be set before this_item()
-  it= this_item();
-  DBUG_ASSERT(it->fixed);
-  max_length= it->max_length;
-  decimals= it->decimals;
-  unsigned_flag= it->unsigned_flag;
-  fixed= 1;
-  return FALSE;
+  DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+
+  return m_thd->spcont->get_case_expr(m_case_expr_id);
 }
 
 
-void Item_splocal::cleanup()
+
+const Item *
+Item_case_expr::this_item() const
 {
-  fixed= 0;
+  DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+
+  return m_thd->spcont->get_case_expr(m_case_expr_id);
 }
 
 
-void Item_splocal::print(String *str)
+Item **
+Item_case_expr::this_item_addr(THD *thd, Item **)
 {
-  str->reserve(m_name.length+8);
-  str->append(m_name.str, m_name.length);
-  str->append('@');
-  str->qs_append(m_offset);
+  DBUG_ASSERT(m_sp == thd->spcont->sp);
+
+  return thd->spcont->get_case_expr_addr(m_case_expr_id);
+}
+
+
+void Item_case_expr::print(String *str)
+{
+  str->append(STRING_WITH_LEN("case_expr@"));
+  str->qs_append(m_case_expr_id);
 }
 
 
@@ -1013,12 +1065,6 @@
 }
 
 
-void Item_name_const::cleanup()
-{
-  fixed= 0;
-}
-
-
 void Item_name_const::print(String *str)
 {
   str->append(STRING_WITH_LEN("NAME_CONST("));
@@ -1038,6 +1084,7 @@
     ref_pointer_array	Pointer to array of reference fields
     fields		All fields in select
     ref			Pointer to item
+    skip_registered     <=> function be must skipped for registered SUM items
 
   NOTES
    This is from split_sum_func2() for items that should be split
@@ -1050,8 +1097,13 @@
 
 
 void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
-                           List<Item> &fields, Item **ref)
+                           List<Item> &fields, Item **ref, 
+                           bool skip_registered)
 {
+  /* An item of type Item_sum  is registered <=> ref_by != 0 */ 
+  if (type() == SUM_FUNC_ITEM && skip_registered && 
+      ((Item_sum *) this)->ref_by)
+    return;                                                 
   if (type() != SUM_FUNC_ITEM && with_sum_func)
   {
     /* Will split complicated items and ignore simple ones */
@@ -3186,14 +3238,8 @@
         {
           for each outer query Q_k beginning from the inner-most one
           {
-            if - Q_k is not a group query AND
-               - Q_k is not inside an aggregate function
-               OR
-               - Q_(k-1) is not in a HAVING or SELECT clause of Q_k
-            {
-              search for a column or derived column named col_ref_i
-              [in table T_j] in the FROM clause of Q_k;
-            }
+            search for a column or derived column named col_ref_i
+            [in table T_j] in the FROM clause of Q_k;
 
             if such a column is not found
               Search for a column or derived column named col_ref_i
@@ -3272,18 +3318,11 @@
 
         place= prev_subselect_item->parsing_place;
         /*
-          Check table fields only if the subquery is used somewhere out of
-          HAVING, or the outer SELECT does not use grouping (i.e. tables are
-          accessible).
-
           In case of a view, find_field_in_tables() writes the pointer to
           the found view field into '*reference', in other words, it
           substitutes this Item_field with the found expression.
         */
-        if ((place != IN_HAVING ||
-             (!select->with_sum_func &&
-              select->group_list.elements == 0)) &&
-            (from_field= find_field_in_tables(thd, this,
+        if ((from_field= find_field_in_tables(thd, this,
                                               outer_context->
                                                 first_name_resolution_table,
                                               outer_context->
@@ -3299,6 +3338,21 @@
             {
               prev_subselect_item->used_tables_cache|= from_field->table->map;
               prev_subselect_item->const_item_cache= 0;
+              if (thd->lex->in_sum_func &&
+                  thd->lex->in_sum_func->nest_level == 
+                  thd->lex->current_select->nest_level)
+              {
+                Item::Type type= (*reference)->type();
+                set_if_bigger(thd->lex->in_sum_func->max_arg_level,
+                              select->nest_level);
+                set_field(from_field);
+                fixed= 1;
+                mark_as_dependent(thd, last_checked_context->select_lex,
+                                  context->select_lex, this,
+                                  ((type == REF_ITEM || type == FIELD_ITEM) ?
+                                   (Item_ident*) (*reference) : 0));
+                return FALSE;
+              }
             }
             else
             {
@@ -3450,6 +3504,11 @@
       return FALSE;
 
     set_field(from_field);
+    if (thd->lex->in_sum_func &&
+        thd->lex->in_sum_func->nest_level == 
+        thd->lex->current_select->nest_level)
+      set_if_bigger(thd->lex->in_sum_func->max_arg_level,
+                    thd->lex->current_select->nest_level);
   }
   else if (thd->set_query_id)
   {
@@ -3946,6 +4005,9 @@
       str_value.set_quick(0, 0, cs);
       return set_field_to_null_with_conversions(field, no_conversions);
     }
+
+    /* NOTE: If null_value == FALSE, "result" must be not NULL.  */
+
     field->set_notnull();
     error=field->store(result->ptr(),result->length(),cs);
     str_value.set_quick(0, 0, cs);
@@ -4639,9 +4701,8 @@
     aggregate function.
   */
   if (((*ref)->with_sum_func && name &&
-       (depended_from ||
-	!(current_sel->linkage != GLOBAL_OPTIONS_TYPE &&
-          current_sel->having_fix_field))) ||
+       !(current_sel->linkage != GLOBAL_OPTIONS_TYPE &&
+         current_sel->having_fix_field)) ||
       !(*ref)->fixed)
   {
     my_error(ER_ILLEGAL_REFERENCE, MYF(0),
@@ -5135,10 +5196,17 @@
     Item_ref *ref= (Item_ref *)arg;
     if (ref->ref[0]->type() != FIELD_ITEM)
     {
+      my_error(ER_BAD_FIELD_ERROR, MYF(0), "", "VALUES() function");
       return TRUE;
     }
     arg= ref->ref[0];
   }
+  /*
+    According to our SQL grammar, VALUES() function can reference
+    only to a column.
+  */
+  DBUG_ASSERT(arg->type() == FIELD_ITEM);
+
   Item_field *field_arg= (Item_field *)arg;
 
   if (field_arg->field->table->insert_values)

--- 1.183/sql/item.h	2005-12-10 23:30:51 -08:00
+++ 1.184/sql/item.h	2005-12-12 00:11:16 -08:00
@@ -729,7 +729,7 @@
   // used in row subselects to get value of elements
   virtual void bring_value() {}
 
-  Field *tmp_table_field_from_field_type(TABLE *table);
+  Field *tmp_table_field_from_field_type(TABLE *table, bool fixed_length);
   virtual Item_field *filed_for_view_update() { return 0; }
 
   virtual Item *neg_transformer(THD *thd) { return NULL; }

--- 1.187/sql/item_cmpfunc.cc	2005-12-02 20:42:27 -08:00
+++ 1.188/sql/item_cmpfunc.cc	2005-12-12 00:11:16 -08:00
@@ -1232,7 +1232,7 @@
 
 Field *Item_func_ifnull::tmp_table_field(TABLE *table)
 {
-  return tmp_table_field_from_field_type(table);
+  return tmp_table_field_from_field_type(table, 0);
 }
 
 double

--- 1.270/sql/item_func.cc	2005-12-10 23:30:51 -08:00
+++ 1.271/sql/item_func.cc	2005-12-12 00:11:16 -08:00
@@ -362,41 +362,43 @@
 }
 
 
-Field *Item_func::tmp_table_field(TABLE *t_arg)
+Field *Item_func::tmp_table_field(TABLE *table)
 {
-  Field *res;
-  LINT_INIT(res);
+  Field *field;
+  LINT_INIT(field);
 
   switch (result_type()) {
   case INT_RESULT:
     if (max_length > 11)
-      res= new Field_longlong(max_length, maybe_null, name, t_arg,
-			      unsigned_flag);
+      field= new Field_longlong(max_length, maybe_null, name, unsigned_flag);
     else
-      res= new Field_long(max_length, maybe_null, name, t_arg,
-			  unsigned_flag);
+      field= new Field_long(max_length, maybe_null, name, unsigned_flag);
     break;
   case REAL_RESULT:
-    res= new Field_double(max_length, maybe_null, name, t_arg, decimals);
+    field= new Field_double(max_length, maybe_null, name, decimals);
     break;
   case STRING_RESULT:
-    res= make_string_field(t_arg);
+    return make_string_field(table);
     break;
   case DECIMAL_RESULT:
-    res= new Field_new_decimal(my_decimal_precision_to_length(decimal_precision(),
-                                                              decimals,
-                                                              unsigned_flag),
-                               maybe_null, name, t_arg, decimals, unsigned_flag);
+    field= new Field_new_decimal(my_decimal_precision_to_length(decimal_precision(),
+                                                                decimals,
+                                                                unsigned_flag),
+                                 maybe_null, name, decimals, unsigned_flag);
     break;
   case ROW_RESULT:
   default:
     // This case should never be chosen
     DBUG_ASSERT(0);
+    field= 0;
     break;
   }
-  return res;
+  if (field)
+    field->init(table);
+  return field;
 }
 
+
 my_decimal *Item_func::val_decimal(my_decimal *decimal_value)
 {
   DBUG_ASSERT(fixed);
@@ -4637,7 +4639,8 @@
 {
   maybe_null= 1;
   m_name->init_qname(current_thd);
-  dummy_table= (TABLE*) sql_calloc(sizeof(TABLE));
+  dummy_table= (TABLE*) sql_calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE));
+  dummy_table->s= (TABLE_SHARE*) (dummy_table+1);
 }
 
 
@@ -4648,9 +4651,11 @@
 {
   maybe_null= 1;
   m_name->init_qname(current_thd);
-  dummy_table= (TABLE*) sql_calloc(sizeof(TABLE));
+  dummy_table= (TABLE*) sql_calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE));
+  dummy_table->s= (TABLE_SHARE*) (dummy_table+1);
 }
 
+
 void
 Item_func_sp::cleanup()
 {
@@ -4705,16 +4710,15 @@
       DBUG_RETURN(0);
     }
   }
-  if (!dummy_table->s)
+  if (!dummy_table->alias)
   {
     char *empty_name= (char *) "";
-    TABLE_SHARE *share;
-    dummy_table->s= share= &dummy_table->share_not_to_be_used;      
-    dummy_table->alias = empty_name;
-    dummy_table->maybe_null = maybe_null;
+    dummy_table->alias= empty_name;
+    dummy_table->maybe_null= maybe_null;
     dummy_table->in_use= current_thd;
-    share->table_cache_key = empty_name;
-    share->table_name = empty_name;
+    dummy_table->s->table_cache_key.str = empty_name;
+    dummy_table->s->table_name.str= empty_name;
+    dummy_table->s->db.str= empty_name;
   }
   field= m_sp->create_result_field(max_length, name, dummy_table);
   DBUG_RETURN(field);

--- 1.170/sql/item_sum.cc	2005-12-02 20:42:27 -08:00
+++ 1.171/sql/item_sum.cc	2005-12-12 00:11:16 -08:00
@@ -371,26 +371,33 @@
 Field *Item_sum::create_tmp_field(bool group, TABLE *table,
                                   uint convert_blob_length)
 {
+  Field *field;
   switch (result_type()) {
   case REAL_RESULT:
-    return new Field_double(max_length,maybe_null,name,table,decimals);
+    field= new Field_double(max_length, maybe_null, name, decimals);
+    break;
   case INT_RESULT:
-    return new Field_longlong(max_length,maybe_null,name,table,unsigned_flag);
+    field= new Field_longlong(max_length, maybe_null, name, unsigned_flag);
+    break;
   case STRING_RESULT:
-    if (max_length > 255 && convert_blob_length)
-      return new Field_varstring(convert_blob_length, maybe_null,
-                                 name, table,
-                                 collation.collation);
-    return make_string_field(table);
+    if (max_length <= 255 || !convert_blob_length)
+      return make_string_field(table);
+    field= new Field_varstring(convert_blob_length, maybe_null,
+                               name, table->s, collation.collation);
+    break;
   case DECIMAL_RESULT:
-    return new Field_new_decimal(max_length, maybe_null, name, table,
+    field= new Field_new_decimal(max_length, maybe_null, name,
                                  decimals, unsigned_flag);
+    break;
   case ROW_RESULT:
   default:
     // This case should never be choosen
     DBUG_ASSERT(0);
     return 0;
   }
+  if (field)
+    field->init(table);
+  return field;
 }
 
 
@@ -538,9 +545,10 @@
 Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table,
 					 uint convert_blob_length)
 {
+  Field *field;
   if (args[0]->type() == Item::FIELD_ITEM)
   {
-    Field *field= ((Item_field*) args[0])->field;
+    field= ((Item_field*) args[0])->field;
     
     if ((field= create_tmp_field_from_field(current_thd, field, name, table,
 					    NULL, convert_blob_length)))
@@ -554,16 +562,21 @@
   */
   switch (args[0]->field_type()) {
   case MYSQL_TYPE_DATE:
-    return new Field_date(maybe_null, name, table, collation.collation);
+    field= new Field_date(maybe_null, name, collation.collation);
+    break;
   case MYSQL_TYPE_TIME:
-    return new Field_time(maybe_null, name, table, collation.collation);
+    field= new Field_time(maybe_null, name, collation.collation);
+    break;
   case MYSQL_TYPE_TIMESTAMP:
   case MYSQL_TYPE_DATETIME:
-    return new Field_datetime(maybe_null, name, table, collation.collation);
-  default:
+    field= new Field_datetime(maybe_null, name, collation.collation);
     break;
+  default:
+    return Item_sum::create_tmp_field(group, table, convert_blob_length);
   }
-  return Item_sum::create_tmp_field(group, table, convert_blob_length);
+  if (field)
+    field->init(table);
+  return field;
 }
 
 
@@ -1065,6 +1078,7 @@
 Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
                                       uint convert_blob_len)
 {
+  Field *field;
   if (group)
   {
     /*
@@ -1072,14 +1086,18 @@
       The easyest way is to do this is to store both value in a string
       and unpack on access.
     */
-    return new Field_string(((hybrid_type == DECIMAL_RESULT) ?
+    field= new Field_string(((hybrid_type == DECIMAL_RESULT) ?
                              dec_bin_size : sizeof(double)) + sizeof(longlong),
-                            0, name, table, &my_charset_bin);
+                            0, name, &my_charset_bin);
   }
-  if (hybrid_type == DECIMAL_RESULT)
-    return new Field_new_decimal(max_length, maybe_null, name, table,
+  else if (hybrid_type == DECIMAL_RESULT)
+    field= new Field_new_decimal(max_length, maybe_null, name,
                                  decimals, unsigned_flag);
-  return new Field_double(max_length, maybe_null, name, table, decimals);
+  else
+    field= new Field_double(max_length, maybe_null, name, decimals);
+  if (field)
+    field->init(table);
+  return field;
 }
 
 
@@ -1244,6 +1262,7 @@
 Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
                                            uint convert_blob_len)
 {
+  Field *field;
   if (group)
   {
     /*
@@ -1251,15 +1270,19 @@
       The easyest way is to do this is to store both value in a string
       and unpack on access.
     */
-    return new Field_string(((hybrid_type == DECIMAL_RESULT) ?
+    field= new Field_string(((hybrid_type == DECIMAL_RESULT) ?
                              dec_bin_size0 + dec_bin_size1 :
                              sizeof(double)*2) + sizeof(longlong),
-                            0, name, table, &my_charset_bin);
+                            0, name, &my_charset_bin);
   }
-  if (hybrid_type == DECIMAL_RESULT)
-    return new Field_new_decimal(max_length, maybe_null, name, table,
+  else if (hybrid_type == DECIMAL_RESULT)
+    field= new Field_new_decimal(max_length, maybe_null, name,
                                  decimals, unsigned_flag);
-  return new Field_double(max_length, maybe_null,name,table,decimals);
+  else
+    field= new Field_double(max_length, maybe_null, name, decimals);
+  if (field)
+    field->init(table);
+  return field;
 }
 
 

--- 1.352/sql/mysql_priv.h	2005-12-06 22:28:11 -08:00
+++ 1.353/sql/mysql_priv.h	2005-12-12 00:11:17 -08:00
@@ -48,6 +48,7 @@
 typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
 #endif
 typedef ulong key_part_map;           /* Used for finding key parts */
+typedef ulong nesting_map;  /* Used for flags of nesting constructs */
 /*
   Used to identify NESTED_JOIN structures within a join (applicable only to
   structures that have not been simplified away and embed more the one
@@ -686,6 +687,7 @@
 bool mysql_preload_keys(THD* thd, TABLE_LIST* table_list);
 int reassign_keycache_tables(THD* thd, KEY_CACHE *src_cache,
                              KEY_CACHE *dst_cache);
+TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
 
 bool mysql_xa_recover(THD *thd);
 
@@ -1138,8 +1140,8 @@
 uint check_word(TYPELIB *lib, const char *val, const char *end,
 		const char **end_of_word);
 
-bool is_keyword(const char *name, uint len);
 
+bool is_keyword(const char *name, uint len);
 
 #define MY_DB_OPT_FILE "db.opt"
 bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);

--- 1.284/sql/sql_base.cc	2005-12-07 02:19:38 -08:00
+++ 1.285/sql/sql_base.cc	2005-12-12 00:29:29 -08:00
@@ -2760,7 +2760,7 @@
         if (!query_tables_last_own)
           query_tables_last_own= thd->lex->query_tables_last;
         if (sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex,
-                                                   tables->table->triggers))
+                                                          tables))
         {
           /*
             Serious error during reading stored routines from mysql.proc table.
@@ -2790,8 +2790,7 @@
       /* We have at least one table in TL here. */
       if (!query_tables_last_own)
         query_tables_last_own= thd->lex->query_tables_last;
-      if (sp_cache_routines_and_add_tables_for_view(thd, thd->lex,
-                                                    tables->view))
+      if (sp_cache_routines_and_add_tables_for_view(thd, thd->lex, tables))
       {
         /*
           Serious error during reading stored routines from mysql.proc table.
@@ -4942,12 +4941,14 @@
                   List<Item> *sum_func_list, bool allow_sum_func)
 {
   reg2 Item *item;
-  ulong save_set_query_id= thd->set_query_id;
+  bool save_set_query_id= thd->set_query_id;
+  nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
   List_iterator<Item> it(fields);
   DBUG_ENTER("setup_fields");
 
   thd->set_query_id=set_query_id;
-  thd->allow_sum_func= allow_sum_func;
+  if (allow_sum_func)
+    thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
   thd->where= THD::DEFAULT_WHERE;
 
   /*
@@ -4970,6 +4971,7 @@
     if (!item->fixed && item->fix_fields(thd, it.ref()) ||
 	(item= *(it.ref()))->check_cols(1))
     {
+      thd->lex->allow_sum_func= save_allow_sum_func;
       thd->set_query_id= save_set_query_id;
       DBUG_RETURN(TRUE); /* purecov: inspected */
     }
@@ -4980,6 +4982,7 @@
       item->split_sum_func(thd, ref_pointer_array, *sum_func_list);
     thd->used_tables|= item->used_tables();
   }
+  thd->lex->allow_sum_func= save_allow_sum_func;
   thd->set_query_id= save_set_query_id;
   DBUG_RETURN(test(thd->net.report_error));
 }

--- 1.223/sql/sql_class.cc	2005-12-10 23:30:52 -08:00
+++ 1.224/sql/sql_class.cc	2005-12-12 00:11:17 -08:00
@@ -288,7 +288,7 @@
 					       variables.date_format);
   variables.datetime_format= date_time_format_copy((THD*) 0,
 						   variables.datetime_format);
-#ifdef HAVE_NDBCLUSTER_DB
+#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
   variables.ndb_use_transactions= 1;
 #endif
   pthread_mutex_unlock(&LOCK_global_system_variables);
@@ -665,7 +665,8 @@
 
   DBUG_ASSERT((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
 	      table->file->has_transactions());
-  add_changed_table(table->s->table_cache_key, table->s->key_length);
+  add_changed_table(table->s->table_cache_key.str,
+                    table->s->table_cache_key.length);
   DBUG_VOID_RETURN;
 }
 
@@ -909,7 +910,7 @@
     return 0;
   }
 
-#ifdef HAVE_INNOBASE_DB
+#ifdef WITH_INNOBASE_STORAGE_ENGINE
   /*
     We may be passing the control from mysqld to the client: release the
     InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
@@ -945,7 +946,7 @@
 
 bool select_send::send_eof()
 {
-#ifdef HAVE_INNOBASE_DB
+#ifdef WITH_INNOBASE_STORAGE_ENGINE
   /* We may be passing the control from mysqld to the client: release the
      InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
      by thd */
@@ -1060,7 +1061,8 @@
 
   if (!dirname_length(exchange->file_name))
   {
-    strxnmov(path, FN_REFLEN, mysql_real_data_home, thd->db ? thd->db : "", NullS);
+    strxnmov(path, FN_REFLEN-1, mysql_real_data_home, thd->db ? thd->db : "",
+             NullS);
     (void) fn_format(path, exchange->file_name, path, "", option);
   }
   else

--- 1.274/sql/sql_class.h	2005-12-05 00:24:44 -08:00
+++ 1.275/sql/sql_class.h	2005-12-12 00:11:17 -08:00
@@ -791,19 +791,6 @@
        and update_row
   */
   ulong set_query_id;
-  /*
-    This variable is used in post-parse stage to declare that sum-functions,
-    or functions which have sense only if GROUP BY is present, are allowed.
-    For example in queries
-    SELECT MIN(i) FROM foo
-    SELECT GROUP_CONCAT(a, b, MIN(i)) FROM ... GROUP BY ...
-    MIN(i) have no sense.
-    Though it's grammar-related issue, it's hard to catch it out during the
-    parse stage because GROUP BY clause goes in the end of query. This
-    variable is mainly used in setup_fields/fix_fields.
-    See item_sum.cc for details.
-  */
-  bool allow_sum_func;
 
   LEX_STRING name; /* name for named prepared statements */
   LEX *lex;                                     // parse tree descriptor
@@ -2111,7 +2098,7 @@
     Routine to which this Item_splocal belongs. Used for checking if correct
     runtime context is used for variable handling.
   */
-  sp_head *owner;
+  sp_head *sp;
 #endif
   bool local;
   uint offset;

--- 1.159/sql/sql_delete.cc	2005-11-23 12:44:56 -08:00
+++ 1.160/sql/sql_delete.cc	2005-12-12 00:11:17 -08:00
@@ -341,7 +341,7 @@
   SELECT_LEX *select_lex= &thd->lex->select_lex;
   DBUG_ENTER("mysql_prepare_delete");
 
-  thd->allow_sum_func= 0;
+  thd->lex->allow_sum_func= 0;
   if (setup_tables(thd, &thd->lex->select_lex.context,
                    &thd->lex->select_lex.top_join_list,
                    table_list, conds, &select_lex->leaf_tables,

--- 1.168/sql/sql_lex.cc	2005-12-06 22:28:11 -08:00
+++ 1.169/sql/sql_lex.cc	2005-12-12 00:11:18 -08:00
@@ -184,6 +184,9 @@
   lex->sroutines_list.empty();
   lex->sroutines_list_own_last= lex->sroutines_list.next;
   lex->sroutines_list_own_elements= 0;
+  lex->nest_level=0 ;
+  lex->allow_sum_func= 0;
+  lex->in_sum_func= NULL;
   DBUG_VOID_RETURN;
 }
 
@@ -1147,6 +1150,7 @@
   first_cond_optimization= 1;
   parsing_place= NO_MATTER;
   exclude_from_table_unique_test= no_wrap_view_item= FALSE;
+  nest_level= 0;
   link_next= 0;
 }
 
@@ -1166,6 +1170,7 @@
   interval_list.empty();
   use_index.empty();
   ftfunc_list_alloc.empty();
+  inner_sum_func_list= 0;
   ftfunc_list= &ftfunc_list_alloc;
   linkage= UNSPECIFIED_TYPE;
   order_list.elements= 0;

--- 1.209/sql/sql_lex.h	2005-12-06 22:28:12 -08:00
+++ 1.210/sql/sql_lex.h	2005-12-12 00:11:18 -08:00
@@ -531,6 +531,8 @@
   ulong table_join_options;
   uint in_sum_expr;
   uint select_number; /* number of select (used for EXPLAIN) */
+  int nest_level;     /* nesting level of select */
+  Item_sum *inner_sum_func_list; /* list of sum func in nested selects */ 
   uint with_wild; /* item list contain '*' */
   bool  braces;   	/* SELECT ... UNION (SELECT ... ) <- this braces */
   /* TRUE when having fix field called in processing of this SELECT */
@@ -794,12 +796,23 @@
 
   SQL_LIST	      proc_list, auxilliary_table_list, save_list;
   create_field	      *last_field;
+  Item_sum *in_sum_func;
   udf_func udf;
   HA_CHECK_OPT   check_opt;			// check/repair options
   HA_CREATE_INFO create_info;
   LEX_MASTER_INFO mi;				// used by CHANGE MASTER
   USER_RESOURCES mqh;
   ulong type;
+  /*
+    This variable is used in post-parse stage to declare that sum-functions,
+    or functions which have sense only if GROUP BY is present, are allowed.
+    For example in a query
+    SELECT ... FROM ...WHERE MIN(i) == 1 GROUP BY ... HAVING MIN(i) > 2
+    MIN(i) in the WHERE clause is not allowed in the opposite to MIN(i)
+    in the HAVING clause. Due to possible nesting of select construct
+    the variable can contain 0 or 1 for each nest level.
+  */
+  nesting_map allow_sum_func;
   enum_sql_command sql_command, orig_sql_command;
   thr_lock_type lock_option;
   enum SSL_type ssl_type;			/* defined in violite.h */
@@ -818,6 +831,7 @@
   uint grant, grant_tot_col, which_columns;
   uint fk_delete_opt, fk_update_opt, fk_match_option;
   uint slave_thd_opt, start_transaction_opt;
+  int nest_level;
   /*
     In LEX representing update which were transformed to multi-update
     stores total number of tables. For LEX representing multi-delete

--- 1.494/sql/sql_parse.cc	2005-12-07 06:17:10 -08:00
+++ 1.495/sql/sql_parse.cc	2005-12-12 00:11:18 -08:00
@@ -2614,7 +2614,7 @@
       goto error; /* purecov: inspected */
     thd->enable_slow_log= opt_log_slow_admin_statements;
     res = mysql_backup_table(thd, first_table);
-    (TABLE_LIST*) select_lex->table_list.first=first_table;
+    select_lex->table_list.first= (byte*) first_table;
     lex->query_tables=all_tables;
     break;
   }
@@ -2627,7 +2627,7 @@
       goto error; /* purecov: inspected */
     thd->enable_slow_log= opt_log_slow_admin_statements;
     res = mysql_restore_table(thd, first_table);
-    (TABLE_LIST*) select_lex->table_list.first=first_table;
+    select_lex->table_list.first= (byte*) first_table;
     lex->query_tables=all_tables;
     break;
   }
@@ -3122,7 +3122,7 @@
         mysql_bin_log.write(&qinfo);
       }
     }
-    (TABLE_LIST*) select_lex->table_list.first=first_table;
+    select_lex->table_list.first= (byte*) first_table;
     lex->query_tables=all_tables;
     break;
   }
@@ -3134,7 +3134,7 @@
       goto error; /* purecov: inspected */
     thd->enable_slow_log= opt_log_slow_admin_statements;
     res = mysql_check_table(thd, first_table, &lex->check_opt);
-    (TABLE_LIST*) select_lex->table_list.first=first_table;
+    select_lex->table_list.first= (byte*) first_table;
     lex->query_tables=all_tables;
     break;
   }
@@ -3156,7 +3156,7 @@
         mysql_bin_log.write(&qinfo);
       }
     }
-    (TABLE_LIST*) select_lex->table_list.first=first_table;
+    select_lex->table_list.first= (byte*) first_table;
     lex->query_tables=all_tables;
     break;
   }
@@ -3181,7 +3181,7 @@
         mysql_bin_log.write(&qinfo);
       }
     }
-    (TABLE_LIST*) select_lex->table_list.first=first_table;
+    select_lex->table_list.first= (byte*) first_table;
     lex->query_tables=all_tables;
     break;
   }
@@ -5428,6 +5428,8 @@
   select_lex->parent_lex= lex; /* Used in init_query. */
   select_lex->init_query();
   select_lex->init_select();
+  lex->nest_level++;
+  select_lex->nest_level= lex->nest_level;
   /*
     Don't evaluate this subquery during statement prepare even if
     it's a constant one. The flag is switched off in the end of
@@ -5768,335 +5770,15 @@
                         buf, "TIMESTAMP");
   }
 
-  if (!(new_field= new_create_field(thd, field_name, type, length, decimals,
-		type_modifier, default_value, on_update_value,
-		comment, change, interval_list, cs, uint_geom_type)))
+  if (!(new_field= new create_field()) ||
+      new_field->init(thd, field_name, type, length, decimals, type_modifier,
+                      default_value, on_update_value, comment, change,
+                      interval_list, cs, uint_geom_type))
     DBUG_RETURN(1);
 
   lex->create_list.push_back(new_field);
   lex->last_field=new_field;
   DBUG_RETURN(0);
-}
-
-/*****************************************************************************
-** Create field definition for create
-** Return 0 on failure, otherwise return create_field instance
-******************************************************************************/
-  
-create_field *
-new_create_field(THD *thd, char *field_name, enum_field_types type,
-		 char *length, char *decimals,
-		 uint type_modifier, 
-		 Item *default_value, Item *on_update_value,
-		 LEX_STRING *comment,
-		 char *change, List<String> *interval_list, CHARSET_INFO *cs,
-		 uint uint_geom_type)
-{
-  register create_field *new_field;
-  uint sign_len, allowed_type_modifier=0;
-  ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
-  DBUG_ENTER("new_create_field");
-  
-  if (!(new_field=new create_field()))
-    DBUG_RETURN(NULL);
-  new_field->field=0;
-  new_field->field_name=field_name;
-  new_field->def= default_value;
-  new_field->flags= type_modifier;
-  new_field->unireg_check= (type_modifier & AUTO_INCREMENT_FLAG ?
-			    Field::NEXT_NUMBER : Field::NONE);
-  new_field->decimals= decimals ? (uint)atoi(decimals) : 0;
-  if (new_field->decimals >= NOT_FIXED_DEC)
-  {
-    my_error(ER_TOO_BIG_SCALE, MYF(0), new_field->decimals, field_name,
-             NOT_FIXED_DEC-1);
-    DBUG_RETURN(NULL);
-  }
-
-  new_field->sql_type=type;
-  new_field->length=0;
-  new_field->change=change;
-  new_field->interval=0;
-  new_field->pack_length= new_field->key_length= 0;
-  new_field->charset=cs;
-  new_field->geom_type= (Field::geometry_type) uint_geom_type;
-
-  new_field->comment=*comment;
-  /*
-    Set flag if this field doesn't have a default value
-  */
-  if (!default_value && !(type_modifier & AUTO_INCREMENT_FLAG) &&
-      (type_modifier & NOT_NULL_FLAG) && type != FIELD_TYPE_TIMESTAMP)
-    new_field->flags|= NO_DEFAULT_VALUE_FLAG;
-
-  if (length && !(new_field->length= (uint) atoi(length)))
-    length=0; /* purecov: inspected */
-  sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
-
-  switch (type) {
-  case FIELD_TYPE_TINY:
-    if (!length) new_field->length=MAX_TINYINT_WIDTH+sign_len;
-    allowed_type_modifier= AUTO_INCREMENT_FLAG;
-    break;
-  case FIELD_TYPE_SHORT:
-    if (!length) new_field->length=MAX_SMALLINT_WIDTH+sign_len;
-    allowed_type_modifier= AUTO_INCREMENT_FLAG;
-    break;
-  case FIELD_TYPE_INT24:
-    if (!length) new_field->length=MAX_MEDIUMINT_WIDTH+sign_len;
-    allowed_type_modifier= AUTO_INCREMENT_FLAG;
-    break;
-  case FIELD_TYPE_LONG:
-    if (!length) new_field->length=MAX_INT_WIDTH+sign_len;
-    allowed_type_modifier= AUTO_INCREMENT_FLAG;
-    break;
-  case FIELD_TYPE_LONGLONG:
-    if (!length) new_field->length=MAX_BIGINT_WIDTH;
-    allowed_type_modifier= AUTO_INCREMENT_FLAG;
-    break;
-  case FIELD_TYPE_NULL:
-    break;
-  case FIELD_TYPE_NEWDECIMAL:
-    if (!length && !new_field->decimals)
-      new_field->length= 10;
-    if (new_field->length > DECIMAL_MAX_PRECISION)
-    {
-      my_error(ER_TOO_BIG_PRECISION, MYF(0), new_field->length, field_name,
-               DECIMAL_MAX_PRECISION);
-      DBUG_RETURN(NULL);
-    }
-    if (new_field->length < new_field->decimals)
-    {
-      my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
-      DBUG_RETURN(NULL);
-    }
-    new_field->length=
-      my_decimal_precision_to_length(new_field->length, new_field->decimals,
-                                     type_modifier & UNSIGNED_FLAG);
-    new_field->pack_length=
-      my_decimal_get_binary_size(new_field->length, new_field->decimals);
-    break;
-  case MYSQL_TYPE_VARCHAR:
-    /*
-      Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
-      if they don't have a default value
-    */
-    max_field_charlength= MAX_FIELD_VARCHARLENGTH;
-    break;
-  case MYSQL_TYPE_STRING:
-    break;
-  case FIELD_TYPE_BLOB:
-  case FIELD_TYPE_TINY_BLOB:
-  case FIELD_TYPE_LONG_BLOB:
-  case FIELD_TYPE_MEDIUM_BLOB:
-  case FIELD_TYPE_GEOMETRY:
-    if (default_value)				// Allow empty as default value
-    {
-      String str,*res;
-      res=default_value->val_str(&str);
-      if (res->length())
-      {
-	my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
-                 field_name); /* purecov: inspected */
-	DBUG_RETURN(NULL);
-      }
-      new_field->def=0;
-    }
-    new_field->flags|=BLOB_FLAG;
-    break;
-  case FIELD_TYPE_YEAR:
-    if (!length || new_field->length != 2)
-      new_field->length=4;			// Default length
-    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
-    break;
-  case FIELD_TYPE_FLOAT:
-    /* change FLOAT(precision) to FLOAT or DOUBLE */
-    allowed_type_modifier= AUTO_INCREMENT_FLAG;
-    if (length && !decimals)
-    {
-      uint tmp_length=new_field->length;
-      if (tmp_length > PRECISION_FOR_DOUBLE)
-      {
-	my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
-	DBUG_RETURN(NULL);
-      }
-      else if (tmp_length > PRECISION_FOR_FLOAT)
-      {
-	new_field->sql_type=FIELD_TYPE_DOUBLE;
-	new_field->length=DBL_DIG+7;			// -[digits].E+###
-      }
-      else
-	new_field->length=FLT_DIG+6;			// -[digits].E+##
-      new_field->decimals= NOT_FIXED_DEC;
-      break;
-    }
-    if (!length && !decimals)
-    {
-      new_field->length =  FLT_DIG+6;
-      new_field->decimals= NOT_FIXED_DEC;
-    }
-    if (new_field->length < new_field->decimals &&
-        new_field->decimals != NOT_FIXED_DEC)
-    {
-      my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
-      DBUG_RETURN(NULL);
-    }
-    break;
-  case FIELD_TYPE_DOUBLE:
-    allowed_type_modifier= AUTO_INCREMENT_FLAG;
-    if (!length && !decimals)
-    {
-      new_field->length = DBL_DIG+7;
-      new_field->decimals=NOT_FIXED_DEC;
-    }
-    if (new_field->length < new_field->decimals &&
-        new_field->decimals != NOT_FIXED_DEC)
-    {
-      my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
-      DBUG_RETURN(NULL);
-    }
-    break;
-  case FIELD_TYPE_TIMESTAMP:
-    if (!length)
-      new_field->length= 14;			// Full date YYYYMMDDHHMMSS
-    else if (new_field->length != 19)
-    {
-      /*
-        We support only even TIMESTAMP lengths less or equal than 14
-        and 19 as length of 4.1 compatible representation.
-      */
-      new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
-      new_field->length= min(new_field->length,14); /* purecov: inspected */
-    }
-    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
-    if (default_value)
-    {
-      /* Grammar allows only NOW() value for ON UPDATE clause */
-      if (default_value->type() == Item::FUNC_ITEM && 
-          ((Item_func*)default_value)->functype() == Item_func::NOW_FUNC)
-      {
-        new_field->unireg_check= (on_update_value?Field::TIMESTAMP_DNUN_FIELD:
-                                                  Field::TIMESTAMP_DN_FIELD);
-        /*
-          We don't need default value any longer moreover it is dangerous.
-          Everything handled by unireg_check further.
-        */
-        new_field->def= 0;
-      }
-      else
-        new_field->unireg_check= (on_update_value?Field::TIMESTAMP_UN_FIELD:
-                                                  Field::NONE);
-    }
-    else
-    {
-      /*
-        If we have default TIMESTAMP NOT NULL column without explicit DEFAULT
-        or ON UPDATE values then for the sake of compatiblity we should treat
-        this column as having DEFAULT NOW() ON UPDATE NOW() (when we don't
-        have another TIMESTAMP column with auto-set option before this one)
-        or DEFAULT 0 (in other cases).
-        So here we are setting TIMESTAMP_OLD_FIELD only temporary, and will
-        replace this value by TIMESTAMP_DNUN_FIELD or NONE later when
-        information about all TIMESTAMP fields in table will be availiable.
-
-        If we have TIMESTAMP NULL column without explicit DEFAULT value
-        we treat it as having DEFAULT NULL attribute.
-      */
-      new_field->unireg_check= (on_update_value ?
-                                Field::TIMESTAMP_UN_FIELD :
-                                (new_field->flags & NOT_NULL_FLAG ?
-                                 Field::TIMESTAMP_OLD_FIELD:
-                                 Field::NONE));
-    }
-    break;
-  case FIELD_TYPE_DATE:				// Old date type
-    if (protocol_version != PROTOCOL_VERSION-1)
-      new_field->sql_type=FIELD_TYPE_NEWDATE;
-    /* fall trough */
-  case FIELD_TYPE_NEWDATE:
-    new_field->length=10;
-    break;
-  case FIELD_TYPE_TIME:
-    new_field->length=10;
-    break;
-  case FIELD_TYPE_DATETIME:
-    new_field->length=19;
-    break;
-  case FIELD_TYPE_SET:
-    {
-      if (interval_list->elements > sizeof(longlong)*8)
-      {
-	my_error(ER_TOO_BIG_SET, MYF(0), field_name); /* purecov: inspected */
-	DBUG_RETURN(NULL);
-      }
-      new_field->pack_length= get_set_pack_length(interval_list->elements);
-
-      List_iterator<String> it(*interval_list);
-      String *tmp;
-      while ((tmp= it++))
-        new_field->interval_list.push_back(tmp);
-      /*
-        Set fake length to 1 to pass the below conditions.
-        Real length will be set in mysql_prepare_table()
-        when we know the character set of the column
-      */
-      new_field->length= 1;
-      break;
-    }
-  case FIELD_TYPE_ENUM:
-    {
-      // Should be safe
-      new_field->pack_length= get_enum_pack_length(interval_list->elements);
-
-      List_iterator<String> it(*interval_list);
-      String *tmp;
-      while ((tmp= it++))
-        new_field->interval_list.push_back(tmp);
-      new_field->length= 1; // See comment for FIELD_TYPE_SET above.
-      break;
-   }
-  case MYSQL_TYPE_VAR_STRING:
-    DBUG_ASSERT(0);                             // Impossible
-    break;
-  case MYSQL_TYPE_BIT:
-    {
-      if (!length)
-        new_field->length= 1;
-      if (new_field->length > MAX_BIT_FIELD_LENGTH)
-      {
-        my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name,
-                 MAX_BIT_FIELD_LENGTH);
-        DBUG_RETURN(NULL);
-      }
-      new_field->pack_length= (new_field->length + 7) / 8;
-      break;
-    }
-  case FIELD_TYPE_DECIMAL:
-    DBUG_ASSERT(0); /* Was obsolete */
-  }
-
-  if (!(new_field->flags & BLOB_FLAG) &&
-      ((new_field->length > max_field_charlength && type != FIELD_TYPE_SET && 
-        type != FIELD_TYPE_ENUM &&
-        (type != MYSQL_TYPE_VARCHAR || default_value)) ||
-       (!new_field->length &&
-        type != MYSQL_TYPE_STRING &&
-        type != MYSQL_TYPE_VARCHAR && type != FIELD_TYPE_GEOMETRY)))
-  {
-    my_error((type == MYSQL_TYPE_VAR_STRING || type == MYSQL_TYPE_VARCHAR ||
-              type == MYSQL_TYPE_STRING) ?  ER_TOO_BIG_FIELDLENGTH :
-             ER_TOO_BIG_DISPLAYWIDTH,
-             MYF(0),
-             field_name, max_field_charlength); /* purecov: inspected */
-    DBUG_RETURN(NULL);
-  }
-  type_modifier&= AUTO_INCREMENT_FLAG;
-  if ((~allowed_type_modifier) & type_modifier)
-  {
-    my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
-    DBUG_RETURN(NULL);
-  }
-  DBUG_RETURN(new_field);
 }
 
 

--- 1.372/sql/sql_select.cc	2005-12-01 02:12:20 -08:00
+++ 1.373/sql/sql_select.cc	2005-12-12 00:29:29 -08:00
@@ -274,21 +274,20 @@
 			       ORDER *order,
 			       ORDER *group, bool *hidden_group_fields)
 {
-  bool save_allow_sum_func;
   int res;
+  nesting_map save_allow_sum_func=thd->lex->allow_sum_func ;
   DBUG_ENTER("setup_without_group");
 
-  save_allow_sum_func= thd->allow_sum_func;
-  thd->allow_sum_func= 0;
+  thd->lex->allow_sum_func&= ~(1 << thd->lex->current_select->nest_level);
   res= setup_conds(thd, tables, leaves, conds);
 
-  thd->allow_sum_func= save_allow_sum_func;
+  thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
   res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields,
                           order);
-  thd->allow_sum_func= 0;
+  thd->lex->allow_sum_func&= ~(1 << thd->lex->current_select->nest_level);
   res= res || setup_group(thd, ref_pointer_array, tables, fields, all_fields,
                           group, hidden_group_fields);
-  thd->allow_sum_func= save_allow_sum_func;
+  thd->lex->allow_sum_func= save_allow_sum_func;
   DBUG_RETURN(res);
 }
 
@@ -355,8 +354,9 @@
   
   if (having)
   {
+    nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
     thd->where="having clause";
-    thd->allow_sum_func=1;
+    thd->lex->allow_sum_func|= 1 << select_lex_arg->nest_level;
     select_lex->having_fix_field= 1;
     bool having_fix_rc= (!having->fixed &&
 			 (having->fix_fields(thd, &having) ||
@@ -366,6 +366,18 @@
       DBUG_RETURN(-1);				/* purecov: inspected */
     if (having->with_sum_func)
       having->split_sum_func(thd, ref_pointer_array, all_fields);
+    thd->lex->allow_sum_func= save_allow_sum_func;
+  }
+  if (select_lex->inner_sum_func_list)
+  {
+    Item_sum *end=select_lex->inner_sum_func_list;
+    Item_sum *item_sum= end;  
+    do
+    { 
+      item_sum= item_sum->next;
+      item_sum->split_sum_func2(thd, ref_pointer_array,
+                                all_fields, item_sum->ref_by, FALSE);
+    } while (item_sum != end);
   }
 
   if (!thd->lex->view_prepare_mode)
@@ -5231,7 +5243,9 @@
         join->const_table_map|=RAND_TABLE_BIT;
       {						// Check const tables
         COND *const_cond=
-	  make_cond_for_table(cond,join->const_table_map,(table_map) 0);
+	  make_cond_for_table(cond,
+                              join->const_table_map,
+                              (table_map) 0);
         DBUG_EXECUTE("where",print_where(const_cond,"constants"););
         for (JOIN_TAB *tab= join->join_tab+join->const_tables;
              tab < join->join_tab+join->tables ; tab++)
@@ -8951,6 +8965,7 @@
 TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
 {
   uint field_count= field_list.elements;
+  uint blob_count= 0;
   Field **field;
   create_field *cdef;                           /* column definition */
   uint record_length= 0;
@@ -8964,8 +8979,14 @@
     return 0;
 
   table->field= field;
-  table->s= share= (TABLE_SHARE*) (table+1);
-  share->fields= field_count;
+  table->s= s= &table->share_not_to_be_used;
+  s->fields= field_count;
+
+  if (!(s->blob_field= (uint*)thd->alloc((field_list.elements + 1) *
+                                         sizeof(uint))))
+    return 0;
+
+  s->blob_ptr_size= mi_portable_sizeof_char_ptr;
 
   /* Create all fields and calculate the total length of record */
   List_iterator_fast<create_field> it(field_list);
@@ -8979,13 +9000,18 @@
                        cdef->interval, cdef->field_name);
     if (!*field)
       goto error;
-    (*field)->init(table);
-    record_length+= (*field)->pack_length();
-    if (! ((*field)->flags & NOT_NULL_FLAG))
-      null_count++;
-    field++;
+    record_length+= (**field).pack_length();
+    if (! ((**field).flags & NOT_NULL_FLAG))
+      ++null_count;
+
+    if ((*field)->flags & BLOB_FLAG)
+      s->blob_field[blob_count++]= (uint) (field - table->field);
+
+    ++field;
   }
   *field= NULL;                                 /* mark the end of the list */
+  s->blob_field[blob_count]= 0;             /* mark the end of the list */
+  s->blob_fields= blob_count;
 
   null_pack_length= (null_count + 7)/8;
   share->reclength= record_length + null_pack_length;

--- 1.102/sql/sql_select.h	2005-12-01 02:12:20 -08:00
+++ 1.103/sql/sql_select.h	2005-12-12 00:11:19 -08:00
@@ -407,7 +407,6 @@
 			ORDER *group, bool distinct, bool save_sum_fields,
 			ulonglong select_options, ha_rows rows_limit,
 			char* alias);
-TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
 void free_tmp_table(THD *thd, TABLE *entry);
 void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
 		       bool reset_with_sum_func);

--- 1.178/sql/sql_update.cc	2005-12-02 11:07:08 -08:00
+++ 1.179/sql/sql_update.cc	2005-12-12 00:11:19 -08:00
@@ -706,7 +706,7 @@
   bzero((char*) &tables,sizeof(tables));	// For ORDER BY
   tables.table= table;
   tables.alias= table_list->alias;
-  thd->allow_sum_func= 0;
+  thd->lex->allow_sum_func= 0;
 
   if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list,
                    table_list, conds, &select_lex->leaf_tables,

--- 1.428/sql/sql_yacc.yy	2005-12-07 06:17:10 -08:00
+++ 1.429/sql/sql_yacc.yy	2005-12-12 00:11:19 -08:00
@@ -1377,41 +1377,11 @@
 	  {
 	    LEX *lex= Lex;
 	    sp_head *sp= lex->sphead;
-            LEX_STRING cmt = { 0, 0 };
-	    create_field *new_field;
-	    uint unused1= 0;
-	    int unused2= 0;
 
-	    if (!(new_field= new_create_field(YYTHD, (char*) "",
-					      (enum enum_field_types)$8,
-			  		      lex->length, lex->dec, lex->type,
-			  		      (Item *)0, (Item *) 0, &cmt, 0,
-					      &lex->interval_list, 
-			  		      (lex->charset ? lex->charset :
-					       default_charset_info),
-					      lex->uint_geom_type)))
-	      YYABORT;
-
-	    sp->m_returns_cs= new_field->charset;
-
-            if (new_field->interval_list.elements)
-            {
-	      new_field->interval= 
-                sp->create_typelib(&new_field->interval_list);
-            }
-            sp_prepare_create_field(YYTHD, new_field);
-
-	    if (prepare_create_field(new_field, &unused1, &unused2, &unused2,
-				     HA_CAN_GEOMETRY))
-	      YYABORT;
-
-	    sp->m_returns= new_field->sql_type;
-	    sp->m_returns_cs= new_field->charset;
-	    sp->m_returns_len= new_field->length;
-	    sp->m_returns_pack= new_field->pack_flag;
-            sp->m_returns_typelib= new_field->interval;
-            sp->m_geom_returns= new_field->geom_type;
-            new_field->interval= NULL;
+            if (sp->fill_field_definition(YYTHD, lex,
+                                          (enum enum_field_types) $8,
+                                          &sp->m_return_field_def))
+              YYABORT;
 
 	    bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
 	  }
@@ -1533,8 +1503,28 @@
 	| sp_fdparam
 	;
 
+sp_init_param:
+	  /* Empty */
+	  {
+	    LEX *lex= Lex;
+
+	    lex->length= 0;
+	    lex->dec= 0;
+	    lex->type= 0;
+	  
+	    lex->default_value= 0;
+	    lex->on_update_value= 0;
+	  
+	    lex->comment= null_lex_str;
+	    lex->charset= NULL;
+	  
+	    lex->interval_list.empty();
+	    lex->uint_geom_type= 0;
+	  }
+	;
+
 sp_fdparam:
-	  ident type
+	  ident sp_init_param type
 	  {
 	    LEX *lex= Lex;
 	    sp_pcontext *spc= lex->spcont;
@@ -1544,7 +1534,17 @@
 	      my_error(ER_SP_DUP_PARAM, MYF(0), $1.str);
 	      YYABORT;
 	    }
-	    spc->push_pvar(&$1, (enum enum_field_types)$2, sp_param_in);
+	    sp_pvar_t *pvar= spc->push_pvar(&$1, (enum enum_field_types)$3,
+                                            sp_param_in);
+
+            if (lex->sphead->fill_field_definition(YYTHD, lex,
+                                                   (enum enum_field_types) $3,
+                                                   &pvar->field_def))
+            {
+              YYABORT;
+            }
+            pvar->field_def.field_name= pvar->name.str;
+            pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
 	  }
 	;
 
@@ -1560,18 +1560,27 @@
 	;
 
 sp_pdparam:
-	  sp_opt_inout ident type
+	  sp_opt_inout sp_init_param ident type
 	  {
 	    LEX *lex= Lex;
 	    sp_pcontext *spc= lex->spcont;
 
-	    if (spc->find_pvar(&$2, TRUE))
+	    if (spc->find_pvar(&$3, TRUE))
 	    {
-	      my_error(ER_SP_DUP_PARAM, MYF(0), $2.str);
+	      my_error(ER_SP_DUP_PARAM, MYF(0), $3.str);
 	      YYABORT;
 	    }
-	    spc->push_pvar(&$2, (enum enum_field_types)$3,
-			   (sp_param_mode_t)$1);
+	    sp_pvar_t *pvar= spc->push_pvar(&$3, (enum enum_field_types)$4,
+			                    (sp_param_mode_t)$1);
+
+            if (lex->sphead->fill_field_definition(YYTHD, lex,
+                                                   (enum enum_field_types) $4,
+                                                   &pvar->field_def))
+            {
+              YYABORT;
+            }
+            pvar->field_def.field_name= pvar->name.str;
+            pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
 	  }
 	;
 
@@ -1623,45 +1632,60 @@
 	;
 
 sp_decl:
-          DECLARE_SYM sp_decl_idents type 
+          DECLARE_SYM sp_decl_idents
           {
             LEX *lex= Lex;
 
             lex->sphead->reset_lex(YYTHD);
             lex->spcont->declare_var_boundary($2);
           }
+          type
           sp_opt_default
           {
             LEX *lex= Lex;
-            sp_pcontext *ctx= lex->spcont;
-            uint max= ctx->context_pvars();
-            enum enum_field_types type= (enum enum_field_types)$3;
-            Item *it= $5;
-            bool has_default= (it != NULL);
-
-            for (uint i = max-$2 ; i < max ; i++)
-            {
-              sp_instr_set *in;
-	      uint off= ctx->pvar_context2index(i);
-
-              ctx->set_type(off, type);
-              if (! has_default)
-                it= new Item_null();  /* QQ Set to the type with null_value? */
-              in = new sp_instr_set(lex->sphead->instructions(),
-                                    ctx,
-                                    off,
-                                    it, type, lex,
-                                    (i == max - 1));
-
-              /*
-                The last instruction is assigned to be responsible for
-                freeing LEX.
-              */
-              lex->sphead->add_instr(in);
-              ctx->set_default(off, it);
+            sp_pcontext *pctx= lex->spcont;
+            uint num_vars= pctx->context_pvars();
+            enum enum_field_types var_type= (enum enum_field_types) $4;
+            Item *dflt_value_item= $5;
+            create_field *create_field_op;
+            
+            if (!dflt_value_item)
+            {
+              dflt_value_item= new Item_null();
+              /* QQ Set to the var_type with null_value? */
+            }
+            
+            for (uint i = num_vars-$2 ; i < num_vars ; i++)
+            {
+              uint var_idx= pctx->pvar_context2index(i);
+              sp_pvar_t *pvar= pctx->find_pvar(var_idx);
+            
+              if (!pvar)
+                YYABORT;
+            
+              pvar->type= var_type;
+              pvar->dflt= dflt_value_item;
+            
+              if (lex->sphead->fill_field_definition(YYTHD, lex, var_type,
+                                                     &pvar->field_def))
+              {
+                YYABORT;
+              }
+            
+              pvar->field_def.field_name= pvar->name.str;
+              pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
+            
+              /* The last instruction is responsible for freeing LEX. */
+
+              lex->sphead->add_instr(
+                new sp_instr_set(lex->sphead->instructions(), pctx, var_idx,
+                                 dflt_value_item, var_type, lex,
+                                 (i == num_vars - 1)));
             }
-            ctx->declare_var_boundary(0);
+
+            pctx->declare_var_boundary(0);
             lex->sphead->restore_lex(YYTHD);
+
             $$.vars= $2;
             $$.conds= $$.hndlrs= $$.curs= 0;
           }
@@ -1884,6 +1908,8 @@
 sp_decl_idents:
 	  ident
 	  {
+            /* NOTE: field definition is filled in sp_decl section. */
+
 	    LEX *lex= Lex;
 	    sp_pcontext *spc= lex->spcont;
 
@@ -1897,6 +1923,8 @@
 	  }
 	| sp_decl_idents ',' ident
 	  {
+            /* NOTE: field definition is filled in sp_decl section. */
+
 	    LEX *lex= Lex;
 	    sp_pcontext *spc= lex->spcont;
 
@@ -1974,8 +2002,8 @@
 	    {
 	      sp_instr_freturn *i;
 
-	      i= new sp_instr_freturn(sp->instructions(), lex->spcont,
-		                      $3, sp->m_returns, lex);
+	      i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3,
+                                      sp->m_return_field_def.sql_type, lex);
 	      sp->add_instr(i);
 	      sp->m_flags|= sp_head::HAS_RETURN;
 	    }
@@ -1991,25 +2019,27 @@
           { Lex->sphead->reset_lex(YYTHD); }
           expr WHEN_SYM
 	  {
-	    /* We "fake" this by using an anonymous variable which we
-	       set to the expression. Note that all WHENs are evaluate
-	       at the same frame level, so we then know that it's the
-	       top-most variable in the frame. */
-	    LEX *lex= Lex;
-	    uint offset= lex->spcont->current_pvars();
-	    sp_instr_set *i = new sp_instr_set(lex->sphead->instructions(),
-                                               lex->spcont, offset, $3,
-                                               MYSQL_TYPE_STRING, lex, TRUE);
-	    LEX_STRING dummy={(char*)"", 0};
-
-	    lex->spcont->push_pvar(&dummy, MYSQL_TYPE_STRING, sp_param_in);
-	    lex->sphead->add_instr(i);
-	    lex->sphead->m_flags|= sp_head::IN_SIMPLE_CASE;
-            lex->sphead->restore_lex(YYTHD);
+	    LEX *lex= Lex;
+	    sp_head *sp= lex->sphead;
+	    sp_pcontext *parsing_ctx= lex->spcont;
+	    int case_expr_id= parsing_ctx->register_case_expr();
+	    
+	    if (parsing_ctx->push_case_expr_id(case_expr_id))
+              YYABORT;
+	    
+	    sp->add_instr(
+	      new sp_instr_set_case_expr(sp->instructions(),
+	                                 parsing_ctx,
+	                                 case_expr_id,
+	                                 $3,
+	                                 lex));
+	    
+	    sp->m_flags|= sp_head::IN_SIMPLE_CASE;
+	    sp->restore_lex(YYTHD);
 	  }
 	  sp_case END CASE_SYM
 	  {
-	    Lex->spcont->pop_pvar();
+	    Lex->spcont->pop_case_expr_id();
 	  }
 	| sp_labeled_control
 	  {}
@@ -2320,20 +2350,20 @@
 	      i= new sp_instr_jump_if_not(ip, ctx, $2, lex);
 	    else
 	    { /* Simple case: <caseval> = <whenval> */
-	      LEX_STRING ivar;
 
-	      ivar.str= (char *)"_tmp_";
-	      ivar.length= 5;
-	      Item_splocal *var= new Item_splocal(ivar,
-                                                  ctx->current_pvars()-1);
+	      Item_case_expr *var;
+              Item *expr;
+
+              var= new Item_case_expr(ctx->get_current_case_expr_id());
+
 #ifndef DBUG_OFF
               if (var)
-                var->owner= sp;
+                var->m_sp= sp;
 #endif
-	      Item *expr= new Item_func_eq(var, $2);
+
+	      expr= new Item_func_eq(var, $2);
 
 	      i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
-              lex->variables_used= 1;
 	    }
 	    sp->push_backpatch(i, ctx->push_label((char *)"", 0));
             sp->add_instr(i);
@@ -5024,16 +5054,14 @@
 	  {
 	    if ($3->is_splocal())
 	    {
-	      LEX_STRING *name;
 	      Item_splocal *il= static_cast<Item_splocal *>($3);
 
-	      name= il->my_name(NULL);
-	      my_error(ER_WRONG_COLUMN_NAME, MYF(0), name->str);
+	      my_error(ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str);
 	      YYABORT;
 	    }
 	    $$= new Item_default_value(Lex->current_context(), $3);
 	  }
-	| VALUES '(' simple_ident ')'
+	| VALUES '(' simple_ident_nospvar ')'
 	  { $$= new Item_insert_value(Lex->current_context(), $3); }
 	| FUNC_ARG0 '(' ')'
 	  {
@@ -6496,7 +6524,7 @@
                  var_list.push_back(var= new my_var($1,1,t->offset,t->type));
 #ifndef DBUG_OFF
 	       if (var)
-		 var->owner= lex->sphead;
+		 var->sp= lex->sphead;
 #endif
 	     }
 	   }
@@ -7807,11 +7835,12 @@
 	  {
             /* We're compiling a stored procedure and found a variable */
             Item_splocal *splocal;
-            splocal= new Item_splocal($1, spv->offset, lex->tok_start_prev - 
+            splocal= new Item_splocal($1, spv->offset, spv->type,
+                                      lex->tok_start_prev - 
                                       lex->sphead->m_tmp_query);
 #ifndef DBUG_OFF
             if (splocal)
-              splocal->owner= lex->sphead;
+              splocal->m_sp= lex->sphead;
 #endif
 	    $$ = (Item*) splocal;
             lex->variables_used= 1;
@@ -9520,6 +9549,7 @@
 	  LEX *lex=Lex;
           lex->pop_context();
 	  lex->current_select = lex->current_select->return_after_parsing();
+          lex->nest_level--;
 	};
 
 definer:

--- 1.140/mysql-test/r/view.result	2005-12-07 06:17:10 -08:00
+++ 1.141/mysql-test/r/view.result	2005-12-12 00:11:15 -08:00
@@ -1933,11 +1933,11 @@
 DROP TABLE t1;
 CHECK TABLE v1, v2, v3, v4, v5, v6;
 Table	Op	Msg_type	Msg_text
-test.v1	check	error	Table 'test.t1' doesn't exist
+test.v1	check	error	View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
 test.v2	check	status	OK
-test.v3	check	error	Table 'test.t1' doesn't exist
+test.v3	check	error	View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
 test.v4	check	status	OK
-test.v5	check	error	Table 'test.t1' doesn't exist
+test.v5	check	error	View 'test.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
 test.v6	check	status	OK
 drop function f1;
 drop function f2;

--- 1.128/mysql-test/t/view.test	2005-12-02 22:53:14 -08:00
+++ 1.129/mysql-test/t/view.test	2005-12-12 00:11:15 -08:00
@@ -1744,7 +1744,6 @@
 CHECK TABLE v1, v2, v3, v4, v5, v6;
 create function f1 () returns int return (select max(col1) from t1);
 DROP TABLE t1;
-# following will show underlying table until BUG#11555 fix
 CHECK TABLE v1, v2, v3, v4, v5, v6;
 drop function f1;
 drop function f2;

--- 1.120/sql/item_subselect.cc	2005-11-23 12:47:27 -08:00
+++ 1.121/sql/item_subselect.cc	2005-12-12 00:11:16 -08:00
@@ -806,6 +806,7 @@
 	!(select_lex->next_select()))
     {
       Item_sum_hybrid *item;
+      nesting_map save_allow_sum_func;
       if (func->l_op())
       {
 	/*
@@ -831,6 +832,8 @@
 	it.replace(item);
       }
 
+      save_allow_sum_func= thd->lex->allow_sum_func;
+      thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
       /*
 	Item_sum_(max|min) can't substitute other item => we can use 0 as
         reference, also Item_sum_(max|min) can't be fixed after creation, so
@@ -838,6 +841,7 @@
       */
       if (item->fix_fields(thd, 0))
 	DBUG_RETURN(RES_ERROR);
+      thd->lex->allow_sum_func= save_allow_sum_func; 
       /* we added aggregate function => we have to change statistic */
       count_field_types(&join->tmp_table_param, join->all_fields, 0);
 

--- 1.36/sql/sql_trigger.cc	2005-11-23 12:47:30 -08:00
+++ 1.37/sql/sql_trigger.cc	2005-12-12 00:11:19 -08:00
@@ -1123,7 +1123,7 @@
                                            trg_action_time_type time_type,
                                            bool old_row_is_record1)
 {
-  int res= 0;
+  bool err_status= FALSE;
   sp_head *sp_trigger= bodies[event][time_type];
 
   if (sp_trigger)
@@ -1183,7 +1183,7 @@
 #endif // NO_EMBEDDED_ACCESS_CHECKS
 
     thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
-    res= sp_trigger->execute_function(thd, 0, 0, 0);
+    err_status= sp_trigger->execute_function(thd, 0, 0, 0);
     thd->restore_sub_statement_state(&statement_state);
 
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1191,7 +1191,7 @@
 #endif // NO_EMBEDDED_ACCESS_CHECKS
   }
 
-  return res;
+  return err_status;
 }
 
 

--- 1.85/mysql-test/r/show_check.result	2005-12-01 01:02:45 -08:00
+++ 1.86/mysql-test/r/show_check.result	2005-12-12 00:11:15 -08:00
@@ -1,6 +1,7 @@
 drop table if exists t1,t2;
 drop table if exists t1aa,t2aa;
 drop database if exists mysqltest;
+drop database if exists mysqltest1;
 delete from mysql.user where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
 delete from mysql.db where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
 flush privileges;

--- 1.58/mysql-test/t/show_check.test	2005-12-01 01:02:45 -08:00
+++ 1.59/mysql-test/t/show_check.test	2005-12-12 00:11:15 -08:00
@@ -10,6 +10,7 @@
 drop table if exists t1,t2;
 drop table if exists t1aa,t2aa;
 drop database if exists mysqltest;
+drop database if exists mysqltest1;
 
 delete from mysql.user where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
 delete from mysql.db where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';

--- 1.176/mysql-test/r/sp.result	2005-12-07 07:58:03 -08:00
+++ 1.177/mysql-test/r/sp.result	2005-12-12 00:11:15 -08:00
@@ -248,13 +248,13 @@
 call sub1("sub1a", (select 7))|
 call sub1("sub1b", (select max(i) from t2))|
 call sub1("sub1c", (select i,d from t2 limit 1))|
+ERROR 21000: Operand should contain 1 column(s)
 call sub1("sub1d", (select 1 from (select 1) a))|
 call sub2("sub2")|
 select * from t1|
 id	data
 sub1a	7
 sub1b	3
-sub1c	1
 sub1d	1
 sub2	6
 select sub3((select max(i) from t2))|
@@ -2686,7 +2686,7 @@
 s	x	y	z
 16	3	1	6
 a
-3.2000
+3.2
 drop procedure bug8937|
 delete from t1|
 drop procedure if exists bug6900|
@@ -2890,21 +2890,30 @@
 select bug9775('a'),bug9775('b'),bug9775('c')|
 bug9775('a')	bug9775('b')	bug9775('c')
 a	b	
+Warnings:
+Warning	1265	Data truncated for column 'bug9775('c')' at row 1
 drop function bug9775|
 create function bug9775(v1 int) returns enum('a','b') return v1|
 select bug9775(1),bug9775(2),bug9775(3)|
 bug9775(1)	bug9775(2)	bug9775(3)
 a	b	
+Warnings:
+Warning	1265	Data truncated for column 'bug9775(3)' at row 1
 drop function bug9775|
 create function bug9775(v1 char(1)) returns set('a','b') return v1|
 select bug9775('a'),bug9775('b'),bug9775('a,b'),bug9775('c')|
 bug9775('a')	bug9775('b')	bug9775('a,b')	bug9775('c')
-a	b	a,b	
+a	b	a	
+Warnings:
+Warning	1265	Data truncated for column 'v1' at row 1
+Warning	1265	Data truncated for column 'bug9775('c')' at row 1
 drop function bug9775|
 create function bug9775(v1 int) returns set('a','b') return v1|
 select bug9775(1),bug9775(2),bug9775(3),bug9775(4)|
 bug9775(1)	bug9775(2)	bug9775(3)	bug9775(4)
 a	b	a,b	
+Warnings:
+Warning	1265	Data truncated for column 'bug9775(4)' at row 1
 drop function bug9775|
 drop function if exists bug8861|
 create function bug8861(v1 int) returns year return v1|
@@ -2927,12 +2936,10 @@
 call bug9004_1(x)|
 call bug9004_1('12345678901234567')|
 Warnings:
-Warning	1265	Data truncated for column 'id' at row 1
-Warning	1265	Data truncated for column 'id' at row 2
+Warning	1265	Data truncated for column 'x' at row 1
 call bug9004_2('12345678901234567890')|
 Warnings:
-Warning	1265	Data truncated for column 'id' at row 1
-Warning	1265	Data truncated for column 'id' at row 2
+Warning	1265	Data truncated for column 'x' at row 1
 delete from t1|
 drop procedure bug9004_1|
 drop procedure bug9004_2|
@@ -3527,14 +3534,15 @@
 call bug12589_1()|
 Table	Create Table
 tm1	CREATE TEMPORARY TABLE `tm1` (
-  `spv1` decimal(1,0) unsigned default NULL
+  `spv1` decimal(3,3) default NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 Warnings:
-Warning	1292	Truncated incorrect DECIMAL value: 'test'
+Warning	1264	Out of range value adjusted for column 'spv1' at row 1
+Warning	1366	Incorrect decimal value: 'test' for column 'spv1' at row 1
 call bug12589_2()|
 Table	Create Table
 tm1	CREATE TEMPORARY TABLE `tm1` (
-  `spv1` decimal(6,3) unsigned default NULL
+  `spv1` decimal(6,3) default NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 call bug12589_3()|
 Table	Create Table
@@ -4016,34 +4024,37 @@
 begin
 declare continue handler for sqlexception select 'boo' as 'Handler';
 begin
-declare v int default x;
+declare v int default undefined_var;
 if v = 1 then
 select 1;
 else
-select 2;
+select v, isnull(v);
 end if;
 end;
 end|
 create procedure bug14643_2()
 begin
 declare continue handler for sqlexception select 'boo' as 'Handler';
-case x
+case undefined_var
 when 1 then
 select 1;
 else
 select 2;
 end case;
+select undefined_var;
 end|
 call bug14643_1()|
 Handler
 boo
-2
-2
+v	isnull(v)
+NULL	1
 call bug14643_2()|
 Handler
 boo
 2
 2
+Handler
+boo
 drop procedure bug14643_1|
 drop procedure bug14643_2|
 drop procedure if exists bug14304|
@@ -4099,23 +4110,23 @@
 x
 4711
 drop procedure bug14376|
-drop procedure if exists p1|
-drop table if exists t1|
-create table t1 (a varchar(255))|
-insert into t1 (a) values ("a - table column")|
-create procedure p1(a varchar(255))
+drop procedure if exists bug5967|
+drop table if exists t3|
+create table t3 (a varchar(255))|
+insert into t3 (a) values ("a - table column")|
+create procedure bug5967(a varchar(255))
 begin
 declare i varchar(255);
-declare c cursor for select a from t1;
+declare c cursor for select a from t3;
 select a;
-select a from t1 into i;
+select a from t3 into i;
 select i as 'Parameter takes precedence over table column';                     open c;
 fetch c into i;
 close c;
 select i as 'Parameter takes precedence over table column in cursors';
 begin
 declare a varchar(255) default 'a - local variable';
-declare c1 cursor for select a from t1;
+declare c1 cursor for select a from t3;
 select a as 'A local variable takes precedence over parameter';
 open c1;
 fetch c1 into i;
@@ -4123,9 +4134,9 @@
 select i as 'A local variable takes precedence over parameter in cursors';
 begin
 declare a varchar(255) default 'a - local variable in a nested compound statement';
-declare c2 cursor for select a from t1;
+declare c2 cursor for select a from t3;
 select a as 'A local variable in a nested compound statement takes precedence over a local variable in the outer statement';
-select a from t1 into i;
+select a from t3 into i;
 select i as  'A local variable in a nested compound statement takes precedence over table column';
 open c2;
 fetch c2 into i;
@@ -4134,7 +4145,7 @@
 end;
 end;
 end|
-call p1("a - stored procedure parameter")|
+call bug5967("a - stored procedure parameter")|
 a
 a - stored procedure parameter
 Parameter takes precedence over table column
@@ -4151,7 +4162,7 @@
 a - local variable in a nested compound statement
 A local variable in a nested compound statement takes precedence over table column in cursors
 a - local variable in a nested compound statement
-drop procedure p1|
+drop procedure bug5967|
 drop procedure if exists bug13012|
 create procedure bug13012()
 BEGIN
@@ -4179,17 +4190,17 @@
 Table	Op	Msg_type	Msg_text
 test.t1	repair	status	OK
 test.t2	repair	status	OK
-test.t3	repair	error	Table 'test.t3' doesn't exist
+test.t3	repair	status	OK
 test.v1	repair	error	'test.v1' is not BASE TABLE
 Table	Op	Msg_type	Msg_text
 test.t1	optimize	status	OK
 test.t2	optimize	status	OK
-test.t3	optimize	error	Table 'test.t3' doesn't exist
+test.t3	optimize	status	OK
 test.v1	optimize	error	'test.v1' is not BASE TABLE
 Table	Op	Msg_type	Msg_text
 test.t1	analyze	status	Table is already up to date
 test.t2	analyze	status	Table is already up to date
-test.t3	analyze	error	Table 'test.t3' doesn't exist
+test.t3	analyze	status	Table is already up to date
 test.v1	analyze	error	'test.v1' is not BASE TABLE
 Warnings:
 Error	1146	Table 'test.t3' doesn't exist
@@ -4202,17 +4213,17 @@
 Table	Op	Msg_type	Msg_text
 test.t1	repair	status	OK
 test.t2	repair	status	OK
-test.t3	repair	error	Table 'test.t3' doesn't exist
+test.t3	repair	status	OK
 test.v1	repair	error	'test.v1' is not BASE TABLE
 Table	Op	Msg_type	Msg_text
 test.t1	optimize	status	OK
 test.t2	optimize	status	OK
-test.t3	optimize	error	Table 'test.t3' doesn't exist
+test.t3	optimize	status	OK
 test.v1	optimize	error	'test.v1' is not BASE TABLE
 Table	Op	Msg_type	Msg_text
 test.t1	analyze	status	Table is already up to date
 test.t2	analyze	status	Table is already up to date
-test.t3	analyze	error	Table 'test.t3' doesn't exist
+test.t3	analyze	status	Table is already up to date
 test.v1	analyze	error	'test.v1' is not BASE TABLE
 Warnings:
 Error	1146	Table 'test.t3' doesn't exist
@@ -4225,17 +4236,17 @@
 Table	Op	Msg_type	Msg_text
 test.t1	repair	status	OK
 test.t2	repair	status	OK
-test.t3	repair	error	Table 'test.t3' doesn't exist
+test.t3	repair	status	OK
 test.v1	repair	error	'test.v1' is not BASE TABLE
 Table	Op	Msg_type	Msg_text
 test.t1	optimize	status	OK
 test.t2	optimize	status	OK
-test.t3	optimize	error	Table 'test.t3' doesn't exist
+test.t3	optimize	status	OK
 test.v1	optimize	error	'test.v1' is not BASE TABLE
 Table	Op	Msg_type	Msg_text
 test.t1	analyze	status	Table is already up to date
 test.t2	analyze	status	Table is already up to date
-test.t3	analyze	error	Table 'test.t3' doesn't exist
+test.t3	analyze	status	Table is already up to date
 test.v1	analyze	error	'test.v1' is not BASE TABLE
 Warnings:
 Error	1146	Table 'test.t3' doesn't exist
@@ -4247,8 +4258,17 @@
 drop procedure bug13012|
 drop view v1;
 select * from t1|
-a
-a - table column
+id	data
+aa	0
+aa	1
+aa	2
+aa	3
+aa	4
+aa	5
+aa	6
+aa	7
+aa	8
+aa	9
 drop schema if exists mysqltest1|
 Warnings:
 Note	1008	Can't drop database 'mysqltest1'; database doesn't exist
@@ -4288,4 +4308,31 @@
 drop schema if exists mysqltest2|
 drop schema if exists mysqltest3|
 use test|
+drop table if exists t3|
+drop procedure if exists bug15441|
+create table t3 (id int not null primary key, county varchar(25))|
+insert into t3 (id, county) values (1, 'York')|
+create procedure bug15441(c varchar(25))
+begin
+update t3 set id=2, county=values(c);
+end|
+call bug15441('county')|
+ERROR 42S22: Unknown column 'c' in 'field list'
+drop procedure bug15441|
+create procedure bug15441(county varchar(25))
+begin
+declare c varchar(25) default "hello";
+insert into t3 (id, county) values (1, county)
+on duplicate key update county= values(county);
+select * from t3;
+update t3 set id=2, county=values(id);
+select * from t3;
+end|
+call bug15441('Yale')|
+id	county
+1	Yale
+id	county
+2	NULL
+drop table t3|
+drop procedure bug15441|
 drop table t1,t2;

--- 1.98/sql/sp.cc	2005-12-07 02:19:38 -08:00
+++ 1.99/sql/sp.cc	2005-12-12 00:11:17 -08:00
@@ -468,7 +468,7 @@
   bzero((char*) &share, sizeof(share));
   table.in_use= thd;
   table.s = &share;
-  field= sp->make_field(0, 0, &table);
+  field= sp->create_result_field(0, 0, &table);
   field->sql_type(result);
   delete field;
 }
@@ -1200,6 +1200,12 @@
     for LEX::sroutine/sroutine_list and sp_head::m_sroutines.
   */
   Sroutine_hash_entry *next;
+  /*
+    Uppermost view which directly or indirectly uses this routine.
+    0 if routine is not used in view. Note that it also can be 0 if
+    statement uses routine both via view and directly.
+  */
+  TABLE_LIST *belong_to_view;
 };
 
 
@@ -1254,9 +1260,11 @@
 
   SYNOPSIS
     add_used_routine()
-      lex     - LEX representing statement
-      arena   - arena in which memory for new element will be allocated
-      key     - key for the hash representing set
+      lex             LEX representing statement
+      arena           Arena in which memory for new element will be allocated
+      key             Key for the hash representing set
+      belong_to_view  Uppermost view which uses this routine
+                      (0 if routine is not used by view)
 
   NOTES
     Will also add element to end of 'LEX::sroutines_list' list.
@@ -1279,7 +1287,8 @@
 */
 
 static bool add_used_routine(LEX *lex, Query_arena *arena,
-                             const LEX_STRING *key)
+                             const LEX_STRING *key,
+                             TABLE_LIST *belong_to_view)
 {
   if (!hash_search(&lex->sroutines, (byte *)key->str, key->length))
   {
@@ -1293,6 +1302,7 @@
     memcpy(rn->key.str, key->str, key->length);
     my_hash_insert(&lex->sroutines, (byte *)rn);
     lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next);
+    rn->belong_to_view= belong_to_view;
     return TRUE;
   }
   return FALSE;
@@ -1323,7 +1333,7 @@
                          sp_name *rt, char rt_type)
 {
   rt->set_routine_type(rt_type);
-  (void)add_used_routine(lex, arena, &rt->m_sroutines_key);
+  (void)add_used_routine(lex, arena, &rt->m_sroutines_key, 0);
   lex->sroutines_list_own_last= lex->sroutines_list.next;
   lex->sroutines_list_own_elements= lex->sroutines_list.elements;
 }
@@ -1393,20 +1403,23 @@
 
   SYNOPSIS
     sp_update_stmt_used_routines()
-      thd - thread context
-      lex - LEX representing statement
-      src - hash representing set from which routines will be added
+      thd             Thread context
+      lex             LEX representing statement
+      src             Hash representing set from which routines will be added
+      belong_to_view  Uppermost view which uses these routines, 0 if none
 
   NOTE
     It will also add elements to end of 'LEX::sroutines_list' list.
 */
 
-static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src)
+static void
+sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src,
+                             TABLE_LIST *belong_to_view)
 {
   for (uint i=0 ; i < src->records ; i++)
   {
     Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i);
-    (void)add_used_routine(lex, thd->stmt_arena, &rt->key);
+    (void)add_used_routine(lex, thd->stmt_arena, &rt->key, belong_to_view);
   }
 }
 
@@ -1417,19 +1430,21 @@
 
   SYNOPSIS
     sp_update_stmt_used_routines()
-      thd  Thread context
-      lex  LEX representing statement
-      src  List representing set from which routines will be added
+      thd             Thread context
+      lex             LEX representing statement
+      src             List representing set from which routines will be added
+      belong_to_view  Uppermost view which uses these routines, 0 if none
 
   NOTE
     It will also add elements to end of 'LEX::sroutines_list' list.
 */
 
-static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src)
+static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src,
+                                         TABLE_LIST *belong_to_view)
 {
   for (Sroutine_hash_entry *rt= (Sroutine_hash_entry *)src->first;
        rt; rt= rt->next)
-    (void)add_used_routine(lex, thd->stmt_arena, &rt->key);
+    (void)add_used_routine(lex, thd->stmt_arena, &rt->key, belong_to_view);
 }
 
 
@@ -1534,9 +1549,11 @@
     {
       if (!(first && first_no_prelock))
       {
-        sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines);
+        sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines,
+                                     rt->belong_to_view);
         tabschnd|=
-          sp->add_used_tables_to_table_list(thd, &lex->query_tables_last);
+          sp->add_used_tables_to_table_list(thd, &lex->query_tables_last,
+                                            rt->belong_to_view);
       }
     }
     first= FALSE;
@@ -1582,21 +1599,22 @@
 
   SYNOPSIS
     sp_cache_routines_and_add_tables_for_view()
-      thd     - thread context
-      lex     - LEX representing statement
-      aux_lex - LEX representing view
-                         
+      thd   Thread context
+      lex   LEX representing statement
+      view  Table list element representing view
+
   RETURN VALUE
      0     - success
      non-0 - failure
 */
 
 int
-sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex)
+sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, TABLE_LIST *view)
 {
   Sroutine_hash_entry **last_cached_routine_ptr=
                           (Sroutine_hash_entry **)lex->sroutines_list.next;
-  sp_update_stmt_used_routines(thd, lex, &aux_lex->sroutines_list);
+  sp_update_stmt_used_routines(thd, lex, &view->view->sroutines_list,
+                               view->top_table());
   return sp_cache_routines_and_add_tables_aux(thd, lex, 
                                               *last_cached_routine_ptr, FALSE,
                                               NULL);
@@ -1610,9 +1628,9 @@
 
   SYNOPSIS
     sp_cache_routines_and_add_tables_for_triggers()
-      thd      - thread context
-      lex      - LEX respresenting statement
-      triggers - triggers of the table
+      thd    thread context
+      lex    LEX respresenting statement
+      table  Table list element for table with trigger
 
   RETURN VALUE
      0     - success
@@ -1621,11 +1639,12 @@
 
 int
 sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
-                                              Table_triggers_list *triggers)
+                                              TABLE_LIST *table)
 {
   int ret= 0;
-
-  if (add_used_routine(lex, thd->stmt_arena, &triggers->sroutines_key))
+  Table_triggers_list *triggers= table->table->triggers;
+  if (add_used_routine(lex, thd->stmt_arena, &triggers->sroutines_key,
+                       table->belong_to_view))
   {
     Sroutine_hash_entry **last_cached_routine_ptr=
                             (Sroutine_hash_entry **)lex->sroutines_list.next;
@@ -1635,10 +1654,12 @@
       {
         if (triggers->bodies[i][j])
         {
-          (void)triggers->bodies[i][j]->add_used_tables_to_table_list(thd,
-                                          &lex->query_tables_last);
+          (void)triggers->bodies[i][j]->
+                add_used_tables_to_table_list(thd, &lex->query_tables_last,
+                                              table->belong_to_view);
           sp_update_stmt_used_routines(thd, lex,
-                                       &triggers->bodies[i][j]->m_sroutines);
+                                       &triggers->bodies[i][j]->m_sroutines,
+                                       table->belong_to_view);
         }
       }
     }

--- 1.204/sql/sp_head.cc	2005-12-07 06:17:10 -08:00
+++ 1.205/sql/sp_head.cc	2005-12-12 00:29:29 -08:00
@@ -27,8 +27,7 @@
 Item_result
 sp_map_result_type(enum enum_field_types type)
 {
-  switch (type)
-  {
+  switch (type) {
   case MYSQL_TYPE_TINY:
   case MYSQL_TYPE_SHORT:
   case MYSQL_TYPE_LONG:
@@ -46,6 +45,81 @@
   }
 }
 
+
+Item::Type
+sp_map_item_type(enum enum_field_types type)
+{
+  switch (type) {
+  case MYSQL_TYPE_TINY:
+  case MYSQL_TYPE_SHORT:
+  case MYSQL_TYPE_LONG:
+  case MYSQL_TYPE_LONGLONG:
+  case MYSQL_TYPE_INT24:
+    return Item::INT_ITEM;
+  case MYSQL_TYPE_DECIMAL:
+  case MYSQL_TYPE_NEWDECIMAL:
+    return Item::DECIMAL_ITEM;
+  case MYSQL_TYPE_FLOAT:
+  case MYSQL_TYPE_DOUBLE:
+    return Item::REAL_ITEM;
+  default:
+    return Item::STRING_ITEM;
+  }
+}
+
+
+/*
+  Return a string representation of the Item value.
+
+  NOTE: this is a legacy-compatible implementation. It fails if the value
+  contains non-ordinary symbols, which should be escaped.
+
+  SYNOPSIS
+    item    a pointer to the Item
+    str     string buffer for representation of the value
+
+  RETURN
+    NULL  on error
+    a pointer to valid a valid string on success
+*/
+
+static String *
+sp_get_item_value(Item *item, String *str)
+{
+  Item_result result_type= item->result_type();
+
+  switch (item->result_type()) {
+  case REAL_RESULT:
+  case INT_RESULT:
+  case DECIMAL_RESULT:
+    return item->val_str(str);
+
+  case STRING_RESULT:
+    {
+      char buf_holder[STRING_BUFFER_USUAL_SIZE];
+      String buf(buf_holder, sizeof(buf_holder), &my_charset_latin1);
+      String *result= item->val_str(str);
+      
+      if (!result)
+        return NULL;
+      
+      buf.append('_');
+      buf.append(result->charset()->csname);
+      buf.append('\'');
+      buf.append(*result);
+      buf.append('\'');
+      str->copy(buf);
+
+      return str;
+    }
+
+  case ROW_RESULT:
+  default:
+    return NULL;
+  }
+}
+
+
 /*
   SYNOPSIS
     sp_get_flags_for_command()
@@ -177,7 +251,7 @@
 
 
 /*
-  Prepare Item for execution (call of fix_fields)
+  Prepare an Item for evaluation (call of fix_fields).
 
   SYNOPSIS
     sp_prepare_func_item()
@@ -189,14 +263,15 @@
     prepared item
 */
 
-static Item *
+Item *
 sp_prepare_func_item(THD* thd, Item **it_addr)
 {
-  Item *it= *it_addr;
   DBUG_ENTER("sp_prepare_func_item");
-  it_addr= it->this_item_addr(thd, it_addr);
+  it_addr= (*it_addr)->this_item_addr(thd, it_addr);
 
-  if (!it->fixed && (*it_addr)->fix_fields(thd, it_addr))
+  if (!(*it_addr)->fixed &&
+      ((*it_addr)->fix_fields(thd, it_addr) ||
+       (*it_addr)->check_cols(1)))
   {
     DBUG_PRINT("info", ("fix_fields() failed"));
     DBUG_RETURN(NULL);
@@ -205,206 +280,62 @@
 }
 
 
-/* Macro to switch arena in sp_eval_func_item */
-#define CREATE_ON_CALLERS_ARENA(new_command, condition, backup_arena)   \
-  do                                                                    \
-  {                                                                     \
-    if (condition)                                                      \
-      thd->set_n_backup_active_arena(thd->spcont->callers_arena,        \
-                                     backup_arena);                     \
-    new_command;                                                        \
-    if (condition)                                                      \
-      thd->restore_active_arena(thd->spcont->callers_arena,             \
-                                backup_arena);                          \
-  } while(0)
-
 /*
-  Evaluate an item and store it in the returned item
+  Evaluate an expression and store the result in the field.
 
   SYNOPSIS
-    sp_eval_func_item()
-      name                  - current thread object
-      it_addr               - pointer to the item to evaluate
-      type                  - type of the item we evaluating
-      reuse                 - used if we would like to reuse existing item
-                              instead of allocation of the new one
-      use_callers_arena     - TRUE if we want to use caller's arena
-                              rather then current one.
-  DESCRIPTION
-   We use this function to evaluate result for stored functions
-   and stored procedure parameters. It is also used to evaluate and
-   (re) allocate variables.
+    sp_eval_expr()
+      thd                   - current thread object
+      expr_item             - the root item of the expression
+      result_field          - the field to store the result
 
   RETURN VALUES
-    Evaluated item is returned
+    FALSE  on success
+    TRUE   on error
 */
 
-Item *
-sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
-		  Item *reuse, bool use_callers_arena)
+bool
+sp_eval_expr(THD *thd, Field *result_field, Item *expr_item)
 {
-  DBUG_ENTER("sp_eval_func_item");
-  Item *it= sp_prepare_func_item(thd, it_addr);
-  uint rsize;
-  Query_arena backup_arena;
-  Item *old_item_next, *old_free_list, **p_free_list;
-  DBUG_PRINT("info", ("type: %d", type));
+DBUG_ENTER("sp_eval_expr");
 
-  LINT_INIT(old_item_next);
-  LINT_INIT(old_free_list);
-  LINT_INIT(p_free_list);
+  if (!(expr_item= sp_prepare_func_item(thd, &expr_item)))
+    DBUG_RETURN(TRUE);
 
-  if (!it)
-    DBUG_RETURN(NULL);
+  bool err_status= FALSE;
 
-  if (reuse)
-  {
-    old_item_next= reuse->next;
-    p_free_list= use_callers_arena ? &thd->spcont->callers_arena->free_list :
-                                     &thd->free_list;
-    old_free_list= *p_free_list;
-  }
-
-  switch (sp_map_result_type(type)) {
-  case INT_RESULT:
-  {
-    longlong i= it->val_int();
-
-    if (it->null_value)
-    {
-      DBUG_PRINT("info", ("INT_RESULT: null"));
-      goto return_null_item;
-    }
-    DBUG_PRINT("info", ("INT_RESULT: %d", i));
-    CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_int(i),
-                            use_callers_arena, &backup_arena);
-    break;
-  }
-  case REAL_RESULT:
-  {
-    double d= it->val_real();
-    uint8 decimals;
-    uint32 max_length;
+  /*
+    Set THD flags to emit warnings/errors in case of overflow/type errors
+    during saving the item into the field.
 
-    if (it->null_value)
-    {
-      DBUG_PRINT("info", ("REAL_RESULT: null"));
-      goto return_null_item;
-    }
+    Save original values and restore them after save.
+  */
+  
+  enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
+  bool save_abort_on_warning= thd->abort_on_warning;
+  bool save_no_trans_update= thd->no_trans_update;
 
-    /*
-      There's some difference between Item::new_item() and the
-      constructor; the former crashes, the latter works... weird.
-    */
-    decimals= it->decimals;
-    max_length= it->max_length;
-    DBUG_PRINT("info", ("REAL_RESULT: %g", d));
-    CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_float(d),
-                            use_callers_arena, &backup_arena);
-    it->decimals= decimals;
-    it->max_length= max_length;
-    break;
-  }
-  case DECIMAL_RESULT:
-  {
-    my_decimal value, *val= it->val_decimal(&value);
-    if (it->null_value)
-      goto return_null_item;
-    CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_decimal(val),
-                            use_callers_arena, &backup_arena);
-#ifndef DBUG_OFF
-    {
-      char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
-      DBUG_PRINT("info", ("DECIMAL_RESULT: %s",
-                          dbug_decimal_as_string(dbug_buff, val)));
-    }
-#endif
-    break;
-  }
-  case STRING_RESULT:
-  {
-    char buffer[MAX_FIELD_WIDTH];
-    String tmp(buffer, sizeof(buffer), it->collation.collation);
-    String *s= it->val_str(&tmp);
+  thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
+  thd->abort_on_warning=
+    thd->variables.sql_mode &
+    (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES);
+  thd->no_trans_update= 0;
 
-    if (type == MYSQL_TYPE_NULL || it->null_value)
-    {
-      DBUG_PRINT("info", ("STRING_RESULT: null"));
-      goto return_null_item;
-    }
-    DBUG_PRINT("info",("STRING_RESULT: %.*s",
-                       s->length(), s->c_ptr_quick()));
-    /*
-      Reuse mechanism in sp_eval_func_item() is only employed for assignments
-      to local variables and OUT/INOUT SP parameters repsesented by
-      Item_splocal. Usually we have some expression, which needs
-      to be calculated and stored into the local variable. However in the
-      case if "it" equals to "reuse", there is no "calculation" step. So,
-      no reason to employ reuse mechanism to save variable into itself.
-    */
-    if (it == reuse)
-      DBUG_RETURN(it);
+  /* Save the value in the field. Convert the value if needed. */
 
-    /*
-      For some functions, 's' is now pointing to an argument of the
-      function, which might be a local variable that is to be reused.
-      In this case, new(reuse, &rsize) below will call the destructor
-      and 's' ends up pointing to freed memory.
-      A somewhat ugly fix is to simply copy the string to our local one
-      (which is unused by most functions anyway), but only if 's' is
-      pointing somewhere else than to 'tmp' or 'it->str_value'.
-     */
-    if (reuse && s != &tmp && s != &it->str_value)
-    {
-      if (tmp.copy((const String)(*s)))
-        DBUG_RETURN(NULL);
-      s= &tmp;
-    }
-
-    CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize)
-                            Item_string(it->collation.collation),
-                            use_callers_arena, &backup_arena);
-    /*
-      We have to use special constructor and allocate string
-      on system heap here. This is because usual Item_string
-      constructor would allocate memory in the callers arena.
-      This would lead to the memory leak in SP loops.
-      See Bug #11333 "Stored Procedure: Memory blow up on
-      repeated SELECT ... INTO query" for sample of such SP.
-      TODO: Usage of the system heap gives significant overhead,
-      however usual "reuse" mechanism does not work here, as
-      Item_string has no max size. That is, if we have a loop, which
-      has string variable with constantly increasing size, we would have
-      to allocate new pieces of memory again and again on each iteration.
-      In future we should probably reserve some area of memory for
-      not-very-large strings and reuse it. But for large strings
-      we would have to use system heap anyway.
-    */
-    ((Item_string*) it)->set_str_with_copy(s->ptr(), s->length());
-    break;
-  }
-  case ROW_RESULT:
-  default:
-    DBUG_ASSERT(0);
-  }
-  goto end;
+  expr_item->save_in_field(result_field, 0);
 
-return_null_item:
-  CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_null(),
-                          use_callers_arena, &backup_arena);
-end:
-  it->rsize= rsize;
+  thd->count_cuted_fields= save_count_cuted_fields;
+  thd->abort_on_warning= save_abort_on_warning;
+  thd->no_trans_update= save_no_trans_update;
 
-  if (reuse && it == reuse)
+  if (thd->net.report_error)
   {
-    /*
-      The Item constructor registered itself in the arena free list,
-      while the item slot is reused, so we have to restore the list.
-    */
-    it->next= old_item_next;
-    *p_free_list= old_free_list;
+    /* Return error status if something went wrong. */
+    err_status= TRUE;
   }
-  DBUG_RETURN(it);
+
+  DBUG_RETURN(err_status);
 }
 
 
@@ -489,9 +420,11 @@
 
 sp_head::sp_head()
   :Query_arena(&main_mem_root, INITIALIZED_FOR_SP),
-   m_flags(0), m_returns_cs(NULL), m_recursion_level(0), m_next_cached_sp(0),
+   m_flags(0), m_recursion_level(0), m_next_cached_sp(0),
    m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this)
 {
+  m_return_field_def.charset = NULL;
+
   extern byte *
     sp_table_key(const byte *ptr, uint *plen, my_bool first);
   DBUG_ENTER("sp_head::sp_head");
@@ -510,6 +443,7 @@
   DBUG_ENTER("sp_head::init");
 
   lex->spcont= m_pcont= new sp_pcontext(NULL);
+
   /*
     Altough trg_table_fields list is used only in triggers we init for all
     types of stored procedures to simplify reset_lex()/restore_lex() code.
@@ -521,7 +455,7 @@
     m_body.str= m_defstr.str= 0;
   m_qname.length= m_db.length= m_name.length= m_params.length=
     m_body.length= m_defstr.length= 0;
-  m_returns_cs= NULL;
+  m_return_field_def.charset= NULL;
   DBUG_VOID_RETURN;
 }
 
@@ -580,12 +514,13 @@
   DBUG_VOID_RETURN;
 }
 
-TYPELIB *
-sp_head::create_typelib(List<String> *src)
+
+static TYPELIB *
+create_typelib(MEM_ROOT *mem_root, create_field *field_def, List<String> *src)
 {
   TYPELIB *result= NULL;
-  CHARSET_INFO *cs= m_returns_cs;
-  DBUG_ENTER("sp_head::clone_typelib");
+  CHARSET_INFO *cs= field_def->charset;
+  DBUG_ENTER("create_typelib");
   if (src->elements)
   {
     result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB));
@@ -630,6 +565,7 @@
   return result;
 }
 
+
 int
 sp_head::create(THD *thd)
 {
@@ -717,19 +653,30 @@
 */
 
 Field *
-sp_head::make_field(uint max_length, const char *name, TABLE *dummy)
+sp_head::create_result_field(uint field_max_length, const char *field_name,
+                             TABLE *table)
 {
+  uint field_length;
   Field *field;
-  DBUG_ENTER("sp_head::make_field");
+<
+  DBUG_ENTER("sp_head::create_result_field");
+
+  field_length= !m_return_field_def.length ?
+                field_max_length : m_return_field_def.length;
 
-  field= ::make_field(dummy->s, (char *)0,
-                      !m_returns_len ? max_length : m_returns_len, 
-                      (uchar *)"", 0, m_returns_pack, m_returns, m_returns_cs,
-                      m_geom_returns, Field::NONE, 
-                      m_returns_typelib,
-                      name ? name : (const char *)m_name.str);
-  if (field)
-    field->init(dummy);
+  field= ::make_field((char*) 0,                    /* field ptr */
+                      field_length,                 /* field [max] length */
+                      (uchar*) "",                  /* null ptr */
+                      0,                            /* null bit */
+                      m_return_field_def.pack_flag,
+                      m_return_field_def.sql_type,
+                      m_return_field_def.charset,
+                      m_return_field_def.geom_type,
+                      Field::NONE,                  /* unreg check */
+                      m_return_field_def.interval,
+                      field_name ? field_name : (const char *) m_name.str,
+                      table);
+  
   DBUG_RETURN(field);
 }
 
@@ -827,12 +774,14 @@
   variables with NAME_CONST('sp_var_name', value) calls.
  
   RETURN
-    0  Ok, thd->query{_length} either has been appropriately replaced or
-       there is no need for replacements.
-    1  Out of memory error.
+    FALSE  on success
+           thd->query{_length} either has been appropriately replaced or there
+           is no need for replacements.
+    TRUE   out of memory error.
 */
 
-static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
+static bool
+subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
 {
   DBUG_ENTER("subst_spvars");
   if (thd->prelocked_mode == NON_PRELOCKED && mysql_bin_log.is_open())
@@ -842,7 +791,7 @@
     String qbuf(buffer, sizeof(buffer), &my_charset_bin);
     int prev_pos, res;
 
-    /* Find all instances of item_splocal used in this statement */
+    /* Find all instances of Item_splocal used in this statement */
     for (Item *item= instr->free_list; item; item= item->next)
     {
       if (item->is_splocal())
@@ -853,7 +802,7 @@
       }
     }
     if (!sp_vars_uses.elements())
-      DBUG_RETURN(0);
+      DBUG_RETURN(FALSE);
       
     /* Sort SP var refs by their occurences in the query */
     sp_vars_uses.sort(cmp_splocal_locations);
@@ -869,7 +818,12 @@
          splocal < sp_vars_uses.back(); splocal++)
     {
       Item *val;
-      (*splocal)->thd= thd;            // fix_fields() is not yet done
+
+      char str_buffer[STRING_BUFFER_USUAL_SIZE];
+      String str_value_holder(str_buffer, sizeof(str_buffer),
+                              &my_charset_latin1);
+      String *str_value;
+      
       /* append the text between sp ref occurences */
       res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos);
       prev_pos= (*splocal)->pos_in_query + (*splocal)->m_name.length;
@@ -878,24 +832,33 @@
       res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('"));
       res|= qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length);
       res|= qbuf.append(STRING_WITH_LEN("',"));
+      res|= (*splocal)->fix_fields(thd, (Item **) splocal);
+
+      if (res)
+        break;
+
       val= (*splocal)->this_item();
       DBUG_PRINT("info", ("print %p", val));
-      val->print(&qbuf);
+      str_value= sp_get_item_value(val, &str_value_holder);
+      if (str_value)
+        res|= qbuf.append(*str_value);
+      else
+        res|= qbuf.append(STRING_WITH_LEN("NULL"));
       res|= qbuf.append(')');
       if (res)
         break;
     }
     res|= qbuf.append(cur + prev_pos, query_str->length - prev_pos);
     if (res)
-      DBUG_RETURN(1);
+      DBUG_RETURN(TRUE);
 
     if (!(pbuf= thd->strmake(qbuf.ptr(), qbuf.length())))
-      DBUG_RETURN(1);
+      DBUG_RETURN(TRUE);
 
     thd->query= pbuf;
     thd->query_length= qbuf.length();
   }
-  DBUG_RETURN(0);
+  DBUG_RETURN(FALSE);
 }
 
 
@@ -929,17 +892,19 @@
   Assume the parameters already set.
   
   RETURN
-    -1  on error
+    FALSE  on success
+    TRUE   on error
 
 */
 
-int sp_head::execute(THD *thd)
+bool
+sp_head::execute(THD *thd)
 {
   DBUG_ENTER("sp_head::execute");
   char olddb[128];
   bool dbchanged;
   sp_rcontext *ctx;
-  int ret= 0;
+  bool err_status= FALSE;
   uint ip= 0;
   ulong save_sql_mode;
   Query_arena *old_arena;
@@ -955,9 +920,7 @@
 
   /* Use some extra margin for possible SP recursion and functions */
   if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (char*)&old_packet))
-  {
-    DBUG_RETURN(-1);
-  }
+    DBUG_RETURN(TRUE);
 
   /* init per-instruction memroot */
   init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
@@ -985,7 +948,8 @@
 
   dbchanged= FALSE;
   if (m_db.length &&
-      (ret= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0, &dbchanged)))
+      (err_status= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0,
+                                 &dbchanged)))
     goto done;
 
   if ((ctx= thd->spcont))
@@ -1063,7 +1027,7 @@
     if (thd->prelocked_mode == NON_PRELOCKED)
       thd->user_var_events_alloc= thd->mem_root;
     
-    ret= i->execute(thd, &ip);
+    err_status= i->execute(thd, &ip);
 
     /*
       If this SP instruction have sent eof, it has caused no_send_error to be
@@ -1091,11 +1055,10 @@
 
     /*
       Check if an exception has occurred and a handler has been found
-      Note: We havo to check even if ret==0, since warnings (and some
-      errors don't return a non-zero value.
-      We also have to check even if thd->killed != 0, since some
-      errors return with this even when a handler has been found
-      (e.g. "bad data").
+      Note: We have to check even if err_status == FALSE, since warnings (and
+      some errors) don't return a non-zero value. We also have to check even
+      if thd->killed != 0, since some errors return with this even when a
+      handler has been found (e.g. "bad data").
     */
     if (ctx)
     {
@@ -1106,13 +1069,12 @@
 	break;
       case SP_HANDLER_CONTINUE:
         thd->restore_active_arena(&execute_arena, &backup_arena);
-        ctx->save_variables(hf);
         thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
         ctx->push_hstack(ip);
         // Fall through
       default:
 	ip= hip;
-	ret= 0;
+	err_status= FALSE;
 	ctx->clear_handler();
 	ctx->enter_handler(hip);
         thd->clear_error();
@@ -1120,7 +1082,7 @@
 	continue;
       }
     }
-  } while (ret == 0 && !thd->killed);
+  } while (!err_status && !thd->killed);
 
   thd->restore_active_arena(&execute_arena, &backup_arena);
 
@@ -1141,11 +1103,11 @@
   state= EXECUTED;
 
  done:
-  DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d",
-		      ret, thd->killed, thd->query_error));
+  DBUG_PRINT("info", ("err_status=%d killed=%d query_error=%d",
+		      err_status, thd->killed, thd->query_error));
 
   if (thd->killed)
-    ret= -1;
+    err_status= TRUE;
   /* If the DB has changed, the pointer has changed too, but the
      original thd->db will then have been freed */
   if (dbchanged)
@@ -1155,7 +1117,7 @@
       (It would generate an error from mysql_change_db() when olddb=="")
     */
     if (! thd->killed)
-      ret|= (int) mysql_change_db(thd, olddb, 1);
+      err_status|= mysql_change_db(thd, olddb, 1);
   }
   m_flags&= ~IS_INVOKED;
   DBUG_PRINT("info", ("first free for 0x%lx --: 0x%lx->0x%lx, level: %lu, flags %x",
@@ -1181,7 +1143,7 @@
                m_first_instance->m_first_free_instance->m_recursion_level ==
                m_recursion_level + 1));
   m_first_instance->m_first_free_instance= this;
-  DBUG_RETURN(ret);
+  DBUG_RETURN(err_status);
 }
 
 
@@ -1193,33 +1155,41 @@
 
   SYNOPSIS
     sp_head::execute_function()
-      thd        Thread handle
-      argp       Passed arguments (these are items from containing statement?)
-      argcount   Number of passed arguments. We need to check if this is
-                 correct.
-      resp   OUT Put result item here (q: is it a constant Item always?) 
+      thd               Thread handle
+      argp              Passed arguments (these are items from containing
+                        statement?)
+      argcount          Number of passed arguments. We need to check if this is
+                        correct.
+      return_value_fld  Save result here.
    
   RETURN
-    0      on OK
-    other  on error
+    FALSE  on success
+    TRUE   on error
 */
 
-int
-sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
+bool
+sp_head::execute_function(THD *thd, Item **argp, uint argcount,
+                          Field *return_value_fld)
 {
-  Item **param_values;
+  Item_cache **param_values;
   ulonglong binlog_save_options;
   bool need_binlog_call;
-  DBUG_ENTER("sp_head::execute_function");
-  DBUG_PRINT("info", ("function %s", m_name.str));
-  uint csize = m_pcont->max_pvars();
-  uint params = m_pcont->current_pvars();
-  uint hmax = m_pcont->max_handlers();
-  uint cmax = m_pcont->max_cursors();
+  uint params;
   sp_rcontext *octx = thd->spcont;
   sp_rcontext *nctx = NULL;
-  uint i;
-  int ret= -1;                                  // Assume error
+  bool err_status= FALSE;
+
+  DBUG_ENTER("sp_head::execute_function");
+  DBUG_PRINT("info", ("function %s", m_name.str));
+
+  params = m_pcont->context_pvars();
+
+  /*
+    Check that the function is called with all specified arguments.
+
+    If it is not, use my_error() to report an error, or it will not terminate
+    the invoking query properly.
+  */
 
   if (argcount != params)
   {
@@ -1229,37 +1199,56 @@
     */
     my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0),
              "FUNCTION", m_qname.str, params, argcount);
-    goto end;
+    DBUG_RETURN(TRUE);
   }
 
-  if (!(param_values= (Item**)thd->alloc(sizeof(Item*)*argcount)))
-    DBUG_RETURN(-1);
+  /* Allocate param_values to be used for dumping the call into binlog. */
+
+  if (!(param_values= (Item_cache**)thd->alloc(sizeof(Item_cache*)*argcount)))
+    DBUG_RETURN(TRUE);
 
   // QQ Should have some error checking here? (types, etc...)
-  if (!(nctx= new sp_rcontext(octx, csize, hmax, cmax)))
-    goto end;
+
+  if (!(nctx= new sp_rcontext(m_pcont, return_value_fld, octx)) ||
+      nctx->init(thd))
+  {
+    delete nctx; /* Delete nctx if it was init() that failed. */
+    DBUG_RETURN(TRUE);
+  }
+
 #ifndef DBUG_OFF
-  nctx->owner= this;
+  nctx->sp= this;
 #endif
-  for (i= 0 ; i < argcount ; i++)
+
+  /* Pass arguments. */
+
   {
-    sp_pvar_t *pvar = m_pcont->find_pvar(i);
-    Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL, FALSE);
-    param_values[i]= it;
+    uint i;
+    
+    for (i= 0 ; i < argcount ; i++)
+    {
+      if (!argp[i]->fixed && argp[i]->fix_fields(thd, &argp[i]))
+      {
+        err_status= TRUE;
+        break;
+      }
 
-    if (!it)
-      goto end;                                 // EOM error
-    nctx->push_item(it);
-  }
+      param_values[i]= Item_cache::get_cache(argp[i]->result_type());
+      param_values[i]->store(argp[i]);
 
+      if (nctx->set_variable(thd, i, param_values[i]))
+      {
+        err_status= TRUE;
+        break;
+      }
+    }
+  }
 
-  /*
-    The rest of the frame are local variables which are all IN.
-    Push NULLs to get the right size (and make the reuse mechanism work) -
-    the will be initialized by set instructions in each frame.
-  */
-  for (; i < csize ; i++)
-    nctx->push_item(NULL);
+  if (err_status)
+  {
+    delete nctx;
+    DBUG_RETURN(TRUE);
+  }
 
   thd->spcont= nctx;
 
@@ -1272,7 +1261,7 @@
   }
     
   thd->options&= ~OPTION_BIN_LOG;
-  ret= execute(thd);
+  err_status= execute(thd);
   thd->options= binlog_save_options;
   
   if (need_binlog_call)
@@ -1288,9 +1277,18 @@
     bufstr.append('(');
     for (uint i=0; i < argcount; i++)
     {
+      String str_value_holder;
+      String *str_value;
+
       if (i)
         bufstr.append(',');
-      param_values[i]->print(&bufstr);
+
+      str_value= sp_get_item_value(param_values[i], &str_value_holder);
+
+      if (str_value)
+        bufstr.append(*str_value);
+      else
+        bufstr.append(STRING_WITH_LEN("NULL"));
     }
     bufstr.append(')');
     
@@ -1306,26 +1304,22 @@
     reset_dynamic(&thd->user_var_events);
   }
 
-  if (m_type == TYPE_ENUM_FUNCTION && ret == 0)
+  if (m_type == TYPE_ENUM_FUNCTION && !err_status)
   {
     /* We need result only in function but not in trigger */
-    Item *it= nctx->get_result();
 
-    if (it)
-      *resp= sp_eval_func_item(thd, &it, m_returns, NULL, FALSE);
-    else
+    if (!nctx->is_return_value_set())
     {
       my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
-      ret= -1;
+      err_status= TRUE;
     }
   }
 
   nctx->pop_all_cursors();	// To avoid memory leaks after an error
-  delete nctx;                                  // Doesn't do anything
+  delete nctx;
   thd->spcont= octx;
 
-end:
-  DBUG_RETURN(ret);
+  DBUG_RETURN(err_status);
 }
 
 
@@ -1357,17 +1351,15 @@
    - copy back values of INOUT and OUT parameters
 
   RETURN
-    0   Ok
-    -1  Error
+    FALSE  on success
+    TRUE   on error
 */
 
-int sp_head::execute_procedure(THD *thd, List<Item> *args)
+bool
+sp_head::execute_procedure(THD *thd, List<Item> *args)
 {
-  int ret= 0;
-  uint csize = m_pcont->max_pvars();
-  uint params = m_pcont->current_pvars();
-  uint hmax = m_pcont->max_handlers();
-  uint cmax = m_pcont->max_cursors();
+  bool err_status= FALSE;
+  uint params = m_pcont->context_pvars();
   sp_rcontext *save_spcont, *octx;
   sp_rcontext *nctx = NULL;
   DBUG_ENTER("sp_head::execute_procedure");
@@ -1377,16 +1369,21 @@
   {
     my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "PROCEDURE",
              m_qname.str, params, args->elements);
-    DBUG_RETURN(-1);
+    DBUG_RETURN(TRUE);
   }
 
   save_spcont= octx= thd->spcont;
   if (! octx)
   {				// Create a temporary old context
-    if (!(octx= new sp_rcontext(octx, csize, hmax, cmax)))
-      DBUG_RETURN(-1);
+    if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) ||
+        octx->init(thd))
+    {
+      delete octx; /* Delete octx if it was init() that failed. */
+      DBUG_RETURN(TRUE);
+    }
+    
 #ifndef DBUG_OFF
-    octx->owner= 0;
+    octx->sp= 0;
 #endif
     thd->spcont= octx;
 
@@ -1394,63 +1391,62 @@
     thd->spcont->callers_arena= thd;
   }
 
-  if (!(nctx= new sp_rcontext(octx, csize, hmax, cmax)))
+  if (!(nctx= new sp_rcontext(m_pcont, NULL, octx)) ||
+      nctx->init(thd))
   {
+    delete nctx; /* Delete nctx if it was init() that failed. */
     thd->spcont= save_spcont;
-    DBUG_RETURN(-1);
+    DBUG_RETURN(TRUE);
   }
 #ifndef DBUG_OFF
-  nctx->owner= this;
+  nctx->sp= this;
 #endif
 
-  if (csize > 0 || hmax > 0 || cmax > 0)
+  if (params > 0)
   {
-    Item_null *nit= NULL;	// Re-use this, and only create if needed
-    uint i;
-    List_iterator<Item> li(*args);
-    Item *it;
+    List_iterator<Item> it_args(*args);
 
-    /* Evaluate SP arguments (i.e. get the values passed as parameters) */
-    // QQ: Should do type checking?
     DBUG_PRINT("info",(" %.*s: eval args", m_name.length, m_name.str));
-    for (i = 0 ; (it= li++) && i < params ; i++)
+
+    for (uint i= 0 ; i < params ; i++)
     {
+      Item *arg_item= it_args++;
       sp_pvar_t *pvar= m_pcont->find_pvar(i);
 
-      if (pvar)
+      if (!arg_item)
+        break;
+
+      if (!pvar)
+        continue;
+
+      if (pvar->mode != sp_param_in)
       {
-	if (pvar->mode != sp_param_in)
-	{
-	  if (!it->is_splocal() && !item_is_user_var(it))
-	  {
-	    my_error(ER_SP_NOT_VAR_ARG, MYF(0), i+1, m_qname.str);
-	    ret= -1;
-	    break;
-	  }
-	}
-	if (pvar->mode == sp_param_out)
-	{
-	  if (! nit)
-          {
-	    if (!(nit= new Item_null()))
-            {
-              ret= -1;
-              break;
-            }
-          }
-	  nctx->push_item(nit); // OUT
-	}
-	else
-	{
-	  Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL, FALSE);
+        if (!arg_item->is_splocal() && !item_is_user_var(arg_item))
+        {
+          my_error(ER_SP_NOT_VAR_ARG, MYF(0), i+1, m_qname.str);
+          err_status= TRUE;
+          break;
+        }
+      }
 
-	  if (!it2)
-	  {
-	    ret= -1;		// Eval failed
-	    break;
-	  }
-          nctx->push_item(it2); // IN or INOUT
-	}
+      if (pvar->mode == sp_param_out)
+      {
+        Item_null *null_item= new Item_null();
+
+        if (!null_item ||
+            nctx->set_variable(thd, i, null_item))
+        {
+          err_status= TRUE;
+          break;
+        }
+      }
+      else
+      {
+        if (nctx->set_variable(thd, i, *it_args.ref()))
+        {
+          err_status= TRUE;
+          break;
+        }
       }
     }
 
@@ -1463,20 +1459,12 @@
       close_thread_tables(thd, 0, 0);
 
     DBUG_PRINT("info",(" %.*s: eval args done", m_name.length, m_name.str));
-
-    /*
-      The rest of the frame are local variables which are all IN.
-      Push NULLs to get the right size (and make the reuse mechanism work) -
-      the will be initialized by set instructions in each frame.
-    */
-    for (; i < csize ; i++)
-      nctx->push_item(NULL);
   }
 
   thd->spcont= nctx;
 
-  if (! ret)
-    ret= execute(thd);
+  if (!err_status)
+    err_status= execute(thd);
 
   /*
     In the case when we weren't able to employ reuse mechanism for
@@ -1486,74 +1474,67 @@
   */
   thd->spcont->callers_arena= octx->callers_arena;
 
-  if (!ret && csize > 0)
+  if (!err_status && params > 0)
   {
-    List_iterator<Item> li(*args);
-    Item *it;
+    List_iterator<Item> it_args(*args);
 
     /*
       Copy back all OUT or INOUT values to the previous frame, or
       set global user variables
     */
-    for (uint i = 0 ; (it= li++) && i < params ; i++)
+    for (uint i= 0 ; i < params ; i++)
     {
+      Item *arg_item= it_args++;
+
+      if (!arg_item)
+        break;
+
       sp_pvar_t *pvar= m_pcont->find_pvar(i);
 
-      if (pvar->mode != sp_param_in)
+      if (pvar->mode == sp_param_in)
+        continue;
+
+      if (arg_item->is_splocal())
       {
-	if (it->is_splocal())
-	{
-	  // Have to copy the item to the caller's mem_root
-	  Item *copy;
-	  uint offset= static_cast<Item_splocal *>(it)->get_offset();
-	  Item *val= nctx->get_item(i);
-	  Item *orig= octx->get_item(offset);
-
-          /*
-            We might need to allocate new item if we weren't able to
-            employ reuse mechanism. Then we should do it on the callers arena.
-          */
-	  copy= sp_eval_func_item(thd, &val, pvar->type, orig, TRUE); // Copy
-
-	  if (!copy)
-	  {
-	    ret= -1;
-	    break;
-	  }
-	  if (copy != orig)
-	    octx->set_item(offset, copy);
-	}
-	else
+        if (octx->set_variable(thd,
+                               ((Item_splocal*) arg_item)->get_var_idx(),
+                               nctx->get_item(i)))
+        {
+          err_status= TRUE;
+          break;
+        }
+      }
+      else
+      {
+        Item_func_get_user_var *guv= item_is_user_var(arg_item);
+
+	if (guv)
 	{
-	  Item_func_get_user_var *guv= item_is_user_var(it);
+	  Item *item= nctx->get_item(i);
+	  Item_func_set_user_var *suv;
 
-	  if (guv)
-	  {
-	    Item *item= nctx->get_item(i);
-	    Item_func_set_user_var *suv;
-
-	    suv= new Item_func_set_user_var(guv->get_name(), item);
-	    /*
-              Item_func_set_user_var is not fixed after construction,
-              call fix_fields().
-	    */
-            if ((ret= test(!suv || suv->fix_fields(thd, &item) ||
-                           suv->check() || suv->update())))
-              break;
-	  }
+	  suv= new Item_func_set_user_var(guv->get_name(), item);
+	  /*
+            Item_func_set_user_var is not fixed after construction,
+            call fix_fields().
+	  */
+          if ((err_status= test(!suv || suv->fix_fields(thd, &item) ||
+                                suv->check() || suv->update())))
+            break;
 	}
       }
+
     }
   }
 
   if (!save_spcont)
-    delete octx;                                // Does nothing
+    delete octx;
 
   nctx->pop_all_cursors();	// To avoid memory leaks after an error
-  delete nctx;                                  // Does nothing
+  delete nctx;
   thd->spcont= save_spcont;
 
-  DBUG_RETURN(ret);
+  DBUG_RETURN(err_status);
 }
 
 
@@ -1589,6 +1570,15 @@
   sublex->trg_chistics= oldlex->trg_chistics;
   sublex->trg_table_fields.empty();
   sublex->sp_lex_in_use= FALSE;
+
+  /* Reset type info. */
+
+  sublex->charset= NULL;
+  sublex->length= NULL;
+  sublex->dec= NULL;
+  sublex->interval_list.empty();
+  sublex->type= 0;
+
   DBUG_VOID_RETURN;
 }
 
@@ -1683,6 +1673,55 @@
   return 0;
 }
 
+
+/*
+  Prepare an instance of create_field for field creation (fill all necessary
+  attributes).
+
+  SYNOPSIS
+    sp_head::fill_field_definition()
+      thd         [IN] Thread handle
+      lex         [IN] Yacc parsing context
+      field_type  [IN] Field type
+      field_def   [OUT] An instance of create_field to be filled
+
+  RETURN
+    FALSE  on success
+    TRUE   on error
+*/
+
+bool
+sp_head::fill_field_definition(THD *thd, LEX *lex,
+                               enum enum_field_types field_type,
+                               create_field *field_def)
+{
+  LEX_STRING cmt = { 0, 0 };
+  uint unused1= 0;
+  int unused2= 0;
+
+  if (field_def->init(thd, (char*) "", field_type, lex->length, lex->dec,
+                      lex->type, (Item*) 0, (Item*) 0, &cmt, 0,
+                      &lex->interval_list,
+                      (lex->charset ? lex->charset : default_charset_info),
+                      lex->uint_geom_type))
+    return TRUE;
+
+  if (field_def->interval_list.elements)
+    field_def->interval= create_typelib(mem_root, field_def,
+                                        &field_def->interval_list);
+
+  sp_prepare_create_field(thd, field_def);
+
+  if (prepare_create_field(field_def, &unused1, &unused2, &unused2,
+                           HA_CAN_GEOMETRY))
+  {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+
 void
 sp_head::set_info(longlong created, longlong modified,
 		  st_sp_chistics *chistics, ulong sql_mode)
@@ -2225,28 +2264,28 @@
 int
 sp_instr_set::exec_core(THD *thd, uint *nextp)
 {
-  int res= thd->spcont->set_item_eval(thd, m_offset, &m_value, m_type);
+  int res= thd->spcont->set_variable(thd, m_offset, m_value);
 
-  if (res < 0 &&
-      thd->spcont->get_item(m_offset) == NULL &&
-      thd->spcont->found_handler_here())
+  if (res && thd->spcont->found_handler_here())
   {
     /*
-      Failed to evaluate the value, the variable is still not initialized,
-      and a handler has been found. Set to null so we can continue.
+      Failed to evaluate the value, and a handler has been found. Reset the
+      variable to NULL.
     */
-    Item *it= new Item_null();
 
-    if (!it || thd->spcont->set_item_eval(thd, m_offset, &it, m_type) < 0)
-    {                           /* If this also failed, we have to abort */
-      sp_rcontext *spcont= thd->spcont;
+    if (thd->spcont->set_variable(thd, m_offset, 0))
+    {
+      /* If this also failed, let's abort. */
 
+      sp_rcontext *spcont= thd->spcont;
+    
       thd->spcont= 0;           /* Avoid handlers */
       my_error(ER_OUT_OF_RESOURCES, MYF(0));
       spcont->clear_handler();
       thd->spcont= spcont;
     }
   }
+
   *nextp = m_ip+1;
   return res;
 }
@@ -2515,20 +2554,22 @@
 int
 sp_instr_freturn::exec_core(THD *thd, uint *nextp)
 {
-  Item *it;
-  int res;
+  /*
+    Change <next instruction pointer>, so that this will be the last
+    instruction in the stored function.
+  */
 
-  it= sp_eval_func_item(thd, &m_value, m_type, NULL, TRUE);
-  if (! it)
-    res= -1;
-  else
-  {
-    res= 0;
-    thd->spcont->set_result(it);
-  }
   *nextp= UINT_MAX;
 
-  return res;
+  /*
+    Evaluate the value of return expression and store it in current runtime
+    context.
+
+    NOTE: It's necessary to evaluate result item right here, because we must
+    do it in scope of execution the current context/block.
+  */
+
+  return thd->spcont->set_return_value(thd, m_value);
 }
 
 void
@@ -2649,7 +2690,6 @@
     *nextp= m_dest;
   else
   {
-    thd->spcont->restore_variables(m_frame);
     *nextp= thd->spcont->pop_hstack();
   }
   thd->spcont->exit_handler();
@@ -2967,6 +3007,65 @@
 }
 
 
+/**************************************************************************
+  sp_instr_set_case_expr class implementation
+**************************************************************************/
+
+int
+sp_instr_set_case_expr::execute(THD *thd, uint *nextp)
+{
+  DBUG_ENTER("sp_instr_set_case_expr::execute");
+
+  DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
+}
+
+
+int
+sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
+{
+  int res= thd->spcont->set_case_expr(thd, m_case_expr_id, m_case_expr);
+
+  if (res &&
+      !thd->spcont->get_case_expr(m_case_expr_id) &&
+      thd->spcont->found_handler_here())
+  {
+    /*
+      Failed to evaluate the value, the case expression is still not
+      initialized, and a handler has been found. Set to NULL so we can continue.
+    */
+
+    Item *null_item= new Item_null();
+    
+    if (!null_item ||
+        thd->spcont->set_case_expr(thd, m_case_expr_id, null_item))
+    {
+      /* If this also failed, we have to abort. */
+
+      sp_rcontext *spcont= thd->spcont;
+    
+      thd->spcont= 0;           /* Avoid handlers */
+      my_error(ER_OUT_OF_RESOURCES, MYF(0));
+      spcont->clear_handler();
+      thd->spcont= spcont;
+    }
+  }
+
+  *nextp = m_ip+1;
+
+  return res; /* no error */
+}
+
+
+void
+sp_instr_set_case_expr::print(String *str)
+{
+  str->append(STRING_WITH_LEN("set_case_expr "));
+  str->qs_append(m_case_expr_id);
+  str->append(' ');
+  m_case_expr->print(str);
+}
+
+
 /* ------------------------------------------------------------------ */
 
 /*
@@ -3139,10 +3238,12 @@
 
   SYNOPSIS
     add_used_tables_to_table_list()
-      thd                   - thread context
-      query_tables_last_ptr - (in/out) pointer the next_global member of last
-                              element of the list where tables will be added
-                              (or to its root).
+      thd                    [in]     Thread context
+      query_tables_last_ptr  [in/out] Pointer to the next_global member of
+                                      last element of the list where tables
+                                      will be added (or to its root).
+      belong_to_view         [in]     Uppermost view which uses this routine,
+                                      0 if none.
 
   DESCRIPTION
     Converts multi-set of tables used by this routine to table list and adds
@@ -3157,7 +3258,8 @@
 
 bool
 sp_head::add_used_tables_to_table_list(THD *thd,
-                                       TABLE_LIST ***query_tables_last_ptr)
+                                       TABLE_LIST ***query_tables_last_ptr,
+                                       TABLE_LIST *belong_to_view)
 {
   uint i;
   Query_arena *arena, backup;
@@ -3200,6 +3302,7 @@
       table->lock_type= stab->lock_type;
       table->cacheable_table= 1;
       table->prelocking_placeholder= 1;
+      table->belong_to_view= belong_to_view;
 
       /* Everyting else should be zeroed */
 

--- 1.78/sql/sp_head.h	2005-11-23 12:47:28 -08:00
+++ 1.79/sql/sp_head.h	2005-12-12 00:11:17 -08:00
@@ -33,6 +33,9 @@
 Item_result
 sp_map_result_type(enum enum_field_types type);
 
+Item::Type
+sp_map_item_type(enum enum_field_types type);
+
 uint
 sp_get_flags_for_command(LEX *lex);
 
@@ -123,12 +126,9 @@
   /* TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */
   int m_type;
   uint m_flags;                 // Boolean attributes of a stored routine
-  enum enum_field_types m_returns; // For FUNCTIONs only
-  Field::geometry_type m_geom_returns;
-  CHARSET_INFO *m_returns_cs;	// For FUNCTIONs only
-  TYPELIB *m_returns_typelib;	// For FUNCTIONs only
-  uint m_returns_len;		// For FUNCTIONs only
-  uint m_returns_pack;		// For FUNCTIONs only
+
+  create_field m_return_field_def; /* This is used for FUNCTIONs only. */
+
   const uchar *m_tmp_query;	// Temporary pointer to sub query string
   uint m_old_cmq;		// Old CLIENT_MULTI_QUERIES value
   st_sp_chistics *m_chistics;
@@ -202,9 +202,6 @@
   void
   init_strings(THD *thd, LEX *lex, sp_name *name);
 
-  TYPELIB *
-  create_typelib(List<String> *src);
-
   int
   create(THD *thd);
 
@@ -214,10 +211,10 @@
   void
   destroy();
 
-  int
-  execute_function(THD *thd, Item **args, uint argcount, Item **resp);
+  bool
+  execute_function(THD *thd, Item **args, uint argcount, Field *return_fld);
 
-  int
+  bool
   execute_procedure(THD *thd, List<Item> *args);
 
   int
@@ -278,7 +275,12 @@
 
   char *create_string(THD *thd, ulong *lenp);
 
-  Field *make_field(uint max_length, const char *name, TABLE *dummy);
+  Field *create_result_field(uint field_max_length, const char *field_name,
+                             TABLE *table);
+
+  bool fill_field_definition(THD *thd, LEX *lex,
+                             enum enum_field_types field_type,
+                             create_field *field_def);
 
   void set_info(longlong created, longlong modified,
 		st_sp_chistics *chistics, ulong sql_mode);
@@ -308,7 +310,8 @@
 
   /* Add tables used by routine to the table list. */
   bool add_used_tables_to_table_list(THD *thd,
-                                     TABLE_LIST ***query_tables_last_ptr);
+                                     TABLE_LIST ***query_tables_last_ptr,
+                                     TABLE_LIST *belong_to_view);
 
   /*
     Check if this stored routine contains statements disallowed
@@ -363,7 +366,7 @@
   */
   HASH m_sptabs;
 
-  int
+  bool
   execute(THD *thd);
 
   /*
@@ -1074,6 +1077,31 @@
 }; // class sp_instr_error : public sp_instr
 
 
+class sp_instr_set_case_expr :public sp_instr
+{
+public:
+
+  sp_instr_set_case_expr(uint ip, sp_pcontext *ctx, uint case_expr_id,
+                         Item *case_expr, LEX *lex)
+    :sp_instr(ip, ctx), m_case_expr_id(case_expr_id), m_case_expr(case_expr),
+     m_lex_keeper(lex, TRUE)
+  {}
+
+  virtual int execute(THD *thd, uint *nextp);
+
+  virtual int exec_core(THD *thd, uint *nextp);
+
+  virtual void print(String *str);
+
+private:
+
+  uint m_case_expr_id;
+  Item *m_case_expr;
+  sp_lex_keeper m_lex_keeper;
+
+}; // class sp_instr_set_case_expr : public sp_instr
+
+
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
 bool
 sp_change_security_context(THD *thd, sp_head *sp,
@@ -1086,8 +1114,10 @@
 sp_add_to_query_tables(THD *thd, LEX *lex,
 		       const char *db, const char *name,
 		       thr_lock_type locktype);
+Item *
+sp_prepare_func_item(THD* thd, Item **it_addr);
 
-Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type,
-                        Item *reuse, bool use_callers_arena);
+bool
+sp_eval_expr(THD *thd, Field *result_field, Item *expr_item);
 
 #endif /* _SP_HEAD_H_ */

--- 1.156/sql/sql_prepare.cc	2005-11-23 04:04:13 -08:00
+++ 1.157/sql/sql_prepare.cc	2005-12-12 00:11:18 -08:00
@@ -2131,7 +2131,8 @@
     lex->result->cleanup();
     lex->result->set_thd(thd);
   }
-  thd->allow_sum_func= 0;
+  lex->allow_sum_func= 0;
+  lex->in_sum_func= NULL;
   DBUG_VOID_RETURN;  
 }
 

--- 1.166/tests/mysql_client_test.c	2005-12-02 07:27:13 -08:00
+++ 1.167/tests/mysql_client_test.c	2005-12-12 00:11:20 -08:00
@@ -14590,6 +14590,40 @@
   myquery(rc);
 }
 
+
+/*
+  Bug #15510: mysql_warning_count returns 0 after mysql_stmt_fetch which
+  should warn
+*/
+static void test_bug15510()
+{
+  MYSQL_STMT *stmt;
+  MYSQL_RES *res;
+  int rc;
+  const char *query= "select 1 from dual where 1/0";
+
+  myheader("test_bug15510");
+
+  rc= mysql_query(mysql, "set @@sql_mode='ERROR_FOR_DIVISION_BY_ZERO'");
+  myquery(rc);
+
+  stmt= mysql_stmt_init(mysql);
+
+  rc= mysql_stmt_prepare(stmt, query, strlen(query));
+  check_execute(stmt, rc);
+
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  rc= mysql_stmt_fetch(stmt);
+  DIE_UNLESS(mysql_warning_count(mysql));
+
+  /* Cleanup */
+  mysql_stmt_close(stmt);
+  rc= mysql_query(mysql, "set @@sql_mode=''");
+  myquery(rc);
+}
+
 /*
   Read and parse arguments and MySQL options from my.cnf
 */
@@ -14849,6 +14883,7 @@
   { "test_bug13488", test_bug13488 },
   { "test_bug13524", test_bug13524 },
   { "test_bug14845", test_bug14845 },
+  { "test_bug15510", test_bug15510},
   { 0, 0 }
 };
 
Thread
bk commit into 5.1 tree (igor:1.1971)igor12 Dec