Commit 79a66a97 authored by Alexey Botchkov's avatar Alexey Botchkov
Browse files

Bug#38083 Error-causing row inserted into partitioned table despite error

parent 0b097b77
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -3145,10 +3145,12 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
                                                       ppar->subpart_fields););
        /* Find the subpartition (it's HASH/KEY so we always have one) */
        partition_info *part_info= ppar->part_info;
        uint32 subpart_id= part_info->get_subpartition_id(part_info);
        uint32 part_id, subpart_id;
                 
        if (part_info->get_subpartition_id(part_info, &subpart_id))
          return 0;

        /* Mark this partition as used in each subpartition. */
        uint32 part_id;
        while ((part_id= ppar->part_iter.get_next(&ppar->part_iter)) !=
                NOT_A_PARTITION_ID)
        {
+3 −2
Original line number Diff line number Diff line
@@ -25,7 +25,8 @@ class partition_info;
typedef int (*get_part_id_func)(partition_info *part_info,
                                 uint32 *part_id,
                                 longlong *func_value);
typedef uint32 (*get_subpart_id_func)(partition_info *part_info);
typedef int (*get_subpart_id_func)(partition_info *part_info,
                                   uint32 *part_id);
 
struct st_ddl_log_memory_entry;

+153 −122
Original line number Diff line number Diff line
@@ -73,10 +73,8 @@ static int get_part_id_charset_func_subpart(partition_info *part_info,
static int get_part_part_id_charset_func(partition_info *part_info,
                                         uint32 *part_id,
                                         longlong *func_value);
static uint32 get_subpart_id_charset_func(partition_info *part_info);
int get_partition_id_list(partition_info *part_info,
                          uint32 *part_id,
                          longlong *func_value);
static int get_subpart_id_charset_func(partition_info *part_info,
                                       uint32 *part_id);
int get_partition_id_list(partition_info *part_info,
                          uint32 *part_id,
                          longlong *func_value);
@@ -119,10 +117,14 @@ int get_partition_id_list_sub_linear_hash(partition_info *part_info,
int get_partition_id_list_sub_linear_key(partition_info *part_info,
                                         uint32 *part_id,
                                         longlong *func_value);
uint32 get_partition_id_hash_sub(partition_info *part_info); 
uint32 get_partition_id_key_sub(partition_info *part_info); 
uint32 get_partition_id_linear_hash_sub(partition_info *part_info); 
uint32 get_partition_id_linear_key_sub(partition_info *part_info); 
int get_partition_id_hash_sub(partition_info *part_info,
                              uint32 *part_id); 
int get_partition_id_key_sub(partition_info *part_info,
                             uint32 *part_id); 
int get_partition_id_linear_hash_sub(partition_info *part_info,
                                     uint32 *part_id); 
int get_partition_id_linear_key_sub(partition_info *part_info,
                                    uint32 *part_id); 
static uint32 get_next_partition_via_walking(PARTITION_ITERATOR*);
static void set_up_range_analysis_info(partition_info *part_info);
static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR*);
@@ -2232,17 +2234,24 @@ bool partition_key_modified(TABLE *table, const MY_BITMAP *fields)
  SYNOPSIS
    part_val_int()
    item_expr                 The item expression to evaluate
    out:result                The value of the partition function,
                                LONGLONG_MIN if any null value in function
  RETURN VALUES
    The value of the partition function, LONGLONG_MIN if any null value
    in function
    TRUE      Error in val_int()
    FALSE     ok
*/

static inline longlong part_val_int(Item *item_expr)
static inline int part_val_int(Item *item_expr, longlong *result)
{
  longlong value= item_expr->val_int();
  *result= item_expr->val_int();
  if (item_expr->null_value)
    value= LONGLONG_MIN;
  return value;
  {
    if (current_thd->is_error())
      return TRUE;
    else
      *result= LONGLONG_MIN;
  }
  return FALSE;
}


@@ -2319,24 +2328,29 @@ static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id,
    get_part_id_hash()
    no_parts                 Number of hash partitions
    part_expr                Item tree of hash function
    out:part_id              The returned partition id
    out:func_value           Value of hash function

  RETURN VALUE
    Calculated partition id
    != 0                          Error code
    FALSE                         Success
*/

inline
static uint32 get_part_id_hash(uint no_parts,
static int get_part_id_hash(uint no_parts,
                            Item *part_expr,
                            uint32 *part_id,
                            longlong *func_value)
{
  longlong int_hash_id;
  DBUG_ENTER("get_part_id_hash");

  *func_value= part_val_int(part_expr);
  if (part_val_int(part_expr, func_value))
    DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);

  int_hash_id= *func_value % no_parts;

  DBUG_RETURN(int_hash_id < 0 ? (uint32) -int_hash_id : (uint32) int_hash_id);
  *part_id= int_hash_id < 0 ? (uint32) -int_hash_id : (uint32) int_hash_id;
  DBUG_RETURN(FALSE);
}


@@ -2349,24 +2363,29 @@ static uint32 get_part_id_hash(uint no_parts,
                        desired information is given
    no_parts            Number of hash partitions
    part_expr           Item tree of hash function
    out:part_id         The returned partition id
    out:func_value      Value of hash function

  RETURN VALUE
    Calculated partition id
    != 0     Error code
    0        OK
*/

inline
static uint32 get_part_id_linear_hash(partition_info *part_info,
static int get_part_id_linear_hash(partition_info *part_info,
                                   uint no_parts,
                                   Item *part_expr,
                                   uint32 *part_id,
                                   longlong *func_value)
{
  DBUG_ENTER("get_part_id_linear_hash");

  *func_value= part_val_int(part_expr);
  DBUG_RETURN(get_part_id_from_linear_hash(*func_value,
  if (part_val_int(part_expr, func_value))
    DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);

  *part_id= get_part_id_from_linear_hash(*func_value,
                                         part_info->linear_hash_mask,
                                           no_parts));
                                         no_parts);
  DBUG_RETURN(FALSE);
}


@@ -2503,49 +2522,7 @@ static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr)
  }
  return;
}
/*
  This function is used to calculate the partition id where all partition
  fields have been prepared to point to a record where the partition field
  values are bound.

  SYNOPSIS
    get_partition_id()
    part_info           A reference to the partition_info struct where all the
                        desired information is given
    out:part_id         The partition id is returned through this pointer
    out: func_value     Value of partition function (longlong)

  RETURN VALUE
    part_id                     Partition id of partition that would contain
                                row with given values of PF-fields
    HA_ERR_NO_PARTITION_FOUND   The fields of the partition function didn't
                                fit into any partition and thus the values of 
                                the PF-fields are not allowed.

  DESCRIPTION
    A routine used from write_row, update_row and delete_row from any
    handler supporting partitioning. It is also a support routine for
    get_partition_set used to find the set of partitions needed to scan
    for a certain index scan or full table scan.
    
    It is actually 14 different variants of this function which are called
    through a function pointer.

    get_partition_id_list
    get_partition_id_range
    get_partition_id_hash_nosub
    get_partition_id_key_nosub
    get_partition_id_linear_hash_nosub
    get_partition_id_linear_key_nosub
    get_partition_id_range_sub_hash
    get_partition_id_range_sub_key
    get_partition_id_range_sub_linear_hash
    get_partition_id_range_sub_linear_key
    get_partition_id_list_sub_hash
    get_partition_id_list_sub_key
    get_partition_id_list_sub_linear_hash
    get_partition_id_list_sub_linear_key
*/

