List:Commits« Previous MessageNext Message »
From:jani Date:April 17 2007 3:45pm
Subject:bk commit into 5.1 tree (jamppa:1.2590)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of jamppa. When jamppa 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@stripped, 2007-04-17 15:45:35+02:00, jamppa@stripped +8 -0
  Merge bk-internal.mysql.com:/data0/bk/mysql-5.1
  into  bk-internal.mysql.com:/data0/bk/mysql-5.1-marvel
  MERGE: 1.2569.1.14

  mysql-test/r/strict.result@stripped, 2007-04-17 15:45:27+02:00, jamppa@stripped
+0 -0
    Auto merged
    MERGE: 1.44.1.1

  sql/ha_ndbcluster.cc@stripped, 2007-04-17 15:45:28+02:00, jamppa@stripped +0
-0
    Auto merged
    MERGE: 1.441.1.3

  sql/item.cc@stripped, 2007-04-17 15:45:28+02:00, jamppa@stripped +0 -0
    Auto merged
    MERGE: 1.258.1.5

  sql/item.h@stripped, 2007-04-17 15:45:28+02:00, jamppa@stripped +0 -0
    Auto merged
    MERGE: 1.234.1.4

  sql/item_cmpfunc.cc@stripped, 2007-04-17 15:45:28+02:00, jamppa@stripped +0 -0
    Auto merged
    MERGE: 1.257.1.3

  sql/sql_delete.cc@stripped, 2007-04-17 15:45:28+02:00, jamppa@stripped +0 -0
    Auto merged
    MERGE: 1.212.1.3

  sql/sql_select.cc@stripped, 2007-04-17 15:45:29+02:00, jamppa@stripped +0 -0
    Auto merged
    MERGE: 1.508.1.3

  sql/sql_table.cc@stripped, 2007-04-17 15:45:29+02:00, jamppa@stripped +0 -0
    Auto merged
    MERGE: 1.399.1.8

# 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:	jamppa
# Host:	bk-internal.mysql.com
# Root:	/data0/bk/mysql-5.1-marvel/RESYNC

--- 1.262/sql/item.cc	2007-04-17 15:45:43 +02:00
+++ 1.263/sql/item.cc	2007-04-17 15:45:43 +02:00
@@ -1662,7 +1662,7 @@
 Item_field::Item_field(Field *f)
   :Item_ident(0, NullS, *f->table_name, f->field_name),
    item_equal(0), no_const_subst(0),
