mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-11485 Split Item_func_between::val_int() into virtual methods in Type_handler
- Removes "Item_result Item_func_opt_neg::m_compare_type" and introduces "Type_handler_hybrid_field_type Item_func_opt_neg::m_comparator" instead. - Removes Item_func_between::compare_as_dates, because the new member m_comparator now contains the precise information about the data type that is used for comparison, which is important for TIME vs DATETIME. - Adds a new method: Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler*), as a better replacement for item_cmp_type(), which additionally can handle TIME vs DATE/DATETIME/TIMESTAMP correctly. Additionally, it correctly handles TIMESTAMP which fixes the problem reported in MDEV-11482. The old compare_as_dates/find_date_time_item() based code didn't handle comparison between TIME and TIMESTAMP correctly and erroneously used TIME comparison instead of DATETIME comparison. - Adds a new method: Type_handler_hybrid_field_type::aggregate_for_comparison(Item **, uint nitems), as a better replacement for agg_cmp_type(), which can handle TIME. - Splits Item_func_between::val_int() into pieces val_int_cmp_xxx(), one new method per XXX_RESULT. - Adds a new virtual method Type_handler::Item_func_between_val_int() whose implementations use Item_func_between::val_int_cmp_xxx(). - Makes type_handler_longlong and type_handler_newdecimal public, as they are now needed in item_cmpfunc.cc. Note: This patch does not change Item_func_in to use the new aggregation methods, so it still uses collect_cmp_type()/item_cmp_type() based aggregation. Item_func_in will be changed in a separate patch and item_cmp_type() will be removed.
This commit is contained in:
@ -980,5 +980,17 @@ Warnings:
|
|||||||
Warning 1441 Datetime function: datetime field overflow
|
Warning 1441 Datetime function: datetime field overflow
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
#
|
#
|
||||||
|
# MDEV-11482 Incorrect result for (time_expr BETWEEN timestamp_exp1 AND timestamp_expr2)
|
||||||
|
#
|
||||||
|
SET @@sql_mode=DEFAULT;
|
||||||
|
SET @@timestamp=UNIX_TIMESTAMP('2001-01-01 10:20:30');
|
||||||
|
CREATE TABLE t1 (a TIMESTAMP,b TIMESTAMP);
|
||||||
|
INSERT INTO t1 VALUES ('2001-01-01 00:00:00','2001-01-01 23:59:59');
|
||||||
|
SELECT * FROM t1 WHERE TIME'10:20:30' BETWEEN a and b;
|
||||||
|
a b
|
||||||
|
2001-01-01 00:00:00 2001-01-01 23:59:59
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET @@timestamp=DEFAULT;
|
||||||
|
#
|
||||||
# End of 10.3 tests
|
# End of 10.3 tests
|
||||||
#
|
#
|
||||||
|
@ -576,6 +576,17 @@ EXPLAIN SELECT * FROM t1 WHERE a >= DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTE
|
|||||||
EXPLAIN SELECT * FROM t1 WHERE a >= COALESCE(DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR));
|
EXPLAIN SELECT * FROM t1 WHERE a >= COALESCE(DATE_ADD(TIMESTAMP'9999-01-01 00:00:00',INTERVAL 1000 YEAR));
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-11482 Incorrect result for (time_expr BETWEEN timestamp_exp1 AND timestamp_expr2)
|
||||||
|
--echo #
|
||||||
|
SET @@sql_mode=DEFAULT;
|
||||||
|
SET @@timestamp=UNIX_TIMESTAMP('2001-01-01 10:20:30');
|
||||||
|
CREATE TABLE t1 (a TIMESTAMP,b TIMESTAMP);
|
||||||
|
INSERT INTO t1 VALUES ('2001-01-01 00:00:00','2001-01-01 23:59:59');
|
||||||
|
SELECT * FROM t1 WHERE TIME'10:20:30' BETWEEN a and b;
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET @@timestamp=DEFAULT;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.3 tests
|
--echo # End of 10.3 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -118,14 +118,15 @@ static int cmp_row_type(Item* item1, Item* item2)
|
|||||||
0 otherwise
|
0 otherwise
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int agg_cmp_type(Item_result *type, Item **items, uint nitems)
|
bool Type_handler_hybrid_field_type::aggregate_for_comparison(Item **items,
|
||||||
|
uint nitems)
|
||||||
{
|
{
|
||||||
uint unsigned_count= items[0]->unsigned_flag;
|
uint unsigned_count= items[0]->unsigned_flag;
|
||||||
type[0]= items[0]->cmp_type();
|
set_handler(items[0]->type_handler());
|
||||||
for (uint i= 1 ; i < nitems ; i++)
|
for (uint i= 1 ; i < nitems ; i++)
|
||||||
{
|
{
|
||||||
unsigned_count+= items[i]->unsigned_flag;
|
unsigned_count+= items[i]->unsigned_flag;
|
||||||
type[0]= item_cmp_type(type[0], items[i]);
|
aggregate_for_comparison(items[i]->type_handler());
|
||||||
/*
|
/*
|
||||||
When aggregating types of two row expressions we have to check
|
When aggregating types of two row expressions we have to check
|
||||||
that they have the same cardinality and that each component
|
that they have the same cardinality and that each component
|
||||||
@ -133,15 +134,16 @@ static int agg_cmp_type(Item_result *type, Item **items, uint nitems)
|
|||||||
the signature of the corresponding component of the second row
|
the signature of the corresponding component of the second row
|
||||||
expression.
|
expression.
|
||||||
*/
|
*/
|
||||||
if (type[0] == ROW_RESULT && cmp_row_type(items[0], items[i]))
|
if (cmp_type() == ROW_RESULT && cmp_row_type(items[0], items[i]))
|
||||||
return 1; // error found: invalid usage of rows
|
return true; // error found: invalid usage of rows
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
If all arguments are of INT type but have different unsigned_flag values,
|
If all arguments are of INT type but have different unsigned_flag values,
|
||||||
switch to DECIMAL_RESULT.
|
switch to DECIMAL_RESULT.
|
||||||
*/
|
*/
|
||||||
if (type[0] == INT_RESULT && unsigned_count != nitems && unsigned_count != 0)
|
if (cmp_type() == INT_RESULT &&
|
||||||
type[0]= DECIMAL_RESULT;
|
unsigned_count != nitems && unsigned_count != 0)
|
||||||
|
set_handler(&type_handler_newdecimal);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2069,7 +2071,6 @@ void Item_func_between::fix_length_and_dec()
|
|||||||
{
|
{
|
||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
max_length= 1;
|
max_length= 1;
|
||||||
compare_as_dates= 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
As some compare functions are generated after sql_yacc,
|
As some compare functions are generated after sql_yacc,
|
||||||
@ -2077,24 +2078,13 @@ void Item_func_between::fix_length_and_dec()
|
|||||||
*/
|
*/
|
||||||
if (!args[0] || !args[1] || !args[2])
|
if (!args[0] || !args[1] || !args[2])
|
||||||
return;
|
return;
|
||||||
if (agg_cmp_type(&m_compare_type, args, 3))
|
if (m_comparator.aggregate_for_comparison(args, 3))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_compare_type == STRING_RESULT &&
|
if (m_comparator.cmp_type() == STRING_RESULT &&
|
||||||
agg_arg_charsets_for_comparison(cmp_collation, args, 3))
|
agg_arg_charsets_for_comparison(cmp_collation, args, 3))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
|
||||||
When comparing as date/time, we need to convert non-temporal values
|
|
||||||
(e.g. strings) to MYSQL_TIME. get_datetime_value() does it
|
|
||||||
automatically when one of the operands is a date/time. But here we
|
|
||||||
may need to compare two strings as dates (str1 BETWEEN str2 AND date).
|
|
||||||
For this to work, we need to know what date/time type we compare
|
|
||||||
strings as.
|
|
||||||
*/
|
|
||||||
if (m_compare_type == TIME_RESULT)
|
|
||||||
compare_as_dates= find_date_time_item(args, 3, 0);
|
|
||||||
|
|
||||||
/* See the comment about the similar block in Item_bool_func2 */
|
/* See the comment about the similar block in Item_bool_func2 */
|
||||||
if (args[0]->real_item()->type() == FIELD_ITEM &&
|
if (args[0]->real_item()->type() == FIELD_ITEM &&
|
||||||
!thd->lex->is_ps_or_view_context_analysis())
|
!thd->lex->is_ps_or_view_context_analysis())
|
||||||
@ -2106,145 +2096,143 @@ void Item_func_between::fix_length_and_dec()
|
|||||||
const bool cvt_arg1= convert_const_to_int(thd, field_item, &args[1]);
|
const bool cvt_arg1= convert_const_to_int(thd, field_item, &args[1]);
|
||||||
const bool cvt_arg2= convert_const_to_int(thd, field_item, &args[2]);
|
const bool cvt_arg2= convert_const_to_int(thd, field_item, &args[2]);
|
||||||
if (cvt_arg1 && cvt_arg2)
|
if (cvt_arg1 && cvt_arg2)
|
||||||
m_compare_type= INT_RESULT; // Works for all types.
|
{
|
||||||
|
// Works for all types
|
||||||
|
m_comparator.set_handler(&type_handler_longlong);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
longlong Item_func_between::val_int()
|
longlong Item_func_between::val_int_cmp_temporal()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
THD *thd= current_thd;
|
||||||
|
longlong value, a, b;
|
||||||
|
Item *cache, **ptr;
|
||||||
|
bool value_is_null, a_is_null, b_is_null;
|
||||||
|
|
||||||
switch (m_compare_type) {
|
ptr= &args[0];
|
||||||
case TIME_RESULT:
|
enum_field_types f_type= m_comparator.field_type();
|
||||||
{
|
value= get_datetime_value(thd, &ptr, &cache, f_type, &value_is_null);
|
||||||
THD *thd= current_thd;
|
if (ptr != &args[0])
|
||||||
longlong value, a, b;
|
thd->change_item_tree(&args[0], *ptr);
|
||||||
Item *cache, **ptr;
|
|
||||||
bool value_is_null, a_is_null, b_is_null;
|
|
||||||
|
|
||||||
ptr= &args[0];
|
if ((null_value= value_is_null))
|
||||||
enum_field_types f_type= field_type_for_temporal_comparison(compare_as_dates);
|
|
||||||
value= get_datetime_value(thd, &ptr, &cache, f_type, &value_is_null);
|
|
||||||
if (ptr != &args[0])
|
|
||||||
thd->change_item_tree(&args[0], *ptr);
|
|
||||||
|
|
||||||
if ((null_value= value_is_null))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ptr= &args[1];
|
|
||||||
a= get_datetime_value(thd, &ptr, &cache, f_type, &a_is_null);
|
|
||||||
if (ptr != &args[1])
|
|
||||||
thd->change_item_tree(&args[1], *ptr);
|
|
||||||
|
|
||||||
ptr= &args[2];
|
|
||||||
b= get_datetime_value(thd, &ptr, &cache, f_type, &b_is_null);
|
|
||||||
if (ptr != &args[2])
|
|
||||||
thd->change_item_tree(&args[2], *ptr);
|
|
||||||
|
|
||||||
if (!a_is_null && !b_is_null)
|
|
||||||
return (longlong) ((value >= a && value <= b) != negated);
|
|
||||||
if (a_is_null && b_is_null)
|
|
||||||
null_value=1;
|
|
||||||
else if (a_is_null)
|
|
||||||
null_value= value <= b; // not null if false range.
|
|
||||||
else
|
|
||||||
null_value= value >= a;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case STRING_RESULT:
|
|
||||||
{
|
|
||||||
String *value,*a,*b;
|
|
||||||
value=args[0]->val_str(&value0);
|
|
||||||
if ((null_value=args[0]->null_value))
|
|
||||||
return 0;
|
|
||||||
a=args[1]->val_str(&value1);
|
|
||||||
b=args[2]->val_str(&value2);
|
|
||||||
if (!args[1]->null_value && !args[2]->null_value)
|
|
||||||
return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 &&
|
|
||||||
sortcmp(value,b,cmp_collation.collation) <= 0) !=
|
|
||||||
negated);
|
|
||||||
if (args[1]->null_value && args[2]->null_value)
|
|
||||||
null_value=1;
|
|
||||||
else if (args[1]->null_value)
|
|
||||||
{
|
|
||||||
// Set to not null if false range.
|
|
||||||
null_value= sortcmp(value,b,cmp_collation.collation) <= 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Set to not null if false range.
|
|
||||||
null_value= sortcmp(value,a,cmp_collation.collation) >= 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case INT_RESULT:
|
|
||||||
{
|
|
||||||
longlong value=args[0]->val_int(), a, b;
|
|
||||||
if ((null_value=args[0]->null_value))
|
|
||||||
return 0; /* purecov: inspected */
|
|
||||||
a=args[1]->val_int();
|
|
||||||
b=args[2]->val_int();
|
|
||||||
if (!args[1]->null_value && !args[2]->null_value)
|
|
||||||
return (longlong) ((value >= a && value <= b) != negated);
|
|
||||||
if (args[1]->null_value && args[2]->null_value)
|
|
||||||
null_value=1;
|
|
||||||
else if (args[1]->null_value)
|
|
||||||
{
|
|
||||||
null_value= value <= b; // not null if false range.
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
null_value= value >= a;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DECIMAL_RESULT:
|
|
||||||
{
|
|
||||||
my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf),
|
|
||||||
a_buf, *a_dec, b_buf, *b_dec;
|
|
||||||
if ((null_value=args[0]->null_value))
|
|
||||||
return 0; /* purecov: inspected */
|
|
||||||
a_dec= args[1]->val_decimal(&a_buf);
|
|
||||||
b_dec= args[2]->val_decimal(&b_buf);
|
|
||||||
if (!args[1]->null_value && !args[2]->null_value)
|
|
||||||
return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 &&
|
|
||||||
my_decimal_cmp(dec, b_dec) <= 0) != negated);
|
|
||||||
if (args[1]->null_value && args[2]->null_value)
|
|
||||||
null_value=1;
|
|
||||||
else if (args[1]->null_value)
|
|
||||||
null_value= (my_decimal_cmp(dec, b_dec) <= 0);
|
|
||||||
else
|
|
||||||
null_value= (my_decimal_cmp(dec, a_dec) >= 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case REAL_RESULT:
|
|
||||||
{
|
|
||||||
double value= args[0]->val_real(),a,b;
|
|
||||||
if ((null_value=args[0]->null_value))
|
|
||||||
return 0; /* purecov: inspected */
|
|
||||||
a= args[1]->val_real();
|
|
||||||
b= args[2]->val_real();
|
|
||||||
if (!args[1]->null_value && !args[2]->null_value)
|
|
||||||
return (longlong) ((value >= a && value <= b) != negated);
|
|
||||||
if (args[1]->null_value && args[2]->null_value)
|
|
||||||
null_value=1;
|
|
||||||
else if (args[1]->null_value)
|
|
||||||
{
|
|
||||||
null_value= value <= b; // not null if false range.
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
null_value= value >= a;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ROW_RESULT:
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
null_value= 1;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
ptr= &args[1];
|
||||||
|
a= get_datetime_value(thd, &ptr, &cache, f_type, &a_is_null);
|
||||||
|
if (ptr != &args[1])
|
||||||
|
thd->change_item_tree(&args[1], *ptr);
|
||||||
|
|
||||||
|
ptr= &args[2];
|
||||||
|
b= get_datetime_value(thd, &ptr, &cache, f_type, &b_is_null);
|
||||||
|
if (ptr != &args[2])
|
||||||
|
thd->change_item_tree(&args[2], *ptr);
|
||||||
|
|
||||||
|
if (!a_is_null && !b_is_null)
|
||||||
|
return (longlong) ((value >= a && value <= b) != negated);
|
||||||
|
if (a_is_null && b_is_null)
|
||||||
|
null_value= true;
|
||||||
|
else if (a_is_null)
|
||||||
|
null_value= value <= b; // not null if false range.
|
||||||
|
else
|
||||||
|
null_value= value >= a;
|
||||||
|
return (longlong) (!null_value && negated);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
longlong Item_func_between::val_int_cmp_string()
|
||||||
|
{
|
||||||
|
String *value,*a,*b;
|
||||||
|
value=args[0]->val_str(&value0);
|
||||||
|
if ((null_value=args[0]->null_value))
|
||||||
|
return 0;
|
||||||
|
a= args[1]->val_str(&value1);
|
||||||
|
b= args[2]->val_str(&value2);
|
||||||
|
if (!args[1]->null_value && !args[2]->null_value)
|
||||||
|
return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 &&
|
||||||
|
sortcmp(value,b,cmp_collation.collation) <= 0) !=
|
||||||
|
negated);
|
||||||
|
if (args[1]->null_value && args[2]->null_value)
|
||||||
|
null_value= true;
|
||||||
|
else if (args[1]->null_value)
|
||||||
|
{
|
||||||
|
// Set to not null if false range.
|
||||||
|
null_value= sortcmp(value,b,cmp_collation.collation) <= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Set to not null if false range.
|
||||||
|
null_value= sortcmp(value,a,cmp_collation.collation) >= 0;
|
||||||
|
}
|
||||||
|
return (longlong) (!null_value && negated);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
longlong Item_func_between::val_int_cmp_int()
|
||||||
|
{
|
||||||
|
longlong value= args[0]->val_int(), a, b;
|
||||||
|
if ((null_value= args[0]->null_value))
|
||||||
|
return 0; /* purecov: inspected */
|
||||||
|
a= args[1]->val_int();
|
||||||
|
b= args[2]->val_int();
|
||||||
|
if (!args[1]->null_value && !args[2]->null_value)
|
||||||
|
return (longlong) ((value >= a && value <= b) != negated);
|
||||||
|
if (args[1]->null_value && args[2]->null_value)
|
||||||
|
null_value= true;
|
||||||
|
else if (args[1]->null_value)
|
||||||
|
{
|
||||||
|
null_value= value <= b; // not null if false range.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
null_value= value >= a;
|
||||||
|
}
|
||||||
|
return (longlong) (!null_value && negated);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
longlong Item_func_between::val_int_cmp_decimal()
|
||||||
|
{
|
||||||
|
my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf),
|
||||||
|
a_buf, *a_dec, b_buf, *b_dec;
|
||||||
|
if ((null_value=args[0]->null_value))
|
||||||
|
return 0; /* purecov: inspected */
|
||||||
|
a_dec= args[1]->val_decimal(&a_buf);
|
||||||
|
b_dec= args[2]->val_decimal(&b_buf);
|
||||||
|
if (!args[1]->null_value && !args[2]->null_value)
|
||||||
|
return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 &&
|
||||||
|
my_decimal_cmp(dec, b_dec) <= 0) != negated);
|
||||||
|
if (args[1]->null_value && args[2]->null_value)
|
||||||
|
null_value= true;
|
||||||
|
else if (args[1]->null_value)
|
||||||
|
null_value= (my_decimal_cmp(dec, b_dec) <= 0);
|
||||||
|
else
|
||||||
|
null_value= (my_decimal_cmp(dec, a_dec) >= 0);
|
||||||
|
return (longlong) (!null_value && negated);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
longlong Item_func_between::val_int_cmp_real()
|
||||||
|
{
|
||||||
|
double value= args[0]->val_real(),a,b;
|
||||||
|
if ((null_value=args[0]->null_value))
|
||||||
|
return 0; /* purecov: inspected */
|
||||||
|
a= args[1]->val_real();
|
||||||
|
b= args[2]->val_real();
|
||||||
|
if (!args[1]->null_value && !args[2]->null_value)
|
||||||
|
return (longlong) ((value >= a && value <= b) != negated);
|
||||||
|
if (args[1]->null_value && args[2]->null_value)
|
||||||
|
null_value= true;
|
||||||
|
else if (args[1]->null_value)
|
||||||
|
{
|
||||||
|
null_value= value <= b; // not null if false range.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
null_value= value >= a;
|
||||||
}
|
}
|
||||||
return (longlong) (!null_value && negated);
|
return (longlong) (!null_value && negated);
|
||||||
}
|
}
|
||||||
@ -4119,7 +4107,7 @@ void Item_func_in::fix_length_and_dec()
|
|||||||
Item *date_arg= 0;
|
Item *date_arg= 0;
|
||||||
uint found_types= 0;
|
uint found_types= 0;
|
||||||
uint type_cnt= 0, i;
|
uint type_cnt= 0, i;
|
||||||
m_compare_type= STRING_RESULT;
|
m_comparator.set_handler(&type_handler_varchar);
|
||||||
left_cmp_type= args[0]->cmp_type();
|
left_cmp_type= args[0]->cmp_type();
|
||||||
if (!(found_types= collect_cmp_types(args, arg_count, true)))
|
if (!(found_types= collect_cmp_types(args, arg_count, true)))
|
||||||
return;
|
return;
|
||||||
@ -4137,7 +4125,7 @@ void Item_func_in::fix_length_and_dec()
|
|||||||
if (found_types & (1U << i))
|
if (found_types & (1U << i))
|
||||||
{
|
{
|
||||||
(type_cnt)++;
|
(type_cnt)++;
|
||||||
m_compare_type= (Item_result) i;
|
m_comparator.set_handler_by_cmp_type((Item_result) i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4161,7 +4149,7 @@ void Item_func_in::fix_length_and_dec()
|
|||||||
4. Neither left expression nor <in value list> contain any NULL value
|
4. Neither left expression nor <in value list> contain any NULL value
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (m_compare_type == ROW_RESULT &&
|
if (m_comparator.cmp_type() == ROW_RESULT &&
|
||||||
((!is_top_level_item() || negated) && // 3
|
((!is_top_level_item() || negated) && // 3
|
||||||
(list_contains_null() || args[0]->maybe_null))) // 4
|
(list_contains_null() || args[0]->maybe_null))) // 4
|
||||||
bisection_possible= false;
|
bisection_possible= false;
|
||||||
@ -4169,12 +4157,12 @@ void Item_func_in::fix_length_and_dec()
|
|||||||
|
|
||||||
if (type_cnt == 1)
|
if (type_cnt == 1)
|
||||||
{
|
{
|
||||||
if (m_compare_type == STRING_RESULT &&
|
if (m_comparator.cmp_type() == STRING_RESULT &&
|
||||||
agg_arg_charsets_for_comparison(cmp_collation, args, arg_count))
|
agg_arg_charsets_for_comparison(cmp_collation, args, arg_count))
|
||||||
return;
|
return;
|
||||||
arg_types_compatible= TRUE;
|
arg_types_compatible= TRUE;
|
||||||
|
|
||||||
if (m_compare_type == ROW_RESULT)
|
if (m_comparator.cmp_type() == ROW_RESULT)
|
||||||
{
|
{
|
||||||
uint cols= args[0]->cols();
|
uint cols= args[0]->cols();
|
||||||
cmp_item_row *cmp= 0;
|
cmp_item_row *cmp= 0;
|
||||||
@ -4221,7 +4209,8 @@ void Item_func_in::fix_length_and_dec()
|
|||||||
See the comment about the similar block in Item_bool_func2
|
See the comment about the similar block in Item_bool_func2
|
||||||
*/
|
*/
|
||||||
if (args[0]->real_item()->type() == FIELD_ITEM &&
|
if (args[0]->real_item()->type() == FIELD_ITEM &&
|
||||||
!thd->lex->is_view_context_analysis() && m_compare_type != INT_RESULT)
|
!thd->lex->is_view_context_analysis() &&
|
||||||
|
m_comparator.cmp_type() != INT_RESULT)
|
||||||
{
|
{
|
||||||
Item_field *field_item= (Item_field*) (args[0]->real_item());
|
Item_field *field_item= (Item_field*) (args[0]->real_item());
|
||||||
if (field_item->field_type() == MYSQL_TYPE_LONGLONG ||
|
if (field_item->field_type() == MYSQL_TYPE_LONGLONG ||
|
||||||
@ -4234,10 +4223,10 @@ void Item_func_in::fix_length_and_dec()
|
|||||||
all_converted= FALSE;
|
all_converted= FALSE;
|
||||||
}
|
}
|
||||||
if (all_converted)
|
if (all_converted)
|
||||||
m_compare_type= INT_RESULT;
|
m_comparator.set_handler(&type_handler_longlong);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (m_compare_type) {
|
switch (m_comparator.cmp_type()) {
|
||||||
case STRING_RESULT:
|
case STRING_RESULT:
|
||||||
array=new (thd->mem_root) in_string(thd, arg_count - 1,
|
array=new (thd->mem_root) in_string(thd, arg_count - 1,
|
||||||
(qsort2_cmp) srtcmp_in,
|
(qsort2_cmp) srtcmp_in,
|
||||||
|
@ -834,10 +834,10 @@ class Item_func_opt_neg :public Item_bool_func
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
/*
|
/*
|
||||||
The result type that will be used for comparison.
|
The data type handler that will be used for comparison.
|
||||||
cmp_type() of all arguments are collected to here.
|
Data type handlers of all arguments are mixed to here.
|
||||||
*/
|
*/
|
||||||
Item_result m_compare_type;
|
Type_handler_hybrid_field_type m_comparator;
|
||||||
/*
|
/*
|
||||||
The collation that will be used for comparison in case
|
The collation that will be used for comparison in case
|
||||||
when m_compare_type is STRING_RESULT.
|
when m_compare_type is STRING_RESULT.
|
||||||
@ -872,11 +872,13 @@ protected:
|
|||||||
Field *field, Item *value);
|
Field *field, Item *value);
|
||||||
public:
|
public:
|
||||||
String value0,value1,value2;
|
String value0,value1,value2;
|
||||||
/* TRUE <=> arguments will be compared as dates. */
|
|
||||||
Item *compare_as_dates;
|
|
||||||
Item_func_between(THD *thd, Item *a, Item *b, Item *c):
|
Item_func_between(THD *thd, Item *a, Item *b, Item *c):
|
||||||
Item_func_opt_neg(thd, a, b, c), compare_as_dates(FALSE) { }
|
Item_func_opt_neg(thd, a, b, c) { }
|
||||||
longlong val_int();
|
longlong val_int()
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed);
|
||||||
|
return m_comparator.type_handler()->Item_func_between_val_int(this);
|
||||||
|
}
|
||||||
enum Functype functype() const { return BETWEEN; }
|
enum Functype functype() const { return BETWEEN; }
|
||||||
const char *func_name() const { return "between"; }
|
const char *func_name() const { return "between"; }
|
||||||
enum precedence precedence() const { return BETWEEN_PRECEDENCE; }
|
enum precedence precedence() const { return BETWEEN_PRECEDENCE; }
|
||||||
@ -893,13 +895,19 @@ public:
|
|||||||
{
|
{
|
||||||
Item_args::propagate_equal_fields(thd,
|
Item_args::propagate_equal_fields(thd,
|
||||||
Context(ANY_SUBST,
|
Context(ANY_SUBST,
|
||||||
m_compare_type,
|
m_comparator.cmp_type(),
|
||||||
compare_collation()),
|
compare_collation()),
|
||||||
cond);
|
cond);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
||||||
{ return get_item_copy<Item_func_between>(thd, mem_root, this); }
|
{ return get_item_copy<Item_func_between>(thd, mem_root, this); }
|
||||||
|
|
||||||
|
longlong val_int_cmp_string();
|
||||||
|
longlong val_int_cmp_temporal();
|
||||||
|
longlong val_int_cmp_int();
|
||||||
|
longlong val_int_cmp_real();
|
||||||
|
longlong val_int_cmp_decimal();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1664,7 +1672,7 @@ public:
|
|||||||
will be replaced to a zero-filled Item_string.
|
will be replaced to a zero-filled Item_string.
|
||||||
Such a change would require rebuilding of cmp_items.
|
Such a change would require rebuilding of cmp_items.
|
||||||
*/
|
*/
|
||||||
Context cmpctx(ANY_SUBST, m_compare_type,
|
Context cmpctx(ANY_SUBST, m_comparator.cmp_type(),
|
||||||
Item_func_in::compare_collation());
|
Item_func_in::compare_collation());
|
||||||
for (uint i= 0; i < arg_count; i++)
|
for (uint i= 0; i < arg_count; i++)
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
static Type_handler_tiny type_handler_tiny;
|
static Type_handler_tiny type_handler_tiny;
|
||||||
static Type_handler_short type_handler_short;
|
static Type_handler_short type_handler_short;
|
||||||
static Type_handler_long type_handler_long;
|
static Type_handler_long type_handler_long;
|
||||||
static Type_handler_longlong type_handler_longlong;
|
|
||||||
static Type_handler_int24 type_handler_int24;
|
static Type_handler_int24 type_handler_int24;
|
||||||
static Type_handler_year type_handler_year;
|
static Type_handler_year type_handler_year;
|
||||||
static Type_handler_bit type_handler_bit;
|
static Type_handler_bit type_handler_bit;
|
||||||
@ -38,7 +37,6 @@ static Type_handler_datetime2 type_handler_datetime2;
|
|||||||
static Type_handler_timestamp type_handler_timestamp;
|
static Type_handler_timestamp type_handler_timestamp;
|
||||||
static Type_handler_timestamp2 type_handler_timestamp2;
|
static Type_handler_timestamp2 type_handler_timestamp2;
|
||||||
static Type_handler_olddecimal type_handler_olddecimal;
|
static Type_handler_olddecimal type_handler_olddecimal;
|
||||||
static Type_handler_newdecimal type_handler_newdecimal;
|
|
||||||
static Type_handler_string type_handler_string;
|
static Type_handler_string type_handler_string;
|
||||||
static Type_handler_tiny_blob type_handler_tiny_blob;
|
static Type_handler_tiny_blob type_handler_tiny_blob;
|
||||||
static Type_handler_medium_blob type_handler_medium_blob;
|
static Type_handler_medium_blob type_handler_medium_blob;
|
||||||
@ -54,6 +52,8 @@ static Type_handler_set type_handler_set;
|
|||||||
Type_handler_null type_handler_null;
|
Type_handler_null type_handler_null;
|
||||||
Type_handler_row type_handler_row;
|
Type_handler_row type_handler_row;
|
||||||
Type_handler_varchar type_handler_varchar;
|
Type_handler_varchar type_handler_varchar;
|
||||||
|
Type_handler_longlong type_handler_longlong;
|
||||||
|
Type_handler_newdecimal type_handler_newdecimal;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,6 +123,55 @@ Type_handler_hybrid_field_type::Type_handler_hybrid_field_type()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Collect built-in data type handlers for comparison.
|
||||||
|
This method is very similar to item_cmp_type() defined in item.cc.
|
||||||
|
Now they coexist. Later item_cmp_type() will be removed.
|
||||||
|
In addition to item_cmp_type(), this method correctly aggregates
|
||||||
|
TIME with DATETIME/TIMESTAMP/DATE, so no additional find_date_time_item()
|
||||||
|
is needed after this call.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
|
||||||
|
{
|
||||||
|
Item_result a= cmp_type();
|
||||||
|
Item_result b= h->cmp_type();
|
||||||
|
if (a == STRING_RESULT && b == STRING_RESULT)
|
||||||
|
m_type_handler= &type_handler_long_blob;
|
||||||
|
else if (a == INT_RESULT && b == INT_RESULT)
|
||||||
|
m_type_handler= &type_handler_longlong;
|
||||||
|
else if (a == ROW_RESULT || b == ROW_RESULT)
|
||||||
|
m_type_handler= &type_handler_row;
|
||||||
|
else if (a == TIME_RESULT || b == TIME_RESULT)
|
||||||
|
{
|
||||||
|
if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We're here if there's only one temporal data type:
|
||||||
|
either m_type_handler or h.
|
||||||
|
*/
|
||||||
|
if (b == TIME_RESULT)
|
||||||
|
m_type_handler= h; // Temporal types bit non-temporal types
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We're here if both m_type_handler and h are temporal data types.
|
||||||
|
*/
|
||||||
|
if (field_type() != MYSQL_TYPE_TIME || h->field_type() != MYSQL_TYPE_TIME)
|
||||||
|
m_type_handler= &type_handler_datetime; // DATETIME bits TIME
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
|
||||||
|
(b == INT_RESULT || b == DECIMAL_RESULT))
|
||||||
|
{
|
||||||
|
m_type_handler= &type_handler_newdecimal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_type_handler= &type_handler_double;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const Type_handler *
|
const Type_handler *
|
||||||
Type_handler::get_handler_by_field_type(enum_field_types type)
|
Type_handler::get_handler_by_field_type(enum_field_types type)
|
||||||
{
|
{
|
||||||
@ -1141,3 +1190,43 @@ Type_handler_string_result::Item_func_hybrid_field_type_get_date(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
|
longlong Type_handler_row::
|
||||||
|
Item_func_between_val_int(Item_func_between *func) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
func->null_value= true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
longlong Type_handler_string_result::
|
||||||
|
Item_func_between_val_int(Item_func_between *func) const
|
||||||
|
{
|
||||||
|
return func->val_int_cmp_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
longlong Type_handler_temporal_result::
|
||||||
|
Item_func_between_val_int(Item_func_between *func) const
|
||||||
|
{
|
||||||
|
return func->val_int_cmp_temporal();
|
||||||
|
}
|
||||||
|
|
||||||
|
longlong Type_handler_int_result::
|
||||||
|
Item_func_between_val_int(Item_func_between *func) const
|
||||||
|
{
|
||||||
|
return func->val_int_cmp_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
longlong Type_handler_real_result::
|
||||||
|
Item_func_between_val_int(Item_func_between *func) const
|
||||||
|
{
|
||||||
|
return func->val_int_cmp_real();
|
||||||
|
}
|
||||||
|
|
||||||
|
longlong Type_handler_decimal_result::
|
||||||
|
Item_func_between_val_int(Item_func_between *func) const
|
||||||
|
{
|
||||||
|
return func->val_int_cmp_decimal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
@ -29,6 +29,7 @@ class Item_cache;
|
|||||||
class Item_sum_hybrid;
|
class Item_sum_hybrid;
|
||||||
class Item_func_hex;
|
class Item_func_hex;
|
||||||
class Item_func_hybrid_field_type;
|
class Item_func_hybrid_field_type;
|
||||||
|
class Item_func_between;
|
||||||
class Type_std_attributes;
|
class Type_std_attributes;
|
||||||
class Sort_param;
|
class Sort_param;
|
||||||
class Arg_comparator;
|
class Arg_comparator;
|
||||||
@ -314,6 +315,8 @@ public:
|
|||||||
MYSQL_TIME *,
|
MYSQL_TIME *,
|
||||||
ulonglong fuzzydate) const= 0;
|
ulonglong fuzzydate) const= 0;
|
||||||
|
|
||||||
|
virtual longlong
|
||||||
|
Item_func_between_val_int(Item_func_between *func) const= 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -410,6 +413,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
longlong Item_func_between_val_int(Item_func_between *func) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -457,6 +461,7 @@ public:
|
|||||||
bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
|
bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
|
||||||
MYSQL_TIME *,
|
MYSQL_TIME *,
|
||||||
ulonglong fuzzydate) const;
|
ulonglong fuzzydate) const;
|
||||||
|
longlong Item_func_between_val_int(Item_func_between *func) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -489,6 +494,7 @@ public:
|
|||||||
bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
|
bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
|
||||||
MYSQL_TIME *,
|
MYSQL_TIME *,
|
||||||
ulonglong fuzzydate) const;
|
ulonglong fuzzydate) const;
|
||||||
|
longlong Item_func_between_val_int(Item_func_between *func) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -521,6 +527,7 @@ public:
|
|||||||
bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
|
bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
|
||||||
MYSQL_TIME *,
|
MYSQL_TIME *,
|
||||||
ulonglong fuzzydate) const;
|
ulonglong fuzzydate) const;
|
||||||
|
longlong Item_func_between_val_int(Item_func_between *func) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -551,6 +558,7 @@ public:
|
|||||||
bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
|
bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
|
||||||
MYSQL_TIME *,
|
MYSQL_TIME *,
|
||||||
ulonglong fuzzydate) const;
|
ulonglong fuzzydate) const;
|
||||||
|
longlong Item_func_between_val_int(Item_func_between *func) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -585,6 +593,7 @@ public:
|
|||||||
bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
|
bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
|
||||||
MYSQL_TIME *,
|
MYSQL_TIME *,
|
||||||
ulonglong fuzzydate) const;
|
ulonglong fuzzydate) const;
|
||||||
|
longlong Item_func_between_val_int(Item_func_between *func) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -960,6 +969,10 @@ public:
|
|||||||
{
|
{
|
||||||
return (m_type_handler= Type_handler::get_handler_by_result_type(type));
|
return (m_type_handler= Type_handler::get_handler_by_result_type(type));
|
||||||
}
|
}
|
||||||
|
const Type_handler *set_handler_by_cmp_type(Item_result type)
|
||||||
|
{
|
||||||
|
return (m_type_handler= Type_handler::get_handler_by_cmp_type(type));
|
||||||
|
}
|
||||||
const Type_handler *set_handler_by_result_type(Item_result type,
|
const Type_handler *set_handler_by_result_type(Item_result type,
|
||||||
uint max_octet_length,
|
uint max_octet_length,
|
||||||
CHARSET_INFO *cs)
|
CHARSET_INFO *cs)
|
||||||
@ -977,6 +990,8 @@ public:
|
|||||||
{
|
{
|
||||||
return (m_type_handler= Type_handler::get_handler_by_real_type(type));
|
return (m_type_handler= Type_handler::get_handler_by_real_type(type));
|
||||||
}
|
}
|
||||||
|
void aggregate_for_comparison(const Type_handler *other);
|
||||||
|
bool aggregate_for_comparison(Item **items, uint nitems);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -997,5 +1012,7 @@ public:
|
|||||||
extern Type_handler_row type_handler_row;
|
extern Type_handler_row type_handler_row;
|
||||||
extern Type_handler_null type_handler_null;
|
extern Type_handler_null type_handler_null;
|
||||||
extern Type_handler_varchar type_handler_varchar;
|
extern Type_handler_varchar type_handler_varchar;
|
||||||
|
extern Type_handler_longlong type_handler_longlong;
|
||||||
|
extern Type_handler_newdecimal type_handler_newdecimal;
|
||||||
|
|
||||||
#endif /* SQL_TYPE_H_INCLUDED */
|
#endif /* SQL_TYPE_H_INCLUDED */
|
||||||
|
Reference in New Issue
Block a user