← Back to team overview

maria-developers team mailing list archive

Re: MDEV-9369 IN operator with ( num, NULL ) gives inconsistent result

 

Hi Sergei,


On 03/16/2016 09:51 PM, Sergei Golubchik wrote:
> Hi, Alexander!
> 
> On Feb 08, Alexander Barkov wrote:
>> Hello Sergei,
>>
>> Please review a patch for MDEV-9369.
>>
>> Briefly, it fixes cmp_item::cmp() to return three possible values: 
>> FALSE, TRUE, UNKNOWN. These values are then recursively pulled to
>> the very top level, to the owner Item_xxx.
>>
>> The owner Item_func_in (as well as Item_func_case and Item_func_equal)
>> then further "translate" these tree-values logic into the traditional
>> val_int()+null_value combination using some additional information.
>>
>> For example, Item_func_in::val_int() uses "negated" as an additional
>> information.
>>
>> The patch looks Ok for me.
> 
> Looks ok to me too. A couple of stylistic comments, see below.
> ok to push afterwards.
> 
>> diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
>> index d5f5087..39003de 100644
>> --- a/sql/item_cmpfunc.cc
>> +++ b/sql/item_cmpfunc.cc
>> @@ -3837,15 +3843,15 @@ void cmp_item_decimal::store_value(Item *item)
>>    /* val may be zero if item is nnull */
>>    if (val && val != &value)
>>      my_decimal2decimal(val, &value);
>> +  set_null_value(item->null_value);
>>  }
>>  
>>  
>>  int cmp_item_decimal::cmp(Item *arg)
>>  {
>>    my_decimal tmp_buf, *tmp= arg->val_decimal(&tmp_buf);
>> -  if (arg->null_value)
>> -    return 1;
>> -  return my_decimal_cmp(&value, tmp);
>> +  return (m_null_value || arg->null_value) ?
> 
> if you access m_null_value directly, you don't need a setter for it.
> it'll be less confusing if you replace set_null_value(X) with m_null_value=X.
> 
> alternatively, you can add a getter is_null_value(). But I personally
> wouldn't do it, cmp_xxx is a small set of simple classes, no need to get
> too enterprisey there.


Removed set_null_value(), changed to use m_null_value directly.


> 
>> +    UNKNOWN : (my_decimal_cmp(&value, tmp) != 0);
>>  }
>>  
>>  
>> @@ -3892,10 +3900,10 @@ cmp_item *cmp_item_datetime::make_same()
>>  }
>>  
>>  
>> -bool Item_func_in::nulls_in_row()
>> +bool Item_func_in::list_contains_null()
> 
> I found the old name clear enough. But ok, whatever...
> 
>>  {
>>    Item **arg,**arg_end;
>> -  for (arg= args+1, arg_end= args+arg_count; arg != arg_end ; arg++)
>> +  for (arg= args + 1, arg_end= args+arg_count; arg != arg_end ; arg++)
>>    {
>>      if ((*arg)->null_inside())
>>        return 1;
>> @@ -4010,6 +4018,32 @@ void Item_func_in::fix_length_and_dec()
>>      }
>>    }
>>  
>> +  /*
>> +    First conditions for bisection to be possible:
>> +     1. All types are similar, and
>> +     2. All expressions in <in value list> are const
>> +  */
>> +  bool bisection_possible=
>> +    type_cnt == 1 &&                                   // 1
>> +    const_itm;                                         // 2
>> +  if (bisection_possible)
>> +  {
>> +    /*
>> +      In the presence of NULLs, the correct result of evaluating this item
>> +      must be UNKNOWN or FALSE. To achieve that:
>> +      - If type is scalar, we can use bisection and the "have_null" boolean.
>> +      - If type is ROW, we will need to scan all of <in value list> when
>> +        searching, so bisection is impossible. Unless:
>> +        3. UNKNOWN and FALSE are equivalent results
>> +        4. Neither left expression nor <in value list> contain any NULL value
>> +      */
>> +
>> +    if (cmp_type == ROW_RESULT &&
>> +        !((is_top_level_item() && !negated) ||              // 3
>> +          (!list_contains_null() && !args[0]->maybe_null))) // 4
>> +      bisection_possible= false;
> 
> I think the condition will be easier to understand if you remove the
> negation of that complex condition in parentheses:
> 
>     if (cmp_type == ROW_RESULT &&
>         ((!is_top_level_item() || negated) &&             // 3
>           (list_contains_null() || args[0]->maybe_null))) // 4
> 
> I find this ^^^ much easier to understand.

Agreed. Fixed to use your version.

Thanks for review! I pushed the patch.

> 
>> +  }
>> +
>>    if (type_cnt == 1)
>>    {
>>      if (cmp_type == STRING_RESULT && 
> 
> Regards,
> Sergei
> Chief Architect MariaDB
> and security@xxxxxxxxxxx
> 


References