-   have_privileges(0), any_privileges(0), fixed_as_field(0)
+   have_privileges(0), any_privileges(0)
 {
   set_field(f);
   /*
@@ -1677,7 +1677,7 @@
                        Field *f)
   :Item_ident(context_arg, f->table->s->db.str, *f->table_name,
f->field_name),
    item_equal(0), no_const_subst(0),
-   have_privileges(0), any_privileges(0), fixed_as_field(0)
+   have_privileges(0), any_privileges(0)
 {
   /*
     We always need to provide Item_field with a fully qualified field
@@ -1716,7 +1716,7 @@
                        const char *field_name_arg)
   :Item_ident(context_arg, db_arg,table_name_arg,field_name_arg),
    field(0), result_field(0), item_equal(0), no_const_subst(0),
-   have_privileges(0), any_privileges(0), fixed_as_field(0)
+   have_privileges(0), any_privileges(0)
 {
   SELECT_LEX *select= current_thd->lex->current_select;
   collation.set(DERIVATION_IMPLICIT);
@@ -1732,8 +1732,7 @@
    item_equal(item->item_equal),
    no_const_subst(item->no_const_subst),
    have_privileges(item->have_privileges),
-   any_privileges(item->any_privileges),
-   fixed_as_field(item->fixed_as_field)
+   any_privileges(item->any_privileges)
 {
   collation.set(DERIVATION_IMPLICIT);
 }
@@ -3502,6 +3501,7 @@
   Item **ref= (Item **) not_found_item;
   SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select;
   Name_resolution_context *outer_context= 0;
+  SELECT_LEX *select= 0;
   /* Currently derived tables cannot be correlated */
   if (current_sel->master_unit()->first_select()->linkage !=
       DERIVED_TABLE_TYPE)
@@ -3510,7 +3510,7 @@
        outer_context;
        outer_context= outer_context->outer_context)
   {
-    SELECT_LEX *select= outer_context->select_lex;
+    select= outer_context->select_lex;
     Item_subselect *prev_subselect_item=
       last_checked_context->select_lex->master_unit()->item;
     last_checked_context= outer_context;
@@ -3553,45 +3553,28 @@
         }
         if (*from_field != view_ref_found)
         {
-
           prev_subselect_item->used_tables_cache|= (*from_field)->table->map;
           prev_subselect_item->const_item_cache= 0;
+          set_field(*from_field);
           if (!last_checked_context->select_lex->having_fix_field &&
-              !fixed_as_field)
+              select->group_list.elements)
           {
             Item_outer_ref *rf;
-            Query_arena *arena= 0, backup;
             /*
-              Each outer field is replaced for an Item_outer_ref object.
-              This is done in order to get correct results when the outer
-              select employs a temporary table.
-              The original fields are saved in the inner_fields_list of the
-              outer select. This list is created by the following reasons:
-              1. We can't add field items to the outer select list directly
-                 because the outer select hasn't been fully fixed yet.
-              2. We need a location to refer to in the Item_ref object
-                 so the inner_fields_list is used as such temporary
-                 reference storage.
-              The new Item_outer_ref object replaces the original field and is
-              also saved in the inner_refs_list of the outer select. Here
-              it is only created. It can be fixed only after the original
-              field has been fixed and this is done in the fix_inner_refs()
-              function.
+              If an outer field is resolved in a grouping select then it
+              is replaced for an Item_outer_ref object. Otherwise an
+              Item_field object is used.
+              The new Item_outer_ref object is saved in the inner_refs_list of
+              the outer select. Here it is only created. It can be fixed only
+              after the original field has been fixed and this is done in the
+              fix_inner_refs() function.
             */
-            set_field(*from_field);
-            arena= thd->activate_stmt_arena_if_needed(&backup);
-            rf= new Item_outer_ref(context, this);
-            if (!rf)
-            {
-              if (arena)
-                thd->restore_active_arena(arena, &backup);
+            ;
+            if (!(rf= new Item_outer_ref(context, this)))
               return -1;
-            }
-            *reference= rf;
+            thd->change_item_tree(reference, rf);
             select->inner_refs_list.push_back(rf);
-            if (arena)
-              thd->restore_active_arena(arena, &backup);
-            fixed_as_field= 1;
+            rf->in_sum_func= thd->lex->in_sum_func;
           }
           if (thd->lex->in_sum_func &&
               thd->lex->in_sum_func->nest_level == 
@@ -3697,11 +3680,20 @@
     rf= (place == IN_HAVING ?
          new Item_ref(context, ref, (char*) table_name,
                       (char*) field_name, alias_name_used) :
+         (!select->group_list.elements ?
          new Item_direct_ref(context, ref, (char*) table_name,
-                             (char*) field_name, alias_name_used));
+                             (char*) field_name, alias_name_used) :
+         new Item_outer_ref(context, ref, (char*) table_name,
+                            (char*) field_name, alias_name_used)));
     *ref= save;
     if (!rf)
       return -1;
+
+    if (place != IN_HAVING && select->group_list.elements)
+    {
+      outer_context->select_lex->inner_refs_list.push_back((Item_outer_ref*)rf);
+      ((Item_outer_ref*)rf)->in_sum_func= thd->lex->in_sum_func;
+    }
     thd->change_item_tree(reference, rf);
     /*
       rf is Item_ref => never substitute other items (in this case)
@@ -5659,15 +5651,18 @@
 
 bool Item_outer_ref::fix_fields(THD *thd, Item **reference)
 {
-  DBUG_ASSERT(*ref);
-  /* outer_field->check_cols() will be made in Item_direct_ref::fix_fields */
-  outer_field->fixed_as_field= 1;
-  if (!outer_field->fixed &&
-      (outer_field->fix_fields(thd, reference)))
+  bool err;
+  /* outer_ref->check_cols() will be made in Item_direct_ref::fix_fields */
+  if ((*ref) && !(*ref)->fixed && ((*ref)->fix_fields(thd,
reference)))
     return TRUE;
-  table_name= outer_field->table_name;
-  return Item_direct_ref::fix_fields(thd, reference);
+  err= Item_direct_ref::fix_fields(thd, reference);
+  if (!outer_ref)
+    outer_ref= *ref;
+  if ((*ref)->type() == Item::FIELD_ITEM)
+    table_name= ((Item_field*)outer_ref)->table_name;
+  return err;
 }
+
 
 /*
   Compare two view column references for equality.

--- 1.237/sql/item.h	2007-04-17 15:45:44 +02:00
+++ 1.238/sql/item.h	2007-04-17 15:45:44 +02:00
@@ -1316,7 +1316,6 @@
   uint have_privileges;
   /* field need any privileges (for VIEW creation) */
   bool any_privileges;
-  bool fixed_as_field;
   Item_field(Name_resolution_context *context_arg,
              const char *db_arg,const char *table_name_arg,
 	     const char *field_name_arg);
@@ -2081,30 +2080,49 @@
 };
 
 
