Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
fee46323
Commit
fee46323
authored
Jul 20, 2018
by
Alexander Barkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-15758 Split Item_bool_func::get_mm_leaf() into virtual methods in Field and Type_handler
parent
6bfeace1
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
586 additions
and
229 deletions
+586
-229
sql/field.h
sql/field.h
+109
-6
sql/item.cc
sql/item.cc
+7
-66
sql/item_func.h
sql/item_func.h
+14
-0
sql/opt_range.cc
sql/opt_range.cc
+342
-157
sql/sql_type.cc
sql/sql_type.cc
+89
-0
sql/sql_type.h
sql/sql_type.h
+25
-0
No files found.
sql/field.h
View file @
fee46323
...
...
@@ -48,6 +48,9 @@ class Item_equal;
class
Virtual_tmp_table
;
class
Qualified_column_ident
;
class
Table_ident
;
class
SEL_ARG
;
class
RANGE_OPT_PARAM
;
struct
KEY_PART
;
enum
enum_check_fields
{
...
...
@@ -847,6 +850,10 @@ class Field: public Value_source
to be quoted when used in constructing an SQL query.
*/
virtual
bool
str_needs_quotes
()
{
return
FALSE
;
}
const
Type_handler
*
type_handler_for_comparison
()
const
{
return
type_handler
()
->
type_handler_for_comparison
();
}
Item_result
result_type
()
const
{
return
type_handler
()
->
result_type
();
...
...
@@ -1375,6 +1382,59 @@ class Field: public Value_source
}
int
warn_if_overflow
(
int
op_result
);
Copy_func
*
get_identical_copy_func
()
const
;
bool
can_optimize_scalar_range
(
const
RANGE_OPT_PARAM
*
param
,
const
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
const
Item
*
value
)
const
;
uchar
*
make_key_image
(
MEM_ROOT
*
mem_root
,
const
KEY_PART
*
key_part
);
SEL_ARG
*
get_mm_leaf_int
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
,
bool
unsigned_field
);
/*
Make a leaf tree for the cases when the value was stored
to the field exactly, without any truncation, rounding or adjustments.
For example, if we stored an INT value into an INT column,
and value->save_in_field_no_warnings() returned 0,
we know that the value was stored exactly.
*/
SEL_ARG
*
stored_field_make_mm_leaf_exact
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
scalar_comparison_op
op
,
Item
*
value
);
/*
Make a leaf tree for the cases when we don't know if
the value was stored to the field without any data loss,
or was modified to a smaller or a greater value.
Used for the data types whose methods Field::store*()
silently adjust the value. This is the most typical case.
*/
SEL_ARG
*
stored_field_make_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
scalar_comparison_op
op
,
Item
*
value
);
/*
Make a leaf tree when an INT value was stored into a field of INT type,
and some truncation happened. Tries to adjust the range search condition
when possible, e.g. "tinytint < 300" -> "tinyint <= 127".
Can also return SEL_ARG_IMPOSSIBLE(), and NULL (not sargable).
*/
SEL_ARG
*
stored_field_make_mm_leaf_bounded_int
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
scalar_comparison_op
op
,
Item
*
value
,
bool
unsigned_field
);
/*
Make a leaf tree when some truncation happened during
value->save_in_field_no_warning(this), and we cannot yet adjust the range
search condition for the current combination of the field and the value
data types.
Returns SEL_ARG_IMPOSSIBLE() for "=" and "<=>".
Returns NULL (not sargable) for other comparison operations.
*/
SEL_ARG
*
stored_field_make_mm_leaf_truncated
(
RANGE_OPT_PARAM
*
prm
,
scalar_comparison_op
,
Item
*
value
);
public:
void
set_table_name
(
String
*
alias
)
{
...
...
@@ -1547,6 +1607,10 @@ class Field: public Value_source
const
Item
*
item
,
bool
is_eq_func
)
const
;
virtual
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
)
=
0
;
bool
can_optimize_outer_join_table_elimination
(
const
Item_bool_func
*
cond
,
const
Item
*
item
)
const
{
...
...
@@ -1708,6 +1772,9 @@ class Field_num :public Field {
{
return
pos_in_interval_val_real
(
min
,
max
);
}
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
);
};
...
...
@@ -1764,6 +1831,9 @@ class Field_str :public Field {
return
pos_in_interval_val_str
(
min
,
max
,
length_size
());
}
bool
test_if_equality_guarantees_uniqueness
(
const
Item
*
const_item
)
const
;
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
);
};
/* base class for Field_string, Field_varstring and Field_blob */
...
...
@@ -2061,6 +2131,12 @@ class Field_int :public Field_num
uint32
prec
=
type_limits_int
()
->
precision
();
return
Information_schema_numeric_attributes
(
prec
,
0
);
}
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
)
{
return
get_mm_leaf_int
(
param
,
key_part
,
cond
,
op
,
value
,
unsigned_flag
);
}
};
...
...
@@ -2543,6 +2619,9 @@ class Field_temporal: public Field {
{
return
true
;
}
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
);
};
...
...
@@ -2823,14 +2902,31 @@ class Field_year :public Field_tiny {
};
class
Field_date
:
public
Field_temporal_with_date
{
class
Field_date_common
:
public
Field_temporal_with_date
{
public:
Field_date_common
(
uchar
*
ptr_arg
,
uchar
*
null_ptr_arg
,
uchar
null_bit_arg
,
enum
utype
unireg_check_arg
,
const
LEX_CSTRING
*
field_name_arg
)
:
Field_temporal_with_date
(
ptr_arg
,
MAX_DATE_WIDTH
,
null_ptr_arg
,
null_bit_arg
,
unireg_check_arg
,
field_name_arg
)
{}
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
);
};
class
Field_date
:
public
Field_date_common
{
void
store_TIME
(
MYSQL_TIME
*
ltime
);
bool
get_TIME
(
MYSQL_TIME
*
ltime
,
const
uchar
*
pos
,
ulonglong
fuzzydate
)
const
;
public:
Field_date
(
uchar
*
ptr_arg
,
uchar
*
null_ptr_arg
,
uchar
null_bit_arg
,
enum
utype
unireg_check_arg
,
const
LEX_CSTRING
*
field_name_arg
)
:
Field_
temporal_with_date
(
ptr_arg
,
MAX_DATE_WIDTH
,
null_ptr_arg
,
null_bit_arg
,
unireg_check_arg
,
field_name_arg
)
{}
:
Field_
date_common
(
ptr_arg
,
null_ptr_arg
,
null_bit_arg
,
unireg_check_arg
,
field_name_arg
)
{}
const
Type_handler
*
type_handler
()
const
{
return
&
type_handler_date
;
}
enum
ha_base_keytype
key_type
()
const
{
return
HA_KEYTYPE_ULONG_INT
;
}
int
reset
(
void
)
{
ptr
[
0
]
=
ptr
[
1
]
=
ptr
[
2
]
=
ptr
[
3
]
=
0
;
return
0
;
}
...
...
@@ -2858,14 +2954,15 @@ class Field_date :public Field_temporal_with_date {
};
class
Field_newdate
:
public
Field_temporal_with_date
{
class
Field_newdate
:
public
Field_date_common
{
void
store_TIME
(
MYSQL_TIME
*
ltime
);
bool
get_TIME
(
MYSQL_TIME
*
ltime
,
const
uchar
*
pos
,
ulonglong
fuzzydate
)
const
;
public:
Field_newdate
(
uchar
*
ptr_arg
,
uchar
*
null_ptr_arg
,
uchar
null_bit_arg
,
enum
utype
unireg_check_arg
,
const
LEX_CSTRING
*
field_name_arg
)
:
Field_
temporal_with_date
(
ptr_arg
,
MAX_DATE_WIDTH
,
null_ptr_arg
,
null_bit_arg
,
unireg_check_arg
,
field_name_arg
)
:
Field_
date_common
(
ptr_arg
,
null_ptr_arg
,
null_bit_arg
,
unireg_check_arg
,
field_name_arg
)
{}
const
Type_handler
*
type_handler
()
const
{
return
&
type_handler_newdate
;
}
enum
ha_base_keytype
key_type
()
const
{
return
HA_KEYTYPE_UINT24
;
}
...
...
@@ -4180,6 +4277,12 @@ class Field_bit :public Field {
}
void
hash
(
ulong
*
nr
,
ulong
*
nr2
);
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
)
{
return
get_mm_leaf_int
(
param
,
key_part
,
cond
,
op
,
value
,
true
);
}
private:
virtual
size_t
do_last_null_byte
()
const
;
int
save_field_metadata
(
uchar
*
first_byte
);
...
...
sql/item.cc
View file @
fee46323
...
...
@@ -6507,7 +6507,7 @@ Item *Item_field::replace_equal_field(THD *thd, uchar *arg)
comparison context, and it's safe to replace it to the constant from
item_equal.
*/
DBUG_ASSERT
(
type_handler
()
->
type_handler
_for_comparison
()
->
cmp_type
()
==
DBUG_ASSERT
(
type_handler_for_comparison
()
->
cmp_type
()
==
item_equal
->
compare_type_handler
()
->
cmp_type
());
return
const_item2
;
}
...
...
@@ -9941,73 +9941,14 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
int
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
{
Item_result
res_type
=
item_cmp_type
(
field
->
result_type
(),
item
->
result_type
());
/*
We have to check field->cmp_type() instead of res_type,
as result_type() - and thus res_type - can never be TIME_RESULT (yet).
*/
if
(
field
->
cmp_type
()
==
TIME_RESULT
)
{
MYSQL_TIME
field_time
,
item_time
,
item_time2
,
*
item_time_cmp
=
&
item_time
;
if
(
field
->
type
()
==
MYSQL_TYPE_TIME
)
{
field
->
get_time
(
&
field_time
);
item
->
get_time
(
&
item_time
);
}
else
{
field
->
get_date
(
&
field_time
,
TIME_INVALID_DATES
);
item
->
get_date
(
&
item_time
,
TIME_INVALID_DATES
);
if
(
item_time
.
time_type
==
MYSQL_TIMESTAMP_TIME
)
if
(
time_to_datetime
(
thd
,
&
item_time
,
item_time_cmp
=
&
item_time2
))
return
1
;
}
return
my_time_compare
(
&
field_time
,
item_time_cmp
);
}
if
(
res_type
==
STRING_RESULT
)
Type_handler_hybrid_field_type
cmp
(
field
->
type_handler_for_comparison
());
if
(
cmp
.
aggregate_for_comparison
(
item
->
type_handler_for_comparison
()))
{
char
item_buff
[
MAX_FIELD_WIDTH
];
char
field_buff
[
MAX_FIELD_WIDTH
];
String
item_tmp
(
item_buff
,
sizeof
(
item_buff
),
&
my_charset_bin
);
String
field_tmp
(
field_buff
,
sizeof
(
field_buff
),
&
my_charset_bin
);
String
*
item_result
=
item
->
val_str
(
&
item_tmp
);
/*
Some implementations of Item::val_str(String*) actually modify
the field Item::null_value, hence we can't check it earlier.
*/
if
(
item
->
null_value
)
return
0
;
String
*
field_result
=
field
->
val_str
(
&
field_tmp
);
return
sortcmp
(
field_result
,
item_result
,
field
->
charset
());
}
if
(
res_type
==
INT_RESULT
)
return
0
;
// Both are of type int
if
(
res_type
==
DECIMAL_RESULT
)
{
my_decimal
item_buf
,
*
item_val
,
field_buf
,
*
field_val
;
item_val
=
item
->
val_decimal
(
&
item_buf
);
if
(
item
->
null_value
)
return
0
;
field_val
=
field
->
val_decimal
(
&
field_buf
);
return
my_decimal_cmp
(
field_val
,
item_val
);
}
/*
The patch for Bug#13463415 started using this function for comparing
BIGINTs. That uncovered a bug in Visual Studio 32bit optimized mode.
Prefixing the auto variables with volatile fixes the problem....
*/
volatile
double
result
=
item
->
val_real
();
if
(
item
->
null_value
)
// At fix_fields() time we checked that "field" and "item" are comparable
DBUG_ASSERT
(
0
);
return
0
;
volatile
double
field_result
=
field
->
val_real
();
if
(
field_result
<
result
)
return
-
1
;
else
if
(
field_result
>
result
)
return
1
;
return
0
;
}
return
cmp
.
type_handler
()
->
stored_field_cmp_to_item
(
thd
,
field
,
item
);
}
...
...
sql/item_func.h
View file @
fee46323
...
...
@@ -78,6 +78,20 @@ class Item_func :public Item_func_or_sum,
EXTRACT_FUNC
,
CHAR_TYPECAST_FUNC
,
FUNC_SP
,
UDF_FUNC
,
NEG_FUNC
,
GSYSVAR_FUNC
,
IN_OPTIMIZER_FUNC
,
DYNCOL_FUNC
,
JSON_EXTRACT_FUNC
};
static
scalar_comparison_op
functype_to_scalar_comparison_op
(
Functype
type
)
{
switch
(
type
)
{
case
EQ_FUNC
:
return
SCALAR_CMP_EQ
;
case
EQUAL_FUNC
:
return
SCALAR_CMP_EQUAL
;
case
LT_FUNC
:
return
SCALAR_CMP_LT
;
case
LE_FUNC
:
return
SCALAR_CMP_LE
;
case
GE_FUNC
:
return
SCALAR_CMP_GE
;
case
GT_FUNC
:
return
SCALAR_CMP_GT
;
default:
break
;
}
DBUG_ASSERT
(
0
);
return
SCALAR_CMP_EQ
;
}
enum
Type
type
()
const
{
return
FUNC_ITEM
;
}
virtual
enum
Functype
functype
()
const
{
return
UNKNOWN_FUNC
;
}
Item_func
(
THD
*
thd
)
:
Item_func_or_sum
(
thd
)
...
...
sql/opt_range.cc
View file @
fee46323
...
...
@@ -1892,6 +1892,118 @@ SEL_ARG::SEL_ARG(Field *field_,uint8 part_,
left
=
right
=
&
null_element
;
}
/*
A number of helper classes:
SEL_ARG_LE, SEL_ARG_LT, SEL_ARG_GT, SEL_ARG_GE,
to share the code between:
Field::stored_field_make_mm_leaf()
Field::stored_field_make_mm_leaf_exact()
*/
class
SEL_ARG_LE
:
public
SEL_ARG
{
public:
SEL_ARG_LE
(
const
uchar
*
key
,
Field
*
field
)
:
SEL_ARG
(
field
,
key
,
key
)
{
if
(
!
field
->
real_maybe_null
())
min_flag
=
NO_MIN_RANGE
;
// From start
else
{
min_value
=
is_null_string
;
min_flag
=
NEAR_MIN
;
// > NULL
}
}
};
class
SEL_ARG_LT
:
public
SEL_ARG_LE
{
public:
/*
Use this constructor if value->save_in_field() went precisely,
without any data rounding or truncation.
*/
SEL_ARG_LT
(
const
uchar
*
key
,
Field
*
field
)
:
SEL_ARG_LE
(
key
,
field
)
{
max_flag
=
NEAR_MAX
;
}
/*
Use this constructor if value->save_in_field() returned success,
but we don't know if rounding or truncation happened
(as some Field::store() do not report minor data changes).
*/
SEL_ARG_LT
(
THD
*
thd
,
const
uchar
*
key
,
Field
*
field
,
Item
*
value
)
:
SEL_ARG_LE
(
key
,
field
)
{
if
(
stored_field_cmp_to_item
(
thd
,
field
,
value
)
==
0
)
max_flag
=
NEAR_MAX
;
}
};
class
SEL_ARG_GT
:
public
SEL_ARG
{
public:
/*
Use this constructor if value->save_in_field() went precisely,
without any data rounding or truncation.
*/
SEL_ARG_GT
(
const
uchar
*
key
,
const
KEY_PART
*
key_part
,
Field
*
field
)
:
SEL_ARG
(
field
,
key
,
key
)
{
// Don't use open ranges for partial key_segments
if
(
!
(
key_part
->
flag
&
HA_PART_KEY_SEG
))
min_flag
=
NEAR_MIN
;
max_flag
=
NO_MAX_RANGE
;
}
/*
Use this constructor if value->save_in_field() returned success,
but we don't know if rounding or truncation happened
(as some Field::store() do not report minor data changes).
*/
SEL_ARG_GT
(
THD
*
thd
,
const
uchar
*
key
,
const
KEY_PART
*
key_part
,
Field
*
field
,
Item
*
value
)
:
SEL_ARG
(
field
,
key
,
key
)
{
// Don't use open ranges for partial key_segments
if
((
!
(
key_part
->
flag
&
HA_PART_KEY_SEG
))
&&
(
stored_field_cmp_to_item
(
thd
,
field
,
value
)
<=
0
))
min_flag
=
NEAR_MIN
;
max_flag
=
NO_MAX_RANGE
;
}
};
class
SEL_ARG_GE
:
public
SEL_ARG
{
public:
/*
Use this constructor if value->save_in_field() went precisely,
without any data rounding or truncation.
*/
SEL_ARG_GE
(
const
uchar
*
key
,
Field
*
field
)
:
SEL_ARG
(
field
,
key
,
key
)
{
max_flag
=
NO_MAX_RANGE
;
}
/*
Use this constructor if value->save_in_field() returned success,
but we don't know if rounding or truncation happened
(as some Field::store() do not report minor data changes).
*/
SEL_ARG_GE
(
THD
*
thd
,
const
uchar
*
key
,
const
KEY_PART
*
key_part
,
Field
*
field
,
Item
*
value
)
:
SEL_ARG
(
field
,
key
,
key
)
{
// Don't use open ranges for partial key_segments
if
((
!
(
key_part
->
flag
&
HA_PART_KEY_SEG
))
&&
(
stored_field_cmp_to_item
(
thd
,
field
,
value
)
<
0
))
min_flag
=
NEAR_MIN
;
max_flag
=
NO_MAX_RANGE
;
}
};
SEL_ARG
*
SEL_ARG
::
clone
(
RANGE_OPT_PARAM
*
param
,
SEL_ARG
*
new_parent
,
SEL_ARG
**
next_arg
)
{
...
...
@@ -8015,52 +8127,112 @@ Item_func_like::get_mm_leaf(RANGE_OPT_PARAM *param,
SEL_ARG
*
Item_bool_func
::
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
Field
*
field
,
KEY_PART
*
key_part
,
Item_func
::
Functype
type
,
Item
*
value
)
Item_func
::
Functype
func
type
,
Item
*
value
)
{
uint
maybe_null
=
(
uint
)
field
->
real_maybe_null
();
SEL_ARG
*
tree
=
0
;
MEM_ROOT
*
alloc
=
param
->
mem_root
;
uchar
*
str
;
int
err
;
DBUG_ENTER
(
"Item_bool_func::get_mm_leaf"
);
DBUG_ASSERT
(
value
);
// IS NULL and IS NOT NULL are handled separately
if
(
key_part
->
image_type
!=
Field
::
itRAW
)
DBUG_RETURN
(
0
);
// e.g. SPATIAL index
DBUG_RETURN
(
field
->
get_mm_leaf
(
param
,
key_part
,
this
,
functype_to_scalar_comparison_op
(
functype
),
value
));
}
if
(
param
->
using_real_indexes
&&
!
field
->
optimize_range
(
param
->
real_keynr
[
key_part
->
key
],
key_part
->
part
)
&&
type
!=
EQ_FUNC
&&
type
!=
EQUAL_FUNC
)
goto
end
;
// Can't optimize this
if
(
!
field
->
can_optimize_range
(
this
,
value
,
type
==
EQUAL_FUNC
||
type
==
EQ_FUNC
))
goto
end
;
bool
Field
::
can_optimize_scalar_range
(
const
RANGE_OPT_PARAM
*
param
,
const
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
const
Item
*
value
)
const
{
bool
is_eq_func
=
op
==
SCALAR_CMP_EQ
||
op
==
SCALAR_CMP_EQUAL
;
if
((
param
->
using_real_indexes
&&
!
optimize_range
(
param
->
real_keynr
[
key_part
->
key
],
key_part
->
part
)
&&
!
is_eq_func
)
||
!
can_optimize_range
(
cond
,
value
,
is_eq_func
))
return
false
;
return
true
;
}
uchar
*
Field
::
make_key_image
(
MEM_ROOT
*
mem_root
,
const
KEY_PART
*
key_part
)
{
DBUG_ENTER
(
"Field::make_key_image"
);
uint
maybe_null
=
(
uint
)
real_maybe_null
();
uchar
*
str
;
if
(
!
(
str
=
(
uchar
*
)
alloc_root
(
mem_root
,
key_part
->
store_length
+
1
)))
DBUG_RETURN
(
0
);
if
(
maybe_null
)
*
str
=
(
uchar
)
is_real_null
();
// Set to 1 if null
get_key_image
(
str
+
maybe_null
,
key_part
->
length
,
key_part
->
image_type
);
DBUG_RETURN
(
str
);
}
SEL_ARG
*
Field
::
stored_field_make_mm_leaf_truncated
(
RANGE_OPT_PARAM
*
param
,
scalar_comparison_op
op
,
Item
*
value
)
{
DBUG_ENTER
(
"Field::stored_field_make_mm_leaf_truncated"
);
if
((
op
==
SCALAR_CMP_EQ
||
op
==
SCALAR_CMP_EQUAL
)
&&
value
->
result_type
()
==
item_cmp_type
(
result_type
(),
value
->
result_type
()))
DBUG_RETURN
(
new
(
param
->
mem_root
)
SEL_ARG_IMPOSSIBLE
(
this
));
/*
TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE
for the cases like int_field > 999999999999999999999999 as well.
*/
DBUG_RETURN
(
0
);
}
err
=
value
->
save_in_field_no_warnings
(
field
,
1
);
SEL_ARG
*
Field_num
::
get_mm_leaf
(
RANGE_OPT_PARAM
*
prm
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
)
{
DBUG_ENTER
(
"Field_num::get_mm_leaf"
);
if
(
!
can_optimize_scalar_range
(
prm
,
key_part
,
cond
,
op
,
value
))
DBUG_RETURN
(
0
);
int
err
=
value
->
save_in_field_no_warnings
(
this
,
1
);
if
((
op
!=
SCALAR_CMP_EQUAL
&&
is_real_null
())
||
err
<
0
)
DBUG_RETURN
(
&
null_element
);
if
(
err
>
0
&&
cmp_type
()
!=
value
->
result_type
())
DBUG_RETURN
(
stored_field_make_mm_leaf_truncated
(
prm
,
op
,
value
));
DBUG_RETURN
(
stored_field_make_mm_leaf
(
prm
,
key_part
,
op
,
value
));
}
SEL_ARG
*
Field_temporal
::
get_mm_leaf
(
RANGE_OPT_PARAM
*
prm
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
)
{
DBUG_ENTER
(
"Field_temporal::get_mm_leaf"
);
if
(
!
can_optimize_scalar_range
(
prm
,
key_part
,
cond
,
op
,
value
))
DBUG_RETURN
(
0
);
int
err
=
value
->
save_in_field_no_warnings
(
this
,
1
);
if
((
op
!=
SCALAR_CMP_EQUAL
&&
is_real_null
())
||
err
<
0
)
DBUG_RETURN
(
&
null_element
);
if
(
err
>
0
)
{
if
(
field
->
type_handler
()
==
&
type_handler_enum
||
field
->
type_handler
()
==
&
type_handler_set
)
{
if
(
type
==
EQ_FUNC
||
type
==
EQUAL_FUNC
)
tree
=
new
(
alloc
)
SEL_ARG_IMPOSSIBLE
(
field
);
goto
end
;
}
DBUG_RETURN
(
stored_field_make_mm_leaf_truncated
(
prm
,
op
,
value
));
DBUG_RETURN
(
stored_field_make_mm_leaf
(
prm
,
key_part
,
op
,
value
));
}
if
(
err
==
2
&&
field
->
cmp_type
()
==
STRING_RESULT
)
{
if
(
type
==
EQ_FUNC
||
type
==
EQUAL_FUNC
)
tree
=
new
(
alloc
)
SEL_ARG_IMPOSSIBLE
(
field
);
else
tree
=
NULL
;
/* Cannot infer anything */
goto
end
;
}
if
(
err
==
3
&&
field
->
type
()
==
FIELD_TYPE_DATE
)
SEL_ARG
*
Field_date_common
::
get_mm_leaf
(
RANGE_OPT_PARAM
*
prm
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
)
{
DBUG_ENTER
(
"Field_date_common::get_mm_leaf"
);
if
(
!
can_optimize_scalar_range
(
prm
,
key_part
,
cond
,
op
,
value
))
DBUG_RETURN
(
0
);
int
err
=
value
->
save_in_field_no_warnings
(
this
,
1
);
if
((
op
!=
SCALAR_CMP_EQUAL
&&
is_real_null
())
||
err
<
0
)
DBUG_RETURN
(
&
null_element
);
if
(
err
>
0
)
{
if
(
err
==
3
)
{
/*
We were saving DATETIME into a DATE column, the conversion went ok
...
...
@@ -8080,81 +8252,86 @@ Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param,
be done together with other types at the end of this function
(grep for stored_field_cmp_to_item)
*/
if
(
type
==
EQ_FUNC
||
type
==
EQUAL_FUNC
)
{
tree
=
new
(
alloc
)
SEL_ARG_IMPOSSIBLE
(
field
);
goto
end
;
}
// Continue with processing non-equality ranges
}
else
if
(
field
->
cmp_type
()
!=
value
->
result_type
())
{
if
((
type
==
EQ_FUNC
||
type
==
EQUAL_FUNC
)
&&
value
->
result_type
()
==
item_cmp_type
(
field
->
result_type
(),
value
->
result_type
()))
{
tree
=
new
(
alloc
)
SEL_ARG_IMPOSSIBLE
(
field
);
goto
end
;
}
else
{
/*
TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE
for the cases like int_field > 999999999999999999999999 as well.
*/
tree
=
0
;
goto
end
;
}
}
/*
guaranteed at this point: err > 0; field and const of same type
If an integer got bounded (e.g. to within 0..255 / -128..127)
for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN)
*/
else
if
(
err
==
1
&&
field
->
result_type
()
==
INT_RESULT
)
{
if
(
type
==
EQ_FUNC
||
type
==
EQUAL_FUNC
)
// e.g. tinyint = 200
{
tree
=
new
(
alloc
)
SEL_ARG_IMPOSSIBLE
(
field
);
goto
end
;
}
if
(
type
==
LT_FUNC
&&
(
value
->
val_int
()
>
0
))
type
=
LE_FUNC
;
else
if
(
type
==
GT_FUNC
&&
(
field
->
type
()
!=
FIELD_TYPE_BIT
)
&&
!
((
Field_num
*
)
field
)
->
unsigned_flag
&&
!
value
->
unsigned_flag
&&
(
value
->
val_int
()
<
0
))
type
=
GE_FUNC
;
if
(
op
==
SCALAR_CMP_EQ
||
op
==
SCALAR_CMP_EQUAL
)
DBUG_RETURN
(
new
(
prm
->
mem_root
)
SEL_ARG_IMPOSSIBLE
(
this
));
DBUG_RETURN
(
stored_field_make_mm_leaf
(
prm
,
key_part
,
op
,
value
));
}
DBUG_RETURN
(
stored_field_make_mm_leaf_truncated
(
prm
,
op
,
value
));
}
else
if
(
err
<
0
)
DBUG_RETURN
(
stored_field_make_mm_leaf
(
prm
,
key_part
,
op
,
value
));
}
SEL_ARG
*
Field_str
::
get_mm_leaf
(
RANGE_OPT_PARAM
*
prm
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
)
{
DBUG_ENTER
(
"Field_str::get_mm_leaf"
);
if
(
!
can_optimize_scalar_range
(
prm
,
key_part
,
cond
,
op
,
value
))
DBUG_RETURN
(
0
);
int
err
=
value
->
save_in_field_no_warnings
(
this
,
1
);
if
((
op
!=
SCALAR_CMP_EQUAL
&&
is_real_null
())
||
err
<
0
)
DBUG_RETURN
(
&
null_element
);
if
(
err
>
0
)
{
/* This happens when we try to insert a NULL field in a not null column */
tree
=
&
null_element
;
// cmp with NULL is never TRUE
goto
end
;
if
(
op
==
SCALAR_CMP_EQ
||
op
==
SCALAR_CMP_EQUAL
)
DBUG_RETURN
(
new
(
prm
->
mem_root
)
SEL_ARG_IMPOSSIBLE
(
this
));
DBUG_RETURN
(
NULL
);
/* Cannot infer anything */
}
DBUG_RETURN
(
stored_field_make_mm_leaf
(
prm
,
key_part
,
op
,
value
));
}
/*
Any sargable predicate except "<=>" involving NULL as a constant is always
FALSE
*/
if
(
type
!=
EQUAL_FUNC
&&
field
->
is_real_null
())
SEL_ARG
*
Field
::
get_mm_leaf_int
(
RANGE_OPT_PARAM
*
prm
,
KEY_PART
*
key_part
,
const
Item_bool_func
*
cond
,
scalar_comparison_op
op
,
Item
*
value
,
bool
unsigned_field
)
{
DBUG_ENTER
(
"Field::get_mm_leaf_int"
);
if
(
!
can_optimize_scalar_range
(
prm
,
key_part
,
cond
,
op
,
value
))
DBUG_RETURN
(
0
);
int
err
=
value
->
save_in_field_no_warnings
(
this
,
1
);
if
((
op
!=
SCALAR_CMP_EQUAL
&&
is_real_null
())
||
err
<
0
)
DBUG_RETURN
(
&
null_element
);
if
(
err
>
0
)
{
tree
=
&
null_element
;
goto
end
;
if
(
value
->
result_type
()
!=
INT_RESULT
)
DBUG_RETURN
(
stored_field_make_mm_leaf_truncated
(
prm
,
op
,
value
));
else
DBUG_RETURN
(
stored_field_make_mm_leaf_bounded_int
(
prm
,
key_part
,
op
,
value
,
unsigned_field
));
}
str
=
(
uchar
*
)
alloc_root
(
alloc
,
key_part
->
store_length
+
1
);
if
(
!
str
)
goto
end
;
if
(
maybe_null
)
*
str
=
(
uchar
)
field
->
is_real_null
();
// Set to 1 if null
field
->
get_key_image
(
str
+
maybe_null
,
key_part
->
length
,
key_part
->
image_type
);
if
(
!
(
tree
=
new
(
alloc
)
SEL_ARG
(
field
,
str
,
str
)))
goto
end
;
// out of memory
if
(
value
->
result_type
()
!=
INT_RESULT
)
DBUG_RETURN
(
stored_field_make_mm_leaf
(
prm
,
key_part
,
op
,
value
));
DBUG_RETURN
(
stored_field_make_mm_leaf_exact
(
prm
,
key_part
,
op
,
value
));
}
/*
This method is called when:
- value->save_in_field_no_warnings() returned err > 0
- and both field and "value" are of integer data types
If an integer got bounded (e.g. to within 0..255 / -128..127)
for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN)
*/
SEL_ARG
*
Field
::
stored_field_make_mm_leaf_bounded_int
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
scalar_comparison_op
op
,
Item
*
value
,
bool
unsigned_field
)
{
DBUG_ENTER
(
"Field::stored_field_make_mm_leaf_bounded_int"
);
if
(
op
==
SCALAR_CMP_EQ
||
op
==
SCALAR_CMP_EQUAL
)
// e.g. tinyint = 200
DBUG_RETURN
(
new
(
param
->
mem_root
)
SEL_ARG_IMPOSSIBLE
(
this
));
longlong
item_val
=
value
->
val_int
();
if
(
op
==
SCALAR_CMP_LT
&&
item_val
>
0
)
op
=
SCALAR_CMP_LE
;
// e.g. rewrite (tinyint < 200) to (tinyint <= 127)
else
if
(
op
==
SCALAR_CMP_GT
&&
!
unsigned_field
&&
!
value
->
unsigned_flag
&&
item_val
<
0
)
op
=
SCALAR_CMP_GE
;
// e.g. rewrite (tinyint > -200) to (tinyint >= -128)
/*
Check if we are comparing an UNSIGNED integer with a negative constant.
...
...
@@ -8167,66 +8344,74 @@ Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param,
negative integers (which otherwise fails because at query execution time
negative integers are cast to unsigned if compared with unsigned).
*/
if
(
field
->
result_type
()
==
INT_RESULT
&&
value
->
result_type
()
==
INT_RESULT
&&
((
field
->
type
()
==
FIELD_TYPE_BIT
||
((
Field_num
*
)
field
)
->
unsigned_flag
)
&&
!
value
->
unsigned_flag
))
if
(
unsigned_field
&&
!
value
->
unsigned_flag
&&
item_val
<
0
)
{
longlong
item_val
=
value
->
val_int
();
if
(
item_val
<
0
)
{
if
(
type
==
LT_FUNC
||
type
==
LE_FUNC
)
{
tree
->
type
=
SEL_ARG
::
IMPOSSIBLE
;
goto
end
;
}
if
(
type
==
GT_FUNC
||
type
==
GE_FUNC
)
{
tree
=
0
;
goto
end
;
}
}
if
(
op
==
SCALAR_CMP_LT
||
op
==
SCALAR_CMP_LE
)
// e.g. uint < -1
DBUG_RETURN
(
new
(
param
->
mem_root
)
SEL_ARG_IMPOSSIBLE
(
this
));
if
(
op
==
SCALAR_CMP_GT
||
op
==
SCALAR_CMP_GE
)
// e.g. uint > -1
DBUG_RETURN
(
0
);
}
DBUG_RETURN
(
stored_field_make_mm_leaf_exact
(
param
,
key_part
,
op
,
value
));
}
switch
(
type
)
{
case
LT_FUNC
:
if
(
stored_field_cmp_to_item
(
param
->
thd
,
field
,
value
)
==
0
)
tree
->
max_flag
=
NEAR_MAX
;
/* fall through */
case
LE_FUNC
:
if
(
!
maybe_null
)
tree
->
min_flag
=
NO_MIN_RANGE
;
/* From start */
else
{
// > NULL
tree
->
min_value
=
is_null_string
;
tree
->
min_flag
=
NEAR_MIN
;
}
break
;
case
GT_FUNC
:
/* Don't use open ranges for partial key_segments */
if
((
!
(
key_part
->
flag
&
HA_PART_KEY_SEG
))
&&
(
stored_field_cmp_to_item
(
param
->
thd
,
field
,
value
)
<=
0
))
tree
->
min_flag
=
NEAR_MIN
;
tree
->
max_flag
=
NO_MAX_RANGE
;
break
;
case
GE_FUNC
:
/* Don't use open ranges for partial key_segments */
if
((
!
(
key_part
->
flag
&
HA_PART_KEY_SEG
))
&&
(
stored_field_cmp_to_item
(
param
->
thd
,
field
,
value
)
<
0
))
tree
->
min_flag
=
NEAR_MIN
;
tree
->
max_flag
=
NO_MAX_RANGE
;
break
;
case
EQ_FUNC
:
case
EQUAL_FUNC
:
break
;
default:
DBUG_ASSERT
(
0
);
SEL_ARG
*
Field
::
stored_field_make_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
scalar_comparison_op
op
,
Item
*
value
)
{
DBUG_ENTER
(
"Field::stored_field_make_mm_leaf"
);
THD
*
thd
=
param
->
thd
;
MEM_ROOT
*
mem_root
=
param
->
mem_root
;
uchar
*
str
;
if
(
!
(
str
=
make_key_image
(
param
->
mem_root
,
key_part
)))
DBUG_RETURN
(
0
);
switch
(
op
)
{
case
SCALAR_CMP_LE
:
DBUG_RETURN
(
new
(
mem_root
)
SEL_ARG_LE
(
str
,
this
));
case
SCALAR_CMP_LT
:
DBUG_RETURN
(
new
(
mem_root
)
SEL_ARG_LT
(
thd
,
str
,
this
,
value
));
case
SCALAR_CMP_GT
:
DBUG_RETURN
(
new
(
mem_root
)
SEL_ARG_GT
(
thd
,
str
,
key_part
,
this
,
value
));
case
SCALAR_CMP_GE
:
DBUG_RETURN
(
new
(
mem_root
)
SEL_ARG_GE
(
thd
,
str
,
key_part
,
this
,
value
));
case
SCALAR_CMP_EQ
:
case
SCALAR_CMP_EQUAL
:
DBUG_RETURN
(
new
(
mem_root
)
SEL_ARG
(
this
,
str
,
str
));
break
;
}
DBUG_ASSERT
(
0
);
DBUG_RETURN
(
NULL
);
}
end:
DBUG_RETURN
(
tree
);
SEL_ARG
*
Field
::
stored_field_make_mm_leaf_exact
(
RANGE_OPT_PARAM
*
param
,
KEY_PART
*
key_part
,
scalar_comparison_op
op
,
Item
*
value
)
{
DBUG_ENTER
(
"Field::stored_field_make_mm_leaf_exact"
);
uchar
*
str
;
if
(
!
(
str
=
make_key_image
(
param
->
mem_root
,
key_part
)))
DBUG_RETURN
(
0
);
switch
(
op
)
{
case
SCALAR_CMP_LE
:
DBUG_RETURN
(
new
(
param
->
mem_root
)
SEL_ARG_LE
(
str
,
this
));
case
SCALAR_CMP_LT
:
DBUG_RETURN
(
new
(
param
->
mem_root
)
SEL_ARG_LT
(
str
,
this
));
case
SCALAR_CMP_GT
:
DBUG_RETURN
(
new
(
param
->
mem_root
)
SEL_ARG_GT
(
str
,
key_part
,
this
));
case
SCALAR_CMP_GE
:
DBUG_RETURN
(
new
(
param
->
mem_root
)
SEL_ARG_GE
(
str
,
this
));
case
SCALAR_CMP_EQ
:
case
SCALAR_CMP_EQUAL
:
DBUG_RETURN
(
new
(
param
->
mem_root
)
SEL_ARG
(
this
,
str
,
str
));
break
;
}
DBUG_ASSERT
(
0
);
DBUG_RETURN
(
NULL
);
}
...
...
sql/sql_type.cc
View file @
fee46323
...
...
@@ -6574,3 +6574,92 @@ void Type_handler_timestamp_common::
else
c
->
set_handler
(
&
type_handler_timestamp
);
}
/***************************************************************************/
int
Type_handler_temporal_with_date
::
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
{
MYSQL_TIME
field_time
,
item_time
,
item_time2
,
*
item_time_cmp
=
&
item_time
;
field
->
get_date
(
&
field_time
,
TIME_INVALID_DATES
);
item
->
get_date
(
&
item_time
,
TIME_INVALID_DATES
);
if
(
item_time
.
time_type
==
MYSQL_TIMESTAMP_TIME
&&
time_to_datetime
(
thd
,
&
item_time
,
item_time_cmp
=
&
item_time2
))
return
1
;
return
my_time_compare
(
&
field_time
,
item_time_cmp
);
}
int
Type_handler_time_common
::
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
{
MYSQL_TIME
field_time
,
item_time
;
field
->
get_time
(
&
field_time
);
item
->
get_time
(
&
item_time
);
return
my_time_compare
(
&
field_time
,
&
item_time
);
}
int
Type_handler_string_result
::
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
{
StringBuffer
<
MAX_FIELD_WIDTH
>
item_tmp
;
StringBuffer
<
MAX_FIELD_WIDTH
>
field_tmp
;
String
*
item_result
=
item
->
val_str
(
&
item_tmp
);
/*
Some implementations of Item::val_str(String*) actually modify
the field Item::null_value, hence we can't check it earlier.
*/
if
(
item
->
null_value
)
return
0
;
String
*
field_result
=
field
->
val_str
(
&
field_tmp
);
return
sortcmp
(
field_result
,
item_result
,
field
->
charset
());
}
int
Type_handler_int_result
::
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
{
DBUG_ASSERT
(
0
);
// Not used yet
return
0
;
}
int
Type_handler_decimal_result
::
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
{
my_decimal
item_buf
,
*
item_val
,
field_buf
,
*
field_val
;
item_val
=
item
->
val_decimal
(
&
item_buf
);
if
(
item
->
null_value
)
return
0
;
field_val
=
field
->
val_decimal
(
&
field_buf
);
return
my_decimal_cmp
(
field_val
,
item_val
);
}
int
Type_handler_real_result
::
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
{
/*
The patch for Bug#13463415 started using this function for comparing
BIGINTs. That uncovered a bug in Visual Studio 32bit optimized mode.
Prefixing the auto variables with volatile fixes the problem....
*/
volatile
double
result
=
item
->
val_real
();
if
(
item
->
null_value
)
return
0
;
volatile
double
field_result
=
field
->
val_real
();
if
(
field_result
<
result
)
return
-
1
;
else
if
(
field_result
>
result
)
return
1
;
return
0
;
}
sql/sql_type.h
View file @
fee46323
...
...
@@ -77,6 +77,17 @@ struct SORT_FIELD_ATTR;
class
Vers_history_point
;
enum
scalar_comparison_op
{
SCALAR_CMP_EQ
,
SCALAR_CMP_EQUAL
,
SCALAR_CMP_LT
,
SCALAR_CMP_LE
,
SCALAR_CMP_GE
,
SCALAR_CMP_GT
};
/**
Class Time is designed to store valid TIME values.
...
...
@@ -1184,6 +1195,8 @@ class Type_handler
{
return
this
;
}
virtual
int
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
=
0
;
virtual
CHARSET_INFO
*
charset_for_protocol
(
const
Item
*
item
)
const
;
virtual
const
Type_handler
*
type_handler_adjusted_to_max_octet_length
(
uint
max_octet_length
,
...
...
@@ -1562,6 +1575,11 @@ class Type_handler_row: public Type_handler
return
ROW_RESULT
;
}
const
Type_handler
*
type_handler_for_comparison
()
const
;
int
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
{
DBUG_ASSERT
(
0
);
return
0
;
}
bool
subquery_type_allows_materialization
(
const
Item
*
inner
,
const
Item
*
outer
)
const
{
...
...
@@ -1888,6 +1906,7 @@ class Type_handler_real_result: public Type_handler_numeric
Item_result
cmp_type
()
const
{
return
REAL_RESULT
;
}
virtual
~
Type_handler_real_result
()
{}
const
Type_handler
*
type_handler_for_comparison
()
const
;
int
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
;
bool
subquery_type_allows_materialization
(
const
Item
*
inner
,
const
Item
*
outer
)
const
;
void
make_sort_key
(
uchar
*
to
,
Item
*
item
,
const
SORT_FIELD_ATTR
*
sort_field
,
...
...
@@ -1965,6 +1984,7 @@ class Type_handler_decimal_result: public Type_handler_numeric
Item_result
cmp_type
()
const
{
return
DECIMAL_RESULT
;
}
virtual
~
Type_handler_decimal_result
()
{};
const
Type_handler
*
type_handler_for_comparison
()
const
;
int
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
;
bool
subquery_type_allows_materialization
(
const
Item
*
inner
,
const
Item
*
outer
)
const
;
Field
*
make_num_distinct_aggregator_field
(
MEM_ROOT
*
,
const
Item
*
)
const
;
...
...
@@ -2174,6 +2194,7 @@ class Type_handler_int_result: public Type_handler_numeric
bool
is_limit_clause_valid_type
()
const
{
return
true
;
}
virtual
~
Type_handler_int_result
()
{}
const
Type_handler
*
type_handler_for_comparison
()
const
;
int
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
;
bool
subquery_type_allows_materialization
(
const
Item
*
inner
,
const
Item
*
outer
)
const
;
Field
*
make_num_distinct_aggregator_field
(
MEM_ROOT
*
,
const
Item
*
)
const
;
...
...
@@ -2237,6 +2258,7 @@ class Type_handler_int_result: public Type_handler_numeric
bool
Item_func_mul_fix_length_and_dec
(
Item_func_mul
*
)
const
;
bool
Item_func_div_fix_length_and_dec
(
Item_func_div
*
)
const
;
bool
Item_func_mod_fix_length_and_dec
(
Item_func_mod
*
)
const
;
};
...
...
@@ -2331,6 +2353,7 @@ class Type_handler_string_result: public Type_handler
CHARSET_INFO
*
charset_for_protocol
(
const
Item
*
item
)
const
;
virtual
~
Type_handler_string_result
()
{}
const
Type_handler
*
type_handler_for_comparison
()
const
;
int
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
;
const
Type_handler
*
type_handler_adjusted_to_max_octet_length
(
uint
max_octet_length
,
CHARSET_INFO
*
cs
)
const
;
...
...
@@ -2885,6 +2908,7 @@ class Type_handler_time_common: public Type_handler_temporal_result
return
Item_divisor_precision_increment_with_seconds
(
item
);
}
const
Type_handler
*
type_handler_for_comparison
()
const
;
int
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
;
void
Column_definition_implicit_upgrade
(
Column_definition
*
c
)
const
;
bool
Column_definition_fix_attributes
(
Column_definition
*
c
)
const
;
bool
Item_save_in_value
(
Item
*
item
,
st_value
*
value
)
const
;
...
...
@@ -2986,6 +3010,7 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result
virtual
~
Type_handler_temporal_with_date
()
{}
bool
Item_eq_value
(
THD
*
thd
,
const
Type_cmp_attributes
*
attr
,
Item
*
a
,
Item
*
b
)
const
;
int
stored_field_cmp_to_item
(
THD
*
thd
,
Field
*
field
,
Item
*
item
)
const
;
bool
Item_save_in_value
(
Item
*
item
,
st_value
*
value
)
const
;
bool
Item_send
(
Item
*
item
,
Protocol
*
protocol
,
st_value
*
buf
)
const
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment