maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #09404
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