+/*
+  Class for outer fields.
+  An object of this class is created when the select where the outer field was
+  resolved is a grouping one. After it has been fixed the ref field will point
+  to either an Item_ref or an Item_direct_ref object which will be used to
+  access the field.
+  See also comments for the fix_inner_refs() and the
+  Item_field::fix_outer_field() functions.
+*/
+
+class Item_sum;
 class Item_outer_ref :public Item_direct_ref
 {
 public:
-  Item_field *outer_field;
+  Item *outer_ref;
+  /* The aggregate function under which this outer ref is used, if any. */
+  Item_sum *in_sum_func;
+  /*
+    TRUE <=> that the outer_ref is already present in the select list
+    of the outer select.
+  */
+  bool found_in_select_list;
   Item_outer_ref(Name_resolution_context *context_arg,
                  Item_field *outer_field_arg)
     :Item_direct_ref(context_arg, 0, outer_field_arg->table_name,
-                          outer_field_arg->field_name),
-    outer_field(outer_field_arg)
+                     outer_field_arg->field_name),
+    outer_ref(outer_field_arg), in_sum_func(0),
+    found_in_select_list(0)
   {
-    ref= (Item**)&outer_field;
+    ref= &outer_ref;
     set_properties();
     fixed= 0;
   }
-  void cleanup()
-  {
-    ref= (Item**)&outer_field;
-    fixed= 0;
-    Item_direct_ref::cleanup();
-    outer_field->cleanup();
-  }
+  Item_outer_ref(Name_resolution_context *context_arg, Item **item,
+                 const char *table_name_arg, const char *field_name_arg,
+                 bool alias_name_used_arg)
+    :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg,
+                     alias_name_used_arg),
+    outer_ref(0), in_sum_func(0), found_in_select_list(1)
+  {}
   void save_in_result_field(bool no_conversions)
   {
-    outer_field->save_org_in_field(result_field);
+    outer_ref->save_org_in_field(result_field);
   }
   bool fix_fields(THD *, Item **);
   table_map used_tables() const

--- 1.261/sql/item_cmpfunc.cc	2007-04-17 15:45:44 +02:00
+++ 1.262/sql/item_cmpfunc.cc	2007-04-17 15:45:44 +02:00
@@ -69,26 +69,80 @@
 
 
 /*
+  Compare row signature of two expressions
+
+  SYNOPSIS:
+    cmp_row_type()
+    item1          the first expression
+    item2         the second expression
+
+  DESCRIPTION
+    The function checks that two expressions have compatible row signatures
+    i.e. that the number of columns they return are the same and that if they
+    are both row expressions then each component from the first expression has 
+    a row signature compatible with the signature of the corresponding component
+    of the second expression.
+
+  RETURN VALUES
+    1  type incompatibility has been detected
+    0  otherwise
+*/
+
+static int cmp_row_type(Item* item1, Item* item2)
+{
+  uint n= item1->cols();
+  if (item2->check_cols(n))
+    return 1;
+  for (uint i=0; i<n; i++)
+  {
+    if (item2->element_index(i)->check_cols(item1->element_index(i)->cols())
||
+        (item1->element_index(i)->result_type() == ROW_RESULT &&
+         cmp_row_type(item1->element_index(i), item2->element_index(i))))
+      return 1;
+  }
+  return 0;
+}
+
+
+/*
   Aggregates result types from the array of items.
 
-  SYNOPSIS
+  SYNOPSIS:
     agg_cmp_type()
-      items        array of items to aggregate the type from
-      nitems       number of items in the array
+    type   [out] the aggregated type
+    items        array of items to aggregate the type from
+    nitems       number of items in the array
 
   DESCRIPTION
     This function aggregates result types from the array of items. Found type
     supposed to be used later for comparison of values of these items.
     Aggregation itself is performed by the item_cmp_type() function.
+    The function also checks compatibility of row signatures for the
+    submitted items (see the spec for the cmp_row_type function). 
+
+  RETURN VALUES
+    1  type incompatibility has been detected
+    0  otherwise
 */
 
-static Item_result agg_cmp_type(Item **items, uint nitems)
+static int agg_cmp_type(Item_result *type, Item **items, uint nitems)
 {
   uint i;
-  Item_result type= items[0]->result_type();
+  type[0]= items[0]->result_type();
   for (i= 1 ; i < nitems ; i++)
-    type= item_cmp_type(type, items[i]->result_type());
-  return type;
+  {
+    type[0]= item_cmp_type(type[0], items[i]->result_type());
+    /*
+      When aggregating types of two row expressions we have to check
+      that they have the same cardinality and that each component
+      of the first row expression has a compatible row signature with
+      the signature of the corresponding component of the second row
+      expression.
+    */ 
+    if (type[0] == ROW_RESULT && cmp_row_type(items[0], items[i]))
+      return 1;     // error found: invalid usage of rows
+  }
+  return 0;
 }
 
 
@@ -105,7 +159,8 @@
     item in the list with each of the remaining items in the 'items' array.
 
   RETURN
-    Bitmap of collected types
+    0 - if row type incompatibility has been detected (see cmp_row_type)
+    Bitmap of collected types - otherwise
 */
 
 static uint collect_cmp_types(Item **items, uint nitems)
