Commit fca2a0c4 authored by gkodinov/kgeorge@magare.gmz's avatar gkodinov/kgeorge@magare.gmz

Merge gkodinov@bk-internal.mysql.com:/home/bk/mysql-5.0-opt

into  magare.gmz:/home/kgeorge/mysql/autopush/B26815-5.0-opt
parents 57b71f34 82ecff6a
...@@ -769,3 +769,14 @@ create table t1 (g geometry not null); ...@@ -769,3 +769,14 @@ create table t1 (g geometry not null);
insert into t1 values(default); insert into t1 values(default);
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
drop table t1; drop table t1;
CREATE TABLE t1 (a GEOMETRY);
CREATE VIEW v1 AS SELECT GeomFromwkb(ASBINARY(a)) FROM t1;
CREATE VIEW v2 AS SELECT a FROM t1;
DESCRIBE v1;
Field Type Null Key Default Extra
GeomFromwkb(ASBINARY(a)) geometry YES NULL
DESCRIBE v2;
Field Type Null Key Default Extra
a geometry YES NULL
DROP VIEW v1,v2;
DROP TABLE t1;
...@@ -717,6 +717,34 @@ d8c4177d225791924.30714720 ...@@ -717,6 +717,34 @@ d8c4177d225791924.30714720
d8c4177d2380fc201.39666693 d8c4177d2380fc201.39666693
d8c4177d24ccef970.14957924 d8c4177d24ccef970.14957924
DROP TABLE t1; 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 End of 4.1 tests
CREATE TABLE t1 ( CREATE TABLE t1 (
id int(11) NOT NULL auto_increment, id int(11) NOT NULL auto_increment,
......
...@@ -3924,3 +3924,26 @@ c a (SELECT GROUP_CONCAT(COUNT(a)+1) FROM t2 WHERE m = a) ...@@ -3924,3 +3924,26 @@ c a (SELECT GROUP_CONCAT(COUNT(a)+1) FROM t2 WHERE m = a)
3 3 4 3 3 4
1 4 2,2 1 4 2,2
DROP table t1,t2; 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;
...@@ -661,12 +661,6 @@ SELECT * FROM t1 GROUP by t1.a ...@@ -661,12 +661,6 @@ SELECT * FROM t1 GROUP by t1.a
HAVING (MAX(t1.b) > (SELECT MAX(t2.b) FROM t2 WHERE t2.c < t1.c HAVING (MAX(t1.b) > (SELECT MAX(t2.b) FROM t2 WHERE t2.c < t1.c
HAVING MAX(t2.b+t1.a) < 10)); HAVING MAX(t2.b+t1.a) < 10));
a b c a b c
SELECT a, AVG(b), (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=AVG(t1.b))
AS test FROM t1 GROUP BY a;
a AVG(b) test
1 4.0000 NULL
2 2.0000 k
3 2.5000 NULL
SELECT a,b,c FROM t1 WHERE b in (9,3,4) ORDER BY b,c; SELECT a,b,c FROM t1 WHERE b in (9,3,4) ORDER BY b,c;
a b c a b c
1 3 c 1 3 c
......
...@@ -479,3 +479,14 @@ create table t1 (g geometry not null); ...@@ -479,3 +479,14 @@ create table t1 (g geometry not null);
insert into t1 values(default); insert into t1 values(default);
drop table t1; drop table t1;
#
# Bug #27300: create view with geometry functions lost columns types
#
CREATE TABLE t1 (a GEOMETRY);
CREATE VIEW v1 AS SELECT GeomFromwkb(ASBINARY(a)) FROM t1;
CREATE VIEW v2 AS SELECT a FROM t1;
DESCRIBE v1;
DESCRIBE v2;
DROP VIEW v1,v2;
DROP TABLE t1;
...@@ -568,6 +568,38 @@ SELECT s.oxid FROM t1 v, t1 s ...@@ -568,6 +568,38 @@ SELECT s.oxid FROM t1 v, t1 s
DROP TABLE t1; 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 --echo End of 4.1 tests
# #
......
...@@ -2782,3 +2782,30 @@ SELECT COUNT(*) c, a, ...@@ -2782,3 +2782,30 @@ SELECT COUNT(*) c, a,
FROM t1 GROUP BY a; FROM t1 GROUP BY a;
DROP table t1,t2; 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;
...@@ -507,8 +507,9 @@ SELECT a, MAX(b), (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=MAX(t1.b)) ...@@ -507,8 +507,9 @@ SELECT a, MAX(b), (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=MAX(t1.b))
SELECT * FROM t1 GROUP by t1.a SELECT * FROM t1 GROUP by t1.a
HAVING (MAX(t1.b) > (SELECT MAX(t2.b) FROM t2 WHERE t2.c < t1.c HAVING (MAX(t1.b) > (SELECT MAX(t2.b) FROM t2 WHERE t2.c < t1.c
HAVING MAX(t2.b+t1.a) < 10)); HAVING MAX(t2.b+t1.a) < 10));
SELECT a, AVG(b), (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=AVG(t1.b)) #FIXME: Enable this test after fixing bug #27321
AS test FROM t1 GROUP BY a; #SELECT a, AVG(b), (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=AVG(t1.b))
# AS test FROM t1 GROUP BY a;
SELECT a,b,c FROM t1 WHERE b in (9,3,4) ORDER BY b,c; SELECT a,b,c FROM t1 WHERE b in (9,3,4) ORDER BY b,c;
......
...@@ -4275,7 +4275,6 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) ...@@ -4275,7 +4275,6 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB: case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_GEOMETRY:
if (this->type() == Item::TYPE_HOLDER) if (this->type() == Item::TYPE_HOLDER)
return new Field_blob(max_length, maybe_null, name, table, return new Field_blob(max_length, maybe_null, name, table,
collation.collation, 1); collation.collation, 1);
...@@ -4283,6 +4282,10 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) ...@@ -4283,6 +4282,10 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
return new Field_blob(max_length, maybe_null, name, table, return new Field_blob(max_length, maybe_null, name, table,
collation.collation); collation.collation);
break; // Blob handled outside of case break; // Blob handled outside of case
case MYSQL_TYPE_GEOMETRY:
return new Field_geom(max_length, maybe_null, name, table,
(Field::geometry_type)
((Item_geometry_func *)this)->get_geometry_type());
} }
} }
......
...@@ -149,6 +149,8 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) ...@@ -149,6 +149,8 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
if (register_sum_func(thd, ref)) if (register_sum_func(thd, ref))
return TRUE; return TRUE;
invalid= aggr_level < 0 && !(allow_sum_func & (1 << nest_level)); 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) if (!invalid && aggr_level < 0)
{ {
...@@ -164,8 +166,9 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) ...@@ -164,8 +166,9 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
Additionally we have to check whether possible nested set functions Additionally we have to check whether possible nested set functions
are acceptable here: they are not, if the level of aggregation of are acceptable here: they are not, if the level of aggregation of
some of them is less than aggr_level. 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) if (invalid)
{ {
my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE), my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
......
***************
*** 177,188 ****
} /* cplusplus */
- #if defined(HAVE_LINUXTHREADS)
- #define THR_KILL_SIGNAL SIGINT
- #else
- #define THR_KILL_SIGNAL SIGUSR2 // Can't use this with LinuxThreads
- #endif
-
#ifdef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R
#include <sys/types.h>
#else
--- 177,182 ----
} /* cplusplus */
#ifdef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R
#include <sys/types.h>
#else
***************
*** 505,510 ****
static void clean_up_mutexes(void);
static int test_if_case_insensitive(const char *dir_name);
static void create_pid_file();
/****************************************************************************
** Code to end mysqld
--- 499,505 ----
static void clean_up_mutexes(void);
static int test_if_case_insensitive(const char *dir_name);
static void create_pid_file();
+ static uint get_thread_lib(void);
/****************************************************************************
** Code to end mysqld
***************
*** 544,550 ****
DBUG_PRINT("info",("Waiting for select_thread"));
#ifndef DONT_USE_THR_ALARM
! if (pthread_kill(select_thread,THR_CLIENT_ALARM))
break; // allready dead
#endif
set_timespec(abstime, 2);
--- 539,546 ----
DBUG_PRINT("info",("Waiting for select_thread"));
#ifndef DONT_USE_THR_ALARM
! if (pthread_kill(select_thread,
! thd_lib_detected == THD_LIB_LT ? SIGALRM : SIGUSR1))
break; // allready dead
#endif
set_timespec(abstime, 2);
***************
*** 844,850 ****
sig,my_thread_id());
}
#ifdef DONT_REMEMBER_SIGNAL
! sigset(sig,print_signal_warning); /* int. thread system calls */
#endif
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
if (sig == SIGALRM)
--- 840,846 ----
sig,my_thread_id());
}
#ifdef DONT_REMEMBER_SIGNAL
! my_sigset(sig, print_signal_warning); /* int. thread system calls */
#endif
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
if (sig == SIGALRM)
***************
*** 1841,1848 ****
DBUG_ENTER("init_signals");
if (test_flags & TEST_SIGINT)
! sigset(THR_KILL_SIGNAL,end_thread_signal);
! sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called!
if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL))
{
--- 1837,1847 ----
DBUG_ENTER("init_signals");
if (test_flags & TEST_SIGINT)
! {
! my_sigset(thd_lib_detected == THD_LIB_LT ? SIGINT : SIGUSR2,
! end_thread_signal);
! }
! my_sigset(THR_SERVER_ALARM, print_signal_warning); // Should never be called!
if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL))
{
***************
*** 1877,1883 ****
#endif
(void) sigemptyset(&set);
#ifdef THREAD_SPECIFIC_SIGPIPE
! sigset(SIGPIPE,abort_thread);
sigaddset(&set,SIGPIPE);
#else
(void) signal(SIGPIPE,SIG_IGN); // Can't know which thread
--- 1876,1882 ----
#endif
(void) sigemptyset(&set);
#ifdef THREAD_SPECIFIC_SIGPIPE
! my_sigset(SIGPIPE, abort_thread);
sigaddset(&set,SIGPIPE);
#else
(void) signal(SIGPIPE,SIG_IGN); // Can't know which thread
***************
*** 2237,2244 ****
MY_INIT(argv[0]); // init my_sys library & pthreads
tzset(); // Set tzname
start_time=time((time_t*) 0);
-
#ifdef OS2
{
// fix timezone for daylight saving
--- 2236,2243 ----
MY_INIT(argv[0]); // init my_sys library & pthreads
tzset(); // Set tzname
+ thd_lib_detected= get_thread_lib();
start_time=time((time_t*) 0);
#ifdef OS2
{
// fix timezone for daylight saving
***************
*** 5547,5552 ****
(void) my_write(file, (byte*) buff, (uint) (end-buff),MYF(MY_WME));
(void) my_close(file, MYF(0));
}
}
--- 5546,5567 ----
(void) my_write(file, (byte*) buff, (uint) (end-buff),MYF(MY_WME));
(void) my_close(file, MYF(0));
}
+ }
+
+
+ static uint get_thread_lib(void)
+ {
+ char buff[64];
+
+ #ifdef _CS_GNU_LIBPTHREAD_VERSION
+ confstr(_CS_GNU_LIBPTHREAD_VERSION, buff, sizeof(buff));
+
+ if (!strncasecmp(buff, "NPTL", 4))
+ return THD_LIB_NPTL;
+ else if (!strncasecmp(buff, "linuxthreads", 12))
+ return THD_LIB_LT;
+ #endif
+ return THD_LIB_OTHER;
}
...@@ -144,6 +144,89 @@ static char is_null_string[2]= {1,0}; ...@@ -144,6 +144,89 @@ static char is_null_string[2]= {1,0};
- get_quick_select() - Walk the SEL_ARG, materialize the key intervals, - get_quick_select() - Walk the SEL_ARG, materialize the key intervals,
and create QUICK_RANGE_SELECT object that will and create QUICK_RANGE_SELECT object that will
read records within these intervals. 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 class SEL_ARG :public Sql_alloc
...@@ -174,6 +257,8 @@ public: ...@@ -174,6 +257,8 @@ public:
enum leaf_color { BLACK,RED } color; enum leaf_color { BLACK,RED } color;
enum Type { IMPOSSIBLE, MAYBE, MAYBE_KEY, KEY_RANGE } type; enum Type { IMPOSSIBLE, MAYBE, MAYBE_KEY, KEY_RANGE } type;
enum { MAX_SEL_ARGS = 64000 };
SEL_ARG() {} SEL_ARG() {}
SEL_ARG(SEL_ARG &); SEL_ARG(SEL_ARG &);
SEL_ARG(Field *,const char *,const char *); SEL_ARG(Field *,const char *,const char *);
...@@ -245,7 +330,8 @@ public: ...@@ -245,7 +330,8 @@ public:
return new SEL_ARG(field, part, min_value, arg->max_value, return new SEL_ARG(field, part, min_value, arg->max_value,
min_flag, arg->max_flag, maybe_flag | arg->maybe_flag); min_flag, arg->max_flag, maybe_flag | arg->maybe_flag);
} }
SEL_ARG *clone(SEL_ARG *new_parent,SEL_ARG **next); SEL_ARG *clone(struct st_qsel_param *param, SEL_ARG *new_parent,
SEL_ARG **next);
bool copy_min(SEL_ARG* arg) bool copy_min(SEL_ARG* arg)
{ // Get overlapping range { // Get overlapping range
...@@ -387,7 +473,7 @@ public: ...@@ -387,7 +473,7 @@ public:
{ {
return parent->left == this ? &parent->left : &parent->right; return parent->left == this ? &parent->left : &parent->right;
} }
SEL_ARG *clone_tree(); SEL_ARG *clone_tree(struct st_qsel_param *param);
}; };
class SEL_IMERGE; class SEL_IMERGE;
...@@ -455,6 +541,8 @@ typedef struct st_qsel_param { ...@@ -455,6 +541,8 @@ typedef struct st_qsel_param {
/* Number of ranges in the last checked tree->key */ /* Number of ranges in the last checked tree->key */
uint n_ranges; uint n_ranges;
uint8 first_null_comp; /* first null component if any, 0 - otherwise */ uint8 first_null_comp; /* first null component if any, 0 - otherwise */
/* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */
uint alloced_sel_args;
} PARAM; } PARAM;
class TABLE_READ_PLAN; class TABLE_READ_PLAN;
...@@ -514,8 +602,8 @@ static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg); ...@@ -514,8 +602,8 @@ static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg);
static SEL_TREE *tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2); static SEL_TREE *tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
static SEL_TREE *tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2); static SEL_TREE *tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
static SEL_ARG *sel_add(SEL_ARG *key1,SEL_ARG *key2); static SEL_ARG *sel_add(SEL_ARG *key1,SEL_ARG *key2);
static SEL_ARG *key_or(SEL_ARG *key1,SEL_ARG *key2); static SEL_ARG *key_or(PARAM *param, SEL_ARG *key1,SEL_ARG *key2);
static SEL_ARG *key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag); static SEL_ARG *key_and(PARAM *param, SEL_ARG *key1,SEL_ARG *key2,uint clone_flag);
static bool get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1); static bool get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1);
bool get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, bool get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
SEL_ARG *key_tree,char *min_key,uint min_key_flag, SEL_ARG *key_tree,char *min_key,uint min_key_flag,
...@@ -740,6 +828,7 @@ int imerge_list_or_tree(PARAM *param, ...@@ -740,6 +828,7 @@ int imerge_list_or_tree(PARAM *param,
return im1->is_empty(); return im1->is_empty();
} }
/*************************************************************************** /***************************************************************************
** Basic functions for SQL_SELECT and QUICK_RANGE_SELECT ** Basic functions for SQL_SELECT and QUICK_RANGE_SELECT
***************************************************************************/ ***************************************************************************/
...@@ -1354,12 +1443,17 @@ SEL_ARG::SEL_ARG(Field *field_,uint8 part_,char *min_value_,char *max_value_, ...@@ -1354,12 +1443,17 @@ SEL_ARG::SEL_ARG(Field *field_,uint8 part_,char *min_value_,char *max_value_,
left=right= &null_element; left=right= &null_element;
} }
SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg) SEL_ARG *SEL_ARG::clone(PARAM *param, SEL_ARG *new_parent, SEL_ARG **next_arg)
{ {
SEL_ARG *tmp; 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 (type != KEY_RANGE)
{ {
if (!(tmp= new SEL_ARG(type))) if (!(tmp= new (param->mem_root) SEL_ARG(type)))
return 0; // out of memory return 0; // out of memory
tmp->prev= *next_arg; // Link into next/prev chain tmp->prev= *next_arg; // Link into next/prev chain
(*next_arg)->next=tmp; (*next_arg)->next=tmp;
...@@ -1367,20 +1461,21 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg) ...@@ -1367,20 +1461,21 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg)
} }
else else
{ {
if (!(tmp= new SEL_ARG(field,part, min_value,max_value, if (!(tmp= new (param->mem_root) SEL_ARG(field,part, min_value,max_value,
min_flag, max_flag, maybe_flag))) min_flag, max_flag, maybe_flag)))
return 0; // OOM return 0; // OOM
tmp->parent=new_parent; tmp->parent=new_parent;
tmp->next_key_part=next_key_part; tmp->next_key_part=next_key_part;
if (left != &null_element) 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 tmp->prev= *next_arg; // Link into next/prev chain
(*next_arg)->next=tmp; (*next_arg)->next=tmp;
(*next_arg)= tmp; (*next_arg)= tmp;
if (right != &null_element) if (right != &null_element)
if (!(tmp->right= right->clone(tmp,next_arg))) if (!(tmp->right= right->clone(param, tmp, next_arg)))
return 0; // OOM return 0; // OOM
} }
increment_use_count(1); increment_use_count(1);
...@@ -1458,11 +1553,12 @@ static int sel_cmp(Field *field, char *a,char *b,uint8 a_flag,uint8 b_flag) ...@@ -1458,11 +1553,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(PARAM *param)
{ {
SEL_ARG tmp_link,*next_arg,*root; SEL_ARG tmp_link,*next_arg,*root;
next_arg= &tmp_link; 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 next_arg->next=0; // Fix last link
tmp_link.next->prev=0; // Fix first link tmp_link.next->prev=0; // Fix first link
if (root) // If not OOM if (root) // If not OOM
...@@ -1937,6 +2033,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, ...@@ -1937,6 +2033,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.real_keynr[param.keys++]=idx; param.real_keynr[param.keys++]=idx;
} }
param.key_parts_end=key_parts; param.key_parts_end=key_parts;
param.alloced_sel_args= 0;
/* Calculate cost of full index read for the shortest covering index */ /* Calculate cost of full index read for the shortest covering index */
if (!head->used_keys.is_clear_all()) if (!head->used_keys.is_clear_all())
...@@ -3926,7 +4023,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) ...@@ -3926,7 +4023,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
while ((item=li++)) while ((item=li++))
{ {
SEL_TREE *new_tree=get_mm_tree(param,item); 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 DBUG_RETURN(0); // out of memory
tree=tree_and(param,tree,new_tree); tree=tree_and(param,tree,new_tree);
if (tree && tree->type == SEL_TREE::IMPOSSIBLE) if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
...@@ -4500,9 +4598,9 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) ...@@ -4500,9 +4598,9 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
tree1->type=SEL_TREE::KEY_SMALLER; tree1->type=SEL_TREE::KEY_SMALLER;
DBUG_RETURN(tree1); DBUG_RETURN(tree1);
} }
key_map result_keys; key_map result_keys;
result_keys.clear_all(); result_keys.clear_all();
/* Join the trees key per key */ /* Join the trees key per key */
SEL_ARG **key1,**key2,**end; SEL_ARG **key1,**key2,**end;
for (key1= tree1->keys,key2= tree2->keys,end=key1+param->keys ; for (key1= tree1->keys,key2= tree2->keys,end=key1+param->keys ;
...@@ -4515,7 +4613,7 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) ...@@ -4515,7 +4613,7 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
flag|=CLONE_KEY1_MAYBE; flag|=CLONE_KEY1_MAYBE;
if (*key2 && !(*key2)->simple_key()) if (*key2 && !(*key2)->simple_key())
flag|=CLONE_KEY2_MAYBE; flag|=CLONE_KEY2_MAYBE;
*key1=key_and(*key1,*key2,flag); *key1=key_and(param, *key1, *key2, flag);
if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE) if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE)
{ {
tree1->type= SEL_TREE::IMPOSSIBLE; tree1->type= SEL_TREE::IMPOSSIBLE;
...@@ -4599,7 +4697,7 @@ tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) ...@@ -4599,7 +4697,7 @@ tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
for (key1= tree1->keys,key2= tree2->keys,end= key1+param->keys ; for (key1= tree1->keys,key2= tree2->keys,end= key1+param->keys ;
key1 != end ; key1++,key2++) key1 != end ; key1++,key2++)
{ {
*key1=key_or(*key1,*key2); *key1=key_or(param, *key1, *key2);
if (*key1) if (*key1)
{ {
result=tree1; // Added to tree1 result=tree1; // Added to tree1
...@@ -4654,14 +4752,14 @@ tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) ...@@ -4654,14 +4752,14 @@ tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
/* And key trees where key1->part < key2 -> part */ /* And key trees where key1->part < key2 -> part */
static SEL_ARG * static SEL_ARG *
and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) and_all_keys(PARAM *param, SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
{ {
SEL_ARG *next; SEL_ARG *next;
ulong use_count=key1->use_count; ulong use_count=key1->use_count;
if (key1->elements != 1) 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); key2->increment_use_count((int) key1->elements-1);
} }
if (key1->type == SEL_ARG::MAYBE_KEY) if (key1->type == SEL_ARG::MAYBE_KEY)
...@@ -4673,7 +4771,7 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) ...@@ -4673,7 +4771,7 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
{ {
if (next->next_key_part) 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) if (tmp && tmp->type == SEL_ARG::IMPOSSIBLE)
{ {
key1=key1->tree_delete(next); key1=key1->tree_delete(next);
...@@ -4682,6 +4780,8 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) ...@@ -4682,6 +4780,8 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
next->next_key_part=tmp; next->next_key_part=tmp;
if (use_count) if (use_count)
next->increment_use_count(use_count); next->increment_use_count(use_count);
if (param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS)
break;
} }
else else
next->next_key_part=key2; next->next_key_part=key2;
...@@ -4707,7 +4807,7 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) ...@@ -4707,7 +4807,7 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
*/ */
static SEL_ARG * static SEL_ARG *
key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) key_and(PARAM *param, SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
{ {
if (!key1) if (!key1)
return key2; return key2;
...@@ -4723,9 +4823,9 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) ...@@ -4723,9 +4823,9 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
// key1->part < key2->part // key1->part < key2->part
key1->use_count--; key1->use_count--;
if (key1->use_count > 0) if (key1->use_count > 0)
if (!(key1= key1->clone_tree())) if (!(key1= key1->clone_tree(param)))
return 0; // OOM 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) && if (((clone_flag & CLONE_KEY2_MAYBE) &&
...@@ -4743,14 +4843,14 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) ...@@ -4743,14 +4843,14 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
if (key1->use_count > 1) if (key1->use_count > 1)
{ {
key1->use_count--; key1->use_count--;
if (!(key1=key1->clone_tree())) if (!(key1=key1->clone_tree(param)))
return 0; // OOM return 0; // OOM
key1->use_count++; key1->use_count++;
} }
if (key1->type == SEL_ARG::MAYBE_KEY) if (key1->type == SEL_ARG::MAYBE_KEY)
{ // Both are maybe key { // Both are maybe key
key1->next_key_part=key_and(key1->next_key_part,key2->next_key_part, key1->next_key_part=key_and(param, key1->next_key_part,
clone_flag); key2->next_key_part, clone_flag);
if (key1->next_key_part && if (key1->next_key_part &&
key1->next_key_part->type == SEL_ARG::IMPOSSIBLE) key1->next_key_part->type == SEL_ARG::IMPOSSIBLE)
return key1; return key1;
...@@ -4761,7 +4861,7 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) ...@@ -4761,7 +4861,7 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
if (key2->next_key_part) if (key2->next_key_part)
{ {
key1->use_count--; // Incremented in and_all_keys 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 key2->use_count--; // Key2 doesn't have a tree
} }
...@@ -4797,7 +4897,8 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) ...@@ -4797,7 +4897,8 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
} }
else if (get_range(&e2,&e1,key2)) else if (get_range(&e2,&e1,key2))
continue; 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); e1->increment_use_count(1);
e2->increment_use_count(1); e2->increment_use_count(1);
if (!next || next->type != SEL_ARG::IMPOSSIBLE) if (!next || next->type != SEL_ARG::IMPOSSIBLE)
...@@ -4845,7 +4946,7 @@ get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1) ...@@ -4845,7 +4946,7 @@ get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1)
static SEL_ARG * static SEL_ARG *
key_or(SEL_ARG *key1,SEL_ARG *key2) key_or(PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
{ {
if (!key1) if (!key1)
{ {
...@@ -4893,7 +4994,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) ...@@ -4893,7 +4994,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
{ {
swap_variables(SEL_ARG *,key1,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 return 0; // OOM
} }
...@@ -5037,7 +5138,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) ...@@ -5037,7 +5138,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
{ // tmp.min. <= x <= tmp.max { // tmp.min. <= x <= tmp.max
tmp->maybe_flag|= key.maybe_flag; tmp->maybe_flag|= key.maybe_flag;
key.increment_use_count(key1->use_count+1); 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 if (!cmp) // Key2 is ready
break; break;
key.copy_max_to_min(tmp); key.copy_max_to_min(tmp);
...@@ -5068,7 +5169,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) ...@@ -5068,7 +5169,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
tmp->increment_use_count(key1->use_count+1); tmp->increment_use_count(key1->use_count+1);
/* Increment key count as it may be used for next loop */ /* Increment key count as it may be used for next loop */
key.increment_use_count(1); 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); key1=key1->insert(new_arg);
break; break;
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
class Sql_alloc class Sql_alloc
{ {
public: public:
static void *operator new(size_t size) static void *operator new(size_t size) throw ()
{ {
return (void*) sql_alloc((uint) size); return (void*) sql_alloc((uint) size);
} }
...@@ -31,9 +31,9 @@ public: ...@@ -31,9 +31,9 @@ public:
{ {
return (void*) sql_alloc((uint) size); 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); } { 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); } { 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, size_t size) { TRASH(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root) static void operator delete(void *ptr, MEM_ROOT *mem_root)
......
...@@ -8793,12 +8793,12 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, ...@@ -8793,12 +8793,12 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
enum enum_field_types type; enum enum_field_types type;
/* /*
DATE/TIME fields have STRING_RESULT result type. To preserve DATE/TIME and GEOMETRY fields have STRING_RESULT result type.
type they needed to be handled separately. To preserve type they needed to be handled separately.
*/ */
if ((type= item->field_type()) == MYSQL_TYPE_DATETIME || if ((type= item->field_type()) == MYSQL_TYPE_DATETIME ||
type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE || type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE ||
type == MYSQL_TYPE_TIMESTAMP) type == MYSQL_TYPE_TIMESTAMP || type == MYSQL_TYPE_GEOMETRY)
new_field= item->tmp_table_field_from_field_type(table); new_field= item->tmp_table_field_from_field_type(table);
/* /*
Make sure that the blob fits into a Field_varstring which has Make sure that the blob fits into a Field_varstring which has
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment