Merge bk-internal.mysql.com:/data0/bk/mysql-5.1

into  bk-internal.mysql.com:/data0/bk/mysql-5.1-opt
This commit is contained in:
ibabaev@bk-internal.mysql.com 2007-03-30 20:00:12 +02:00
commit 8c3525ff31
27 changed files with 472 additions and 98 deletions

View file

@ -214,3 +214,12 @@ select count(*) from t1;
count(*)
0
drop table t1;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
DELETE FROM t1 ORDER BY x;
ERROR 42S22: Unknown column 'x' in 'order clause'
DELETE FROM t1 ORDER BY t2.x;
ERROR 42S22: Unknown column 't2.x' in 'order clause'
DELETE FROM t1 ORDER BY (SELECT x);
ERROR 42S22: Unknown column 'x' in 'field list'
DROP TABLE t1;

View file

@ -730,6 +730,12 @@ point(b, b) IS NULL linestring(b) IS NULL polygon(b) IS NULL multipoint(b) IS NU
1 1 1 1 1 1 1
0 1 1 1 1 1 1
drop table t1;
CREATE TABLE t1(a POINT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (NULL);
SELECT * FROM t1;
a
NULL
DROP TABLE t1;
End of 4.1 tests
create table t1 (s1 geometry not null,s2 char(100));
create trigger t1_bu before update on t1 for each row set new.s1 = null;

View file

@ -1141,4 +1141,9 @@ EXPLAIN SELECT 1 FROM t2 WHERE a IN
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 256 Using where
SHOW VARIABLES LIKE 'old';
Variable_name Value
old OFF
SET @@old = off;
ERROR HY000: Variable 'old' is a read only variable
DROP TABLE t1, t2;

View file

@ -717,6 +717,34 @@ d8c4177d225791924.30714720
d8c4177d2380fc201.39666693
d8c4177d24ccef970.14957924
DROP TABLE t1;
create table t1 (
c1 char(10), c2 char(10), c3 char(10), c4 char(10),
c5 char(10), c6 char(10), c7 char(10), c8 char(10),
c9 char(10), c10 char(10), c11 char(10), c12 char(10),
c13 char(10), c14 char(10), c15 char(10), c16 char(10),
index(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,c13,c14,c15,c16)
);
insert into t1 (c1) values ('1'),('1'),('1'),('1');
select * from t1 where
c1 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c2 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c3 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c4 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c5 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c6 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c7 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c8 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c9 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c10 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c11 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c12 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c13 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c14 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c15 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c16 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
;
c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16
drop table t1;
End of 4.1 tests
CREATE TABLE t1 (
id int(11) NOT NULL auto_increment,

View file

@ -621,3 +621,20 @@ Pos Instruction
0 stmt 2 "CREATE INDEX idx ON t1 (c1)"
DROP PROCEDURE p1;
End of 5.0 tests.
CREATE PROCEDURE p1()
BEGIN
DECLARE dummy int default 0;
CASE 12
WHEN 12
THEN SET dummy = 0;
END CASE;
END//
SHOW PROCEDURE CODE p1;
Pos Instruction
0 set dummy@0 0
1 set_case_expr (6) 0 12
2 jump_if_not 5(6) (case_expr@0 = 12)
3 set dummy@0 0
4 jump 6
5 error 1339
DROP PROCEDURE p1;

View file

@ -3905,6 +3905,48 @@ COUNT(*) a
2 2
3 3
DROP TABLE t1,t2;
CREATE TABLE t1 (a int, b int);
CREATE TABLE t2 (m int, n int);
INSERT INTO t1 VALUES (2,2), (2,2), (3,3), (3,3), (3,3), (4,4);
INSERT INTO t2 VALUES (1,11), (2,22), (3,32), (4,44), (4,44);
SELECT COUNT(*) c, a,
(SELECT GROUP_CONCAT(COUNT(a)) FROM t2 WHERE m = a)
FROM t1 GROUP BY a;
c a (SELECT GROUP_CONCAT(COUNT(a)) FROM t2 WHERE m = a)
2 2 2
3 3 3
1 4 1,1
SELECT COUNT(*) c, a,
(SELECT GROUP_CONCAT(COUNT(a)+1) FROM t2 WHERE m = a)
FROM t1 GROUP BY a;
c a (SELECT GROUP_CONCAT(COUNT(a)+1) FROM t2 WHERE m = a)
2 2 3
3 3 4
1 4 2,2
DROP table t1,t2;
CREATE TABLE t1 (a int, b int);
INSERT INTO t1 VALUES (2,22),(1,11),(2,22);
SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a;
a
1
2
SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a;
a
SELECT a FROM t1 t0
WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a;
a
1
2
SET @@sql_mode='ansi';
SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a;
ERROR HY000: Invalid use of group function
SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a;
ERROR HY000: Invalid use of group function
SELECT a FROM t1 t0
WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a;
ERROR HY000: Invalid use of group function
SET @@sql_mode=default;
DROP TABLE t1;
CREATE TABLE t1 (s1 char(1));
INSERT INTO t1 VALUES ('a');
SELECT * FROM t1 WHERE _utf8'a' = ANY (SELECT s1 FROM t1);

View file

@ -203,3 +203,21 @@ select * from t1 where a is null;
delete from t1 where a is null;
select count(*) from t1;
drop table t1;
#
# Bug #26186: delete order by, sometimes accept unknown column
#
CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1);
--error ER_BAD_FIELD_ERROR
DELETE FROM t1 ORDER BY x;
# even columns from a table not used in query (and not even existing)
--error ER_BAD_FIELD_ERROR
DELETE FROM t1 ORDER BY t2.x;
# subquery (as long as the subquery from is valid or DUAL)
--error ER_BAD_FIELD_ERROR
DELETE FROM t1 ORDER BY (SELECT x);
DROP TABLE t1;

View file

@ -424,6 +424,14 @@ from t1;
drop table t1;
#
# Bug #27164: Crash when mixing InnoDB and MyISAM Geospatial tables
#
CREATE TABLE t1(a POINT) ENGINE=MyISAM;
INSERT INTO t1 VALUES (NULL);
SELECT * FROM t1;
DROP TABLE t1;
--echo End of 4.1 tests
#

View file

@ -755,7 +755,8 @@ SET SQL_MODE = '';
#
# Bug #21174: Index degrades sort performance and
# optimizer does not honor IGNORE INDEX
# optimizer does not honor IGNORE INDEX.
# a.k.a WL3527.
#
CREATE TABLE t1 (a INT, b INT,
PRIMARY KEY (a),
@ -819,4 +820,8 @@ EXPLAIN SELECT a, SUM(b) FROM t2 IGNORE INDEX (a) GROUP BY a LIMIT 2;
EXPLAIN SELECT 1 FROM t2 WHERE a IN
(SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2));
SHOW VARIABLES LIKE 'old';
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
SET @@old = off;
DROP TABLE t1, t2;

View file

@ -568,6 +568,38 @@ SELECT s.oxid FROM t1 v, t1 s
DROP TABLE t1;
# BUG#26624 high mem usage (crash) in range optimizer (depends on order of fields in where)
create table t1 (
c1 char(10), c2 char(10), c3 char(10), c4 char(10),
c5 char(10), c6 char(10), c7 char(10), c8 char(10),
c9 char(10), c10 char(10), c11 char(10), c12 char(10),
c13 char(10), c14 char(10), c15 char(10), c16 char(10),
index(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,c13,c14,c15,c16)
);
insert into t1 (c1) values ('1'),('1'),('1'),('1');
# This must run without crash and fast:
select * from t1 where
c1 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c2 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c3 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c4 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c5 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c6 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c7 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c8 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c9 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c10 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c11 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c12 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c13 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c14 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c15 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
and c16 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh")
;
drop table t1;
--echo End of 4.1 tests
#

View file

@ -447,3 +447,21 @@ DROP PROCEDURE p1;
--echo End of 5.0 tests.
#
# Bug #26303: reserve() not called before qs_append() may lead to buffer
# overflow
#
DELIMITER //;
CREATE PROCEDURE p1()
BEGIN
DECLARE dummy int default 0;
CASE 12
WHEN 12
THEN SET dummy = 0;
END CASE;
END//
DELIMITER ;//
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;

View file

@ -2765,6 +2765,50 @@ SELECT COUNT(*), a
DROP TABLE t1,t2;
#
# Bug #27229: GROUP_CONCAT in subselect with COUNT() as an argument
#
CREATE TABLE t1 (a int, b int);
CREATE TABLE t2 (m int, n int);
INSERT INTO t1 VALUES (2,2), (2,2), (3,3), (3,3), (3,3), (4,4);
INSERT INTO t2 VALUES (1,11), (2,22), (3,32), (4,44), (4,44);
SELECT COUNT(*) c, a,
(SELECT GROUP_CONCAT(COUNT(a)) FROM t2 WHERE m = a)
FROM t1 GROUP BY a;
SELECT COUNT(*) c, a,
(SELECT GROUP_CONCAT(COUNT(a)+1) FROM t2 WHERE m = a)
FROM t1 GROUP BY a;
DROP table t1,t2;
#
# Bug #27348: SET FUNCTION used in a subquery from WHERE condition
#
CREATE TABLE t1 (a int, b int);
INSERT INTO t1 VALUES (2,22),(1,11),(2,22);
SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a;
SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a;
SELECT a FROM t1 t0
WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a;
SET @@sql_mode='ansi';
--error 1111
SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a;
--error 1111
SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a;
--error 1111
SELECT a FROM t1 t0
WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a;
SET @@sql_mode=default;
DROP TABLE t1;
# Bug#20835 (literal string with =any values)
#
CREATE TABLE t1 (s1 char(1));

View file

@ -1353,7 +1353,7 @@ public:
int store_decimal(const my_decimal *);
void get_key_image(char *buff,uint length,imagetype type);
uint size_of() const { return sizeof(*this); }
int reset(void) { return !maybe_null(); }
int reset(void) { return !maybe_null() || Field_blob::reset(); }
};
#endif /*HAVE_SPATIAL*/