@@ -116,12 +171,17 @@
   DBUG_ASSERT(nitems > 1);
   found_types= 0;
   for (i= 1; i < nitems ; i++)
+  {
+    if ((left_result == ROW_RESULT || 
+         items[i]->result_type() == ROW_RESULT) &&
+        cmp_row_type(items[0], items[i]))
+      return 0;
     found_types|= 1<< (uint)item_cmp_type(left_result,
                                            items[i]->result_type());
+  }
   return found_types;
 }
 
-
 static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
                               const char *fname)
 {
@@ -1358,7 +1418,8 @@
   */
   if (!args[0] || !args[1] || !args[2])
     return;
-  cmp_type= agg_cmp_type(args, 3);
+  if ( agg_cmp_type(&cmp_type, args, 3))
+    return;
   if (cmp_type == STRING_RESULT &&
       agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV, 1))
    return;
@@ -2047,7 +2108,8 @@
     for (nagg= 0; nagg < ncases/2 ; nagg++)
       agg[nagg+1]= args[nagg*2];
     nagg++;
-    found_types= collect_cmp_types(agg, nagg);
+    if (!(found_types= collect_cmp_types(agg, nagg)))
+      return;
 
     for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
     {
@@ -2751,7 +2813,8 @@
   uint type_cnt= 0, i;
   Item_result cmp_type= STRING_RESULT;
   left_result_type= args[0]->result_type();
-  found_types= collect_cmp_types(args, arg_count);
+  if (!(found_types= collect_cmp_types(args, arg_count)))
+    return;
   
   for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++)
   {

--- 1.215/sql/sql_delete.cc	2007-04-17 15:45:44 +02:00
+++ 1.216/sql/sql_delete.cc	2007-04-17 15:45:44 +02:00
@@ -394,6 +394,8 @@
 {
   Item *fake_conds= 0;
   SELECT_LEX *select_lex= &thd->lex->select_lex;
+  const char *operation = thd->lex->sql_command == SQLCOM_TRUNCATE ?
+                          "TRUNCATE" : "DELETE";
   DBUG_ENTER("mysql_prepare_delete");
   List<Item> all_fields;
 
@@ -408,14 +410,14 @@
     DBUG_RETURN(TRUE);
   if (!table_list->updatable || check_key_in_view(thd, table_list))
   {
-    my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
+    my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, operation);
     DBUG_RETURN(TRUE);
   }
   {
     TABLE_LIST *duplicate;
     if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
     {
-      update_non_unique_table_error(table_list, "DELETE", duplicate);
+      update_non_unique_table_error(table_list, operation, duplicate);
       DBUG_RETURN(TRUE);
     }
   }
@@ -933,7 +935,8 @@
   if (!dont_send_ok)
   {
     enum legacy_db_type table_type;
-    mysql_frm_type(thd, path, &table_type);
+    if (mysql_frm_type(thd, path, &table_type) == FRMTYPE_VIEW)
+      goto trunc_by_del;
     if (table_type == DB_TYPE_UNKNOWN)
     {
       my_error(ER_NO_SUCH_TABLE, MYF(0),

--- 1.511/sql/sql_select.cc	2007-04-17 15:45:44 +02:00
+++ 1.512/sql/sql_select.cc	2007-04-17 15:45:44 +02:00
@@ -280,15 +280,30 @@
     ref_pointer_array Array of references to Items used in current select
 
   DESCRIPTION
-    The function fixes fields referenced from inner selects and
-    also fixes references (Item_ref objects) to these fields. Each field
-    is fixed as a usual hidden field of the current select - it is added
-    to the all_fields list and the pointer to it is saved in the
-    ref_pointer_array if latter is provided.
-    After the field has been fixed we proceed with fixing references
-    (Item_ref objects) to this field from inner subqueries. If the
-    ref_pointer_array is provided then Item_ref objects is set to
-    reference element in that array with the pointer to the field.
+    The function serves 3 purposes - adds fields referenced from inner
+    selects to the current select list, resolves which class to use
+    to access referenced item (Item_ref of Item_direct_ref) and fixes
+    references (Item_ref objects) to these fields.
+
+    If a field isn't already in the select list and the ref_pointer_array
+    is provided then it is added to the all_fields list and the pointer to
+    it is saved in the ref_pointer_array.
+
+    The class to access the outer field is determined by the following rules:
+    1. If the outer field isn't used under an aggregate function
+      then the Item_ref class should be used.
+    2. If the outer field is used under an aggregate function and this
+      function is aggregated in the select where the outer field was
+      resolved or in some more inner select then the Item_direct_ref
+      class should be used.
+    The resolution is done here and not at the fix_fields() stage as
+    it can be done only after sum functions are fixed and pulled up to
+    selects where they are have to be aggregated.
+    When the class is chosen it substitutes the original field in the
+    Item_outer_ref object.
+
+    After this we proceed with fixing references (Item_outer_ref objects) to
+    this field from inner subqueries.
 
   RETURN
     TRUE  an error occured
@@ -301,33 +316,64 @@
 {
   Item_outer_ref *ref;
   bool res= FALSE;
+  bool direct_ref= FALSE;
+
   List_iterator<Item_outer_ref> ref_it(select->inner_refs_list);
   while ((ref= ref_it++))
   {
-    Item_field *item= ref->outer_field;
+    Item *item= ref->outer_ref;
+    Item **item_ref= ref->ref;
+    Item_ref *new_ref;
     /*
       TODO: this field item already might be present in the select list.
       In this case instead of adding new field item we could use an
       existing one. The change will lead to less operations for copying fields,
       smaller temporary tables and less data passed through filesort.
     */
-    if (ref_pointer_array)
+    if (ref_pointer_array && !ref->found_in_select_list)
     {
       int el= all_fields.elements;
-      ref_pointer_array[el]= (Item*)item;
+      ref_pointer_array[el]= item;
       /* Add the field item to the select list of the current select. */
-      all_fields.push_front((Item*)item);
+      all_fields.push_front(item);
       /*
         If it's needed reset each Item_ref item that refers this field with
         a new reference taken from ref_pointer_array.
       */
-      ref->ref= ref_pointer_array + el;
+      item_ref= ref_pointer_array + el;
     }
-    if (!ref->fixed && ref->fix_fields(thd, 0))
+
+    if (ref->in_sum_func)
     {
-      res= TRUE;
-      break;
+      Item_sum *sum_func;
+      if (ref->in_sum_func->nest_level > select->nest_level)
+        direct_ref= TRUE;
+      else
+      {
+        for (sum_func= ref->in_sum_func; sum_func &&
+             sum_func->aggr_level >= select->nest_level;
+             sum_func= sum_func->in_sum_func)
+        {
+          if (sum_func->aggr_level == select->nest_level)
+          {
+            direct_ref= TRUE;
+            break;
+          }
+        }
+      }
     }
+    new_ref= direct_ref ?
+              new Item_direct_ref(ref->context, item_ref, ref->field_name,
+                          ref->table_name, ref->alias_name_used) :
+              new Item_ref(ref->context, item_ref, ref->field_name,
+                          ref->table_name, ref->alias_name_used);
+    if (!new_ref)
+      return TRUE;
+    ref->outer_ref= new_ref;
+    ref->ref= &ref->outer_ref;
+
+    if (!ref->fixed && ref->fix_fields(thd, 0))
+      return TRUE;
     thd->used_tables|= item->used_tables();
   }
   return res;
@@ -479,10 +525,6 @@
   if (having && having->with_sum_func)
     having->split_sum_func2(thd, ref_pointer_array, all_fields,
                             &having, TRUE);
-  if (select_lex->inner_refs_list.elements &&
-      fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array))
-    DBUG_RETURN(-1);
-
   if (select_lex->inner_sum_func_list)
   {
     Item_sum *end=select_lex->inner_sum_func_list;
@@ -495,6 +537,10 @@
     } while (item_sum != end);
   }
 
+  if (select_lex->inner_refs_list.elements &&
+      fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array))
+    DBUG_RETURN(-1);
+
   if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
     DBUG_RETURN(-1);
   
@@ -5379,7 +5425,9 @@
   }
   else if (keyuse->val->type() == Item::FIELD_ITEM ||
            (keyuse->val->type() == Item::REF_ITEM &&
-            ((Item_ref*)keyuse->val)->ref_type() == Item_ref::OUTER_REF) )
+            ((Item_ref*)keyuse->val)->ref_type() == Item_ref::OUTER_REF &&
+            (*(Item_ref**)((Item_ref*)keyuse->val)->ref)->ref_type() ==
+             Item_ref::DIRECT_REF) )
     return new store_key_field(thd,
 			       key_part->field,
 			       key_buff + maybe_null,
@@ -13799,9 +13847,7 @@
       ORDER *ord_iter;
       for (ord_iter= group; ord_iter; ord_iter= ord_iter->next)
         if ((*ord_iter->item)->eq(item, 1))
-          break;
-      if (ord_iter)
-        continue;
+          goto next_item;
       
       ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER));
       if (!ord)
