1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00
This commit is contained in:
bell@sanja.is.com.ua
2003-07-03 11:59:57 +03:00
43 changed files with 877 additions and 425 deletions

View File

@@ -3,7 +3,7 @@
path=`dirname $0`
. "$path/SETUP.sh"
extra_flags="$pentium_cflags $debug_cflags -USAFEMALLOC -DHAVE_purify"
extra_flags="$pentium_cflags $debug_cflags -USAFEMALLOC -UFORCE_INIT_OF_VARS -DHAVE_purify"
c_warnings="$c_warnings $debug_extra_warnings"
cxx_warnings="$cxx_warnings $debug_extra_warnings"
extra_configs="$pentium_configs $debug_configs"

View File

@@ -868,9 +868,9 @@ AC_SUBST(orbit_idl)
AC_DEFUN([MYSQL_CHECK_ISAM], [
AC_ARG_WITH([isam], [
--without-isam Disable the ISAM table type],
--with-isam Enable the ISAM table type],
[with_isam="$withval"],
[with_isam=yes])
[with_isam=no])
isam_libs=
if test X"$with_isam" = X"yes"

View File

@@ -23,7 +23,6 @@
#include "mysql.h"
#include <m_string.h>
#include <m_ctype.h>
#include <dbug.h>
#if defined(HAVE_BROKEN_GETPASS) && !defined(HAVE_GETPASSPHRASE)
#undef HAVE_GETPASS

View File

@@ -42,7 +42,7 @@
**********************************************************************/
#define MTEST_VERSION "1.28"
#define MTEST_VERSION "1.29"
#include <my_global.h>
#include <mysql_embed.h>
@@ -64,8 +64,9 @@
#include <violite.h>
#define MAX_QUERY 65536
#define MAX_COLUMNS 256
#define PAD_SIZE 128
#define MAX_CONS 1024
#define MAX_CONS 128
#define MAX_INCLUDE_DEPTH 16
#define LAZY_GUESS_BUF_SIZE 8192
#define INIT_Q_LINES 1024
@@ -192,7 +193,7 @@ Q_SYNC_WITH_MASTER,
Q_SYNC_SLAVE_WITH_MASTER,
Q_ERROR,
Q_SEND, Q_REAP,
Q_DIRTY_CLOSE, Q_REPLACE,
Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN,
Q_PING, Q_EVAL,
Q_RPL_PROBE, Q_ENABLE_RPL_PARSE,
Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT,
@@ -246,6 +247,7 @@ const char *command_names[]=
"reap",
"dirty_close",
"replace_result",
"replace_column",
"ping",
"eval",
"rpl_probe",
@@ -290,7 +292,7 @@ VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw,
int eval_expr(VAR* v, const char *p, const char** p_end);
static int read_server_arguments(const char *name);
/* Definitions for replace */
/* Definitions for replace result */
typedef struct st_pointer_array { /* when using array-strings */
TYPELIB typelib; /* Pointer to strings */
@@ -318,6 +320,13 @@ static char *out_buff;
static uint out_length;
static int eval_result = 0;
/* For column replace */
char *replace_column[MAX_COLUMNS];
uint max_replace_column= 0;
static void get_replace_column(struct st_query *q);
static void free_replace_column();
/* Disable functions that only exist in MySQL 4.0 */
#if MYSQL_VERSION_ID < 40000 || defined(EMBEDDED_LIBRARY)
void mysql_enable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
@@ -338,7 +347,6 @@ static const char *embedded_server_groups[] = {
NullS
};
static void do_eval(DYNAMIC_STRING* query_eval, const char* query)
{
const char* p;
@@ -433,6 +441,7 @@ static void free_used_memory()
delete_dynamic(&q_lines);
dynstr_free(&ds_res);
free_replace();
free_replace_column();
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
free_defaults(default_argv);
mysql_server_end();
@@ -2048,23 +2057,31 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
dynstr_append_mem(ds, val, len);
}
/*
Append all results to the dynamic string separated with '\t'
Values may be converted with 'replace_column'
*/
static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res)
{
MYSQL_ROW row;
int num_fields= mysql_num_fields(res);
uint num_fields= mysql_num_fields(res);
unsigned long *lengths;
while ((row = mysql_fetch_row(res)))
{
int i;
uint i;
lengths = mysql_fetch_lengths(res);
for (i = 0; i < num_fields; i++)
{
const char *val= row[i];
ulonglong len= lengths[i];
if (i < max_replace_column && replace_column[i])
{
val= replace_column[i];
len= strlen(val);
}
if (!val)
{
val= "NULL";
@@ -2076,6 +2093,7 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res)
}
dynstr_append_mem(ds, "\n", 1);
}
free_replace_column();
}
@@ -2539,6 +2557,9 @@ int main(int argc, char **argv)
case Q_REPLACE:
get_replace(q);
break;
case Q_REPLACE_COLUMN:
get_replace_column(q);
break;
case Q_SAVE_MASTER_POS: do_save_master_pos(); break;
case Q_SYNC_WITH_MASTER: do_sync_with_master(q); break;
case Q_SYNC_SLAVE_WITH_MASTER:
@@ -3357,3 +3378,60 @@ static void free_replace_buffer(void)
{
my_free(out_buff,MYF(MY_WME));
}
/****************************************************************************
Replace results for a column
*****************************************************************************/
static void free_replace_column()
{
uint i;
for (i=0 ; i < max_replace_column ; i++)
{
if (replace_column[i])
{
my_free(replace_column[i], 0);
replace_column[i]= 0;
}
}
max_replace_column= 0;
}
/*
Get arguments for replace_columns. The syntax is:
replace-column column_number to_string [column_number to_string ...]
Where each argument may be quoted with ' or "
A argument may also be a variable, in which case the value of the
variable is replaced.
*/
static void get_replace_column(struct st_query *q)
{
char *from=q->first_argument;
char *buff,*start;
DBUG_ENTER("get_replace_columns");
free_replace_column();
if (!*from)
die("Missing argument in %s\n", q->query);
/* Allocate a buffer for results */
start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
while (*from)
{
char *to;
uint column_number;
to= get_string(&buff, &from, q);
if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
die("Wrong column number to replace_columns in %s\n", q->query);
if (!*from)
die("Wrong number of arguments to replace in %s\n", q->query);
to= get_string(&buff, &from, q);
my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR);
replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE));
set_if_bigger(max_replace_column, column_number);
}
my_free(start, MYF(0));
}

View File

@@ -36,8 +36,8 @@ ER_CON_COUNT_ERROR, "08004", "",
ER_BAD_HOST_ERROR, "08S01", "",
ER_HANDSHAKE_ERROR, "08S01", "",
ER_DBACCESS_DENIED_ERROR, "42000", "",
ER_ACCESS_DENIED_ERROR, "42000", "28000",
ER_NO_DB_ERROR, "42000", "",
ER_ACCESS_DENIED_ERROR, "28000", "",
ER_NO_DB_ERROR, "3D000", "",
ER_UNKNOWN_COM_ERROR, "08S01", "",
ER_BAD_NULL_ERROR, "23000", "",
ER_BAD_DB_ERROR, "42000", "",
@@ -68,7 +68,7 @@ ER_BLOB_USED_AS_KEY, "42000", "S1009",
ER_TOO_BIG_FIELDLENGTH, "42000", "S1009",
ER_WRONG_AUTO_KEY, "42000", "S1009",
ER_FORCING_CLOSE, "08S01", "",
ER_IPSOCK_ERROR, "088S01", "",
ER_IPSOCK_ERROR, "08S01", "",
ER_NO_SUCH_INDEX, "42S12", "S1009",
ER_WRONG_FIELD_TERMINATORS, "42000", "S1009",
ER_BLOBS_AND_NO_TERMINATED, "42000", "S1009",

View File

@@ -111,11 +111,16 @@ insert into t1 set i = null;
select last_insert_id();
last_insert_id()
255
insert into t1 set i = 254;
ERROR 23000: Duplicate entry '254' for key 1
select last_insert_id();
last_insert_id()
255
insert into t1 set i = null;
ERROR 23000: Duplicate entry '255' for key 1
select last_insert_id();
last_insert_id()
255
0
drop table t1;
create table t1 (i tinyint unsigned not null auto_increment, key (i));
insert into t1 set i = 254;

View File

@@ -173,9 +173,9 @@ INSERT INTO t2 values (1),(2),(3);
INSERT INTO t3 VALUES (1,'1'),(2,'2'),(1,'1'),(2,'2');
explain SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 index a a 5 NULL 6 Using index; Using temporary
1 SIMPLE t2 index a a 4 NULL 5 Using index; Distinct
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where; Distinct
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 2 Using temporary
1 SIMPLE t2 ref a a 4 test.t1.a 2 Using index
1 SIMPLE t3 ref a a 5 test.t1.b 2 Using where; Using index
SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a;
a
1

View File

@@ -169,7 +169,7 @@ select REQ_ID, Group_Concat(URL) as URL from T_URL, T_REQUEST where
T_REQUEST.URL_ID = T_URL.URL_ID group by REQ_ID;
REQ_ID URL
1 www.host.com
5 www.host.com,www.google.com,www.help.com
5 www.google.com,www.help.com,www.host.com
drop table T_URL;
drop table T_REQUEST;
select group_concat(sum(a)) from t1 group by grp;

View File

@@ -122,7 +122,7 @@ select "user4";
user4
user4
select a from t1;
ERROR 42000: No Database Selected
ERROR 3D000: No Database Selected
select * from mysqltest.t1,test.t1;
a b c a
1 1 1 test.t1

View File

@@ -1,4 +1,5 @@
drop table if exists t1,t2,t3,t4,t5,t6;
drop database if exists mysqltest;
create table t1 (a int not null primary key auto_increment, message char(20));
create table t2 (a int not null primary key auto_increment, message char(20));
INSERT INTO t1 (message) VALUES ("Testing"),("table"),("t1");
@@ -174,15 +175,26 @@ t3 CREATE TABLE `t3` (
`a` int(11) NOT NULL default '0',
`b` char(20) default NULL,
KEY `a` (`a`)
) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(t1,t2)
) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(`t1`,`t2`)
create table t4 (a int not null, b char(10), key(a)) type=MERGE UNION=(t1,t2);
select * from t4;
ERROR HY000: Can't open file: 't4.MRG'. (errno: 143)
create table t5 (a int not null, b char(10), key(a)) type=MERGE UNION=(test.t1,test_2.t2);
ERROR HY000: Incorrect table definition; All MERGE tables must be in the same database
drop table if exists t5,t4,t3,t1,t2;
Warnings:
Note 1051 Unknown table 't5'
alter table t4 add column c int;
ERROR HY000: Can't open file: 't4.MRG'. (errno: 143)
create database mysqltest;
create table mysqltest.t6 (a int not null primary key auto_increment, message char(20));
create table t5 (a int not null, b char(20), key(a)) type=MERGE UNION=(test.t1,mysqltest.t6);
show create table t5;
Table Create Table
t5 CREATE TABLE `t5` (
`a` int(11) NOT NULL default '0',
`b` char(20) default NULL,
KEY `a` (`a`)
) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(`t1`,`mysqltest`.`t6`)
alter table t5 type=myisam;
drop table t5, mysqltest.t6;
drop database mysqltest;
drop table t4,t3,t1,t2;
create table t1 (c char(10)) type=myisam;
create table t2 (c char(10)) type=myisam;
create table t3 (c char(10)) union=(t1,t2) type=merge;
@@ -251,14 +263,14 @@ t3 CREATE TABLE `t3` (
`incr` int(11) NOT NULL default '0',
`othr` int(11) NOT NULL default '0',
PRIMARY KEY (`incr`)
) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(t1,t2)
) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(`t1`,`t2`)
alter table t3 drop primary key;
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
`incr` int(11) NOT NULL default '0',
`othr` int(11) NOT NULL default '0'
) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(t1,t2)
) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(`t1`,`t2`)
drop table t3,t2,t1;
create table t1 (a int not null, key(a)) type=merge;
select * from t1;
@@ -294,21 +306,21 @@ t4 CREATE TABLE `t4` (
`a` int(11) NOT NULL default '0',
`b` int(11) NOT NULL default '0',
KEY `a` (`a`,`b`)
) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(t1,t2)
) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(`t1`,`t2`)
show create table t5;
Table Create Table
t5 CREATE TABLE `t5` (
`a` int(11) NOT NULL default '0',
`b` int(11) NOT NULL auto_increment,
PRIMARY KEY (`a`,`b`)
) TYPE=MRG_MyISAM CHARSET=latin1 INSERT_METHOD=FIRST UNION=(t1,t2)
) TYPE=MRG_MyISAM CHARSET=latin1 INSERT_METHOD=FIRST UNION=(`t1`,`t2`)
show create table t6;
Table Create Table
t6 CREATE TABLE `t6` (
`a` int(11) NOT NULL default '0',
`b` int(11) NOT NULL auto_increment,
PRIMARY KEY (`a`,`b`)
) TYPE=MRG_MyISAM CHARSET=latin1 INSERT_METHOD=LAST UNION=(t1,t2)
) TYPE=MRG_MyISAM CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`)
insert into t1 values (1,NULL),(1,NULL),(1,NULL),(1,NULL);
insert into t2 values (2,NULL),(2,NULL),(2,NULL),(2,NULL);
select * from t3 order by b,a limit 3;
@@ -373,7 +385,7 @@ t4 CREATE TABLE `t4` (
`a` int(11) NOT NULL default '0',
`b` int(11) NOT NULL default '0',
KEY `a` (`a`,`b`)
) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(t1,t2,t3)
) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(`t1`,`t2`,`t3`)
select * from t4 order by a,b;
a b
1 1
@@ -399,7 +411,7 @@ t4 CREATE TABLE `t4` (
`a` int(11) NOT NULL default '0',
`b` int(11) NOT NULL default '0',
KEY `a` (`a`,`b`)
) TYPE=MRG_MyISAM CHARSET=latin1 INSERT_METHOD=FIRST UNION=(t1,t2,t3)
) TYPE=MRG_MyISAM CHARSET=latin1 INSERT_METHOD=FIRST UNION=(`t1`,`t2`,`t3`)
insert into t4 values (4,1),(4,2);
select * from t1 order by a,b;
a b
@@ -528,7 +540,11 @@ a b
6 1
6 2
6 3
drop table if exists t6, t5, t4, t3, t2, t1;
insert into t1 values (99,NULL);
select * from t4 where a+0 > 90;
a b
99 1
drop table t6, t5, t4, t3, t2, t1;
CREATE TABLE t1 ( a int(11) NOT NULL default '0', b int(11) NOT NULL default '0', PRIMARY KEY (a,b)) TYPE=MyISAM;
INSERT INTO t1 VALUES (1,1), (2,1);
CREATE TABLE t2 ( a int(11) NOT NULL default '0', b int(11) NOT NULL default '0', PRIMARY KEY (a,b)) TYPE=MyISAM;
@@ -540,7 +556,7 @@ max(b)
select max(b) from t1 where a = 2;
max(b)
1
drop table if exists t3,t1,t2;
drop table t3,t1,t2;
create table t1 (a int not null);
create table t2 (a int not null);
insert into t1 values (1);
@@ -559,7 +575,7 @@ select * from t6;
a
1
2
drop table if exists t6, t3, t1, t2, t4, t5;
drop table t6, t3, t1, t2, t4, t5;
CREATE TABLE t1 (
fileset_id tinyint(3) unsigned NOT NULL default '0',
file_code varchar(32) NOT NULL default '',

View File

@@ -21,7 +21,10 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a,b a 9 NULL 3 Using where; Using index
explain select * from t1 where (a is null or a = 7) and b=7;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b b 4 const 2 Using where
1 SIMPLE t1 ref_or_null a,b a 9 const,const 2 Using where; Using index
explain select * from t1 where (a is null or a = 7) and b=7 order by a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref_or_null a,b a 9 const,const 2 Using where; Using index; Using filesort
explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where; Using index
@@ -56,13 +59,15 @@ NULL 9
NULL 9
select * from t1 where (a is null or a = 7) and b=7;
a b
NULL 7
7 7
NULL 7
select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
a b
NULL 7
NULL 9
NULL 9
create table t2 like t1;
insert into t2 select * from t1;
alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10));
explain select * from t1 where a is null and b = 2;
id select_type table type possible_keys key key_len ref rows Extra
@@ -84,7 +89,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a,b a 5 NULL 5 Using where
explain select * from t1 where (a is null or a = 7) and b=7 and c=0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL a,b NULL NULL NULL 12 Using where
1 SIMPLE t1 ref_or_null a,b a 5 const 4 Using where
explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where
@@ -125,8 +130,8 @@ NULL 9 0
NULL 9 0
select * from t1 where (a is null or a = 7) and b=7 and c=0;
a b c
NULL 7 0
7 7 0
NULL 7 0
select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
a b c
NULL 7 0
@@ -136,6 +141,103 @@ select * from t1 where b like "6%";
a b c
6 6 0
drop table t1;
rename table t2 to t1;
alter table t1 modify b int null;
insert into t1 values (7,null), (8,null), (8,7);
explain select * from t1 where a = 7 and (b=7 or b is null);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref_or_null a,b a 10 const,const 2 Using where; Using index
select * from t1 where a = 7 and (b=7 or b is null);
a b
7 7
7 NULL
explain select * from t1 where (a = 7 or a is null) and (b=7 or b is null);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a,b a 10 NULL 4 Using where; Using index
select * from t1 where (a = 7 or a is null) and (b=7 or b is null);
a b
NULL 7
7 NULL
7 7
explain select * from t1 where (a = 7 or a is null) and (a = 7 or a is null);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref_or_null a a 5 const 5 Using where; Using index
select * from t1 where (a = 7 or a is null) and (a = 7 or a is null);
a b
7 NULL
7 7
NULL 7
NULL 9
NULL 9
create table t2 (a int);
insert into t2 values (7),(8);
explain select * from t2 straight_join t1 where t1.a=t2.a and b is null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 2
1 SIMPLE t1 ref a,b a 10 test.t2.a,const 2 Using where; Using index
drop index b on t1;
explain select * from t2,t1 where t1.a=t2.a and b is null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 2
1 SIMPLE t1 ref a a 10 test.t2.a,const 2 Using where; Using index
select * from t2,t1 where t1.a=t2.a and b is null;
a a b
7 7 NULL
8 8 NULL
explain select * from t2,t1 where t1.a=t2.a and (b= 7 or b is null);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 2
1 SIMPLE t1 ref_or_null a a 10 test.t2.a,const 4 Using where; Using index
select * from t2,t1 where t1.a=t2.a and (b= 7 or b is null);
a a b
7 7 7
7 7 NULL
8 8 7
8 8 NULL
explain select * from t2,t1 where (t1.a=t2.a or t1.a is null) and b= 7;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 2
1 SIMPLE t1 ref_or_null a a 10 test.t2.a,const 4 Using where; Using index
select * from t2,t1 where (t1.a=t2.a or t1.a is null) and b= 7;
a a b
7 7 7
7 NULL 7
8 8 7
8 NULL 7
explain select * from t2,t1 where (t1.a=t2.a or t1.a is null) and (b= 7 or b is null);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 2
1 SIMPLE t1 ref_or_null a a 5 test.t2.a 4 Using where; Using index
select * from t2,t1 where (t1.a=t2.a or t1.a is null) and (b= 7 or b is null);
a a b
7 7 NULL
7 7 7
7 NULL 7
8 8 NULL
8 8 7
8 NULL 7
insert into t2 values (null),(6);
delete from t1 where a=8;
explain select * from t2,t1 where t1.a=t2.a or t1.a is null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 4
1 SIMPLE t1 ref_or_null a a 5 test.t2.a 4 Using where; Using index
explain select * from t2,t1 where t1.a<=>t2.a or (t1.a is null and t1.b <> 9);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 4
1 SIMPLE t1 ref_or_null a a 5 test.t2.a 4 Using where; Using index
select * from t2,t1 where t1.a<=>t2.a or (t1.a is null and t1.b <> 9);
a a b
7 7 NULL
7 7 7
7 NULL 7
8 NULL 7
NULL NULL 7
NULL NULL 9
NULL NULL 9
6 6 6
6 NULL 7
drop table t1,t2;
CREATE TABLE t1 (
id int(10) unsigned NOT NULL auto_increment,
uniq_id int(10) unsigned default NULL,

View File

@@ -828,7 +828,7 @@ a t1.a in (select t2.a from t2)
explain SELECT t1.a, t1.a in (select t2.a from t2) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 Using index
2 DEPENDENT SUBQUERY t2 index a a 5 NULL 3 Using where; Using index
2 DEPENDENT SUBQUERY t2 ref_or_null a a 5 const 2 Using where; Using index
drop table t1,t2;
create table t1 (a float);
select 10.5 IN (SELECT * from t1 LIMIT 1);
@@ -1152,6 +1152,19 @@ INSERT INTO t1 VALUES (1,0,NULL,NULL),(2,0,NULL,NULL);
SELECT DISTINCT REF_ID FROM t1 WHERE ID= (SELECT DISTINCT REF_ID FROM t1 WHERE ID=2);
REF_ID
DROP TABLE t1;
create table t1 (a int, b int);
create table t2 (a int, b int);
insert into t1 values (1,0), (2,0), (3,0);
insert into t2 values (1,1), (2,1), (3,1), (2,2);
update ignore t1 set b=(select b from t2 where t1.a=t2.a);
Warnings:
Error 1240 Subselect returns more than 1 record
select * from t1;
a b
1 1
2 NULL
3 1
drop table t1, t2;
create table t1(City VARCHAR(30),Location geometry);
insert into t1 values("Paris",GeomFromText('POINT(2.33 48.87)'));
select City from t1 where (select intersects(GeomFromText(AsText(Location)),GeomFromText('Polygon((2 50, 2.5 50, 2.5 47, 2 47, 2 50))'))=0);

View File

@@ -80,6 +80,9 @@ insert into t1 set i = 254;
insert into t1 set i = null;
select last_insert_id();
--error 1062
insert into t1 set i = 254;
select last_insert_id();
--error 1062
insert into t1 set i = null;
select last_insert_id();
drop table t1;
@@ -100,5 +103,6 @@ select last_insert_id();
--error 1062
insert into t1 values (NULL, 10);
select last_insert_id();
drop table t1;

View File

@@ -22,7 +22,7 @@ drop table t1;
#
# A bit bigger test
# The 'replace_result' statements are needed because the cardinality calculated
# The 'replace_column' statements are needed because the cardinality calculated
# by innodb is not always the same between runs
#
@@ -51,7 +51,7 @@ select * from t1 where parent_id=102;
select level,id from t1 where level=1;
select level,id,parent_id from t1 where level=1;
optimize table t1;
--replace_result 87 # 50 # 48 # 43 # 25 # 24 # 6 # 3 #
--replace_column 7 #
show keys from t1;
drop table t1;

View File

@@ -4,6 +4,7 @@
--disable_warnings
drop table if exists t1,t2,t3,t4,t5,t6;
drop database if exists mysqltest;
--enable_warnings
create table t1 (a int not null primary key auto_increment, message char(20));
@@ -48,12 +49,22 @@ show create table t3;
create table t4 (a int not null, b char(10), key(a)) type=MERGE UNION=(t1,t2);
--error 1016
select * from t4;
--error 1212
create table t5 (a int not null, b char(10), key(a)) type=MERGE UNION=(test.t1,test_2.t2);
--error 1016
alter table t4 add column c int;
#
# Test tables in different databases
#
create database mysqltest;
create table mysqltest.t6 (a int not null primary key auto_increment, message char(20));
create table t5 (a int not null, b char(20), key(a)) type=MERGE UNION=(test.t1,mysqltest.t6);
show create table t5;
alter table t5 type=myisam;
drop table t5, mysqltest.t6;
drop database mysqltest;
# Because of windows, it's important that we drop the merge tables first!
# This should give a warning on table t5
drop table if exists t5,t4,t3,t1,t2;
drop table t4,t3,t1,t2;
create table t1 (c char(10)) type=myisam;
create table t2 (c char(10)) type=myisam;
@@ -177,7 +188,9 @@ select * from t1 order by a,b;
select * from t2 order by a,b;
select * from t5 order by a,b;
select * from t6 order by a,b;
drop table if exists t6, t5, t4, t3, t2, t1;
insert into t1 values (99,NULL);
select * from t4 where a+0 > 90;
drop table t6, t5, t4, t3, t2, t1;
CREATE TABLE t1 ( a int(11) NOT NULL default '0', b int(11) NOT NULL default '0', PRIMARY KEY (a,b)) TYPE=MyISAM;
INSERT INTO t1 VALUES (1,1), (2,1);
@@ -186,7 +199,7 @@ INSERT INTO t2 VALUES (1,2), (2,2);
CREATE TABLE t3 ( a int(11) NOT NULL default '0', b int(11) NOT NULL default '0', KEY a (a,b)) TYPE=MRG_MyISAM UNION=(t1,t2);
select max(b) from t3 where a = 2;
select max(b) from t1 where a = 2;
drop table if exists t3,t1,t2;
drop table t3,t1,t2;
#
# temporary merge tables
@@ -203,7 +216,7 @@ insert into t4 values (1);
insert into t5 values (2);
create temporary table t6 (a int not null) TYPE=MERGE UNION=(t4,t5);
select * from t6;
drop table if exists t6, t3, t1, t2, t4, t5;
drop table t6, t3, t1, t2, t4, t5;
#
# testing merge::records_in_range and optimizer

View File

@@ -14,6 +14,7 @@ explain select * from t1 where a=2 and b = 2;
explain select * from t1 where a<=>b limit 2;
explain select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3;
explain select * from t1 where (a is null or a = 7) and b=7;
explain select * from t1 where (a is null or a = 7) and b=7 order by a;
explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2;
explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
explain select * from t1 where a > 1 and a < 3 limit 1;
@@ -25,6 +26,8 @@ select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3;
select * from t1 where (a is null or a > 0 and a < 3) and b > 7 limit 3;
select * from t1 where (a is null or a = 7) and b=7;
select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
create table t2 like t1;
insert into t2 select * from t1;
alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10));
explain select * from t1 where a is null and b = 2;
explain select * from t1 where a is null and b = 2 and c=0;
@@ -47,8 +50,38 @@ select * from t1 where (a is null or a > 0 and a < 3) and b > 7 limit 3;
select * from t1 where (a is null or a = 7) and b=7 and c=0;
select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
select * from t1 where b like "6%";
drop table t1;
#
# Test ref_or_null optimization
#
drop table t1;
rename table t2 to t1;
alter table t1 modify b int null;
insert into t1 values (7,null), (8,null), (8,7);
explain select * from t1 where a = 7 and (b=7 or b is null);
select * from t1 where a = 7 and (b=7 or b is null);
explain select * from t1 where (a = 7 or a is null) and (b=7 or b is null);
select * from t1 where (a = 7 or a is null) and (b=7 or b is null);
explain select * from t1 where (a = 7 or a is null) and (a = 7 or a is null);
select * from t1 where (a = 7 or a is null) and (a = 7 or a is null);
create table t2 (a int);
insert into t2 values (7),(8);
explain select * from t2 straight_join t1 where t1.a=t2.a and b is null;
drop index b on t1;
explain select * from t2,t1 where t1.a=t2.a and b is null;
select * from t2,t1 where t1.a=t2.a and b is null;
explain select * from t2,t1 where t1.a=t2.a and (b= 7 or b is null);
select * from t2,t1 where t1.a=t2.a and (b= 7 or b is null);
explain select * from t2,t1 where (t1.a=t2.a or t1.a is null) and b= 7;
select * from t2,t1 where (t1.a=t2.a or t1.a is null) and b= 7;
explain select * from t2,t1 where (t1.a=t2.a or t1.a is null) and (b= 7 or b is null);
select * from t2,t1 where (t1.a=t2.a or t1.a is null) and (b= 7 or b is null);
insert into t2 values (null),(6);
delete from t1 where a=8;
explain select * from t2,t1 where t1.a=t2.a or t1.a is null;
explain select * from t2,t1 where t1.a<=>t2.a or (t1.a is null and t1.b <> 9);
select * from t2,t1 where t1.a<=>t2.a or (t1.a is null and t1.b <> 9);
drop table t1,t2;
#
# The following failed for Matt Loschert

View File

@@ -739,6 +739,19 @@ INSERT INTO t1 VALUES (1,0,NULL,NULL),(2,0,NULL,NULL);
SELECT DISTINCT REF_ID FROM t1 WHERE ID= (SELECT DISTINCT REF_ID FROM t1 WHERE ID=2);
DROP TABLE t1;
#
# uninterruptable update
#
create table t1 (a int, b int);
create table t2 (a int, b int);
insert into t1 values (1,0), (2,0), (3,0);
insert into t2 values (1,1), (2,1), (3,1), (2,2);
update ignore t1 set b=(select b from t2 where t1.a=t2.a);
select * from t1;
drop table t1, t2;
#
# correct behavoiur for function from reduced subselect

View File

@@ -28,6 +28,7 @@ my_string my_load_path(my_string to, const char *path,
const char *own_path_prefix)
{
char buff[FN_REFLEN];
int is_cur;
DBUG_ENTER("my_load_path");
DBUG_PRINT("enter",("path: %s prefix: %s",path,
own_path_prefix ? own_path_prefix : ""));
@@ -35,14 +36,16 @@ my_string my_load_path(my_string to, const char *path,
if ((path[0] == FN_HOMELIB && path[1] == FN_LIBCHAR) ||
test_if_hard_path(path))
VOID(strmov(buff,path));
else if ((path[0] == FN_CURLIB && path[1] == FN_LIBCHAR) ||
else if ((is_cur=(path[0] == FN_CURLIB && path[1] == FN_LIBCHAR)) ||
(is_prefix((gptr) path,FN_PARENTDIR)) ||
! own_path_prefix)
{
if (! my_getwd(buff,(uint) (FN_REFLEN-strlen(path)),MYF(0)))
VOID(strcat(buff,path));
if (is_cur)
is_cur=2; /* Remove current dir */
if (! my_getwd(buff,(uint) (FN_REFLEN-strlen(path)+is_cur),MYF(0)))
VOID(strcat(buff,path+is_cur));
else
VOID(strmov(buff,path));
VOID(strmov(buff,path)); /* Return org file name */
}
else
VOID(strxmov(buff,own_path_prefix,path,NullS));

View File

@@ -458,17 +458,19 @@ int handle_options(int *argc, char ***argv,
static char *check_struct_option(char *cur_arg, char *key_name)
{
char *ptr, *ptr2;
char *ptr, *end;
ptr= strcend(cur_arg, '.');
ptr2= strcend(cur_arg, '=');
ptr= strcend(cur_arg + 1, '.'); // Skip the first character
end= strcend(cur_arg, '=');
/*
Minimum length for a struct option is 3 (--a.b)
If the (first) dot is after an equal sign, then it is part
If the first dot is after an equal sign, then it is part
of a variable value and the option is not a struct option.
Also, if the last character in the string before the ending
NULL, or the character right before equal sign is the first
dot found, the option is not a struct option.
*/
if (strlen(ptr) >= 3 && ptr2 - ptr > 0)
if (end - ptr > 1)
{
uint len= ptr - cur_arg;
strnmov(key_name, cur_arg, len);

View File

@@ -123,20 +123,22 @@ int my_realpath(char *to, const char *filename,
}
else
{
/* Realpath didn't work; Use original name */
/*
Realpath didn't work; Use my_load_path() which is a poor substitute
original name but will at least be able to resolve paths that starts
with '.'.
*/
DBUG_PRINT("error",("realpath failed with errno: %d", errno));
my_errno=errno;
if (MyFlags & MY_WME)
my_error(EE_REALPATH, MYF(0), filename, my_errno);
if (to != filename)
strmov(to,filename);
my_load_path(to, filename, NullS);
result= -1;
}
}
DBUG_RETURN(result);
#else
if (to != filename)
strmov(to,filename);
my_load_path(to, filename, NullS);
return 0;
#endif
}

View File

@@ -303,14 +303,40 @@ THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd,
return to;
}
/* Find out database name and table name from a filename */
static void split_file_name(const char *file_name,
LEX_STRING *db, LEX_STRING *name)
{
uint name_length, dir_length, prefix_length;
char buff[FN_REFLEN];
db->length= 0;
name_length= (uint) (strmake(buff, file_name, sizeof(buff)-1) - buff);
dir_length= dirname_length(buff);
if (dir_length > 1)
{
/* Get database */
buff[dir_length-1]= 0; // Remove end '/'
prefix_length= dirname_length(buff);
db->str= (char*) file_name+ prefix_length;
db->length= dir_length - prefix_length -1;
}
name->str= (char*) file_name+ dir_length;
name->length= (uint) (fn_ext(name->str) - name->str);
}
void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info)
{
// [phi] auto_increment stuff is missing (but currently not needed)
DBUG_ENTER("ha_myisammrg::update_create_info");
if (!(create_info->used_fields & HA_CREATE_USED_UNION))
{
MYRG_TABLE *open_table;
THD *thd=current_thd;
create_info->merge_list.next= &create_info->merge_list.first;
create_info->merge_list.elements=0;
@@ -318,14 +344,17 @@ void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info)
open_table != file->end_table ;
open_table++)
{
char *name=open_table->table->filename;
char buff[FN_REFLEN];
TABLE_LIST *ptr;
LEX_STRING db, name;
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
goto err;
fn_format(buff,name,"","",3);
if (!(ptr->real_name=thd->strdup(buff)))
split_file_name(open_table->table->filename, &db, &name);
if (!(ptr->real_name= thd->strmake(name.str, name.length)))
goto err;
if (db.length && !(ptr->db= thd->strmake(db.str, db.length)))
goto err;
create_info->merge_list.elements++;
(*create_info->merge_list.next) = (byte*) ptr;
create_info->merge_list.next= (byte**) &ptr->next;
@@ -344,37 +373,34 @@ err:
DBUG_VOID_RETURN;
}
int ha_myisammrg::create(const char *name, register TABLE *form,
HA_CREATE_INFO *create_info)
{
char buff[FN_REFLEN],**table_names,**pos;
TABLE_LIST *tables= (TABLE_LIST*) create_info->merge_list.first;
THD *thd= current_thd;
DBUG_ENTER("ha_myisammrg::create");
if (!(table_names= (char**) sql_alloc((create_info->merge_list.elements+1)*
if (!(table_names= (char**) thd->alloc((create_info->merge_list.elements+1)*
sizeof(char*))))
DBUG_RETURN(1);
for (pos=table_names ; tables ; tables=tables->next)
{
char *table_name;
TABLE **tbl= 0;
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
TABLE **tbl=find_temporary_table(current_thd,
tables->db, tables->real_name);
tbl= find_temporary_table(thd, tables->db, tables->real_name);
if (!tbl)
{
table_name=sql_alloc(1+
my_snprintf(buff,FN_REFLEN,"%s/%s/%s",mysql_real_data_home,
tables->db, tables->real_name));
if (!table_name)
uint length= my_snprintf(buff,FN_REFLEN,"%s%s/%s",
mysql_real_data_home,
tables->db, tables->real_name);
if (!(table_name= thd->strmake(buff, length)))
DBUG_RETURN(1);
strcpy(table_name, buff);
}
else
table_name=(*tbl)->path;
}
else
table_name=tables->real_name;
*pos++= table_name;
}
*pos=0;
@@ -384,9 +410,13 @@ int ha_myisammrg::create(const char *name, register TABLE *form,
(my_bool) 0));
}
void ha_myisammrg::append_create_info(String *packet)
{
char buff[FN_REFLEN];
const char *current_db;
uint db_length;
THD *thd= current_thd;
if (file->merge_insert_method != MERGE_INSERT_DISABLED)
{
packet->append(" INSERT_METHOD=",15);
@@ -395,15 +425,26 @@ void ha_myisammrg::append_create_info(String *packet)
packet->append(" UNION=(",8);
MYRG_TABLE *open_table,*first;
current_db= table->table_cache_key;
db_length= strlen(current_db);
for (first=open_table=file->open_tables ;
open_table != file->end_table ;
open_table++)
{
char *name= open_table->table->filename;
fn_format(buff,name,"","",3);
LEX_STRING db, name;
split_file_name(open_table->table->filename, &db, &name);
if (open_table != first)
packet->append(',');
packet->append(buff,(uint) strlen(buff));
/* Report database for mapped table if it isn't in current database */
if (db.length &&
(db_length != db.length ||
strncmp(current_db, db.str, db.length)))
{
append_identifier(thd, packet, db.str, db.length);
packet->append('.');
}
append_identifier(thd, packet, name.str, name.length);
}
packet->append(')');
}

View File

@@ -709,6 +709,8 @@ void handler::update_auto_increment()
nr=get_auto_increment();
if (!table->next_number_field->store(nr))
thd->insert_id((ulonglong) nr);
else
thd->insert_id(table->next_number_field->val_int());
auto_increment_column_changed=1;
DBUG_VOID_RETURN;
}

View File

@@ -49,7 +49,13 @@ Item::Item():
next= thd->free_list; // Put in free list
thd->free_list= this;
loop_id= 0;
if (thd->lex.current_select->parsing_place == SELECT_LEX_NODE::SELECT_LIST)
/*
Item constructor can be called during execution other tnen SQL_COM
command => we should check thd->lex.current_select on zero (thd->lex
can be uninitialised)
*/
if (thd->lex.current_select &&
thd->lex.current_select->parsing_place == SELECT_LEX_NODE::SELECT_LIST)
thd->lex.current_select->select_items++;
}

View File

@@ -187,8 +187,6 @@ public:
collation.collation= collation_arg->collation;
collation.derivation= collation_arg->derivation;
}
bool binary() const
{ return charset()->state & MY_CS_BINSORT ? 1 : 0 ; }
virtual bool walk(Item_processor processor, byte *arg)
{

View File

@@ -388,12 +388,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
return 1;
if (args[0]->maybe_null)
maybe_null=1;
/*
TODO: Check if following is right
(set_charset set type of result, not how compare should be used)
*/
if (args[0]->binary())
set_charset(&my_charset_bin);
with_sum_func= args[0]->with_sum_func;
used_tables_cache= args[0]->used_tables();
const_item_cache= args[0]->const_item();
@@ -938,7 +933,7 @@ Item *Item_func_case::find_item(String *str)
if ((tmp=args[i]->val_str(str))) // If not null
{
/* QQ: COERCIBILITY */
if (first_expr_is_binary || args[i]->binary())
if (first_expr_is_binary || (args[i]->charset()->state & MY_CS_BINSORT))
{
if (sortcmp(tmp,first_expr_str,&my_charset_bin)==0)
return args[i+1];
@@ -1049,7 +1044,7 @@ Item_func_case::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
used_tables_cache|=(first_expr)->used_tables();
const_item_cache&= (first_expr)->const_item();
with_sum_func= with_sum_func || (first_expr)->with_sum_func;
first_expr_is_binary= first_expr->binary();
first_expr_is_binary= first_expr->charset()->state & MY_CS_BINSORT;
}
if (else_expr)
{

View File

@@ -128,8 +128,6 @@ public:
bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
void print(String *str) { Item_func::print_op(str); }
bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); }
virtual bool binary() const
{ return test(cmp_collation.collation->state & MY_CS_BINSORT); }
static Item_bool_func2* eq_creator(Item *a, Item *b);
static Item_bool_func2* ne_creator(Item *a, Item *b);

View File

@@ -1357,7 +1357,18 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
Item *item= *arg;
if (item->fix_fields(thd, tables, arg) || item->check_cols(1))
return 1;
if (item->binary())
/*
TODO: We should think about this. It is not always
right way just to set an UDF result to return my_charset_bin
if one argument has binary sorting order.
The result collation should be calculated according to arguments
derivations in some cases and should not in other cases.
Moreover, some arguments can represent a numeric input
which doesn't effect the result character set and collation.
There is no a general rule for UDF. Everything depends on
the particular user definted function.
*/
if (item->charset()->state & MY_CS_BINSORT)
func->set_charset(&my_charset_bin);
if (item->maybe_null)
func->maybe_null=1;

View File

@@ -748,7 +748,7 @@ String *Item_func_replace::val_str(String *str)
res->set_charset(collation.collation);
#ifdef USE_MB
binary_cmp = (args[0]->binary() || args[1]->binary() || !use_mb(res->charset()));
binary_cmp = ((res->charset()->state & MY_CS_BINSORT) || !use_mb(res->charset()));
#endif
if (res2->length() == 0)

View File

@@ -532,6 +532,8 @@ int mysqld_show_fields(THD *thd,TABLE_LIST *table, const char *wild,
bool verbose);
int mysqld_show_keys(THD *thd, TABLE_LIST *table);
int mysqld_show_logs(THD *thd);
void append_identifier(THD *thd, String *packet, const char *name,
uint length);
void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
int mysqld_dump_create_info(THD *thd, TABLE *table, int fd = -1);
int mysqld_show_create(THD *thd, TABLE_LIST *table_list);

View File

@@ -1820,6 +1820,18 @@ extern "C" int my_message_sql(uint error, const char *str,
DBUG_ENTER("my_message_sql");
DBUG_PRINT("error", ("Message: '%s'", str));
if ((thd= current_thd))
{
/*
thd->lex.current_select equel to zero if lex structure is not inited
(not query command (COM_QUERY))
*/
if (thd->lex.current_select &&
thd->lex.current_select->no_error && !thd->is_fatal_error)
{
DBUG_PRINT("error", ("above error converted to warning"));
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
}
else
{
NET *net= &thd->net;
net->report_error= 1;
@@ -1829,6 +1841,7 @@ extern "C" int my_message_sql(uint error, const char *str,
net->last_errno= error ? error : ER_UNKNOWN_ERROR;
}
}
}
else
sql_print_error("%s: %s",my_progname,str); /* purecov: inspected */
DBUG_RETURN(0);

View File

@@ -572,7 +572,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag)
#endif
}
send_eof(thd);
send_eof(thd, 1);
DBUG_RETURN(prepare_for_send(list));
err:

View File

@@ -44,12 +44,6 @@ int sortcmp2(void* cmp_arg __attribute__((unused)),
return sortcmp(a,b,a->charset());
}
int stringcmp2(void* cmp_arg __attribute__((unused)),
const String *a,const String *b)
{
return sortcmp(a,b,&my_charset_bin);
}
int compare_double2(void* cmp_arg __attribute__((unused)),
const double *s, const double *t)
{

View File

@@ -99,8 +99,6 @@ int collect_string(String *element, element_count count,
int sortcmp2(void* cmp_arg __attribute__((unused)),
const String *a,const String *b);
int stringcmp2(void* cmp_arg __attribute__((unused)),
const String *a,const String *b);
class field_str :public field_info
{
@@ -117,8 +115,7 @@ public:
max_arg("",default_charset_info), sum(0),
must_be_blob(0), was_zero_fill(0),
was_maybe_zerofill(0), can_be_still_num(1)
{ init_tree(&tree, 0, 0, sizeof(String), a->binary() ?
(qsort_cmp2) stringcmp2 : (qsort_cmp2) sortcmp2,
{ init_tree(&tree, 0, 0, sizeof(String), (qsort_cmp2) sortcmp2,
0, (tree_element_free) free_string, NULL); };
void add();

View File

@@ -503,8 +503,23 @@ public:
#ifdef SIGNAL_WITH_VIO_CLOSE
Vio* active_vio;
#endif
ulonglong next_insert_id,last_insert_id,current_insert_id,
limit_found_rows;
/*
next_insert_id is set on SET INSERT_ID= #. This is used as the next
generated auto_increment value in handler.cc
*/
ulonglong next_insert_id;
/*
The insert_id used for the last statement or set by SET LAST_INSERT_ID=#
or SELECT LAST_INSERT_ID(#). Used for binary log and returned by
LAST_INSERT_ID()
*/
ulonglong last_insert_id;
/*
Set to the first value that LAST_INSERT_ID() returned for the last
statement. When this is set, last_insert_id_used is set to true.
*/
ulonglong current_insert_id;
ulonglong limit_found_rows;
ha_rows select_limit, offset_limit, cuted_fields,
sent_row_count, examined_row_count;
table_map used_tables;

View File

@@ -122,6 +122,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length)
lex->yacc_yyss=lex->yacc_yyvs=0;
lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE);
lex->sql_command=SQLCOM_END;
lex->duplicates= DUP_ERROR;
return lex;
}
@@ -965,7 +966,7 @@ void st_select_lex_node::init_query()
{
options= 0;
linkage= UNSPECIFIED_TYPE;
no_table_names_allowed= uncacheable= dependent= 0;
no_error= no_table_names_allowed= uncacheable= dependent= 0;
}
void st_select_lex_node::init_select()

View File

@@ -211,6 +211,7 @@ public:
bool dependent; /* dependent from outer select subselect */
bool uncacheable; /* result of this query can't be cached */
bool no_table_names_allowed; /* used for global order by */
bool no_error; /* suppress error message (convert it to warnings) */
static void *operator new(size_t size)
{

View File

@@ -1057,6 +1057,11 @@ bool do_command(THD *thd)
net= &thd->net;
thd->current_tablenr=0;
/*
indicator of uninitialized lex => normal flow of errors handling
(see my_message_sql)
*/
thd->lex.current_select= 0;
packet=0;
old_timeout=net->read_timeout;
@@ -3388,11 +3393,6 @@ static bool check_merge_table_access(THD *thd, char *db,
{
if (!tmp->db || !tmp->db[0])
tmp->db=db;
else if (strcmp(tmp->db,db))
{
send_error(thd,ER_UNION_TABLES_IN_DIFFERENT_DIR);
return 1;
}
}
error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
table_list);
@@ -4439,6 +4439,7 @@ static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
return 0;
}
/*
Check if the select is a simple select (not an union)

View File

@@ -31,8 +31,11 @@
#include <ft_global.h>
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"MAYBE_REF","ALL","range","index","fulltext" };
"MAYBE_REF","ALL","range","index","fulltext",
"ref_or_null"
};
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
DYNAMIC_ARRAY *keyuse);
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
@@ -106,6 +109,8 @@ static int join_read_prev_same(READ_RECORD *info);
static int join_read_prev(READ_RECORD *info);
static int join_ft_read_first(JOIN_TAB *tab);
static int join_ft_read_next(READ_RECORD *info);
static int join_read_always_key_or_null(JOIN_TAB *tab);
static int join_read_next_same_or_null(READ_RECORD *info);
static COND *make_cond_for_table(COND *cond,table_map table,
table_map used_table);
static Item* part_of_refkey(TABLE *form,Field *field);
@@ -450,6 +455,9 @@ JOIN::optimize()
DBUG_RETURN(0);
optimized= 1;
// Ignore errors of execution if option IGNORE present
if (thd->lex.duplicates == DUP_IGNORE)
thd->lex.current_select->no_error= 1;
#ifdef HAVE_REF_TO_FIELDS // Not done yet
/* Add HAVING to WHERE if possible */
if (having && !group_list && !sum_func_count)
@@ -1470,8 +1478,9 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
DYNAMIC_ARRAY *keyuse_array)
{
int error;
uint i,table_count,const_count,found_ref,refs,key,const_ref,eq_part;
table_map found_const_table_map,all_table_map;
uint i,table_count,const_count,key;
table_map found_const_table_map, all_table_map, found_ref, refs;
key_map const_ref, eq_part;
TABLE **table_vector;
JOIN_TAB *stat,*stat_end,*s,**stat_ref;
KEYUSE *keyuse,*start_keyuse;
@@ -1646,16 +1655,17 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
key=keyuse->key;
s->keys|= (key_map) 1 << key; // QQ: remove this ?
refs=const_ref=eq_part=0;
refs=const_ref=0;
eq_part=0;
do
{
if (keyuse->val->type() != Item::NULL_ITEM)
if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize)
{
if (!((~found_const_table_map) & keyuse->used_tables))
const_ref|= (key_map) 1 << keyuse->keypart;
else
refs|=keyuse->used_tables;
eq_part|= (uint) 1 << keyuse->keypart;
eq_part|= (key_map) 1 << keyuse->keypart;
}
keyuse++;
} while (keyuse->table == table && keyuse->key == key);
@@ -1714,8 +1724,6 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
if (s->worst_seeks < 2.0) // Fix for small tables
s->worst_seeks=2.0;
/* if (s->type == JT_EQ_REF)
continue; */
if (s->const_keys)
{
ha_rows records;
@@ -1766,7 +1774,10 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
join->found_const_table_map=found_const_table_map;
if (join->const_tables != join->tables)
{
optimize_keyuse(join, keyuse_array);
find_best_combination(join,all_table_map & ~join->const_table_map);
}
else
{
memcpy((gptr) join->best_positions,(gptr) join->positions,
@@ -1788,13 +1799,26 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
typedef struct key_field_t { // Used when finding key fields
Field *field;
Item *val; // May be empty if diff constant
uint level,const_level; // QQ: Remove const_level
uint level;
uint optimize;
bool eq_func;
bool exists_optimize;
} KEY_FIELD;
/* Values in optimize */
#define KEY_OPTIMIZE_EXISTS 1
#define KEY_OPTIMIZE_REF_OR_NULL 2
/* merge new key definitions to old ones, remove those not used in both */
/*
Merge new key definitions to old ones, remove those not used in both
This is called for OR between different levels
To be able to do 'ref_or_null' we merge a comparison of a column
and 'column IS NULL' to one test. This is useful for sub select queries
that are internally transformed to something like:
SELECT * FROM t1 WHERE t1.key=outer_ref_field or t1.key IS NULL
*/
static KEY_FIELD *
merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
@@ -1816,20 +1840,46 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
{
if (new_fields->val->used_tables())
{
/*
If the value matches, we can use the key reference.
If not, we keep it until we have examined all new values
*/
if (old->val->eq(new_fields->val, old->field->binary()))
{
old->level=old->const_level=and_level;
old->exists_optimize&=new_fields->exists_optimize;
old->level= and_level;
old->optimize= ((old->optimize & new_fields->optimize &
KEY_OPTIMIZE_EXISTS) |
((old->optimize | new_fields->optimize) &
KEY_OPTIMIZE_REF_OR_NULL));
}
}
else if (old->val->eq(new_fields->val, old->field->binary()) &&
old->eq_func && new_fields->eq_func)
else if (old->eq_func && new_fields->eq_func &&
old->val->eq(new_fields->val, old->field->binary()))
{
old->level=old->const_level=and_level;
old->exists_optimize&=new_fields->exists_optimize;
old->level= and_level;
old->optimize= ((old->optimize & new_fields->optimize &
KEY_OPTIMIZE_EXISTS) |
((old->optimize | new_fields->optimize) &
KEY_OPTIMIZE_REF_OR_NULL));
}
else // Impossible; remove it
else if (old->eq_func && new_fields->eq_func &&
(old->val->is_null() || new_fields->val->is_null()))
{
/* field = expression OR field IS NULL */
old->level= and_level;
old->optimize= KEY_OPTIMIZE_REF_OR_NULL;
/* Remember the NOT NULL value */
if (old->val->is_null())
old->val= new_fields->val;
}
else
{
/*
We are comparing two different const. In this case we can't
use a key-lookup on this so it's better to remove the value
and let the range optimzier handle it
*/
if (old == --first_free) // If last item
break;
*old= *first_free; // Remove old value
@@ -1841,7 +1891,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
/* Remove all not used items */
for (KEY_FIELD *old=start ; old != first_free ;)
{
if (old->level != and_level && old->const_level != and_level)
if (old->level != and_level)
{ // Not used in all levels
if (old == --first_free)
break;
@@ -1854,32 +1904,53 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
}
/*
Add a possible key to array of possible keys if it's usable as a key
SYNPOSIS
add_key_field()
key_fields Pointer to add key, if usable
and_level And level, to be stored in KEY_FIELD
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
usable_tables Tables which can be used for key optimization
NOTES
If we are doing a NOT NULL comparison on a NOT NULL field in a outer join
table, we store this to be able to do not exists optimization later.
RETURN
*key_fields is incremented if we stored a key in the array
*/
static void
add_key_field(KEY_FIELD **key_fields,uint and_level,
Field *field,bool eq_func,Item *value,
table_map usable_tables)
{
bool exists_optimize=0;
uint exists_optimize= 0;
if (!(field->flags & PART_KEY_FLAG))
{
// Don't remove column IS NULL on a LEFT JOIN table
if (!eq_func || !value || value->type() != Item::NULL_ITEM ||
!field->table->maybe_null || field->null_ptr)
return; // Not a key. Skip it
exists_optimize=1;
exists_optimize= KEY_OPTIMIZE_EXISTS;
}
else
{
table_map used_tables=0;
if (value && (used_tables=value->used_tables()) &
(field->table->map | RAND_TABLE_BIT))
if (value && ((used_tables=value->used_tables()) &
(field->table->map | RAND_TABLE_BIT)))
return;
if (!(usable_tables & field->table->map))
{
if (!eq_func || !value || value->type() != Item::NULL_ITEM ||
!field->table->maybe_null || field->null_ptr)
return; // Can't use left join optimize
exists_optimize=1;
exists_optimize= KEY_OPTIMIZE_EXISTS;
}
else
{
@@ -1894,7 +1965,8 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
return; // Can't be used as eq key
}
/* Save the following cases:
/*
Save the following cases:
Field op constant
Field LIKE constant where constant doesn't start with a wildcard
Field = field2 where field2 is in a different table
@@ -1906,8 +1978,10 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
if (value->const_item())
stat[0].const_keys |= possible_keys;
/* We can't always use indexes when comparing a string index to a
number. cmp_type() is checked to allow compare of dates to numbers */
/*
We can't always use indexes when comparing a string index to a
number. cmp_type() is checked to allow compare of dates to numbers
*/
if (!eq_func ||
field->result_type() == STRING_RESULT &&
value->result_type() != STRING_RESULT &&
@@ -1919,8 +1993,8 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
(*key_fields)->field= field;
(*key_fields)->eq_func= eq_func;
(*key_fields)->val= value;
(*key_fields)->level=(*key_fields)->const_level=and_level;
(*key_fields)->exists_optimize=exists_optimize;
(*key_fields)->level= and_level;
(*key_fields)->optimize= exists_optimize;
(*key_fields)++;
}
@@ -1940,12 +2014,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
while ((item=li++))
add_key_fields(stat,key_fields,and_level,item,usable_tables);
for (; org_key_fields != *key_fields ; org_key_fields++)
{
if (org_key_fields->const_level == org_key_fields->level)
org_key_fields->const_level=org_key_fields->level= *and_level;
else
org_key_fields->const_level= *and_level;
}
org_key_fields->level= *and_level;
}
else
{
@@ -2050,7 +2119,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
TABLE *form= field->table;
KEYUSE keyuse;
if (key_field->eq_func && !key_field->exists_optimize)
if (key_field->eq_func && !(key_field->optimize & KEY_OPTIMIZE_EXISTS))
{
for (uint key=0 ; key < form->keys ; key++)
{
@@ -2068,7 +2137,9 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
keyuse.val = key_field->val;
keyuse.key = key;
keyuse.keypart=part;
keyuse.keypart_map= (key_part_map) 1 << part;
keyuse.used_tables=key_field->val->used_tables();
keyuse.optimize= key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL;
VOID(insert_dynamic(keyuse_array,(gptr) &keyuse));
}
}
@@ -2152,16 +2223,23 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
VOID(insert_dynamic(keyuse_array,(gptr) &keyuse));
}
static int
sort_keyuse(KEYUSE *a,KEYUSE *b)
{
int res;
if (a->table->tablenr != b->table->tablenr)
return (int) (a->table->tablenr - b->table->tablenr);
if (a->key != b->key)
return (int) (a->key - b->key);
if (a->keypart != b->keypart)
return (int) (a->keypart - b->keypart);
return test(a->used_tables) - test(b->used_tables); // Place const first
// Place const values before other ones
if ((res= test(a->used_tables) - test(b->used_tables)))
return res;
/* Place rows that are not 'OPTIMIZE_REF_OR_NULL' first */
return (int) ((a->optimize & KEY_OPTIMIZE_REF_OR_NULL) -
(b->optimize & KEY_OPTIMIZE_REF_OR_NULL));
}
@@ -2177,8 +2255,6 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
SELECT_LEX *select_lex)
{
uint and_level,i,found_eq_constant;
{
KEY_FIELD *key_fields,*end;
if (!(key_fields=(KEY_FIELD*)
@@ -2201,7 +2277,6 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
/* fill keyuse with found key parts */
for (KEY_FIELD *field=key_fields ; field != end ; field++)
add_key_part(keyuse,field);
}
if (select_lex->ftfunc_list->elements)
{
@@ -2209,9 +2284,10 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
}
/*
Remove ref if there is a keypart which is a ref and a const.
Remove keyparts without previous keyparts.
Special treatment for ft-keys.
Remove the following things from KEYUSE:
- ref if there is a keypart which is a ref and a const.
- keyparts without previous keyparts.
*/
if (keyuse->elements)
{
@@ -2229,8 +2305,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
for (i=0 ; i < keyuse->elements-1 ; i++,use++)
{
if (!use->used_tables)
use->table->const_key_parts[use->key] |=
(key_part_map) 1 << use->keypart;
use->table->const_key_parts[use->key]|= use->keypart_map;
if (use->keypart != FT_KEYPART)
{
if (use->key == prev->key && use->table == prev->table)
@@ -2259,6 +2334,41 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
return FALSE;
}
/*
Update some values in keyuse for faster find_best_combination() loop
*/
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
{
KEYUSE *end,*keyuse= dynamic_element(keyuse_array, 0, KEYUSE*);
for (end= keyuse+ keyuse_array->elements ; keyuse < end ; keyuse++)
{
table_map map;
/*
If we find a ref, assume this table matches a proportional
part of this table.
For example 100 records matching a table with 5000 records
gives 5000/100 = 50 records per key
Constant tables are ignored.
To avoid bad matches, we don't make ref_table_rows less than 100.
*/
keyuse->ref_table_rows= ~(table_map) 0; // If no ref
if (keyuse->used_tables &
(map= (keyuse->used_tables & ~join->const_table_map &
~OUTER_REF_TABLE_BIT)))
{
uint tablenr;
for (tablenr=0 ; ! (map & 1) ; map>>=1, tablenr++) ;
if (map == 1) // Only one table
{
TABLE *tmp_table=join->all_tables[tablenr];
keyuse->ref_table_rows= max(tmp_table->file->records, 100);
}
}
}
}
/*****************************************************************************
Go through all combinations of not marked tables and find the one
@@ -2345,7 +2455,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
uint max_key_part=0;
/* Test how we can use keys */
rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; /* Assumed records/key */
rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; // Assumed records/key
for (keyuse=s->keyuse ; keyuse->table == table ;)
{
key_map found_part=0;
@@ -2353,44 +2463,27 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
uint key=keyuse->key;
KEY *keyinfo=table->key_info+key;
bool ft_key=(keyuse->keypart == FT_KEYPART);
uint found_ref_or_null= 0;
/* Calculate how many key segments of the current key we can use */
start_key=keyuse;
do
{
uint keypart=keyuse->keypart;
uint found_part_ref_or_null= KEY_OPTIMIZE_REF_OR_NULL;
do
{
if (!ft_key)
if (!(rest_tables & keyuse->used_tables) &&
!(found_ref_or_null & keyuse->optimize))
{
table_map map;
if (!(rest_tables & keyuse->used_tables))
{
found_part|= (key_part_map) 1 << keypart;
found_part|=keyuse->keypart_map;
found_ref|= keyuse->used_tables;
}
/*
If we find a ref, assume this table matches a proportional
part of this table.
For example 100 records matching a table with 5000 records
gives 5000/100 = 50 records per key
Constant tables are ignored and to avoid bad matches,
we don't make rec less than 100.
*/
if (keyuse->used_tables &
(map=(keyuse->used_tables & ~join->const_table_map &
~OUTER_REF_TABLE_BIT)))
{
uint tablenr;
for (tablenr=0 ; ! (map & 1) ; map>>=1, tablenr++) ;
if (map == 1) // Only one table
{
TABLE *tmp_table=join->all_tables[tablenr];
if (rec > tmp_table->file->records && rec > 100)
rec=max(tmp_table->file->records,100);
}
}
if (rec > keyuse->ref_table_rows)
rec= keyuse->ref_table_rows;
found_part_ref_or_null&= keyuse->optimize;
}
keyuse++;
found_ref_or_null|= found_part_ref_or_null;
} while (keyuse->table == table && keyuse->key == key &&
keyuse->keypart == keypart);
} while (keyuse->table == table && keyuse->key == key);
@@ -2400,8 +2493,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
*/
if (!found_part && !ft_key)
continue; // Nothing usable found
if (rec == 0)
rec=1L; // Fix for small tables
if (rec < MATCHING_ROWS_IN_OTHER_TABLE)
rec= MATCHING_ROWS_IN_OTHER_TABLE; // Fix for small tables
/*
ft-keys require special treatment
@@ -2420,7 +2513,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
/*
Check if we found full key
*/
if (found_part == PREV_BITS(uint,keyinfo->key_parts))
if (found_part == PREV_BITS(uint,keyinfo->key_parts) &&
!found_ref_or_null)
{ /* use eq key */
max_key_part= (uint) ~0;
if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
@@ -2473,7 +2567,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
Set tmp to (previous record count) * (records / combination)
*/
if ((found_part & 1) &&
!(table->file->index_flags(key) & HA_ONLY_WHOLE_INDEX))
(!(table->file->index_flags(key) & HA_ONLY_WHOLE_INDEX) ||
found_part == PREV_BITS(uint,keyinfo->key_parts)))
{
max_key_part=max_part_bit(found_part);
/*
@@ -2523,6 +2618,12 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
}
records=(ulong) tmp;
}
if (found_ref_or_null)
{
/* We need to do two key searches to find key */
tmp*= 2.0;
records*= 2.0;
}
}
if (table->used_keys & ((key_map) 1 << key))
{
@@ -2772,9 +2873,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
TABLE *table;
KEY *keyinfo;
/*
Use best key from find_best
*/
/* Use best key from find_best */
table=j->table;
key=keyuse->key;
keyinfo=table->key_info+key;
@@ -2790,14 +2889,22 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
else
{
keyparts=length=0;
uint found_part_ref_or_null= 0;
/*
Calculate length for the used key
Stop if there is a missing key part or when we find second key_part
with KEY_OPTIMIZE_REF_OR_NULL
*/
do
{
if (!((~used_tables) & keyuse->used_tables))
if (!(~used_tables & keyuse->used_tables))
{
if (keyparts == keyuse->keypart)
if (keyparts == keyuse->keypart &&
!(found_part_ref_or_null & keyuse->optimize))
{
keyparts++;
length+= keyinfo->key_part[keyuse->keypart].store_length;
found_part_ref_or_null|= keyuse->optimize;
}
}
keyuse++;
@@ -2821,7 +2928,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
keyuse=org_keyuse;
store_key **ref_key= j->ref.key_copy;
byte *key_buff=j->ref.key_buff;
byte *key_buff=j->ref.key_buff, *null_ref_key= 0;
if (ftkey)
{
j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
@@ -2849,9 +2956,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
maybe_null ? (char*) key_buff : 0,
keyinfo->key_part[i].length, keyuse->val);
if (thd->is_fatal_error)
{
return TRUE;
}
tmp.copy();
}
else
@@ -2859,17 +2964,25 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
keyuse,join->const_table_map,
&keyinfo->key_part[i],
(char*) key_buff,maybe_null);
/* Remmeber if we are going to use REF_OR_NULL */
if (keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL)
null_ref_key= key_buff;
key_buff+=keyinfo->key_part[i].store_length;
}
} /* not ftkey */
*ref_key=0; // end_marker
if (j->type == JT_FT) /* no-op */;
else if (j->type == JT_CONST)
if (j->type == JT_FT)
return 0;
if (j->type == JT_CONST)
j->table->const_table= 1;
else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY))
!= HA_NOSAME) ||
keyparts != keyinfo->key_parts)
j->type=JT_REF; /* Must read with repeat */
!= HA_NOSAME) || keyparts != keyinfo->key_parts ||
null_ref_key)
{
/* Must read with repeat */
j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
j->null_ref_key= null_ref_key;
}
else if (ref_key == j->ref.key_copy)
{
/*
@@ -3180,6 +3293,7 @@ make_join_readinfo(JOIN *join, uint options)
table->file->extra(HA_EXTRA_KEYREAD);
}
break;
case JT_REF_OR_NULL:
case JT_REF:
table->status=STATUS_NO_RECORD;
if (tab->select)
@@ -3190,14 +3304,22 @@ make_join_readinfo(JOIN *join, uint options)
delete tab->quick;
tab->quick=0;
table->file->index_init(tab->ref.key);
tab->read_first_record= join_read_always_key;
tab->read_record.read_record= join_read_next_same;
if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
if (tab->type == JT_REF)
{
tab->read_first_record= join_read_always_key;
tab->read_record.read_record= join_read_next_same;
}
else
{
tab->read_first_record= join_read_always_key_or_null;
tab->read_record.read_record= join_read_next_same_or_null;
}
break;
case JT_FT:
table->status=STATUS_NO_RECORD;
@@ -5208,6 +5330,40 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last)
The different ways to read a record
Returns -1 if row was not found, 0 if row was found and 1 on errors
*****************************************************************************/
/* Help function when we get some an error from the table handler */
static int report_error(TABLE *table, int error)
{
if (error == HA_ERR_END_OF_FILE || error == HA_ERR_KEY_NOT_FOUND)
{
table->status= STATUS_GARBAGE;
return -1; // key not found; ok
}
/*
Locking reads can legally return also these errors, do not
print them to the .err log
*/
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error("Got error %d when reading table '%s'",
error, table->path);
table->file->print_error(error,MYF(0));
return 1;
}
static int safe_index_read(JOIN_TAB *tab)
{
int error;
TABLE *table= tab->table;
if ((error=table->file->index_read(table->record[0],
tab->ref.key_buff,
tab->ref.key_length, HA_READ_KEY_EXACT)))
return report_error(table, error);
return 0;
}
static int
join_read_const_table(JOIN_TAB *tab, POSITION *pos)
{
@@ -5262,10 +5418,7 @@ join_read_system(JOIN_TAB *tab)
table->primary_key)))
{
if (error != HA_ERR_END_OF_FILE)
{
table->file->print_error(error,MYF(0));
return 1;
}
return report_error(table, error);
table->null_row=1; // This is ok.
empty_record(table); // Make empty record
return -1;
@@ -5299,15 +5452,7 @@ join_read_const(JOIN_TAB *tab)
table->null_row=1;
empty_record(table);
if (error != HA_ERR_KEY_NOT_FOUND)
{
/* Locking reads can legally return also these errors, do not
print them to the .err log */
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error("read_const: Got error %d when reading table %s",
error, table->path);
table->file->print_error(error,MYF(0));
return 1;
}
return report_error(table, error);
return -1;
}
store_record(table,record[1]);
@@ -5340,12 +5485,7 @@ join_read_key(JOIN_TAB *tab)
tab->ref.key_buff,
tab->ref.key_length,HA_READ_KEY_EXACT);
if (error && error != HA_ERR_KEY_NOT_FOUND)
{
sql_print_error("read_key: Got error %d when reading table '%s'",error,
table->path);
table->file->print_error(error,MYF(0));
return 1;
}
return report_error(table, error);
}
table->null_row=0;
return table->status ? -1 : 0;
@@ -5365,18 +5505,13 @@ join_read_always_key(JOIN_TAB *tab)
tab->ref.key_length,HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND)
{
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error("read_const: Got error %d when reading table %s",error,
table->path);
table->file->print_error(error,MYF(0));
return 1;
}
return report_error(table, error);
return -1; /* purecov: inspected */
}
return 0;
}
/*
This function is used when optimizing away ORDER BY in
SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC
@@ -5395,13 +5530,7 @@ join_read_last_key(JOIN_TAB *tab)
tab->ref.key_length)))
{
if (error != HA_ERR_KEY_NOT_FOUND)
{
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error("read_const: Got error %d when reading table %s",error,
table->path);
table->file->print_error(error,MYF(0));
return 1;
}
return report_error(table, error);
return -1; /* purecov: inspected */
}
return 0;
@@ -5428,19 +5557,14 @@ join_read_next_same(READ_RECORD *info)
tab->ref.key_length)))
{
if (error != HA_ERR_END_OF_FILE)
{
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error("read_next: Got error %d when reading table %s",error,
table->path);
table->file->print_error(error,MYF(0));
return 1;
}
return report_error(table, error);
table->status= STATUS_GARBAGE;
return -1;
}
return 0;
}
static int
join_read_prev_same(READ_RECORD *info)
{
@@ -5449,22 +5573,8 @@ join_read_prev_same(READ_RECORD *info)
JOIN_TAB *tab=table->reginfo.join_tab;
if ((error=table->file->index_prev(table->record[0])))
{
if (error != HA_ERR_END_OF_FILE)
{
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error("read_next: Got error %d when reading table %s",error,
table->path);
table->file->print_error(error,MYF(0));
error= 1;
}
else
{
table->status= STATUS_GARBAGE;
error= -1;
}
}
else if (key_cmp(table, tab->ref.key_buff, tab->ref.key,
return report_error(table, error);
if (key_cmp(table, tab->ref.key_buff, tab->ref.key,
tab->ref.key_length))
{
table->status=STATUS_NOT_FOUND;
@@ -5502,6 +5612,7 @@ join_init_read_record(JOIN_TAB *tab)
return (*tab->read_record.read_record)(&tab->read_record);
}
static int
join_read_first(JOIN_TAB *tab)
{
@@ -5519,17 +5630,10 @@ join_read_first(JOIN_TAB *tab)
tab->read_record.file=table->file;
tab->read_record.index=tab->index;
tab->read_record.record=table->record[0];
error=tab->table->file->index_first(tab->table->record[0]);
if (error)
if ((error=tab->table->file->index_first(tab->table->record[0])))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
{
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error("read_first_with_key: Got error %d when reading table",
error);
table->file->print_error(error,MYF(0));
return 1;
}
report_error(table, error);
return -1;
}
return 0;
@@ -5539,23 +5643,13 @@ join_read_first(JOIN_TAB *tab)
static int
join_read_next(READ_RECORD *info)
{
int error=info->file->index_next(info->record);
if (error)
{
if (error != HA_ERR_END_OF_FILE)
{
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error(
"read_next_with_key: Got error %d when reading table %s",
error, info->table->path);
info->file->print_error(error,MYF(0));
return 1;
}
return -1;
}
int error;
if ((error=info->file->index_next(info->record)))
return report_error(info->table, error);
return 0;
}
static int
join_read_last(JOIN_TAB *tab)
{
@@ -5573,19 +5667,8 @@ join_read_last(JOIN_TAB *tab)
tab->read_record.file=table->file;
tab->read_record.index=tab->index;
tab->read_record.record=table->record[0];
error=tab->table->file->index_last(tab->table->record[0]);
if (error)
{
if (error != HA_ERR_END_OF_FILE)
{
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error("read_last_with_key: Got error %d when reading table",
error, table->path);
table->file->print_error(error,MYF(0));
return 1;
}
return -1;
}
if ((error= tab->table->file->index_last(tab->table->record[0])))
return report_error(table, error);
return 0;
}
@@ -5593,20 +5676,9 @@ join_read_last(JOIN_TAB *tab)
static int
join_read_prev(READ_RECORD *info)
{
int error=info->file->index_prev(info->record);
if (error)
{
if (error != HA_ERR_END_OF_FILE)
{
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error(
"read_prev_with_key: Got error %d when reading table: %s",
error,info->table->path);
info->file->print_error(error,MYF(0));
return 1;
}
return -1;
}
int error;
if ((error= info->file->index_prev(info->record)))
return report_error(info->table, error);
return 0;
}
@@ -5623,42 +5695,57 @@ join_ft_read_first(JOIN_TAB *tab)
#endif
table->file->ft_init();
error=table->file->ft_read(table->record[0]);
if (error)
{
if (error != HA_ERR_END_OF_FILE)
{
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error("ft_read_first: Got error %d when reading table %s",
error, table->path);
table->file->print_error(error,MYF(0));
return 1;
}
return -1;
}
if ((error= table->file->ft_read(table->record[0])))
return report_error(table, error);
return 0;
}
static int
join_ft_read_next(READ_RECORD *info)
{
int error=info->file->ft_read(info->table->record[0]);
if (error)
{
if (error != HA_ERR_END_OF_FILE)
{
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error("ft_read_next: Got error %d when reading table %s",
error, info->table->path);
info->file->print_error(error,MYF(0));
return 1;
}
return -1;
}
int error;
if ((error= info->file->ft_read(info->table->record[0])))
return report_error(info->table, error);
return 0;
}
/*
Reading of key with key reference and one part that may be NULL
*/
static int
join_read_always_key_or_null(JOIN_TAB *tab)
{
int res;
/* First read according to key which is NOT NULL */
*tab->null_ref_key=0;
if ((res= join_read_always_key(tab)) >= 0)
return res;
/* Then read key with null value */
*tab->null_ref_key= 1;
return safe_index_read(tab);
}
static int
join_read_next_same_or_null(READ_RECORD *info)
{
int error;
if ((error= join_read_next_same(info)) >= 0)
return error;
JOIN_TAB *tab= info->table->reginfo.join_tab;
/* Test if we have already done a read after null key */
if (*tab->null_ref_key)
return -1; // All keys read
*tab->null_ref_key= 1; // Read null key
return safe_index_read(tab);
}
/*****************************************************************************
The different end of select functions
These functions returns < 0 when end is reached, 0 on ok and > 0 if a
@@ -6386,10 +6473,13 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
}
ref_key= -1;
if (tab->ref.key >= 0) // Constant range in WHERE
/* Test if constant range in WHERE */
if (tab->ref.key >= 0)
{
ref_key= tab->ref.key;
ref_key_parts= tab->ref.key_parts;
if (tab->type == JT_REF_OR_NULL)
DBUG_RETURN(0);
}
else if (select && select->quick) // Range found by opt_range
{

View File

@@ -27,8 +27,10 @@
typedef struct keyuse_t {
TABLE *table;
Item *val; /* or value if no field */
uint key,keypart;
table_map used_tables;
uint key, keypart, optimize;
key_map keypart_map;
ha_rows ref_table_rows;
} KEYUSE;
class store_key;
@@ -73,7 +75,7 @@ typedef struct st_join_cache {
*/
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
JT_ALL, JT_RANGE, JT_NEXT, JT_FT};
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL};
class JOIN;
@@ -85,6 +87,7 @@ typedef struct st_join_table {
QUICK_SELECT *quick;
Item *on_expr;
const char *info;
byte *null_ref_key;
int (*read_first_record)(struct st_join_table *tab);
int (*next_select)(JOIN *,struct st_join_table *,bool);
READ_RECORD read_record;

View File

@@ -27,8 +27,6 @@
#include "ha_berkeley.h" // For berkeley_show_logs
#endif
/* extern "C" pthread_mutex_t THR_LOCK_keycache; */
static const char *grant_names[]={
"select","insert","update","delete","create","drop","reload","shutdown",
"process","file","grant","references","index","alter"};
@@ -43,15 +41,11 @@ static int mysql_find_files(THD *thd,List<char> *files, const char *db,
static int
store_create_info(THD *thd, TABLE *table, String *packet);
static void
append_identifier(THD *thd, String *packet, const char *name);
extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd;
/****************************************************************************
** Send list of databases
** A database is a directory in the mysql_data_home directory
****************************************************************************/
/*
Report list of databases
A database is a directory in the mysql_data_home directory
*/
int
mysqld_show_dbs(THD *thd,const char *wild)
@@ -1002,8 +996,8 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
}
static void
append_identifier(THD *thd, String *packet, const char *name)
void
append_identifier(THD *thd, String *packet, const char *name, uint length)
{
char qtype;
if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
@@ -1014,12 +1008,12 @@ append_identifier(THD *thd, String *packet, const char *name)
if (thd->options & OPTION_QUOTE_SHOW_CREATE)
{
packet->append(&qtype, 1);
packet->append(name, 0, system_charset_info);
packet->append(name, length, system_charset_info);
packet->append(&qtype, 1);
}
else
{
packet->append(name, 0, system_charset_info);
packet->append(name, length, system_charset_info);
}
}
@@ -1050,7 +1044,7 @@ store_create_info(THD *thd, TABLE *table, String *packet)
packet->append("CREATE TEMPORARY TABLE ", 23);
else
packet->append("CREATE TABLE ", 13);
append_identifier(thd,packet,table->real_name);
append_identifier(thd,packet, table->real_name, strlen(table->real_name));
packet->append(" (\n", 3);
Field **ptr,*field;
@@ -1061,7 +1055,7 @@ store_create_info(THD *thd, TABLE *table, String *packet)
uint flags = field->flags;
packet->append(" ", 2);
append_identifier(thd,packet,field->field_name);
append_identifier(thd,packet,field->field_name, strlen(field->field_name));
packet->append(' ');
// check for surprises from the previous call to Field::sql_type()
if (type.ptr() != tmp)
@@ -1152,7 +1146,7 @@ store_create_info(THD *thd, TABLE *table, String *packet)
packet->append("KEY ", 4);
if (!found_primary)
append_identifier(thd, packet, key_info->name);
append_identifier(thd, packet, key_info->name, strlen(key_info->name));
if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) &&
!limited_mysql_mode && !foreign_db_mode)
@@ -1174,7 +1168,8 @@ store_create_info(THD *thd, TABLE *table, String *packet)
packet->append(',');
if (key_part->field)
append_identifier(thd,packet,key_part->field->field_name);
append_identifier(thd,packet,key_part->field->field_name,
strlen(key_part->field->field_name));
if (!key_part->field ||
(key_part->length !=
table->field[key_part->fieldnr-1]->key_length() &&
@@ -1190,16 +1185,16 @@ store_create_info(THD *thd, TABLE *table, String *packet)
packet->append(')');
}
/*
Get possible foreign key definitions stored in InnoDB and append them
to the CREATE TABLE statement
*/
handler *file = table->file;
/* Get possible foreign key definitions stored in InnoDB and append them
to the CREATE TABLE statement */
char* for_str= file->get_foreign_key_create_info();
if (for_str) {
if (for_str)
{
packet->append(for_str, strlen(for_str));
file->free_foreign_key_create_info(for_str);
}
@@ -1267,7 +1262,8 @@ store_create_info(THD *thd, TABLE *table, String *packet)
{
char buff[100];
sprintf(buff," RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld",
my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE);
my_raid_type(file->raid_type), file->raid_chunks,
file->raid_chunksize/RAID_BLOCK_SIZE);
packet->append(buff);
}
}

View File

@@ -1597,6 +1597,7 @@ alter_list_item:
LEX *lex=Lex;
lex->length=lex->dec=0; lex->type=0; lex->interval=0;
lex->default_value=lex->comment=0;
lex->charset= NULL;
lex->simple_alter=0;
}
type opt_attribute

View File

@@ -395,7 +395,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
}
else
{
if (!(charset=get_charset((uint) strpos[14], MYF(0))))
if (!strpos[14])
charset= &my_charset_bin;
else if (!(charset=get_charset((uint) strpos[14], MYF(0))))
charset= (outparam->table_charset ? outparam->table_charset:
default_charset_info);
}

View File

@@ -460,8 +460,10 @@ static bool pack_fields(File file,List<create_field> &create_fields)
buff[13]= (uchar) field->sql_type;
if (field->sql_type == FIELD_TYPE_GEOMETRY)
buff[14]= (uchar) field->geom_type;
else
else if (field->charset)
buff[14]= (uchar) field->charset->number;
else
buff[14]= 0; // Numerical
int2store(buff+15, field->comment.length);
comment_length+= field->comment.length;
set_if_bigger(int_count,field->interval_id);