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
1c61a92b
Commit
1c61a92b
authored
Nov 19, 2003
by
sergefp@mysql.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
index_merge implementation using Unique class, to be merged into 5.0
parent
0466c250
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1108 additions
and
177 deletions
+1108
-177
BitKeeper/etc/logging_ok
BitKeeper/etc/logging_ok
+1
-0
sql/filesort.cc
sql/filesort.cc
+40
-15
sql/opt_ft.cc
sql/opt_ft.cc
+1
-1
sql/opt_ft.h
sql/opt_ft.h
+6
-5
sql/opt_range.cc
sql/opt_range.cc
+777
-104
sql/opt_range.h
sql/opt_range.h
+112
-18
sql/records.cc
sql/records.cc
+2
-1
sql/sql_class.cc
sql/sql_class.cc
+2
-2
sql/sql_list.h
sql/sql_list.h
+7
-0
sql/sql_select.cc
sql/sql_select.cc
+88
-20
sql/sql_select.h
sql/sql_select.h
+6
-2
sql/sql_test.cc
sql/sql_test.cc
+31
-1
sql/sql_union.cc
sql/sql_union.cc
+3
-2
sql/sql_update.cc
sql/sql_update.cc
+32
-6
No files found.
BitKeeper/etc/logging_ok
View file @
1c61a92b
...
@@ -110,6 +110,7 @@ serg@serg.mylan
...
@@ -110,6 +110,7 @@ serg@serg.mylan
serg@serg.mysql.com
serg@serg.mysql.com
serg@sergbook.mylan
serg@sergbook.mylan
serg@sergbook.mysql.com
serg@sergbook.mysql.com
sergefp@mysql.com
sinisa@rhols221.adsl.netsonic.fi
sinisa@rhols221.adsl.netsonic.fi
tfr@beta.frontier86.ee
tfr@beta.frontier86.ee
tfr@indrek.tfr.cafe.ee
tfr@indrek.tfr.cafe.ee
...
...
sql/filesort.cc
View file @
1c61a92b
...
@@ -49,7 +49,8 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer,
...
@@ -49,7 +49,8 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer,
BUFFPEK
*
buffpek
,
BUFFPEK
*
buffpek
,
uint
maxbuffer
,
IO_CACHE
*
tempfile
,
uint
maxbuffer
,
IO_CACHE
*
tempfile
,
IO_CACHE
*
outfile
);
IO_CACHE
*
outfile
);
static
bool
save_index
(
SORTPARAM
*
param
,
uchar
**
sort_keys
,
uint
count
);
static
bool
save_index
(
SORTPARAM
*
param
,
uchar
**
sort_keys
,
uint
count
,
FILESORT_INFO
*
table_sort
);
static
uint
sortlength
(
SORT_FIELD
*
sortorder
,
uint
s_length
,
static
uint
sortlength
(
SORT_FIELD
*
sortorder
,
uint
s_length
,
bool
*
multi_byte_charset
);
bool
*
multi_byte_charset
);
static
SORT_ADDON_FIELD
*
get_addon_fields
(
THD
*
thd
,
Field
**
ptabfield
,
static
SORT_ADDON_FIELD
*
get_addon_fields
(
THD
*
thd
,
Field
**
ptabfield
,
...
@@ -86,7 +87,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
...
@@ -86,7 +87,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
#ifdef SKIP_DBUG_IN_FILESORT
#ifdef SKIP_DBUG_IN_FILESORT
DBUG_PUSH
(
""
);
/* No DBUG here */
DBUG_PUSH
(
""
);
/* No DBUG here */
#endif
#endif
FILESORT_INFO
table_sort
;
bzero
(
&
table_sort
,
sizeof
(
FILESORT_INFO
));
outfile
=
table
->
sort
.
io_cache
;
outfile
=
table
->
sort
.
io_cache
;
my_b_clear
(
&
tempfile
);
my_b_clear
(
&
tempfile
);
my_b_clear
(
&
buffpek_pointers
);
my_b_clear
(
&
buffpek_pointers
);
...
@@ -108,14 +111,15 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
...
@@ -108,14 +111,15 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
param
.
sort_length
,
param
.
sort_length
,
&
param
.
addon_length
);
&
param
.
addon_length
);
}
}
table
->
sort
.
addon_buf
=
0
;
table
->
sort
.
addon_length
=
param
.
addon_length
;
table_sort
.
addon_buf
=
0
;
table
->
sort
.
addon_field
=
param
.
addon_field
;
table_sort
.
addon_length
=
param
.
addon_length
;
table
->
sort
.
unpack
=
unpack_addon_fields
;
table_sort
.
addon_field
=
param
.
addon_field
;
table_sort
.
unpack
=
unpack_addon_fields
;
if
(
param
.
addon_field
)
if
(
param
.
addon_field
)
{
{
param
.
res_length
=
param
.
addon_length
;
param
.
res_length
=
param
.
addon_length
;
if
(
!
(
table
->
sort
.
addon_buf
=
(
byte
*
)
my_malloc
(
param
.
addon_length
,
if
(
!
(
table
_
sort
.
addon_buf
=
(
byte
*
)
my_malloc
(
param
.
addon_length
,
MYF
(
MY_WME
))))
MYF
(
MY_WME
))))
goto
err
;
goto
err
;
}
}
...
@@ -194,7 +198,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
...
@@ -194,7 +198,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if
(
maxbuffer
==
0
)
// The whole set is in memory
if
(
maxbuffer
==
0
)
// The whole set is in memory
{
{
if
(
save_index
(
&
param
,
sort_keys
,(
uint
)
records
))
if
(
save_index
(
&
param
,
sort_keys
,(
uint
)
records
,
&
table_sort
))
goto
err
;
goto
err
;
}
}
else
else
...
@@ -257,6 +261,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
...
@@ -257,6 +261,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
#ifdef SKIP_DBUG_IN_FILESORT
#ifdef SKIP_DBUG_IN_FILESORT
DBUG_POP
();
/* Ok to DBUG */
DBUG_POP
();
/* Ok to DBUG */
#endif
#endif
memcpy
(
&
table
->
sort
,
&
table_sort
,
sizeof
(
FILESORT_INFO
));
table
->
sort
.
io_cache
=
outfile
;
DBUG_PRINT
(
"exit"
,(
"records: %ld"
,
records
));
DBUG_PRINT
(
"exit"
,(
"records: %ld"
,
records
));
DBUG_RETURN
(
error
?
HA_POS_ERROR
:
records
);
DBUG_RETURN
(
error
?
HA_POS_ERROR
:
records
);
}
/* filesort */
}
/* filesort */
...
@@ -360,12 +366,24 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
...
@@ -360,12 +366,24 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
current_thd
->
variables
.
read_buff_size
);
current_thd
->
variables
.
read_buff_size
);
}
}
READ_RECORD
read_record_info
;
if
(
quick_select
)
{
if
(
select
->
quick
->
reset
())
DBUG_RETURN
(
HA_POS_ERROR
);
init_read_record
(
&
read_record_info
,
current_thd
,
select
->
quick
->
head
,
select
,
1
,
1
);
}
for
(;;)
for
(;;)
{
{
if
(
quick_select
)
if
(
quick_select
)
{
{
if
((
error
=
select
->
quick
->
get_next
()))
if
((
error
=
read_record_info
.
read_record
(
&
read_record_info
)))
break
;
{
error
=
HA_ERR_END_OF_FILE
;
break
;
}
file
->
position
(
sort_form
->
record
[
0
]);
file
->
position
(
sort_form
->
record
[
0
]);
}
}
else
/* Not quick-select */
else
/* Not quick-select */
...
@@ -393,6 +411,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
...
@@ -393,6 +411,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
if
(
error
&&
error
!=
HA_ERR_RECORD_DELETED
)
if
(
error
&&
error
!=
HA_ERR_RECORD_DELETED
)
break
;
break
;
}
}
if
(
*
killed
)
if
(
*
killed
)
{
{
DBUG_PRINT
(
"info"
,(
"Sort killed by user"
));
DBUG_PRINT
(
"info"
,(
"Sort killed by user"
));
...
@@ -426,8 +445,14 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
...
@@ -426,8 +445,14 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
else
else
file
->
unlock_row
();
file
->
unlock_row
();
}
}
(
void
)
file
->
extra
(
HA_EXTRA_NO_CACHE
);
/* End cacheing of records */
if
(
quick_select
)
file
->
rnd_end
();
end_read_record
(
&
read_record_info
);
else
{
(
void
)
file
->
extra
(
HA_EXTRA_NO_CACHE
);
/* End cacheing of records */
file
->
rnd_end
();
}
DBUG_PRINT
(
"test"
,(
"error: %d indexpos: %d"
,
error
,
indexpos
));
DBUG_PRINT
(
"test"
,(
"error: %d indexpos: %d"
,
error
,
indexpos
));
if
(
error
!=
HA_ERR_END_OF_FILE
)
if
(
error
!=
HA_ERR_END_OF_FILE
)
{
{
...
@@ -665,8 +690,8 @@ static void make_sortkey(register SORTPARAM *param,
...
@@ -665,8 +690,8 @@ static void make_sortkey(register SORTPARAM *param,
return
;
return
;
}
}
static
bool
save_index
(
SORTPARAM
*
param
,
uchar
**
sort_keys
,
uint
count
,
static
bool
save_index
(
SORTPARAM
*
param
,
uchar
**
sort_keys
,
uint
coun
t
)
FILESORT_INFO
*
table_sor
t
)
{
{
uint
offset
,
res_length
;
uint
offset
,
res_length
;
byte
*
to
;
byte
*
to
;
...
@@ -677,7 +702,7 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count)
...
@@ -677,7 +702,7 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count)
offset
=
param
->
rec_length
-
res_length
;
offset
=
param
->
rec_length
-
res_length
;
if
((
ha_rows
)
count
>
param
->
max_rows
)
if
((
ha_rows
)
count
>
param
->
max_rows
)
count
=
(
uint
)
param
->
max_rows
;
count
=
(
uint
)
param
->
max_rows
;
if
(
!
(
to
=
param
->
sort_form
->
sort
.
record_pointers
=
if
(
!
(
to
=
table_sort
->
record_pointers
=
(
byte
*
)
my_malloc
(
res_length
*
count
,
MYF
(
MY_WME
))))
(
byte
*
)
my_malloc
(
res_length
*
count
,
MYF
(
MY_WME
))))
DBUG_RETURN
(
1
);
/* purecov: inspected */
DBUG_RETURN
(
1
);
/* purecov: inspected */
for
(
uchar
**
end
=
sort_keys
+
count
;
sort_keys
!=
end
;
sort_keys
++
)
for
(
uchar
**
end
=
sort_keys
+
count
;
sort_keys
!=
end
;
sort_keys
++
)
...
...
sql/opt_ft.cc
View file @
1c61a92b
...
@@ -26,7 +26,7 @@
...
@@ -26,7 +26,7 @@
** Create a FT or QUICK RANGE based on a key
** Create a FT or QUICK RANGE based on a key
****************************************************************************/
****************************************************************************/
QUICK_SELECT
*
get_ft_or_quick_select_for_ref
(
TABLE
*
table
,
JOIN_TAB
*
tab
)
QUICK_
RANGE_
SELECT
*
get_ft_or_quick_select_for_ref
(
TABLE
*
table
,
JOIN_TAB
*
tab
)
{
{
if
(
tab
->
type
==
JT_FT
)
if
(
tab
->
type
==
JT_FT
)
return
new
FT_SELECT
(
table
,
&
tab
->
ref
);
return
new
FT_SELECT
(
table
,
&
tab
->
ref
);
...
...
sql/opt_ft.h
View file @
1c61a92b
...
@@ -24,17 +24,18 @@
...
@@ -24,17 +24,18 @@
#pragma interface
/* gcc class implementation */
#pragma interface
/* gcc class implementation */
#endif
#endif
class
FT_SELECT
:
public
QUICK_SELECT
{
class
FT_SELECT
:
public
QUICK_
RANGE_
SELECT
{
public:
public:
TABLE_REF
*
ref
;
TABLE_REF
*
ref
;
FT_SELECT
(
TABLE
*
table
,
TABLE_REF
*
tref
)
:
FT_SELECT
(
TABLE
*
table
,
TABLE_REF
*
tref
)
:
QUICK_SELECT
(
table
,
tref
->
key
,
1
),
ref
(
tref
)
{
init
();
}
QUICK_
RANGE_
SELECT
(
table
,
tref
->
key
,
1
),
ref
(
tref
)
{
init
();
}
int
init
()
{
return
error
=
file
->
ft_init
(
);
}
int
init
()
{
QUICK_RANGE_SELECT
::
init
();
return
(
error
=
file
->
ft_init
()
);
}
int
get_next
()
{
return
error
=
file
->
ft_read
(
record
);
}
int
get_next
()
{
return
error
=
file
->
ft_read
(
record
);
}
int
get_type
()
{
return
QS_TYPE_FULLTEXT
;
}
};
};
QUICK_SELECT
*
get_ft_or_quick_select_for_ref
(
TABLE
*
table
,
JOIN_TAB
*
tab
);
QUICK_
RANGE_
SELECT
*
get_ft_or_quick_select_for_ref
(
TABLE
*
table
,
JOIN_TAB
*
tab
);
#endif
#endif
sql/opt_range.cc
View file @
1c61a92b
...
@@ -267,14 +267,17 @@ public:
...
@@ -267,14 +267,17 @@ public:
SEL_ARG
*
clone_tree
();
SEL_ARG
*
clone_tree
();
};
};
class
SEL_IMERGE
;
class
SEL_TREE
:
public
Sql_alloc
class
SEL_TREE
:
public
Sql_alloc
{
{
public:
public:
enum
Type
{
IMPOSSIBLE
,
ALWAYS
,
MAYBE
,
KEY
,
KEY_SMALLER
}
type
;
enum
Type
{
IMPOSSIBLE
,
ALWAYS
,
MAYBE
,
KEY
,
KEY_SMALLER
}
type
;
SEL_TREE
(
enum
Type
type_arg
)
:
type
(
type_arg
)
{}
SEL_TREE
(
enum
Type
type_arg
)
:
type
(
type_arg
)
{}
SEL_TREE
()
:
type
(
KEY
)
{
bzero
((
char
*
)
keys
,
sizeof
(
keys
));}
SEL_TREE
()
:
type
(
KEY
)
,
keys_map
(
0
)
{
bzero
((
char
*
)
keys
,
sizeof
(
keys
));}
SEL_ARG
*
keys
[
MAX_KEY
];
SEL_ARG
*
keys
[
MAX_KEY
];
key_map
keys_map
;
/* bitmask of non-NULL elements in keys */
List
<
SEL_IMERGE
>
merges
;
/* possible ways to read rows using index_merge */
};
};
...
@@ -301,10 +304,19 @@ static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
...
@@ -301,10 +304,19 @@ static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
char
*
min_key
,
uint
min_key_flag
,
char
*
min_key
,
uint
min_key_flag
,
char
*
max_key
,
uint
max_key_flag
);
char
*
max_key
,
uint
max_key_flag
);
static
QUICK_SELECT
*
get_quick_select
(
PARAM
*
param
,
uint
index
,
QUICK_RANGE_SELECT
*
get_quick_select
(
PARAM
*
param
,
uint
index
,
SEL_ARG
*
key_tree
);
SEL_ARG
*
key_tree
,
MEM_ROOT
*
alloc
=
NULL
);
static
int
get_quick_select_params
(
SEL_TREE
*
tree
,
PARAM
&
param
,
key_map
&
needed_reg
,
TABLE
*
head
,
bool
index_read_can_be_used
,
double
*
read_time
,
ha_rows
*
records
,
SEL_ARG
***
key_to_read
);
#ifndef DBUG_OFF
#ifndef DBUG_OFF
static
void
print_quick
(
QUICK_SELECT
*
quick
,
key_map
needed_reg
);
void
print_quick_sel_imerge
(
QUICK_INDEX_MERGE_SELECT
*
quick
,
key_map
needed_reg
);
void
print_quick_sel_range
(
QUICK_RANGE_SELECT
*
quick
,
key_map
needed_reg
);
#endif
#endif
static
SEL_TREE
*
tree_and
(
PARAM
*
param
,
SEL_TREE
*
tree1
,
SEL_TREE
*
tree2
);
static
SEL_TREE
*
tree_and
(
PARAM
*
param
,
SEL_TREE
*
tree1
,
SEL_TREE
*
tree2
);
static
SEL_TREE
*
tree_or
(
PARAM
*
param
,
SEL_TREE
*
tree1
,
SEL_TREE
*
tree2
);
static
SEL_TREE
*
tree_or
(
PARAM
*
param
,
SEL_TREE
*
tree1
,
SEL_TREE
*
tree2
);
...
@@ -312,16 +324,234 @@ static SEL_ARG *sel_add(SEL_ARG *key1,SEL_ARG *key2);
...
@@ -312,16 +324,234 @@ static SEL_ARG *sel_add(SEL_ARG *key1,SEL_ARG *key2);
static
SEL_ARG
*
key_or
(
SEL_ARG
*
key1
,
SEL_ARG
*
key2
);
static
SEL_ARG
*
key_or
(
SEL_ARG
*
key1
,
SEL_ARG
*
key2
);
static
SEL_ARG
*
key_and
(
SEL_ARG
*
key1
,
SEL_ARG
*
key2
,
uint
clone_flag
);
static
SEL_ARG
*
key_and
(
SEL_ARG
*
key1
,
SEL_ARG
*
key2
,
uint
clone_flag
);
static
bool
get_range
(
SEL_ARG
**
e1
,
SEL_ARG
**
e2
,
SEL_ARG
*
root1
);
static
bool
get_range
(
SEL_ARG
**
e1
,
SEL_ARG
**
e2
,
SEL_ARG
*
root1
);
static
bool
get_quick_keys
(
PARAM
*
param
,
QUICK
_SELECT
*
quick
,
KEY_PART
*
key
,
bool
get_quick_keys
(
PARAM
*
param
,
QUICK_RANGE
_SELECT
*
quick
,
KEY_PART
*
key
,
SEL_ARG
*
key_tree
,
char
*
min_key
,
uint
min_key_flag
,
SEL_ARG
*
key_tree
,
char
*
min_key
,
uint
min_key_flag
,
char
*
max_key
,
uint
max_key_flag
);
char
*
max_key
,
uint
max_key_flag
);
static
bool
eq_tree
(
SEL_ARG
*
a
,
SEL_ARG
*
b
);
static
bool
eq_tree
(
SEL_ARG
*
a
,
SEL_ARG
*
b
);
static
SEL_ARG
null_element
(
SEL_ARG
::
IMPOSSIBLE
);
static
SEL_ARG
null_element
(
SEL_ARG
::
IMPOSSIBLE
);
static
bool
null_part_in_key
(
KEY_PART
*
key_part
,
const
char
*
key
,
uint
length
);
static
bool
null_part_in_key
(
KEY_PART
*
key_part
,
const
char
*
key
,
uint
length
);
bool
sel_trees_can_be_ored
(
SEL_TREE
*
tree1
,
SEL_TREE
*
tree2
,
PARAM
*
param
);
/*
SEL_IMERGE is a list of possible ways to do index merge, i.e. it is
a condition in the following form:
(t_1||t_2||...||t_N) && (next)
where all t_i are SEL_TREEs, next is another SEL_IMERGE and no pair
(t_i,t_j) contains SEL_ARGS for the same index.
SEL_TREE contained in SEL_IMERGE always has merges=NULL.
This class relies on memory manager to do the cleanup.
*/
class
SEL_IMERGE
:
public
Sql_alloc
{
enum
{
PREALLOCED_TREES
=
10
};
public:
SEL_TREE
*
trees_prealloced
[
PREALLOCED_TREES
];
SEL_TREE
**
trees
;
/* trees used to do index_merge */
SEL_TREE
**
trees_next
;
/* last of these trees */
SEL_TREE
**
trees_end
;
/* end of allocated space */
SEL_ARG
***
best_keys
;
/* best keys to read in SEL_TREEs */
SEL_IMERGE
()
:
trees
(
&
trees_prealloced
[
0
]),
trees_next
(
trees
),
trees_end
(
trees
+
PREALLOCED_TREES
)
{}
int
or_sel_tree
(
PARAM
*
param
,
SEL_TREE
*
tree
);
int
or_sel_tree_with_checks
(
PARAM
*
param
,
SEL_TREE
*
new_tree
);
int
or_sel_imerge_with_checks
(
PARAM
*
param
,
SEL_IMERGE
*
imerge
);
};
/*
Add SEL_TREE to this index_merge without any checks,
NOTES
This function implements the following:
(x_1||...||x_N) || t = (x_1||...||x_N||t), where x_i, t are SEL_TREEs
RETURN
0 - OK
-1 - Out of memory.
*/
int
SEL_IMERGE
::
or_sel_tree
(
PARAM
*
param
,
SEL_TREE
*
tree
)
{
if
(
trees_next
==
trees_end
)
{
const
int
realloc_ratio
=
2
;
/* Double size for next round */
uint
old_elements
=
(
trees_end
-
trees
);
uint
old_size
=
sizeof
(
SEL_TREE
**
)
*
old_elements
;
uint
new_size
=
old_size
*
realloc_ratio
;
SEL_TREE
**
new_trees
;
if
(
!
(
new_trees
=
(
SEL_TREE
**
)
alloc_root
(
param
->
mem_root
,
new_size
)))
return
-
1
;
memcpy
(
new_trees
,
trees
,
old_size
);
trees
=
new_trees
;
trees_next
=
trees
+
old_elements
;
trees_end
=
trees
+
old_elements
*
realloc_ratio
;
}
*
(
trees_next
++
)
=
tree
;
return
0
;
}
/*
Perform OR operation on this SEL_IMERGE and supplied SEL_TREE new_tree,
combining new_tree with one of the trees in this SEL_IMERGE if they both
have SEL_ARGs for the same key.
SYNOPSIS
or_sel_tree_with_checks()
param PARAM from SQL_SELECT::test_quick_select
new_tree SEL_TREE with type KEY or KEY_SMALLER.
NOTES
This does the following:
(t_1||...||t_k)||new_tree =
either
= (t_1||...||t_k||new_tree)
or
= (t_1||....||(t_j|| new_tree)||...||t_k),
where t_i, y are SEL_TREEs.
new_tree is combined with the first t_j it has a SEL_ARG on common
key with. As a consequence of this, choice of keys to do index_merge
read may depend on the order of conditions in WHERE part of the query.
RETURN
0 OK
1 One of the trees was combined with new_tree to SEL_TREE::ALWAYS,
and (*this) should be discarded.
-1 An error occurred.
*/
int
SEL_IMERGE
::
or_sel_tree_with_checks
(
PARAM
*
param
,
SEL_TREE
*
new_tree
)
{
for
(
SEL_TREE
**
tree
=
trees
;
tree
!=
trees_next
;
tree
++
)
{
if
(
sel_trees_can_be_ored
(
*
tree
,
new_tree
,
param
))
{
*
tree
=
tree_or
(
param
,
*
tree
,
new_tree
);
if
(
!*
tree
)
return
1
;
if
(((
*
tree
)
->
type
==
SEL_TREE
::
MAYBE
)
||
((
*
tree
)
->
type
==
SEL_TREE
::
ALWAYS
))
return
1
;
/* SEL_TREE::IMPOSSIBLE is impossible here */
return
0
;
}
}
/* new tree cannot be combined with any of existing trees */
return
or_sel_tree
(
param
,
new_tree
);
}
/*
Perform OR operation on this index_merge and supplied index_merge list.
RETURN
0 - OK
1 - One of conditions in result is always TRUE and this SEL_IMERGE
should be discarded.
-1 - An error occurred
*/
int
SEL_IMERGE
::
or_sel_imerge_with_checks
(
PARAM
*
param
,
SEL_IMERGE
*
imerge
)
{
for
(
SEL_TREE
**
tree
=
imerge
->
trees
;
tree
!=
imerge
->
trees_next
;
tree
++
)
{
if
(
or_sel_tree_with_checks
(
param
,
*
tree
))
return
1
;
}
return
0
;
}
/*
Perform AND operation on two index_merge lists, storing result in *im1.
*/
inline
void
imerge_list_and_list
(
List
<
SEL_IMERGE
>
*
im1
,
List
<
SEL_IMERGE
>
*
im2
)
{
im1
->
concat
(
im2
);
}
/*
Perform OR operation on 2 index_merge lists, storing result in first list.
NOTES
The following conversion is implemented:
(a_1 &&...&& a_N)||(b_1 &&...&& b_K) = AND_i,j(a_i || b_j) =>
=> (a_1||b_1).
i.e. all conjuncts except the first one are currently dropped.
This is done to avoid producing N*K ways to do index_merge.
If (a_1||b_1) produce a condition that is always true, NULL is
returned and index_merge is discarded. (while it is actually
possible to try harder).
As a consequence of this, choice of keys to do index_merge
read may depend on the order of conditions in WHERE part of
the query.
RETURN
0 OK, result is stored in *im1
other Error, both passed lists are unusable
*/
int
imerge_list_or_list
(
PARAM
*
param
,
List
<
SEL_IMERGE
>
*
im1
,
List
<
SEL_IMERGE
>
*
im2
)
{
SEL_IMERGE
*
imerge
=
im1
->
head
();
im1
->
empty
();
im1
->
push_back
(
imerge
);
return
imerge
->
or_sel_imerge_with_checks
(
param
,
im2
->
head
());
}
/*
Perform OR operation on index_merge list and key tree.
RETURN
0 OK, result is stored in *im1
other Error
*/
int
imerge_list_or_tree
(
PARAM
*
param
,
List
<
SEL_IMERGE
>
*
im1
,
SEL_TREE
*
tree
)
{
SEL_IMERGE
*
imerge
;
List_iterator
<
SEL_IMERGE
>
it
(
*
im1
);
while
((
imerge
=
it
++
))
{
if
(
imerge
->
or_sel_tree_with_checks
(
param
,
tree
))
it
.
remove
();
}
return
im1
->
is_empty
();
}
/***************************************************************************
/***************************************************************************
** Basic functions for SQL_SELECT and QUICK_SELECT
** Basic functions for SQL_SELECT and QUICK_
RANGE_
SELECT
***************************************************************************/
***************************************************************************/
/* make a select from mysql info
/* make a select from mysql info
...
@@ -378,23 +608,34 @@ SQL_SELECT::~SQL_SELECT()
...
@@ -378,23 +608,34 @@ SQL_SELECT::~SQL_SELECT()
#undef index // Fix for Unixware 7
#undef index // Fix for Unixware 7
QUICK_SELECT
::
QUICK_SELECT
(
TABLE
*
table
,
uint
key_nr
,
bool
no_alloc
)
QUICK_SELECT_I
::
QUICK_SELECT_I
()
:
dont_free
(
0
),
error
(
0
),
index
(
key_nr
),
max_used_key_length
(
0
),
:
max_used_key_length
(
0
),
used_key_parts
(
0
),
head
(
table
),
it
(
ranges
),
range
(
0
)
used_key_parts
(
0
)
{}
QUICK_RANGE_SELECT
::
QUICK_RANGE_SELECT
(
TABLE
*
table
,
uint
key_nr
,
bool
no_alloc
,
MEM_ROOT
*
parent_alloc
)
:
dont_free
(
0
),
error
(
0
),
it
(
ranges
),
range
(
0
)
{
{
if
(
!
no_alloc
)
index
=
key_nr
;
head
=
table
;
if
(
!
no_alloc
&&
!
parent_alloc
)
{
{
init_sql_alloc
(
&
alloc
,
1024
,
0
);
// Allocates everything here
init_sql_alloc
(
&
alloc
,
1024
,
0
);
// Allocates everything here
my_pthread_setspecific_ptr
(
THR_MALLOC
,
&
alloc
);
my_pthread_setspecific_ptr
(
THR_MALLOC
,
&
alloc
);
}
}
else
else
bzero
((
char
*
)
&
alloc
,
sizeof
(
alloc
));
bzero
((
char
*
)
&
alloc
,
sizeof
(
alloc
));
file
=
head
->
file
;
file
=
head
->
file
;
record
=
head
->
record
[
0
];
record
=
head
->
record
[
0
];
init
();
}
int
QUICK_RANGE_SELECT
::
init
()
{
return
(
error
=
file
->
index_init
(
index
));
}
}
QUICK_
SELECT
::~
QUICK
_SELECT
()
QUICK_
RANGE_SELECT
::~
QUICK_RANGE
_SELECT
()
{
{
if
(
!
dont_free
)
if
(
!
dont_free
)
{
{
...
@@ -403,6 +644,47 @@ QUICK_SELECT::~QUICK_SELECT()
...
@@ -403,6 +644,47 @@ QUICK_SELECT::~QUICK_SELECT()
}
}
}
}
QUICK_INDEX_MERGE_SELECT
::
QUICK_INDEX_MERGE_SELECT
(
THD
*
thd_param
,
TABLE
*
table
)
:
cur_quick_it
(
quick_selects
),
thd
(
thd_param
),
unique
(
NULL
)
{
index
=
MAX_KEY
;
head
=
table
;
reset_called
=
false
;
init_sql_alloc
(
&
alloc
,
1024
,
0
);
}
int
QUICK_INDEX_MERGE_SELECT
::
init
()
{
cur_quick_it
.
rewind
();
cur_quick_select
=
cur_quick_it
++
;
return
cur_quick_select
->
init
();
}
int
QUICK_INDEX_MERGE_SELECT
::
reset
()
{
int
result
;
DBUG_ENTER
(
"QUICK_INDEX_MERGE_SELECT::reset"
);
if
(
reset_called
)
DBUG_RETURN
(
0
);
reset_called
=
true
;
result
=
cur_quick_select
->
reset
()
&&
prepare_unique
();
DBUG_RETURN
(
result
);
}
bool
QUICK_INDEX_MERGE_SELECT
::
push_quick_back
(
QUICK_RANGE_SELECT
*
quick_sel_range
)
{
return
quick_selects
.
push_back
(
quick_sel_range
);
}
QUICK_INDEX_MERGE_SELECT
::~
QUICK_INDEX_MERGE_SELECT
()
{
quick_selects
.
delete_elements
();
free_root
(
&
alloc
,
MYF
(
0
));
}
QUICK_RANGE
::
QUICK_RANGE
()
QUICK_RANGE
::
QUICK_RANGE
()
:
min_key
(
0
),
max_key
(
0
),
min_length
(
0
),
max_length
(
0
),
:
min_key
(
0
),
max_key
(
0
),
min_length
(
0
),
max_length
(
0
),
flag
(
NO_MIN_RANGE
|
NO_MAX_RANGE
)
flag
(
NO_MIN_RANGE
|
NO_MAX_RANGE
)
...
@@ -581,6 +863,8 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
...
@@ -581,6 +863,8 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
uint
basflag
;
uint
basflag
;
uint
idx
;
uint
idx
;
double
scan_time
;
double
scan_time
;
QUICK_INDEX_MERGE_SELECT
*
quick_imerge
=
NULL
;
THD
*
thd
=
current_thd
;
DBUG_ENTER
(
"test_quick_select"
);
DBUG_ENTER
(
"test_quick_select"
);
DBUG_PRINT
(
"enter"
,(
"keys_to_use: %lu prev_tables: %lu const_tables: %lu"
,
DBUG_PRINT
(
"enter"
,(
"keys_to_use: %lu prev_tables: %lu const_tables: %lu"
,
(
ulong
)
keys_to_use
,
(
ulong
)
prev_tables
,
(
ulong
)
keys_to_use
,
(
ulong
)
prev_tables
,
...
@@ -626,13 +910,13 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
...
@@ -626,13 +910,13 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
param
.
keys
=
0
;
param
.
keys
=
0
;
param
.
mem_root
=
&
alloc
;
param
.
mem_root
=
&
alloc
;
current_
thd
->
no_errors
=
1
;
// Don't warn about NULL
thd
->
no_errors
=
1
;
// Don't warn about NULL
init_sql_alloc
(
&
alloc
,
2048
,
0
);
init_sql_alloc
(
&
alloc
,
2048
,
0
);
if
(
!
(
param
.
key_parts
=
(
KEY_PART
*
)
alloc_root
(
&
alloc
,
if
(
!
(
param
.
key_parts
=
(
KEY_PART
*
)
alloc_root
(
&
alloc
,
sizeof
(
KEY_PART
)
*
sizeof
(
KEY_PART
)
*
head
->
key_parts
)))
head
->
key_parts
)))
{
{
current_
thd
->
no_errors
=
0
;
thd
->
no_errors
=
0
;
free_root
(
&
alloc
,
MYF
(
0
));
// Return memory & allocator
free_root
(
&
alloc
,
MYF
(
0
));
// Return memory & allocator
DBUG_RETURN
(
0
);
// Can't use range
DBUG_RETURN
(
0
);
// Can't use range
}
}
...
@@ -673,70 +957,205 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
...
@@ -673,70 +957,205 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
read_time
=
(
double
)
HA_POS_ERROR
;
read_time
=
(
double
)
HA_POS_ERROR
;
}
}
else
if
(
tree
->
type
==
SEL_TREE
::
KEY
||
else
if
(
tree
->
type
==
SEL_TREE
::
KEY
||
tree
->
type
==
SEL_TREE
::
KEY_SMALLER
)
tree
->
type
==
SEL_TREE
::
KEY_SMALLER
)
{
{
SEL_ARG
**
key
,
**
end
,
**
best_key
=
0
;
/*
It is possible to use a quick select (but maybe it would be slower
than 'all' table scan).
for
(
idx
=
0
,
key
=
tree
->
keys
,
end
=
key
+
param
.
keys
;
*/
key
!=
end
;
SEL_ARG
**
best_key
=
0
;
key
++
,
idx
++
)
ha_rows
found_records
;
{
double
found_read_time
=
read_time
;
ha_rows
found_records
;
double
found_read_time
;
if
(
!
get_quick_select_params
(
tree
,
param
,
needed_reg
,
head
,
true
,
if
(
*
key
)
&
found_read_time
,
&
found_records
,
{
&
best_key
))
uint
keynr
=
param
.
real_keynr
[
idx
];
{
if
((
*
key
)
->
type
==
SEL_ARG
::
MAYBE_KEY
||
/*
(
*
key
)
->
maybe_flag
)
Ok, quick select is better than 'all' table scan and we have its
needed_reg
|=
(
key_map
)
1
<<
keynr
;
parameters, so construct it.
*/
found_records
=
check_quick_select
(
&
param
,
idx
,
*
key
);
read_time
=
found_read_time
;
if
(
found_records
!=
HA_POS_ERROR
&&
found_records
>
2
&&
records
=
found_records
;
head
->
used_keys
&
((
table_map
)
1
<<
keynr
)
&&
(
head
->
file
->
index_flags
(
keynr
)
&
HA_KEY_READ_ONLY
))
if
((
quick
=
get_quick_select
(
&
param
,(
uint
)
(
best_key
-
tree
->
keys
),
{
*
best_key
))
&&
(
!
quick
->
init
()))
/*
{
We can resolve this by only reading through this key.
quick
->
records
=
records
;
Assume that we will read trough the whole key range
quick
->
read_time
=
read_time
;
and that all key blocks are half full (normally things are
}
much better).
}
*/
uint
keys_per_block
=
(
head
->
file
->
block_size
/
2
/
/*
(
head
->
key_info
[
keynr
].
key_length
+
btw, tree type SEL_TREE::INDEX_MERGE was not introduced
head
->
file
->
ref_length
)
+
1
);
intentionally
found_read_time
=
((
double
)
(
found_records
+
keys_per_block
-
1
)
/
*/
(
double
)
keys_per_block
);
}
/* if no range select could be built, try using index_merge */
else
if
(
!
quick
&&
!
tree
->
merges
.
is_empty
())
found_read_time
=
(
head
->
file
->
read_time
(
keynr
,
{
param
.
range_count
,
DBUG_PRINT
(
"info"
,(
"No range reads possible,"
found_records
)
+
" trying to construct index_merge"
));
(
double
)
found_records
/
TIME_FOR_COMPARE
);
SEL_IMERGE
*
imerge
;
if
(
read_time
>
found_read_time
)
SEL_IMERGE
*
min_imerge
=
NULL
;
{
double
min_imerge_cost
=
DBL_MAX
;
read_time
=
found_read_time
;
ha_rows
min_imerge_records
;
records
=
found_records
;
best_key
=
key
;
List_iterator_fast
<
SEL_IMERGE
>
it
(
tree
->
merges
);
}
while
((
imerge
=
it
++
))
}
{
}
double
imerge_cost
=
0
;
if
(
best_key
&&
records
)
ha_rows
imerge_total_records
=
0
;
{
double
tree_read_time
;
if
((
quick
=
get_quick_select
(
&
param
,(
uint
)
(
best_key
-
tree
->
keys
),
ha_rows
tree_records
;
*
best_key
)))
imerge
->
best_keys
=
{
(
SEL_ARG
***
)
alloc_root
(
&
alloc
,
quick
->
records
=
records
;
(
imerge
->
trees_next
-
imerge
->
trees
)
*
quick
->
read_time
=
read_time
;
sizeof
(
void
*
));
}
for
(
SEL_TREE
**
ptree
=
imerge
->
trees
;
}
ptree
!=
imerge
->
trees_next
;
ptree
++
)
{
tree_read_time
=
read_time
;
if
(
get_quick_select_params
(
*
ptree
,
param
,
needed_reg
,
head
,
false
,
&
tree_read_time
,
&
tree_records
,
&
(
imerge
->
best_keys
[
ptree
-
imerge
->
trees
])))
goto
imerge_fail
;
imerge_cost
+=
tree_read_time
;
imerge_total_records
+=
tree_records
;
}
imerge_total_records
=
min
(
imerge_total_records
,
head
->
file
->
records
);
imerge_cost
+=
imerge_total_records
/
TIME_FOR_COMPARE
;
if
(
imerge_cost
<
min_imerge_cost
)
{
min_imerge
=
imerge
;
min_imerge_cost
=
imerge_cost
;
min_imerge_records
=
imerge_total_records
;
}
imerge_fail:
;
}
if
(
!
min_imerge
)
goto
end_free
;
records
=
min_imerge_records
;
/* ok, got minimal imerge, *min_imerge, with cost min_imerge_cost */
if
(
head
->
used_keys
)
{
/* check if "ALL" +"using index" read would be faster */
int
key_for_use
=
find_shortest_key
(
head
,
head
->
used_keys
);
ha_rows
total_table_records
=
(
0
==
head
->
file
->
records
)
?
1
:
head
->
file
->
records
;
uint
keys_per_block
=
(
head
->
file
->
block_size
/
2
/
(
head
->
key_info
[
key_for_use
].
key_length
+
head
->
file
->
ref_length
)
+
1
);
double
all_index_scan_read_time
=
((
double
)(
total_table_records
+
keys_per_block
-
1
)
/
(
double
)
keys_per_block
);
DBUG_PRINT
(
"info"
,
(
"'all' scan will be using key %d, read time %g"
,
key_for_use
,
all_index_scan_read_time
));
if
(
all_index_scan_read_time
<
min_imerge_cost
)
{
DBUG_PRINT
(
"info"
,
(
"index merge would be slower, "
"will do full 'index' scan"
));
goto
end_free
;
}
}
else
{
/* check if "ALL" would be faster */
if
(
read_time
<
min_imerge_cost
)
{
DBUG_PRINT
(
"info"
,
(
"index merge would be slower, "
"will do full table scan"
));
goto
end_free
;
}
}
if
(
!
(
quick
=
quick_imerge
=
new
QUICK_INDEX_MERGE_SELECT
(
thd
,
head
)))
goto
end_free
;
quick
->
records
=
min_imerge_records
;
quick
->
read_time
=
min_imerge_cost
;
my_pthread_setspecific_ptr
(
THR_MALLOC
,
&
quick_imerge
->
alloc
);
QUICK_RANGE_SELECT
*
new_quick
;
for
(
SEL_TREE
**
ptree
=
min_imerge
->
trees
;
ptree
!=
min_imerge
->
trees_next
;
ptree
++
)
{
SEL_ARG
**
tree_best_key
=
min_imerge
->
best_keys
[
ptree
-
min_imerge
->
trees
];
if
((
new_quick
=
get_quick_select
(
&
param
,
(
uint
)(
tree_best_key
-
(
*
ptree
)
->
keys
),
*
tree_best_key
,
&
quick_imerge
->
alloc
)))
{
new_quick
->
records
=
min_imerge_records
;
new_quick
->
read_time
=
min_imerge_cost
;
/*
QUICK_RANGE_SELECT::QUICK_RANGE_SELECT leaves THR_MALLOC
pointing to its allocator, restore it back
*/
quick_imerge
->
last_quick_select
=
new_quick
;
if
(
quick_imerge
->
push_quick_back
(
new_quick
))
{
delete
new_quick
;
delete
quick
;
quick
=
quick_imerge
=
NULL
;
goto
end_free
;
}
}
else
{
delete
quick
;
quick
=
quick_imerge
=
NULL
;
goto
end_free
;
}
}
free_root
(
&
alloc
,
MYF
(
0
));
my_pthread_setspecific_ptr
(
THR_MALLOC
,
old_root
);
if
(
quick
->
init
())
{
delete
quick
;
quick
=
quick_imerge
=
NULL
;
DBUG_PRINT
(
"error"
,
(
"Failed to allocate index merge structures,"
"falling back to full scan."
));
}
goto
end
;
}
}
}
}
}
end_free:
free_root
(
&
alloc
,
MYF
(
0
));
// Return memory & allocator
free_root
(
&
alloc
,
MYF
(
0
));
// Return memory & allocator
my_pthread_setspecific_ptr
(
THR_MALLOC
,
old_root
);
my_pthread_setspecific_ptr
(
THR_MALLOC
,
old_root
);
current_thd
->
no_errors
=
0
;
end:
thd
->
no_errors
=
0
;
}
}
DBUG_EXECUTE
(
"info"
,
print_quick
(
quick
,
needed_reg
););
DBUG_EXECUTE
(
"info"
,
{
if
(
quick_imerge
)
print_quick_sel_imerge
(
quick_imerge
,
needed_reg
);
else
print_quick_sel_range
((
QUICK_RANGE_SELECT
*
)
quick
,
needed_reg
);
}
);
/*
/*
Assume that if the user is using 'limit' we will only need to scan
Assume that if the user is using 'limit' we will only need to scan
limit rows if we are using a key
limit rows if we are using a key
...
@@ -744,6 +1163,77 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
...
@@ -744,6 +1163,77 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
DBUG_RETURN
(
records
?
test
(
quick
)
:
-
1
);
DBUG_RETURN
(
records
?
test
(
quick
)
:
-
1
);
}
}
/*
Calculate quick select read time, # of records, and best key to use
without constructing QUICK_SELECT
*/
static
int
get_quick_select_params
(
SEL_TREE
*
tree
,
PARAM
&
param
,
key_map
&
needed_reg
,
TABLE
*
head
,
bool
index_read_can_be_used
,
double
*
read_time
,
ha_rows
*
records
,
SEL_ARG
***
key_to_read
)
{
int
idx
;
int
result
=
1
;
/*
Note that there may be trees that have type SEL_TREE::KEY but contain
no key reads at all. For example, tree for expression "key1 is not null"
where key1 is defined as "not null".
*/
SEL_ARG
**
key
,
**
end
;
for
(
idx
=
0
,
key
=
tree
->
keys
,
end
=
key
+
param
.
keys
;
key
!=
end
;
key
++
,
idx
++
)
{
ha_rows
found_records
;
double
found_read_time
;
if
(
*
key
)
{
uint
keynr
=
param
.
real_keynr
[
idx
];
if
((
*
key
)
->
type
==
SEL_ARG
::
MAYBE_KEY
||
(
*
key
)
->
maybe_flag
)
needed_reg
|=
(
key_map
)
1
<<
keynr
;
key_map
usable_keys
=
index_read_can_be_used
?
(
head
->
used_keys
&
((
key_map
)
1
<<
keynr
))
:
0
;
found_records
=
check_quick_select
(
&
param
,
idx
,
*
key
);
if
(
found_records
!=
HA_POS_ERROR
&&
found_records
>
2
&&
usable_keys
&&
(
head
->
file
->
index_flags
(
keynr
)
&
HA_KEY_READ_ONLY
))
{
/*
We can resolve this by only reading through this key.
Assume that we will read trough the whole key range
and that all key blocks are half full (normally things are
much better).
*/
uint
keys_per_block
=
(
head
->
file
->
block_size
/
2
/
(
head
->
key_info
[
keynr
].
key_length
+
head
->
file
->
ref_length
)
+
1
);
found_read_time
=
((
double
)
(
found_records
+
keys_per_block
-
1
)
/
(
double
)
keys_per_block
);
}
else
found_read_time
=
(
head
->
file
->
read_time
(
keynr
,
param
.
range_count
,
found_records
)
+
(
double
)
found_records
/
TIME_FOR_COMPARE
);
if
(
*
read_time
>
found_read_time
)
{
*
read_time
=
found_read_time
;
*
records
=
found_records
;
*
key_to_read
=
key
;
result
=
0
;
}
}
}
return
result
;
}
/* make a select tree of all keys in condition */
/* make a select tree of all keys in condition */
static
SEL_TREE
*
get_mm_tree
(
PARAM
*
param
,
COND
*
cond
)
static
SEL_TREE
*
get_mm_tree
(
PARAM
*
param
,
COND
*
cond
)
...
@@ -911,6 +1401,7 @@ get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value,
...
@@ -911,6 +1401,7 @@ get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value,
sel_arg
=
new
SEL_ARG
(
SEL_ARG
::
MAYBE_KEY
);
// This key may be used later
sel_arg
=
new
SEL_ARG
(
SEL_ARG
::
MAYBE_KEY
);
// This key may be used later
sel_arg
->
part
=
(
uchar
)
key_part
->
part
;
sel_arg
->
part
=
(
uchar
)
key_part
->
part
;
tree
->
keys
[
key_part
->
key
]
=
sel_add
(
tree
->
keys
[
key_part
->
key
],
sel_arg
);
tree
->
keys
[
key_part
->
key
]
=
sel_add
(
tree
->
keys
[
key_part
->
key
],
sel_arg
);
tree
->
keys_map
|=
1
<<
key_part
->
key
;
}
}
}
}
DBUG_RETURN
(
tree
);
DBUG_RETURN
(
tree
);
...
@@ -1176,6 +1667,8 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
...
@@ -1176,6 +1667,8 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
DBUG_RETURN
(
tree1
);
DBUG_RETURN
(
tree1
);
}
}
bool
trees_have_key
=
false
;
key_map
result_keys
=
0
;
/* Join the trees key per key */
/* Join the trees key per key */
SEL_ARG
**
key1
,
**
key2
,
**
end
;
SEL_ARG
**
key1
,
**
key2
,
**
end
;
for
(
key1
=
tree1
->
keys
,
key2
=
tree2
->
keys
,
end
=
key1
+
param
->
keys
;
for
(
key1
=
tree1
->
keys
,
key2
=
tree2
->
keys
,
end
=
key1
+
param
->
keys
;
...
@@ -1184,6 +1677,7 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
...
@@ -1184,6 +1677,7 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
uint
flag
=
0
;
uint
flag
=
0
;
if
(
*
key1
||
*
key2
)
if
(
*
key1
||
*
key2
)
{
{
trees_have_key
=
true
;
if
(
*
key1
&&
!
(
*
key1
)
->
simple_key
())
if
(
*
key1
&&
!
(
*
key1
)
->
simple_key
())
flag
|=
CLONE_KEY1_MAYBE
;
flag
|=
CLONE_KEY1_MAYBE
;
if
(
*
key2
&&
!
(
*
key2
)
->
simple_key
())
if
(
*
key2
&&
!
(
*
key2
)
->
simple_key
())
...
@@ -1192,17 +1686,57 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
...
@@ -1192,17 +1686,57 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
if
((
*
key1
)
->
type
==
SEL_ARG
::
IMPOSSIBLE
)
if
((
*
key1
)
->
type
==
SEL_ARG
::
IMPOSSIBLE
)
{
{
tree1
->
type
=
SEL_TREE
::
IMPOSSIBLE
;
tree1
->
type
=
SEL_TREE
::
IMPOSSIBLE
;
break
;
DBUG_RETURN
(
tree1
)
;
}
}
result_keys
|=
1
<<
(
key1
-
tree1
->
keys
);
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
(
*
key1
)
->
test_use_count
(
*
key1
);
(
*
key1
)
->
test_use_count
(
*
key1
);
#endif
#endif
}
}
}
}
tree1
->
keys_map
=
result_keys
;
/* dispose index_merge if there is a "range" option */
if
(
trees_have_key
)
{
tree1
->
merges
.
empty
();
DBUG_RETURN
(
tree1
);
}
/* ok, both trees are index_merge trees */
imerge_list_and_list
(
&
tree1
->
merges
,
&
tree2
->
merges
);
DBUG_RETURN
(
tree1
);
DBUG_RETURN
(
tree1
);
}
}
/*
Check if two SEL_TREES can be combined into one without using index_merge
*/
bool
sel_trees_can_be_ored
(
SEL_TREE
*
tree1
,
SEL_TREE
*
tree2
,
PARAM
*
param
)
{
key_map
common_keys
=
tree1
->
keys_map
&
tree2
->
keys_map
;
DBUG_ENTER
(
"sel_trees_can_be_ored"
);
if
(
!
common_keys
)
DBUG_RETURN
(
false
);
/* trees have a common key, check if they refer to same key part */
SEL_ARG
**
key1
,
**
key2
;
for
(
uint
key_no
=
0
;
key_no
<
param
->
keys
;
key_no
++
,
common_keys
=
common_keys
>>
1
)
{
if
(
common_keys
&
1
)
{
key1
=
tree1
->
keys
+
key_no
;
key2
=
tree2
->
keys
+
key_no
;
if
((
*
key1
)
->
part
==
(
*
key2
)
->
part
)
{
DBUG_RETURN
(
true
);
}
}
}
DBUG_RETURN
(
false
);
}
static
SEL_TREE
*
static
SEL_TREE
*
tree_or
(
PARAM
*
param
,
SEL_TREE
*
tree1
,
SEL_TREE
*
tree2
)
tree_or
(
PARAM
*
param
,
SEL_TREE
*
tree1
,
SEL_TREE
*
tree2
)
...
@@ -1219,19 +1753,61 @@ tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
...
@@ -1219,19 +1753,61 @@ tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
if
(
tree2
->
type
==
SEL_TREE
::
MAYBE
)
if
(
tree2
->
type
==
SEL_TREE
::
MAYBE
)
DBUG_RETURN
(
tree2
);
DBUG_RETURN
(
tree2
);
/* Join the trees key per key */
SEL_TREE
*
result
=
0
;
SEL_ARG
**
key1
,
**
key2
,
**
end
;
key_map
result_keys
=
0
;
SEL_TREE
*
result
=
0
;
if
(
sel_trees_can_be_ored
(
tree1
,
tree2
,
param
))
for
(
key1
=
tree1
->
keys
,
key2
=
tree2
->
keys
,
end
=
key1
+
param
->
keys
;
key1
!=
end
;
key1
++
,
key2
++
)
{
{
*
key1
=
key_or
(
*
key1
,
*
key2
);
/* Join the trees key per key */
if
(
*
key1
)
SEL_ARG
**
key1
,
**
key2
,
**
end
;
for
(
key1
=
tree1
->
keys
,
key2
=
tree2
->
keys
,
end
=
key1
+
param
->
keys
;
key1
!=
end
;
key1
++
,
key2
++
)
{
{
result
=
tree1
;
// Added to tree1
*
key1
=
key_or
(
*
key1
,
*
key2
);
if
(
*
key1
)
{
result
=
tree1
;
// Added to tree1
result_keys
|=
1
<<
(
key1
-
tree1
->
keys
);
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
(
*
key1
)
->
test_use_count
(
*
key1
);
(
*
key1
)
->
test_use_count
(
*
key1
);
#endif
#endif
}
}
if
(
result
)
result
->
keys_map
=
result_keys
;
}
else
{
/* ok, two trees have KEY type but cannot be used without index merge */
if
(
tree1
->
merges
.
is_empty
()
&&
tree2
->
merges
.
is_empty
())
{
SEL_IMERGE
*
merge
;
/* both trees are "range" trees, produce new index merge structure */
if
(
!
(
result
=
new
SEL_TREE
())
||
!
(
merge
=
new
SEL_IMERGE
())
||
(
result
->
merges
.
push_back
(
merge
))
||
(
merge
->
or_sel_tree
(
param
,
tree1
))
||
(
merge
->
or_sel_tree
(
param
,
tree2
)))
result
=
NULL
;
else
result
->
type
=
tree1
->
type
;
}
else
if
(
!
tree1
->
merges
.
is_empty
()
&&
!
tree2
->
merges
.
is_empty
())
{
if
(
imerge_list_or_list
(
param
,
&
tree1
->
merges
,
&
tree2
->
merges
))
result
=
new
SEL_TREE
(
SEL_TREE
::
ALWAYS
);
else
result
=
tree1
;
}
else
{
/* one tree is index merge tree and another is range tree */
if
(
tree1
->
merges
.
is_empty
())
swap
(
SEL_TREE
*
,
tree1
,
tree2
);
/* add tree2 to tree1->merges, checking if it collapses to ALWAYS */
if
(
imerge_list_or_tree
(
param
,
&
tree1
->
merges
,
tree2
))
result
=
new
SEL_TREE
(
SEL_TREE
::
ALWAYS
);
else
result
=
tree1
;
}
}
}
}
DBUG_RETURN
(
result
);
DBUG_RETURN
(
result
);
...
@@ -2201,14 +2777,17 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
...
@@ -2201,14 +2777,17 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
/****************************************************************************
/****************************************************************************
** change a tree to a structure to be used by quick_select
** change a tree to a structure to be used by quick_select
** This uses it's own malloc tree
** This uses it's own malloc tree
** The caller should call QUICK_SELCT::init for returned quick select
****************************************************************************/
****************************************************************************/
QUICK_RANGE_SELECT
*
static
QUICK_SELECT
*
get_quick_select
(
PARAM
*
param
,
uint
idx
,
SEL_ARG
*
key_tree
,
get_quick_select
(
PARAM
*
param
,
uint
idx
,
SEL_ARG
*
key_tree
)
MEM_ROOT
*
parent_alloc
)
{
{
QUICK_SELECT
*
quick
;
QUICK_
RANGE_
SELECT
*
quick
;
DBUG_ENTER
(
"get_quick_select"
);
DBUG_ENTER
(
"get_quick_select"
);
if
((
quick
=
new
QUICK_SELECT
(
param
->
table
,
param
->
real_keynr
[
idx
])))
if
((
quick
=
new
QUICK_RANGE_SELECT
(
param
->
table
,
param
->
real_keynr
[
idx
],
test
(
parent_alloc
),
parent_alloc
)))
{
{
if
(
quick
->
error
||
if
(
quick
->
error
||
get_quick_keys
(
param
,
quick
,
param
->
key
[
idx
],
key_tree
,
param
->
min_key
,
0
,
get_quick_keys
(
param
,
quick
,
param
->
key
[
idx
],
key_tree
,
param
->
min_key
,
0
,
...
@@ -2220,9 +2799,10 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree)
...
@@ -2220,9 +2799,10 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree)
else
else
{
{
quick
->
key_parts
=
(
KEY_PART
*
)
quick
->
key_parts
=
(
KEY_PART
*
)
memdup_root
(
&
quick
->
alloc
,(
char
*
)
param
->
key
[
idx
],
memdup_root
(
parent_alloc
?
parent_alloc
:
&
quick
->
alloc
,
sizeof
(
KEY_PART
)
*
(
char
*
)
param
->
key
[
idx
],
param
->
table
->
key_info
[
param
->
real_keynr
[
idx
]].
key_parts
);
sizeof
(
KEY_PART
)
*
param
->
table
->
key_info
[
param
->
real_keynr
[
idx
]].
key_parts
);
}
}
}
}
DBUG_RETURN
(
quick
);
DBUG_RETURN
(
quick
);
...
@@ -2232,9 +2812,8 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree)
...
@@ -2232,9 +2812,8 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree)
/*
/*
** Fix this to get all possible sub_ranges
** Fix this to get all possible sub_ranges
*/
*/
bool
static
bool
get_quick_keys
(
PARAM
*
param
,
QUICK_RANGE_SELECT
*
quick
,
KEY_PART
*
key
,
get_quick_keys
(
PARAM
*
param
,
QUICK_SELECT
*
quick
,
KEY_PART
*
key
,
SEL_ARG
*
key_tree
,
char
*
min_key
,
uint
min_key_flag
,
SEL_ARG
*
key_tree
,
char
*
min_key
,
uint
min_key_flag
,
char
*
max_key
,
uint
max_key_flag
)
char
*
max_key
,
uint
max_key_flag
)
{
{
...
@@ -2343,7 +2922,7 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
...
@@ -2343,7 +2922,7 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
Return 1 if there is only one range and this uses the whole primary key
Return 1 if there is only one range and this uses the whole primary key
*/
*/
bool
QUICK_SELECT
::
unique_key_range
()
bool
QUICK_
RANGE_
SELECT
::
unique_key_range
()
{
{
if
(
ranges
.
elements
==
1
)
if
(
ranges
.
elements
==
1
)
{
{
...
@@ -2380,16 +2959,22 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length)
...
@@ -2380,16 +2959,22 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length)
** Create a QUICK RANGE based on a key
** Create a QUICK RANGE based on a key
****************************************************************************/
****************************************************************************/
QUICK_SELECT
*
get_quick_select_for_ref
(
TABLE
*
table
,
TABLE_REF
*
ref
)
QUICK_
RANGE_
SELECT
*
get_quick_select_for_ref
(
TABLE
*
table
,
TABLE_REF
*
ref
)
{
{
table
->
file
->
index_end
();
// Remove old cursor
table
->
file
->
index_end
();
// Remove old cursor
QUICK_
SELECT
*
quick
=
new
QUICK_SELECT
(
table
,
ref
->
key
,
1
);
QUICK_
RANGE_SELECT
*
quick
=
new
QUICK_RANGE_SELECT
(
table
,
ref
->
key
,
1
);
KEY
*
key_info
=
&
table
->
key_info
[
ref
->
key
];
KEY
*
key_info
=
&
table
->
key_info
[
ref
->
key
];
KEY_PART
*
key_part
;
KEY_PART
*
key_part
;
uint
part
;
uint
part
;
if
(
!
quick
)
if
(
!
quick
)
return
0
;
return
0
;
if
(
quick
->
init
())
{
delete
quick
;
return
0
;
}
if
(
cp_buffer_from_ref
(
ref
))
if
(
cp_buffer_from_ref
(
ref
))
{
{
if
(
current_thd
->
is_fatal_error
)
if
(
current_thd
->
is_fatal_error
)
...
@@ -2427,11 +3012,82 @@ err:
...
@@ -2427,11 +3012,82 @@ err:
return
0
;
return
0
;
}
}
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
/*
Fetch all row ids into unique.
*/
int
QUICK_INDEX_MERGE_SELECT
::
prepare_unique
()
{
int
result
;
DBUG_ENTER
(
"QUICK_INDEX_MERGE_SELECT::prepare_unique"
);
/* we're going to just read rowids */
head
->
file
->
extra
(
HA_EXTRA_KEYREAD
);
unique
=
new
Unique
(
refposcmp2
,
(
void
*
)
&
head
->
file
->
ref_length
,
head
->
file
->
ref_length
,
MEM_STRIP_BUF_SIZE
);
if
(
!
unique
)
DBUG_RETURN
(
1
);
do
{
while
((
result
=
cur_quick_select
->
get_next
())
==
HA_ERR_END_OF_FILE
)
{
cur_quick_select
=
cur_quick_it
++
;
if
(
!
cur_quick_select
)
break
;
cur_quick_select
->
init
();
if
(
cur_quick_select
->
reset
())
DBUG_RETURN
(
1
);
}
if
(
result
)
{
/*
table read error (including HA_ERR_END_OF_FILE on last quick select
in index_merge)
*/
if
(
result
!=
HA_ERR_END_OF_FILE
)
{
DBUG_RETURN
(
result
);
}
else
break
;
}
if
(
thd
->
killed
)
DBUG_RETURN
(
1
);
cur_quick_select
->
file
->
position
(
cur_quick_select
->
record
);
if
(
unique
->
unique_add
((
char
*
)
cur_quick_select
->
file
->
ref
))
DBUG_RETURN
(
1
);
}
while
(
true
);
/* ok, all row ids are in Unique */
result
=
unique
->
get
(
head
);
/* index_merge currently doesn't support "using index" at all */
head
->
file
->
extra
(
HA_EXTRA_NO_KEYREAD
);
DBUG_RETURN
(
result
);
}
int
QUICK_INDEX_MERGE_SELECT
::
get_next
()
{
DBUG_ENTER
(
"QUICK_INDEX_MERGE_SELECT::get_next"
);
DBUG_PRINT
(
"QUICK_INDEX_MERGE_SELECT"
,
(
"ERROR: index merge error: get_next should not be called "
));
DBUG_ASSERT
(
0
);
DBUG_RETURN
(
HA_ERR_END_OF_FILE
);
}
/* get next possible record using quick-struct */
/* get next possible record using quick-struct */
int
QUICK_SELECT
::
get_next
()
int
QUICK_
RANGE_
SELECT
::
get_next
()
{
{
DBUG_ENTER
(
"get_next"
);
DBUG_ENTER
(
"
QUICK_RANGE_SELECT::
get_next"
);
for
(;;)
for
(;;)
{
{
...
@@ -2518,7 +3174,7 @@ int QUICK_SELECT::get_next()
...
@@ -2518,7 +3174,7 @@ int QUICK_SELECT::get_next()
Returns 0 if key <= range->max_key
Returns 0 if key <= range->max_key
*/
*/
int
QUICK_SELECT
::
cmp_next
(
QUICK_RANGE
*
range_arg
)
int
QUICK_
RANGE_
SELECT
::
cmp_next
(
QUICK_RANGE
*
range_arg
)
{
{
if
(
range_arg
->
flag
&
NO_MAX_RANGE
)
if
(
range_arg
->
flag
&
NO_MAX_RANGE
)
return
0
;
/* key can't be to large */
return
0
;
/* key can't be to large */
...
@@ -2559,8 +3215,9 @@ int QUICK_SELECT::cmp_next(QUICK_RANGE *range_arg)
...
@@ -2559,8 +3215,9 @@ int QUICK_SELECT::cmp_next(QUICK_RANGE *range_arg)
for now, this seems to work right at least.
for now, this seems to work right at least.
*/
*/
QUICK_SELECT_DESC
::
QUICK_SELECT_DESC
(
QUICK_SELECT
*
q
,
uint
used_key_parts
)
QUICK_SELECT_DESC
::
QUICK_SELECT_DESC
(
QUICK_RANGE_SELECT
*
q
,
:
QUICK_SELECT
(
*
q
),
rev_it
(
rev_ranges
)
uint
used_key_parts
)
:
QUICK_RANGE_SELECT
(
*
q
),
rev_it
(
rev_ranges
)
{
{
bool
not_read_after_key
=
file
->
table_flags
()
&
HA_NOT_READ_AFTER_KEY
;
bool
not_read_after_key
=
file
->
table_flags
()
&
HA_NOT_READ_AFTER_KEY
;
QUICK_RANGE
*
r
;
QUICK_RANGE
*
r
;
...
@@ -2827,7 +3484,23 @@ print_key(KEY_PART *key_part,const char *key,uint used_length)
...
@@ -2827,7 +3484,23 @@ print_key(KEY_PART *key_part,const char *key,uint used_length)
}
}
}
}
static
void
print_quick
(
QUICK_SELECT
*
quick
,
key_map
needed_reg
)
void
print_quick_sel_imerge
(
QUICK_INDEX_MERGE_SELECT
*
quick
,
key_map
needed_reg
)
{
DBUG_ENTER
(
"print_param"
);
if
(
!
_db_on_
||
!
quick
)
DBUG_VOID_RETURN
;
List_iterator_fast
<
QUICK_RANGE_SELECT
>
it
(
quick
->
quick_selects
);
QUICK_RANGE_SELECT
*
quick_range_sel
;
while
((
quick_range_sel
=
it
++
))
{
print_quick_sel_range
(
quick_range_sel
,
needed_reg
);
}
DBUG_VOID_RETURN
;
}
void
print_quick_sel_range
(
QUICK_RANGE_SELECT
*
quick
,
key_map
needed_reg
)
{
{
QUICK_RANGE
*
range
;
QUICK_RANGE
*
range
;
DBUG_ENTER
(
"print_param"
);
DBUG_ENTER
(
"print_param"
);
...
...
sql/opt_range.h
View file @
1c61a92b
...
@@ -65,48 +65,142 @@ class QUICK_RANGE :public Sql_alloc {
...
@@ -65,48 +65,142 @@ class QUICK_RANGE :public Sql_alloc {
}
}
};
};
//class INDEX_MERGE;
class
QUICK_SELECT
{
/*
Quick select interface.
This class is parent for all QUICK_*_SELECT and FT_SELECT classes.
*/
class
QUICK_SELECT_I
{
public:
public:
ha_rows
records
;
/* estimate of # of records to be retrieved */
double
read_time
;
/* time to perform this retrieval */
TABLE
*
head
;
/*
the only index this quick select uses, or MAX_KEY for
QUICK_INDEX_MERGE_SELECT
*/
uint
index
;
uint
max_used_key_length
,
used_key_parts
;
QUICK_SELECT_I
();
virtual
~
QUICK_SELECT_I
(){};
virtual
int
init
()
=
0
;
virtual
int
reset
(
void
)
=
0
;
virtual
int
get_next
()
=
0
;
/* get next record to retrieve */
virtual
bool
reverse_sorted
()
=
0
;
virtual
bool
unique_key_range
()
{
return
false
;
}
enum
{
QS_TYPE_RANGE
=
0
,
QS_TYPE_INDEX_MERGE
=
1
,
QS_TYPE_RANGE_DESC
=
2
,
QS_TYPE_FULLTEXT
=
3
};
/* Get type of this quick select - one of the QS_* values */
virtual
int
get_type
()
=
0
;
};
struct
st_qsel_param
;
class
SEL_ARG
;
class
QUICK_RANGE_SELECT
:
public
QUICK_SELECT_I
{
protected:
bool
next
,
dont_free
;
bool
next
,
dont_free
;
public:
int
error
;
int
error
;
uint
index
,
max_used_key_length
,
used_key_parts
;
TABLE
*
head
;
handler
*
file
;
handler
*
file
;
byte
*
record
;
byte
*
record
;
protected:
friend
void
print_quick_sel_range
(
QUICK_RANGE_SELECT
*
quick
,
key_map
needed_reg
);
friend
QUICK_RANGE_SELECT
*
get_quick_select_for_ref
(
TABLE
*
table
,
struct
st_table_ref
*
ref
);
friend
bool
get_quick_keys
(
struct
st_qsel_param
*
param
,
QUICK_RANGE_SELECT
*
quick
,
KEY_PART
*
key
,
SEL_ARG
*
key_tree
,
char
*
min_key
,
uint
min_key_flag
,
char
*
max_key
,
uint
max_key_flag
);
friend
QUICK_RANGE_SELECT
*
get_quick_select
(
struct
st_qsel_param
*
,
uint
idx
,
SEL_ARG
*
key_tree
,
MEM_ROOT
*
alloc
);
friend
class
QUICK_SELECT_DESC
;
List
<
QUICK_RANGE
>
ranges
;
List
<
QUICK_RANGE
>
ranges
;
List_iterator
<
QUICK_RANGE
>
it
;
List_iterator
<
QUICK_RANGE
>
it
;
QUICK_RANGE
*
range
;
QUICK_RANGE
*
range
;
MEM_ROOT
alloc
;
MEM_ROOT
alloc
;
KEY_PART
*
key_parts
;
KEY_PART
*
key_parts
;
ha_rows
records
;
double
read_time
;
QUICK_SELECT
(
TABLE
*
table
,
uint
index_arg
,
bool
no_alloc
=
0
);
virtual
~
QUICK_SELECT
();
void
reset
(
void
)
{
next
=
0
;
it
.
rewind
();
}
int
init
()
{
return
error
=
file
->
index_init
(
index
);
}
virtual
int
get_next
();
virtual
bool
reverse_sorted
()
{
return
0
;
}
int
cmp_next
(
QUICK_RANGE
*
range
);
int
cmp_next
(
QUICK_RANGE
*
range
);
public:
QUICK_RANGE_SELECT
(
TABLE
*
table
,
uint
index_arg
,
bool
no_alloc
=
0
,
MEM_ROOT
*
parent_alloc
=
NULL
);
~
QUICK_RANGE_SELECT
();
int
reset
(
void
)
{
next
=
0
;
it
.
rewind
();
return
0
;
}
int
init
();
int
get_next
();
bool
reverse_sorted
()
{
return
0
;
}
bool
unique_key_range
();
bool
unique_key_range
();
int
get_type
()
{
return
QS_TYPE_RANGE
;
}
};
};
/*
Index merge quick select.
It is implemented as a container for several QUICK_RANGE_SELECTs.
*/
class
QUICK_INDEX_MERGE_SELECT
:
public
QUICK_SELECT_I
{
public:
QUICK_INDEX_MERGE_SELECT
(
THD
*
thd
,
TABLE
*
table
);
~
QUICK_INDEX_MERGE_SELECT
();
int
init
();
int
reset
(
void
);
int
get_next
();
bool
reverse_sorted
()
{
return
false
;
}
bool
unique_key_range
()
{
return
false
;
}
int
get_type
()
{
return
QS_TYPE_INDEX_MERGE
;
}
bool
push_quick_back
(
QUICK_RANGE_SELECT
*
quick_sel_range
);
/* range quick selects this index_merge read consists of */
List
<
QUICK_RANGE_SELECT
>
quick_selects
;
/* quick select which is currently used for rows retrieval */
List_iterator_fast
<
QUICK_RANGE_SELECT
>
cur_quick_it
;
QUICK_RANGE_SELECT
*
cur_quick_select
;
/* last element in quick_selects list. */
QUICK_RANGE_SELECT
*
last_quick_select
;
Unique
*
unique
;
MEM_ROOT
alloc
;
THD
*
thd
;
int
prepare_unique
();
bool
reset_called
;
};
class
QUICK_SELECT_DESC
:
public
QUICK_SELECT
class
QUICK_SELECT_DESC
:
public
QUICK_
RANGE_
SELECT
{
{
public:
public:
QUICK_SELECT_DESC
(
QUICK_SELECT
*
q
,
uint
used_key_parts
);
QUICK_SELECT_DESC
(
QUICK_
RANGE_
SELECT
*
q
,
uint
used_key_parts
);
int
get_next
();
int
get_next
();
bool
reverse_sorted
()
{
return
1
;
}
bool
reverse_sorted
()
{
return
1
;
}
int
get_type
()
{
return
QS_TYPE_RANGE_DESC
;
}
private:
private:
int
cmp_prev
(
QUICK_RANGE
*
range
);
int
cmp_prev
(
QUICK_RANGE
*
range
);
bool
range_reads_after_key
(
QUICK_RANGE
*
range
);
bool
range_reads_after_key
(
QUICK_RANGE
*
range
);
#ifdef NOT_USED
#ifdef NOT_USED
bool
test_if_null_range
(
QUICK_RANGE
*
range
,
uint
used_key_parts
);
bool
test_if_null_range
(
QUICK_RANGE
*
range
,
uint
used_key_parts
);
#endif
#endif
void
reset
(
void
)
{
next
=
0
;
rev_it
.
rewind
()
;
}
int
reset
(
void
)
{
next
=
0
;
rev_it
.
rewind
();
return
0
;
}
List
<
QUICK_RANGE
>
rev_ranges
;
List
<
QUICK_RANGE
>
rev_ranges
;
List_iterator
<
QUICK_RANGE
>
rev_it
;
List_iterator
<
QUICK_RANGE
>
rev_it
;
};
};
...
@@ -114,7 +208,7 @@ private:
...
@@ -114,7 +208,7 @@ private:
class
SQL_SELECT
:
public
Sql_alloc
{
class
SQL_SELECT
:
public
Sql_alloc
{
public:
public:
QUICK_SELECT
*
quick
;
// If quick-select used
QUICK_SELECT
_I
*
quick
;
// If quick-select used
COND
*
cond
;
// where condition
COND
*
cond
;
// where condition
TABLE
*
head
;
TABLE
*
head
;
IO_CACHE
file
;
// Positions to used records
IO_CACHE
file
;
// Positions to used records
...
@@ -134,6 +228,6 @@ class SQL_SELECT :public Sql_alloc {
...
@@ -134,6 +228,6 @@ class SQL_SELECT :public Sql_alloc {
bool
force_quick_range
=
0
);
bool
force_quick_range
=
0
);
};
};
QUICK_SELECT
*
get_quick_select_for_ref
(
TABLE
*
table
,
struct
st_table_ref
*
ref
);
QUICK_
RANGE_
SELECT
*
get_quick_select_for_ref
(
TABLE
*
table
,
struct
st_table_ref
*
ref
);
#endif
#endif
sql/records.cc
View file @
1c61a92b
...
@@ -98,7 +98,8 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
...
@@ -98,7 +98,8 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
}
}
}
}
}
}
else
if
(
select
&&
select
->
quick
)
else
if
(
select
&&
select
->
quick
&&
(
select
->
quick
->
get_type
()
!=
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
))
{
{
DBUG_PRINT
(
"info"
,(
"using rr_quick"
));
DBUG_PRINT
(
"info"
,(
"using rr_quick"
));
info
->
read_record
=
rr_quick
;
info
->
read_record
=
rr_quick
;
...
...
sql/sql_class.cc
View file @
1c61a92b
...
@@ -537,8 +537,8 @@ int THD::send_explain_fields(select_result *result)
...
@@ -537,8 +537,8 @@ int THD::send_explain_fields(select_result *result)
item
->
maybe_null
=
1
;
item
->
maybe_null
=
1
;
field_list
.
push_back
(
item
=
new
Item_empty_string
(
"key"
,
NAME_LEN
));
field_list
.
push_back
(
item
=
new
Item_empty_string
(
"key"
,
NAME_LEN
));
item
->
maybe_null
=
1
;
item
->
maybe_null
=
1
;
field_list
.
push_back
(
item
=
new
Item_
return_int
(
"key_len"
,
3
,
field_list
.
push_back
(
item
=
new
Item_
empty_string
(
"key_len"
,
MYSQL_TYPE_LONGLONG
));
NAME_LEN
*
MAX_KEY
));
item
->
maybe_null
=
1
;
item
->
maybe_null
=
1
;
field_list
.
push_back
(
item
=
new
Item_empty_string
(
"ref"
,
field_list
.
push_back
(
item
=
new
Item_empty_string
(
"ref"
,
NAME_LEN
*
MAX_REF_PARTS
));
NAME_LEN
*
MAX_REF_PARTS
));
...
...
sql/sql_list.h
View file @
1c61a92b
...
@@ -135,6 +135,12 @@ public:
...
@@ -135,6 +135,12 @@ public:
last
=
&
first
;
last
=
&
first
;
return
tmp
->
info
;
return
tmp
->
info
;
}
}
inline
void
concat
(
base_list
*
list
)
{
*
last
=
list
->
first
;
last
=
list
->
last
;
elements
+=
list
->
elements
;
}
inline
list_node
*
last_node
()
{
return
*
last
;
}
inline
list_node
*
last_node
()
{
return
*
last
;
}
inline
list_node
*
first_node
()
{
return
first
;}
inline
list_node
*
first_node
()
{
return
first
;}
inline
void
*
head
()
{
return
first
->
info
;
}
inline
void
*
head
()
{
return
first
->
info
;
}
...
@@ -255,6 +261,7 @@ public:
...
@@ -255,6 +261,7 @@ public:
}
}
empty
();
empty
();
}
}
inline
void
concat
(
List
<
T
>
*
list
)
{
base_list
::
concat
(
list
);
}
};
};
...
...
sql/sql_select.cc
View file @
1c61a92b
...
@@ -32,7 +32,8 @@
...
@@ -32,7 +32,8 @@
const
char
*
join_type_str
[]
=
{
"UNKNOWN"
,
"system"
,
"const"
,
"eq_ref"
,
"ref"
,
const
char
*
join_type_str
[]
=
{
"UNKNOWN"
,
"system"
,
"const"
,
"eq_ref"
,
"ref"
,
"MAYBE_REF"
,
"ALL"
,
"range"
,
"index"
,
"fulltext"
,
"MAYBE_REF"
,
"ALL"
,
"range"
,
"index"
,
"fulltext"
,
"ref_or_null"
,
"simple_in"
,
"index_in"
"ref_or_null"
,
"simple_in"
,
"index_in"
,
"index_merge"
};
};
static
void
optimize_keyuse
(
JOIN
*
join
,
DYNAMIC_ARRAY
*
keyuse_array
);
static
void
optimize_keyuse
(
JOIN
*
join
,
DYNAMIC_ARRAY
*
keyuse_array
);
...
@@ -114,7 +115,6 @@ static int join_read_next_same_or_null(READ_RECORD *info);
...
@@ -114,7 +115,6 @@ static int join_read_next_same_or_null(READ_RECORD *info);
static
COND
*
make_cond_for_table
(
COND
*
cond
,
table_map
table
,
static
COND
*
make_cond_for_table
(
COND
*
cond
,
table_map
table
,
table_map
used_table
);
table_map
used_table
);
static
Item
*
part_of_refkey
(
TABLE
*
form
,
Field
*
field
);
static
Item
*
part_of_refkey
(
TABLE
*
form
,
Field
*
field
);
static
uint
find_shortest_key
(
TABLE
*
table
,
key_map
usable_keys
);
static
bool
test_if_skip_sort_order
(
JOIN_TAB
*
tab
,
ORDER
*
order
,
static
bool
test_if_skip_sort_order
(
JOIN_TAB
*
tab
,
ORDER
*
order
,
ha_rows
select_limit
,
bool
no_changes
);
ha_rows
select_limit
,
bool
no_changes
);
static
int
create_sort_index
(
THD
*
thd
,
JOIN
*
join
,
ORDER
*
order
,
static
int
create_sort_index
(
THD
*
thd
,
JOIN
*
join
,
ORDER
*
order
,
...
@@ -3285,7 +3285,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
...
@@ -3285,7 +3285,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
with key reading */
with key reading */
if
(
tab
->
needed_reg
==
0
&&
tab
->
type
!=
JT_EQ_REF
if
(
tab
->
needed_reg
==
0
&&
tab
->
type
!=
JT_EQ_REF
&&
tab
->
type
!=
JT_FT
&&
(
tab
->
type
!=
JT_REF
||
&&
tab
->
type
!=
JT_FT
&&
(
tab
->
type
!=
JT_REF
||
(
uint
)
tab
->
ref
.
key
==
tab
->
quick
->
index
))
(
uint
)
tab
->
ref
.
key
==
tab
->
quick
->
index
))
{
{
sel
->
quick
=
tab
->
quick
;
// Use value from get_quick_...
sel
->
quick
=
tab
->
quick
;
// Use value from get_quick_...
sel
->
quick_keys
=
0
;
sel
->
quick_keys
=
0
;
...
@@ -5725,8 +5725,8 @@ test_if_quick_select(JOIN_TAB *tab)
...
@@ -5725,8 +5725,8 @@ test_if_quick_select(JOIN_TAB *tab)
static
int
static
int
join_init_read_record
(
JOIN_TAB
*
tab
)
join_init_read_record
(
JOIN_TAB
*
tab
)
{
{
if
(
tab
->
select
&&
tab
->
select
->
quick
)
if
(
tab
->
select
&&
tab
->
select
->
quick
&&
tab
->
select
->
quick
->
reset
()
)
tab
->
select
->
quick
->
reset
()
;
return
1
;
init_read_record
(
&
tab
->
read_record
,
tab
->
join
->
thd
,
tab
->
table
,
init_read_record
(
&
tab
->
read_record
,
tab
->
join
->
thd
,
tab
->
table
,
tab
->
select
,
1
,
1
);
tab
->
select
,
1
,
1
);
return
(
*
tab
->
read_record
.
read_record
)(
&
tab
->
read_record
);
return
(
*
tab
->
read_record
.
read_record
)(
&
tab
->
read_record
);
...
@@ -6473,7 +6473,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
...
@@ -6473,7 +6473,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
return
reverse
;
return
reverse
;
}
}
static
uint
find_shortest_key
(
TABLE
*
table
,
key_map
usable_keys
)
uint
find_shortest_key
(
TABLE
*
table
,
key_map
usable_keys
)
{
{
uint
min_length
=
(
uint
)
~
0
;
uint
min_length
=
(
uint
)
~
0
;
uint
best
=
MAX_KEY
;
uint
best
=
MAX_KEY
;
...
@@ -6601,6 +6601,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
...
@@ -6601,6 +6601,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
}
}
else
if
(
select
&&
select
->
quick
)
// Range found by opt_range
else
if
(
select
&&
select
->
quick
)
// Range found by opt_range
{
{
/* assume results are not ordered when index merge is used */
if
(
select
->
quick
->
get_type
()
==
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
DBUG_RETURN
(
0
);
ref_key
=
select
->
quick
->
index
;
ref_key
=
select
->
quick
->
index
;
ref_key_parts
=
select
->
quick
->
used_key_parts
;
ref_key_parts
=
select
->
quick
->
used_key_parts
;
}
}
...
@@ -6635,6 +6638,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
...
@@ -6635,6 +6638,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
}
}
else
else
{
{
/*
We have verified above that select->quick is not
index_merge quick select.
*/
select
->
quick
->
index
=
new_ref_key
;
select
->
quick
->
index
=
new_ref_key
;
select
->
quick
->
init
();
select
->
quick
->
init
();
}
}
...
@@ -6656,10 +6663,13 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
...
@@ -6656,10 +6663,13 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
*/
if
(
!
select
->
quick
->
reverse_sorted
())
if
(
!
select
->
quick
->
reverse_sorted
())
{
{
if
(
table
->
file
->
index_flags
(
ref_key
)
&
HA_NOT_READ_PREFIX_LAST
)
if
(
table
->
file
->
index_flags
(
ref_key
)
&
HA_NOT_READ_PREFIX_LAST
||
(
select
->
quick
->
get_type
()
==
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
))
DBUG_RETURN
(
0
);
// Use filesort
DBUG_RETURN
(
0
);
// Use filesort
// ORDER BY range_key DESC
QUICK_SELECT_DESC
*
tmp
=
new
QUICK_SELECT_DESC
(
select
->
quick
,
// ORDER BY range_key DESC
QUICK_SELECT_DESC
*
tmp
=
new
QUICK_SELECT_DESC
((
QUICK_RANGE_SELECT
*
)(
select
->
quick
),
used_key_parts
);
used_key_parts
);
if
(
!
tmp
||
tmp
->
error
)
if
(
!
tmp
||
tmp
->
error
)
{
{
...
@@ -6794,8 +6804,11 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
...
@@ -6794,8 +6804,11 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
{
{
select
->
quick
=
tab
->
quick
;
select
->
quick
=
tab
->
quick
;
tab
->
quick
=
0
;
tab
->
quick
=
0
;
/* We can only use 'Only index' if quick key is same as ref_key */
/*
if
(
table
->
key_read
&&
(
uint
)
tab
->
ref
.
key
!=
select
->
quick
->
index
)
We can only use 'Only index' if quick key is same as ref_key
and in index_merge 'Only index' cannot be used
*/
if
(
table
->
key_read
&&
((
uint
)
tab
->
ref
.
key
!=
select
->
quick
->
index
))
{
{
table
->
key_read
=
0
;
table
->
key_read
=
0
;
table
->
file
->
extra
(
HA_EXTRA_NO_KEYREAD
);
table
->
file
->
extra
(
HA_EXTRA_NO_KEYREAD
);
...
@@ -8598,12 +8611,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
...
@@ -8598,12 +8611,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
JOIN_TAB
*
tab
=
join
->
join_tab
+
i
;
JOIN_TAB
*
tab
=
join
->
join_tab
+
i
;
TABLE
*
table
=
tab
->
table
;
TABLE
*
table
=
tab
->
table
;
char
buff
[
512
],
*
buff_ptr
=
buff
;
char
buff
[
512
],
*
buff_ptr
=
buff
;
char
buff1
[
512
],
buff2
[
512
];
char
buff1
[
512
],
buff2
[
512
],
buff3
[
512
];
char
keylen_str_buf
[
64
];
char
derived_name
[
64
];
char
derived_name
[
64
];
String
tmp1
(
buff1
,
sizeof
(
buff1
),
cs
);
String
tmp1
(
buff1
,
sizeof
(
buff1
),
cs
);
String
tmp2
(
buff2
,
sizeof
(
buff2
),
cs
);
String
tmp2
(
buff2
,
sizeof
(
buff2
),
cs
);
String
tmp3
(
buff3
,
sizeof
(
buff3
),
cs
);
tmp1
.
length
(
0
);
tmp1
.
length
(
0
);
tmp2
.
length
(
0
);
tmp2
.
length
(
0
);
tmp3
.
length
(
0
);
item_list
.
empty
();
item_list
.
empty
();
item_list
.
push_back
(
new
Item_int
((
int32
)
item_list
.
push_back
(
new
Item_int
((
int32
)
...
@@ -8612,7 +8628,13 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
...
@@ -8612,7 +8628,13 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
strlen
(
join
->
select_lex
->
type
),
strlen
(
join
->
select_lex
->
type
),
cs
));
cs
));
if
(
tab
->
type
==
JT_ALL
&&
tab
->
select
&&
tab
->
select
->
quick
)
if
(
tab
->
type
==
JT_ALL
&&
tab
->
select
&&
tab
->
select
->
quick
)
tab
->
type
=
JT_RANGE
;
{
if
(
tab
->
select
->
quick
->
get_type
()
==
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
tab
->
type
=
JT_INDEX_MERGE
;
else
tab
->
type
=
JT_RANGE
;
}
if
(
table
->
derived_select_number
)
if
(
table
->
derived_select_number
)
{
{
/* Derived table name generation */
/* Derived table name generation */
...
@@ -8646,10 +8668,14 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
...
@@ -8646,10 +8668,14 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
if
(
tab
->
ref
.
key_parts
)
if
(
tab
->
ref
.
key_parts
)
{
{
KEY
*
key_info
=
table
->
key_info
+
tab
->
ref
.
key
;
KEY
*
key_info
=
table
->
key_info
+
tab
->
ref
.
key
;
register
uint
length
;
item_list
.
push_back
(
new
Item_string
(
key_info
->
name
,
item_list
.
push_back
(
new
Item_string
(
key_info
->
name
,
strlen
(
key_info
->
name
),
strlen
(
key_info
->
name
),
system_charset_info
));
system_charset_info
));
item_list
.
push_back
(
new
Item_int
((
int32
)
tab
->
ref
.
key_length
));
length
=
longlong2str
(
tab
->
ref
.
key_length
,
keylen_str_buf
,
10
)
-
keylen_str_buf
;
item_list
.
push_back
(
new
Item_string
(
keylen_str_buf
,
length
,
system_charset_info
));
for
(
store_key
**
ref
=
tab
->
ref
.
key_copy
;
*
ref
;
ref
++
)
for
(
store_key
**
ref
=
tab
->
ref
.
key_copy
;
*
ref
;
ref
++
)
{
{
if
(
tmp2
.
length
())
if
(
tmp2
.
length
())
...
@@ -8661,18 +8687,60 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
...
@@ -8661,18 +8687,60 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
else
if
(
tab
->
type
==
JT_NEXT
)
else
if
(
tab
->
type
==
JT_NEXT
)
{
{
KEY
*
key_info
=
table
->
key_info
+
tab
->
index
;
KEY
*
key_info
=
table
->
key_info
+
tab
->
index
;
register
uint
length
;
item_list
.
push_back
(
new
Item_string
(
key_info
->
name
,
item_list
.
push_back
(
new
Item_string
(
key_info
->
name
,
strlen
(
key_info
->
name
),
cs
));
strlen
(
key_info
->
name
),
cs
));
item_list
.
push_back
(
new
Item_int
((
int32
)
key_info
->
key_length
));
length
=
longlong2str
(
key_info
->
key_length
,
keylen_str_buf
,
10
)
-
keylen_str_buf
;
item_list
.
push_back
(
new
Item_string
(
keylen_str_buf
,
length
,
system_charset_info
));
item_list
.
push_back
(
item_null
);
item_list
.
push_back
(
item_null
);
}
}
else
if
(
tab
->
select
&&
tab
->
select
->
quick
)
else
if
(
tab
->
select
&&
tab
->
select
->
quick
)
{
{
KEY
*
key_info
=
table
->
key_info
+
tab
->
select
->
quick
->
index
;
if
(
tab
->
select
->
quick
->
get_type
()
==
item_list
.
push_back
(
new
Item_string
(
key_info
->
name
,
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
strlen
(
key_info
->
name
),
cs
));
{
item_list
.
push_back
(
new
Item_int
((
int32
)
tab
->
select
->
quick
->
QUICK_INDEX_MERGE_SELECT
*
quick_imerge
=
max_used_key_length
));
(
QUICK_INDEX_MERGE_SELECT
*
)
tab
->
select
->
quick
;
QUICK_RANGE_SELECT
*
quick
;
List_iterator_fast
<
QUICK_RANGE_SELECT
>
it
(
quick_imerge
->
quick_selects
);
while
((
quick
=
it
++
))
{
KEY
*
key_info
=
table
->
key_info
+
quick
->
index
;
register
uint
length
;
if
(
tmp3
.
length
())
tmp3
.
append
(
','
);
tmp3
.
append
(
key_info
->
name
);
if
(
tmp2
.
length
())
tmp2
.
append
(
','
);
length
=
longlong2str
(
quick
->
max_used_key_length
,
keylen_str_buf
,
10
)
-
keylen_str_buf
;
tmp2
.
append
(
keylen_str_buf
,
length
);
}
}
else
{
KEY
*
key_info
=
table
->
key_info
+
tab
->
select
->
quick
->
index
;
register
uint
length
;
tmp3
.
append
(
key_info
->
name
);
length
=
longlong2str
(
tab
->
select
->
quick
->
max_used_key_length
,
keylen_str_buf
,
10
)
-
keylen_str_buf
;
tmp2
.
append
(
keylen_str_buf
,
length
);
}
item_list
.
push_back
(
new
Item_string
(
tmp3
.
ptr
(),
tmp3
.
length
(),
cs
));
item_list
.
push_back
(
new
Item_string
(
tmp2
.
ptr
(),
tmp2
.
length
(),
cs
));
item_list
.
push_back
(
item_null
);
item_list
.
push_back
(
item_null
);
}
}
else
else
...
...
sql/sql_select.h
View file @
1c61a92b
...
@@ -76,7 +76,7 @@ typedef struct st_join_cache {
...
@@ -76,7 +76,7 @@ typedef struct st_join_cache {
enum
join_type
{
JT_UNKNOWN
,
JT_SYSTEM
,
JT_CONST
,
JT_EQ_REF
,
JT_REF
,
JT_MAYBE_REF
,
enum
join_type
{
JT_UNKNOWN
,
JT_SYSTEM
,
JT_CONST
,
JT_EQ_REF
,
JT_REF
,
JT_MAYBE_REF
,
JT_ALL
,
JT_RANGE
,
JT_NEXT
,
JT_FT
,
JT_REF_OR_NULL
,
JT_ALL
,
JT_RANGE
,
JT_NEXT
,
JT_FT
,
JT_REF_OR_NULL
,
JT_SIMPLE_IN
,
JT_INDEX_IN
};
JT_SIMPLE_IN
,
JT_INDEX_IN
,
JT_INDEX_MERGE
};
class
JOIN
;
class
JOIN
;
...
@@ -85,7 +85,7 @@ typedef struct st_join_table {
...
@@ -85,7 +85,7 @@ typedef struct st_join_table {
KEYUSE
*
keyuse
;
/* pointer to first used key */
KEYUSE
*
keyuse
;
/* pointer to first used key */
SQL_SELECT
*
select
;
SQL_SELECT
*
select
;
COND
*
select_cond
;
COND
*
select_cond
;
QUICK_SELECT
*
quick
;
QUICK_SELECT
_I
*
quick
;
Item
*
on_expr
;
Item
*
on_expr
;
const
char
*
info
;
const
char
*
info
;
byte
*
null_ref_key
;
byte
*
null_ref_key
;
...
@@ -307,10 +307,14 @@ void copy_fields(TMP_TABLE_PARAM *param);
...
@@ -307,10 +307,14 @@ void copy_fields(TMP_TABLE_PARAM *param);
void
copy_funcs
(
Item
**
func_ptr
);
void
copy_funcs
(
Item
**
func_ptr
);
bool
create_myisam_from_heap
(
THD
*
thd
,
TABLE
*
table
,
TMP_TABLE_PARAM
*
param
,
bool
create_myisam_from_heap
(
THD
*
thd
,
TABLE
*
table
,
TMP_TABLE_PARAM
*
param
,
int
error
,
bool
ignore_last_dupp_error
);
int
error
,
bool
ignore_last_dupp_error
);
uint
find_shortest_key
(
TABLE
*
table
,
key_map
usable_keys
);
/* functions from opt_sum.cc */
/* functions from opt_sum.cc */
int
opt_sum_query
(
TABLE_LIST
*
tables
,
List
<
Item
>
&
all_fields
,
COND
*
conds
);
int
opt_sum_query
(
TABLE_LIST
*
tables
,
List
<
Item
>
&
all_fields
,
COND
*
conds
);
/* from sql_delete.cc, used by opt_range.cc */
extern
"C"
int
refposcmp2
(
void
*
arg
,
const
void
*
a
,
const
void
*
b
);
/* class to copying an field/item to a key struct */
/* class to copying an field/item to a key struct */
class
store_key
:
public
Sql_alloc
class
store_key
:
public
Sql_alloc
...
...
sql/sql_test.cc
View file @
1c61a92b
...
@@ -179,9 +179,39 @@ TEST_join(JOIN *join)
...
@@ -179,9 +179,39 @@ TEST_join(JOIN *join)
" quick select checked for each record (keys: %d)
\n
"
,
" quick select checked for each record (keys: %d)
\n
"
,
(
int
)
tab
->
select
->
quick_keys
);
(
int
)
tab
->
select
->
quick_keys
);
else
if
(
tab
->
select
->
quick
)
else
if
(
tab
->
select
->
quick
)
fprintf
(
DBUG_FILE
,
" quick select used on key %s, length: %d
\n
"
,
{
int
quick_type
=
tab
->
select
->
quick
->
get_type
();
if
((
quick_type
==
QUICK_SELECT_I
::
QS_TYPE_RANGE
)
||
(
quick_type
==
QUICK_SELECT_I
::
QS_TYPE_RANGE_DESC
))
{
fprintf
(
DBUG_FILE
,
" quick select used on key %s, length: %d
\n
"
,
form
->
key_info
[
tab
->
select
->
quick
->
index
].
name
,
form
->
key_info
[
tab
->
select
->
quick
->
index
].
name
,
tab
->
select
->
quick
->
max_used_key_length
);
tab
->
select
->
quick
->
max_used_key_length
);
}
else
if
(
quick_type
==
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
{
QUICK_INDEX_MERGE_SELECT
*
quick_imerge
=
(
QUICK_INDEX_MERGE_SELECT
*
)
tab
->
select
->
quick
;
QUICK_RANGE_SELECT
*
quick
;
fprintf
(
DBUG_FILE
,
" index_merge quick select used
\n
"
);
List_iterator_fast
<
QUICK_RANGE_SELECT
>
it
(
quick_imerge
->
quick_selects
);
while
((
quick
=
it
++
))
{
fprintf
(
DBUG_FILE
,
" range quick select: key %s, length: %d
\n
"
,
form
->
key_info
[
quick
->
index
].
name
,
quick
->
max_used_key_length
);
}
}
else
{
fprintf
(
DBUG_FILE
,
" quick select of unknown nature used
\n
"
);
}
}
else
else
VOID
(
fputs
(
" select used
\n
"
,
DBUG_FILE
));
VOID
(
fputs
(
" select used
\n
"
,
DBUG_FILE
));
}
}
...
...
sql/sql_union.cc
View file @
1c61a92b
...
@@ -117,7 +117,8 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
...
@@ -117,7 +117,8 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
{
{
SELECT_LEX
*
lex_select_save
=
thd
->
lex
.
current_select
;
SELECT_LEX
*
lex_select_save
=
thd
->
lex
.
current_select
;
SELECT_LEX
*
select_cursor
;
SELECT_LEX
*
select_cursor
;
DBUG_ENTER
(
"st_select_lex_unit::prepare"
);
SELECT_LEX
*
sl
;
DBUG_ENTER
(
"st_select_lex_unit::prepare"
);
if
(
prepared
)
if
(
prepared
)
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
...
@@ -185,7 +186,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
...
@@ -185,7 +186,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
union_result
->
not_describe
=
1
;
union_result
->
not_describe
=
1
;
union_result
->
tmp_table_param
=
tmp_table_param
;
union_result
->
tmp_table_param
=
tmp_table_param
;
for
(
SELECT_LEX
*
sl
=
select_cursor
;
sl
;
sl
=
sl
->
next_select
())
for
(
sl
=
select_cursor
;
sl
;
sl
=
sl
->
next_select
())
{
{
JOIN
*
join
=
new
JOIN
(
thd
,
sl
->
item_list
,
JOIN
*
join
=
new
JOIN
(
thd
,
sl
->
item_list
,
sl
->
options
|
thd
->
options
|
SELECT_NO_UNLOCK
,
sl
->
options
|
thd
->
options
|
SELECT_NO_UNLOCK
,
...
...
sql/sql_update.cc
View file @
1c61a92b
...
@@ -171,10 +171,18 @@ int mysql_update(THD *thd,
...
@@ -171,10 +171,18 @@ int mysql_update(THD *thd,
init_ftfuncs
(
thd
,
&
thd
->
lex
.
select_lex
,
1
);
init_ftfuncs
(
thd
,
&
thd
->
lex
.
select_lex
,
1
);
/* Check if we are modifying a key that we are used to search with */
/* Check if we are modifying a key that we are used to search with */
if
(
select
&&
select
->
quick
)
if
(
select
&&
select
->
quick
)
used_key_is_modified
=
(
!
select
->
quick
->
unique_key_range
()
&&
{
check_if_key_used
(
table
,
if
(
select
->
quick
->
get_type
()
!=
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
(
used_index
=
select
->
quick
->
index
),
{
fields
));
used_index
=
select
->
quick
->
index
;
used_key_is_modified
=
(
!
select
->
quick
->
unique_key_range
()
&&
check_if_key_used
(
table
,
used_index
,
fields
));
}
else
{
used_key_is_modified
=
true
;
}
}
else
if
((
used_index
=
table
->
file
->
key_used_on_scan
)
<
MAX_KEY
)
else
if
((
used_index
=
table
->
file
->
key_used_on_scan
)
<
MAX_KEY
)
used_key_is_modified
=
check_if_key_used
(
table
,
used_index
,
fields
);
used_key_is_modified
=
check_if_key_used
(
table
,
used_index
,
fields
);
else
else
...
@@ -688,8 +696,26 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
...
@@ -688,8 +696,26 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
case
JT_ALL
:
case
JT_ALL
:
/* If range search on index */
/* If range search on index */
if
(
join_tab
->
quick
)
if
(
join_tab
->
quick
)
return
!
check_if_key_used
(
table
,
join_tab
->
quick
->
index
,
{
*
fields
);
if
(
join_tab
->
quick
->
get_type
()
!=
QUICK_SELECT_I
::
QS_TYPE_INDEX_MERGE
)
{
return
!
check_if_key_used
(
table
,
join_tab
->
quick
->
index
,
*
fields
);
}
else
{
QUICK_INDEX_MERGE_SELECT
*
qsel_imerge
=
(
QUICK_INDEX_MERGE_SELECT
*
)(
join_tab
->
quick
);
List_iterator_fast
<
QUICK_RANGE_SELECT
>
it
(
qsel_imerge
->
quick_selects
);
QUICK_RANGE_SELECT
*
quick
;
while
((
quick
=
it
++
))
{
if
(
check_if_key_used
(
table
,
quick
->
index
,
*
fields
))
return
0
;
}
return
1
;
}
}
/* If scanning in clustered key */
/* If scanning in clustered key */
if
((
table
->
file
->
table_flags
()
&
HA_PRIMARY_KEY_IN_READ_INDEX
)
&&
if
((
table
->
file
->
table_flags
()
&
HA_PRIMARY_KEY_IN_READ_INDEX
)
&&
table
->
primary_key
<
MAX_KEY
)
table
->
primary_key
<
MAX_KEY
)
...
...
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