@@ -13816,6 +13862,7 @@
       *prev=ord;
       prev= &ord->next;
     }
+next_item:
     ref_pointer_array++;
   }
   *prev=0;

--- 1.403/sql/sql_table.cc	2007-04-17 15:45:44 +02:00
+++ 1.404/sql/sql_table.cc	2007-04-17 15:45:44 +02:00
@@ -1929,10 +1929,11 @@
     which has some duplicates on its right
 
   RETURN VALUES
-    void
+    0             ok
+    1             Error
 */
 
-void check_duplicates_in_interval(const char *set_or_name,
+bool check_duplicates_in_interval(const char *set_or_name,
                                   const char *name, TYPELIB *typelib,
                                   CHARSET_INFO *cs, unsigned int *dup_val_count)
 {
@@ -1948,6 +1949,13 @@
     tmp.count--;
     if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
     {
+      if ((current_thd->variables.sql_mode &
+         (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
+      {
+        my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
+                 name,*cur_value,set_or_name);
+        return 1;
+      }
       push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_NOTE,
 			  ER_DUPLICATED_VALUE_IN_TYPE,
 			  ER(ER_DUPLICATED_VALUE_IN_TYPE),
@@ -1955,6 +1963,7 @@
       (*dup_val_count)++;
     }
   }
+  return 0;
 }
 
 
@@ -2090,9 +2099,10 @@
     if (sql_field->charset->state & MY_CS_BINSORT)
       sql_field->pack_flag|=FIELDFLAG_BINARY;
     sql_field->unireg_check=Field::INTERVAL_FIELD;
-    check_duplicates_in_interval("ENUM",sql_field->field_name,
-                                 sql_field->interval,
-                                 sql_field->charset, &dup_val_count);
+    if (check_duplicates_in_interval("ENUM",sql_field->field_name,
+                                     sql_field->interval,
+                                     sql_field->charset, &dup_val_count))
+      DBUG_RETURN(1);
     break;
   case MYSQL_TYPE_SET:
     sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
@@ -2100,9 +2110,10 @@
     if (sql_field->charset->state & MY_CS_BINSORT)
       sql_field->pack_flag|=FIELDFLAG_BINARY;
     sql_field->unireg_check=Field::BIT_FIELD;
-    check_duplicates_in_interval("SET",sql_field->field_name,
-                                 sql_field->interval,
-                                 sql_field->charset, &dup_val_count);
+    if (check_duplicates_in_interval("SET",sql_field->field_name,
+                                     sql_field->interval,
+                                     sql_field->charset, &dup_val_count))
+      DBUG_RETURN(1);
     /* Check that count of unique members is not more then 64 */
     if (sql_field->interval->count -  dup_val_count > sizeof(longlong)*8)
     {

--- 1.444/sql/ha_ndbcluster.cc	2007-04-17 15:45:44 +02:00
+++ 1.445/sql/ha_ndbcluster.cc	2007-04-17 15:45:44 +02:00
@@ -480,7 +480,10 @@
   {
     Ndb *ndb= get_ndb();
     struct Ndb_statistics stat;
-    ndb->setDatabaseName(m_dbname);
+    if (ndb->setDatabaseName(m_dbname))
+    {
+      return my_errno= HA_ERR_OUT_OF_MEM;
+    }
     result= ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat);
     if (result == 0)
     {
@@ -874,7 +877,11 @@
       DBUG_PRINT("info", ("allocate blobs buffer size %u", offset));
       buffer= my_malloc(offset, MYF(MY_WME));
       if (buffer == NULL)
+      {
+        sql_print_error("ha_ndbcluster::get_ndb_blobs_value: "
+                        "my_malloc(%u) failed", offset);
         DBUG_RETURN(-1);
+      }
       buffer_size= offset;
     }
   }
@@ -1066,6 +1073,12 @@
   if (data.unique_index_attrid_map)
     my_free((char*)data.unique_index_attrid_map, MYF(0));
   data.unique_index_attrid_map= (uchar*)my_malloc(sz,MYF(MY_WME));
+  if (data.unique_index_attrid_map == 0)
+  {
+    sql_print_error("fix_unique_index_attr_order: my_malloc(%u) failure",
+                    (unsigned int)sz);
+    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+  }
 
   KEY_PART_INFO* key_part= key_info->key_part;
   KEY_PART_INFO* end= key_part+key_info->key_parts;
@@ -3809,7 +3822,10 @@
       Ndb *ndb= get_ndb();
       ndb->setDatabaseName(m_dbname);
       struct Ndb_statistics stat;
-      ndb->setDatabaseName(m_dbname);
+      if (ndb->setDatabaseName(m_dbname))
+      {
+        DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM);
+      }
       if (current_thd->variables.ndb_use_exact_count &&
           (result= ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat))
           == 0)