View file

@ -1088,7 +1088,7 @@ bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **it)
Item_case_expr methods
*****************************************************************************/
Item_case_expr::Item_case_expr(int case_expr_id)
Item_case_expr::Item_case_expr(uint case_expr_id)
:Item_sp_variable( C_STRING_WITH_LEN("case_expr")),
m_case_expr_id(case_expr_id)
{
@ -1125,6 +1125,8 @@ Item_case_expr::this_item_addr(THD *thd, Item **)
void Item_case_expr::print(String *str)
{
if (str->reserve(MAX_INT_WIDTH + sizeof("case_expr@")))
return; /* purecov: inspected */
VOID(str->append(STRING_WITH_LEN("case_expr@")));
str->qs_append(m_case_expr_id);
}
@ -1289,15 +1291,18 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
Exception is Item_direct_view_ref which we need to convert to
Item_ref to allow fields from view being stored in tmp table.
*/
Item_aggregate_ref *item_ref;
uint el= fields.elements;
Item *new_item, *real_itm= real_item();
Item *real_itm= real_item();
ref_pointer_array[el]= real_itm;
if (!(new_item= new Item_aggregate_ref(&thd->lex->current_select->context,
if (!(item_ref= new Item_aggregate_ref(&thd->lex->current_select->context,
ref_pointer_array + el, 0, name)))
return; // fatal_error is set
if (type() == SUM_FUNC_ITEM)
item_ref->depended_from= ((Item_sum *) this)->depended_from();
fields.push_front(real_itm);
thd->change_item_tree(ref, new_item);
thd->change_item_tree(ref, item_ref);
}
}

View file

@ -1116,7 +1116,7 @@ inline Item_result Item_splocal::result_type() const
class Item_case_expr :public Item_sp_variable
{
public:
Item_case_expr(int case_expr_id);
Item_case_expr(uint case_expr_id);
public:
Item *this_item();
@ -1135,7 +1135,7 @@ public:
void print(String *str);
private:
int m_case_expr_id;
uint m_case_expr_id;
};
/*****************************************************************************

View file

@ -61,9 +61,9 @@ bool Item_sum::init_sum_func_check(THD *thd)
/* Save a pointer to object to be used in items for nested set functions */
thd->lex->in_sum_func= this;
nest_level= thd->lex->current_select->nest_level;
nest_level_tables_count= thd->lex->current_select->join->tables;
ref_by= 0;
aggr_level= -1;
aggr_sel= NULL;
max_arg_level= -1;
max_sum_func_level= -1;
return FALSE;
@ -149,9 +149,14 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
if (register_sum_func(thd, ref))
return TRUE;
invalid= aggr_level < 0 && !(allow_sum_func & (1 << nest_level));
if (!invalid && thd->variables.sql_mode & MODE_ANSI)
invalid= aggr_level < 0 && max_arg_level < nest_level;
}
if (!invalid && aggr_level < 0)
{
aggr_level= nest_level;
aggr_sel= thd->lex->current_select;
}
/*
By this moment we either found a subquery where the set function is
to be aggregated and assigned a value that is >= 0 to aggr_level,
@ -161,8 +166,9 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
Additionally we have to check whether possible nested set functions
are acceptable here: they are not, if the level of aggregation of
some of them is less than aggr_level.
*/
invalid= aggr_level <= max_sum_func_level;
*/
if (!invalid)
invalid= aggr_level <= max_sum_func_level;
if (invalid)
{
my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
@ -212,7 +218,6 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
bool Item_sum::register_sum_func(THD *thd, Item **ref)
{
SELECT_LEX *sl;
SELECT_LEX *aggr_sl= NULL;
nesting_map allow_sum_func= thd->lex->allow_sum_func;
for (sl= thd->lex->current_select->master_unit()->outer_select() ;
sl && sl->nest_level > max_arg_level;
@ -222,7 +227,7 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
{
/* Found the most nested subquery where the function can be aggregated */
aggr_level= sl->nest_level;
aggr_sl= sl;
aggr_sel= sl;
}
}
if (sl && (allow_sum_func & (1 << sl->nest_level)))
@ -233,21 +238,22 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
The set function will be aggregated in this subquery.
*/
aggr_level= sl->nest_level;
aggr_sl= sl;
aggr_sel= sl;
}
if (aggr_level >= 0)
{
ref_by= ref;
/* Add the object to the list of registered objects assigned to aggr_sl */
if (!aggr_sl->inner_sum_func_list)
/* Add the object to the list of registered objects assigned to aggr_sel */
if (!aggr_sel->inner_sum_func_list)
next= this;
else
{
next= aggr_sl->inner_sum_func_list->next;
aggr_sl->inner_sum_func_list->next= this;
next= aggr_sel->inner_sum_func_list->next;
aggr_sel->inner_sum_func_list->next= this;
}
aggr_sl->inner_sum_func_list= this;
aggr_sl->with_sum_func= 1;
aggr_sel->inner_sum_func_list= this;
aggr_sel->with_sum_func= 1;
/*
Mark Item_subselect(s) as containing aggregate function all the way up
@ -265,11 +271,11 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
has aggregate functions directly referenced (i.e. not through a sub-select).
*/
for (sl= thd->lex->current_select;
sl && sl != aggr_sl && sl->master_unit()->item;
sl && sl != aggr_sel && sl->master_unit()->item;
sl= sl->master_unit()->outer_select() )
sl->master_unit()->item->with_sum_func= 1;
}
thd->lex->current_select->mark_as_dependent(aggr_sl);
thd->lex->current_select->mark_as_dependent(aggr_sel);
return FALSE;
}
@ -299,10 +305,10 @@ Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements),
Item_sum::Item_sum(THD *thd, Item_sum *item):
Item_result_field(thd, item), arg_count(item->arg_count),
aggr_sel(item->aggr_sel),
nest_level(item->nest_level), aggr_level(item->aggr_level),
quick_group(item->quick_group), used_tables_cache(item->used_tables_cache),
forced_const(item->forced_const),
nest_level_tables_count(item->nest_level_tables_count)
forced_const(item->forced_const)
{
if (arg_count <= 2)
args=tmp_args;
@ -449,8 +455,7 @@ void Item_sum::update_used_tables ()
used_tables_cache&= PSEUDO_TABLE_BITS;
/* the aggregate function is aggregated into its local context */
if (aggr_level == nest_level)
used_tables_cache |= (1 << nest_level_tables_count) - 1;
used_tables_cache |= (1 << aggr_sel->join->tables) - 1;
}
}

