1
0
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:
Alexander Barkov
2016-12-06 23:20:39 +04:00
parent 1c1d8fe9e4
commit cfda0a71a7
6 changed files with 296 additions and 170 deletions

View File

@ -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
# #

View File

@ -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 #

View File

@ -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,

View File

@ -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++)
{ {

View File

@ -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();
}
/***************************************************************************/

View File

@ -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 */