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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
e8b74f68
Commit
e8b74f68
authored
Oct 11, 2004
by
unknown
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Manual merge with implementation for WL#1724
parent
22ecf1d7
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 @
e8b74f68
...
...
@@ -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 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
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 @
e8b74f68
...
...
@@ -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