@@ -4564,7 +4580,10 @@
                              HA_CREATE_INFO *info)
 {
   // Set name
-  col.setName(field->field_name);
+  if (col.setName(field->field_name))
+  {
+    return (my_errno= errno);
+  }
   // Get char set
   CHARSET_INFO *cs= field->charset();
   // Set type and sizes
@@ -4922,7 +4941,10 @@
 #endif /* HAVE_NDB_BINLOG */
 
   DBUG_PRINT("table", ("name: %s", m_tabname));  
-  tab.setName(m_tabname);
+  if (tab.setName(m_tabname))
+  {
+    DBUG_RETURN(my_errno= errno);
+  }
   tab.setLogging(!(create_info->options & HA_LEX_CREATE_TMP_TABLE));    
   tab.setSingleUserMode(single_user_mode);
 
@@ -4954,7 +4976,10 @@
     else
       col.setStorageType(NdbDictionary::Column::StorageTypeMemory);
 
-    tab.addColumn(col);
+    if (tab.addColumn(col))
+    {
+      DBUG_RETURN(my_errno= errno);
+    }
     if (col.getPrimaryKey())
       pk_length += (field->pack_length() + 3) / 4;
   }
@@ -4996,13 +5021,19 @@
   if (form->s->primary_key == MAX_KEY) 
   {
     DBUG_PRINT("info", ("Generating shadow key"));
-    col.setName("$PK");
+    if (col.setName("$PK"))
+    {
+      DBUG_RETURN(my_errno= errno);
+    }
     col.setType(NdbDictionary::Column::Bigunsigned);
     col.setLength(1);
     col.setNullable(FALSE);
     col.setPrimaryKey(TRUE);
     col.setAutoIncrement(TRUE);
-    tab.addColumn(col);
+    if (tab.addColumn(col))
+    {
+      DBUG_RETURN(my_errno= errno);
+    }
     pk_length += 2;
   }
  
