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
a19eee45
Commit
a19eee45
authored
Oct 11, 2004
by
timour@mysql.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Manual merge with implementation for WL#1724
parent
f2a78b13
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
282 additions
and
205 deletions
+282
-205
sql/opt_range.cc
sql/opt_range.cc
+38
-17
sql/sql_select.cc
sql/sql_select.cc
+244
-188
No files found.
sql/opt_range.cc
View file @
a19eee45
...
@@ -1672,8 +1672,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
...
@@ -1672,8 +1672,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if
(
!
head
->
used_keys
.
is_clear_all
())
if
(
!
head
->
used_keys
.
is_clear_all
())
{
{
int
key_for_use
=
find_shortest_key
(
head
,
&
head
->
used_keys
);
int
key_for_use
=
find_shortest_key
(
head
,
&
head
->
used_keys
);
double
key_read_time
=
get_index_only_read_time
(
&
param
,
records
,
double
key_read_time
=
(
get_index_only_read_time
(
&
param
,
records
,
key_for_use
);
key_for_use
)
+
(
double
)
records
/
TIME_FOR_COMPARE
);
DBUG_PRINT
(
"info"
,
(
"'all'+'using index' scan will be using key %d, "
DBUG_PRINT
(
"info"
,
(
"'all'+'using index' scan will be using key %d, "
"read time %g"
,
key_for_use
,
key_read_time
));
"read time %g"
,
key_for_use
,
key_read_time
));
if
(
key_read_time
<
read_time
)
if
(
key_read_time
<
read_time
)
...
@@ -2176,6 +2177,12 @@ skip_to_ror_scan:
...
@@ -2176,6 +2177,12 @@ skip_to_ror_scan:
assumed that each time we read the next key from the index, the handler
assumed that each time we read the next key from the index, the handler
performs a random seek, thus the cost is proportional to the number of
performs a random seek, thus the cost is proportional to the number of
blocks read.
blocks read.
TODO:
Move this to handler->read_time() by adding a flag 'index-only-read' to
this call. The reason for doing this is that the current function doesn't
handle the case when the row is stored in the b-tree (like in innodb
clustered index)
*/
*/
inline
double
get_index_only_read_time
(
const
PARAM
*
param
,
ha_rows
records
,
inline
double
get_index_only_read_time
(
const
PARAM
*
param
,
ha_rows
records
,
...
@@ -2190,6 +2197,7 @@ inline double get_index_only_read_time(const PARAM* param, ha_rows records,
...
@@ -2190,6 +2197,7 @@ inline double get_index_only_read_time(const PARAM* param, ha_rows records,
return
read_time
;
return
read_time
;
}
}
typedef
struct
st_ror_scan_info
typedef
struct
st_ror_scan_info
{
{
uint
idx
;
/* # of used key in param->keys */
uint
idx
;
/* # of used key in param->keys */
...
@@ -3056,22 +3064,24 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
...
@@ -3056,22 +3064,24 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
tree
->
n_ror_scans
++
;
tree
->
n_ror_scans
++
;
tree
->
ror_scans_map
.
set_bit
(
idx
);
tree
->
ror_scans_map
.
set_bit
(
idx
);
}
}
double
cpu_cost
=
(
double
)
found_records
/
TIME_FOR_COMPARE
;
if
(
found_records
!=
HA_POS_ERROR
&&
found_records
>
2
&&
if
(
found_records
!=
HA_POS_ERROR
&&
found_records
>
2
&&
read_index_only
&&
read_index_only
&&
(
param
->
table
->
file
->
index_flags
(
keynr
,
param
->
max_key_part
,
1
)
&
(
param
->
table
->
file
->
index_flags
(
keynr
,
param
->
max_key_part
,
1
)
&
HA_KEYREAD_ONLY
)
&&
HA_KEYREAD_ONLY
)
&&
!
(
pk_is_clustered
&&
keynr
==
param
->
table
->
primary_key
))
!
(
pk_is_clustered
&&
keynr
==
param
->
table
->
primary_key
))
/* We can resolve this by only reading through this key. */
/* We can resolve this by only reading through this key. */
found_read_time
=
get_index_only_read_time
(
param
,
found_records
,
keynr
);
found_read_time
=
get_index_only_read_time
(
param
,
found_records
,
keynr
)
+
cpu_cost
;
else
else
/*
/*
cost(read_through_index) = cost(disk_io) + cost(row_in_range_checks)
cost(read_through_index) = cost(disk_io) + cost(row_in_range_checks)
The row_in_range check is in QUICK_RANGE_SELECT::cmp_next function.
The row_in_range check is in QUICK_RANGE_SELECT::cmp_next function.
*/
*/
found_read_time
=
(
param
->
table
->
file
->
read_time
(
keynr
,
found_read_time
=
param
->
table
->
file
->
read_time
(
keynr
,
param
->
range_count
,
param
->
range_count
,
found_records
)
+
found_records
)
+
(
double
)
found_records
/
TIME_FOR_COMPARE
)
;
cpu_cost
;
DBUG_PRINT
(
"info"
,(
"read_time: %g found_read_time: %g"
,
DBUG_PRINT
(
"info"
,(
"read_time: %g found_read_time: %g"
,
read_time
,
found_read_time
));
read_time
,
found_read_time
));
...
@@ -3424,6 +3434,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
...
@@ -3424,6 +3434,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
{
{
uint
maybe_null
=
(
uint
)
field
->
real_maybe_null
(),
copies
;
uint
maybe_null
=
(
uint
)
field
->
real_maybe_null
(),
copies
;
uint
field_length
=
field
->
pack_length
()
+
maybe_null
;
uint
field_length
=
field
->
pack_length
()
+
maybe_null
;
bool
optimize_range
;
SEL_ARG
*
tree
;
SEL_ARG
*
tree
;
char
*
str
,
*
str2
;
char
*
str
,
*
str2
;
DBUG_ENTER
(
"get_mm_leaf"
);
DBUG_ENTER
(
"get_mm_leaf"
);
...
@@ -3454,6 +3465,9 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
...
@@ -3454,6 +3465,9 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
((
Field_str
*
)
field
)
->
charset
()
!=
conf_func
->
compare_collation
())
((
Field_str
*
)
field
)
->
charset
()
!=
conf_func
->
compare_collation
())
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
optimize_range
=
field
->
optimize_range
(
param
->
real_keynr
[
key_part
->
key
],
key_part
->
part
);
if
(
type
==
Item_func
::
LIKE_FUNC
)
if
(
type
==
Item_func
::
LIKE_FUNC
)
{
{
bool
like_error
;
bool
like_error
;
...
@@ -3461,8 +3475,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
...
@@ -3461,8 +3475,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
String
tmp
(
buff1
,
sizeof
(
buff1
),
value
->
collation
.
collation
),
*
res
;
String
tmp
(
buff1
,
sizeof
(
buff1
),
value
->
collation
.
collation
),
*
res
;
uint
length
,
offset
,
min_length
,
max_length
;
uint
length
,
offset
,
min_length
,
max_length
;
if
(
!
field
->
optimize_range
(
param
->
real_keynr
[
key_part
->
key
],
if
(
!
optimize_range
)
key_part
->
part
))
DBUG_RETURN
(
0
);
// Can't optimize this
DBUG_RETURN
(
0
);
// Can't optimize this
if
(
!
(
res
=
value
->
val_str
(
&
tmp
)))
if
(
!
(
res
=
value
->
val_str
(
&
tmp
)))
DBUG_RETURN
(
&
null_element
);
DBUG_RETURN
(
&
null_element
);
...
@@ -3527,8 +3540,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
...
@@ -3527,8 +3540,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
DBUG_RETURN
(
new
SEL_ARG
(
field
,
min_str
,
max_str
));
DBUG_RETURN
(
new
SEL_ARG
(
field
,
min_str
,
max_str
));
}
}
if
(
!
field
->
optimize_range
(
param
->
real_keynr
[
key_part
->
key
],
if
(
!
optimize_range
&&
key_part
->
part
)
&&
type
!=
Item_func
::
EQ_FUNC
&&
type
!=
Item_func
::
EQ_FUNC
&&
type
!=
Item_func
::
EQUAL_FUNC
)
type
!=
Item_func
::
EQUAL_FUNC
)
DBUG_RETURN
(
0
);
// Can't optimize this
DBUG_RETURN
(
0
);
// Can't optimize this
...
@@ -3542,7 +3554,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
...
@@ -3542,7 +3554,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
field
->
cmp_type
()
!=
value
->
result_type
())
field
->
cmp_type
()
!=
value
->
result_type
())
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
if
(
value
->
save_in_field
(
field
,
1
)
<
0
)
if
(
value
->
save_in_field
_no_warnings
(
field
,
1
)
<
0
)
{
{
/* This happens when we try to insert a NULL field in a not null column */
/* This happens when we try to insert a NULL field in a not null column */
DBUG_RETURN
(
&
null_element
);
// cmp with NULL is never TRUE
DBUG_RETURN
(
&
null_element
);
// cmp with NULL is never TRUE
...
@@ -3736,13 +3748,14 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
...
@@ -3736,13 +3748,14 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
if
(
*
key2
&&
!
(
*
key2
)
->
simple_key
())
if
(
*
key2
&&
!
(
*
key2
)
->
simple_key
())
flag
|=
CLONE_KEY2_MAYBE
;
flag
|=
CLONE_KEY2_MAYBE
;
*
key1
=
key_and
(
*
key1
,
*
key2
,
flag
);
*
key1
=
key_and
(
*
key1
,
*
key2
,
flag
);
if
((
*
key1
)
->
type
==
SEL_ARG
::
IMPOSSIBLE
)
if
(
*
key1
&&
(
*
key1
)
->
type
==
SEL_ARG
::
IMPOSSIBLE
)
{
{
tree1
->
type
=
SEL_TREE
::
IMPOSSIBLE
;
tree1
->
type
=
SEL_TREE
::
IMPOSSIBLE
;
DBUG_RETURN
(
tree1
);
DBUG_RETURN
(
tree1
);
}
}
result_keys
.
set_bit
(
key1
-
tree1
->
keys
);
result_keys
.
set_bit
(
key1
-
tree1
->
keys
);
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
if
(
*
key1
)
(
*
key1
)
->
test_use_count
(
*
key1
);
(
*
key1
)
->
test_use_count
(
*
key1
);
#endif
#endif
}
}
...
@@ -3974,6 +3987,13 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
...
@@ -3974,6 +3987,13 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
return
key1
;
return
key1
;
}
}
if
((
key1
->
min_flag
|
key2
->
min_flag
)
&
GEOM_FLAG
)
{
key1
->
free_tree
();
key2
->
free_tree
();
return
0
;
// Can't optimize this
}
key1
->
use_count
--
;
key1
->
use_count
--
;
key2
->
use_count
--
;
key2
->
use_count
--
;
SEL_ARG
*
e1
=
key1
->
first
(),
*
e2
=
key2
->
first
(),
*
new_tree
=
0
;
SEL_ARG
*
e1
=
key1
->
first
(),
*
e2
=
key2
->
first
(),
*
new_tree
=
0
;
...
@@ -4056,7 +4076,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
...
@@ -4056,7 +4076,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
key1
->
use_count
--
;
key1
->
use_count
--
;
key2
->
use_count
--
;
key2
->
use_count
--
;
if
(
key1
->
part
!=
key2
->
part
)
if
(
key1
->
part
!=
key2
->
part
||
(
key1
->
min_flag
|
key2
->
min_flag
)
&
GEOM_FLAG
)
{
{
key1
->
free_tree
();
key1
->
free_tree
();
key2
->
free_tree
();
key2
->
free_tree
();
...
@@ -4716,7 +4737,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
...
@@ -4716,7 +4737,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
ulong
count
=
count_key_part_usage
(
root
,
pos
->
next_key_part
);
ulong
count
=
count_key_part_usage
(
root
,
pos
->
next_key_part
);
if
(
count
>
pos
->
next_key_part
->
use_count
)
if
(
count
>
pos
->
next_key_part
->
use_count
)
{
{
sql_print_error
(
"Note: Use_count: Wrong count for key at %lx, %lu should be %lu"
,
sql_print_error
(
"Note: Use_count: Wrong count for key at
0x
%lx, %lu should be %lu"
,
pos
,
pos
->
next_key_part
->
use_count
,
count
);
pos
,
pos
->
next_key_part
->
use_count
,
count
);
return
;
return
;
}
}
...
@@ -4724,7 +4745,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
...
@@ -4724,7 +4745,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
}
}
}
}
if
(
e_count
!=
elements
)
if
(
e_count
!=
elements
)
sql_print_error
(
"Warning: Wrong use count: %u (should be %u) for tree at %lx"
,
sql_print_error
(
"Warning: Wrong use count: %u (should be %u) for tree at
0x
%lx"
,
e_count
,
elements
,
(
gptr
)
this
);
e_count
,
elements
,
(
gptr
)
this
);
}
}
...
...
sql/sql_select.cc
View file @
a19eee45
...
@@ -226,27 +226,13 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
...
@@ -226,27 +226,13 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
thd
->
net
.
report_error
));
thd
->
net
.
report_error
));
if
(
thd
->
net
.
report_error
)
if
(
thd
->
net
.
report_error
)
res
=
1
;
res
=
1
;
if
(
res
>
0
)
if
(
unlikely
(
res
))
{
if
(
result
)
{
{
if
(
res
>
0
)
result
->
send_error
(
0
,
NullS
);
result
->
send_error
(
0
,
NullS
);
result
->
abort
();
result
->
abort
();
}
else
send_error
(
thd
,
0
,
NullS
);
res
=
1
;
// Error sent to client
res
=
1
;
// Error sent to client
}
}
if
(
res
<
0
)
{
if
(
result
)
{
result
->
abort
();
}
res
=
1
;
}
if
(
result
!=
lex
->
result
)
delete
result
;
DBUG_RETURN
(
res
);
DBUG_RETURN
(
res
);
}
}
...
@@ -349,9 +335,7 @@ JOIN::prepare(Item ***rref_pointer_array,
...
@@ -349,9 +335,7 @@ JOIN::prepare(Item ***rref_pointer_array,
if
((
subselect
=
select_lex
->
master_unit
()
->
item
))
if
((
subselect
=
select_lex
->
master_unit
()
->
item
))
{
{
Item_subselect
::
trans_res
res
;
Item_subselect
::
trans_res
res
;
if
((
res
=
((
!
thd
->
lex
->
view_prepare_mode
)
?
if
((
res
=
subselect
->
select_transformer
(
this
))
!=
subselect
->
select_transformer
(
this
)
:
subselect
->
no_select_transform
()))
!=
Item_subselect
::
RES_OK
)
Item_subselect
::
RES_OK
)
{
{
select_lex
->
fix_prepare_information
(
thd
,
&
conds
);
select_lex
->
fix_prepare_information
(
thd
,
&
conds
);
...
@@ -553,6 +537,7 @@ JOIN::optimize()
...
@@ -553,6 +537,7 @@ JOIN::optimize()
if
(
cond_value
==
Item
::
COND_FALSE
||
if
(
cond_value
==
Item
::
COND_FALSE
||
(
!
unit
->
select_limit_cnt
&&
!
(
select_options
&
OPTION_FOUND_ROWS
)))
(
!
unit
->
select_limit_cnt
&&
!
(
select_options
&
OPTION_FOUND_ROWS
)))
{
/* Impossible cond */
{
/* Impossible cond */
DBUG_PRINT
(
"info"
,
(
"Impossible WHERE"
));
zero_result_cause
=
"Impossible WHERE"
;
zero_result_cause
=
"Impossible WHERE"
;
error
=
0
;
error
=
0
;
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
...
@@ -570,20 +555,24 @@ JOIN::optimize()
...
@@ -570,20 +555,24 @@ JOIN::optimize()
{
{
if
(
res
>
1
)
if
(
res
>
1
)
{
{
DBUG_PRINT
(
"error"
,(
"Error from opt_sum_query"
));
DBUG_RETURN
(
1
);
DBUG_RETURN
(
1
);
}
}
if
(
res
<
0
)
if
(
res
<
0
)
{
{
DBUG_PRINT
(
"info"
,(
"No matching min/max row"
));
zero_result_cause
=
"No matching min/max row"
;
zero_result_cause
=
"No matching min/max row"
;
error
=
0
;
error
=
0
;
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
}
}
DBUG_PRINT
(
"info"
,(
"Select tables optimized away"
));
zero_result_cause
=
"Select tables optimized away"
;
zero_result_cause
=
"Select tables optimized away"
;
tables_list
=
0
;
// All tables resolved
tables_list
=
0
;
// All tables resolved
}
}
}
}
if
(
!
tables_list
)
if
(
!
tables_list
)
{
{
DBUG_PRINT
(
"info"
,(
"No tables"
));
error
=
0
;
error
=
0
;
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
}
}
...
@@ -777,6 +766,10 @@ JOIN::optimize()
...
@@ -777,6 +766,10 @@ JOIN::optimize()
(
select_lex
->
ftfunc_list
->
elements
?
(
select_lex
->
ftfunc_list
->
elements
?
SELECT_NO_JOIN_CACHE
:
0
));
SELECT_NO_JOIN_CACHE
:
0
));
/* Perform FULLTEXT search before all regular searches */
if
(
!
(
select_options
&
SELECT_DESCRIBE
))
init_ftfuncs
(
thd
,
select_lex
,
test
(
order
));
/*
/*
is this simple IN subquery?
is this simple IN subquery?
*/
*/
...
@@ -883,8 +876,7 @@ JOIN::optimize()
...
@@ -883,8 +876,7 @@ JOIN::optimize()
((
group_list
&&
const_tables
!=
tables
&&
((
group_list
&&
const_tables
!=
tables
&&
(
!
simple_group
||
(
!
simple_group
||
!
test_if_skip_sort_order
(
&
join_tab
[
const_tables
],
group_list
,
!
test_if_skip_sort_order
(
&
join_tab
[
const_tables
],
group_list
,
unit
->
select_limit_cnt
,
unit
->
select_limit_cnt
,
0
)))
||
0
)))
||
select_distinct
)
&&
select_distinct
)
&&
tmp_table_param
.
quick_group
&&
!
procedure
)
tmp_table_param
.
quick_group
&&
!
procedure
)
{
{
...
@@ -899,8 +891,6 @@ JOIN::optimize()
...
@@ -899,8 +891,6 @@ JOIN::optimize()
}
}
having
=
0
;
having
=
0
;
/* Perform FULLTEXT search before all regular searches */
init_ftfuncs
(
thd
,
select_lex
,
test
(
order
));
/* Create a tmp table if distinct or if the sort is too complicated */
/* Create a tmp table if distinct or if the sort is too complicated */
if
(
need_tmp
)
if
(
need_tmp
)
{
{
...
@@ -2572,7 +2562,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond,
...
@@ -2572,7 +2562,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond,
bool
is_const
=
1
;
bool
is_const
=
1
;
for
(
uint
i
=
0
;
i
<
num_values
;
i
++
)
for
(
uint
i
=
0
;
i
<
num_values
;
i
++
)
/*
/*
TODO:
this looks like a bug,
should be
TODO:
This looks like a bug. It
should be
is_const&= (value[i])->const_item();
is_const&= (value[i])->const_item();
*/
*/
is_const
&=
(
*
value
)
->
const_item
();
is_const
&=
(
*
value
)
->
const_item
();
...
@@ -2583,22 +2573,32 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond,
...
@@ -2583,22 +2573,32 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond,
number. cmp_type() is checked to allow compare of dates to numbers.
number. cmp_type() is checked to allow compare of dates to numbers.
eq_func is NEVER true when num_values > 1
eq_func is NEVER true when num_values > 1
*/
*/
if
(
!
eq_func
||
if
(
!
eq_func
)
field
->
result_type
()
==
STRING_RESULT
&&
(
*
value
)
->
result_type
()
!=
STRING_RESULT
&&
field
->
cmp_type
()
!=
(
*
value
)
->
result_type
())
return
;
return
;
if
(
field
->
result_type
()
==
STRING_RESULT
)
{
if
((
*
value
)
->
result_type
()
!=
STRING_RESULT
)
{
if
(
field
->
cmp_type
()
!=
(
*
value
)
->
result_type
())
return
;
}
else
{
/*
/*
We can't use indexes if the effective collation
We can't use indexes if the effective collation
of the operation differ from the field collation.
of the operation differ from the field collation.
We also cannot use index on a text column, as the column may
contain 'x' 'x\t' 'x ' and 'read_next_same' will stop after
'x' when searching for WHERE col='x '
*/
*/
if
(
field
->
result
_type
()
==
STRING_RESULT
&&
if
(
field
->
cmp
_type
()
==
STRING_RESULT
&&
(
*
value
)
->
result_type
()
==
STRING_RESULT
&&
(((
Field_str
*
)
field
)
->
charset
()
!=
cond
->
compare_collation
()
||
field
->
cmp_type
()
==
STRING_RESULT
&&
((
*
value
)
->
type
()
!=
Item
::
NULL_ITEM
&&
((
Field_str
*
)
field
)
->
charset
()
!=
cond
->
compare_collation
(
))
(
field
->
flags
&
BLOB_FLAG
)
&&
!
field
->
binary
())
))
return
;
return
;
}
}
}
}
}
}
DBUG_ASSERT
(
num_values
==
1
);
DBUG_ASSERT
(
num_values
==
1
);
...
@@ -2701,7 +2701,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
...
@@ -2701,7 +2701,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
!
(
cond_func
->
used_tables
()
&
OUTER_REF_TABLE_BIT
))
!
(
cond_func
->
used_tables
()
&
OUTER_REF_TABLE_BIT
))
{
{
Item
*
tmp
=
new
Item_null
;
Item
*
tmp
=
new
Item_null
;
if
(
!
tmp
)
// Should never be true
if
(
unlikely
(
!
tmp
))
// Should never be true
return
;
return
;
add_key_field
(
key_fields
,
*
and_level
,
cond_func
,
add_key_field
(
key_fields
,
*
and_level
,
cond_func
,
((
Item_field
*
)
(
cond_func
->
arguments
()[
0
])
->
real_item
())
((
Item_field
*
)
(
cond_func
->
arguments
()[
0
])
->
real_item
())
...
@@ -4135,7 +4135,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
...
@@ -4135,7 +4135,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
rec
=
keyuse
->
ref_table_rows
;
rec
=
keyuse
->
ref_table_rows
;
/*
/*
If there is one 'key_column IS NULL' expression, we can
If there is one 'key_column IS NULL' expression, we can
use this ref_or_null optimsation of this field
use this ref_or_null optim
i
sation of this field
*/
*/
found_ref_or_null
|=
(
keyuse
->
optimize
&
found_ref_or_null
|=
(
keyuse
->
optimize
&
KEY_OPTIMIZE_REF_OR_NULL
);
KEY_OPTIMIZE_REF_OR_NULL
);
...
@@ -4652,6 +4652,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
...
@@ -4652,6 +4652,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
store_key
**
ref_key
=
j
->
ref
.
key_copy
;
store_key
**
ref_key
=
j
->
ref
.
key_copy
;
byte
*
key_buff
=
j
->
ref
.
key_buff
,
*
null_ref_key
=
0
;
byte
*
key_buff
=
j
->
ref
.
key_buff
,
*
null_ref_key
=
0
;
bool
keyuse_uses_no_tables
=
TRUE
;
if
(
ftkey
)
if
(
ftkey
)
{
{
j
->
ref
.
items
[
0
]
=
((
Item_func
*
)(
keyuse
->
val
))
->
key_item
();
j
->
ref
.
items
[
0
]
=
((
Item_func
*
)(
keyuse
->
val
))
->
key_item
();
...
@@ -4671,6 +4672,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
...
@@ -4671,6 +4672,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
uint
maybe_null
=
test
(
keyinfo
->
key_part
[
i
].
null_bit
);
uint
maybe_null
=
test
(
keyinfo
->
key_part
[
i
].
null_bit
);
j
->
ref
.
items
[
i
]
=
keyuse
->
val
;
// Save for cond removal
j
->
ref
.
items
[
i
]
=
keyuse
->
val
;
// Save for cond removal
keyuse_uses_no_tables
=
keyuse_uses_no_tables
&&
!
keyuse
->
used_tables
;
if
(
!
keyuse
->
used_tables
&&
if
(
!
keyuse
->
used_tables
&&
!
(
join
->
select_options
&
SELECT_DESCRIBE
))
!
(
join
->
select_options
&
SELECT_DESCRIBE
))
{
// Compare against constant
{
// Compare against constant
...
@@ -4710,7 +4712,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
...
@@ -4710,7 +4712,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
j
->
type
=
null_ref_key
?
JT_REF_OR_NULL
:
JT_REF
;
j
->
type
=
null_ref_key
?
JT_REF_OR_NULL
:
JT_REF
;
j
->
ref
.
null_ref_key
=
null_ref_key
;
j
->
ref
.
null_ref_key
=
null_ref_key
;
}
}
else
if
(
ref_key
==
j
->
ref
.
key_copy
)
else
if
(
keyuse_uses_no_tables
)
{
{
/*
/*
This happen if we are using a constant expression in the ON part
This happen if we are using a constant expression in the ON part
...
@@ -4971,6 +4973,28 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
...
@@ -4971,6 +4973,28 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
COND
*
const_cond
=
COND
*
const_cond
=
make_cond_for_table
(
cond
,
join
->
const_table_map
,(
table_map
)
0
);
make_cond_for_table
(
cond
,
join
->
const_table_map
,(
table_map
)
0
);
DBUG_EXECUTE
(
"where"
,
print_where
(
const_cond
,
"constants"
););
DBUG_EXECUTE
(
"where"
,
print_where
(
const_cond
,
"constants"
););
for
(
JOIN_TAB
*
tab
=
join
->
join_tab
+
join
->
const_tables
;
tab
<
join
->
join_tab
+
join
->
tables
;
tab
++
)
{
if
(
tab
->
on_expr
)
{
JOIN_TAB
*
cond_tab
=
tab
->
first_inner
;
COND
*
tmp
=
make_cond_for_table
(
tab
->
on_expr
,
join
->
const_table_map
,
(
table_map
)
0
);
if
(
!
tmp
)
continue
;
tmp
=
new
Item_func_trig_cond
(
tmp
,
&
cond_tab
->
not_null_compl
);
if
(
!
tmp
)
DBUG_RETURN
(
1
);
tmp
->
quick_fix_field
();
cond_tab
->
select_cond
=
!
cond_tab
->
select_cond
?
tmp
:
new
Item_cond_and
(
cond_tab
->
select_cond
,
tmp
);
if
(
!
cond_tab
->
select_cond
)
DBUG_RETURN
(
1
);
cond_tab
->
select_cond
->
quick_fix_field
();
}
}
if
(
const_cond
&&
!
const_cond
->
val_int
())
if
(
const_cond
&&
!
const_cond
->
val_int
())
{
{
DBUG_PRINT
(
"info"
,(
"Found impossible WHERE condition"
));
DBUG_PRINT
(
"info"
,(
"Found impossible WHERE condition"
));
...
@@ -4985,13 +5009,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
...
@@ -4985,13 +5009,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
JOIN_TAB
*
tab
=
join
->
join_tab
+
i
;
JOIN_TAB
*
tab
=
join
->
join_tab
+
i
;
JOIN_TAB
*
first_inner_tab
=
tab
->
first_inner
;
JOIN_TAB
*
first_inner_tab
=
tab
->
first_inner
;
table_map
current_map
=
tab
->
table
->
map
;
table_map
current_map
=
tab
->
table
->
map
;
bool
use_quick_range
=
0
;
/*
/*
Following force including random expression in last table condition.
Following force including random expression in last table condition.
It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5
It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5
*/
*/
if
(
i
==
join
->
tables
-
1
)
if
(
i
==
join
->
tables
-
1
)
current_map
|=
OUTER_REF_TABLE_BIT
|
RAND_TABLE_BIT
;
current_map
|=
OUTER_REF_TABLE_BIT
|
RAND_TABLE_BIT
;
bool
use_quick_range
=
0
;
used_tables
|=
current_map
;
used_tables
|=
current_map
;
if
(
tab
->
type
==
JT_REF
&&
tab
->
quick
&&
if
(
tab
->
type
==
JT_REF
&&
tab
->
quick
&&
...
@@ -5012,11 +5036,26 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
...
@@ -5012,11 +5036,26 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
tmp
=
make_cond_for_table
(
cond
,
used_tables
,
current_map
);
tmp
=
make_cond_for_table
(
cond
,
used_tables
,
current_map
);
if
(
cond
&&
!
tmp
&&
tab
->
quick
)
if
(
cond
&&
!
tmp
&&
tab
->
quick
)
{
// Outer join
{
// Outer join
if
(
tab
->
type
!=
JT_ALL
)
{
/*
Don't use the quick method
We come here in the case where we have 'key=constant' and
the test is removed by make_cond_for_table()
*/
delete
tab
->
quick
;
tab
->
quick
=
0
;
}
else
{
/*
/*
Hack to handle the case where we only refer to a table
Hack to handle the case where we only refer to a table
in the ON part of an OUTER JOIN.
in the ON part of an OUTER JOIN. In this case we want the code
below to check if we should use 'quick' instead.
*/
*/
tmp
=
new
Item_int
((
longlong
)
1
,
1
);
// Always true
tmp
=
new
Item_int
((
longlong
)
1
,
1
);
// Always true
}
}
}
if
(
tmp
||
!
cond
)
if
(
tmp
||
!
cond
)
{
{
...
@@ -5217,6 +5256,7 @@ static void
...
@@ -5217,6 +5256,7 @@ static void
make_join_readinfo
(
JOIN
*
join
,
uint
options
)
make_join_readinfo
(
JOIN
*
join
,
uint
options
)
{
{
uint
i
;
uint
i
;
bool
statistics
=
test
(
!
(
join
->
select_options
&
SELECT_DESCRIBE
));
bool
statistics
=
test
(
!
(
join
->
select_options
&
SELECT_DESCRIBE
));
DBUG_ENTER
(
"make_join_readinfo"
);
DBUG_ENTER
(
"make_join_readinfo"
);
...
@@ -5315,7 +5355,8 @@ make_join_readinfo(JOIN *join, uint options)
...
@@ -5315,7 +5355,8 @@ make_join_readinfo(JOIN *join, uint options)
join
->
thd
->
server_status
|=
SERVER_QUERY_NO_GOOD_INDEX_USED
;
join
->
thd
->
server_status
|=
SERVER_QUERY_NO_GOOD_INDEX_USED
;
tab
->
read_first_record
=
join_init_quick_read_record
;
tab
->
read_first_record
=
join_init_quick_read_record
;
if
(
statistics
)
if
(
statistics
)
statistic_increment
(
select_range_check_count
,
&
LOCK_status
);
statistic_increment
(
join
->
thd
->
status_var
.
select_range_check_count
,
&
LOCK_status
);
}
}
else
else
{
{
...
@@ -5325,13 +5366,15 @@ make_join_readinfo(JOIN *join, uint options)
...
@@ -5325,13 +5366,15 @@ make_join_readinfo(JOIN *join, uint options)
if
(
tab
->
select
&&
tab
->
select
->
quick
)
if
(
tab
->
select
&&
tab
->
select
->
quick
)
{
{
if
(
statistics
)
if
(
statistics
)
statistic_increment
(
select_range_count
,
&
LOCK_status
);
statistic_increment
(
join
->
thd
->
status_var
.
select_range_count
,
&
LOCK_status
);
}
}
else
else
{
{
join
->
thd
->
server_status
|=
SERVER_QUERY_NO_INDEX_USED
;
join
->
thd
->
server_status
|=
SERVER_QUERY_NO_INDEX_USED
;
if
(
statistics
)
if
(
statistics
)
statistic_increment
(
select_scan_count
,
&
LOCK_status
);
statistic_increment
(
join
->
thd
->
status_var
.
select_scan_count
,
&
LOCK_status
);
}
}
}
}
else
else
...
@@ -5339,13 +5382,15 @@ make_join_readinfo(JOIN *join, uint options)
...
@@ -5339,13 +5382,15 @@ make_join_readinfo(JOIN *join, uint options)
if
(
tab
->
select
&&
tab
->
select
->
quick
)
if
(
tab
->
select
&&
tab
->
select
->
quick
)
{
{
if
(
statistics
)
if
(
statistics
)
statistic_increment
(
select_full_range_join_count
,
&
LOCK_status
);
statistic_increment
(
join
->
thd
->
status_var
.
select_full_range_join_count
,
&
LOCK_status
);
}
}
else
else
{
{
join
->
thd
->
server_status
|=
SERVER_QUERY_NO_INDEX_USED
;
join
->
thd
->
server_status
|=
SERVER_QUERY_NO_INDEX_USED
;
if
(
statistics
)
if
(
statistics
)
statistic_increment
(
select_full_join_count
,
&
LOCK_status
);
statistic_increment
(
join
->
thd
->
status_var
.
select_full_join_count
,
&
LOCK_status
);
}
}
}
}
if
(
!
table
->
no_keyread
)
if
(
!
table
->
no_keyread
)
...
@@ -5520,6 +5565,10 @@ JOIN::join_free(bool full)
...
@@ -5520,6 +5565,10 @@ JOIN::join_free(bool full)
if
(
full
)
if
(
full
)
{
{
group_fields
.
delete_elements
();
group_fields
.
delete_elements
();
/*
We can't call delete_elements() on copy_funcs as this will cause
problems in free_elements() as some of the elements are then deleted.
*/
tmp_table_param
.
copy_funcs
.
empty
();
tmp_table_param
.
copy_funcs
.
empty
();
tmp_table_param
.
cleanup
();
tmp_table_param
.
cleanup
();
}
}
...
@@ -5704,7 +5753,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
...
@@ -5704,7 +5753,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
}
}
if
((
ref
=
order_tables
&
(
not_const_tables
^
first_table
)))
if
((
ref
=
order_tables
&
(
not_const_tables
^
first_table
)))
{
{
if
(
only_eq_ref_tables
(
join
,
first_order
,
ref
))
if
(
!
(
order_tables
&
first_table
)
&&
only_eq_ref_tables
(
join
,
first_order
,
ref
))
{
{
DBUG_PRINT
(
"info"
,(
"removing: %s"
,
order
->
item
[
0
]
->
full_name
()));
DBUG_PRINT
(
"info"
,(
"removing: %s"
,
order
->
item
[
0
]
->
full_name
()));
continue
;
continue
;
...
@@ -5827,7 +5876,10 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
...
@@ -5827,7 +5876,10 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
Item
*
right_item
=
func
->
arguments
()[
1
];
Item
*
right_item
=
func
->
arguments
()[
1
];
Item_func
::
Functype
functype
=
func
->
functype
();
Item_func
::
Functype
functype
=
func
->
functype
();
if
(
right_item
->
eq
(
field
,
0
)
&&
left_item
!=
value
)
if
(
right_item
->
eq
(
field
,
0
)
&&
left_item
!=
value
&&
(
left_item
->
result_type
()
!=
STRING_RESULT
||
value
->
result_type
()
!=
STRING_RESULT
||
left_item
->
collation
.
collation
==
value
->
collation
.
collation
))
{
{
Item
*
tmp
=
value
->
new_item
();
Item
*
tmp
=
value
->
new_item
();
if
(
tmp
)
if
(
tmp
)
...
@@ -5845,7 +5897,10 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
...
@@ -5845,7 +5897,10 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
func
->
set_cmp_func
();
func
->
set_cmp_func
();
}
}
}
}
else
if
(
left_item
->
eq
(
field
,
0
)
&&
right_item
!=
value
)
else
if
(
left_item
->
eq
(
field
,
0
)
&&
right_item
!=
value
&&
(
right_item
->
result_type
()
!=
STRING_RESULT
||
value
->
result_type
()
!=
STRING_RESULT
||
right_item
->
collation
.
collation
==
value
->
collation
.
collation
))
{
{
Item
*
tmp
=
value
->
new_item
();
Item
*
tmp
=
value
->
new_item
();
if
(
tmp
)
if
(
tmp
)
...
@@ -5965,62 +6020,6 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
...
@@ -5965,62 +6020,6 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
}
}
/*
Eliminate NOT functions from the condition tree.
SYNPOSIS
eliminate_not_funcs()
thd thread handler
cond condition tree
DESCRIPTION
Eliminate NOT functions from the condition tree where it's possible.
Recursively traverse condition tree to find all NOT functions.
Call neg_transformer() method for negated arguments.
NOTE
If neg_transformer() returned a new condition we call fix_fields().
We don't delete any items as it's not needed. They will be deleted
later at once.
RETURN
New condition tree
*/
COND
*
eliminate_not_funcs
(
THD
*
thd
,
COND
*
cond
)
{
DBUG_ENTER
(
"eliminate_not_funcs"
);
if
(
!
cond
)
DBUG_RETURN
(
cond
);
if
(
cond
->
type
()
==
Item
::
COND_ITEM
)
/* OR or AND */
{
List_iterator
<
Item
>
li
(
*
((
Item_cond
*
)
cond
)
->
argument_list
());
Item
*
item
;
while
((
item
=
li
++
))
{
Item
*
new_item
=
eliminate_not_funcs
(
thd
,
item
);
if
(
item
!=
new_item
)
VOID
(
li
.
replace
(
new_item
));
/* replace item with a new condition */
}
}
else
if
(
cond
->
type
()
==
Item
::
FUNC_ITEM
&&
/* 'NOT' operation? */
((
Item_func
*
)
cond
)
->
functype
()
==
Item_func
::
NOT_FUNC
)
{
COND
*
new_cond
=
((
Item_func
*
)
cond
)
->
arguments
()[
0
]
->
neg_transformer
(
thd
);
if
(
new_cond
)
{
/*
Here we can delete the NOT function. Something like: delete cond;
But we don't need to do it. All items will be deleted later at once.
*/
cond
=
new_cond
;
}
}
DBUG_RETURN
(
cond
);
}
/*
/*
Simplify joins replacing outer joins by inner joins whenever it's possible
Simplify joins replacing outer joins by inner joins whenever it's possible
...
@@ -6085,9 +6084,9 @@ COND *eliminate_not_funcs(THD *thd, COND *cond)
...
@@ -6085,9 +6084,9 @@ COND *eliminate_not_funcs(THD *thd, COND *cond)
The function removes all unnecessary braces from the expression
The function removes all unnecessary braces from the expression
produced by the conversions.
produced by the conversions.
E.g. SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a t3.b=t1.b
E.g. SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a
AND
t3.b=t1.b
finally is converted to:
finally is converted to:
SELECT * FROM t1, t2, t3 WHERE t2.c < 5 AND t2.a=t1.a t3.b=t1.b
SELECT * FROM t1, t2, t3 WHERE t2.c < 5 AND t2.a=t1.a
AND
t3.b=t1.b
It also will remove braces from the following queries:
It also will remove braces from the following queries:
SELECT * from (t1 LEFT JOIN t2 ON t2.a=t1.a) LEFT JOIN t3 ON t3.b=t2.b
SELECT * from (t1 LEFT JOIN t2 ON t2.a=t1.a) LEFT JOIN t3 ON t3.b=t2.b
...
@@ -6122,6 +6121,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
...
@@ -6122,6 +6121,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
NESTED_JOIN
*
nested_join
;
NESTED_JOIN
*
nested_join
;
TABLE_LIST
*
prev_table
=
0
;
TABLE_LIST
*
prev_table
=
0
;
List_iterator
<
TABLE_LIST
>
li
(
*
join_list
);
List_iterator
<
TABLE_LIST
>
li
(
*
join_list
);
DBUG_ENTER
(
"simplify_joins"
);
/*
/*
Try to simplify join operations from join_list.
Try to simplify join operations from join_list.
...
@@ -6255,35 +6255,37 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
...
@@ -6255,35 +6255,37 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
li
.
replace
(
nested_join
->
join_list
);
li
.
replace
(
nested_join
->
join_list
);
}
}
}
}
return
conds
;
DBUG_RETURN
(
conds
)
;
}
}
static
COND
*
static
COND
*
optimize_cond
(
JOIN
*
join
,
COND
*
conds
,
Item
::
cond_result
*
cond_value
)
optimize_cond
(
JOIN
*
join
,
COND
*
conds
,
Item
::
cond_result
*
cond_value
)
{
{
DBUG_ENTER
(
"optimize_cond"
);
THD
*
thd
=
join
->
thd
;
THD
*
thd
=
join
->
thd
;
SELECT_LEX
*
select
=
thd
->
lex
->
current_select
;
SELECT_LEX
*
select
=
thd
->
lex
->
current_select
;
DBUG_ENTER
(
"optimize_cond"
);
if
(
select
->
first_cond_optimization
)
if
(
select
->
first_cond_optimization
)
{
{
Item_arena
*
arena
=
thd
->
current_arena
;
/*
Item_arena
backup
;
The following code will allocate the new items in a permanent
if
(
arena
)
MEMROOT for prepared statements and stored procedures.
*/
Item_arena
*
arena
=
thd
->
current_arena
,
backup
;
if
(
arena
->
is_conventional
())
arena
=
0
;
// For easier test
else
thd
->
set_n_backup_item_arena
(
arena
,
&
backup
);
thd
->
set_n_backup_item_arena
(
arena
,
&
backup
);
if
(
conds
)
select
->
first_cond_optimization
=
0
;
{
DBUG_EXECUTE
(
"where"
,
print_where
(
conds
,
"original"
););
/* eliminate NOT operators */
conds
=
eliminate_not_funcs
(
thd
,
conds
);
}
/* Convert all outer joins to inner joins if possible */
/* Convert all outer joins to inner joins if possible */
conds
=
simplify_joins
(
join
,
join
->
join_list
,
conds
,
TRUE
);
conds
=
simplify_joins
(
join
,
join
->
join_list
,
conds
,
TRUE
);
select
->
prep_where
=
conds
?
conds
->
copy_andor_structure
(
thd
)
:
0
;
select
->
prep_where
=
conds
?
conds
->
copy_andor_structure
(
thd
)
:
0
;
select
->
first_cond_optimization
=
0
;
if
(
arena
)
if
(
arena
)
thd
->
restore_backup_item_arena
(
arena
,
&
backup
);
thd
->
restore_backup_item_arena
(
arena
,
&
backup
);
}
}
...
@@ -6291,10 +6293,11 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
...
@@ -6291,10 +6293,11 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
if
(
!
conds
)
if
(
!
conds
)
{
{
*
cond_value
=
Item
::
COND_TRUE
;
*
cond_value
=
Item
::
COND_TRUE
;
DBUG_RETURN
(
conds
)
;
select
->
prep_where
=
0
;
}
}
else
DBUG_EXECUTE
(
"where"
,
print_where
(
conds
,
"after negation elimination"
););
{
DBUG_EXECUTE
(
"where"
,
print_where
(
conds
,
"original"
););
/* change field = field to field = const for each found field = const */
/* change field = field to field = const for each found field = const */
propagate_cond_constants
((
I_List
<
COND_CMP
>
*
)
0
,
conds
,
conds
);
propagate_cond_constants
((
I_List
<
COND_CMP
>
*
)
0
,
conds
,
conds
);
/*
/*
...
@@ -6304,6 +6307,7 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
...
@@ -6304,6 +6307,7 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
DBUG_EXECUTE
(
"where"
,
print_where
(
conds
,
"after const change"
););
DBUG_EXECUTE
(
"where"
,
print_where
(
conds
,
"after const change"
););
conds
=
remove_eq_conds
(
thd
,
conds
,
cond_value
)
;
conds
=
remove_eq_conds
(
thd
,
conds
,
cond_value
)
;
DBUG_EXECUTE
(
"info"
,
print_where
(
conds
,
"after remove"
););
DBUG_EXECUTE
(
"info"
,
print_where
(
conds
,
"after remove"
););
}
DBUG_RETURN
(
conds
);
DBUG_RETURN
(
conds
);
}
}
...
@@ -6767,7 +6771,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
...
@@ -6767,7 +6771,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
(
int
)
distinct
,
(
int
)
save_sum_fields
,
(
int
)
distinct
,
(
int
)
save_sum_fields
,
(
ulong
)
rows_limit
,
test
(
group
)));
(
ulong
)
rows_limit
,
test
(
group
)));
statistic_increment
(
created_tmp_tables
,
&
LOCK_status
);
statistic_increment
(
thd
->
status_var
.
created_tmp_tables
,
&
LOCK_status
);
if
(
use_temp_pool
)
if
(
use_temp_pool
)
temp_pool_slot
=
bitmap_set_next
(
&
temp_pool
);
temp_pool_slot
=
bitmap_set_next
(
&
temp_pool
);
...
@@ -6894,14 +6898,21 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
...
@@ -6894,14 +6898,21 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
tmp_from_field
++
;
tmp_from_field
++
;
*
(
reg_field
++
)
=
new_field
;
*
(
reg_field
++
)
=
new_field
;
reclength
+=
new_field
->
pack_length
();
reclength
+=
new_field
->
pack_length
();
if
(
!
(
new_field
->
flags
&
NOT_NULL_FLAG
))
null_count
++
;
if
(
new_field
->
flags
&
BLOB_FLAG
)
if
(
new_field
->
flags
&
BLOB_FLAG
)
{
{
*
blob_field
++=
new_field
;
*
blob_field
++=
new_field
;
blob_count
++
;
blob_count
++
;
}
}
((
Item_sum
*
)
item
)
->
args
[
i
]
=
new
Item_field
(
new_field
);
((
Item_sum
*
)
item
)
->
args
[
i
]
=
new
Item_field
(
new_field
);
if
(
!
(
new_field
->
flags
&
NOT_NULL_FLAG
))
{
null_count
++
;
/*
new_field->maybe_null() is still false, it will be
changed below. But we have to setup Item_field correctly
*/
((
Item_sum
*
)
item
)
->
args
[
i
]
->
maybe_null
=
1
;
}
}
}
}
}
}
}
...
@@ -7346,7 +7357,8 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
...
@@ -7346,7 +7357,8 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
table
->
db_stat
=
0
;
table
->
db_stat
=
0
;
goto
err
;
goto
err
;
}
}
statistic_increment
(
created_tmp_disk_tables
,
&
LOCK_status
);
statistic_increment
(
table
->
in_use
->
status_var
.
created_tmp_disk_tables
,
&
LOCK_status
);
table
->
db_record_offset
=
1
;
table
->
db_record_offset
=
1
;
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
err:
err:
...
@@ -7434,6 +7446,18 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
...
@@ -7434,6 +7446,18 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
new_table
.
no_rows
=
1
;
new_table
.
no_rows
=
1
;
}
}
#ifdef TO_BE_DONE_LATER_IN_4_1
/*
To use start_bulk_insert() (which is new in 4.1) we need to find
all places where a corresponding end_bulk_insert() should be put.
*/
table
->
file
->
info
(
HA_STATUS_VARIABLE
);
/* update table->file->records */
new_table
.
file
->
start_bulk_insert
(
table
->
file
->
records
);
#else
/* HA_EXTRA_WRITE_CACHE can stay until close, no need to disable it */
new_table
.
file
->
extra
(
HA_EXTRA_WRITE_CACHE
);
#endif
/* copy all old rows */
/* copy all old rows */
while
(
!
table
->
file
->
rnd_next
(
new_table
.
record
[
1
]))
while
(
!
table
->
file
->
rnd_next
(
new_table
.
record
[
1
]))
{
{
...
@@ -8146,6 +8170,19 @@ join_read_system(JOIN_TAB *tab)
...
@@ -8146,6 +8170,19 @@ join_read_system(JOIN_TAB *tab)
}
}
/*
Read a table when there is at most one matching row
SYNOPSIS
join_read_const()
tab Table to read
RETURN
0 Row was found
-1 Row was not found
1 Got an error (other than row not found) during read
*/
static
int
static
int
join_read_const
(
JOIN_TAB
*
tab
)
join_read_const
(
JOIN_TAB
*
tab
)
{
{
...
@@ -8153,6 +8190,7 @@ join_read_const(JOIN_TAB *tab)
...
@@ -8153,6 +8190,7 @@ join_read_const(JOIN_TAB *tab)
TABLE
*
table
=
tab
->
table
;
TABLE
*
table
=
tab
->
table
;
if
(
table
->
status
&
STATUS_GARBAGE
)
// If first read
if
(
table
->
status
&
STATUS_GARBAGE
)
// If first read
{
{
table
->
status
=
0
;
if
(
cp_buffer_from_ref
(
&
tab
->
ref
))
if
(
cp_buffer_from_ref
(
&
tab
->
ref
))
error
=
HA_ERR_KEY_NOT_FOUND
;
error
=
HA_ERR_KEY_NOT_FOUND
;
else
else
...
@@ -8163,6 +8201,7 @@ join_read_const(JOIN_TAB *tab)
...
@@ -8163,6 +8201,7 @@ join_read_const(JOIN_TAB *tab)
}
}
if
(
error
)
if
(
error
)
{
{
table
->
status
=
STATUS_NOT_FOUND
;
table
->
null_row
=
1
;
table
->
null_row
=
1
;
empty_record
(
table
);
empty_record
(
table
);
if
(
error
!=
HA_ERR_KEY_NOT_FOUND
)
if
(
error
!=
HA_ERR_KEY_NOT_FOUND
)
...
@@ -9378,7 +9417,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
...
@@ -9378,7 +9417,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
keys
.
merge
(
table
->
used_keys
);
keys
.
merge
(
table
->
used_keys
);
/*
/*
We are adding here also the index speified in FORCE INDEX clause,
We are adding here also the index spe
c
ified in FORCE INDEX clause,
if any.
if any.
This is to allow users to use index in ORDER BY.
This is to allow users to use index in ORDER BY.
*/
*/
...
@@ -10157,7 +10196,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
...
@@ -10157,7 +10196,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
Item
*
itemptr
=*
order
->
item
;
Item
*
itemptr
=*
order
->
item
;
if
(
itemptr
->
type
()
==
Item
::
INT_ITEM
)
if
(
itemptr
->
type
()
==
Item
::
INT_ITEM
)
{
/* Order by position */
{
/* Order by position */
uint
count
=
itemptr
->
val_int
();
uint
count
=
(
uint
)
itemptr
->
val_int
();
if
(
!
count
||
count
>
fields
.
elements
)
if
(
!
count
||
count
>
fields
.
elements
)
{
{
my_printf_error
(
ER_BAD_FIELD_ERROR
,
ER
(
ER_BAD_FIELD_ERROR
),
my_printf_error
(
ER_BAD_FIELD_ERROR
,
ER
(
ER_BAD_FIELD_ERROR
),
...
@@ -10165,18 +10204,25 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
...
@@ -10165,18 +10204,25 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
thd
->
where
);
thd
->
where
);
return
1
;
return
1
;
}
}
order
->
item
=
ref_pointer_array
+
count
-
1
;
order
->
item
=
ref_pointer_array
+
count
-
1
;
order
->
in_field_list
=
1
;
order
->
in_field_list
=
1
;
order
->
counter
=
count
;
order
->
counter_used
=
1
;
return
0
;
return
0
;
}
}
uint
counter
;
uint
counter
;
Item
**
item
=
find_item_in_list
(
itemptr
,
fields
,
&
counter
,
IGNORE_ERRORS
);
Item
**
item
=
find_item_in_list
(
itemptr
,
fields
,
&
counter
,
if
(
item
)
REPORT_EXCEPT_NOT_FOUND
);
if
(
!
item
)
return
1
;
if
(
item
!=
(
Item
**
)
not_found_item
)
{
{
order
->
item
=
ref_pointer_array
+
counter
;
order
->
item
=
ref_pointer_array
+
counter
;
order
->
in_field_list
=
1
;
order
->
in_field_list
=
1
;
return
0
;
return
0
;
}
}
order
->
in_field_list
=
0
;
order
->
in_field_list
=
0
;
Item
*
it
=
*
order
->
item
;
Item
*
it
=
*
order
->
item
;
/*
/*
...
@@ -10639,7 +10685,16 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
...
@@ -10639,7 +10685,16 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
{
{
if
(
!
(
pos
=
new
Item_copy_string
(
pos
)))
if
(
!
(
pos
=
new
Item_copy_string
(
pos
)))
goto
err
;
goto
err
;
if
(
param
->
copy_funcs
.
push_back
(
pos
))
/*
Item_copy_string::copy for function can call
Item_copy_string::val_int for blob via Item_ref.
But if Item_copy_string::copy for blob isn't called before,
it's value will be wrong
so let's insert Item_copy_string for blobs in the beginning of
copy_funcs
(to see full test case look at having.test, BUG #4358)
*/
if
(
param
->
copy_funcs
.
push_front
(
pos
))
goto
err
;
goto
err
;
}
}
else
else
...
@@ -11676,7 +11731,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
...
@@ -11676,7 +11731,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
SYNOPSIS
SYNOPSIS
print_join()
print_join()
thd thread handler
thd thread handler
str string where table should b
b
e printed
str string where table should be printed
tables list of tables in join
tables list of tables in join
*/
*/
...
@@ -11732,30 +11787,31 @@ void st_table_list::print(THD *thd, String *str)
...
@@ -11732,30 +11787,31 @@ void st_table_list::print(THD *thd, String *str)
print_join
(
thd
,
str
,
&
nested_join
->
join_list
);
print_join
(
thd
,
str
,
&
nested_join
->
join_list
);
str
->
append
(
')'
);
str
->
append
(
')'
);
}
}
else
if
(
view_name
.
str
)
else
{
const
char
*
cmp_name
;
// Name to compare with alias
if
(
view_name
.
str
)
{
{
append_identifier
(
thd
,
str
,
view_db
.
str
,
view_db
.
length
);
append_identifier
(
thd
,
str
,
view_db
.
str
,
view_db
.
length
);
str
->
append
(
'.'
);
str
->
append
(
'.'
);
append_identifier
(
thd
,
str
,
view_name
.
str
,
view_name
.
length
);
append_identifier
(
thd
,
str
,
view_name
.
str
,
view_name
.
length
);
if
(
my_strcasecmp
(
table_alias_charset
,
view_name
.
str
,
alias
))
cmp_name
=
view_name
.
str
;
{
str
->
append
(
' '
);
append_identifier
(
thd
,
str
,
alias
,
strlen
(
alias
));
}
}
}
else
if
(
derived
)
else
if
(
derived
)
{
{
str
->
append
(
'('
);
str
->
append
(
'('
);
derived
->
print
(
str
);
derived
->
print
(
str
);
str
->
append
(
") "
,
2
);
str
->
append
(
')'
);
append_identifier
(
thd
,
str
,
alias
,
strlen
(
alias
));
cmp_name
=
""
;
// Force printing of alias
}
}
else
else
{
{
append_identifier
(
thd
,
str
,
db
,
db_length
);
append_identifier
(
thd
,
str
,
db
,
db_length
);
str
->
append
(
'.'
);
str
->
append
(
'.'
);
append_identifier
(
thd
,
str
,
real_name
,
real_name_length
);
append_identifier
(
thd
,
str
,
real_name
,
real_name_length
);
if
(
my_strcasecmp
(
table_alias_charset
,
real_name
,
alias
))
cmp_name
=
real_name
;
}
if
(
my_strcasecmp
(
table_alias_charset
,
cmp_name
,
alias
))
{
{
str
->
append
(
' '
);
str
->
append
(
' '
);
append_identifier
(
thd
,
str
,
alias
,
strlen
(
alias
));
append_identifier
(
thd
,
str
,
alias
,
strlen
(
alias
));
...
@@ -11771,7 +11827,7 @@ void st_select_lex::print(THD *thd, String *str)
...
@@ -11771,7 +11827,7 @@ void st_select_lex::print(THD *thd, String *str)
str
->
append
(
"select "
,
7
);
str
->
append
(
"select "
,
7
);
/
/options
/
* First add options */
if
(
options
&
SELECT_STRAIGHT_JOIN
)
if
(
options
&
SELECT_STRAIGHT_JOIN
)
str
->
append
(
"straight_join "
,
14
);
str
->
append
(
"straight_join "
,
14
);
if
((
thd
->
lex
->
lock_option
==
TL_READ_HIGH_PRIORITY
)
&&
if
((
thd
->
lex
->
lock_option
==
TL_READ_HIGH_PRIORITY
)
&&
...
...
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