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
c964cb1b
Commit
c964cb1b
authored
Aug 14, 2010
by
Sergey Petrunya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
key/rowid buffer overflow fixes for various tricky cases.
parent
d098596b
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
78 additions
and
46 deletions
+78
-46
mysql-test/r/join_nested_jcl6.result
mysql-test/r/join_nested_jcl6.result
+3
-3
sql/multi_range_read.cc
sql/multi_range_read.cc
+67
-43
sql/multi_range_read.h
sql/multi_range_read.h
+8
-0
No files found.
mysql-test/r/join_nested_jcl6.result
View file @
c964cb1b
...
@@ -865,12 +865,12 @@ LEFT JOIN
...
@@ -865,12 +865,12 @@ LEFT JOIN
(t1,t2)
(t1,t2)
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
a b a b a b
a b a b a b
4 2 1 2 3 2
4 2 1 2 4 2
4 2 1 2 4 2
4 2 1 2 3 2
4 2 1 2 3 2
4 2 1 2 4 2
4 2 1 2 4 2
4 2 1 2 3 2
4 2 1 2 3 2
4 2 1 2 4 2
4 2 1 2 4 2
4 2 1 2 3 2
NULL NULL 2 2 3 2
NULL NULL 2 2 3 2
NULL NULL 2 2 4 2
NULL NULL 2 2 4 2
EXPLAIN EXTENDED
EXPLAIN EXTENDED
...
@@ -1105,8 +1105,8 @@ t0.b=t1.b AND
...
@@ -1105,8 +1105,8 @@ t0.b=t1.b AND
(t8.b=t9.b OR t8.c IS NULL) AND
(t8.b=t9.b OR t8.c IS NULL) AND
(t9.a=1);
(t9.a=1);
a b a b a b a b a b a b a b a b a b a b
a b a b a b a b a b a b a b a b a b a b
1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2 1 2
1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2 1 2
1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2 1 2
1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2 1 2
1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 1
1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 1
1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 1
1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 1
1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 2
1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 2
...
@@ -1785,8 +1785,8 @@ ON t7.b=t8.b AND t6.b < 10
...
@@ -1785,8 +1785,8 @@ ON t7.b=t8.b AND t6.b < 10
ON t6.b >= 2 AND t5.b=t7.b AND
ON t6.b >= 2 AND t5.b=t7.b AND
(t8.a > 0 OR t8.c IS NULL);
(t8.a > 0 OR t8.c IS NULL);
a b a b a b a b
a b a b a b a b
2 2 1 2 2 2 1 2
2 2 3 2 2 2 1 2
2 2 3 2 2 2 1 2
2 2 1 2 2 2 1 2
1 1 1 2 1 1 NULL NULL
1 1 1 2 1 1 NULL NULL
1 1 3 2 1 1 NULL NULL
1 1 3 2 1 1 NULL NULL
3 3 NULL NULL NULL NULL NULL NULL
3 3 NULL NULL NULL NULL NULL NULL
...
...
sql/multi_range_read.cc
View file @
c964cb1b
...
@@ -563,8 +563,8 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
...
@@ -563,8 +563,8 @@ int DsMrr_impl::dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs,
If the above call has scanned through all intervals in *seq, then
If the above call has scanned through all intervals in *seq, then
adjust *buf to indicate that the remaining buffer space will not be used.
adjust *buf to indicate that the remaining buffer space will not be used.
*/
*/
if
(
dsmrr_eof
)
//
if (dsmrr_eof)
buf
->
end_of_used_area
=
rowid_buffer
.
end_of_space
();
//
buf->end_of_used_area= rowid_buffer.end_of_space();
/*
/*
h->inited == INDEX may occur when 'range checked for each record' is
h->inited == INDEX may occur when 'range checked for each record' is
...
@@ -619,21 +619,18 @@ static int rowid_cmp(void *h, uchar *a, uchar *b)
...
@@ -619,21 +619,18 @@ static int rowid_cmp(void *h, uchar *a, uchar *b)
buffer. When the buffer is full or scan is completed, sort the buffer by
buffer. When the buffer is full or scan is completed, sort the buffer by
rowid and return.
rowid and return.
The function assumes that rowids buffer is empty when it is invoked.
New2:
we will need to scan either
- the source sequence getting records
- use dsmrr_next_from_index..
dsmrr_eof is set to indicate whether we've exhausted the list of ranges we're
dsmrr_eof is set to indicate whether we've exhausted the list of ranges we're
scanning.
scanning. This function never returns HA_ERR_END_OF_FILE.
post-condition:
rowid buffer is not empty, or key source is exhausted.
@param h Table handler
@param h Table handler
@retval 0 OK, the next portion of rowids is in the buffer,
@retval 0 OK, the next portion of rowids is in the buffer,
properly ordered
properly ordered
@retval other Error
@retval other Error
*/
*/
int
DsMrr_impl
::
dsmrr_fill_rowid_buffer
()
int
DsMrr_impl
::
dsmrr_fill_rowid_buffer
()
...
@@ -642,9 +639,11 @@ int DsMrr_impl::dsmrr_fill_rowid_buffer()
...
@@ -642,9 +639,11 @@ int DsMrr_impl::dsmrr_fill_rowid_buffer()
int
res
;
int
res
;
DBUG_ENTER
(
"DsMrr_impl::dsmrr_fill_rowid_buffer"
);
DBUG_ENTER
(
"DsMrr_impl::dsmrr_fill_rowid_buffer"
);
DBUG_ASSERT
(
rowid_buffer
.
is_empty
());
rowid_buffer
.
reset_for_writing
();
rowid_buffer
.
reset_for_writing
();
identical_rowid_ptr
=
NULL
;
identical_rowid_ptr
=
NULL
;
if
(
do_sort_keys
)
if
(
key_buffer
.
is_reverse
())
key_buffer
.
flip
();
key_buffer
.
flip
();
while
(
rowid_buffer
.
have_space_for
(
rowid_buff_elem_size
))
while
(
rowid_buffer
.
have_space_for
(
rowid_buff_elem_size
))
...
@@ -657,7 +656,6 @@ int DsMrr_impl::dsmrr_fill_rowid_buffer()
...
@@ -657,7 +656,6 @@ int DsMrr_impl::dsmrr_fill_rowid_buffer()
if
(
res
)
if
(
res
)
break
;
break
;
KEY_MULTI_RANGE
*
curr_range
=
&
h2
->
handler
::
mrr_cur_range
;
KEY_MULTI_RANGE
*
curr_range
=
&
h2
->
handler
::
mrr_cur_range
;
if
(
!
do_sort_keys
&&
/* If keys are sorted then this check is already done */
if
(
!
do_sort_keys
&&
/* If keys are sorted then this check is already done */
h2
->
mrr_funcs
.
skip_index_tuple
&&
h2
->
mrr_funcs
.
skip_index_tuple
&&
...
@@ -674,6 +672,8 @@ int DsMrr_impl::dsmrr_fill_rowid_buffer()
...
@@ -674,6 +672,8 @@ int DsMrr_impl::dsmrr_fill_rowid_buffer()
if
(
res
&&
res
!=
HA_ERR_END_OF_FILE
)
if
(
res
&&
res
!=
HA_ERR_END_OF_FILE
)
DBUG_RETURN
(
res
);
DBUG_RETURN
(
res
);
if
(
!
do_sort_keys
)
dsmrr_eof
=
test
(
res
==
HA_ERR_END_OF_FILE
);
dsmrr_eof
=
test
(
res
==
HA_ERR_END_OF_FILE
);
/* Sort the buffer contents by rowid */
/* Sort the buffer contents by rowid */
...
@@ -830,6 +830,10 @@ void DsMrr_impl::setup_buffer_sizes(key_range *sample_key)
...
@@ -830,6 +830,10 @@ void DsMrr_impl::setup_buffer_sizes(key_range *sample_key)
dsmrr_eof is set to indicate whether we've exhausted the list of ranges
dsmrr_eof is set to indicate whether we've exhausted the list of ranges
we're scanning.
we're scanning.
post-condition:
- key buffer is non-empty
- key buffer is empty and source range sequence is exhausted
*/
*/
void
DsMrr_impl
::
dsmrr_fill_key_buffer
()
void
DsMrr_impl
::
dsmrr_fill_key_buffer
()
...
@@ -838,12 +842,16 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
...
@@ -838,12 +842,16 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
KEY_MULTI_RANGE
cur_range
;
KEY_MULTI_RANGE
cur_range
;
DBUG_ENTER
(
"DsMrr_impl::dsmrr_fill_key_buffer"
);
DBUG_ENTER
(
"DsMrr_impl::dsmrr_fill_key_buffer"
);
// reset the buffer for writing.
DBUG_ASSERT
(
!
key_tuple_length
||
key_buffer
.
is_empty
());
if
(
key_tuple_length
)
if
(
key_tuple_length
)
{
{
if
(
do_rowid_fetch
)
if
(
do_rowid_fetch
&&
rowid_buffer
.
is_empty
()
)
{
{
/* Restore original buffer sizes */
/*
We're using two buffers and both of them are empty now. Restore the
original sizes
*/
rowid_buffer
.
set_buffer_space
(
full_buf
,
rowid_buffer_end
,
1
);
rowid_buffer
.
set_buffer_space
(
full_buf
,
rowid_buffer_end
,
1
);
key_buffer
.
set_buffer_space
(
rowid_buffer_end
,
full_buf_end
,
-
1
);
key_buffer
.
set_buffer_space
(
rowid_buffer_end
,
full_buf_end
,
-
1
);
}
}
...
@@ -858,7 +866,6 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
...
@@ -858,7 +866,6 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
if
(
!
key_tuple_length
)
if
(
!
key_tuple_length
)
{
{
/* This only happens when we've just started filling the buffer */
/* This only happens when we've just started filling the buffer */
//DBUG_ASSERT(key_buffer.used_size() == 0);
setup_buffer_sizes
(
&
cur_range
.
start_key
);
setup_buffer_sizes
(
&
cur_range
.
start_key
);
}
}
...
@@ -991,21 +998,21 @@ check_record:
...
@@ -991,21 +998,21 @@ check_record:
}
}
/* First, make sure we have a range at start of the buffer */
/* First, make sure we have a range at start of the buffer */
if
(
key_buffer
.
is_empty
())
//psergey-todo: why would we re-fill it here in the case when
// we're doing rowid retrieval?
// - need to check if this is really happening.
if
(
!
key_buffer
.
have_data
(
key_buff_elem_size
))
{
{
if
(
dsmrr_eof
)
if
(
dsmrr_eof
)
{
{
res
=
HA_ERR_END_OF_FILE
;
res
=
HA_ERR_END_OF_FILE
;
goto
end
;
goto
end
;
}
}
/*
When rowid fetching is used, it controls all buffer refills. When we're
on our own, try refilling our buffer.
*/
if
(
!
do_rowid_fetch
)
if
(
!
do_rowid_fetch
)
dsmrr_fill_key_buffer
();
dsmrr_fill_key_buffer
();
if
(
!
key_buffer
.
have_data
(
key_buff_elem_size
))
if
(
key_buffer
.
is_empty
())
{
{
res
=
HA_ERR_END_OF_FILE
;
res
=
HA_ERR_END_OF_FILE
;
goto
end
;
goto
end
;
...
@@ -1015,16 +1022,16 @@ check_record:
...
@@ -1015,16 +1022,16 @@ check_record:
if
(
do_rowid_fetch
)
if
(
do_rowid_fetch
)
{
{
/*
/*
At this point we're not using anything beyond what we've read from key
At this point we're not using anything what we've read from key
buffer. Shrik the key buffer and grow the rowid buffer.
buffer. Cut off unused key buffer space and give it to the rowid
buffer.
*/
*/
uchar
*
unused_start
;
uchar
*
unused_start
,
*
unused_end
;
uchar
*
unused_end
;
key_buffer
.
remove_unused_space
(
&
unused_start
,
&
unused_end
);
key_buffer
.
remove_unused_space
(
&
unused_start
,
&
unused_end
);
rowid_buffer
.
grow
(
unused_start
,
unused_end
);
rowid_buffer
.
grow
(
unused_start
,
unused_end
);
}
}
/* Get the next range to scan*/
/* Get the next range to scan
*/
cur_index_tuple
=
key_in_buf
=
key_buffer
.
read
(
key_size_in_keybuf
);
cur_index_tuple
=
key_in_buf
=
key_buffer
.
read
(
key_size_in_keybuf
);
if
(
use_key_pointers
)
if
(
use_key_pointers
)
cur_index_tuple
=
*
((
uchar
**
)
cur_index_tuple
);
cur_index_tuple
=
*
((
uchar
**
)
cur_index_tuple
);
...
@@ -1119,20 +1126,41 @@ int DsMrr_impl::dsmrr_next(char **range_info)
...
@@ -1119,20 +1126,41 @@ int DsMrr_impl::dsmrr_next(char **range_info)
while
(
1
)
while
(
1
)
{
{
if
(
!
rowid_buffer
.
have_data
(
1
))
if
(
rowid_buffer
.
is_empty
())
{
if
(
do_sort_keys
)
{
if
(
!
key_buffer
.
is_empty
()
||
in_index_range
)
{
/* There are some sorted keys left. Use them to get rowids */
if
((
res
=
dsmrr_fill_rowid_buffer
()))
return
res
;
/* for fatal errors */
}
if
(
rowid_buffer
.
is_empty
())
{
{
if
(
dsmrr_eof
)
if
(
dsmrr_eof
)
return
HA_ERR_END_OF_FILE
;
return
HA_ERR_END_OF_FILE
;
if
(
do_sort_keys
&&
key_buffer
.
used_size
()
==
0
)
dsmrr_fill_key_buffer
();
dsmrr_fill_key_buffer
();
if
((
res
=
dsmrr_fill_rowid_buffer
()))
return
res
;
}
}
else
{
/*
There is no buffer with sorted keys. If fill_rowid_buffer() haven't
reached eof condition before, try refilling the buffer.
*/
if
(
dsmrr_eof
)
return
HA_ERR_END_OF_FILE
;
if
((
res
=
dsmrr_fill_rowid_buffer
()))
if
((
res
=
dsmrr_fill_rowid_buffer
()))
return
res
;
return
res
;
}
}
}
/* Return eof if there are no rowids in the buffer after re-fill attempt */
/* Return eof if there are no rowids in the buffer after re-fill attempt */
if
(
!
rowid_buffer
.
have_data
(
1
))
if
(
rowid_buffer
.
is_empty
(
))
return
HA_ERR_END_OF_FILE
;
return
HA_ERR_END_OF_FILE
;
rowid
=
rowid_buffer
.
read
(
h
->
ref_length
);
rowid
=
rowid_buffer
.
read
(
h
->
ref_length
);
...
@@ -1145,10 +1173,6 @@ int DsMrr_impl::dsmrr_next(char **range_info)
...
@@ -1145,10 +1173,6 @@ int DsMrr_impl::dsmrr_next(char **range_info)
memcpy
(
range_info
,
range_id
,
sizeof
(
uchar
*
));
memcpy
(
range_info
,
range_id
,
sizeof
(
uchar
*
));
}
}
//psergey2-note: the below isn't right- we won't want to skip over this
// rowid because this (rowid, range_id) pair has nothing.. the next
// identical rowids might have something.. (but we set identicals later,
// dont we?)
if
(
h2
->
mrr_funcs
.
skip_record
&&
if
(
h2
->
mrr_funcs
.
skip_record
&&
h2
->
mrr_funcs
.
skip_record
(
h2
->
mrr_iter
,
(
char
*
)
cur_range_info
,
rowid
))
h2
->
mrr_funcs
.
skip_record
(
h2
->
mrr_iter
,
(
char
*
)
cur_range_info
,
rowid
))
continue
;
continue
;
...
...
sql/multi_range_read.h
View file @
c964cb1b
...
@@ -75,6 +75,7 @@ public:
...
@@ -75,6 +75,7 @@ public:
uchar
*
used_area
()
{
return
(
direction
==
1
)
?
read_pos
:
write_pos
;
}
uchar
*
used_area
()
{
return
(
direction
==
1
)
?
read_pos
:
write_pos
;
}
size_t
used_size
();
size_t
used_size
();
bool
is_empty
()
{
return
used_size
()
==
0
;
}
/* Read-mode functions */
/* Read-mode functions */
void
reset_for_reading
();
void
reset_for_reading
();
...
@@ -278,6 +279,13 @@ private:
...
@@ -278,6 +279,13 @@ private:
bool
dsmrr_eof
;
/* TRUE <=> We have reached EOF when reading index tuples */
bool
dsmrr_eof
;
/* TRUE <=> We have reached EOF when reading index tuples */
/*
TRUE <=> key buffer is exhausted (we need this because we may have a situation
where we've read everything from the key buffer but haven't finished with
scanning the last range)
*/
bool
key_eof
;
/* TRUE <=> need range association, buffer holds {rowid, range_id} pairs */
/* TRUE <=> need range association, buffer holds {rowid, range_id} pairs */
bool
is_mrr_assoc
;
bool
is_mrr_assoc
;
...
...
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