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
Hide 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,
if
(
!
head
->
used_keys
.
is_clear_all
())
{
int
key_for_use
=
find_shortest_key
(
head
,
&
head
->
used_keys
);
double
key_read_time
=
get_index_only_read_time
(
&
param
,
records
,
key_for_use
);
double
key_read_time
=
(
get_index_only_read_time
(
&
param
,
records
,
key_for_use
)
+
(
double
)
records
/
TIME_FOR_COMPARE
);
DBUG_PRINT
(
"info"
,
(
"'all'+'using index' scan will be using key %d, "
"read time %g"
,
key_for_use
,
key_read_time
));
if
(
key_read_time
<
read_time
)
...
...
@@ -2176,6 +2177,12 @@ skip_to_ror_scan:
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
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
,
...
...
@@ -2190,6 +2197,7 @@ inline double get_index_only_read_time(const PARAM* param, ha_rows records,
return
read_time
;
}
typedef
struct
st_ror_scan_info
{
uint
idx
;
/* # of used key in param->keys */
...
...
@@ -3056,22 +3064,24 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
tree
->
n_ror_scans
++
;
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
&&
read_index_only
&&
(
param
->
table
->
file
->
index_flags
(
keynr
,
param
->
max_key_part
,
1
)
&
HA_KEYREAD_ONLY
)
&&
!
(
pk_is_clustered
&&
keynr
==
param
->
table
->
primary_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
/*
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.
*/
found_read_time
=
(
param
->
table
->
file
->
read_time
(
keynr
,
param
->
range_count
,
found_records
)
+
(
double
)
found_records
/
TIME_FOR_COMPARE
)
;
found_read_time
=
param
->
table
->
file
->
read_time
(
keynr
,
param
->
range_count
,
found_records
)
+
cpu_cost
;
DBUG_PRINT
(
"info"
,(
"read_time: %g found_read_time: %g"
,
read_time
,
found_read_time
));
...
...
@@ -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
field_length
=
field
->
pack_length
()
+
maybe_null
;
bool
optimize_range
;
SEL_ARG
*
tree
;
char
*
str
,
*
str2
;
DBUG_ENTER
(
"get_mm_leaf"
);
...
...
@@ -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
())
DBUG_RETURN
(
0
);
optimize_range
=
field
->
optimize_range
(
param
->
real_keynr
[
key_part
->
key
],
key_part
->
part
);
if
(
type
==
Item_func
::
LIKE_FUNC
)
{
bool
like_error
;
...
...
@@ -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
;
uint
length
,
offset
,
min_length
,
max_length
;
if
(
!
field
->
optimize_range
(
param
->
real_keynr
[
key_part
->
key
],
key_part
->
part
))
if
(
!
optimize_range
)
DBUG_RETURN
(
0
);
// Can't optimize this
if
(
!
(
res
=
value
->
val_str
(
&
tmp
)))
DBUG_RETURN
(
&
null_element
);
...
...
@@ -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
));
}
if
(
!
field
->
optimize_range
(
param
->
real_keynr
[
key_part
->
key
],
key_part
->
part
)
&&
if
(
!
optimize_range
&&
type
!=
Item_func
::
EQ_FUNC
&&
type
!=
Item_func
::
EQUAL_FUNC
)
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,
field
->
cmp_type
()
!=
value
->
result_type
())
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 */
DBUG_RETURN
(
&
null_element
);
// cmp with NULL is never TRUE
...
...
@@ -3736,14 +3748,15 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
if
(
*
key2
&&
!
(
*
key2
)
->
simple_key
())
flag
|=
CLONE_KEY2_MAYBE
;
*
key1
=
key_and
(
*
key1
,
*
key2
,
flag
);
if
((
*
key1
)
->
type
==
SEL_ARG
::
IMPOSSIBLE
)
if
(
*
key1
&&
(
*
key1
)
->
type
==
SEL_ARG
::
IMPOSSIBLE
)
{
tree1
->
type
=
SEL_TREE
::
IMPOSSIBLE
;
DBUG_RETURN
(
tree1
);
}
result_keys
.
set_bit
(
key1
-
tree1
->
keys
);
#ifdef EXTRA_DEBUG
(
*
key1
)
->
test_use_count
(
*
key1
);
if
(
*
key1
)
(
*
key1
)
->
test_use_count
(
*
key1
);
#endif
}
}
...
...
@@ -3974,6 +3987,13 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
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
--
;
key2
->
use_count
--
;
SEL_ARG
*
e1
=
key1
->
first
(),
*
e2
=
key2
->
first
(),
*
new_tree
=
0
;
...
...
@@ -4056,7 +4076,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
key1
->
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
();
key2
->
free_tree
();
...
...
@@ -4716,7 +4737,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
ulong
count
=
count_key_part_usage
(
root
,
pos
->
next_key_part
);
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
);
return
;
}
...
...
@@ -4724,7 +4745,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
}
}
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
);
}
...
...
sql/sql_select.cc
View file @
a19eee45
...
...
@@ -226,27 +226,13 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
thd
->
net
.
report_error
));
if
(
thd
->
net
.
report_error
)
res
=
1
;
if
(
res
>
0
)
if
(
unlikely
(
res
)
)
{
if
(
result
)
{
if
(
res
>
0
)
result
->
send_error
(
0
,
NullS
);
result
->
abort
();
}
else
send_error
(
thd
,
0
,
NullS
);
result
->
abort
();
res
=
1
;
// Error sent to client
}
if
(
res
<
0
)
{
if
(
result
)
{
result
->
abort
();
}
res
=
1
;
}
if
(
result
!=
lex
->
result
)
delete
result
;
DBUG_RETURN
(
res
);
}
...
...
@@ -349,9 +335,7 @@ JOIN::prepare(Item ***rref_pointer_array,
if
((
subselect
=
select_lex
->
master_unit
()
->
item
))
{
Item_subselect
::
trans_res
res
;
if
((
res
=
((
!
thd
->
lex
->
view_prepare_mode
)
?
subselect
->
select_transformer
(
this
)
:
subselect
->
no_select_transform
()))
!=
if
((
res
=
subselect
->
select_transformer
(
this
))
!=
Item_subselect
::
RES_OK
)
{
select_lex
->
fix_prepare_information
(
thd
,
&
conds
);
...
...
@@ -553,6 +537,7 @@ JOIN::optimize()
if
(
cond_value
==
Item
::
COND_FALSE
||
(
!
unit
->
select_limit_cnt
&&
!
(
select_options
&
OPTION_FOUND_ROWS
)))
{
/* Impossible cond */
DBUG_PRINT
(
"info"
,
(
"Impossible WHERE"
));
zero_result_cause
=
"Impossible WHERE"
;
error
=
0
;
DBUG_RETURN
(
0
);
...
...
@@ -570,20 +555,24 @@ JOIN::optimize()
{
if
(
res
>
1
)
{
DBUG_PRINT
(
"error"
,(
"Error from opt_sum_query"
));
DBUG_RETURN
(
1
);
}
if
(
res
<
0
)
{
DBUG_PRINT
(
"info"
,(
"No matching min/max row"
));
zero_result_cause
=
"No matching min/max row"
;
error
=
0
;
DBUG_RETURN
(
0
);
}
DBUG_PRINT
(
"info"
,(
"Select tables optimized away"
));
zero_result_cause
=
"Select tables optimized away"
;
tables_list
=
0
;
// All tables resolved
}
}
if
(
!
tables_list
)
{
DBUG_PRINT
(
"info"
,(
"No tables"
));
error
=
0
;
DBUG_RETURN
(
0
);
}
...
...
@@ -777,6 +766,10 @@ JOIN::optimize()
(
select_lex
->
ftfunc_list
->
elements
?
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?
*/
...
...
@@ -832,7 +825,7 @@ JOIN::optimize()
join_tab
->
info
=
"Using index; Using where"
;
else
join_tab
->
info
=
"Using index"
;
DBUG_RETURN
(
unit
->
item
->
change_engine
(
new
subselect_indexsubquery_engine
(
thd
,
join_tab
,
...
...
@@ -869,7 +862,7 @@ JOIN::optimize()
as in other cases the join is done before the sort.
*/
if
(
const_tables
!=
tables
&&
(
order
||
group_list
)
&&
(
order
||
group_list
)
&&
join_tab
[
const_tables
].
type
!=
JT_ALL
&&
join_tab
[
const_tables
].
type
!=
JT_FT
&&
join_tab
[
const_tables
].
type
!=
JT_REF_OR_NULL
&&
...
...
@@ -883,8 +876,7 @@ JOIN::optimize()
((
group_list
&&
const_tables
!=
tables
&&
(
!
simple_group
||
!
test_if_skip_sort_order
(
&
join_tab
[
const_tables
],
group_list
,
unit
->
select_limit_cnt
,
0
)))
||
unit
->
select_limit_cnt
,
0
)))
||
select_distinct
)
&&
tmp_table_param
.
quick_group
&&
!
procedure
)
{
...
...
@@ -899,8 +891,6 @@ JOIN::optimize()
}
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 */
if
(
need_tmp
)
{
...
...
@@ -908,7 +898,7 @@ JOIN::optimize()
thd
->
proc_info
=
"Creating tmp table"
;
init_items_ref_array
();
tmp_table_param
.
hidden_field_count
=
(
all_fields
.
elements
-
fields_list
.
elements
);
if
(
!
(
exec_tmp_table1
=
...
...
@@ -2446,7 +2436,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
}
else
if
(
old
->
eq_func
&&
new_fields
->
eq_func
&&
old
->
val
->
eq
(
new_fields
->
val
,
old
->
field
->
binary
()))
{
old
->
level
=
and_level
;
old
->
optimize
=
((
old
->
optimize
&
new_fields
->
optimize
&
...
...
@@ -2505,7 +2495,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
field Field used in comparision
eq_func True if we used =, <=> or IS NULL
value Value used for comparison with field
Is NULL for BETWEEN and IN
Is NULL for BETWEEN and IN
usable_tables Tables which can be used for key optimization
NOTES
...
...
@@ -2572,7 +2562,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond,
bool
is_const
=
1
;
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
)
->
const_item
();
...
...
@@ -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.
eq_func is NEVER true when num_values > 1
*/
if
(
!
eq_func
||
field
->
result_type
()
==
STRING_RESULT
&&
(
*
value
)
->
result_type
()
!=
STRING_RESULT
&&
field
->
cmp_type
()
!=
(
*
value
)
->
result_type
())
return
;
/*
We can't use indexes if the effective collation
of the operation differ from the field collation.
*/
if
(
field
->
result_type
()
==
STRING_RESULT
&&
(
*
value
)
->
result_type
()
==
STRING_RESULT
&&
field
->
cmp_type
()
==
STRING_RESULT
&&
((
Field_str
*
)
field
)
->
charset
()
!=
cond
->
compare_collation
())
return
;
if
(
!
eq_func
)
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
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
->
cmp_type
()
==
STRING_RESULT
&&
(((
Field_str
*
)
field
)
->
charset
()
!=
cond
->
compare_collation
()
||
((
*
value
)
->
type
()
!=
Item
::
NULL_ITEM
&&
(
field
->
flags
&
BLOB_FLAG
)
&&
!
field
->
binary
())))
return
;
}
}
}
}
DBUG_ASSERT
(
num_values
==
1
);
...
...
@@ -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
))
{
Item
*
tmp
=
new
Item_null
;
if
(
!
tmp
)
// Should never be true
if
(
unlikely
(
!
tmp
))
// Should never be true
return
;
add_key_field
(
key_fields
,
*
and_level
,
cond_func
,
((
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,
rec
=
keyuse
->
ref_table_rows
;
/*
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
&
KEY_OPTIMIZE_REF_OR_NULL
);
...
...
@@ -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
;
byte
*
key_buff
=
j
->
ref
.
key_buff
,
*
null_ref_key
=
0
;
bool
keyuse_uses_no_tables
=
TRUE
;
if
(
ftkey
)
{
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,
uint
maybe_null
=
test
(
keyinfo
->
key_part
[
i
].
null_bit
);
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
&&
!
(
join
->
select_options
&
SELECT_DESCRIBE
))
{
// Compare against constant
...
...
@@ -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
->
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
...
...
@@ -4971,10 +4973,32 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
COND
*
const_cond
=
make_cond_for_table
(
cond
,
join
->
const_table_map
,(
table_map
)
0
);
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
())
{
DBUG_PRINT
(
"info"
,(
"Found impossible WHERE condition"
));
DBUG_RETURN
(
1
);
// Impossible const condition
DBUG_RETURN
(
1
);
// Impossible const condition
}
}
}
...
...
@@ -4985,13 +5009,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
JOIN_TAB
*
tab
=
join
->
join_tab
+
i
;
JOIN_TAB
*
first_inner_tab
=
tab
->
first_inner
;
table_map
current_map
=
tab
->
table
->
map
;
bool
use_quick_range
=
0
;
/*
Following force including random expression in last table condition.
It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5
*/
if
(
i
==
join
->
tables
-
1
)
current_map
|=
OUTER_REF_TABLE_BIT
|
RAND_TABLE_BIT
;
bool
use_quick_range
=
0
;
used_tables
|=
current_map
;
if
(
tab
->
type
==
JT_REF
&&
tab
->
quick
&&
...
...
@@ -5012,15 +5036,30 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
tmp
=
make_cond_for_table
(
cond
,
used_tables
,
current_map
);
if
(
cond
&&
!
tmp
&&
tab
->
quick
)
{
// Outer join
/*
Hack to handle the case where we only refer to a table
in the ON part of an OUTER JOIN.
*/
tmp
=
new
Item_int
((
longlong
)
1
,
1
);
// Always true
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
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
}
}
if
(
tmp
||
!
cond
)
{
DBUG_EXECUTE
(
"where"
,
print_where
(
tmp
,
tab
->
table
->
table_name
););
DBUG_EXECUTE
(
"where"
,
print_where
(
tmp
,
tab
->
table
->
table_name
););
SQL_SELECT
*
sel
=
tab
->
select
=
(
SQL_SELECT
*
)
join
->
thd
->
memdup
((
gptr
)
select
,
sizeof
(
SQL_SELECT
));
if
(
!
sel
)
...
...
@@ -5030,7 +5069,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
add a match guard to the pushed down predicate.
The guard will turn the predicate on only after
the first match for outer tables is encountered.
*/
*/
if
(
cond
)
{
/*
Because of QUICK_GROUP_MIN_MAX_SELECT there may be a select without
...
...
@@ -5217,6 +5256,7 @@ static void
make_join_readinfo
(
JOIN
*
join
,
uint
options
)
{
uint
i
;
bool
statistics
=
test
(
!
(
join
->
select_options
&
SELECT_DESCRIBE
));
DBUG_ENTER
(
"make_join_readinfo"
);
...
...
@@ -5315,7 +5355,8 @@ make_join_readinfo(JOIN *join, uint options)
join
->
thd
->
server_status
|=
SERVER_QUERY_NO_GOOD_INDEX_USED
;
tab
->
read_first_record
=
join_init_quick_read_record
;
if
(
statistics
)
statistic_increment
(
select_range_check_count
,
&
LOCK_status
);
statistic_increment
(
join
->
thd
->
status_var
.
select_range_check_count
,
&
LOCK_status
);
}
else
{
...
...
@@ -5325,13 +5366,15 @@ make_join_readinfo(JOIN *join, uint options)
if
(
tab
->
select
&&
tab
->
select
->
quick
)
{
if
(
statistics
)
statistic_increment
(
select_range_count
,
&
LOCK_status
);
statistic_increment
(
join
->
thd
->
status_var
.
select_range_count
,
&
LOCK_status
);
}
else
{
join
->
thd
->
server_status
|=
SERVER_QUERY_NO_INDEX_USED
;
if
(
statistics
)
statistic_increment
(
select_scan_count
,
&
LOCK_status
);
statistic_increment
(
join
->
thd
->
status_var
.
select_scan_count
,
&
LOCK_status
);
}
}
else
...
...
@@ -5339,13 +5382,15 @@ make_join_readinfo(JOIN *join, uint options)
if
(
tab
->
select
&&
tab
->
select
->
quick
)
{
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
{
join
->
thd
->
server_status
|=
SERVER_QUERY_NO_INDEX_USED
;
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
)
...
...
@@ -5520,6 +5565,10 @@ JOIN::join_free(bool full)
if
(
full
)
{
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
.
cleanup
();
}
...
...
@@ -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
(
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
()));
continue
;
...
...
@@ -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_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
();
if
(
tmp
)
...
...
@@ -5845,7 +5897,10 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
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
();
if
(
tmp
)
...
...
@@ -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
...
...
@@ -6085,9 +6084,9 @@ COND *eliminate_not_funcs(THD *thd, COND *cond)
The function removes all unnecessary braces from the expression
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:
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:
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)
NESTED_JOIN
*
nested_join
;
TABLE_LIST
*
prev_table
=
0
;
List_iterator
<
TABLE_LIST
>
li
(
*
join_list
);
DBUG_ENTER
(
"simplify_joins"
);
/*
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)
li
.
replace
(
nested_join
->
join_list
);
}
}
return
conds
;
DBUG_RETURN
(
conds
)
;
}
static
COND
*
optimize_cond
(
JOIN
*
join
,
COND
*
conds
,
Item
::
cond_result
*
cond_value
)
{
DBUG_ENTER
(
"optimize_cond"
);
THD
*
thd
=
join
->
thd
;
SELECT_LEX
*
select
=
thd
->
lex
->
current_select
;
DBUG_ENTER
(
"optimize_cond"
);
if
(
select
->
first_cond_optimization
)
{
Item_arena
*
arena
=
thd
->
current_arena
;
Item_arena
backup
;
if
(
arena
)
/*
The following code will allocate the new items in a permanent
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
);
if
(
conds
)
{
DBUG_EXECUTE
(
"where"
,
print_where
(
conds
,
"original"
););
/* eliminate NOT operators */
conds
=
eliminate_not_funcs
(
thd
,
conds
);
}
select
->
first_cond_optimization
=
0
;
/* Convert all outer joins to inner joins if possible */
conds
=
simplify_joins
(
join
,
join
->
join_list
,
conds
,
TRUE
);
select
->
prep_where
=
conds
?
conds
->
copy_andor_structure
(
thd
)
:
0
;
select
->
first_cond_optimization
=
0
;
if
(
arena
)
thd
->
restore_backup_item_arena
(
arena
,
&
backup
);
}
...
...
@@ -6291,19 +6293,21 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
if
(
!
conds
)
{
*
cond_value
=
Item
::
COND_TRUE
;
DBUG_RETURN
(
conds
);
select
->
prep_where
=
0
;
}
else
{
DBUG_EXECUTE
(
"where"
,
print_where
(
conds
,
"original"
););
/* change field = field to field = const for each found field = const */
propagate_cond_constants
((
I_List
<
COND_CMP
>
*
)
0
,
conds
,
conds
);
/*
Remove all instances of item == item
Remove all and-levels where CONST item != CONST item
*/
DBUG_EXECUTE
(
"where"
,
print_where
(
conds
,
"after const change"
););
conds
=
remove_eq_conds
(
thd
,
conds
,
cond_value
)
;
DBUG_EXECUTE
(
"info"
,
print_where
(
conds
,
"after remove"
););
}
DBUG_EXECUTE
(
"where"
,
print_where
(
conds
,
"after negation elimination"
););
/* change field = field to field = const for each found field = const */
propagate_cond_constants
((
I_List
<
COND_CMP
>
*
)
0
,
conds
,
conds
);
/*
Remove all instances of item == item
Remove all and-levels where CONST item != CONST item
*/
DBUG_EXECUTE
(
"where"
,
print_where
(
conds
,
"after const change"
););
conds
=
remove_eq_conds
(
thd
,
conds
,
cond_value
)
;
DBUG_EXECUTE
(
"info"
,
print_where
(
conds
,
"after remove"
););
DBUG_RETURN
(
conds
);
}
...
...
@@ -6631,7 +6635,7 @@ static Field* create_tmp_field_from_item(THD *thd,
copy_func If set and item is a function, store copy of item
in this array
from_field if field will be created using other field as example,
pointer example field will be written here
pointer example field will be written here
group 1 if we are going to do a relative group by on result
modify_item 1 if item->result_field should point to new item.
This is relevent for how fill_record() is going to
...
...
@@ -6640,7 +6644,7 @@ static Field* create_tmp_field_from_item(THD *thd,
the record in the original table.
If modify_item is 0 then fill_record() will update
the temporary table
RETURN
0 on error
new_created field
...
...
@@ -6664,13 +6668,13 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
return
new
Field_double
(
item_sum
->
max_length
,
maybe_null
,
item
->
name
,
table
,
item_sum
->
decimals
);
case
Item_sum
:
:
VARIANCE_FUNC
:
/* Place for sum & count */
case
Item_sum
:
:
STD_FUNC
:
case
Item_sum
:
:
STD_FUNC
:
if
(
group
)
return
new
Field_string
(
sizeof
(
double
)
*
2
+
sizeof
(
longlong
),
0
,
item
->
name
,
table
,
&
my_charset_bin
);
else
return
new
Field_double
(
item_sum
->
max_length
,
maybe_null
,
item
->
name
,
table
,
item_sum
->
decimals
);
item
->
name
,
table
,
item_sum
->
decimals
);
case
Item_sum
:
:
UNIQUE_USERS_FUNC
:
return
new
Field_long
(
9
,
maybe_null
,
item
->
name
,
table
,
1
);
default:
...
...
@@ -6767,7 +6771,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
(
int
)
distinct
,
(
int
)
save_sum_fields
,
(
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
)
temp_pool_slot
=
bitmap_set_next
(
&
temp_pool
);
...
...
@@ -6778,7 +6782,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
else
// if we run out of slots or we are not using tempool
sprintf
(
path
,
"%s%s%lx_%lx_%x"
,
mysql_tmpdir
,
tmp_file_prefix
,
current_pid
,
thd
->
thread_id
,
thd
->
tmp_table
++
);
if
(
lower_case_table_names
)
my_casedn_str
(
files_charset_info
,
path
);
...
...
@@ -6894,14 +6898,21 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
tmp_from_field
++
;
*
(
reg_field
++
)
=
new_field
;
reclength
+=
new_field
->
pack_length
();
if
(
!
(
new_field
->
flags
&
NOT_NULL_FLAG
))
null_count
++
;
if
(
new_field
->
flags
&
BLOB_FLAG
)
{
*
blob_field
++=
new_field
;
blob_count
++
;
}
((
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,
table
->
db_stat
=
0
;
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
;
DBUG_RETURN
(
0
);
err:
...
...
@@ -7434,6 +7446,18 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
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 */
while
(
!
table
->
file
->
rnd_next
(
new_table
.
record
[
1
]))
{
...
...
@@ -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
join_read_const
(
JOIN_TAB
*
tab
)
{
...
...
@@ -8153,6 +8190,7 @@ join_read_const(JOIN_TAB *tab)
TABLE
*
table
=
tab
->
table
;
if
(
table
->
status
&
STATUS_GARBAGE
)
// If first read
{
table
->
status
=
0
;
if
(
cp_buffer_from_ref
(
&
tab
->
ref
))
error
=
HA_ERR_KEY_NOT_FOUND
;
else
...
...
@@ -8163,6 +8201,7 @@ join_read_const(JOIN_TAB *tab)
}
if
(
error
)
{
table
->
status
=
STATUS_NOT_FOUND
;
table
->
null_row
=
1
;
empty_record
(
table
);
if
(
error
!=
HA_ERR_KEY_NOT_FOUND
)
...
...
@@ -9378,9 +9417,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
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.
This is to allow users to use index in ORDER BY.
This is to allow users to use index in ORDER BY.
*/
if
(
table
->
force_index
)
keys
.
merge
(
table
->
keys_in_use_for_query
);
...
...
@@ -10157,7 +10196,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
Item
*
itemptr
=*
order
->
item
;
if
(
itemptr
->
type
()
==
Item
::
INT_ITEM
)
{
/* Order by position */
uint
count
=
itemptr
->
val_int
();
uint
count
=
(
uint
)
itemptr
->
val_int
();
if
(
!
count
||
count
>
fields
.
elements
)
{
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,
thd
->
where
);
return
1
;
}
order
->
item
=
ref_pointer_array
+
count
-
1
;
order
->
item
=
ref_pointer_array
+
count
-
1
;
order
->
in_field_list
=
1
;
order
->
counter
=
count
;
order
->
counter_used
=
1
;
return
0
;
}
uint
counter
;
Item
**
item
=
find_item_in_list
(
itemptr
,
fields
,
&
counter
,
IGNORE_ERRORS
);
if
(
item
)
Item
**
item
=
find_item_in_list
(
itemptr
,
fields
,
&
counter
,
REPORT_EXCEPT_NOT_FOUND
);
if
(
!
item
)
return
1
;
if
(
item
!=
(
Item
**
)
not_found_item
)
{
order
->
item
=
ref_pointer_array
+
counter
;
order
->
in_field_list
=
1
;
return
0
;
}
order
->
in_field_list
=
0
;
Item
*
it
=
*
order
->
item
;
/*
...
...
@@ -10639,7 +10685,16 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
{
if
(
!
(
pos
=
new
Item_copy_string
(
pos
)))
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
;
}
else
...
...
@@ -11676,7 +11731,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
SYNOPSIS
print_join()
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
*/
...
...
@@ -11732,30 +11787,31 @@ void st_table_list::print(THD *thd, String *str)
print_join
(
thd
,
str
,
&
nested_join
->
join_list
);
str
->
append
(
')'
);
}
else
if
(
view_name
.
str
)
else
{
append_identifier
(
thd
,
str
,
view_db
.
str
,
view_db
.
length
);
str
->
append
(
'.'
);
append_identifier
(
thd
,
str
,
view_name
.
str
,
view_name
.
length
);
if
(
my_strcasecmp
(
table_alias_charset
,
view_name
.
str
,
alias
))
const
char
*
cmp_name
;
// Name to compare with alias
if
(
view_name
.
str
)
{
str
->
append
(
' '
);
append_identifier
(
thd
,
str
,
alias
,
strlen
(
alias
));
append_identifier
(
thd
,
str
,
view_db
.
str
,
view_db
.
length
);
str
->
append
(
'.'
);
append_identifier
(
thd
,
str
,
view_name
.
str
,
view_name
.
length
);
cmp_name
=
view_name
.
str
;
}
}
else
if
(
derived
)
{
str
->
append
(
'('
);
derived
->
print
(
str
);
str
->
append
(
") "
,
2
);
append_identifier
(
thd
,
str
,
alias
,
strlen
(
alias
));
}
else
{
append_identifier
(
thd
,
str
,
db
,
db_length
);
str
->
append
(
'.'
);
append_identifier
(
thd
,
str
,
real_name
,
real_name_length
);
if
(
my_strcasecmp
(
table_alias_charset
,
real_name
,
alias
))
else
if
(
derived
)
{
str
->
append
(
'('
);
derived
->
print
(
str
);
str
->
append
(
')'
);
cmp_name
=
""
;
// Force printing of alias
}
else
{
append_identifier
(
thd
,
str
,
db
,
db_length
);
str
->
append
(
'.'
);
append_identifier
(
thd
,
str
,
real_name
,
real_name_length
);
cmp_name
=
real_name
;
}
if
(
my_strcasecmp
(
table_alias_charset
,
cmp_name
,
alias
))
{
str
->
append
(
' '
);
append_identifier
(
thd
,
str
,
alias
,
strlen
(
alias
));
...
...
@@ -11771,7 +11827,7 @@ void st_select_lex::print(THD *thd, String *str)
str
->
append
(
"select "
,
7
);
/
/options
/
* First add options */
if
(
options
&
SELECT_STRAIGHT_JOIN
)
str
->
append
(
"straight_join "
,
14
);
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