/*
  This function is used to calculate the main partition to use in the case of
@@ -2560,11 +2537,10 @@ static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr)
    out:func_value      The value calculated by partition function

  RETURN VALUE
    part_id                     Partition id of partition that would contain
                                row with given values of PF-fields
    HA_ERR_NO_PARTITION_FOUND   The fields of the partition function didn't
                                fit into any partition and thus the values of 
                                the PF-fields are not allowed.
    0                           OK

  DESCRIPTION
    
@@ -2640,13 +2616,14 @@ static int get_part_part_id_charset_func(partition_info *part_info,
}


static uint32 get_subpart_id_charset_func(partition_info *part_info)
static int get_subpart_id_charset_func(partition_info *part_info,
                                       uint32 *part_id)
{
  int res;
  copy_to_part_field_buffers(part_info->subpart_charset_field_array,
                             part_info->subpart_field_buffers,
                             part_info->restore_subpart_field_ptrs);
  res= part_info->get_subpartition_id_charset(part_info);
  res= part_info->get_subpartition_id_charset(part_info, part_id);
  restore_part_field_pointers(part_info->subpart_charset_field_array,
                              part_info->restore_subpart_field_ptrs);
  return res;
@@ -2661,11 +2638,15 @@ int get_partition_id_list(partition_info *part_info,
  int list_index;
  int min_list_index= 0;
  int max_list_index= part_info->no_list_values - 1;
  longlong part_func_value= part_val_int(part_info->part_expr);
  longlong part_func_value;
  int error= part_val_int(part_info->part_expr, &part_func_value);
  longlong list_value;
  bool unsigned_flag= part_info->part_expr->unsigned_flag;
  DBUG_ENTER("get_partition_id_list");

  if (error)
    goto notfound;

  if (part_info->part_expr->null_value)
  {
    if (part_info->has_null_value)
@@ -2809,10 +2790,14 @@ int get_partition_id_range(partition_info *part_info,
  uint min_part_id= 0;
  uint max_part_id= max_partition;
  uint loc_part_id;
  longlong part_func_value= part_val_int(part_info->part_expr);
  longlong part_func_value;
  int error= part_val_int(part_info->part_expr, &part_func_value);
  bool unsigned_flag= part_info->part_expr->unsigned_flag;
  DBUG_ENTER("get_partition_id_range");

  if (error)
    DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);

  if (part_info->part_expr->null_value)
  {
    *part_id= 0;
@@ -2970,9 +2955,8 @@ int get_partition_id_hash_nosub(partition_info *part_info,
                                 uint32 *part_id,
                                 longlong *func_value)
{
  *part_id= get_part_id_hash(part_info->no_parts, part_info->part_expr,
                             func_value);
  return 0;
  return get_part_id_hash(part_info->no_parts, part_info->part_expr,
                          part_id, func_value);
}


@@ -2980,9 +2964,8 @@ int get_partition_id_linear_hash_nosub(partition_info *part_info,
                                        uint32 *part_id,
                                        longlong *func_value)
{
  *part_id= get_part_id_linear_hash(part_info, part_info->no_parts,
                                    part_info->part_expr, func_value);
  return 0;
  return get_part_id_linear_hash(part_info, part_info->no_parts,
                                 part_info->part_expr, part_id, func_value);
}


@@ -3023,8 +3006,12 @@ int get_partition_id_range_sub_hash(partition_info *part_info,
    DBUG_RETURN(error);
  }
  no_subparts= part_info->no_subparts;
  sub_part_id= get_part_id_hash(no_subparts, part_info->subpart_expr,
                                &local_func_value);
  if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr,
                                        &sub_part_id, &local_func_value))))
  {
    DBUG_RETURN(error);
  }

  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
  DBUG_RETURN(0);
}
@@ -3046,9 +3033,14 @@ int get_partition_id_range_sub_linear_hash(partition_info *part_info,
    DBUG_RETURN(error);
  }
  no_subparts= part_info->no_subparts;
  sub_part_id= get_part_id_linear_hash(part_info, no_subparts,
  if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts,
                                               part_info->subpart_expr,
                                       &local_func_value);
                                               &sub_part_id,
                                               &local_func_value))))
  {
    DBUG_RETURN(error);
  }

  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
  DBUG_RETURN(0);
}
@@ -3117,8 +3109,12 @@ int get_partition_id_list_sub_hash(partition_info *part_info,
    DBUG_RETURN(error);
  }
  no_subparts= part_info->no_subparts;
  sub_part_id= get_part_id_hash(no_subparts, part_info->subpart_expr,
                                &local_func_value);
  if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr,
                                        &sub_part_id, &local_func_value))))
  {
    DBUG_RETURN(error);
  }

  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
  DBUG_RETURN(0);
}
@@ -3140,9 +3136,14 @@ int get_partition_id_list_sub_linear_hash(partition_info *part_info,
    DBUG_RETURN(error);
  }
  no_subparts= part_info->no_subparts;
  sub_part_id= get_part_id_linear_hash(part_info, no_subparts,
  if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts,
                                               part_info->subpart_expr,
                                       &local_func_value);
                                               &sub_part_id,
                                               &local_func_value))))
  {
    DBUG_RETURN(error);
  }
   
  *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
  DBUG_RETURN(0);
}
@@ -3219,36 +3220,43 @@ int get_partition_id_list_sub_linear_key(partition_info *part_info,
    get_partition_id_linear_key_sub
*/

