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
c89fc771
Commit
c89fc771
authored
May 16, 2006
by
sergefp@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/psergey/mysql-5.0-bug19618
parents
62e0e90a
b7c52881
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
109 additions
and
29 deletions
+109
-29
mysql-test/r/func_in.result
mysql-test/r/func_in.result
+17
-0
mysql-test/t/func_in.test
mysql-test/t/func_in.test
+12
-0
sql/opt_range.cc
sql/opt_range.cc
+80
-29
No files found.
mysql-test/r/func_in.result
View file @
c89fc771
...
@@ -326,3 +326,20 @@ deallocate prepare s;
...
@@ -326,3 +326,20 @@ deallocate prepare s;
set @str=NULL;
set @str=NULL;
drop table t2;
drop table t2;
drop table t1;
drop table t1;
create table t1 (
some_id smallint(5) unsigned,
key (some_id)
);
insert into t1 values (1),(2);
select some_id from t1 where some_id not in(2,-1);
some_id
1
select some_id from t1 where some_id not in(-4,-1,-4);
some_id
1
2
select some_id from t1 where some_id not in(-4,-1,3423534,2342342);
some_id
1
2
drop table t1;
mysql-test/t/func_in.test
View file @
c89fc771
...
@@ -220,3 +220,15 @@ set @str=NULL;
...
@@ -220,3 +220,15 @@ set @str=NULL;
drop
table
t2
;
drop
table
t2
;
drop
table
t1
;
drop
table
t1
;
# BUG#19618: Crash in range optimizer for
# "unsigned_keypart NOT IN(negative_number,...)"
# (introduced in fix BUG#15872)
create
table
t1
(
some_id
smallint
(
5
)
unsigned
,
key
(
some_id
)
);
insert
into
t1
values
(
1
),(
2
);
select
some_id
from
t1
where
some_id
not
in
(
2
,
-
1
);
select
some_id
from
t1
where
some_id
not
in
(
-
4
,
-
1
,
-
4
);
select
some_id
from
t1
where
some_id
not
in
(
-
4
,
-
1
,
3423534
,
2342342
);
drop
table
t1
;
sql/opt_range.cc
View file @
c89fc771
...
@@ -3503,17 +3503,46 @@ static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func,
...
@@ -3503,17 +3503,46 @@ static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func,
if
(
inv
)
if
(
inv
)
{
{
/*
We get here for conditions like "t.keypart NOT IN (....)".
If the IN-list contains only constants (and func->array is an ordered
array of them), we construct the appropriate SEL_ARG tree manually,
because constructing it using the range analyzer (as
AND_i( t.keypart != c_i)) will cause lots of memory to be consumed
(see BUG#15872).
*/
if
(
func
->
array
&&
func
->
cmp_type
!=
ROW_RESULT
)
if
(
func
->
array
&&
func
->
cmp_type
!=
ROW_RESULT
)
{
{
/*
We get here for conditions in form "t.key NOT IN (c1, c2, ...)"
(where c{i} are constants).
Our goal is to produce a SEL_ARG graph that represents intervals:
($MIN<t.key<c1) OR (c1<t.key<c2) OR (c2<t.key<c3) OR ... (*)
where $MIN is either "-inf" or NULL.
The most straightforward way to handle NOT IN would be to convert
it to "(t.key != c1) AND (t.key != c2) AND ..." and let the range
optimizer to build SEL_ARG graph from that. However that will cause
the range optimizer to use O(N^2) memory (it's a bug, not filed),
and people do use big NOT IN lists (see BUG#15872). Also, for big
NOT IN lists constructing/using graph (*) does not make the query
faster.
So, we will handle NOT IN manually in the following way:
* if the number of entries in the NOT IN list is less then
NOT_IN_IGNORE_THRESHOLD, we will construct SEL_ARG graph (*)
manually.
* Otherwise, we will construct a smaller graph: for
"t.key NOT IN (c1,...cN)" we construct a graph representing
($MIN < t.key) OR (cN < t.key) // here sequence of c_i is
// ordered.
A note about partially-covering indexes: for those (e.g. for
"a CHAR(10), KEY(a(5))") the handling is correct (albeit not very
efficient):
Instead of "t.key < c1" we get "t.key <= prefix-val(c1)".
Combining the intervals in (*) together, we get:
(-inf<=t.key<=c1) OR (c1<=t.key<=c2) OR (c2<=t.key<=c3) OR ...
i.e. actually we get intervals combined into one interval:
(-inf<=t.key<=+inf). This doesn't make much sense but it doesn't
cause any problems.
*/
MEM_ROOT
*
tmp_root
=
param
->
mem_root
;
param
->
thd
->
mem_root
=
param
->
old_root
;
/*
/*
Create one Item_type constant object. We'll need it as
Create one Item_type constant object. We'll need it as
get_mm_parts only accepts constant values wrapped in Item_Type
get_mm_parts only accepts constant values wrapped in Item_Type
...
@@ -3522,25 +3551,35 @@ static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func,
...
@@ -3522,25 +3551,35 @@ static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func,
per-statement mem_root (while thd->mem_root is currently pointing
per-statement mem_root (while thd->mem_root is currently pointing
to mem_root local to range optimizer).
to mem_root local to range optimizer).
*/
*/
MEM_ROOT
*
tmp_root
=
param
->
mem_root
;
param
->
thd
->
mem_root
=
param
->
old_root
;
Item
*
value_item
=
func
->
array
->
create_item
();
Item
*
value_item
=
func
->
array
->
create_item
();
param
->
thd
->
mem_root
=
tmp_root
;
param
->
thd
->
mem_root
=
tmp_root
;
if
(
!
value_item
)
if
(
!
value_item
)
break
;
break
;
/* Get a SEL_TREE for "-inf < X < c_0" interval */
/* Get a SEL_TREE for "(-inf|NULL) < X < c_0" interval. */
func
->
array
->
value_to_item
(
0
,
value_item
);
uint
i
=
0
;
tree
=
get_mm_parts
(
param
,
cond_func
,
field
,
Item_func
::
LT_FUNC
,
do
value_item
,
cmp_type
);
{
if
(
!
tree
)
func
->
array
->
value_to_item
(
i
,
value_item
);
tree
=
get_mm_parts
(
param
,
cond_func
,
field
,
Item_func
::
LT_FUNC
,
value_item
,
cmp_type
);
if
(
!
tree
)
break
;
i
++
;
}
while
(
i
<
func
->
array
->
count
&&
tree
->
type
==
SEL_TREE
::
IMPOSSIBLE
);
if
(
!
tree
||
tree
->
type
==
SEL_TREE
::
IMPOSSIBLE
)
{
/* We get here in cases like "t.unsigned NOT IN (-1,-2,-3) */
tree
=
NULL
;
break
;
break
;
}
#define NOT_IN_IGNORE_THRESHOLD 1000
#define NOT_IN_IGNORE_THRESHOLD 1000
SEL_TREE
*
tree2
;
SEL_TREE
*
tree2
;
if
(
func
->
array
->
count
<
NOT_IN_IGNORE_THRESHOLD
)
if
(
func
->
array
->
count
<
NOT_IN_IGNORE_THRESHOLD
)
{
{
for
(
uint
i
=
1
;
i
<
func
->
array
->
count
;
i
++
)
for
(;
i
<
func
->
array
->
count
;
i
++
)
{
{
if
(
func
->
array
->
compare_elems
(
i
,
i
-
1
))
if
(
func
->
array
->
compare_elems
(
i
,
i
-
1
))
{
{
...
@@ -3548,32 +3587,44 @@ static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func,
...
@@ -3548,32 +3587,44 @@ static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func,
func
->
array
->
value_to_item
(
i
,
value_item
);
func
->
array
->
value_to_item
(
i
,
value_item
);
tree2
=
get_mm_parts
(
param
,
cond_func
,
field
,
Item_func
::
LT_FUNC
,
tree2
=
get_mm_parts
(
param
,
cond_func
,
field
,
Item_func
::
LT_FUNC
,
value_item
,
cmp_type
);
value_item
,
cmp_type
);
if
(
!
tree2
)
{
tree
=
NULL
;
break
;
}
/* Change all intervals to be "c_{i-1} < X < c_i" */
/* Change all intervals to be "c_{i-1} < X < c_i" */
for
(
uint
idx
=
0
;
idx
<
param
->
keys
;
idx
++
)
for
(
uint
idx
=
0
;
idx
<
param
->
keys
;
idx
++
)
{
{
SEL_ARG
*
new_interval
;
SEL_ARG
*
new_interval
,
*
last_val
;
if
((
new_interval
=
tree2
->
keys
[
idx
]))
if
(((
new_interval
=
tree2
->
keys
[
idx
]))
&&
((
last_val
=
tree
->
keys
[
idx
]
->
last
())))
{
{
SEL_ARG
*
last_val
=
tree
->
keys
[
idx
]
->
last
();
new_interval
->
min_value
=
last_val
->
max_value
;
new_interval
->
min_value
=
last_val
->
max_value
;
new_interval
->
min_flag
=
NEAR_MIN
;
new_interval
->
min_flag
=
NEAR_MIN
;
}
}
}
}
/*
The following doesn't try to allocate memory so no need to
check for NULL.
*/
tree
=
tree_or
(
param
,
tree
,
tree2
);
tree
=
tree_or
(
param
,
tree
,
tree2
);
}
}
}
}
}
}
else
else
func
->
array
->
value_to_item
(
func
->
array
->
count
-
1
,
value_item
);
func
->
array
->
value_to_item
(
func
->
array
->
count
-
1
,
value_item
);
/*
if
(
tree
&&
tree
->
type
!=
SEL_TREE
::
IMPOSSIBLE
)
Get the SEL_TREE for the last "c_last < X < +inf" interval
{
(value_item cotains c_last already)
/*
*/
Get the SEL_TREE for the last "c_last < X < +inf" interval
tree2
=
get_mm_parts
(
param
,
cond_func
,
field
,
Item_func
::
GT_FUNC
,
(value_item cotains c_last already)
value_item
,
cmp_type
);
*/
tree
=
tree_or
(
param
,
tree
,
tree2
);
tree2
=
get_mm_parts
(
param
,
cond_func
,
field
,
Item_func
::
GT_FUNC
,
value_item
,
cmp_type
);
tree
=
tree_or
(
param
,
tree
,
tree2
);
}
}
}
else
else
{
{
...
...
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