@@ -5350,13 +5381,19 @@
     // TODO Only temporary ordered indexes supported
     ndb_index.setLogging(FALSE); 
   }
-  ndb_index.setTable(m_tabname);
+  if (ndb_index.setTable(m_tabname))
+  {
+    DBUG_RETURN(my_errno= errno);
+  }
 
   for (; key_part != end; key_part++) 
   {
     Field *field= key_part->field;
     DBUG_PRINT("info", ("attr: %s", field->field_name));
-    ndb_index.addColumnName(field->field_name);
+    if (ndb_index.addColumnName(field->field_name))
+    {
+      DBUG_RETURN(my_errno= errno);
+    }
   }
   
   if (dict->createIndex(ndb_index, *m_table))
@@ -5517,7 +5554,10 @@
   }
   // Change current database to that of target table
   set_dbname(to);
-  ndb->setDatabaseName(m_dbname);
+  if (ndb->setDatabaseName(m_dbname))
+  {
+    ERR_RETURN(ndb->getNdbError());
+  }
 
   NdbDictionary::Table new_tab= *orig_tab;
   new_tab.setName(new_tabname);
@@ -6091,7 +6131,10 @@
   if (!res)
   {
     Ndb *ndb= get_ndb();
-    ndb->setDatabaseName(m_dbname);
+    if (ndb->setDatabaseName(m_dbname))
+    {
+      ERR_RETURN(ndb->getNdbError());
+    }
     struct Ndb_statistics stat;
     res= ndb_get_table_statistics(NULL, FALSE, ndb, m_table, &stat);
     stats.mean_rec_length= stat.row_size;
@@ -6158,6 +6201,11 @@
   DBUG_ENTER("seize_thd_ndb");
 
   thd_ndb= new Thd_ndb();
+  if (thd_ndb == NULL)
+  {
+    my_errno= HA_ERR_OUT_OF_MEM;
+    return NULL;
+  }
   if (thd_ndb->ndb->init(max_transactions) != 0)
   {
     ERR_PRINT(thd_ndb->ndb->getNdbError());
@@ -6210,7 +6258,10 @@
   
   if (!(ndb= check_ndb_in_thd(thd)))
     DBUG_RETURN(HA_ERR_NO_CONNECTION);
-  ndb->setDatabaseName(m_dbname);
+  if (ndb->setDatabaseName(m_dbname))
+  {
+    ERR_RETURN(ndb->getNdbError());
+  }
   DBUG_RETURN(0);
 }
 
@@ -6248,7 +6299,10 @@
 
   if (!(ndb= check_ndb_in_thd(thd)))
     DBUG_RETURN(HA_ERR_NO_CONNECTION);  
-  ndb->setDatabaseName(db);
+  if (ndb->setDatabaseName(db))
+  {
+    ERR_RETURN(ndb->getNdbError());
+  }
   NDBDICT* dict= ndb->getDictionary();
   build_table_filename(key, sizeof(key), db, name, "", 0);
   /* ndb_share reference temporary */
@@ -6349,7 +6403,6 @@
 
   if (!(ndb= check_ndb_in_thd(thd)))
     DBUG_RETURN(HA_ERR_NO_CONNECTION);
-
   NDBDICT* dict= ndb->getDictionary();
   NdbDictionary::Dictionary::List list;
   if (dict->listObjects(list, NdbDictionary::Object::UserTable) != 0)
@@ -6419,8 +6472,10 @@
   char full_path[FN_REFLEN];
   char *tmp= full_path +
     build_table_filename(full_path, sizeof(full_path), dbname, "", "", 0);
-
-  ndb->setDatabaseName(dbname);
+  if (ndb->setDatabaseName(dbname))
+  {
+    ERR_RETURN(ndb->getNdbError());
+  }
   List_iterator_fast<char> it(drop_list);
   while ((tabname=it++))
   {
@@ -6911,6 +6966,7 @@
   {
     DBUG_PRINT("error",("Ndb_cluster_connection(%s)",
                         opt_ndbcluster_connectstring));
+    my_errno= HA_ERR_OUT_OF_MEM;
     goto ndbcluster_init_error;
   }
   {
@@ -6925,6 +6981,7 @@
   if ( (g_ndb= new Ndb(g_ndb_cluster_connection, "sys")) == 0 )
   {
     DBUG_PRINT("error", ("failed to create global ndb object"));
+    my_errno= HA_ERR_OUT_OF_MEM;
     goto ndbcluster_init_error;
   }
   if (g_ndb->init() != 0)
@@ -7417,7 +7474,10 @@
   Ndb *ndb;
   if (!(ndb= check_ndb_in_thd(thd)))
     DBUG_RETURN(1);
-  ndb->setDatabaseName(dbname);
+  if (ndb->setDatabaseName(dbname))
+  {
+    ERR_RETURN(ndb->getNdbError());
+  }
   uint lock= share->commit_count_lock;
   pthread_mutex_unlock(&share->mutex);
 
@@ -8633,7 +8693,10 @@
     return((char*)comment);
   }
 
-  ndb->setDatabaseName(m_dbname);
+  if (ndb->setDatabaseName(m_dbname))
+  {
+    return((char*)comment);
+  }
   const NDBTAB* tab= m_table;
   DBUG_ASSERT(tab != NULL);
 
@@ -8642,6 +8705,8 @@
   const unsigned fmt_len_plus_extra= length + strlen(fmt);
   if ((str= my_malloc(fmt_len_plus_extra, MYF(0))) == NULL)
   {
+    sql_print_error("ha_ndbcluster::update_table_comment: "
+                    "my_malloc(%u) failed", (unsigned int)fmt_len_plus_extra);
     return (char*)comment;
   }
 
@@ -8668,8 +8733,12 @@
    pthread_mutex_lock(&LOCK_ndb_util_thread);
 
   thd= new THD; /* note that contructor of THD uses DBUG_ */
+  if (thd == NULL)
+  {
+    my_errno= HA_ERR_OUT_OF_MEM;
+    DBUG_RETURN(NULL);
+  }
   THD_CHECK_SENTRY(thd);
-
   pthread_detach_this_thread();
   ndb_util_thread= pthread_self();
 
@@ -8842,11 +8911,13 @@
       pthread_mutex_lock(&share->mutex);
       lock= share->commit_count_lock;
       pthread_mutex_unlock(&share->mutex);
-
       {
         /* Contact NDB to get commit count for table */
         Ndb* ndb= thd_ndb->ndb;
-        ndb->setDatabaseName(share->db);
+        if (ndb->setDatabaseName(share->db))
+        {
+          goto loop_next;
+        }
         Ndb_table_guard ndbtab_g(ndb->getDictionary(), share->table_name);
         if (ndbtab_g.get_table() &&
             ndb_get_table_statistics(NULL, FALSE, ndb,
@@ -8869,7 +8940,7 @@
           stat.commit_count= 0;
         }
       }
-
+  loop_next:
       pthread_mutex_lock(&share->mutex);
       if (share->commit_count_lock == lock)
         share->commit_count= stat.commit_count;
@@ -8949,6 +9020,11 @@
 { 
   DBUG_ENTER("cond_push");
   Ndb_cond_stack *ndb_cond = new Ndb_cond_stack();
+  if (ndb_cond == NULL)
+  {
+    my_errno= HA_ERR_OUT_OF_MEM;
+    DBUG_RETURN(NULL);
+  }
   DBUG_EXECUTE("where",print_where((COND *)cond, m_tabname););
   if (m_cond_stack)
     ndb_cond->next= m_cond_stack;

--- 1.45/mysql-test/r/strict.result	2007-04-17 15:45:44 +02:00
+++ 1.46/mysql-test/r/strict.result	2007-04-17 15:45:44 +02:00
@@ -1388,4 +1388,9 @@
 insert into t1 values ('2E3x');
 ERROR 01000: Data truncated for column 'a' at row 1
 drop table t1;
+set sql_mode='traditional';
+create table t1 (f1 set('a','a'));
+ERROR HY000: Column 'f1' has duplicated value 'a' in SET
+create table t1 (f1 enum('a','a'));
+ERROR HY000: Column 'f1' has duplicated value 'a' in ENUM
 End of 5.0 tests
Thread
bk commit into 5.1 tree (jamppa:1.2590)jani17 Apr