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
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
9d884fd3
Commit
9d884fd3
authored
Aug 12, 2015
by
Alexander Barkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-8599 "WHERE varchar_field LIKE temporal_const" does not use range optimizer
parent
6e091dc7
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
243 additions
and
170 deletions
+243
-170
mysql-test/r/func_like.result
mysql-test/r/func_like.result
+25
-0
mysql-test/t/func_like.test
mysql-test/t/func_like.test
+19
-0
sql/item_cmpfunc.h
sql/item_cmpfunc.h
+14
-0
sql/opt_range.cc
sql/opt_range.cc
+183
-168
sql/opt_range.h
sql/opt_range.h
+2
-2
No files found.
mysql-test/r/func_like.result
View file @
9d884fd3
...
...
@@ -227,5 +227,30 @@ Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 10.0) and (`test`.`t1`.`a` like 10.00))
DROP TABLE t1;
#
# MDEV-8599 "WHERE varchar_field LIKE temporal_const" does not use range optimizer
#
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1, KEY(a)) ENGINE=MyISAM;
INSERT INTO t1 VALUES ('00:00:00');
INSERT INTO t1 VALUES ('00:00:01');
INSERT INTO t1 VALUES ('00:00:02');
INSERT INTO t1 VALUES ('00:00:03');
INSERT INTO t1 VALUES ('00:00:04');
INSERT INTO t1 VALUES ('00:00:05');
INSERT INTO t1 VALUES ('00:00:06');
INSERT INTO t1 VALUES ('00:00:07');
EXPLAIN SELECT * FROM t1 WHERE a LIKE '00:00:00';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 13 NULL 1 Using where; Using index
EXPLAIN SELECT * FROM t1 WHERE a LIKE TIME'00:00:00';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 13 NULL 1 Using where; Using index
SELECT * FROM t1 WHERE a LIKE '00:00:00';
a
00:00:00
SELECT * FROM t1 WHERE a LIKE TIME'00:00:00';
a
00:00:00
DROP TABLE t1;
#
# End of 10.1 tests
#
mysql-test/t/func_like.test
View file @
9d884fd3
...
...
@@ -163,6 +163,25 @@ SELECT * FROM t1 WHERE a=10.0 AND a LIKE 10.00;
EXPLAIN
EXTENDED
SELECT
*
FROM
t1
WHERE
a
=
10.0
AND
a
LIKE
10.00
;
DROP
TABLE
t1
;
--
echo
#
--
echo
# MDEV-8599 "WHERE varchar_field LIKE temporal_const" does not use range optimizer
--
echo
#
CREATE
TABLE
t1
(
a
VARCHAR
(
10
)
CHARACTER
SET
latin1
,
KEY
(
a
))
ENGINE
=
MyISAM
;
INSERT
INTO
t1
VALUES
(
'00:00:00'
);
INSERT
INTO
t1
VALUES
(
'00:00:01'
);
INSERT
INTO
t1
VALUES
(
'00:00:02'
);
INSERT
INTO
t1
VALUES
(
'00:00:03'
);
INSERT
INTO
t1
VALUES
(
'00:00:04'
);
INSERT
INTO
t1
VALUES
(
'00:00:05'
);
INSERT
INTO
t1
VALUES
(
'00:00:06'
);
INSERT
INTO
t1
VALUES
(
'00:00:07'
);
EXPLAIN
SELECT
*
FROM
t1
WHERE
a
LIKE
'00:00:00'
;
EXPLAIN
SELECT
*
FROM
t1
WHERE
a
LIKE
TIME
'00:00:00'
;
SELECT
*
FROM
t1
WHERE
a
LIKE
'00:00:00'
;
SELECT
*
FROM
t1
WHERE
a
LIKE
TIME
'00:00:00'
;
DROP
TABLE
t1
;
--
echo
#
--
echo
# End of 10.1 tests
--
echo
#
sql/item_cmpfunc.h
View file @
9d884fd3
...
...
@@ -120,6 +120,10 @@ public:
friend
class
Item_func
;
};
class
SEL_ARG
;
struct
KEY_PART
;
class
Item_bool_func
:
public
Item_int_func
{
protected:
...
...
@@ -147,6 +151,9 @@ protected:
SEL_TREE
*
get_ne_mm_tree
(
RANGE_OPT_PARAM
*
param
,
Field
*
field
,
Item
*
lt_value
,
Item
*
gt_value
,
Item_result
cmp_type
);
virtual
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
Field
*
field
,
KEY_PART
*
key_part
,
Item_func
::
Functype
type
,
Item
*
value
);
public:
Item_bool_func
()
:
Item_int_func
()
{}
Item_bool_func
(
Item
*
a
)
:
Item_int_func
(
a
)
{}
...
...
@@ -1437,6 +1444,9 @@ protected:
DBUG_ENTER
(
"Item_func_null_predicate::get_func_mm_tree"
);
DBUG_RETURN
(
get_mm_parts
(
param
,
field
,
functype
(),
value
,
cmp_type
));
}
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
Field
*
field
,
KEY_PART
*
key_part
,
Item_func
::
Functype
type
,
Item
*
value
);
public:
Item_func_null_predicate
(
Item
*
a
)
:
Item_bool_func
(
a
)
{
}
void
add_key_fields
(
JOIN
*
join
,
KEY_FIELD
**
key_fields
,
uint
*
and_level
,
...
...
@@ -1552,6 +1562,10 @@ class Item_func_like :public Item_bool_func2
DTCollation
cmp_collation
;
String
cmp_value1
,
cmp_value2
;
bool
with_sargable_pattern
()
const
;
protected:
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
Field
*
field
,
KEY_PART
*
key_part
,
Item_func
::
Functype
type
,
Item
*
value
);
public:
int
escape
;
...
...
sql/opt_range.cc
View file @
9d884fd3
...
...
@@ -945,10 +945,6 @@ class TABLE_READ_PLAN;
struct
st_index_scan_info
;
struct
st_ror_scan_info
;
static
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
COND
*
cond_func
,
Field
*
field
,
KEY_PART
*
key_part
,
Item_func
::
Functype
type
,
Item
*
value
);
static
bool
is_key_scan_ror
(
PARAM
*
param
,
uint
keynr
,
uint8
nparts
);
static
ha_rows
check_quick_select
(
PARAM
*
param
,
uint
idx
,
bool
index_only
,
SEL_ARG
*
tree
,
bool
update_tbl_stats
,
...
...
@@ -8235,7 +8231,19 @@ Item_bool_func::get_mm_parts(RANGE_OPT_PARAM *param, Field *field,
DBUG_RETURN
(
0
);
// OOM
if
(
!
value
||
!
(
value
->
used_tables
()
&
~
param
->
read_tables
))
{
sel_arg
=
get_mm_leaf
(
param
,
this
,
key_part
->
field
,
key_part
,
type
,
value
);
/*
We need to restore the runtime mem_root of the thread in this
function because it evaluates the value of its argument, while
the argument can be any, e.g. a subselect. The subselect
items, in turn, assume that all the memory allocated during
the evaluation has the same life span as the item itself.
TODO: opt_range.cc should not reset thd->mem_root at all.
*/
MEM_ROOT
*
tmp_root
=
param
->
mem_root
;
param
->
thd
->
mem_root
=
param
->
old_root
;
sel_arg
=
get_mm_leaf
(
param
,
key_part
->
field
,
key_part
,
type
,
value
);
param
->
thd
->
mem_root
=
tmp_root
;
if
(
!
sel_arg
)
continue
;
if
(
sel_arg
->
type
==
SEL_ARG
::
IMPOSSIBLE
)
...
...
@@ -8263,53 +8271,144 @@ Item_bool_func::get_mm_parts(RANGE_OPT_PARAM *param, Field *field,
}
static
SEL_ARG
*
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
COND
*
conf_func
,
Field
*
field
,
KEY_PART
*
key_part
,
Item_func
::
Functype
type
,
Item
*
value
)
SEL_ARG
*
Item_func_null_predicate
::
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
Field
*
field
,
KEY_PART
*
key_part
,
Item_func
::
Functype
type
,
Item
*
value
)
{
uint
maybe_null
=
(
uint
)
field
->
real_maybe_null
();
bool
optimize_range
;
SEL_ARG
*
tree
=
0
;
MEM_ROOT
*
alloc
=
param
->
mem_root
;
uchar
*
str
;
int
err
;
DBUG_ENTER
(
"get_mm_leaf"
);
DBUG_ENTER
(
"Item_func_null_predicate::get_mm_leaf"
);
DBUG_ASSERT
(
!
value
);
/*
No check for field->table->maybe_null. It's perfecly fine to use range
access for cases like
SELECT * FROM t1 LEFT JOIN t2 ON t2.key IS [NOT] NULL
ON expression is evaluated before considering NULL-complemented rows, so
IS [NOT] NULL has regular semantics.
*/
if
(
!
field
->
real_maybe_null
())
DBUG_RETURN
(
type
==
ISNULL_FUNC
?
&
null_element
:
NULL
);
SEL_ARG
*
tree
;
if
(
!
(
tree
=
new
(
alloc
)
SEL_ARG
(
field
,
is_null_string
,
is_null_string
)))
DBUG_RETURN
(
0
);
if
(
type
==
Item_func
::
ISNOTNULL_FUNC
)
{
tree
->
min_flag
=
NEAR_MIN
;
/* IS NOT NULL -> X > NULL */
tree
->
max_flag
=
NO_MAX_RANGE
;
}
DBUG_RETURN
(
tree
);
}
SEL_ARG
*
Item_func_like
::
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
Field
*
field
,
KEY_PART
*
key_part
,
Item_func
::
Functype
type
,
Item
*
value
)
{
DBUG_ENTER
(
"Item_func_like::get_mm_leaf"
);
DBUG_ASSERT
(
value
);
if
(
key_part
->
image_type
!=
Field
::
itRAW
)
DBUG_RETURN
(
0
);
if
(
param
->
using_real_indexes
&&
!
field
->
optimize_range
(
param
->
real_keynr
[
key_part
->
key
],
key_part
->
part
))
DBUG_RETURN
(
0
);
if
(
field
->
result_type
()
==
STRING_RESULT
&&
field
->
charset
()
!=
compare_collation
())
DBUG_RETURN
(
0
);
StringBuffer
<
MAX_FIELD_WIDTH
>
tmp
(
value
->
collation
.
collation
);
String
*
res
;
if
(
!
(
res
=
value
->
val_str
(
&
tmp
)))
DBUG_RETURN
(
&
null_element
);
if
(
field
->
cmp_type
()
!=
STRING_RESULT
)
DBUG_RETURN
(
0
);
/*
We need to restore the runtime mem_root of the thread in this
function because it evaluates the value of its argument, while
the argument can be any, e.g. a subselect. The subselect
items, in turn, assume that all the memory allocated during
the evaluation has the same life span as the item itself.
TODO: opt_range.cc should not reset thd->mem_root at all.
TODO:
Check if this was a function. This should have be optimized away
in the sql_select.cc
*/
param
->
thd
->
mem_root
=
param
->
old_root
;
if
(
!
value
)
// IS NULL or IS NOT NULL
if
(
res
!=
&
tmp
)
{
/*
No check for field->table->maybe_null. It's perfecly fine to use range
access for cases like
tmp
.
copy
(
*
res
);
// Get own copy
res
=
&
tmp
;
}
SELECT * FROM t1 LEFT JOIN t2 ON t2.key IS [NOT] NULL
uint
maybe_null
=
(
uint
)
field
->
real_maybe_null
();
uint
field_length
=
field
->
pack_length
()
+
maybe_null
;
size_t
offset
=
maybe_null
;
size_t
length
=
key_part
->
store_length
;
ON expression is evaluated before considering NULL-complemented rows, so
IS [NOT] NULL has regular semantics.
*/
if
(
!
maybe_null
)
// Not null field
{
if
(
type
==
Item_func
::
ISNULL_FUNC
)
tree
=
&
null_element
;
goto
end
;
}
if
(
!
(
tree
=
new
(
alloc
)
SEL_ARG
(
field
,
is_null_string
,
is_null_string
)))
goto
end
;
// out of memory
if
(
type
==
Item_func
::
ISNOTNULL_FUNC
)
if
(
length
!=
key_part
->
length
+
maybe_null
)
{
/* key packed with length prefix */
offset
+=
HA_KEY_BLOB_LENGTH
;
field_length
=
length
-
HA_KEY_BLOB_LENGTH
;
}
else
{
if
(
unlikely
(
length
<
field_length
))
{
tree
->
min_flag
=
NEAR_MIN
;
/* IS NOT NULL -> X > NULL */
tree
->
max_flag
=
NO_MAX_RANGE
;
/*
This can only happen in a table created with UNIREG where one key
overlaps many fields
*/
length
=
field_length
;
}
goto
end
;
else
field_length
=
length
;
}
length
+=
offset
;
uchar
*
min_str
,
*
max_str
;
if
(
!
(
min_str
=
(
uchar
*
)
alloc_root
(
param
->
mem_root
,
length
*
2
)))
DBUG_RETURN
(
0
);
max_str
=
min_str
+
length
;
if
(
maybe_null
)
max_str
[
0
]
=
min_str
[
0
]
=
0
;
size_t
min_length
,
max_length
;
field_length
-=
maybe_null
;
if
(
my_like_range
(
field
->
charset
(),
res
->
ptr
(),
res
->
length
(),
escape
,
wild_one
,
wild_many
,
field_length
,
(
char
*
)
min_str
+
offset
,
(
char
*
)
max_str
+
offset
,
&
min_length
,
&
max_length
))
DBUG_RETURN
(
0
);
// Can't optimize with LIKE
if
(
offset
!=
maybe_null
)
// BLOB or VARCHAR
{
int2store
(
min_str
+
maybe_null
,
min_length
);
int2store
(
max_str
+
maybe_null
,
max_length
);
}
SEL_ARG
*
tree
=
new
(
param
->
mem_root
)
SEL_ARG
(
field
,
min_str
,
max_str
);
DBUG_RETURN
(
tree
);
}
SEL_ARG
*
Item_bool_func
::
get_mm_leaf
(
RANGE_OPT_PARAM
*
param
,
Field
*
field
,
KEY_PART
*
key_part
,
Item_func
::
Functype
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
/*
1. Usually we can't use an index if the column collation
...
...
@@ -8327,9 +8426,9 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
field
->
match_collation_to_optimize_range
()
&&
value
->
result_type
()
==
STRING_RESULT
&&
key_part
->
image_type
==
Field
::
itRAW
&&
field
->
charset
()
!=
co
nf_func
->
co
mpare_collation
()
&&
!
((
type
==
Item_func
::
EQUAL_FUNC
||
type
==
Item_func
::
EQ_FUNC
)
&&
co
nf_func
->
co
mpare_collation
()
->
state
&
MY_CS_BINSORT
))
field
->
charset
()
!=
compare_collation
()
&&
!
((
type
==
EQUAL_FUNC
||
type
==
EQ_FUNC
)
&&
compare_collation
()
->
state
&
MY_CS_BINSORT
))
goto
end
;
if
(
value
->
cmp_type
()
==
TIME_RESULT
&&
field
->
cmp_type
()
!=
TIME_RESULT
)
goto
end
;
...
...
@@ -8338,14 +8437,14 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
{
// @todo: use is_spatial_operator() instead?
switch
(
type
)
{
case
Item_func
:
:
SP_EQUALS_FUNC
:
case
Item_func
:
:
SP_DISJOINT_FUNC
:
case
Item_func
:
:
SP_INTERSECTS_FUNC
:
case
Item_func
:
:
SP_TOUCHES_FUNC
:
case
Item_func
:
:
SP_CROSSES_FUNC
:
case
Item_func
:
:
SP_WITHIN_FUNC
:
case
Item_func
:
:
SP_CONTAINS_FUNC
:
case
Item_func
:
:
SP_OVERLAPS_FUNC
:
case
SP_EQUALS_FUNC
:
case
SP_DISJOINT_FUNC
:
case
SP_INTERSECTS_FUNC
:
case
SP_TOUCHES_FUNC
:
case
SP_CROSSES_FUNC
:
case
SP_WITHIN_FUNC
:
case
SP_CONTAINS_FUNC
:
case
SP_OVERLAPS_FUNC
:
break
;
default:
/*
...
...
@@ -8356,95 +8455,11 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
}
}
if
(
param
->
using_real_indexes
)
optimize_range
=
field
->
optimize_range
(
param
->
real_keynr
[
key_part
->
key
],
key_part
->
part
);
else
optimize_range
=
TRUE
;
if
(
type
==
Item_func
::
LIKE_FUNC
)
{
bool
like_error
;
char
buff1
[
MAX_FIELD_WIDTH
];
uchar
*
min_str
,
*
max_str
;
String
tmp
(
buff1
,
sizeof
(
buff1
),
value
->
collation
.
collation
),
*
res
;
size_t
length
,
offset
,
min_length
,
max_length
;
uint
field_length
=
field
->
pack_length
()
+
maybe_null
;
if
(
!
optimize_range
)
goto
end
;
if
(
!
(
res
=
value
->
val_str
(
&
tmp
)))
{
tree
=
&
null_element
;
goto
end
;
}
/*
TODO:
Check if this was a function. This should have be optimized away
in the sql_select.cc
*/
if
(
res
!=
&
tmp
)
{
tmp
.
copy
(
*
res
);
// Get own copy
res
=
&
tmp
;
}
if
(
field
->
cmp_type
()
!=
STRING_RESULT
)
goto
end
;
// Can only optimize strings
offset
=
maybe_null
;
length
=
key_part
->
store_length
;
if
(
length
!=
key_part
->
length
+
maybe_null
)
{
/* key packed with length prefix */
offset
+=
HA_KEY_BLOB_LENGTH
;
field_length
=
length
-
HA_KEY_BLOB_LENGTH
;
}
else
{
if
(
unlikely
(
length
<
field_length
))
{
/*
This can only happen in a table created with UNIREG where one key
overlaps many fields
*/
length
=
field_length
;
}
else
field_length
=
length
;
}
length
+=
offset
;
if
(
!
(
min_str
=
(
uchar
*
)
alloc_root
(
alloc
,
length
*
2
)))
goto
end
;
max_str
=
min_str
+
length
;
if
(
maybe_null
)
max_str
[
0
]
=
min_str
[
0
]
=
0
;
field_length
-=
maybe_null
;
like_error
=
my_like_range
(
field
->
charset
(),
res
->
ptr
(),
res
->
length
(),
((
Item_func_like
*
)(
conf_func
))
->
escape
,
wild_one
,
wild_many
,
field_length
,
(
char
*
)
min_str
+
offset
,
(
char
*
)
max_str
+
offset
,
&
min_length
,
&
max_length
);
if
(
like_error
)
// Can't optimize with LIKE
goto
end
;
if
(
offset
!=
maybe_null
)
// BLOB or VARCHAR
{
int2store
(
min_str
+
maybe_null
,
min_length
);
int2store
(
max_str
+
maybe_null
,
max_length
);
}
tree
=
new
(
alloc
)
SEL_ARG
(
field
,
min_str
,
max_str
);
goto
end
;
}
if
(
!
optimize_range
&&
type
!=
Item_func
::
EQ_FUNC
&&
type
!=
Item_func
::
EQUAL_FUNC
)
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
/*
...
...
@@ -8456,7 +8471,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
err
=
value
->
save_in_field_no_warnings
(
field
,
1
);
if
(
err
==
2
&&
field
->
cmp_type
()
==
STRING_RESULT
)
{
if
(
type
==
Item_func
::
EQ_FUNC
)
if
(
type
==
EQ_FUNC
)
{
tree
=
new
(
alloc
)
SEL_ARG
(
field
,
0
,
0
);
tree
->
type
=
SEL_ARG
::
IMPOSSIBLE
;
...
...
@@ -8469,7 +8484,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
{
if
(
field
->
cmp_type
()
!=
value
->
result_type
())
{
if
((
type
==
Item_func
::
EQ_FUNC
||
type
==
Item_func
::
EQUAL_FUNC
)
&&
if
((
type
==
EQ_FUNC
||
type
==
EQUAL_FUNC
)
&&
value
->
result_type
()
==
item_cmp_type
(
field
->
result_type
(),
value
->
result_type
()))
{
...
...
@@ -8485,8 +8500,8 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
*/
tree
=
0
;
if
(
err
==
3
&&
field
->
type
()
==
FIELD_TYPE_DATE
&&
(
type
==
Item_func
::
GT_FUNC
||
type
==
Item_func
::
GE_FUNC
||
type
==
Item_func
::
LT_FUNC
||
type
==
Item_func
::
LE_FUNC
)
)
(
type
==
GT_FUNC
||
type
==
GE_FUNC
||
type
==
LT_FUNC
||
type
==
LE_FUNC
)
)
{
/*
We were saving DATETIME into a DATE column, the conversion went ok
...
...
@@ -8519,14 +8534,14 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
*/
else
if
(
err
==
1
&&
field
->
result_type
()
==
INT_RESULT
)
{
if
(
type
==
Item_func
::
LT_FUNC
&&
(
value
->
val_int
()
>
0
))
type
=
Item_func
::
LE_FUNC
;
else
if
(
type
==
Item_func
::
GT_FUNC
&&
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
&&
!
((
Item_int
*
)
value
)
->
unsigned_flag
&&
(
value
->
val_int
()
<
0
))
type
=
Item_func
::
GE_FUNC
;
type
=
GE_FUNC
;
}
}
else
if
(
err
<
0
)
...
...
@@ -8540,7 +8555,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
Any sargable predicate except "<=>" involving NULL as a constant is always
FALSE
*/
if
(
type
!=
Item_func
::
EQUAL_FUNC
&&
field
->
is_real_null
())
if
(
type
!=
EQUAL_FUNC
&&
field
->
is_real_null
())
{
tree
=
&
null_element
;
goto
end
;
...
...
@@ -8576,12 +8591,12 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
longlong
item_val
=
value
->
val_int
();
if
(
item_val
<
0
)
{
if
(
type
==
Item_func
::
LT_FUNC
||
type
==
Item_func
::
LE_FUNC
)
if
(
type
==
LT_FUNC
||
type
==
LE_FUNC
)
{
tree
->
type
=
SEL_ARG
::
IMPOSSIBLE
;
goto
end
;
}
if
(
type
==
Item_func
::
GT_FUNC
||
type
==
Item_func
::
GE_FUNC
)
if
(
type
==
GT_FUNC
||
type
==
GE_FUNC
)
{
tree
=
0
;
goto
end
;
...
...
@@ -8590,11 +8605,11 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
}
switch
(
type
)
{
case
Item_func
:
:
LT_FUNC
:
case
LT_FUNC
:
if
(
stored_field_cmp_to_item
(
param
->
thd
,
field
,
value
)
==
0
)
tree
->
max_flag
=
NEAR_MAX
;
/* fall through */
case
Item_func
:
:
LE_FUNC
:
case
LE_FUNC
:
if
(
!
maybe_null
)
tree
->
min_flag
=
NO_MIN_RANGE
;
/* From start */
else
...
...
@@ -8603,61 +8618,61 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
tree
->
min_flag
=
NEAR_MIN
;
}
break
;
case
Item_func
:
:
GT_FUNC
:
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
Item_func
:
:
GE_FUNC
:
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
Item_func
:
:
SP_EQUALS_FUNC
:
case
SP_EQUALS_FUNC
:
tree
->
min_flag
=
GEOM_FLAG
|
HA_READ_MBR_EQUAL
;
// NEAR_MIN;//512;
tree
->
max_flag
=
NO_MAX_RANGE
;
break
;
case
Item_func
:
:
SP_DISJOINT_FUNC
:
case
SP_DISJOINT_FUNC
:
tree
->
min_flag
=
GEOM_FLAG
|
HA_READ_MBR_DISJOINT
;
// NEAR_MIN;//512;
tree
->
max_flag
=
NO_MAX_RANGE
;
break
;
case
Item_func
:
:
SP_INTERSECTS_FUNC
:
case
SP_INTERSECTS_FUNC
:
tree
->
min_flag
=
GEOM_FLAG
|
HA_READ_MBR_INTERSECT
;
// NEAR_MIN;//512;
tree
->
max_flag
=
NO_MAX_RANGE
;
break
;
case
Item_func
:
:
SP_TOUCHES_FUNC
:
case
SP_TOUCHES_FUNC
:
tree
->
min_flag
=
GEOM_FLAG
|
HA_READ_MBR_INTERSECT
;
// NEAR_MIN;//512;
tree
->
max_flag
=
NO_MAX_RANGE
;
break
;
case
Item_func
:
:
SP_CROSSES_FUNC
:
case
SP_CROSSES_FUNC
:
tree
->
min_flag
=
GEOM_FLAG
|
HA_READ_MBR_INTERSECT
;
// NEAR_MIN;//512;
tree
->
max_flag
=
NO_MAX_RANGE
;
break
;
case
Item_func
:
:
SP_WITHIN_FUNC
:
case
SP_WITHIN_FUNC
:
tree
->
min_flag
=
GEOM_FLAG
|
HA_READ_MBR_WITHIN
;
// NEAR_MIN;//512;
tree
->
max_flag
=
NO_MAX_RANGE
;
break
;
case
Item_func
:
:
SP_CONTAINS_FUNC
:
case
SP_CONTAINS_FUNC
:
tree
->
min_flag
=
GEOM_FLAG
|
HA_READ_MBR_CONTAIN
;
// NEAR_MIN;//512;
tree
->
max_flag
=
NO_MAX_RANGE
;
break
;
case
Item_func
:
:
SP_OVERLAPS_FUNC
:
case
SP_OVERLAPS_FUNC
:
tree
->
min_flag
=
GEOM_FLAG
|
HA_READ_MBR_INTERSECT
;
// NEAR_MIN;//512;
tree
->
max_flag
=
NO_MAX_RANGE
;
break
;
case
EQ_FUNC
:
case
EQUAL_FUNC
:
break
;
default:
DBUG_ASSERT
(
0
);
break
;
}
end:
param
->
thd
->
mem_root
=
alloc
;
DBUG_RETURN
(
tree
);
}
...
...
sql/opt_range.h
View file @
9d884fd3
...
...
@@ -38,7 +38,7 @@
class
JOIN
;
class
Item_sum
;
typedef
struct
st_key_part
{
struct
KEY_PART
{
uint16
key
,
part
;
/* See KEY_PART_INFO for meaning of the next two: */
uint16
store_length
,
length
;
...
...
@@ -50,7 +50,7 @@ typedef struct st_key_part {
uint8
flag
;
Field
*
field
;
Field
::
imagetype
image_type
;
}
KEY_PART
;
};
class
Explain_quick_select
;
/*
...
...
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