View file

@ -233,6 +233,7 @@ public:
Item_sum *next; /* next in the circular chain of registered objects */
uint arg_count;
Item_sum *in_sum_func; /* embedding set function if any */
st_select_lex * aggr_sel; /* select where the function is aggregated */
int8 nest_level; /* number of the nesting level of the set function */
int8 aggr_level; /* nesting level of the aggregating subquery */
int8 max_arg_level; /* max level of unbound column references */
@ -242,7 +243,6 @@ public:
protected:
table_map used_tables_cache;
bool forced_const;
byte nest_level_tables_count;
public:
@ -365,6 +365,8 @@ public:
bool init_sum_func_check(THD *thd);
bool check_sum_func(THD *thd, Item **ref);
bool register_sum_func(THD *thd, Item **ref);
st_select_lex *depended_from()
{ return (nest_level == aggr_level ? 0 : aggr_sel); }
};

View file

@ -6271,7 +6271,7 @@ The minimum value for this variable is 4096.",
(gptr*) &global_system_variables.net_write_timeout,
(gptr*) &max_system_variables.net_write_timeout, 0, GET_ULONG,
REQUIRED_ARG, NET_WRITE_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
{ "old_mode", OPT_OLD_MODE, "Use compatible behaviour.",
{ "old", OPT_OLD_MODE, "Use compatible behavior.",
(gptr*) &global_system_variables.old_mode,
(gptr*) &max_system_variables.old_mode, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},

View file

@ -84,7 +84,7 @@ static int sel_cmp(Field *f,char *a,char *b,uint8 a_flag,uint8 b_flag);
static char is_null_string[2]= {1,0};
class RANGE_OPT_PARAM;
/*
A construction block of the SEL_ARG-graph.
@ -170,6 +170,89 @@ static char is_null_string[2]= {1,0};
- get_quick_select() - Walk the SEL_ARG, materialize the key intervals,
and create QUICK_RANGE_SELECT object that will
read records within these intervals.
4. SPACE COMPLEXITY NOTES
SEL_ARG graph is a representation of an ordered disjoint sequence of
intervals over the ordered set of index tuple values.
For multi-part keys, one can construct a WHERE expression such that its
list of intervals will be of combinatorial size. Here is an example:
(keypart1 IN (1,2, ..., n1)) AND
(keypart2 IN (1,2, ..., n2)) AND
(keypart3 IN (1,2, ..., n3))
For this WHERE clause the list of intervals will have n1*n2*n3 intervals
of form
(keypart1, keypart2, keypart3) = (k1, k2, k3), where 1 <= k{i} <= n{i}
SEL_ARG graph structure aims to reduce the amount of required space by
"sharing" the elementary intervals when possible (the pic at the
beginning of this comment has examples of such sharing). The sharing may
prevent combinatorial blowup:
There are WHERE clauses that have combinatorial-size interval lists but
will be represented by a compact SEL_ARG graph.
Example:
(keypartN IN (1,2, ..., n1)) AND
...
(keypart2 IN (1,2, ..., n2)) AND
(keypart1 IN (1,2, ..., n3))
but not in all cases:
- There are WHERE clauses that do have a compact SEL_ARG-graph
representation but get_mm_tree() and its callees will construct a
graph of combinatorial size.
Example:
(keypart1 IN (1,2, ..., n1)) AND
(keypart2 IN (1,2, ..., n2)) AND
...
(keypartN IN (1,2, ..., n3))
- There are WHERE clauses for which the minimal possible SEL_ARG graph
representation will have combinatorial size.
Example:
By induction: Let's take any interval on some keypart in the middle:
kp15=c0
Then let's AND it with this interval 'structure' from preceding and
following keyparts:
(kp14=c1 AND kp16=c3) OR keypart14=c2) (*)
We will obtain this SEL_ARG graph:
kp14 $ kp15 $ kp16
$ $
+---------+ $ +---------+ $ +---------+
| kp14=c1 |--$-->| kp15=c0 |--$-->| kp16=c3 |
+---------+ $ +---------+ $ +---------+
| $ $
+---------+ $ +---------+ $
| kp14=c2 |--$-->| kp15=c0 | $
+---------+ $ +---------+ $
$ $
Note that we had to duplicate "kp15=c0" and there was no way to avoid
that.
The induction step: AND the obtained expression with another "wrapping"
expression like (*).
When the process ends because of the limit on max. number of keyparts
we'll have:
WHERE clause length is O(3*#max_keyparts)
SEL_ARG graph size is O(2^(#max_keyparts/2))
(it is also possible to construct a case where instead of 2 in 2^n we
have a bigger constant, e.g. 4, and get a graph with 4^(31/2)= 2^31
nodes)
We avoid consuming too much memory by setting a limit on the number of
SEL_ARG object we can construct during one range analysis invocation.
*/
class SEL_ARG :public Sql_alloc
@ -200,6 +283,8 @@ public:
enum leaf_color { BLACK,RED } color;
enum Type { IMPOSSIBLE, MAYBE, MAYBE_KEY, KEY_RANGE } type;
enum { MAX_SEL_ARGS = 64000 };
SEL_ARG() {}
SEL_ARG(SEL_ARG &);
SEL_ARG(Field *,const char *,const char *);
@ -271,7 +356,7 @@ public:
return new SEL_ARG(field, part, min_value, arg->max_value,
min_flag, arg->max_flag, maybe_flag | arg->maybe_flag);
}
SEL_ARG *clone(SEL_ARG *new_parent,SEL_ARG **next);
SEL_ARG *clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, SEL_ARG **next);
bool copy_min(SEL_ARG* arg)
{ // Get overlapping range
@ -423,7 +508,6 @@ public:
{
return parent->left == this ? &parent->left : &parent->right;
}
SEL_ARG *clone_tree();
/*
@ -466,6 +550,7 @@ public:
}
return !field->key_cmp(min_val, max_val);
}
SEL_ARG *clone_tree(RANGE_OPT_PARAM *param);
};
class SEL_IMERGE;
@ -545,6 +630,8 @@ public:
using_real_indexes==TRUE
*/
uint real_keynr[MAX_KEY];
/* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */
uint alloced_sel_args;
};
class PARAM : public RANGE_OPT_PARAM
@ -634,8 +721,9 @@ static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg);
static SEL_TREE *tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
static SEL_TREE *tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
static SEL_ARG *sel_add(SEL_ARG *key1,SEL_ARG *key2);
static SEL_ARG *key_or(SEL_ARG *key1,SEL_ARG *key2);
static SEL_ARG *key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag);
static SEL_ARG *key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2);
static SEL_ARG *key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2,
uint clone_flag);
static bool get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1);
bool get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
SEL_ARG *key_tree,char *min_key,uint min_key_flag,
@ -860,6 +948,7 @@ int imerge_list_or_tree(RANGE_OPT_PARAM *param,
return im1->is_empty();
}
/***************************************************************************
** Basic functions for SQL_SELECT and QUICK_RANGE_SELECT
***************************************************************************/
@ -1510,12 +1599,18 @@ SEL_ARG::SEL_ARG(Field *field_,uint8 part_,char *min_value_,char *max_value_,
left=right= &null_element;
}
SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg)
SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent,
SEL_ARG **next_arg)
{
SEL_ARG *tmp;
/* Bail out if we have already generated too many SEL_ARGs */
if (++param->alloced_sel_args > MAX_SEL_ARGS)
return 0;
if (type != KEY_RANGE)
{
if (!(tmp= new SEL_ARG(type)))
if (!(tmp= new (param->mem_root) SEL_ARG(type)))
return 0; // out of memory
tmp->prev= *next_arg; // Link into next/prev chain
(*next_arg)->next=tmp;
@ -1523,20 +1618,21 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg)
}
else
{
if (!(tmp= new SEL_ARG(field,part, min_value,max_value,
min_flag, max_flag, maybe_flag)))
if (!(tmp= new (param->mem_root) SEL_ARG(field,part, min_value,max_value,
min_flag, max_flag, maybe_flag)))
return 0; // OOM
tmp->parent=new_parent;
tmp->next_key_part=next_key_part;
if (left != &null_element)
tmp->left=left->clone(tmp,next_arg);
if (!(tmp->left=left->clone(param, tmp, next_arg)))
return 0; // OOM
tmp->prev= *next_arg; // Link into next/prev chain
(*next_arg)->next=tmp;
(*next_arg)= tmp;
if (right != &null_element)
if (!(tmp->right= right->clone(tmp,next_arg)))
if (!(tmp->right= right->clone(param, tmp, next_arg)))
return 0; // OOM
}
increment_use_count(1);
@ -1614,11 +1710,12 @@ static int sel_cmp(Field *field, char *a,char *b,uint8 a_flag,uint8 b_flag)
}
SEL_ARG *SEL_ARG::clone_tree()
SEL_ARG *SEL_ARG::clone_tree(RANGE_OPT_PARAM *param)
{
SEL_ARG tmp_link,*next_arg,*root;
next_arg= &tmp_link;
root= clone((SEL_ARG *) 0, &next_arg);
if (!(root= clone(param, (SEL_ARG *) 0, &next_arg)))
return 0;
next_arg->next=0; // Fix last link
tmp_link.next->prev=0; // Fix first link
if (root) // If not OOM
@ -2120,6 +2217,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.real_keynr[param.keys++]=idx;
}
param.key_parts_end=key_parts;
param.alloced_sel_args= 0;
/* Calculate cost of full index read for the shortest covering index */
if (!head->covering_keys.is_clear_all())
@ -2512,6 +2610,7 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
range_par->using_real_indexes= FALSE;
range_par->remove_jump_scans= FALSE;
range_par->real_keynr[0]= 0;
range_par->alloced_sel_args= 0;
thd->no_errors=1; // Don't warn about NULL
thd->mem_root=&alloc;
@ -5242,7 +5341,8 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
while ((item=li++))
{
SEL_TREE *new_tree=get_mm_tree(param,item);
if (param->thd->is_fatal_error)
if (param->thd->is_fatal_error ||
param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS)
DBUG_RETURN(0); // out of memory
tree=tree_and(param,tree,new_tree);
if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
@ -5818,9 +5918,9 @@ tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
tree1->type=SEL_TREE::KEY_SMALLER;
DBUG_RETURN(tree1);
}
key_map result_keys;
result_keys.clear_all();
/* Join the trees key per key */
SEL_ARG **key1,**key2,**end;
for (key1= tree1->keys,key2= tree2->keys,end=key1+param->keys ;
@ -5833,7 +5933,7 @@ tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
flag|=CLONE_KEY1_MAYBE;
if (*key2 && !(*key2)->simple_key())
flag|=CLONE_KEY2_MAYBE;
*key1=key_and(*key1,*key2,flag);
*key1=key_and(param, *key1, *key2, flag);
if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE)
{
tree1->type= SEL_TREE::IMPOSSIBLE;
@ -5994,7 +6094,7 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
for (key1= tree1->keys,key2= tree2->keys,end= key1+param->keys ;
key1 != end ; key1++,key2++)
{
*key1=key_or(*key1,*key2);
*key1=key_or(param, *key1, *key2);
if (*key1)
{
result=tree1; // Added to tree1
@ -6058,14 +6158,15 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
/* And key trees where key1->part < key2 -> part */
static SEL_ARG *
and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
and_all_keys(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2,
uint clone_flag)
{
SEL_ARG *next;
ulong use_count=key1->use_count;
if (key1->elements != 1)
{
key2->use_count+=key1->elements-1;
key2->use_count+=key1->elements-1; //psergey: why we don't count that key1 has n-k-p?
key2->increment_use_count((int) key1->elements-1);
}
if (key1->type == SEL_ARG::MAYBE_KEY)
@ -6077,7 +6178,7 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
{
if (next->next_key_part)
{
SEL_ARG *tmp=key_and(next->next_key_part,key2,clone_flag);
SEL_ARG *tmp= key_and(param, next->next_key_part, key2, clone_flag);
if (tmp && tmp->type == SEL_ARG::IMPOSSIBLE)
{
key1=key1->tree_delete(next);
@ -6086,6 +6187,8 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
next->next_key_part=tmp;
if (use_count)
next->increment_use_count(use_count);
if (param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS)
break;
}
else
next->next_key_part=key2;
@ -6102,8 +6205,10 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
SYNOPSIS
key_and()
key1 First argument, root of its RB-tree
key2 Second argument, root of its RB-tree
param Range analysis context (needed to track if we have allocated
too many SEL_ARGs)
key1 First argument, root of its RB-tree
key2 Second argument, root of its RB-tree
RETURN
RB-tree root of the resulting SEL_ARG graph.
@ -6111,7 +6216,7 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
*/
static SEL_ARG *
key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
{
if (!key1)
return key2;
@ -6127,9 +6232,9 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
// key1->part < key2->part
key1->use_count--;
if (key1->use_count > 0)
if (!(key1= key1->clone_tree()))
if (!(key1= key1->clone_tree(param)))
return 0; // OOM
return and_all_keys(key1,key2,clone_flag);
return and_all_keys(param, key1, key2, clone_flag);
}
if (((clone_flag & CLONE_KEY2_MAYBE) &&
@ -6147,14 +6252,14 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
if (key1->use_count > 1)
{
key1->use_count--;
if (!(key1=key1->clone_tree()))
if (!(key1=key1->clone_tree(param)))
return 0; // OOM
key1->use_count++;
}
if (key1->type == SEL_ARG::MAYBE_KEY)
{ // Both are maybe key
key1->next_key_part=key_and(key1->next_key_part,key2->next_key_part,
clone_flag);
key1->next_key_part=key_and(param, key1->next_key_part,
key2->next_key_part, clone_flag);
if (key1->next_key_part &&
key1->next_key_part->type == SEL_ARG::IMPOSSIBLE)
return key1;
@ -6165,7 +6270,7 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
if (key2->next_key_part)
{
key1->use_count--; // Incremented in and_all_keys
return and_all_keys(key1,key2,clone_flag);
return and_all_keys(param, key1, key2, clone_flag);
}
key2->use_count--; // Key2 doesn't have a tree
}
@ -6201,7 +6306,8 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
}
else if (get_range(&e2,&e1,key2))
continue;
SEL_ARG *next=key_and(e1->next_key_part,e2->next_key_part,clone_flag);
SEL_ARG *next=key_and(param, e1->next_key_part, e2->next_key_part,
clone_flag);
e1->increment_use_count(1);
e2->increment_use_count(1);
if (!next || next->type != SEL_ARG::IMPOSSIBLE)
@ -6249,7 +6355,7 @@ get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1)
static SEL_ARG *
key_or(SEL_ARG *key1,SEL_ARG *key2)
key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
{
if (!key1)
{
@ -6297,7 +6403,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
{
swap_variables(SEL_ARG *,key1,key2);
}
if (key1->use_count > 0 || !(key1=key1->clone_tree()))
if (key1->use_count > 0 || !(key1=key1->clone_tree(param)))
return 0; // OOM
}
@ -6441,7 +6547,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
{ // tmp.min. <= x <= tmp.max
tmp->maybe_flag|= key.maybe_flag;
key.increment_use_count(key1->use_count+1);
tmp->next_key_part=key_or(tmp->next_key_part,key.next_key_part);
tmp->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part);
if (!cmp) // Key2 is ready
break;
key.copy_max_to_min(tmp);
@ -6472,7 +6578,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
tmp->increment_use_count(key1->use_count+1);
/* Increment key count as it may be used for next loop */
key.increment_use_count(1);
new_arg->next_key_part=key_or(tmp->next_key_part,key.next_key_part);
new_arg->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part);
key1=key1->insert(new_arg);
break;
}

View file

@ -356,6 +356,8 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count",
&SV::net_retry_count,
0, fix_net_retry_count);
sys_var_thd_bool sys_new_mode("new", &SV::new_mode);
sys_var_bool_ptr_readonly sys_old_mode("old",
&global_system_variables.old_mode);
sys_var_thd_bool sys_old_alter_table("old_alter_table",
&SV::old_alter_table);
sys_var_thd_bool sys_old_passwords("old_passwords", &SV::old_passwords);
@ -942,6 +944,7 @@ SHOW_VAR init_vars[]= {
{sys_net_retry_count.name, (char*) &sys_net_retry_count, SHOW_SYS},
{sys_net_write_timeout.name,(char*) &sys_net_write_timeout, SHOW_SYS},
{sys_new_mode.name, (char*) &sys_new_mode, SHOW_SYS},
{sys_old_mode.name, (char*) &sys_old_mode, SHOW_SYS},
{sys_old_alter_table.name, (char*) &sys_old_alter_table, SHOW_SYS},
{sys_old_passwords.name, (char*) &sys_old_passwords, SHOW_SYS},
{"open_files_limit", (char*) &open_files_limit, SHOW_LONG},

View file

@ -169,6 +169,16 @@ public:
};
class sys_var_bool_ptr_readonly :public sys_var_bool_ptr
{
public:
sys_var_bool_ptr_readonly(const char *name_arg, my_bool *value_arg)
:sys_var_bool_ptr(name_arg, value_arg)
{}
bool is_readonly() const { return 1; }
};
class sys_var_str :public sys_var
{
public:

View file

@ -5838,7 +5838,6 @@ bool setup_tables_and_check_access(THD *thd,
TABLE_LIST *leaves_tmp= NULL;
bool first_table= true;
thd->leaf_count= 0;
if (setup_tables(thd, context, from_clause, tables,
&leaves_tmp, select_insert))
return TRUE;
@ -5856,7 +5855,6 @@ bool setup_tables_and_check_access(THD *thd,
return TRUE;
}
first_table= 0;
thd->leaf_count++;
}
return FALSE;
}

View file

@ -1412,9 +1412,6 @@ public:
partition_info *work_part_info;
#endif
/* pass up the count of "leaf" tables in a JOIN out of setup_tables() */
byte leaf_count;
THD();
~THD();

View file

@ -54,6 +54,27 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (mysql_prepare_delete(thd, table_list, &conds))
DBUG_RETURN(TRUE);
/* check ORDER BY even if it can be ignored */
if (order && order->elements)
{
TABLE_LIST tables;
List<Item> fields;
List<Item> all_fields;
bzero((char*) &tables,sizeof(tables));
tables.table = table;
tables.alias = table_list->alias;
if (select_lex->setup_ref_array(thd, order->elements) ||
setup_order(thd, select_lex->ref_pointer_array, &tables,
fields, all_fields, (ORDER*) order->first))
{
delete select;
free_underlaid_joins(thd, &thd->lex->select_lex);
DBUG_RETURN(TRUE);
}
}
const_cond= (!conds || conds->const_item());
safe_update=test(thd->options & OPTION_SAFE_UPDATES);
if (safe_update && const_cond)
@ -155,23 +176,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{
uint length= 0;
SORT_FIELD *sortorder;
TABLE_LIST tables;
List<Item> fields;
List<Item> all_fields;
ha_rows examined_rows;
bzero((char*) &tables,sizeof(tables));
tables.table = table;
tables.alias = table_list->alias;
if (select_lex->setup_ref_array(thd, order->elements) ||
setup_order(thd, select_lex->ref_pointer_array, &tables,
fields, all_fields, (ORDER*) order->first))
{
delete select;
free_underlaid_joins(thd, &thd->lex->select_lex);
DBUG_RETURN(TRUE);
}
if ((!select || table->quick_keys.is_clear_all()) && limit != HA_POS_ERROR)
usable_index= get_index_for_order(table, (ORDER*)(order->first), limit);

View file

@ -2466,14 +2466,12 @@ bool mysql_insert_select_prepare(THD *thd)
DBUG_ASSERT(select_lex->leaf_tables != 0);
lex->leaf_tables_insert= select_lex->leaf_tables;
/* skip all leaf tables belonged to view where we are insert */
for (first_select_leaf_table= select_lex->leaf_tables->next_leaf,
thd->leaf_count --;
for (first_select_leaf_table= select_lex->leaf_tables->next_leaf;
first_select_leaf_table &&
first_select_leaf_table->belong_to_view &&
first_select_leaf_table->belong_to_view ==
lex->leaf_tables_insert->belong_to_view;
first_select_leaf_table= first_select_leaf_table->next_leaf,
thd->leaf_count --)
first_select_leaf_table= first_select_leaf_table->next_leaf)
{}
select_lex->leaf_tables= first_select_leaf_table;
DBUG_RETURN(FALSE);

View file

@ -23,7 +23,7 @@
class Sql_alloc
{
public:
static void *operator new(size_t size)
static void *operator new(size_t size) throw ()
{
return (void*) sql_alloc((uint) size);
}
@ -31,9 +31,9 @@ public:
{
return (void*) sql_alloc((uint) size);
}
static void *operator new[](size_t size, MEM_ROOT *mem_root)
static void *operator new[](size_t size, MEM_ROOT *mem_root) throw ()
{ return (void*) alloc_root(mem_root, (uint) size); }
static void *operator new(size_t size, MEM_ROOT *mem_root)
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
{ return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root)

View file

@ -413,7 +413,12 @@ JOIN::prepare(Item ***rref_pointer_array,
tables_list, &select_lex->leaf_tables,
FALSE, SELECT_ACL, SELECT_ACL))
DBUG_RETURN(-1);
tables= thd->leaf_count;
TABLE_LIST *table_ptr;
for (table_ptr= select_lex->leaf_tables;
table_ptr;
table_ptr= table_ptr->next_leaf)
tables++;
if (setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
select_lex->setup_ref_array(thd, og_num) ||
@ -9417,13 +9422,19 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
{
if (item->with_sum_func && type != Item::SUM_FUNC_ITEM)
{
/*
Mark that the we have ignored an item that refers to a summary
function. We need to know this if someone is going to use
DISTINCT on the result.
*/
param->using_indirect_summary_function=1;
continue;
if (item->used_tables() & OUTER_REF_TABLE_BIT)
item->update_used_tables();
if (type == Item::SUBSELECT_ITEM ||
(item->used_tables() & ~OUTER_REF_TABLE_BIT))
{
/*
Mark that the we have ignored an item that refers to a summary
function. We need to know this if someone is going to use
DISTINCT on the result.
*/
param->using_indirect_summary_function=1;
continue;
}
}
if (item->const_item() && (int) hidden_field_count <= 0)
continue; // We don't have to store this
@ -9608,6 +9619,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
share->default_values= table->record[1]+alloc_length;
}
copy_func[0]=0; // End marker
param->func_count= copy_func - param->items_to_copy;
setup_tmp_table_column_bitmaps(table, bitmaps);
@ -13824,6 +13836,7 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
if (!sum_item->quick_group)
param->quick_group=0; // UDF SUM function
param->sum_func_count++;
param->func_count++;
for (uint i=0 ; i < sum_item->arg_count ; i++)
{