uint32 get_partition_id_hash_sub(partition_info *part_info)
int get_partition_id_hash_sub(partition_info *part_info,
                              uint32 *part_id)
{
  longlong func_value;
  return get_part_id_hash(part_info->no_subparts, part_info->subpart_expr,
                          &func_value);
                          part_id, &func_value);
}


uint32 get_partition_id_linear_hash_sub(partition_info *part_info)
int get_partition_id_linear_hash_sub(partition_info *part_info,
                                     uint32 *part_id)
{
  longlong func_value;
  return get_part_id_linear_hash(part_info, part_info->no_subparts,
                                 part_info->subpart_expr, &func_value);
                                 part_info->subpart_expr, part_id,
                                 &func_value);
}


uint32 get_partition_id_key_sub(partition_info *part_info)
int get_partition_id_key_sub(partition_info *part_info,
                             uint32 *part_id)
{
  longlong func_value;
  return get_part_id_key(part_info->subpart_field_array,
  *part_id= get_part_id_key(part_info->subpart_field_array,
                            part_info->no_subparts, &func_value);
  return FALSE;
}


uint32 get_partition_id_linear_key_sub(partition_info *part_info)
int get_partition_id_linear_key_sub(partition_info *part_info,
                                       uint32 *part_id)
{
  longlong func_value;
  return get_part_id_linear_key(part_info,
  *part_id= get_part_id_linear_key(part_info,
                                   part_info->subpart_field_array,
                                   part_info->no_subparts, &func_value);
  return FALSE;
}


@@ -3337,37 +3345,40 @@ static bool check_part_func_bound(Field **ptr)
    buf           A buffer that can be used to evaluate the partition function
    key_info      The index object
    key_spec      A key_range containing key and key length
    out:part_id   The returned partition id

  RETURN VALUES
    part_id       Subpartition id to use
    TRUE                    All fields in partition function are set
    FALSE                   Not all fields in partition function are set

  DESCRIPTION
    Use key buffer to set-up record in buf, move field pointers and
    get the partition identity and restore field pointers afterwards.
*/

static uint32 get_sub_part_id_from_key(const TABLE *table,uchar *buf,
static int get_sub_part_id_from_key(const TABLE *table,uchar *buf,
                                    KEY *key_info,
                                       const key_range *key_spec)
                                    const key_range *key_spec,
                                    uint32 *part_id)
{
  uchar *rec0= table->record[0];
  partition_info *part_info= table->part_info;
  uint32 part_id;
  int res;
  DBUG_ENTER("get_sub_part_id_from_key");

  key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
  if (likely(rec0 == buf))
  {
    part_id= part_info->get_subpartition_id(part_info);
    res= part_info->get_subpartition_id(part_info, part_id);
  }
  else
  {
    Field **part_field_array= part_info->subpart_field_array;
    set_field_ptr(part_field_array, buf, rec0);
    part_id= part_info->get_subpartition_id(part_info);
    res= part_info->get_subpartition_id(part_info, part_id);
    set_field_ptr(part_field_array, rec0, buf);
  }
  DBUG_RETURN(part_id);
  DBUG_RETURN(res);
}

/*
@@ -3586,7 +3597,13 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
      else if (part_info->is_sub_partitioned())
      {
        if (part_info->all_fields_in_SPF.is_set(index))
          sub_part= get_sub_part_id_from_key(table, buf, key_info, key_spec);
        {
          if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part))
          {
            part_spec->start_part= no_parts;
            DBUG_VOID_RETURN;
          }
        }
        else if (part_info->all_fields_in_PPF.is_set(index))
        {
          if (get_part_id_from_key(table,buf,key_info,
@@ -3632,7 +3649,14 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
        else if (part_info->is_sub_partitioned())
        {
          if (check_part_func_bound(part_info->subpart_field_array))
            sub_part= get_sub_part_id_from_key(table, buf, key_info, key_spec);
          {
            if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part))
            {
              part_spec->start_part= no_parts;
              clear_indicator_in_key_fields(key_info);
              DBUG_VOID_RETURN;
            }
          }
          else if (check_part_func_bound(part_info->part_field_array))
          {
            if (get_part_id_from_key(table,buf,key_info,key_spec,&part_part))
@@ -6836,10 +6860,12 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
    field->set_null();
    if (is_subpart)
    {
      part_id= part_info->get_subpartition_id(part_info);
      if (!part_info->get_subpartition_id(part_info, &part_id))
      {
        init_single_partition_iterator(part_id, part_iter);
        return 1; /* Ok, iterator initialized */
      }
    }
    else
    {
      longlong dummy;
@@ -7007,13 +7033,18 @@ static uint32 get_next_partition_via_walking(PARTITION_ITERATOR *part_iter)
static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter)
{
  Field *field= part_iter->part_info->subpart_field_array[0];
  uint32 res;
  if (part_iter->field_vals.cur == part_iter->field_vals.end)
  {
    part_iter->field_vals.cur= part_iter->field_vals.start;
    return NOT_A_PARTITION_ID;
  }
  field->store(part_iter->field_vals.cur++, FALSE);
  return part_iter->part_info->get_subpartition_id(part_iter->part_info);
  if (part_iter->part_info->get_subpartition_id(part_iter->part_info,
                                                &res))
    return NOT_A_PARTITION_ID;
  return res;

}