merge fix

sql/handler.h:
  Auto merged
sql/item.cc:
  Auto merged
sql/item_strfunc.cc:
  Auto merged
sql/sql_class.h:
  Auto merged
sql/sql_lex.cc:
  Auto merged
sql/sql_lex.h:
  Auto merged
sql/sql_select.cc:
  Auto merged
sql/sql_table.cc:
  Auto merged
This commit is contained in:
unknown 2003-04-26 15:26:28 +03:00
commit 0c94064bbd
66 changed files with 1582 additions and 780 deletions

View file

@ -605,3 +605,4 @@ vio/viotest-ssl
myisam/ftbench/var/*
myisam/ftbench/data
myisam/ftbench/t
client/ssl_test

View file

@ -22,7 +22,7 @@ LIBS = @CLIENT_LIBS@
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysql/libmysqlclient.la
bin_PROGRAMS = mysql mysqladmin mysqlcheck mysqlshow \
mysqldump mysqlimport mysqltest mysqlbinlog mysqlmanagerc mysqlmanager-pwgen
noinst_PROGRAMS = insert_test select_test thread_test
noinst_PROGRAMS = insert_test select_test thread_test ssl_test
noinst_HEADERS = sql_string.h completion_hash.h my_readline.h \
client_priv.h
mysql_SOURCES = mysql.cc readline.cc sql_string.cc completion_hash.cc

View file

@ -40,4 +40,4 @@ enum options { OPT_CHARSETS_DIR=256, OPT_DEFAULT_CHARSET,
OPT_DELETE_MASTER_LOGS,
OPT_PROMPT, OPT_IGN_LINES,OPT_TRANSACTION,OPT_MYSQL_PROTOCOL,
OPT_SHARED_MEMORY_BASE_NAME, OPT_FRM, OPT_SKIP_OPTIMIZATION,
OPT_COMPATIBLE, OPT_RECONNECT };
OPT_COMPATIBLE, OPT_RECONNECT, OPT_DELIMITER };

View file

@ -44,7 +44,7 @@
#include <locale.h>
#endif
const char *VER= "13.5";
const char *VER= "14.0";
/* Don't try to make a nice table if the data is too big */
#define MAX_COLUMN_LENGTH 1024
@ -108,6 +108,7 @@ extern "C" {
#include "completion_hash.h"
#define PROMPT_CHAR '\\'
#define DEFAULT_DELIMITER ";"
typedef struct st_status
{
@ -137,8 +138,8 @@ static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0;
static my_string opt_mysql_unix_port=0;
static int connect_flag=CLIENT_INTERACTIVE;
static char *current_host,*current_db,*current_user=0,*opt_password=0,
*current_prompt=0,
*default_charset= (char*) MYSQL_CHARSET;
*current_prompt=0, *delimiter_str= 0,
*default_charset= (char*) MYSQL_CHARSET;
static char *histfile;
static String glob_buffer,old_buffer;
static String processed_prompt;
@ -160,6 +161,8 @@ static char pager[FN_REFLEN], outfile[FN_REFLEN];
static FILE *PAGER, *OUTFILE;
static MEM_ROOT hash_mem_root;
static uint prompt_counter;
static char delimiter[16]= DEFAULT_DELIMITER;
static uint delimiter_length= 1;
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
@ -187,7 +190,7 @@ static int com_quit(String *str,char*),
com_use(String *str,char*), com_source(String *str, char*),
com_rehash(String *str, char*), com_tee(String *str, char*),
com_notee(String *str, char*),
com_prompt(String *str, char*);
com_prompt(String *str, char*), com_delimiter(String *str, char*);
#ifdef USE_POPEN
static int com_nopager(String *str, char*), com_pager(String *str, char*),
@ -255,7 +258,8 @@ static COMMANDS commands[] = {
"Set outfile [to_outfile]. Append everything into given outfile." },
{ "use", 'u', com_use, 1,
"Use another database. Takes database name as argument." },
{ "delimiter", 'd', com_delimiter, 1,
"Set query delimiter. " },
/* Get bash-like expansion for some commands */
{ "create table", 0, 0, 0, ""},
{ "create database", 0, 0, 0, ""},
@ -312,7 +316,8 @@ int main(int argc,char *argv[])
MY_INIT(argv[0]);
DBUG_ENTER("main");
DBUG_PROCESS(argv[0]);
delimiter_str= delimiter;
default_prompt = my_strdup(getenv("MYSQL_PS1") ?
getenv("MYSQL_PS1") :
"mysql> ",MYF(MY_WME));
@ -482,6 +487,8 @@ static struct my_option my_long_options[] =
#endif
{"database", 'D', "Database to use.", (gptr*) &current_db,
(gptr*) &current_db, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"delimiter", OPT_DELIMITER, "Delimiter to be used.", (gptr*) &delimiter_str,
(gptr*) &delimiter_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"execute", 'e', "Execute command and quit. (Output like with --batch).", 0,
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"vertical", 'E', "Print the output of a query (rows) vertically.",
@ -642,6 +649,14 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
strmov(mysql_charsets_dir, argument);
charsets_dir = mysql_charsets_dir;
break;
case OPT_DELIMITER:
if (argument == disabled_my_option)
strmov(delimiter, DEFAULT_DELIMITER);
else
strmake(delimiter, argument, sizeof(delimiter) - 1);
delimiter_length= strlen(delimiter);
delimiter_str= delimiter;
break;
case OPT_LOCAL_INFILE:
using_opt_local_infile=1;
break;
@ -925,7 +940,7 @@ static COMMANDS *find_command (char *name,char cmd_char)
{
while (my_isspace(charset_info,*name))
name++;
if (strchr(name,';') || strstr(name,"\\g"))
if (strstr(name, delimiter) || strstr(name, "\\g"))
return ((COMMANDS *) 0);
if ((end=strcont(name," \t")))
{
@ -958,7 +973,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
bool *ml_comment)
{
uchar inchar;
char buff[80],*pos,*out;
char buff[80], *pos, *out;
COMMANDS *com;
if (!line[0] && buffer.is_empty())
@ -987,7 +1002,9 @@ static bool add_line(String &buffer,char *line,char *in_string,
}
#endif
if (!*ml_comment && inchar == '\\')
{ // mSQL or postgreSQL style command ?
{
// Found possbile one character command like \c
if (!(inchar = (uchar) *++pos))
break; // readline adds one '\'
if (*in_string || inchar == 'N') // \N is short for NULL
@ -1004,9 +1021,14 @@ static bool add_line(String &buffer,char *line,char *in_string,
return 1; // Quit
if (com->takes_params)
{
for (pos++ ; *pos && *pos != ';' ; pos++) ; // Remove parameters
for (pos++ ;
*pos && (*pos != *delimiter ||
!is_prefix(pos + 1, delimiter + 1)) ; pos++)
; // Remove parameters
if (!*pos)
pos--;
else
pos+= delimiter_length - 1; // Point at last delim char
}
out=line;
}
@ -1020,31 +1042,37 @@ static bool add_line(String &buffer,char *line,char *in_string,
continue;
}
}
else if (!*ml_comment && inchar == ';' && !*in_string)
{ // ';' is end of command
else if (!*ml_comment && (*pos == *delimiter &&
is_prefix(pos + 1, delimiter + 1)) &&
!*in_string)
{
uint old_delimiter_length= delimiter_length;
if (out != line)
buffer.append(line,(uint) (out-line)); // Add this line
if ((com=find_command(buffer.c_ptr(),0)))
buffer.append(line, (uint) (out - line)); // Add this line
if ((com= find_command(buffer.c_ptr(), 0)))
{
if ((*com->func)(&buffer,buffer.c_ptr()) > 0)
if ((*com->func)(&buffer, buffer.c_ptr()) > 0)
return 1; // Quit
}
else
{
int error=com_go(&buffer,0);
int error= com_go(&buffer, 0);
if (error)
{
return error < 0 ? 0 : 1; // < 0 is not fatal
}
}
buffer.length(0);
out=line;
out= line;
pos+= old_delimiter_length - 1;
}
else if (!*ml_comment && (!*in_string && (inchar == '#' ||
inchar == '-' && pos[1] == '-' &&
my_isspace(charset_info,pos[2]))))
break; // comment to end of line
else if (!*in_string && inchar == '/' && *(pos+1) == '*' && *(pos+2) != '!')
else if (!*in_string && inchar == '/' && *(pos+1) == '*' &&
*(pos+2) != '!')
{
pos++;
*ml_comment= 1;
@ -2353,6 +2381,26 @@ static int com_source(String *buffer, char *line)
}
/* ARGSUSED */
static int
com_delimiter(String *buffer __attribute__((unused)), char *line)
{
char buff[256], *tmp;
strmake(buff, line, sizeof(buff) - 1);
tmp= get_arg(buff, 0);
if (!tmp || !*tmp)
{
put_info("DELIMITER must be followed by a 'delimiter' character or string",
INFO_ERROR);
return 0;
}
strmake(delimiter, tmp, sizeof(delimiter) - 1);
delimiter_length= strlen(delimiter);
return 0;
}
/* ARGSUSED */
static int
com_use(String *buffer __attribute__((unused)), char *line)
@ -2416,16 +2464,15 @@ com_use(String *buffer __attribute__((unused)), char *line)
char *get_arg(char *line, my_bool get_next_arg)
{
char *ptr;
char *ptr, *start;
my_bool quoted= 0, valid_arg= 0;
uint count= 0;
char qtype= 0;
ptr= line;
if (get_next_arg)
{
for (; ptr && *ptr; ptr++);
if ((ptr + 1) && *(ptr + 1))
for (; *ptr; ptr++) ;
if (*(ptr + 1))
ptr++;
}
else
@ -2448,18 +2495,12 @@ char *get_arg(char *line, my_bool get_next_arg)
quoted= 1;
ptr++;
}
for (; ptr && *ptr; ptr++, count++)
for (start=ptr ; *ptr; ptr++)
{
if (*ptr == '\\') // escaped character
if (*ptr == '\\' && ptr[1]) // escaped character
{
// jump over the backslash
char *tmp_ptr, tmp_buff[256];
tmp_ptr= strmov(tmp_buff, (ptr - count));
tmp_ptr-= (strlen(tmp_buff) - count);
strmov(tmp_ptr, (ptr + 1));
strmov(line, tmp_buff);
ptr= line;
ptr+= count;
// Remove the backslash
strmov(ptr, ptr+1);
}
else if ((!quoted && *ptr == ' ') || (quoted && *ptr == qtype))
{
@ -2467,10 +2508,8 @@ char *get_arg(char *line, my_bool get_next_arg)
break;
}
}
for (ptr-= count; ptr && *ptr; ptr++)
if (!my_isspace(charset_info, *ptr))
valid_arg= 1;
return valid_arg ? ptr - count : '\0';
valid_arg= ptr != start;
return valid_arg ? start : NullS;
}
@ -2512,7 +2551,7 @@ sql_real_connect(char *host,char *database,char *user,char *password,
}
if (!mysql_real_connect(&mysql, host, user, password,
database, opt_mysql_port, opt_mysql_unix_port,
connect_flag))
connect_flag | CLIENT_MULTI_QUERIES))
{
if (!silent ||
(mysql_errno(&mysql) != CR_CONN_HOST_ERROR &&
@ -2615,6 +2654,7 @@ com_status(String *buffer __attribute__((unused)),
tee_fprintf(stdout, "Current pager:\t\t%s\n", pager);
tee_fprintf(stdout, "Using outfile:\t\t'%s'\n", opt_outfile ? outfile : "");
#endif
tee_fprintf(stdout, "Using delimiter:\t%s\n", delimiter);
tee_fprintf(stdout, "Server version:\t\t%s\n", mysql_get_server_info(&mysql));
tee_fprintf(stdout, "Protocol version:\t%d\n", mysql_get_proto_info(&mysql));
tee_fprintf(stdout, "Connection:\t\t%s\n", mysql_get_host_info(&mysql));

View file

@ -41,7 +41,9 @@ int main(int argc, char **argv)
mysql_init(&mysql);
#ifdef HAVE_OPENSSL
mysql_ssl_set(&mysql,"../SSL/MySQL-client-key.pem","../SSL/MySQL-client-cert.pem","../SSL/MySQL-ca-cert.pem","../SSL/");
mysql_ssl_set(&mysql,"../SSL/MySQL-client-key.pem",
"../SSL/MySQL-client-cert.pem",
"../SSL/MySQL-ca-cert.pem", 0, 0);
#endif
if (!(sock = mysql_real_connect(&mysql,"127.0.0.1",0,0,argv[1],3306,NULL,0)))
{
@ -49,7 +51,6 @@ int main(int argc, char **argv)
perror("");
exit(1);
}
printf("Cipher:%s\n",mysql_ssl_cipher(&mysql));
count = 0;
num = atoi(argv[2]);
while (count < num)
@ -62,7 +63,7 @@ int main(int argc, char **argv)
}
if (!(res=mysql_store_result(sock)))
{
fprintf(stderr,"Couldn't get result from query failed\n",
fprintf(stderr,"Couldn't get result from query failed (%s)\n",
mysql_error(sock));
exit(1);
}

View file

@ -40,26 +40,26 @@ A
a
AD
ad
AE
ae
AE
AF
af
B
b
B
SS
ss
U
u
U
UE
ue
Ü
ü
Y
y
ü
Ü
Z
z
Å
å
Å
Ä
ä
ß
@ -69,26 +69,26 @@ A
a
AD
ad
AE
ae
AE
AF
af
B
b
B
SS
ss
U
u
U
UE
ue
Ü
ü
Y
y
ü
Ü
Z
z
Å
å
Å
Ä
ä
ß
@ -100,23 +100,23 @@ a
å
AD
ad
AE
ae
Ä
ae
AE
ä
AF
af
B
AF
b
SS
ss
B
ß
ss
SS
U
u
UE
ue
Ü
UE
ü
Ü
Y
y
Z
@ -129,23 +129,23 @@ AD
ad
AE
ae
AF
af
AF
Ä
ä
Å
å
B
b
SS
B
ss
SS
ß
U
u
UE
ue
Ü
ü
Ü
Y
y
Z
@ -187,26 +187,26 @@ A
a
AD
ad
AE
ae
AE
AF
af
B
b
B
SS
ss
U
u
U
UE
ue
Ü
ü
Y
y
ü
Ü
Z
z
Å
å
Å
Ä
ä
ß
@ -218,23 +218,23 @@ a
å
AD
ad
AE
ae
Ä
ae
AE
ä
AF
af
B
AF
b
SS
ss
B
ß
ss
SS
U
u
UE
ue
Ü
UE
ü
Ü
Y
y
Z
@ -247,23 +247,23 @@ AD
ad
AE
ae
AF
af
AF
Ä
ä
Å
å
B
b
SS
B
ss
SS
ß
U
u
UE
ue
Ü
ü
Ü
Y
y
Z
@ -511,59 +511,59 @@ SHOW FIELDS FROM t1;
Field Type Collation Null Key Default Extra
latin1_f char(32) latin1_bin YES NULL
SET CHARACTER SET 'latin1';
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
Variable_name Value
client_collation latin1_swedish_ci
collation_client latin1_swedish_ci
SET CHARACTER SET latin1;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
Variable_name Value
client_collation latin1_swedish_ci
SHOW VARIABLES LIKE 'client_collation';
collation_client latin1_swedish_ci
SHOW VARIABLES LIKE 'collation_client';
Variable_name Value
client_collation latin1_swedish_ci
collation_client latin1_swedish_ci
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
charset('a') collation('a') coercibility('a') 'a'='A'
latin1 latin1_swedish_ci 3 1
SET CHARACTER SET latin1 COLLATE latin1_bin;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
Variable_name Value
client_collation latin1_bin
collation_client latin1_bin
SET CHARACTER SET LATIN1 COLLATE Latin1_Bin;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
Variable_name Value
client_collation latin1_bin
collation_client latin1_bin
SET CHARACTER SET 'latin1' COLLATE 'latin1_bin';
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
Variable_name Value
client_collation latin1_bin
collation_client latin1_bin
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
charset('a') collation('a') coercibility('a') 'a'='A'
latin1 latin1_swedish_ci 3 1
SET CHARACTER SET koi8r;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
Variable_name Value
client_collation koi8r_general_ci
collation_client koi8r_general_ci
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
charset('a') collation('a') coercibility('a') 'a'='A'
latin1 latin1_swedish_ci 3 1
SET CHARACTER SET koi8r COLLATE koi8r_bin;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
Variable_name Value
client_collation koi8r_bin
collation_client koi8r_bin
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
charset('a') collation('a') coercibility('a') 'a'='A'
latin1 latin1_swedish_ci 3 1
SET CHARACTER SET koi8r COLLATE DEFAULT;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
Variable_name Value
client_collation koi8r_general_ci
collation_client koi8r_general_ci
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
charset('a') collation('a') coercibility('a') 'a'='A'
latin1 latin1_swedish_ci 3 1
SET CHARACTER SET DEFAULT;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
Variable_name Value
client_collation latin1_swedish_ci
collation_client latin1_swedish_ci
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
charset('a') collation('a') coercibility('a') 'a'='A'
latin1 latin1_swedish_ci 3 1

View file

@ -753,10 +753,10 @@ lower(utf8_f)
Ú
Ö
Ö
<EFBFBD>
£
Å
£
<EFBFBD>
Ä
Ä
Ç

View file

@ -7,11 +7,6 @@ length(@test_compress_string)
select uncompress(compress(@test_compress_string));
uncompress(compress(@test_compress_string))
string for test compress function aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
select uncompress(@test_compress_string);
uncompress(@test_compress_string)
NULL
Warnings:
Error 1254 Too big size of uncompressed data. The maximum size is 8192. (probably, length of uncompressed data was corrupted)
select uncompressed_length(compress(@test_compress_string))=length(@test_compress_string);
uncompressed_length(compress(@test_compress_string))=length(@test_compress_string)
1
@ -33,3 +28,15 @@ select concat('|',c,'|') from t1;
concat('|',c,'|')
|d|
drop table t1;
select compress("");
compress("")
select uncompress("");
uncompress("")
select uncompress(compress(""));
uncompress(compress(""))
select uncompressed_length("");
uncompressed_length("")
0

View file

@ -146,7 +146,7 @@ select grp,group_concat(c) from t1 group by grp;
grp group_concat(c)
1 NULL
2 b
3 E,D,D
3 D,D,E
4
5 NULL
Warnings:

View file

@ -10,7 +10,7 @@ a
3
show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 0
Qcache_queries_in_cache 1
drop table t1;
commit;
set autocommit=1;
@ -24,7 +24,7 @@ a
3
show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 0
Qcache_queries_in_cache 1
drop table t1;
commit;
create table t1 (a int not null) type=innodb;
@ -69,7 +69,7 @@ Variable_name Value
Qcache_queries_in_cache 3
show status like "Qcache_hits";
Variable_name Value
Qcache_hits 0
Qcache_hits 3
insert into t1 values (3);
insert into t2 values (3);
insert into t1 values (4);
@ -93,11 +93,11 @@ Variable_name Value
Qcache_queries_in_cache 3
show status like "Qcache_hits";
Variable_name Value
Qcache_hits 0
Qcache_hits 4
commit;
show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 1
Qcache_queries_in_cache 3
drop table if exists t1;
CREATE TABLE t1 (id int(11) NOT NULL auto_increment, PRIMARY KEY (id)) TYPE=InnoDB;
select count(*) from t1;

View file

@ -0,0 +1,18 @@
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
stop slave;
create table t1 (a int) type=innodb;
reset slave;
start slave;
stop slave;
start slave;
select master_pos_wait('master-bin.001',3000,120)=-1;
master_pos_wait('master-bin.001',3000,120)=-1
0
select * from t1 where a=8000;
a
8000

View file

@ -458,6 +458,14 @@ Subselect returns more than 1 record
select numeropost as a FROM t1 ORDER BY (SELECT 1 FROM t1 HAVING a=1);
Subselect returns more than 1 record
drop table t1;
create table t1 (a int);
insert into t1 values (1),(2),(3);
(select * from t1) union (select * from t1) order by (select a from t1 limit 1);
a
1
2
3
drop table t1;
CREATE TABLE t1 (field char(1) NOT NULL DEFAULT 'b');
INSERT INTO t1 VALUES ();
SELECT field FROM t1 WHERE 1=(SELECT 1 UNION ALL SELECT 1 FROM (SELECT 1) a HAVING field='b');
@ -810,7 +818,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 NULL a 5 NULL 3 Using where; Using index
2 DEPENDENT SUBQUERY t2 index a a 5 NULL 3 Using where; Using index
drop table t1,t2;
create table t1 (a float);
select 10.5 IN (SELECT * from t1 LIMIT 1);
@ -1062,7 +1070,7 @@ SELECT 0 IN (SELECT 1 FROM t1 a);
EXPLAIN SELECT 0 IN (SELECT 1 FROM t1 a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
INSERT INTO t1 (pseudo) VALUES ('test1');
SELECT 0 IN (SELECT 1 FROM t1 a);
0 IN (SELECT 1 FROM t1 a)
@ -1070,7 +1078,7 @@ SELECT 0 IN (SELECT 1 FROM t1 a);
EXPLAIN SELECT 0 IN (SELECT 1 FROM t1 a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
drop table t1;
CREATE TABLE `t1` (
`i` int(11) NOT NULL default '0',
@ -1099,3 +1107,9 @@ id name
2 lenka
1 lenka
drop table t1,t2;
create table t1 (a int, unique index indexa (a));
insert into t1 values (-1), (-4), (-2), (NULL);
select -10 IN (select a from t1 FORCE INDEX (indexa));
-10 IN (select a from t1 FORCE INDEX (indexa))
NULL
drop table t1;

View file

@ -156,9 +156,9 @@ show variables like 'net_buffer_length';
Variable_name Value
net_buffer_length 1048576
set character set cp1251_koi8;
show variables like "client_collation";
show variables like "collation_client";
Variable_name Value
client_collation cp1251_bulgarian_ci
collation_client cp1251_bulgarian_ci
select @@timestamp>0;
@@timestamp>0
1
@ -185,7 +185,7 @@ set SESSION query_cache_size=10000;
Variable 'query_cache_size' is a GLOBAL variable and should be set with SET GLOBAL
set GLOBAL table_type=DEFAULT;
Variable 'table_type' doesn't have a default value
set client_collation=UNKNOWN_CHARACTER_SET;
set collation_client=UNKNOWN_CHARACTER_SET;
Unknown character set: 'UNKNOWN_CHARACTER_SET'
set global autocommit=1;
Variable 'autocommit' is a LOCAL variable and can't be used with SET GLOBAL

View file

@ -128,29 +128,29 @@ SHOW CREATE TABLE t1;
SHOW FIELDS FROM t1;
SET CHARACTER SET 'latin1';
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
SET CHARACTER SET latin1;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
SHOW VARIABLES LIKE 'collation_client';
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
SET CHARACTER SET latin1 COLLATE latin1_bin;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
SET CHARACTER SET LATIN1 COLLATE Latin1_Bin;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
SET CHARACTER SET 'latin1' COLLATE 'latin1_bin';
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
SET CHARACTER SET koi8r;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
SET CHARACTER SET koi8r COLLATE koi8r_bin;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
SET CHARACTER SET koi8r COLLATE DEFAULT;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
SET CHARACTER SET DEFAULT;
SHOW VARIABLES LIKE 'client_collation';
SHOW VARIABLES LIKE 'collation_client';
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
--error 1251
SET CHARACTER SET latin1 COLLATE koi8r;

View file

@ -7,7 +7,6 @@ select @test_compress_string:='string for test compress function aaaaaaaaaaaaaaa
select length(@test_compress_string);
select uncompress(compress(@test_compress_string));
select uncompress(@test_compress_string);
select uncompressed_length(compress(@test_compress_string))=length(@test_compress_string);
select uncompressed_length(compress(@test_compress_string));
select length(compress(@test_compress_string))<length(@test_compress_string);
@ -17,4 +16,10 @@ insert into t1 (a,b,c) values (compress(@test_compress_string),compress(@test_co
select uncompress(a) from t1;
select uncompress(b) from t1;
select concat('|',c,'|') from t1;
drop table t1;
drop table t1;
select compress("");
select uncompress("");
select uncompress(compress(""));
select uncompressed_length("");

View file

@ -0,0 +1,4 @@
-O max_binlog_size=16384
--innodb
--log-warnings

View file

@ -0,0 +1,61 @@
# When the relay log gets rotated while the I/O thread
# is reading a transaction, the transaction spans on two or more
# relay logs. If STOP SLAVE occurs while the SQL thread is
# executing a part of the transaction in the non-first relay logs,
# we test if START SLAVE will resume in the beginning of the
# transaction (i.e., step back to the first relay log)
# The slave is started with max_binlog_size=16384 bytes,
# to force many rotations (approximately 30 rotations)
# If the master or slave does not support InnoDB, this test will pass
source include/master-slave.inc;
connection slave;
stop slave;
connection master;
create table t1 (a int) type=innodb;
let $1=8000;
disable_query_log;
begin;
while ($1)
{
# eval means expand $ expressions
eval insert into t1 values( $1 );
dec $1;
}
commit;
# This will generate a 500kB master's binlog,
# which corresponds to 30 slave's relay logs.
enable_query_log;
save_master_pos;
connection slave;
reset slave;
start slave;
# We wait 1 sec for the SQL thread to be somewhere in
# the middle of the transaction, hopefully not in
# the first relay log, and hopefully before the COMMIT.
# Usually it stops when the SQL thread is around the 15th relay log.
# We cannot use MASTER_POS_WAIT() as master's position
# increases only when the slave executes the COMMIT.
system sleep 1;
stop slave;
# We suppose the SQL thread stopped before COMMIT.
# If so the transaction was rolled back
# and the table is now empty.
# Now restart
start slave;
# And see if the table contains '8000'
# which proves that the transaction restarted at
# the right place.
# We must wait for the transaction to commit before
# reading, MASTER_POS_WAIT() will do it for sure
# (the only statement with position>=3000 is COMMIT).
# Older versions of MySQL would hang forever in MASTER_POS_WAIT
# because COMMIT was said to be position 0 in the master's log (bug).
# Detect this with timeout.
select master_pos_wait('master-bin.001',3000,120)=-1;
select * from t1 where a=8000;
# Note that the simple fact to have less than around 30 slave's binlogs
# (the slave is started with --log-slave-updates) is already
# a proof that the transaction was not properly resumed.

View file

@ -244,6 +244,11 @@ select numeropost as a FROM t1 GROUP BY (SELECT 1 FROM t1 HAVING a=1);
select numeropost as a FROM t1 ORDER BY (SELECT 1 FROM t1 HAVING a=1);
drop table t1;
create table t1 (a int);
insert into t1 values (1),(2),(3);
(select * from t1) union (select * from t1) order by (select a from t1 limit 1);
drop table t1;
#iftest
CREATE TABLE t1 (field char(1) NOT NULL DEFAULT 'b');
INSERT INTO t1 VALUES ();
@ -690,3 +695,11 @@ INSERT INTO t2 VALUES (4,'vita'), (1,'vita'), (2,'vita'), (1,'vita');
update t1, t2 set t2.name='lenka' where t2.id in (select id from t1);
select * from t2;
drop table t1,t2;
#
# correct NULL in <CONSTANT> IN (SELECT ...)
#
create table t1 (a int, unique index indexa (a));
insert into t1 values (-1), (-4), (-2), (NULL);
select -10 IN (select a from t1 FORCE INDEX (indexa));
drop table t1;

View file

@ -92,7 +92,7 @@ set net_buffer_length=2000000000;
show variables like 'net_buffer_length';
set character set cp1251_koi8;
show variables like "client_collation";
show variables like "collation_client";
select @@timestamp>0;
set @@rand_seed1=10000000,@@rand_seed2=1000000;
@ -119,7 +119,7 @@ set SESSION query_cache_size=10000;
--error 1230
set GLOBAL table_type=DEFAULT;
--error 1115
set client_collation=UNKNOWN_CHARACTER_SET;
set collation_client=UNKNOWN_CHARACTER_SET;
--error 1228
set global autocommit=1;
--error 1228

View file

@ -1,4 +1,5 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -51,6 +52,10 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer,
static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count);
static uint sortlength(SORT_FIELD *sortorder, uint s_length,
bool *multi_byte_charset);
static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield,
uint sortlength, uint *plength);
static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
byte *buff);
/*
Creates a set of pointers that can be used to read the rows
@ -82,16 +87,48 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
DBUG_PUSH(""); /* No DBUG here */
#endif
outfile= table->io_cache;
outfile= table->sort.io_cache;
my_b_clear(&tempfile);
my_b_clear(&buffpek_pointers);
buffpek=0;
sort_keys= (uchar **) NULL;
error= 1;
bzero((char*) &param,sizeof(param));
param.sort_length= sortlength(sortorder, s_length, &multi_byte_charset);
param.ref_length= table->file->ref_length;
param.sort_length= (sortlength(sortorder,s_length, &multi_byte_charset)+
param.ref_length);
param.addon_field= 0;
param.addon_length= 0;
if (!(table->tmp_table || table->fulltext_searched))
{
/*
Get the descriptors of all fields whose values are appended
to sorted fields and get its total length in param.spack_length.
*/
param.addon_field= get_addon_fields(thd, table->field,
param.sort_length,
&param.addon_length);
}
table->sort.addon_buf= 0;
table->sort.addon_length= param.addon_length;
table->sort.addon_field= param.addon_field;
table->sort.unpack= unpack_addon_fields;
if (param.addon_field)
{
param.res_length= param.addon_length;
if (!(table->sort.addon_buf= (byte *) my_malloc(param.addon_length,
MYF(MY_WME))))
goto err;
}
else
{
param.res_length= param.ref_length;
/*
The reference to the record is considered
as an additional sorted field
*/
param.sort_length+= param.ref_length;
}
param.rec_length= param.sort_length+param.addon_length;
param.max_rows= max_rows;
if (select && select->quick)
@ -115,7 +152,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
records=table->file->estimate_number_of_rows();
selected_records_file= 0;
}
if (param.sort_length == param.ref_length && records > param.max_rows)
if (param.rec_length == param.ref_length && records > param.max_rows)
records=param.max_rows; /* purecov: inspected */
if (multi_byte_charset &&
@ -127,9 +164,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
while (memavl >= min_sort_memory)
{
ulong old_memavl;
ulong keys= memavl/(param.sort_length+sizeof(char*));
ulong keys= memavl/(param.rec_length+sizeof(char*));
param.keys=(uint) min(records+1, keys);
if ((sort_keys= (uchar **) make_char_array(param.keys, param.sort_length,
if ((sort_keys= (uchar **) make_char_array(param.keys, param.rec_length,
MYF(0))))
break;
old_memavl=memavl;
@ -176,8 +213,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
Use also the space previously used by string pointers in sort_buffer
for temporary key storage.
*/
param.keys=((param.keys*(param.sort_length+sizeof(char*))) /
param.sort_length-1);
param.keys=((param.keys*(param.rec_length+sizeof(char*))) /
param.rec_length-1);
maxbuffer--; // Offset from 0
if (merge_many_buff(&param,(uchar*) sort_keys,buffpek,&maxbuffer,
&tempfile))
@ -356,8 +393,8 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
if (write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
DBUG_RETURN(HA_POS_ERROR);
idx=0;
if (param->ref_length == param->sort_length &&
my_b_tell(tempfile)/param->sort_length >= param->max_rows)
if (param->ref_length == param->rec_length &&
my_b_tell(tempfile)/param->rec_length >= param->max_rows)
{
/*
We are writing the result index file and have found all
@ -385,7 +422,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
DBUG_RETURN(my_b_inited(tempfile) ?
(ha_rows) (my_b_tell(tempfile)/param->sort_length) :
(ha_rows) (my_b_tell(tempfile)/param->rec_length) :
idx);
} /* find_all_keys */
@ -394,29 +431,30 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
static int
write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
{
uint sort_length;
uint sort_length, rec_length;
uchar **end;
BUFFPEK buffpek;
DBUG_ENTER("write_keys");
sort_length=param->sort_length;
sort_length= param->sort_length;
rec_length= param->rec_length;
#ifdef MC68000
quicksort(sort_keys,count,sort_length);
#else
my_string_ptr_sort((gptr) sort_keys,(uint) count,sort_length);
my_string_ptr_sort((gptr) sort_keys, (uint) count, sort_length);
#endif
if (!my_b_inited(tempfile) &&
open_cached_file(tempfile,mysql_tmpdir,TEMP_PREFIX,DISK_BUFFER_SIZE,
MYF(MY_WME)))
goto err; /* purecov: inspected */
buffpek.file_pos=my_b_tell(tempfile);
open_cached_file(tempfile, mysql_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
MYF(MY_WME)))
goto err; /* purecov: inspected */
buffpek.file_pos= my_b_tell(tempfile);
if ((ha_rows) count > param->max_rows)
count=(uint) param->max_rows; /* purecov: inspected */
count=(uint) param->max_rows; /* purecov: inspected */
buffpek.count=(ha_rows) count;
for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
if (my_b_write(tempfile,(byte*) *sort_keys,(uint) sort_length))
if (my_b_write(tempfile, (byte*) *sort_keys, (uint) rec_length))
goto err;
if (my_b_write(buffpek_pointers, (byte*) &buffpek, sizeof(buffpek)))
goto err;
@ -505,10 +543,10 @@ static void make_sortkey(register SORTPARAM *param,
}
else
{
my_strnxfrm(cs,(uchar*)to,length,(const uchar*)res->ptr(),length);
bzero((char *)to+length,diff);
my_strnxfrm(cs,(uchar*)to,length,(const uchar*)res->ptr(),length);
bzero((char *)to+length,diff);
}
break;
break;
}
case INT_RESULT:
{
@ -577,29 +615,56 @@ static void make_sortkey(register SORTPARAM *param,
else
to+= sort_field->length;
}
memcpy((byte*) to,ref_pos,(size_s) param->ref_length);/* Save filepos last */
if (param->addon_field)
{
/*
Save field values appended to sorted fields.
First null bit indicators are appended then field values follow.
In this implementation we use fixed layout for field values -
the same for all records.
*/
SORT_ADDON_FIELD *addonf= param->addon_field;
uchar *nulls= to;
DBUG_ASSERT(addonf);
bzero((char *) nulls, addonf->offset);
to+= addonf->offset;
for ( ; (field= addonf->field) ; addonf++)
{
if (addonf->null_bit && field->is_null())
nulls[addonf->null_offset]|= addonf->null_bit;
else
field->pack((char *) to, field->ptr);
to+= addonf->length;
}
}
else
{
/* Save filepos last */
memcpy((byte*) to, ref_pos, (size_s) param->ref_length);
}
return;
}
static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count)
{
uint offset,ref_length;
uint offset,res_length;
byte *to;
DBUG_ENTER("save_index");
my_string_ptr_sort((gptr) sort_keys,(uint) count,param->sort_length);
ref_length=param->ref_length;
offset=param->sort_length-ref_length;
my_string_ptr_sort((gptr) sort_keys, (uint) count, param->sort_length);
res_length= param->res_length;
offset= param->rec_length-res_length;
if ((ha_rows) count > param->max_rows)
count=(uint) param->max_rows;
if (!(to=param->sort_form->record_pointers=
(byte*) my_malloc(ref_length*count,MYF(MY_WME))))
DBUG_RETURN(1); /* purecov: inspected */
for (uchar **end=sort_keys+count ; sort_keys != end ; sort_keys++)
if (!(to= param->sort_form->sort.record_pointers=
(byte*) my_malloc(res_length*count, MYF(MY_WME))))
DBUG_RETURN(1); /* purecov: inspected */
for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++)
{
memcpy(to,*sort_keys+offset,ref_length);
to+=ref_length;
memcpy(to, *sort_keys+offset, res_length);
to+= res_length;
}
DBUG_RETURN(0);
}
@ -654,7 +719,7 @@ int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
/* This returns (uint) -1 if something goes wrong */
uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
uint sort_length)
uint rec_length)
{
register uint count;
uint length;
@ -662,33 +727,35 @@ uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count)))
{
if (my_pread(fromfile->file,(byte*) buffpek->base,
(length= sort_length*count),buffpek->file_pos,MYF_RW))
(length= rec_length*count),buffpek->file_pos,MYF_RW))
return((uint) -1); /* purecov: inspected */
buffpek->key=buffpek->base;
buffpek->file_pos+= length; /* New filepos */
buffpek->count-= count;
buffpek->mem_count= count;
}
return (count*sort_length);
return (count*rec_length);
} /* read_to_buffer */
/* Merge buffers to one buffer */
/*
Merge buffers to one buffer
*/
int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
IO_CACHE *to_file, uchar *sort_buffer,
BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb,
int flag)
IO_CACHE *to_file, uchar *sort_buffer,
BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb,
int flag)
{
int error;
uint sort_length,offset;
uint rec_length,sort_length,res_length,offset;
ulong maxcount;
ha_rows max_rows,org_max_rows;
my_off_t to_start_filepos;
uchar *strpos;
BUFFPEK *buffpek,**refpek;
QUEUE queue;
qsort2_cmp cmp;
qsort2_cmp cmp;
volatile bool *killed= &current_thd->killed;
bool not_killable;
DBUG_ENTER("merge_buffers");
@ -697,29 +764,32 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
if (param->not_killable)
{
killed= &not_killable;
not_killable=0;
not_killable= 0;
}
error=0;
offset=(sort_length=param->sort_length)-param->ref_length;
maxcount=(ulong) (param->keys/((uint) (Tb-Fb) +1));
to_start_filepos=my_b_tell(to_file);
strpos=(uchar*) sort_buffer;
org_max_rows=max_rows=param->max_rows;
rec_length= param->rec_length;
res_length= param->res_length;
sort_length= param->sort_length;
offset= rec_length-res_length;
maxcount= (ulong) (param->keys/((uint) (Tb-Fb) +1));
to_start_filepos= my_b_tell(to_file);
strpos= (uchar*) sort_buffer;
org_max_rows=max_rows= param->max_rows;
if (init_queue(&queue,(uint) (Tb-Fb)+1,offsetof(BUFFPEK,key),0,
(queue_compare)
(cmp=get_ptr_compare(sort_length)),(void*) &sort_length))
DBUG_RETURN(1); /* purecov: inspected */
if (init_queue(&queue, (uint) (Tb-Fb)+1, offsetof(BUFFPEK,key), 0,
(queue_compare) (cmp= get_ptr_compare(sort_length)),
(void*) &sort_length))
DBUG_RETURN(1); /* purecov: inspected */
for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
{
buffpek->base= strpos;
buffpek->max_keys=maxcount;
strpos+= (uint) (error=(int) read_to_buffer(from_file,buffpek,
sort_length));
buffpek->max_keys= maxcount;
strpos+= (uint) (error= (int) read_to_buffer(from_file, buffpek,
rec_length));
if (error == -1)
goto err; /* purecov: inspected */
queue_insert(&queue,(byte*) buffpek);
goto err; /* purecov: inspected */
queue_insert(&queue, (byte*) buffpek);
}
if (param->unique_buff)
@ -732,98 +802,101 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
This is safe as we know that there is always more than one element
in each block to merge (This is guaranteed by the Unique:: algorithm
*/
buffpek=(BUFFPEK*) queue_top(&queue);
memcpy(param->unique_buff, buffpek->key, sort_length);
if (my_b_write(to_file,(byte*) buffpek->key, sort_length))
buffpek= (BUFFPEK*) queue_top(&queue);
memcpy(param->unique_buff, buffpek->key, rec_length);
if (my_b_write(to_file, (byte*) buffpek->key, rec_length))
{
error=1; goto err; /* purecov: inspected */
error=1; goto err; /* purecov: inspected */
}
buffpek->key+=sort_length;
buffpek->key+= rec_length;
buffpek->mem_count--;
if (!--max_rows)
{
error=0; /* purecov: inspected */
goto end; /* purecov: inspected */
error= 0; /* purecov: inspected */
goto end; /* purecov: inspected */
}
queue_replaced(&queue); // Top element has been used
queue_replaced(&queue); // Top element has been used
}
else
cmp=0; // Not unique
cmp= 0; // Not unique
while (queue.elements > 1)
{
if (*killed)
{
error=1; goto err; /* purecov: inspected */
error= 1; goto err; /* purecov: inspected */
}
for (;;)
{
buffpek=(BUFFPEK*) queue_top(&queue);
if (cmp) // Remove duplicates
buffpek= (BUFFPEK*) queue_top(&queue);
if (cmp) // Remove duplicates
{
if (!(*cmp)(&sort_length, &(param->unique_buff),
(uchar**) &buffpek->key))
goto skip_duplicate;
memcpy(param->unique_buff, (uchar*) buffpek->key,sort_length);
if (!(*cmp)(&sort_length, &(param->unique_buff),
(uchar**) &buffpek->key))
goto skip_duplicate;
memcpy(param->unique_buff, (uchar*) buffpek->key, rec_length);
}
if (flag == 0)
{
if (my_b_write(to_file,(byte*) buffpek->key, sort_length))
{
error=1; goto err; /* purecov: inspected */
}
if (my_b_write(to_file,(byte*) buffpek->key, rec_length))
{
error=1; goto err; /* purecov: inspected */
}
}
else
{
WRITE_REF(to_file,(byte*) buffpek->key+offset);
if (my_b_write(to_file, (byte*) buffpek->key+offset, res_length))
{
error=1; goto err; /* purecov: inspected */
}
}
if (!--max_rows)
{
error=0; /* purecov: inspected */
goto end; /* purecov: inspected */
error= 0; /* purecov: inspected */
goto end; /* purecov: inspected */
}
skip_duplicate:
buffpek->key+=sort_length;
buffpek->key+= rec_length;
if (! --buffpek->mem_count)
{
if (!(error=(int) read_to_buffer(from_file,buffpek,
sort_length)))
{
uchar *base=buffpek->base;
ulong max_keys=buffpek->max_keys;
if (!(error= (int) read_to_buffer(from_file,buffpek,
rec_length)))
{
uchar *base= buffpek->base;
ulong max_keys= buffpek->max_keys;
VOID(queue_remove(&queue,0));
VOID(queue_remove(&queue,0));
/* Put room used by buffer to use in other buffer */
for (refpek= (BUFFPEK**) &queue_top(&queue);
refpek <= (BUFFPEK**) &queue_end(&queue);
refpek++)
{
buffpek= *refpek;
if (buffpek->base+buffpek->max_keys*sort_length == base)
{
buffpek->max_keys+=max_keys;
break;
}
else if (base+max_keys*sort_length == buffpek->base)
{
buffpek->base=base;
buffpek->max_keys+=max_keys;
break;
}
}
break; /* One buffer have been removed */
}
else if (error == -1)
goto err; /* purecov: inspected */
/* Put room used by buffer to use in other buffer */
for (refpek= (BUFFPEK**) &queue_top(&queue);
refpek <= (BUFFPEK**) &queue_end(&queue);
refpek++)
{
buffpek= *refpek;
if (buffpek->base+buffpek->max_keys*rec_length == base)
{
buffpek->max_keys+= max_keys;
break;
}
else if (base+max_keys*rec_length == buffpek->base)
{
buffpek->base= base;
buffpek->max_keys+= max_keys;
break;
}
}
break; /* One buffer have been removed */
}
else if (error == -1)
goto err; /* purecov: inspected */
}
queue_replaced(&queue); /* Top element has been replaced */
queue_replaced(&queue); /* Top element has been replaced */
}
}
buffpek=(BUFFPEK*) queue_top(&queue);
buffpek= (BUFFPEK*) queue_top(&queue);
buffpek->base= sort_buffer;
buffpek->max_keys=param->keys;
buffpek->max_keys= param->keys;
/*
As we know all entries in the buffer are unique, we only have to
@ -833,7 +906,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
{
if (!(*cmp)(&sort_length, &(param->unique_buff), (uchar**) &buffpek->key))
{
buffpek->key+=sort_length; // Remove duplicate
buffpek->key+= rec_length; // Remove duplicate
--buffpek->mem_count;
}
}
@ -841,37 +914,40 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
do
{
if ((ha_rows) buffpek->mem_count > max_rows)
{ /* Don't write too many records */
buffpek->mem_count=(uint) max_rows;
buffpek->count=0; /* Don't read more */
{ /* Don't write too many records */
buffpek->mem_count= (uint) max_rows;
buffpek->count= 0; /* Don't read more */
}
max_rows-=buffpek->mem_count;
max_rows-= buffpek->mem_count;
if (flag == 0)
{
if (my_b_write(to_file,(byte*) buffpek->key,
(sort_length*buffpek->mem_count)))
(rec_length*buffpek->mem_count)))
{
error=1; goto err; /* purecov: inspected */
error= 1; goto err; /* purecov: inspected */
}
}
else
{
register uchar *end;
strpos= buffpek->key+offset;
for (end=strpos+buffpek->mem_count*sort_length;
strpos != end ;
strpos+=sort_length)
{
WRITE_REF(to_file,strpos);
for (end= strpos+buffpek->mem_count*rec_length ;
strpos != end ;
strpos+= rec_length)
{
if (my_b_write(to_file, (byte *) strpos, res_length))
{
error=1; goto err;
}
}
}
}
while ((error=(int) read_to_buffer(from_file,buffpek,sort_length))
!= -1 && error != 0);
while ((error=(int) read_to_buffer(from_file,buffpek, rec_length))
!= -1 && error != 0);
end:
lastbuff->count=min(org_max_rows-max_rows,param->max_rows);
lastbuff->file_pos=to_start_filepos;
lastbuff->count= min(org_max_rows-max_rows, param->max_rows);
lastbuff->file_pos= to_start_filepos;
err:
delete_queue(&queue);
DBUG_RETURN(error);
@ -925,7 +1001,6 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
sortorder->need_strxnfrm= 0;
if (sortorder->field)
{
if (sortorder->field->type() == FIELD_TYPE_BLOB)
sortorder->length= thd->variables.max_sort_length;
else
@ -947,7 +1022,7 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
case STRING_RESULT:
sortorder->length=sortorder->item->max_length;
if (use_strnxfrm((cs=sortorder->item->charset())))
{
{
sortorder->length= sortorder->length*cs->strxfrm_multiply;
sortorder->need_strxnfrm= 1;
*multi_byte_charset= 1;
@ -981,6 +1056,148 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
}
/*
Get descriptors of fields appended to sorted fields and
calculate its total length
SYNOPSIS
get_addon_fields()
thd Current thread
ptabfields Array of references to the table fields
sortlength Total length of sorted fields
plength out: Total length of appended fields
DESCRIPTION
The function first finds out what fields are used in the result set.
Then it calculates the length of the buffer to store the values of
these fields together with the value of sort values.
If the calculated length is not greater than max_length_for_sort_data
the function allocates memory for an array of descriptors containing
layouts for the values of the non-sorted fields in the buffer and
fills them.
NOTES
The null bits for the appended values are supposed to be put together
and stored the buffer just ahead of the value of the first field.
RETURN
Pointer to the layout descriptors for the appended fields, if any
NULL - if we do not store field values with sort data.
*/
static SORT_ADDON_FIELD *
get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
{
Field **pfield;
Field *field;
SORT_ADDON_FIELD *addonf;
uint length= 0;
uint fields= 0;
uint null_fields= 0;
/*
If there is a reference to a field in the query add it
to the the set of appended fields.
Note for future refinement:
This this a too strong condition.
Actually we need only the fields referred in the
result set. And for some of them it makes sense to use
the values directly from sorted fields.
*/
*plength= 0;
/*
The following statement is added to avoid sorting in alter_table.
The fact is the filter 'field->query_id != thd->query_id'
doesn't work for alter table
*/
if (thd->lex.sql_command != SQLCOM_SELECT)
return 0;
for (pfield= ptabfield; (field= *pfield) ; pfield++)
{
if (field->query_id != thd->query_id)
continue;
if (field->flags & BLOB_FLAG)
return 0;
length+= field->max_packed_col_length(field->pack_length());
if (field->maybe_null())
null_fields++;
fields++;
}
if (!fields)
return 0;
length+= (null_fields+7)/8;
if (length+sortlength > thd->variables.max_length_for_sort_data ||
!(addonf= (SORT_ADDON_FIELD *) my_malloc(sizeof(SORT_ADDON_FIELD)*
(fields+1), MYF(MY_WME))))
return 0;
*plength= length;
length= (null_fields+7)/8;
null_fields= 0;
for (pfield= ptabfield; (field= *pfield) ; pfield++)
{
if (field->query_id != thd->query_id)
continue;
addonf->field= field;
addonf->offset= length;
if (field->maybe_null())
{
addonf->null_offset= null_fields/8;
addonf->null_bit= 1<<(null_fields & 7);
null_fields++;
}
else
{
addonf->null_offset= 0;
addonf->null_bit= 0;
}
addonf->length= field->max_packed_col_length(field->pack_length());
length+= addonf->length;
addonf++;
}
addonf->field= 0; // Put end marker
DBUG_PRINT("info",("addon_length: %d",length));
return (addonf-fields);
}
/*
Copy (unpack) values appended to sorted fields from a buffer back to
their regular positions specified by the Field::ptr pointers.
SYNOPSIS
unpack_addon_fields()
addon_field Array of descriptors for appended fields
buff Buffer which to unpack the value from
NOTES
The function is supposed to be used only as a callback function
when getting field values for the sorted result set.
RETURN
void.
*/
static void
unpack_addon_fields(struct st_sort_addon_field *addon_field, byte *buff)
{
Field *field;
SORT_ADDON_FIELD *addonf= addon_field;
for ( ; (field= addonf->field) ; addonf++)
{
if (addonf->null_bit && (addonf->null_bit & buff[addonf->null_offset]))
{
field->set_null();
continue;
}
field->set_notnull();
field->unpack(field->ptr, (char *) buff+addonf->offset);
}
}
/*
** functions to change a double or float to a sortable string
** The following should work for IEEE

View file

@ -166,6 +166,7 @@ class ha_berkeley: public handler
}
longlong get_auto_increment();
void print_error(int error, myf errflag);
uint8 table_cache_type() { return HA_CACHE_TBL_TRANSACT; }
};
extern bool berkeley_skip, berkeley_shared_data;

View file

@ -475,7 +475,7 @@ If thd is not in the autocommit state, this function also starts a new
transaction for thd if there is no active trx yet, and assigns a consistent
read view to it if there is no read view yet. */
my_bool
bool
innobase_query_caching_of_table_permitted(
/*======================================*/
/* out: TRUE if permitted, FALSE if not;
@ -916,11 +916,11 @@ innobase_commit_low(
/* Update the replication position info inside InnoDB */
trx->mysql_master_log_file_name
= active_mi->rli.master_log_name;
= active_mi->rli.group_master_log_name;
trx->mysql_master_log_pos = ((ib_longlong)
(active_mi->rli.master_log_pos +
active_mi->rli.event_len +
active_mi->rli.pending));
(active_mi->rli.group_master_log_pos +
active_mi->rli.event_len
));
}
#endif /* HAVE_REPLICATION */
trx_commit_for_mysql(trx);

View file

@ -168,6 +168,7 @@ class ha_innobase: public handler
enum thr_lock_type lock_type);
void init_table_handle_for_HANDLER();
longlong get_auto_increment();
uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
};
extern bool innodb_skip;
@ -207,6 +208,6 @@ int innobase_close_connection(THD *thd);
int innobase_drop_database(char *path);
int innodb_show_status(THD* thd);
my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name,
uint full_name_len);
bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name,
uint full_name_len);
void innobase_release_temporary_latches(void* innobase_tid);

View file

@ -877,6 +877,16 @@ int handler::delete_all_rows()
return (my_errno=HA_ERR_WRONG_COMMAND);
}
bool handler::caching_allowed(THD* thd, char* table_key,
uint key_length, uint8 cache_type)
{
if (cache_type == HA_CACHE_TBL_ASKTRANSACT)
return innobase_query_caching_of_table_permitted(thd, table_key,
key_length);
else
return 1;
}
/****************************************************************************
** Some general functions that isn't in the handler class
****************************************************************************/

View file

@ -117,6 +117,11 @@
#define HA_OPTION_NO_DELAY_KEY_WRITE (1L << 18)
#define HA_MAX_REC_LENGTH 65535
/* Table caching type */
#define HA_CACHE_TBL_NONTRANSACT 0
#define HA_CACHE_TBL_ASKTRANSACT 1
#define HA_CACHE_TBL_TRANSACT 2
enum db_type { DB_TYPE_UNKNOWN=0,DB_TYPE_DIAB_ISAM=1,
DB_TYPE_HASH,DB_TYPE_MISAM,DB_TYPE_PISAM,
DB_TYPE_RMS_ISAM, DB_TYPE_HEAP, DB_TYPE_ISAM,
@ -343,6 +348,16 @@ public:
virtual THR_LOCK_DATA **store_lock(THD *thd,
THR_LOCK_DATA **to,
enum thr_lock_type lock_type)=0;
/* Type of table for caching query */
virtual uint8 table_cache_type() { return HA_CACHE_TBL_NONTRANSACT; }
/*
Is query with this cable cachable (have sense only for ASKTRANSACT
tables)
*/
static bool caching_allowed(THD* thd, char* table_key,
uint key_length, uint8 cahe_type);
};
/* Some extern variables used with handlers */

View file

@ -172,7 +172,7 @@ bool Item::get_time(TIME *ltime)
CHARSET_INFO * Item::default_charset() const
{
return current_thd->db_charset;
return current_thd->variables.collation_connection;
}
bool Item::set_charset(CHARSET_INFO *cs1, enum coercion co1,

View file

@ -603,6 +603,7 @@ public:
item(it)
{}
bool fix_fields(THD *, struct st_table_list *, Item ** ref);
Item **storage() {return &item;}
};
/*

View file

@ -1781,6 +1781,43 @@ longlong Item_func_isnull::val_int()
return args[0]->is_null() ? 1: 0;
}
longlong Item_is_not_null_test::val_int()
{
DBUG_ENTER("Item_is_not_null_test::val_int");
if (!used_tables_cache)
{
owner->was_null|= (!cached_value);
DBUG_PRINT("info", ("cached :%d", cached_value));
DBUG_RETURN(cached_value);
}
if (args[0]->is_null())
{
DBUG_PRINT("info", ("null"))
owner->was_null|= 1;
DBUG_RETURN(0);
}
else
DBUG_RETURN(1);
}
/* Optimize case of not_null_column IS NULL */
void Item_is_not_null_test::update_used_tables()
{
if (!args[0]->maybe_null)
{
used_tables_cache= 0; /* is always true */
cached_value= (longlong) 1;
}
else
{
args[0]->update_used_tables();
if (!(used_tables_cache=args[0]->used_tables()))
{
/* Remember if the value is always NULL or never NULL */
cached_value= (longlong) !args[0]->is_null();
}
}
}
longlong Item_func_isnotnull::val_int()
{
@ -1870,7 +1907,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
{
const char* tmp = first + 1;
for (; *tmp != wild_many && *tmp != wild_one && *tmp != escape; tmp++) ;
canDoTurboBM = tmp == last;
canDoTurboBM = (tmp == last) && !use_mb(args[0]->charset());
}
if (canDoTurboBM)

View file

@ -648,6 +648,7 @@ class Item_func_in :public Item_int_func
class Item_func_isnull :public Item_bool_func
{
protected:
longlong cached_value;
public:
Item_func_isnull(Item *a) :Item_bool_func(a) {}
@ -656,11 +657,11 @@ public:
void fix_length_and_dec()
{
decimals=0; max_length=1; maybe_null=0;
Item_func_isnull::update_used_tables();
update_used_tables();
}
const char *func_name() const { return "isnull"; }
/* Optimize case of not_null_column IS NULL */
void update_used_tables()
virtual void update_used_tables()
{
if (!args[0]->maybe_null)
{
@ -680,6 +681,22 @@ public:
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
};
/* Functions used by HAVING for rewriting IN subquery */
class Item_in_subselect;
class Item_is_not_null_test :public Item_func_isnull
{
Item_in_subselect* owner;
public:
Item_is_not_null_test(Item_in_subselect* ow, Item *a)
:Item_func_isnull(a), owner(ow)
{}
longlong val_int();
const char *func_name() const { return "is_not_null_test"; }
void update_used_tables();
};
class Item_func_isnotnull :public Item_bool_func
{
public:

View file

@ -646,7 +646,13 @@ Item *create_func_point(Item *a, Item *b)
return new Item_func_point(a, b);
}
#ifdef HAVE_COMPRESS
#if !defined(HAVE_COMPRESS)
Item *create_func_compress (Item*a __attribute__((unused))){return 0;}
Item *create_func_uncompress (Item*a __attribute__((unused))){return 0;}
Item *create_func_uncompressed_length(Item*a __attribute__((unused))){return 0;}
#else
Item *create_func_compress(Item* a)
{

View file

@ -142,9 +142,7 @@ Item *create_func_numgeometries(Item *a);
Item *create_func_point(Item *a, Item *b);
#ifdef HAVE_COMPRESS
Item *create_func_compress(Item *a);
Item *create_func_uncompress(Item *a);
Item *create_func_uncompressed_length(Item *a);
#endif

View file

@ -993,7 +993,8 @@ longlong Item_func_uncompressed_length::val_int()
return 0; /* purecov: inspected */
}
null_value=0;
return uint4korr(res->c_ptr());
if (res->is_empty()) return 0;
return uint4korr(res->c_ptr()) & 0x3FFFFFFF;
}
#endif /* HAVE_COMPRESS */

View file

@ -2925,6 +2925,8 @@ ret:
String *Item_func_compress::val_str(String *str)
{
String *res= args[0]->val_str(str);
if (res->is_empty()) return res;
int err= Z_OK;
int code;
@ -2940,14 +2942,13 @@ String *Item_func_compress::val_str(String *str)
compress(compress(compress(...)))
I.e. zlib give number 'at least'..
*/
uLongf new_size= (uLongf)((res->length()*120)/100)+12;
ulong new_size= (ulong)((res->length()*120)/100)+12;
buffer.realloc((uint32)new_size+sizeof(int32)+sizeof(char));
Byte *body= ((Byte*)buffer.c_ptr())+sizeof(int32);
err= compress(body, &new_size,(const Bytef*)res->c_ptr(), res->length());
buffer.realloc((uint32)new_size + 4 + 1);
Byte *body= ((Byte*)buffer.c_ptr()) + 4;
if (err != Z_OK)
if ((err= compress(body, &new_size,
(const Bytef*)res->c_ptr(), res->length())) != Z_OK)
{
code= err==Z_MEM_ERROR ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_BUF_ERROR;
push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,code,ER(code));
@ -2955,18 +2956,17 @@ String *Item_func_compress::val_str(String *str)
return 0;
}
int4store(buffer.c_ptr(),res->length());
buffer.length((uint32)new_size+sizeof(int32));
/* This is for the stupid char fields which trimm ' ': */
int4store(buffer.c_ptr(),res->length() & 0x3FFFFFFF);
/* This is for the stupid char fields which trim ' ': */
char *last_char= ((char*)body)+new_size-1;
if (*last_char == ' ')
{
*++last_char= '.';
new_size++;
}
buffer.length((uint32)new_size+sizeof(int32));
buffer.length((uint32)new_size + 4);
return &buffer;
}
@ -2974,7 +2974,9 @@ String *Item_func_compress::val_str(String *str)
String *Item_func_uncompress::val_str(String *str)
{
String *res= args[0]->val_str(str);
uLongf new_size= uint4korr(res->c_ptr());
if (res->is_empty()) return res;
ulong new_size= uint4korr(res->c_ptr()) & 0x3FFFFFFF;
int err= Z_OK;
uint code;
@ -2983,16 +2985,14 @@ String *Item_func_uncompress::val_str(String *str)
push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_TOO_BIG_FOR_UNCOMPRESS,
ER(ER_TOO_BIG_FOR_UNCOMPRESS),MAX_BLOB_WIDTH);
null_value= 1;
null_value= 0;
return 0;
}
buffer.realloc((uint32)new_size);
err= uncompress((Byte*)buffer.c_ptr(), &new_size,
((const Bytef*)res->c_ptr())+sizeof(int32),res->length());
if (err == Z_OK)
if ((err= uncompress((Byte*)buffer.c_ptr(), &new_size,
((const Bytef*)res->c_ptr())+4,res->length())) == Z_OK)
{
buffer.length((uint32)new_size);
return &buffer;

View file

@ -508,9 +508,31 @@ void Item_in_subselect::single_value_transformer(THD *thd,
sl->item_list.push_back(new Item_int("Not_used", (longlong) 1, 21));
if (sl->table_list.elements)
{
item= (*func)(expr, new Item_asterisk_remover(this, item,
(char *)"<no matter>",
(char*)"<result>"));
Item *having= item, *isnull= item;
if (item->type() == Item::FIELD_ITEM &&
((Item_field*) item)->field_name[0] == '*')
{
Item_asterisk_remover *remover;
item= remover= new Item_asterisk_remover(this, item,
(char*)"<no matter>",
(char*)"<result>");
having=
new Item_is_not_null_test(this,
new Item_ref(remover->storage(),
(char*)"<no matter>",
(char*)"<null test>"));
isnull=
new Item_is_not_null_test(this,
new Item_ref(remover->storage(),
(char*)"<no matter>",
(char*)"<null test>"));
}
having= new Item_is_not_null_test(this, having);
sl->having= (sl->having ?
new Item_cond_and(having, sl->having) :
having);
item= new Item_cond_or((*func)(expr, item),
new Item_func_isnull(isnull));
sl->where= and_items(sl->where, item);
}
else

View file

@ -183,6 +183,7 @@ public:
friend class Item_asterisk_remover;
friend class Item_ref_null_helper;
friend class Item_is_not_null_test;
};
/* ALL/ANY/SOME subselect */

View file

@ -448,9 +448,7 @@ static SYMBOL sql_functions[] = {
{ "CHARACTER_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_char_length)},
{ "COALESCE", SYM(COALESCE),0,0},
{ "COERCIBILITY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_coercibility)},
#ifdef HAVE_COMPRESS
{ "COMPRESS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_compress)},
#endif
{ "CONCAT", SYM(CONCAT),0,0},
{ "CONCAT_WS", SYM(CONCAT_WS),0,0},
{ "CONNECTION_ID", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_connection_id)},
@ -627,10 +625,8 @@ static SYMBOL sql_functions[] = {
{ "TOUCHES", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_touches)},
{ "TRIM", SYM(TRIM),0,0},
{ "UCASE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
#ifdef HAVE_COMPRESS
{ "UNCOMPRESS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_uncompress)},
{ "UNCOMPRESSED_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_uncompressed_length)},
#endif
{ "UNIQUE_USERS", SYM(UNIQUE_USERS),0,0},
{ "UNIX_TIMESTAMP", SYM(UNIX_TIMESTAMP),0,0},
{ "UPPER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},

View file

@ -592,24 +592,32 @@ err:
/*
Delete the current log file, remove it from index file and start on next
Delete relay log files prior to rli->group_relay_log_name
(i.e. all logs which are not involved in a non-finished group
(transaction)), remove them from the index file and start on next relay log.
SYNOPSIS
purge_first_log()
rli Relay log information
rli Relay log information
included If false, all relay logs that are strictly before
rli->group_relay_log_name are deleted ; if true, the latter is
deleted too (i.e. all relay logs
read by the SQL slave thread are deleted).
NOTE
- This is only called from the slave-execute thread when it has read
all commands from a log and want to switch to a new log.
- When this happens, we should never be in an active transaction as
a transaction is always written as a single block to the binary log.
all commands from a relay log and want to switch to a new relay log.
- When this happens, we can be in an active transaction as
a transaction can span over two relay logs
(although it is always written as a single block to the master's binary
log, hence cannot span over two master's binary logs).
IMPLEMENTATION
- Protects index file with LOCK_index
- Delete first log file,
- Copy all file names after this one to the front of the index file
- Delete relevant relay log files
- Copy all file names after these ones to the front of the index file
- If the OS has truncate, truncate the file, else fill it with \n'
- Read the first file name from the index file and store in rli->linfo
- Read the next file name from the index file and store in rli->linfo
RETURN VALUES
0 ok
@ -620,66 +628,68 @@ err:
#ifdef HAVE_REPLICATION
int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli)
int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli, bool included)
{
int error;
DBUG_ENTER("purge_first_log");
/*
Test pre-conditions.
Assume that we have previously read the first log and
stored it in rli->relay_log_name
*/
DBUG_ASSERT(is_open());
DBUG_ASSERT(rli->slave_running == 1);
DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->relay_log_name));
DBUG_ASSERT(rli->linfo.index_file_offset ==
strlen(rli->relay_log_name) + 1);
DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name));
/* We have already processed the relay log, so it's safe to delete it */
my_delete(rli->relay_log_name, MYF(0));
pthread_mutex_lock(&LOCK_index);
if (copy_up_file_and_fill(&index_file, rli->linfo.index_file_offset))
{
error= LOG_INFO_IO;
goto err;
}
pthread_mutex_lock(&rli->log_space_lock);
rli->relay_log.purge_logs(rli->group_relay_log_name, included,
0, 0, &rli->log_space_total);
// Tell the I/O thread to take the relay_log_space_limit into account
rli->ignore_log_space_limit= 0;
pthread_mutex_unlock(&rli->log_space_lock);
/*
Update the space counter used by all relay logs
Ok to broadcast after the critical region as there is no risk of
the mutex being destroyed by this thread later - this helps save
context switches
*/
pthread_mutex_lock(&rli->log_space_lock);
rli->log_space_total -= rli->relay_log_pos;
//tell the I/O thread to take the relay_log_space_limit into account
rli->ignore_log_space_limit= 0;
pthread_mutex_unlock(&rli->log_space_lock);
pthread_cond_broadcast(&rli->log_space_cond);
/*
Read the next log file name from the index file and pass it back to
the caller
If included is true, we want the first relay log;
otherwise we want the one after event_relay_log_name.
*/
if ((error=find_log_pos(&rli->linfo, NullS, 0 /*no mutex*/)))
if ((included && (error=find_log_pos(&rli->linfo, NullS, 0))) ||
(!included &&
((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)) ||
(error=find_next_log(&rli->linfo, 0)))))
{
char buff[22];
sql_print_error("next log error: %d offset: %s log: %s",
error,
llstr(rli->linfo.index_file_offset,buff),
rli->linfo.log_file_name);
sql_print_error("next log error: %d offset: %s log: %s included: %d",
error,
llstr(rli->linfo.index_file_offset,buff),
rli->group_relay_log_name,
included);
goto err;
}
/*
Reset position to current log. This involves setting both of the
position variables:
Reset rli's coordinates to the current log.
*/
rli->relay_log_pos = BIN_LOG_HEADER_SIZE;
rli->pending = 0;
strmake(rli->relay_log_name,rli->linfo.log_file_name,
sizeof(rli->relay_log_name)-1);
rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
sizeof(rli->event_relay_log_name)-1);
/*
If we removed the rli->group_relay_log_name file,
we must update the rli->group* coordinates, otherwise do not touch it as the
group's execution is not finished (e.g. COMMIT not executed)
*/
if (included)
{
rli->group_relay_log_pos = BIN_LOG_HEADER_SIZE;
strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
sizeof(rli->group_relay_log_name)-1);
}
/* Store where we are in the new file for the execution thread */
flush_relay_log_info(rli);
@ -693,13 +703,14 @@ err:
Update log index_file
*/
int MYSQL_LOG::update_log_index(LOG_INFO* log_info)
int MYSQL_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
{
if (copy_up_file_and_fill(&index_file, log_info->index_file_start_offset))
return LOG_INFO_IO;
// now update offsets in index file for running threads
adjust_linfo_offsets(log_info->index_file_start_offset);
if (need_update_threads)
adjust_linfo_offsets(log_info->index_file_start_offset);
return 0;
}
@ -708,9 +719,13 @@ int MYSQL_LOG::update_log_index(LOG_INFO* log_info)
SYNOPSIS
purge_logs()
thd Thread pointer
to_log Delete all log file name before this file. This file is not
deleted
to_log Delete all log file name before this file.
included If true, to_log is deleted too.
need_mutex
need_update_threads If we want to update the log coordinates of
all threads. False for relay logs, true otherwise.
freed_log_space If not null, decrement this variable of
the amount of log space freed
NOTES
If any of the logs before the deleted one is in use,
@ -722,31 +737,59 @@ int MYSQL_LOG::update_log_index(LOG_INFO* log_info)
LOG_INFO_EOF to_log not found
*/
int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
int MYSQL_LOG::purge_logs(const char *to_log,
bool included,
bool need_mutex,
bool need_update_threads,
ulonglong *decrease_log_space)
{
int error;
bool exit_loop= 0;
LOG_INFO log_info;
DBUG_ENTER("purge_logs");
DBUG_PRINT("info",("to_log= %s",to_log));
if (no_rotate)
DBUG_RETURN(LOG_INFO_PURGE_NO_ROTATE);
pthread_mutex_lock(&LOCK_index);
if (need_mutex)
pthread_mutex_lock(&LOCK_index);
if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/)))
goto err;
/*
File name exists in index file; Delete until we find this file
File name exists in index file; delete until we find this file
or a file that is used.
*/
if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
goto err;
while (strcmp(to_log,log_info.log_file_name) &&
!log_in_use(log_info.log_file_name))
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
!log_in_use(log_info.log_file_name))
{
/* It's not fatal even if we can't delete a log file */
my_delete(log_info.log_file_name, MYF(0));
if (find_next_log(&log_info, 0))
ulong tmp;
if (decrease_log_space) //stat the file we want to delete
{
MY_STAT s;
if (my_stat(log_info.log_file_name,&s,MYF(0)))
tmp= s.st_size;
else
{
/*
If we could not stat, we can't know the amount
of space that deletion will free. In most cases,
deletion won't work either, so it's not a problem.
*/
tmp= 0;
}
}
/*
It's not fatal if we can't delete a log file ;
if we could delete it, take its size into account
*/
DBUG_PRINT("info",("purging %s",log_info.log_file_name));
if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space)
*decrease_log_space-= tmp;
if (find_next_log(&log_info, 0) || exit_loop)
break;
}
@ -754,10 +797,11 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
If we get killed -9 here, the sysadmin would have to edit
the log index file after restart - otherwise, this should be safe
*/
error= update_log_index(&log_info);
error= update_log_index(&log_info, need_update_threads);
err:
pthread_mutex_unlock(&LOCK_index);
if (need_mutex)
pthread_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
@ -779,7 +823,7 @@ err:
LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated
*/
int MYSQL_LOG::purge_logs_before_date(THD* thd, time_t purge_time)
int MYSQL_LOG::purge_logs_before_date(time_t purge_time)
{
int error;
LOG_INFO log_info;
@ -816,7 +860,7 @@ int MYSQL_LOG::purge_logs_before_date(THD* thd, time_t purge_time)
If we get killed -9 here, the sysadmin would have to edit
the log index file after restart - otherwise, this should be safe
*/
error= update_log_index(&log_info);
error= update_log_index(&log_info, 1);
err:
pthread_mutex_unlock(&LOCK_index);
@ -1269,7 +1313,7 @@ err:
{
long purge_time= time(0) - expire_logs_days*24*60*60;
if (purge_time >= 0)
error= purge_logs_before_date(current_thd, purge_time);
error= purge_logs_before_date(purge_time);
}
#endif
@ -1534,7 +1578,6 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
If you don't do it this way, you will get a deadlock in THD::awake()
*/
void MYSQL_LOG:: wait_for_update(THD* thd)
{
safe_mutex_assert_owner(&LOCK_log);

View file

@ -310,11 +310,36 @@ int Log_event::exec_event(struct st_relay_log_info* rli)
*/
if (rli)
{
if (rli->inside_transaction)
rli->inc_pending(get_event_len());
/*
If in a transaction, and if the slave supports transactions,
just inc_event_relay_log_pos(). We only have to check for OPTION_BEGIN
(not OPTION_NOT_AUTOCOMMIT) as transactions are logged
with BEGIN/COMMIT, not with SET AUTOCOMMIT= .
CAUTION: opt_using_transactions means
innodb || bdb ; suppose the master supports InnoDB and BDB,
but the slave supports only BDB, problems
will arise:
- suppose an InnoDB table is created on the master,
- then it will be MyISAM on the slave
- but as opt_using_transactions is true, the slave will believe he is
transactional with the MyISAM table. And problems will come when one
does START SLAVE; STOP SLAVE; START SLAVE; (the slave will resume at BEGIN
whereas there has not been any rollback). This is the problem of
using opt_using_transactions instead of a finer
"does the slave support _the_transactional_handler_used_on_the_master_".
More generally, we'll have problems when a query mixes a transactional
handler and MyISAM and STOP SLAVE is issued in the middle of the
"transaction". START SLAVE will resume at BEGIN while the MyISAM table has
already been updated.
*/
if ((thd->options & OPTION_BEGIN) && opt_using_transactions)
rli->inc_event_relay_log_pos(get_event_len());
else
{
rli->inc_pos(get_event_len(),log_pos);
rli->inc_group_relay_log_pos(get_event_len(),log_pos);
flush_relay_log_info(rli);
}
}
@ -878,9 +903,13 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
thd->db = rewrite_db((char*)db);
/*
InnoDB internally stores the master log position it has processed so far;
position to store is really pos + pending + event_len
since we must store the pos of the END of the current log event
InnoDB internally stores the master log position it has executed so far,
i.e. the position just after the COMMIT event.
When InnoDB will want to store, the positions in rli won't have
been updated yet, so group_master_log_* will point to old BEGIN
and event_master_log* will point to the beginning of current COMMIT.
So the position to store is event_master_log_pos + event_len
since we must store the pos of the END of the current log event (COMMIT).
*/
rli->event_len= get_event_len();
@ -909,18 +938,6 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
DBUG_PRINT("query",("%s",thd->query));
mysql_parse(thd, thd->query, q_len);
/*
Set a flag if we are inside an transaction so that we can restart
the transaction from the start if we are killed
This will only be done if we are supporting transactional tables
in the slave.
*/
if (!strcmp(thd->query,"BEGIN"))
rli->inside_transaction= opt_using_transactions;
else if (!strcmp(thd->query,"COMMIT"))
rli->inside_transaction=0;
DBUG_PRINT("info",("expected_error: %d last_errno: %d",
expected_error, thd->net.last_errno));
if ((expected_error != (actual_error= thd->net.last_errno)) &&
@ -1776,14 +1793,15 @@ int Rotate_log_event::write_data(IO_CACHE* file)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
{
char* log_name = rli->master_log_name;
char* log_name = rli->group_master_log_name;
DBUG_ENTER("Rotate_log_event::exec_event");
pthread_mutex_lock(&rli->data_lock);
memcpy(log_name, new_log_ident, ident_len+1);
rli->master_log_pos = pos;
rli->relay_log_pos += get_event_len();
DBUG_PRINT("info", ("master_log_pos: %d", (ulong) rli->master_log_pos));
rli->group_master_log_pos = pos;
rli->event_relay_log_pos += get_event_len();
rli->group_relay_log_pos = rli->event_relay_log_pos;
DBUG_PRINT("info", ("group_master_log_pos: %d", (ulong) rli->group_master_log_pos));
pthread_mutex_unlock(&rli->data_lock);
pthread_cond_broadcast(&rli->data_cond);
flush_relay_log_info(rli);
@ -1905,7 +1923,7 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
thd->next_insert_id = val;
break;
}
rli->inc_pending(get_event_len());
rli->inc_event_relay_log_pos(get_event_len());
return 0;
}
#endif
@ -1967,7 +1985,7 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli)
{
thd->rand.seed1= (ulong) seed1;
thd->rand.seed2= (ulong) seed2;
rli->inc_pending(get_event_len());
rli->inc_event_relay_log_pos(get_event_len());
return 0;
}
#endif // !MYSQL_CLIENT
@ -2199,7 +2217,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
e.update_hash(val, val_len, type, charset, Item::COER_NOCOLL);
free_root(&thd->mem_root,0);
rli->inc_pending(get_event_len());
rli->inc_event_relay_log_pos(get_event_len());
return 0;
}
#endif // !MYSQL_CLIENT
@ -2241,7 +2259,7 @@ Slave_log_event::Slave_log_event(THD* thd_arg,
pthread_mutex_lock(&mi->data_lock);
pthread_mutex_lock(&rli->data_lock);
master_host_len = strlen(mi->host);
master_log_len = strlen(rli->master_log_name);
master_log_len = strlen(rli->group_master_log_name);
// on OOM, just do not initialize the structure and print the error
if ((mem_pool = (char*)my_malloc(get_data_size() + 1,
MYF(MY_WME))))
@ -2249,9 +2267,9 @@ Slave_log_event::Slave_log_event(THD* thd_arg,
master_host = mem_pool + SL_MASTER_HOST_OFFSET ;
memcpy(master_host, mi->host, master_host_len + 1);
master_log = master_host + master_host_len + 1;
memcpy(master_log, rli->master_log_name, master_log_len + 1);
memcpy(master_log, rli->group_master_log_name, master_log_len + 1);
master_port = mi->port;
master_pos = rli->master_log_pos;
master_pos = rli->group_master_log_pos;
DBUG_PRINT("info", ("master_log: %s pos: %d", master_log,
(ulong) master_pos));
}
@ -2381,19 +2399,19 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
int Stop_log_event::exec_event(struct st_relay_log_info* rli)
{
// do not clean up immediately after rotate event
if (rli->master_log_pos > BIN_LOG_HEADER_SIZE)
if (rli->group_master_log_pos > BIN_LOG_HEADER_SIZE)
{
close_temporary_tables(thd);
cleanup_load_tmpdir();
}
/*
We do not want to update master_log pos because we get a rotate event
before stop, so by now master_log_name is set to the next log.
before stop, so by now group_master_log_name is set to the next log.
If we updated it, we will have incorrect master coordinates and this
could give false triggers in MASTER_POS_WAIT() that we have reached
the target position when in fact we have not.
*/
rli->inc_pos(get_event_len(), 0);
rli->inc_group_relay_log_pos(get_event_len(), 0);
flush_relay_log_info(rli);
return 0;
}

View file

@ -721,7 +721,7 @@ extern ulong max_binlog_size, rpl_recovery_rank, thread_cache_size;
extern ulong com_stat[(uint) SQLCOM_END], com_other, back_log;
extern ulong specialflag, current_pid;
extern ulong expire_logs_days;
extern my_bool relay_log_purge;
extern uint test_flags,select_errors,ha_open_options;
extern uint protocol_version,dropping_tables;
extern uint delay_key_write_options;

View file

@ -314,7 +314,7 @@ my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool lower_case_table_names, opt_old_rpl_compat;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
my_bool opt_log_slave_updates= 0, opt_old_passwords=0, use_old_passwords=0;
my_bool opt_console= 0;
my_bool opt_console= 0, opt_bdb, opt_innodb;
volatile bool mqh_used = 0;
FILE *bootstrap_file=0;
@ -442,6 +442,7 @@ const char **errmesg; /* Error messages */
const char *myisam_recover_options_str="OFF";
const char *sql_mode_str="OFF";
ulong rpl_recovery_rank=0;
my_bool relay_log_purge=1;
my_string mysql_unix_port=NULL, opt_mysql_tmpdir=NULL;
MY_TMPDIR mysql_tmpdir_list;
@ -2092,9 +2093,9 @@ static int init_common_variables(const char *conf_file_name, int argc,
#endif
if (!(default_charset_info= get_charset_by_name(sys_charset.value, MYF(MY_WME))))
return 1;
global_system_variables.result_collation= default_charset_info;
global_system_variables.client_collation= default_charset_info;
global_system_variables.literal_collation= default_charset_info;
global_system_variables.collation_results= default_charset_info;
global_system_variables.collation_client= default_charset_info;
global_system_variables.collation_connection= default_charset_info;
charsets_list= list_charsets(MYF(MY_CS_COMPILED | MY_CS_CONFIG));
@ -2208,7 +2209,7 @@ static int init_server_components()
{
long purge_time= time(0) - expire_logs_days*24*60*60;
if (purge_time >= 0)
mysql_bin_log.purge_logs_before_date(current_thd, purge_time);
mysql_bin_log.purge_logs_before_date(purge_time);
}
#endif
}
@ -3400,7 +3401,7 @@ enum options
OPT_DELAY_KEY_WRITE, OPT_CHARSETS_DIR,
OPT_BDB_HOME, OPT_BDB_LOG,
OPT_BDB_TMP, OPT_BDB_NOSYNC,
OPT_BDB_LOCK, OPT_BDB_SKIP,
OPT_BDB_LOCK, OPT_BDB,
OPT_BDB_NO_RECOVER, OPT_BDB_SHARED,
OPT_MASTER_HOST, OPT_MASTER_USER,
OPT_MASTER_PASSWORD, OPT_MASTER_PORT,
@ -3430,7 +3431,7 @@ enum options
OPT_INNODB_FLUSH_METHOD,
OPT_INNODB_FAST_SHUTDOWN,
OPT_SAFE_SHOW_DB,
OPT_INNODB_SKIP, OPT_SKIP_SAFEMALLOC,
OPT_INNODB, OPT_SKIP_SAFEMALLOC,
OPT_TEMP_POOL, OPT_TX_ISOLATION,
OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
@ -3457,7 +3458,7 @@ enum options
OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE,
OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS,
OPT_MAX_DELAYED_THREADS, OPT_MAX_HEP_TABLE_SIZE,
OPT_MAX_JOIN_SIZE, OPT_MAX_SORT_LENGTH,
OPT_MAX_JOIN_SIZE, OPT_MAX_LENGTH_FOR_SORT_DATA, OPT_MAX_SORT_LENGTH,
OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS,
OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE,
OPT_MAX_ERROR_COUNT, OPT_MAX_PREP_STMT,
@ -3468,7 +3469,7 @@ enum options
OPT_OPEN_FILES_LIMIT,
OPT_QUERY_CACHE_LIMIT, OPT_QUERY_CACHE_MIN_RES_UNIT, OPT_QUERY_CACHE_SIZE,
OPT_QUERY_CACHE_TYPE, OPT_RECORD_BUFFER,
OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT,
OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE,
OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME,
OPT_SORT_BUFFER, OPT_TABLE_CACHE,
OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE,
@ -3529,8 +3530,10 @@ struct my_option my_long_options[] =
(gptr*) &berkeley_tmpdir, (gptr*) &berkeley_tmpdir, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif /* HAVE_BERKELEY_DB */
{"skip-bdb", OPT_BDB_SKIP, "Don't use berkeley db (will save memory)",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"bdb", OPT_BDB, "Enable Berkeley DB (if this version of MySQL supports it). \
Disable with --skip-bdb (will save memory)",
(gptr*) &opt_bdb, (gptr*) &opt_bdb, 0, GET_BOOL, NO_ARG, 1, 0, 0,
0, 0, 0},
{"big-tables", OPT_BIG_TABLES,
"Allow big result sets by saving all temporary sets on file (Solves most 'table full' errors)",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@ -3885,8 +3888,10 @@ struct my_option my_long_options[] =
"Start without grant tables. This gives all users FULL ACCESS to all tables!",
(gptr*) &opt_noacl, (gptr*) &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
0},
{"skip-innodb", OPT_INNODB_SKIP, "Don't use Innodb (will save memory)",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"innodb", OPT_INNODB, "Enable InnoDB (if this version of MySQL supports it). \
Disable with --skip-innodb (will save memory)",
(gptr*) &opt_innodb, (gptr*) &opt_innodb, 0, GET_BOOL, NO_ARG, 1, 0, 0,
0, 0, 0},
{"skip-locking", OPT_SKIP_LOCK,
"Deprecated option, use --skip-external-locking instead",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@ -4159,6 +4164,11 @@ struct my_option my_long_options[] =
(gptr*) &global_system_variables.max_join_size,
(gptr*) &max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG,
~0L, 1, ~0L, 0, 1, 0},
{"max_length_for_sort_data", OPT_MAX_LENGTH_FOR_SORT_DATA,
"Max number of bytes in sorted records",
(gptr*) &global_system_variables.max_length_for_sort_data,
(gptr*) &max_system_variables.max_length_for_sort_data, 0, GET_ULONG,
REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0},
{"max_prepared_statements", OPT_MAX_PREP_STMT,
"Max number of prepared_statements for a thread",
(gptr*) &global_system_variables.max_prep_stmt_count,
@ -4272,6 +4282,11 @@ struct my_option my_long_options[] =
(gptr*) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE, 0},
#ifdef HAVE_REPLICATION
{"relay_log_purge", OPT_RELAY_LOG_PURGE,
"0 = do not purge relay logs. 1 = purge them as soon as they are no more needed.",
(gptr*) &relay_log_purge,
(gptr*) &relay_log_purge, 0, GET_BOOL, NO_ARG,
1, 0, 1, 0, 1, 0},
{"relay_log_space_limit", OPT_RELAY_LOG_SPACE_LIMIT,
"Max space to use for all relay logs",
(gptr*) &relay_log_space_limit,
@ -4575,9 +4590,9 @@ static void set_options(void)
sizeof(mysql_real_data_home)-1);
/* Set default values for some variables */
global_system_variables.result_collation= default_charset_info;
global_system_variables.client_collation= default_charset_info;
global_system_variables.literal_collation= default_charset_info;
global_system_variables.collation_results= default_charset_info;
global_system_variables.collation_client= default_charset_info;
global_system_variables.collation_connection= default_charset_info;
global_system_variables.table_type= DB_TYPE_MYISAM;
global_system_variables.tx_isolation= ISO_REPEATABLE_READ;
global_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
@ -5016,16 +5031,32 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
berkeley_shared_data=1;
break;
#endif /* HAVE_BERKELEY_DB */
case OPT_BDB_SKIP:
case OPT_BDB:
#ifdef HAVE_BERKELEY_DB
berkeley_skip=1;
have_berkeley_db=SHOW_OPTION_DISABLED;
if (opt_bdb)
{
berkeley_skip=0;
have_berkeley_db=SHOW_OPTION_YES;
}
else
{
berkeley_skip=1;
have_berkeley_db=SHOW_OPTION_DISABLED;
}
#endif
break;
case OPT_INNODB_SKIP:
case OPT_INNODB:
#ifdef HAVE_INNOBASE_DB
innodb_skip=1;
have_innodb=SHOW_OPTION_DISABLED;
if (opt_innodb)
{
innodb_skip=0;
have_innodb=SHOW_OPTION_YES;
}
else
{
innodb_skip=1;
have_innodb=SHOW_OPTION_DISABLED;
}
#endif
break;
case OPT_INNODB_DATA_FILE_PATH:

View file

@ -349,13 +349,13 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
select->head=head;
select->cond=conds;
if (head->io_cache)
if (head->sort.io_cache)
{
select->file= *head->io_cache;
select->file= *head->sort.io_cache;
select->records=(ha_rows) (select->file.end_of_file/
head->file->ref_length);
my_free((gptr) (head->io_cache),MYF(0));
head->io_cache=0;
my_free((gptr) (head->sort.io_cache),MYF(0));
head->sort.io_cache=0;
}
DBUG_RETURN(select);
}

View file

@ -724,7 +724,7 @@ bool Protocol_simple::store(const char *from, uint length,
bool Protocol_simple::store(const char *from, uint length,
CHARSET_INFO *fromcs)
{
CHARSET_INFO *tocs= this->thd->variables.result_collation;
CHARSET_INFO *tocs= this->thd->variables.collation_results;
#ifndef DEBUG_OFF
DBUG_ASSERT(field_types == 0 ||
field_types[field_pos] == MYSQL_TYPE_DECIMAL ||

View file

@ -1,3 +1,4 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
@ -22,6 +23,8 @@
static int rr_quick(READ_RECORD *info);
static int rr_sequential(READ_RECORD *info);
static int rr_from_tempfile(READ_RECORD *info);
static int rr_unpack_from_tempfile(READ_RECORD *info);
static int rr_unpack_from_buffer(READ_RECORD *info);
static int rr_from_pointers(READ_RECORD *info);
static int rr_from_cache(READ_RECORD *info);
static int init_rr_cache(READ_RECORD *info);
@ -41,8 +44,16 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
info->table=table;
info->file= table->file;
info->forms= &info->table; /* Only one table */
info->record=table->record[0];
info->ref_length=table->file->ref_length;
if (table->sort.addon_field)
{
info->rec_buf= table->sort.addon_buf;
info->ref_length= table->sort.addon_length;
}
else
{
info->record= table->record[0];
info->ref_length= table->file->ref_length;
}
info->select=select;
info->print_error=print_error;
info->ignore_not_found_rows= 0;
@ -51,11 +62,12 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
if (select && my_b_inited(&select->file))
tempfile= &select->file;
else
tempfile= table->io_cache;
tempfile= table->sort.io_cache;
if (tempfile && my_b_inited(tempfile)) // Test if ref-records was used
{
DBUG_PRINT("info",("using rr_from_tempfile"));
info->read_record=rr_from_tempfile;
info->read_record= (table->sort.addon_field ?
rr_unpack_from_tempfile : rr_from_tempfile);
info->io_cache=tempfile;
reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0);
info->ref_pos=table->file->ref;
@ -85,13 +97,15 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
DBUG_PRINT("info",("using rr_quick"));
info->read_record=rr_quick;
}
else if (table->record_pointers)
else if (table->sort.record_pointers)
{
DBUG_PRINT("info",("using record_pointers"));
table->file->rnd_init(0);
info->cache_pos=table->record_pointers;
info->cache_end=info->cache_pos+ table->found_records*info->ref_length;
info->read_record= rr_from_pointers;
info->cache_pos=table->sort.record_pointers;
info->cache_end=info->cache_pos+
table->sort.found_records*info->ref_length;
info->read_record= (table->sort.addon_field ?
rr_unpack_from_buffer : rr_from_pointers);
}
else
{
@ -112,7 +126,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
void end_read_record(READ_RECORD *info)
{ /* free cache if used */
{ /* free cache if used */
if (info->cache)
{
my_free_lock((char*) info->cache,MYF(0));
@ -120,6 +134,19 @@ void end_read_record(READ_RECORD *info)
}
if (info->table)
{
TABLE *table= info->table;
if (table->sort.record_pointers)
{
my_free((gptr) table->sort.record_pointers,MYF(0));
table->sort.record_pointers=0;
}
if (table->sort.addon_buf)
{
my_free((char *) table->sort.addon_buf, MYF(0));
my_free((char *) table->sort.addon_field, MYF(MY_ALLOW_ZERO_PTR));
table->sort.addon_buf=0;
table->sort.addon_field=0;
}
(void) info->file->extra(HA_EXTRA_NO_CACHE);
(void) info->file->rnd_end();
info->table=0;
@ -200,6 +227,34 @@ tryNext:
} /* rr_from_tempfile */
/*
Read a result set record from a temporary file after sorting
SYNOPSIS
rr_unpack_from_tempfile()
info Reference to the context including record descriptors
DESCRIPTION
The function first reads the next sorted record from the temporary file.
into a buffer. If a success it calls a callback function that unpacks
the fields values use in the result set from this buffer into their
positions in the regular record buffer.
RETURN
0 - Record successfully read.
-1 - There is no record to be read anymore.
*/
static int rr_unpack_from_tempfile(READ_RECORD *info)
{
if (my_b_read(info->io_cache, info->rec_buf, info->ref_length))
return -1;
TABLE *table= info->table;
(*table->sort.unpack)(table->sort.addon_field, info->rec_buf);
return 0;
}
static int rr_from_pointers(READ_RECORD *info)
{
int tmp;
@ -228,6 +283,34 @@ tryNext:
return tmp;
}
/*
Read a result set record from a buffer after sorting
SYNOPSIS
rr_unpack_from_buffer()
info Reference to the context including record descriptors
DESCRIPTION
The function first reads the next sorted record from the sort buffer.
If a success it calls a callback function that unpacks
the fields values use in the result set from this buffer into their
positions in the regular record buffer.
RETURN
0 - Record successfully read.
-1 - There is no record to be read anymore.
*/
static int rr_unpack_from_buffer(READ_RECORD *info)
{
if (info->cache_pos == info->cache_end)
return -1; /* End of buffer */
TABLE *table= info->table;
(*table->sort.unpack)(table->sort.addon_field, info->cache_pos);
info->cache_pos+= info->ref_length;
return 0;
}
/* cacheing of records from a database */
static int init_rr_cache(READ_RECORD *info)

View file

@ -873,7 +873,6 @@ int load_master_data(THD* thd)
// don't hit the magic number
if (active_mi->master_log_pos < BIN_LOG_HEADER_SIZE)
active_mi->master_log_pos = BIN_LOG_HEADER_SIZE;
active_mi->rli.pending = 0;
flush_master_info(active_mi);
}
mc_mysql_free_result(master_status_res);
@ -897,9 +896,13 @@ int load_master_data(THD* thd)
return 1;
}
pthread_mutex_lock(&active_mi->rli.data_lock);
active_mi->rli.master_log_pos = active_mi->master_log_pos;
strmake(active_mi->rli.master_log_name,active_mi->master_log_name,
sizeof(active_mi->rli.master_log_name)-1);
active_mi->rli.group_master_log_pos = active_mi->master_log_pos;
strmake(active_mi->rli.group_master_log_name,active_mi->master_log_name,
sizeof(active_mi->rli.group_master_log_name)-1);
/*
No need to update rli.event* coordinates, they will be when the slave
threads start ; only rli.group* coordinates are necessary here.
*/
flush_relay_log_info(&active_mi->rli);
pthread_cond_broadcast(&active_mi->rli.data_cond);
pthread_mutex_unlock(&active_mi->rli.data_lock);

View file

@ -105,7 +105,9 @@ sys_var_str sys_charset("character_set",
sys_check_charset,
sys_update_charset,
sys_set_default_charset);
sys_var_client_collation sys_client_collation("client_collation");
sys_var_collation_client sys_collation_client("collation_client");
sys_var_collation_connection sys_collation_connection("collation_connection");
sys_var_collation_results sys_collation_results("collation_results");
sys_var_bool_ptr sys_concurrent_insert("concurrent_insert",
&myisam_concurrent_insert);
sys_var_long_ptr sys_connect_timeout("connect_timeout",
@ -131,7 +133,6 @@ sys_var_thd_ulong sys_join_buffer_size("join_buffer_size",
sys_var_ulonglong_ptr sys_key_buffer_size("key_buffer_size",
&keybuff_size,
fix_key_buffer_size);
sys_var_literal_collation sys_literal_collation("literal_collation");
sys_var_bool_ptr sys_local_infile("local_infile",
&opt_local_infile);
sys_var_thd_bool sys_log_warnings("log_warnings", &SV::log_warnings);
@ -166,6 +167,8 @@ sys_var_thd_ulong sys_pseudo_thread_id("pseudo_thread_id",
sys_var_thd_ha_rows sys_max_join_size("max_join_size",
&SV::max_join_size,
fix_max_join_size);
sys_var_thd_ulong sys_max_length_for_sort_data("max_length_for_sort_data",
&SV::max_length_for_sort_data);
#ifndef TO_BE_DELETED /* Alias for max_join_size */
sys_var_thd_ha_rows sys_sql_max_join_size("sql_max_join_size",
&SV::max_join_size,
@ -200,7 +203,10 @@ sys_var_thd_ulong sys_read_buff_size("read_buffer_size",
&SV::read_buff_size);
sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size",
&SV::read_rnd_buff_size);
sys_var_result_collation sys_result_collation("result_collation");
#ifdef HAVE_REPLICATION
sys_var_bool_ptr sys_relay_log_purge("relay_log_purge",
&relay_log_purge);
#endif
sys_var_long_ptr sys_rpl_recovery_rank("rpl_recovery_rank",
&rpl_recovery_rank);
sys_var_long_ptr sys_query_cache_size("query_cache_size",
@ -343,7 +349,9 @@ sys_var *sys_variables[]=
&sys_binlog_cache_size,
&sys_buffer_results,
&sys_bulk_insert_buff_size,
&sys_client_collation,
&sys_collation_client,
&sys_collation_connection,
&sys_collation_results,
&sys_concurrent_insert,
&sys_connect_timeout,
&sys_default_week_format,
@ -362,7 +370,6 @@ sys_var *sys_variables[]=
&sys_interactive_timeout,
&sys_join_buffer_size,
&sys_key_buffer_size,
&sys_literal_collation,
&sys_last_insert_id,
&sys_local_infile,
&sys_log_binlog,
@ -380,6 +387,7 @@ sys_var *sys_variables[]=
&sys_max_error_count,
&sys_max_heap_table_size,
&sys_max_join_size,
&sys_max_length_for_sort_data,
&sys_max_prep_stmt_count,
&sys_max_sort_length,
&sys_max_tmp_tables,
@ -406,7 +414,9 @@ sys_var *sys_variables[]=
&sys_rand_seed2,
&sys_read_buff_size,
&sys_read_rnd_buff_size,
&sys_result_collation,
#ifdef HAVE_REPLICATION
&sys_relay_log_purge,
#endif
&sys_rpl_recovery_rank,
&sys_safe_updates,
&sys_select_limit,
@ -455,7 +465,9 @@ struct show_var_st init_vars[]= {
{sys_bulk_insert_buff_size.name,(char*) &sys_bulk_insert_buff_size,SHOW_SYS},
{sys_charset.name, (char*) &sys_charset, SHOW_SYS},
{"character_sets", (char*) &charsets_list, SHOW_CHAR_PTR},
{sys_client_collation.name, (char*) &sys_client_collation, SHOW_SYS},
{sys_collation_client.name, (char*) &sys_collation_client, SHOW_SYS},
{sys_collation_connection.name,(char*) &sys_collation_connection, SHOW_SYS},
{sys_collation_results.name, (char*) &sys_collation_results, SHOW_SYS},
{sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS},
{sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS},
{"datadir", mysql_real_data_home, SHOW_CHAR},
@ -508,7 +520,6 @@ struct show_var_st init_vars[]= {
{sys_key_buffer_size.name, (char*) &sys_key_buffer_size, SHOW_SYS},
{"language", language, SHOW_CHAR},
{"large_files_support", (char*) &opt_large_files, SHOW_BOOL},
{sys_literal_collation.name,(char*) &sys_literal_collation, SHOW_SYS},
{sys_local_infile.name, (char*) &sys_local_infile, SHOW_SYS},
#ifdef HAVE_MLOCKALL
{"locked_in_memory", (char*) &locked_in_memory, SHOW_BOOL},
@ -533,6 +544,9 @@ struct show_var_st init_vars[]= {
{sys_max_delayed_threads.name,(char*) &sys_max_delayed_threads, SHOW_SYS},
{sys_max_heap_table_size.name,(char*) &sys_max_heap_table_size, SHOW_SYS},
{sys_max_join_size.name, (char*) &sys_max_join_size, SHOW_SYS},
{sys_max_length_for_sort_data.name,
(char*) &sys_max_length_for_sort_data,
SHOW_SYS},
{sys_max_prep_stmt_count.name,(char*) &sys_max_prep_stmt_count, SHOW_SYS},
{sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS},
{sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS},
@ -562,7 +576,9 @@ struct show_var_st init_vars[]= {
{sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS},
{sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS},
{sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS},
{sys_result_collation.name, (char*) &sys_result_collation, SHOW_SYS},
#ifdef HAVE_REPLICATION
{sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS},
#endif
{sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS},
#ifdef HAVE_QUERY_CACHE
{sys_query_cache_limit.name,(char*) &sys_query_cache_limit, SHOW_SYS},
@ -1210,86 +1226,80 @@ bool sys_var_collation::check(THD *thd, set_var *var)
return 0;
}
bool sys_var_client_collation::update(THD *thd, set_var *var)
bool sys_var_collation_client::update(THD *thd, set_var *var)
{
if (var->type == OPT_GLOBAL)
global_system_variables.client_collation= var->save_result.charset;
global_system_variables.collation_client= var->save_result.charset;
else
{
thd->variables.client_collation= var->save_result.charset;
thd->protocol_simple.init(thd);
thd->protocol_prep.init(thd);
}
thd->variables.collation_client= var->save_result.charset;
return 0;
}
byte *sys_var_client_collation::value_ptr(THD *thd, enum_var_type type)
byte *sys_var_collation_client::value_ptr(THD *thd, enum_var_type type)
{
CHARSET_INFO *cs= ((type == OPT_GLOBAL) ?
global_system_variables.client_collation :
thd->variables.client_collation);
global_system_variables.collation_client :
thd->variables.collation_client);
return cs ? (byte*) cs->name : (byte*) "";
}
void sys_var_client_collation::set_default(THD *thd, enum_var_type type)
void sys_var_collation_client::set_default(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
global_system_variables.client_collation= default_charset_info;
global_system_variables.collation_client= default_charset_info;
else
{
thd->variables.client_collation= global_system_variables.client_collation;
}
thd->variables.collation_client= global_system_variables.collation_client;
}
bool sys_var_literal_collation::update(THD *thd, set_var *var)
bool sys_var_collation_connection::update(THD *thd, set_var *var)
{
if (var->type == OPT_GLOBAL)
global_system_variables.literal_collation= var->save_result.charset;
global_system_variables.collation_connection= var->save_result.charset;
else
thd->variables.literal_collation= var->save_result.charset;
thd->variables.collation_connection= var->save_result.charset;
return 0;
}
byte *sys_var_literal_collation::value_ptr(THD *thd, enum_var_type type)
byte *sys_var_collation_connection::value_ptr(THD *thd, enum_var_type type)
{
CHARSET_INFO *cs= ((type == OPT_GLOBAL) ?
global_system_variables.literal_collation :
thd->variables.literal_collation);
global_system_variables.collation_connection :
thd->variables.collation_connection);
return cs ? (byte*) cs->name : (byte*) "";
}
void sys_var_literal_collation::set_default(THD *thd, enum_var_type type)
void sys_var_collation_connection::set_default(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
global_system_variables.literal_collation= default_charset_info;
global_system_variables.collation_connection= default_charset_info;
else
thd->variables.literal_collation= global_system_variables.literal_collation;
thd->variables.collation_connection= global_system_variables.collation_connection;
}
bool sys_var_result_collation::update(THD *thd, set_var *var)
bool sys_var_collation_results::update(THD *thd, set_var *var)
{
if (var->type == OPT_GLOBAL)
global_system_variables.result_collation= var->save_result.charset;
global_system_variables.collation_results= var->save_result.charset;
else
thd->variables.result_collation= var->save_result.charset;
thd->variables.collation_results= var->save_result.charset;
return 0;
}
byte *sys_var_result_collation::value_ptr(THD *thd, enum_var_type type)
byte *sys_var_collation_results::value_ptr(THD *thd, enum_var_type type)
{
CHARSET_INFO *cs= ((type == OPT_GLOBAL) ?
global_system_variables.result_collation :
thd->variables.result_collation);
global_system_variables.collation_results :
thd->variables.collation_results);
return cs ? (byte*) cs->name : (byte*) "";
}
void sys_var_result_collation::set_default(THD *thd, enum_var_type type)
void sys_var_collation_results::set_default(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
global_system_variables.result_collation= default_charset_info;
global_system_variables.collation_results= default_charset_info;
else
thd->variables.result_collation= global_system_variables.result_collation;
thd->variables.collation_results= global_system_variables.collation_results;
}
@ -1297,16 +1307,16 @@ void sys_var_result_collation::set_default(THD *thd, enum_var_type type)
Functions to handle SET NAMES and SET CHARACTER SET
*****************************************************************************/
int set_var_client_collation::check(THD *thd)
int set_var_collation_client::check(THD *thd)
{
return 0;
}
int set_var_client_collation::update(THD *thd)
int set_var_collation_client::update(THD *thd)
{
thd->variables.client_collation= client_collation;
thd->variables.literal_collation= literal_collation;
thd->variables.result_collation= result_collation;
thd->variables.collation_client= collation_client;
thd->variables.collation_connection= collation_connection;
thd->variables.collation_results= collation_results;
thd->protocol_simple.init(thd);
thd->protocol_prep.init(thd);
return 0;

View file

@ -420,28 +420,28 @@ SHOW_TYPE type() { return SHOW_CHAR; }
virtual void set_default(THD *thd, enum_var_type type)= 0;
};
class sys_var_client_collation :public sys_var_collation
class sys_var_collation_client :public sys_var_collation
{
public:
sys_var_client_collation(const char *name_arg) :sys_var_collation(name_arg) {}
sys_var_collation_client(const char *name_arg) :sys_var_collation(name_arg) {}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
byte *value_ptr(THD *thd, enum_var_type type);
};
class sys_var_literal_collation :public sys_var_collation
class sys_var_collation_connection :public sys_var_collation
{
public:
sys_var_literal_collation(const char *name_arg) :sys_var_collation(name_arg) {}
sys_var_collation_connection(const char *name_arg) :sys_var_collation(name_arg) {}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
byte *value_ptr(THD *thd, enum_var_type type);
};
class sys_var_result_collation :public sys_var_collation
class sys_var_collation_results :public sys_var_collation
{
public:
sys_var_result_collation(const char *name_arg) :sys_var_collation(name_arg) {}
sys_var_collation_results(const char *name_arg) :sys_var_collation(name_arg) {}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
byte *value_ptr(THD *thd, enum_var_type type);
@ -553,18 +553,18 @@ public:
/* For SET NAMES and SET CHARACTER SET */
class set_var_client_collation: public set_var_base
class set_var_collation_client: public set_var_base
{
CHARSET_INFO *client_collation;
CHARSET_INFO *literal_collation;
CHARSET_INFO *result_collation;
CHARSET_INFO *collation_client;
CHARSET_INFO *collation_connection;
CHARSET_INFO *collation_results;
public:
set_var_client_collation(CHARSET_INFO *client_coll_arg,
CHARSET_INFO *literal_coll_arg,
set_var_collation_client(CHARSET_INFO *client_coll_arg,
CHARSET_INFO *connection_coll_arg,
CHARSET_INFO *result_coll_arg)
:client_collation(client_coll_arg),
literal_collation(literal_coll_arg),
result_collation(result_coll_arg)
:collation_client(client_coll_arg),
collation_connection(connection_coll_arg),
collation_results(result_coll_arg)
{}
int check(THD *thd);
int update(THD *thd);

View file

@ -217,11 +217,7 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
- If not, open the 'log' binary file.
TODO
- check proper initialization of master_log_name/master_log_pos
- We may always want to delete all logs before 'log'.
Currently if we are not calling this with 'log' as NULL or the first
log we will never delete relay logs.
If we want this we should not set skip_log_purge to 1.
- check proper initialization of group_master_log_name/group_master_log_pos
RETURN VALUES
0 ok
@ -248,7 +244,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
rli->cur_log_fd = -1;
}
rli->relay_log_pos = pos;
rli->group_relay_log_pos = rli->event_relay_log_pos = pos;
/*
Test to see if the previous run was with the skip of purging
@ -260,18 +256,15 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
goto err;
}
if (log) // If not first log
if (log && rli->relay_log.find_log_pos(&rli->linfo, log, 1))
{
if (strcmp(log, rli->linfo.log_file_name))
rli->skip_log_purge= 1; // Different name; Don't purge
if (rli->relay_log.find_log_pos(&rli->linfo, log, 1))
{
*errmsg="Could not find target log during relay log initialization";
goto err;
}
*errmsg="Could not find target log during relay log initialization";
goto err;
}
strmake(rli->relay_log_name,rli->linfo.log_file_name,
sizeof(rli->relay_log_name)-1);
strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
sizeof(rli->group_relay_log_name)-1);
strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
sizeof(rli->event_relay_log_name)-1);
if (rli->relay_log.is_active(rli->linfo.log_file_name))
{
/*
@ -302,7 +295,7 @@ err:
If we don't purge, we can't honour relay_log_space_limit ;
silently discard it
*/
if (rli->skip_log_purge)
if (!relay_log_purge)
rli->log_space_limit= 0;
pthread_cond_broadcast(&rli->data_cond);
if (need_data_lock)
@ -383,9 +376,8 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
to display fine in any case.
*/
rli->master_log_name[0]= 0;
rli->master_log_pos= 0;
rli->pending= 0;
rli->group_master_log_name[0]= 0;
rli->group_master_log_pos= 0;
if (!rli->inited)
DBUG_RETURN(0);
@ -402,16 +394,18 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
goto err;
}
/* Save name of used relay log file */
strmake(rli->relay_log_name, rli->relay_log.get_log_fname(),
sizeof(rli->relay_log_name)-1);
strmake(rli->group_relay_log_name, rli->relay_log.get_log_fname(),
sizeof(rli->group_relay_log_name)-1);
strmake(rli->event_relay_log_name, rli->relay_log.get_log_fname(),
sizeof(rli->event_relay_log_name)-1);
// Just first log with magic number and nothing else
rli->log_space_total= BIN_LOG_HEADER_SIZE;
rli->relay_log_pos= BIN_LOG_HEADER_SIZE;
rli->group_relay_log_pos= rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
rli->relay_log.reset_bytes_written();
if (!just_reset)
error= init_relay_log_pos(rli, rli->relay_log_name, rli->relay_log_pos,
0 /* do not need data lock */, errmsg);
error= init_relay_log_pos(rli, rli->group_relay_log_name, rli->group_relay_log_pos,
0 /* do not need data lock */, errmsg);
err:
#ifndef DBUG_OFF
char buf[22];
@ -1238,13 +1232,11 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
fn_format(fname, info_fname, mysql_data_home, "", 4+32);
pthread_mutex_lock(&rli->data_lock);
info_fd = rli->info_fd;
rli->pending = 0;
rli->cur_log_fd = -1;
rli->slave_skip_counter=0;
rli->abort_pos_wait=0;
rli->skip_log_purge=0;
rli->log_space_limit = relay_log_space_limit;
rli->log_space_total = 0;
rli->log_space_limit= relay_log_space_limit;
rli->log_space_total= 0;
// TODO: make this work with multi-master
if (!opt_relay_logname)
@ -1285,8 +1277,8 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */,
&msg))
goto err;
rli->master_log_name[0]= 0;
rli->master_log_pos= 0;
rli->group_master_log_name[0]= 0;
rli->group_master_log_pos= 0;
rli->info_fd= info_fd;
}
else // file exists
@ -1307,31 +1299,33 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
rli->info_fd = info_fd;
int relay_log_pos, master_log_pos;
if (init_strvar_from_file(rli->relay_log_name,
sizeof(rli->relay_log_name), &rli->info_file,
if (init_strvar_from_file(rli->group_relay_log_name,
sizeof(rli->group_relay_log_name), &rli->info_file,
"") ||
init_intvar_from_file(&relay_log_pos,
&rli->info_file, BIN_LOG_HEADER_SIZE) ||
init_strvar_from_file(rli->master_log_name,
sizeof(rli->master_log_name), &rli->info_file,
init_strvar_from_file(rli->group_master_log_name,
sizeof(rli->group_master_log_name), &rli->info_file,
"") ||
init_intvar_from_file(&master_log_pos, &rli->info_file, 0))
{
msg="Error reading slave log configuration";
goto err;
}
rli->relay_log_pos= relay_log_pos;
rli->master_log_pos= master_log_pos;
strmake(rli->event_relay_log_name,rli->group_relay_log_name,
sizeof(rli->event_relay_log_name)-1);
rli->group_relay_log_pos= rli->event_relay_log_pos= relay_log_pos;
rli->group_master_log_pos= master_log_pos;
if (init_relay_log_pos(rli,
rli->relay_log_name,
rli->relay_log_pos,
rli->group_relay_log_name,
rli->group_relay_log_pos,
0 /* no data lock*/,
&msg))
goto err;
}
DBUG_ASSERT(rli->relay_log_pos >= BIN_LOG_HEADER_SIZE);
DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->relay_log_pos);
DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
/*
Now change the cache from READ to WRITE - must do this
before flush_relay_log_info
@ -1407,7 +1401,7 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli)
{
LOG_INFO linfo;
DBUG_ENTER("count_relay_log_space");
rli->log_space_total = 0;
rli->log_space_total= 0;
if (rli->relay_log.find_log_pos(&linfo, NullS, 1))
{
sql_print_error("Could not find first log while counting relay log space");
@ -1631,10 +1625,10 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
protocol->store((uint32) mi->connect_retry);
protocol->store(mi->master_log_name, &my_charset_bin);
protocol->store((ulonglong) mi->master_log_pos);
protocol->store(mi->rli.relay_log_name +
dirname_length(mi->rli.relay_log_name), &my_charset_bin);
protocol->store((ulonglong) mi->rli.relay_log_pos);
protocol->store(mi->rli.master_log_name, &my_charset_bin);
protocol->store(mi->rli.group_relay_log_name +
dirname_length(mi->rli.group_relay_log_name), &my_charset_bin);
protocol->store((ulonglong) mi->rli.group_relay_log_pos);
protocol->store(mi->rli.group_master_log_name, &my_charset_bin);
protocol->store(mi->slave_running ? "Yes":"No", &my_charset_bin);
protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin);
protocol->store(&replicate_do_db);
@ -1642,7 +1636,7 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
protocol->store((uint32) mi->rli.last_slave_errno);
protocol->store(mi->rli.last_slave_error, &my_charset_bin);
protocol->store((uint32) mi->rli.slave_skip_counter);
protocol->store((ulonglong) mi->rli.master_log_pos);
protocol->store((ulonglong) mi->rli.group_master_log_pos);
protocol->store((ulonglong) mi->rli.log_space_total);
pthread_mutex_unlock(&mi->rli.data_lock);
pthread_mutex_unlock(&mi->data_lock);
@ -1673,17 +1667,15 @@ bool flush_master_info(MASTER_INFO* mi)
st_relay_log_info::st_relay_log_info()
:info_fd(-1), cur_log_fd(-1), master_log_pos(0), save_temporary_tables(0),
cur_log_old_open_count(0), log_space_total(0), ignore_log_space_limit(0),
slave_skip_counter(0), abort_pos_wait(0), slave_run_id(0),
sql_thd(0), last_slave_errno(0), inited(0), abort_slave(0),
slave_running(0), skip_log_purge(0),
inside_transaction(0) /* the default is autocommit=1 */
:info_fd(-1), cur_log_fd(-1), save_temporary_tables(0),
cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0),
ignore_log_space_limit(0), slave_skip_counter(0), abort_pos_wait(0),
slave_run_id(0), sql_thd(0), last_slave_errno(0), inited(0), abort_slave(0),
slave_running(0)
{
relay_log_name[0] = master_log_name[0] = 0;
group_relay_log_name[0]= event_relay_log_name[0]= group_master_log_name[0]= 0;
last_slave_error[0]=0;
bzero(&info_file,sizeof(info_file));
bzero(&cache_buf, sizeof(cache_buf));
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
@ -1745,8 +1737,8 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
set_timespec(abstime,timeout);
DBUG_ENTER("wait_for_pos");
DBUG_PRINT("enter",("master_log_name: '%s' pos: %lu timeout: %ld",
master_log_name, (ulong) master_log_pos,
DBUG_PRINT("enter",("group_master_log_name: '%s' pos: %lu timeout: %ld",
group_master_log_name, (ulong) group_master_log_pos,
(long) timeout));
pthread_mutex_lock(&data_lock);
@ -1796,10 +1788,10 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
{
bool pos_reached;
int cmp_result= 0;
DBUG_ASSERT(*master_log_name || master_log_pos == 0);
if (*master_log_name)
DBUG_ASSERT(*group_master_log_name || group_master_log_pos == 0);
if (*group_master_log_name)
{
char *basename= master_log_name + dirname_length(master_log_name);
char *basename= group_master_log_name + dirname_length(group_master_log_name);
/*
First compare the parts before the extension.
Find the dot in the master's log basename,
@ -1814,13 +1806,13 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
}
// Now compare extensions.
char *q_end;
ulong master_log_name_extension= strtoul(q, &q_end, 10);
if (master_log_name_extension < log_name_extension)
ulong group_master_log_name_extension= strtoul(q, &q_end, 10);
if (group_master_log_name_extension < log_name_extension)
cmp_result = -1 ;
else
cmp_result= (master_log_name_extension > log_name_extension) ? 1 : 0 ;
cmp_result= (group_master_log_name_extension > log_name_extension) ? 1 : 0 ;
}
pos_reached = ((!cmp_result && master_log_pos >= (ulonglong)log_pos) ||
pos_reached = ((!cmp_result && group_master_log_pos >= (ulonglong)log_pos) ||
cmp_result > 0);
if (pos_reached || thd->killed)
break;
@ -2127,7 +2119,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
(rli->slave_skip_counter && type_code != ROTATE_EVENT))
{
/* TODO: I/O thread should not even log events with the same server id */
rli->inc_pos(ev->get_event_len(),
rli->inc_group_relay_log_pos(ev->get_event_len(),
type_code != STOP_EVENT ? ev->log_pos : LL(0),
1/* skip lock*/);
flush_relay_log_info(rli);
@ -2497,15 +2489,13 @@ slave_begin:
rli->abort_slave = 0;
pthread_mutex_unlock(&rli->run_lock);
pthread_cond_broadcast(&rli->start_cond);
// This should always be set to 0 when the slave thread is started
rli->pending = 0;
//tell the I/O thread to take relay_log_space_limit into account from now on
rli->ignore_log_space_limit= 0;
if (init_relay_log_pos(rli,
rli->relay_log_name,
rli->relay_log_pos,
rli->group_relay_log_name,
rli->group_relay_log_pos,
1 /*need data lock*/, &errmsg))
{
sql_print_error("Error initializing relay log position: %s",
@ -2513,18 +2503,18 @@ slave_begin:
goto err;
}
THD_CHECK_SENTRY(thd);
DBUG_ASSERT(rli->relay_log_pos >= BIN_LOG_HEADER_SIZE);
DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->relay_log_pos);
DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
DBUG_ASSERT(rli->sql_thd == thd);
DBUG_PRINT("master_info",("log_file_name: %s position: %s",
rli->master_log_name,
llstr(rli->master_log_pos,llbuff)));
rli->group_master_log_name,
llstr(rli->group_master_log_pos,llbuff)));
if (global_system_variables.log_warnings)
sql_print_error("Slave SQL thread initialized, starting replication in \
log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
llstr(rli->master_log_pos,llbuff),rli->relay_log_name,
llstr(rli->relay_log_pos,llbuff1));
llstr(rli->group_master_log_pos,llbuff),rli->group_relay_log_name,
llstr(rli->group_relay_log_pos,llbuff1));
/* Read queries from the IO/THREAD until this thread is killed */
@ -2541,7 +2531,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
Error running query, slave SQL thread aborted. Fix the problem, and restart \
the slave SQL thread with \"SLAVE START\". We stopped at log \
'%s' position %s",
RPL_LOG_NAME, llstr(rli->master_log_pos, llbuff));
RPL_LOG_NAME, llstr(rli->group_master_log_pos, llbuff));
goto err;
}
}
@ -2549,7 +2539,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
/* Thread stopped. Print the current replication position to the log */
sql_print_error("Slave SQL thread exiting, replication stopped in log \
'%s' at position %s",
RPL_LOG_NAME, llstr(rli->master_log_pos,llbuff));
RPL_LOG_NAME, llstr(rli->group_master_log_pos,llbuff));
err:
VOID(pthread_mutex_lock(&LOCK_thread_count));
@ -2699,7 +2689,7 @@ err:
rev The rotate log event read from the binary log
DESCRIPTION
Updates the master info and relay data with the place in the next binary
Updates the master info with the place in the next binary
log where we should start reading.
NOTES
@ -3073,18 +3063,14 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli)
IO_CACHE *file = &rli->info_file;
char buff[FN_REFLEN*2+22*2+4], *pos;
/* sql_thd is not set when calling from init_slave() */
if ((rli->sql_thd && rli->sql_thd->options & OPTION_BEGIN))
return 0; // Wait for COMMIT
my_b_seek(file, 0L);
pos=strmov(buff, rli->relay_log_name);
pos=strmov(buff, rli->group_relay_log_name);
*pos++='\n';
pos=longlong2str(rli->relay_log_pos, pos, 10);
pos=longlong2str(rli->group_relay_log_pos, pos, 10);
*pos++='\n';
pos=strmov(pos, rli->master_log_name);
pos=strmov(pos, rli->group_master_log_name);
*pos++='\n';
pos=longlong2str(rli->master_log_pos, pos, 10);
pos=longlong2str(rli->group_master_log_pos, pos, 10);
*pos='\n';
if (my_b_write(file, (byte*) buff, (ulong) (pos-buff)+1))
error=1;
@ -3107,7 +3093,7 @@ static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg)
DBUG_ENTER("reopen_relay_log");
IO_CACHE *cur_log = rli->cur_log=&rli->cache_buf;
if ((rli->cur_log_fd=open_binlog(cur_log,rli->relay_log_name,
if ((rli->cur_log_fd=open_binlog(cur_log,rli->event_relay_log_name,
errmsg)) <0)
DBUG_RETURN(0);
/*
@ -3115,7 +3101,7 @@ static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg)
relay_log_pos Current log pos
pending Number of bytes already processed from the event
*/
my_b_seek(cur_log,rli->relay_log_pos + rli->pending);
my_b_seek(cur_log,rli->event_relay_log_pos);
DBUG_RETURN(cur_log);
}
@ -3124,7 +3110,7 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
{
Log_event* ev;
IO_CACHE* cur_log = rli->cur_log;
pthread_mutex_t *log_lock = rli->relay_log.get_log_lock();
pthread_mutex_t *log_lock = rli->relay_log.get_log_lock();
const char* errmsg=0;
THD* thd = rli->sql_thd;
DBUG_ENTER("next_event");
@ -3173,7 +3159,7 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
}
}
DBUG_ASSERT(my_b_tell(cur_log) >= BIN_LOG_HEADER_SIZE);
DBUG_ASSERT(my_b_tell(cur_log) == rli->relay_log_pos + rli->pending);
DBUG_ASSERT(my_b_tell(cur_log) == rli->event_relay_log_pos);
/*
Relay log is always in new format - if the master is 3.23, the
I/O thread will convert the format for us
@ -3240,8 +3226,8 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
// prevent the I/O thread from blocking next times
rli->ignore_log_space_limit= 1;
// If the I/O thread is blocked, unblock it
pthread_cond_broadcast(&rli->log_space_cond);
pthread_mutex_unlock(&rli->log_space_lock);
pthread_cond_broadcast(&rli->log_space_cond);
// Note that wait_for_update unlocks lock_log !
rli->relay_log.wait_for_update(rli->sql_thd);
// re-acquire data lock since we released it earlier
@ -3258,16 +3244,25 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
my_close(rli->cur_log_fd, MYF(MY_WME));
rli->cur_log_fd = -1;
/*
TODO: make skip_log_purge a start-up option. At this point this
is not critical priority
*/
if (!rli->skip_log_purge)
if (relay_log_purge)
{
// purge_first_log will properly set up relay log coordinates in rli
if (rli->relay_log.purge_first_log(rli))
/*
purge_first_log will properly set up relay log coordinates in rli.
If the group's coordinates are equal to the event's coordinates
(i.e. the relay log was not rotated in the middle of a group),
we can purge this relay log too.
We do ulonglong and string comparisons, this may be slow but
- purging the last relay log is nice (it can save 1GB of disk), so we
like to detect the case where we can do it, and given this,
- I see no better detection method
- purge_first_log is not called that often
*/
if (rli->relay_log.purge_first_log
(rli,
rli->group_relay_log_pos == rli->event_relay_log_pos
&& !strcmp(rli->group_relay_log_name,rli->event_relay_log_name)))
{
errmsg = "Error purging processed log";
errmsg = "Error purging processed logs";
goto err;
}
}
@ -3285,10 +3280,9 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
errmsg = "error switching to the next log";
goto err;
}
rli->relay_log_pos = BIN_LOG_HEADER_SIZE;
rli->pending=0;
strmake(rli->relay_log_name,rli->linfo.log_file_name,
sizeof(rli->relay_log_name)-1);
rli->event_relay_log_pos = BIN_LOG_HEADER_SIZE;
strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
sizeof(rli->event_relay_log_name)-1);
flush_relay_log_info(rli);
}
@ -3336,7 +3330,7 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
event(errno: %d cur_log->error: %d)",
my_errno,cur_log->error);
// set read position to the beginning of the event
my_b_seek(cur_log,rli->relay_log_pos+rli->pending);
my_b_seek(cur_log,rli->event_relay_log_pos);
/* otherwise, we have had a partial read */
errmsg = "Aborting slave SQL thread because of partial event read";
break; // To end of function

View file

@ -92,12 +92,6 @@ typedef struct st_relay_log_info
cur_log_fd - file descriptor of the current read relay log
*/
File info_fd,cur_log_fd;
/* name of current read relay log */
char relay_log_name[FN_REFLEN];
/* master log name corresponding to current read position */
char master_log_name[FN_REFLEN];
/* original log position of last processed event */
volatile my_off_t master_log_pos;
/*
Protected with internal locks.
@ -142,20 +136,36 @@ typedef struct st_relay_log_info
uint32 cur_log_old_open_count;
/*
relay_log_pos - Current offset in the relay log.
pending - In some cases we do not increment offset immediately
after processing an event, because the following event
needs to be processed atomically together with this one
such as:
Intvar_event - sets auto_increment value
Rand_event - sets the random seed
However, once both events have been processed, we need to
increment by the cumulative offset. 'pending' stores the
extra offset to be added to the position.
Let's call a group (of events) :
- a transaction
or
- an autocommiting query + its associated events (INSERT_ID,
TIMESTAMP...)
We need these rli coordinates :
- relay log name and position of the beginning of the group we currently are
executing. Needed to know where we have to restart when replication has
stopped in the middle of a group (which has been rolled back by the slave).
- relay log name and position just after the event we have just
executed. This event is part of the current group.
Formerly we only had the immediately above coordinates, plus a 'pending'
variable, but this dealt wrong with the case of a transaction starting on a
relay log and finishing (commiting) on another relay log. Case which can
happen when, for example, the relay log gets rotated because of
max_binlog_size.
*/
ulonglong relay_log_pos, pending;
char group_relay_log_name[FN_REFLEN];
ulonglong group_relay_log_pos;
char event_relay_log_name[FN_REFLEN];
ulonglong event_relay_log_pos;
/*
Original log name and position of the group we're currently executing
(whose coordinates are group_relay_log_name/pos in the relay log)
in the master's binlog. These concern the *group*, because in the master's
binlog the log_pos that comes with each event is the position of the
beginning of the group.
*/
char group_master_log_name[FN_REFLEN];
volatile my_off_t group_master_log_pos;
/*
Handling of the relay_log_space_limit optional constraint.
@ -193,38 +203,39 @@ typedef struct st_relay_log_info
/* if not set, the value of other members of the structure are undefined */
bool inited;
volatile bool abort_slave, slave_running;
bool skip_log_purge;
bool inside_transaction;
st_relay_log_info();
~st_relay_log_info();
inline void inc_pending(ulonglong val)
inline void inc_event_relay_log_pos(ulonglong val)
{
pending += val;
event_relay_log_pos+= val;
}
/* TODO: this probably needs to be fixed */
inline void inc_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0)
void inc_group_relay_log_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0)
{
if (!skip_lock)
pthread_mutex_lock(&data_lock);
relay_log_pos += val+pending;
pending = 0;
if (log_pos)
master_log_pos = log_pos+ val;
inc_event_relay_log_pos(val);
group_relay_log_pos= event_relay_log_pos;
strmake(group_relay_log_name,event_relay_log_name,
sizeof(group_relay_log_name)-1);
/*
If the slave does not support transactions and replicates a transaction,
users should not trust group_master_log_pos (which they can display with
SHOW SLAVE STATUS or read from relay-log.info), because to compute
group_master_log_pos the slave relies on log_pos stored in the master's
binlog, but if we are in a master's transaction these positions are always
the BEGIN's one (excepted for the COMMIT), so group_master_log_pos does
not advance as it should on the non-transactional slave (it advances by
big leaps, whereas it should advance by small leaps).
*/
if (log_pos) // 3.23 binlogs don't have log_posx
group_master_log_pos= log_pos+ val;
pthread_cond_broadcast(&data_cond);
if (!skip_lock)
pthread_mutex_unlock(&data_lock);
}
/*
thread safe read of position - not needed if we are in the slave thread,
but required otherwise as var is a longlong
*/
inline void read_pos(ulonglong& var)
{
pthread_mutex_lock(&data_lock);
var = relay_log_pos;
pthread_mutex_unlock(&data_lock);
}
int wait_for_pos(THD* thd, String* log_name, longlong log_pos,
longlong timeout);
@ -334,7 +345,7 @@ typedef struct st_table_rule_ent
#define TABLE_RULE_ARR_SIZE 16
#define MAX_SLAVE_ERRMSG 1024
#define RPL_LOG_NAME (rli->master_log_name[0] ? rli->master_log_name :\
#define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\
"FIRST")
#define IO_RPL_LOG_NAME (mi->master_log_name[0] ? mi->master_log_name :\
"FIRST")

View file

@ -49,7 +49,7 @@ extern "C" byte *table_cache_key(const byte *record,uint *length,
void table_cache_init(void)
{
VOID(hash_init(&open_cache,system_charset_info,
VOID(hash_init(&open_cache,&my_charset_bin,
table_cache_size+16,0,0,table_cache_key,
(hash_free_key) free_cache_entry,0));
mysql_rm_tmp_tables();
@ -245,16 +245,11 @@ static void free_cache_entry(TABLE *table)
void free_io_cache(TABLE *table)
{
DBUG_ENTER("free_io_cache");
if (table->io_cache)
if (table->sort.io_cache)
{
close_cached_file(table->io_cache);
my_free((gptr) table->io_cache,MYF(0));
table->io_cache=0;
}
if (table->record_pointers)
{
my_free((gptr) table->record_pointers,MYF(0));
table->record_pointers=0;
close_cached_file(table->sort.io_cache);
my_free((gptr) table->sort.io_cache,MYF(0));
table->sort.io_cache=0;
}
DBUG_VOID_RETURN;
}

View file

@ -758,9 +758,11 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
DBUG_ENTER("Query_cache::store_query");
if (query_cache_size == 0)
DBUG_VOID_RETURN;
uint8 tables_type= 0;
if ((local_tables = is_cacheable(thd, thd->query_length,
thd->query, &thd->lex, tables_used)))
thd->query, &thd->lex, tables_used,
&tables_type)))
{
NET *net= &thd->net;
byte flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0);
@ -836,6 +838,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
net->query_cache_query= (gptr) query_block;
header->writer(net);
header->tables_type(tables_type);
// init_n_lock make query block locked
BLOCK_UNLOCK_WR(query_block);
}
@ -882,15 +885,10 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
Query_cache_block_table *block_table, *block_table_end;
ulong tot_length;
byte flags;
bool check_tables;
DBUG_ENTER("Query_cache::send_result_to_client");
if (query_cache_size == 0 ||
/*
it is not possible to check has_transactions() function of handler
because tables not opened yet
*/
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) ||
thd->variables.query_cache_type == 0)
if (query_cache_size == 0 || thd->variables.query_cache_type == 0)
goto err;
@ -970,6 +968,16 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
}
DBUG_PRINT("qcache", ("Query have result 0x%lx", (ulong) query));
if ((thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
(query->tables_type() & HA_CACHE_TBL_TRANSACT))
{
DBUG_PRINT("qcache",
("we are in transaction and have transaction tables in query"));
BLOCK_UNLOCK_RD(query_block);
goto err_unlock;
}
check_tables= query->tables_type() & HA_CACHE_TBL_ASKTRANSACT;
// Check access;
block_table= query_block->table(0);
block_table_end= block_table+query_block->n_tables;
@ -997,9 +1005,22 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
DBUG_PRINT("qcache", ("Need to check column privileges for %s.%s",
table_list.db, table_list.alias));
BLOCK_UNLOCK_RD(query_block);
thd->lex.safe_to_cache_query=0; // Don't try to cache this
thd->lex.safe_to_cache_query= 0; // Don't try to cache this
goto err_unlock; // Parse query
}
if (check_tables && !handler::caching_allowed(thd, table->db(),
table->key_length(),
table->type()))
{
DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
table_list.db, table_list.alias));
BLOCK_UNLOCK_RD(query_block);
thd->lex.safe_to_cache_query= 0; // Don't try to cache this
goto err_unlock; // Parse query
}
else
DBUG_PRINT("qcache", ("handler allow caching (%d) %s,%s",
check_tables, table_list.db, table_list.alias));
}
move_to_query_list_end(query_block);
hits++;
@ -1061,7 +1082,8 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used,
if (tables_used->derived)
continue;
if (using_transactions &&
tables_used->table->file->has_transactions())
(tables_used->table->file->table_cache_type() ==
HA_CACHE_TBL_TRANSACT))
/*
Tables_used->table can't be 0 in transaction.
Only 'drop' invalidate not opened table, but 'drop'
@ -1115,7 +1137,8 @@ void Query_cache::invalidate(THD *thd, TABLE *table,
{
using_transactions = using_transactions &&
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
if (using_transactions && table->file->has_transactions())
if (using_transactions &&
(table->file->table_cache_type() == HA_CACHE_TBL_TRANSACT))
thd->add_changed_table(table);
else
invalidate_table(table);
@ -1934,7 +1957,8 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
block_table->n=n;
if (!insert_table(tables_used->table->key_length,
tables_used->table->table_cache_key, block_table,
tables_used->db_length))
tables_used->db_length,
tables_used->table->file->table_cache_type()))
break;
if (tables_used->table->db_type == DB_TYPE_MRG_MYISAM)
@ -1947,11 +1971,12 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
{
char key[MAX_DBKEY_LENGTH];
uint32 db_length;
uint key_length =filename_2_table_key(key, table->table->filename,
uint key_length= filename_2_table_key(key, table->table->filename,
&db_length);
(++block_table)->n= ++n;
if (!insert_table(key_length, key, block_table,
db_length))
db_length,
tables_used->table->file->table_cache_type()))
goto err;
}
}
@ -1978,7 +2003,7 @@ err:
my_bool
Query_cache::insert_table(uint key_len, char *key,
Query_cache_block_table *node,
uint32 db_length)
uint32 db_length, uint8 cache_type)
{
DBUG_ENTER("Query_cache::insert_table");
DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d",
@ -2016,6 +2041,8 @@ Query_cache::insert_table(uint key_len, char *key,
}
char *db = header->db();
header->table(db + db_length + 1);
header->key_length(key_len);
header->type(cache_type);
}
Query_cache_block_table *list_root = table_block->table(0);
@ -2446,7 +2473,9 @@ void Query_cache::double_linked_list_join(Query_cache_block *head_tail,
TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
char *query,
LEX *lex, TABLE_LIST *tables_used)
LEX *lex,
TABLE_LIST *tables_used,
uint8 *tables_type)
{
TABLE_COUNTER_TYPE table_count = 0;
DBUG_ENTER("Query_cache::is_cacheable");
@ -2457,7 +2486,6 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
OPTION_TO_QUERY_CACHE))) &&
lex->safe_to_cache_query)
{
my_bool has_transactions = 0;
DBUG_PRINT("qcache", ("options %lx %lx, type %u",
OPTION_TO_QUERY_CACHE,
lex->select_lex.options,
@ -2469,8 +2497,7 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
DBUG_PRINT("qcache", ("table %s, db %s, type %u",
tables_used->real_name,
tables_used->db, tables_used->table->db_type));
has_transactions = (has_transactions ||
tables_used->table->file->has_transactions());
*tables_type|= tables_used->table->file->table_cache_type();
if (tables_used->table->db_type == DB_TYPE_MRG_ISAM ||
tables_used->table->tmp_table != NO_TMP_TABLE ||
@ -2500,7 +2527,7 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
}
if ((thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
has_transactions)
((*tables_type)&HA_CACHE_TBL_TRANSACT))
{
DBUG_PRINT("qcache", ("not in autocommin mode"));
DBUG_RETURN(0);
@ -2941,7 +2968,7 @@ void Query_cache::bins_dump()
{
uint i;
if (!initialized)
if (!initialized || query_cache_size == 0)
{
DBUG_PRINT("qcache", ("Query Cache not initialized"));
return;
@ -2982,7 +3009,7 @@ void Query_cache::bins_dump()
void Query_cache::cache_dump()
{
if (!initialized)
if (!initialized || query_cache_size == 0)
{
DBUG_PRINT("qcache", ("Query Cache not initialized"));
return;
@ -3071,7 +3098,7 @@ void Query_cache::queries_dump()
void Query_cache::tables_dump()
{
if (!initialized)
if (!initialized || query_cache_size == 0)
{
DBUG_PRINT("qcache", ("Query Cache not initialized"));
return;

View file

@ -115,18 +115,21 @@ struct Query_cache_query
Query_cache_block *res;
NET *wri;
ulong len;
uint8 tbls_type;
inline void init_n_lock();
void unlock_n_destroy();
inline ulonglong found_rows() { return limit_found_rows; }
inline void found_rows(ulonglong rows) { limit_found_rows = rows; }
inline void found_rows(ulonglong rows) { limit_found_rows= rows; }
inline Query_cache_block *result() { return res; }
inline void result(Query_cache_block *p) { res=p; }
inline void result(Query_cache_block *p) { res= p; }
inline NET *writer() { return wri; }
inline void writer(NET *p) { wri=p; }
inline void writer(NET *p) { wri= p; }
inline uint8 tables_type() { return tbls_type; }
inline void tables_type(uint8 type) { tbls_type= type; }
inline ulong length() { return len; }
inline ulong add(ulong packet_len) { return(len += packet_len); }
inline void length(ulong length) { len = length; }
inline ulong add(ulong packet_len) { return(len+= packet_len); }
inline void length(ulong length) { len= length; }
inline gptr query()
{
return (gptr)(((byte*)this)+
@ -144,10 +147,16 @@ struct Query_cache_query
struct Query_cache_table
{
char *tbl;
uint key_len;
uint8 table_type;
inline char *db() { return (char *) data(); }
inline char *table() { return tbl; }
inline void table(char *table) { tbl = table; }
inline void table(char *table) { tbl= table; }
inline uint key_length() { return key_len; }
inline void key_length(uint len) { key_len= len; }
inline uint8 type() { return table_type; }
inline void type(uint8 t) { table_type= t; }
inline gptr data()
{
return (gptr)(((byte*)this)+
@ -276,7 +285,7 @@ protected:
TABLE_COUNTER_TYPE tables);
my_bool insert_table(uint key_len, char *key,
Query_cache_block_table *node,
uint32 db_length);
uint32 db_length, uint8 cache_type);
void unlink_table(Query_cache_block_table *node);
Query_cache_block *get_free_block (ulong len, my_bool not_less,
ulong min);
@ -334,7 +343,8 @@ protected:
(query without tables not cached)
*/
TABLE_COUNTER_TYPE is_cacheable(THD *thd, uint32 query_len, char *query,
LEX *lex, TABLE_LIST *tables_used);
LEX *lex, TABLE_LIST *tables_used,
uint8 *tables_type);
public:
Query_cache(ulong query_cache_limit = ULONG_MAX,

View file

@ -207,7 +207,6 @@ void THD::init(void)
{
pthread_mutex_lock(&LOCK_global_system_variables);
variables= global_system_variables;
variables.client_collation= default_charset_info;
pthread_mutex_unlock(&LOCK_global_system_variables);
server_status= SERVER_STATUS_AUTOCOMMIT;
options= thd_startup_options;

View file

@ -145,10 +145,12 @@ public:
int generate_new_name(char *new_name,const char *old_name);
void make_log_name(char* buf, const char* log_ident);
bool is_active(const char* log_file_name);
int update_log_index(LOG_INFO* linfo);
int purge_logs(THD* thd, const char* to_log);
int purge_logs_before_date(THD* thd, time_t purge_time);
int purge_first_log(struct st_relay_log_info* rli);
int update_log_index(LOG_INFO* linfo, bool need_update_threads);
int purge_logs(const char *to_log, bool included,
bool need_mutex, bool need_update_threads,
ulonglong *decrease_log_space);
int purge_logs_before_date(time_t purge_time);
int purge_first_log(struct st_relay_log_info* rli, bool included);
bool reset_logs(THD* thd);
// if we are exiting, we also want to close the index file
void close(bool exiting = 0);
@ -352,6 +354,7 @@ struct system_variables
ulong max_allowed_packet;
ulong max_error_count;
ulong max_heap_table_size;
ulong max_length_for_sort_data;
ulong max_prep_stmt_count;
ulong max_sort_length;
ulong max_tmp_tables;
@ -382,9 +385,9 @@ struct system_variables
my_bool low_priority_updates;
my_bool new_mode;
CHARSET_INFO *client_collation;
CHARSET_INFO *literal_collation;
CHARSET_INFO *result_collation;
CHARSET_INFO *collation_client;
CHARSET_INFO *collation_connection;
CHARSET_INFO *collation_results;
};
void free_tmp_table(THD *thd, TABLE *entry);
@ -665,7 +668,7 @@ public:
net.report_error= 1;
DBUG_PRINT("error",("Fatal error set"));
}
inline CHARSET_INFO *charset() { return variables.client_collation; }
inline CHARSET_INFO *charset() { return variables.collation_client; }
};
/*

View file

@ -1203,23 +1203,60 @@ TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table,
}
ulong st_select_lex_node::get_table_join_options() { return 0; }
/*
This is used for UNION & subselect to create a new table list of all used
tables.
The table_list->table entry in all used tables are set to point
to the entries in this list.
*/
// interface
/*
Interface method of table list creation for query
SYNOPSIS
st_select_lex_unit::create_total_list()
thd THD pointer
result pointer on result list of tables pointer
check_derived force derived table chacking (used for creating
table list for derived query)
DESCRIPTION
This is used for UNION & subselect to create a new table list of all used
tables.
The table_list->table entry in all used tables are set to point
to the entries in this list.
RETURN
0 - OK
!0 - error
*/
bool st_select_lex_unit::create_total_list(THD *thd, st_lex *lex,
TABLE_LIST **result,
bool check_derived)
{
*result= 0;
return create_total_list_n_last_return(thd, lex, &result, check_derived);
for (SELECT_LEX_UNIT *unit= this; unit; unit= unit->next_unit())
{
if ((res= unit->create_total_list_n_last_return(thd, lex, &result,
check_derived)))
return res;
}
return 0;
}
// list creator
/*
Table list creation for query
SYNOPSIS
st_select_lex_unit::create_total_list()
thd THD pointer
lex pointer on LEX stricture
result pointer on pointer on result list of tables pointer
check_derived force derived table chacking (used for creating
table list for derived query)
DESCRIPTION
This is used for UNION & subselect to create a new table list of all used
tables.
The table_list->table entry in all used tables are set to point
to the entries in this list.
RETURN
0 - OK
!0 - error
*/
bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex,
TABLE_LIST ***result,
bool check_derived)

View file

@ -230,6 +230,7 @@ public:
virtual st_select_lex_unit* master_unit()= 0;
virtual st_select_lex* outer_select()= 0;
virtual st_select_lex_node* return_after_parsing()= 0;
virtual bool set_braces(bool value);
virtual bool inc_in_sum_expr();
@ -284,6 +285,8 @@ public:
global parameters for union
*/
st_select_lex_node *global_parameters;
//node on wich we should return current_select pointer after parsing subquery
st_select_lex_node *return_to;
/* LIMIT clause runtime counters */
ha_rows select_limit_cnt, offset_limit_cnt;
/* not NULL if union used in subselect, point to subselect item */
@ -304,6 +307,7 @@ public:
(st_select_lex*) slave->next : (st_select_lex*) slave;
}
st_select_lex_unit* next_unit() { return (st_select_lex_unit*) next; }
st_select_lex_node* return_after_parsing() { return return_to; }
void exclude_level();
/* UNION methods */
@ -366,6 +370,10 @@ public:
{
return &link_next;
}
st_select_lex_node* return_after_parsing()
{
return master_unit()->return_after_parsing();
}
bool set_braces(bool value);
bool inc_in_sum_expr();

View file

@ -3235,7 +3235,8 @@ mysql_init_query(THD *thd)
lex->select_lex.init_query();
lex->value_list.empty();
lex->param_list.empty();
lex->unit.next= lex->unit.master= lex->unit.link_next= 0;
lex->unit.next= lex->unit.master= lex->unit.return_to=
lex->unit.link_next= 0;
lex->unit.prev= lex->unit.link_prev= 0;
lex->unit.global_parameters= lex->unit.slave= lex->current_select=
lex->all_selects_list= &lex->select_lex;
@ -3283,9 +3284,9 @@ bool
mysql_new_select(LEX *lex, bool move_down)
{
SELECT_LEX *select_lex = new SELECT_LEX();
select_lex->select_number= ++lex->thd->select_number;
if (!select_lex)
return 1;
select_lex->select_number= ++lex->thd->select_number;
select_lex->init_query();
select_lex->init_select();
if (move_down)
@ -3297,9 +3298,13 @@ mysql_new_select(LEX *lex, bool move_down)
unit->init_query();
unit->init_select();
unit->thd= lex->thd;
unit->include_down(lex->current_select);
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
unit->include_neighbour(lex->current_select);
else
unit->include_down(lex->current_select);
unit->link_next= 0;
unit->link_prev= 0;
unit->return_to= lex->current_select;
select_lex->include_down(unit);
}
else
@ -3975,7 +3980,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
{
long purge_time= time(0) - expire_logs_days*24*60*60;
if (purge_time >= 0)
mysql_bin_log.purge_logs_before_date(thd, purge_time);
mysql_bin_log.purge_logs_before_date(purge_time);
}
#endif
mysql_slow_log.new_file(1);

View file

@ -292,7 +292,7 @@ int purge_master_logs(THD* thd, const char* to_log)
char search_file_name[FN_REFLEN];
mysql_bin_log.make_log_name(search_file_name, to_log);
int res = mysql_bin_log.purge_logs(thd, search_file_name);
int res = mysql_bin_log.purge_logs(search_file_name, 0, 1, 1, NULL);
return purge_error_message(thd, res);
}
@ -300,7 +300,7 @@ int purge_master_logs(THD* thd, const char* to_log)
int purge_master_logs_before_date(THD* thd, time_t purge_time)
{
int res = mysql_bin_log.purge_logs_before_date(thd, purge_time);
int res = mysql_bin_log.purge_logs_before_date(purge_time);
return purge_error_message(thd ,res);
}
@ -776,24 +776,25 @@ int reset_slave(THD *thd, MASTER_INFO* mi)
error=1;
goto err;
}
//delete relay logs, clear relay log coordinates
// delete relay logs, clear relay log coordinates
if ((error= purge_relay_logs(&mi->rli, thd,
1 /* just reset */,
&errmsg)))
goto err;
//Clear master's log coordinates (only for good display of SHOW SLAVE STATUS)
// Clear master's log coordinates (only for good display of SHOW SLAVE STATUS)
mi->master_log_name[0]= 0;
mi->master_log_pos= BIN_LOG_HEADER_SIZE;
//close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0
// close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0
end_master_info(mi);
//and delete these two files
// and delete these two files
fn_format(fname, master_info_file, mysql_data_home, "", 4+32);
if (my_stat(fname, &stat_area, MYF(0)) && my_delete(fname, MYF(MY_WME)))
{
error=1;
goto err;
}
// delete relay_log_info_file
fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32);
if (my_stat(fname, &stat_area, MYF(0)) && my_delete(fname, MYF(MY_WME)))
{
@ -874,7 +875,6 @@ int change_master(THD* thd, MASTER_INFO* mi)
// if we change host or port, we must reset the postion
mi->master_log_name[0] = 0;
mi->master_log_pos= BIN_LOG_HEADER_SIZE;
mi->rli.pending = 0;
}
if (lex_mi->log_file_name)
@ -883,7 +883,6 @@ int change_master(THD* thd, MASTER_INFO* mi)
if (lex_mi->pos)
{
mi->master_log_pos= lex_mi->pos;
mi->rli.pending = 0;
}
DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
@ -901,20 +900,22 @@ int change_master(THD* thd, MASTER_INFO* mi)
if (lex_mi->relay_log_name)
{
need_relay_log_purge= 0;
strmake(mi->rli.relay_log_name,lex_mi->relay_log_name,
sizeof(mi->rli.relay_log_name)-1);
strmake(mi->rli.group_relay_log_name,lex_mi->relay_log_name,
sizeof(mi->rli.group_relay_log_name)-1);
strmake(mi->rli.event_relay_log_name,lex_mi->relay_log_name,
sizeof(mi->rli.event_relay_log_name)-1);
}
if (lex_mi->relay_log_pos)
{
need_relay_log_purge= 0;
mi->rli.relay_log_pos=lex_mi->relay_log_pos;
mi->rli.group_relay_log_pos= mi->rli.event_relay_log_pos= lex_mi->relay_log_pos;
}
flush_master_info(mi);
if (need_relay_log_purge)
{
mi->rli.skip_log_purge= 0;
relay_log_purge= 1;
thd->proc_info="purging old relay logs";
if (purge_relay_logs(&mi->rli, thd,
0 /* not only reset, but also reinit */,
@ -928,11 +929,11 @@ int change_master(THD* thd, MASTER_INFO* mi)
else
{
const char* msg;
mi->rli.skip_log_purge= 1;
relay_log_purge= 0;
/* Relay log is already initialized */
if (init_relay_log_pos(&mi->rli,
mi->rli.relay_log_name,
mi->rli.relay_log_pos,
mi->rli.group_relay_log_name,
mi->rli.group_relay_log_pos,
0 /*no data lock*/,
&msg))
{
@ -941,12 +942,12 @@ int change_master(THD* thd, MASTER_INFO* mi)
DBUG_RETURN(1);
}
}
mi->rli.master_log_pos = mi->master_log_pos;
mi->rli.group_master_log_pos = mi->master_log_pos;
DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
strmake(mi->rli.master_log_name,mi->master_log_name,
sizeof(mi->rli.master_log_name)-1);
if (!mi->rli.master_log_name[0]) // uninitialized case
mi->rli.master_log_pos=0;
strmake(mi->rli.group_master_log_name,mi->master_log_name,
sizeof(mi->rli.group_master_log_name)-1);
if (!mi->rli.group_master_log_name[0]) // uninitialized case
mi->rli.group_master_log_pos=0;
pthread_mutex_lock(&mi->rli.data_lock);
mi->rli.abort_pos_wait++;

View file

@ -299,7 +299,7 @@ JOIN::prepare(Item ***rref_pointer_array,
DBUG_RETURN(-1); /* purecov: inspected */
ref_pointer_array= *rref_pointer_array;
if (having)
{
thd->where="having clause";
@ -313,6 +313,7 @@ JOIN::prepare(Item ***rref_pointer_array,
if (having->with_sum_func)
having->split_sum_func(ref_pointer_array, all_fields);
}
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
DBUG_RETURN(-1);
/*
@ -426,7 +427,7 @@ JOIN::optimize()
#ifdef HAVE_REF_TO_FIELDS // Not done yet
/* Add HAVING to WHERE if possible */
if (having && !group_list && ! sum_func_count)
if (having && !group_list && !sum_func_count)
{
if (!conds)
{
@ -4014,7 +4015,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item_sum::AVG_FUNC: /* Place for sum & count */
if (group)
return new Field_string(sizeof(double)+sizeof(longlong),
maybe_null, item->name,table,&my_charset_bin);
0, item->name,table,&my_charset_bin);
else
return new Field_double(item_sum->max_length,maybe_null,
item->name, table, item_sum->decimals);
@ -4022,7 +4023,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item_sum::STD_FUNC:
if (group)
return new Field_string(sizeof(double)*2+sizeof(longlong),
maybe_null, item->name,table,&my_charset_bin);
0, item->name,table,&my_charset_bin);
else
return new Field_double(item_sum->max_length, maybe_null,
item->name,table,item_sum->decimals);
@ -5626,11 +5627,11 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
TABLE *table=jt->table;
join->select_options ^= OPTION_FOUND_ROWS;
if (table->record_pointers ||
(table->io_cache && my_b_inited(table->io_cache)))
if (table->sort.record_pointers ||
(table->sort.io_cache && my_b_inited(table->sort.io_cache)))
{
/* Using filesort */
join->send_records= table->found_records;
join->send_records= table->sort.found_records;
}
else
{
@ -6465,8 +6466,8 @@ create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order,
if (!(sortorder=make_unireg_sortorder(order,&length)))
goto err; /* purecov: inspected */
/* It's not fatal if the following alloc fails */
table->io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
MYF(MY_WME | MY_ZEROFILL));
table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
MYF(MY_WME | MY_ZEROFILL));
table->status=0; // May be wrong if quick_select
// If table has a range, move it to select
@ -6495,9 +6496,9 @@ create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order,
}
if (table->tmp_table)
table->file->info(HA_STATUS_VARIABLE); // Get record count
table->found_records=filesort(thd, table,sortorder, length,
select, filesort_limit, &examined_rows);
tab->records=table->found_records; // For SQL_CALC_ROWS
table->sort.found_records=filesort(thd, table,sortorder, length,
select, filesort_limit, &examined_rows);
tab->records=table->sort.found_records; // For SQL_CALC_ROWS
delete select; // filesort did select
tab->select=0;
tab->select_cond=0;
@ -6509,7 +6510,7 @@ create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order,
table->key_read=0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
DBUG_RETURN(table->found_records == HA_POS_ERROR);
DBUG_RETURN(table->sort.found_records == HA_POS_ERROR);
err:
DBUG_RETURN(-1);
}

View file

@ -19,6 +19,30 @@
#define MERGEBUFF 7
#define MERGEBUFF2 15
/*
The structure SORT_ADDON_FIELD describes a fixed layout
for field values appended to sorted values in records to be sorted
in the sort buffer.
Only fixed layout is supported now.
Null bit maps for the appended values is placed before the values
themselves. Offsets are from the last sorted field, that is from the
record referefence, which is still last component of sorted records.
It is preserved for backward compatiblility.
The structure is used tp store values of the additional fields
in the sort buffer. It is used also when these values are read
from a temporary file/buffer. As the reading procedures are beyond the
scope of the 'filesort' code the values have to be retrieved via
the callback function 'unpack_addon_fields'.
*/
typedef struct st_sort_addon_field { /* Sort addon packed field */
Field *field; /* Original field */
uint offset; /* Offset from the last sorted field */
uint null_offset; /* Offset to to null bit from the last sorted field */
uint length; /* Length in the sort buffer */
uint8 null_bit; /* Null bit mask for the field */
} SORT_ADDON_FIELD;
typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */
my_off_t file_pos; /* Where we are in the sort file */
uchar *base,*key; /* key pointers */
@ -27,15 +51,18 @@ typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */
ulong max_keys; /* Max keys in buffert */
} BUFFPEK;
typedef struct st_sort_param {
uint sort_length; /* Length of sort columns */
uint keys; /* Max keys / buffert */
uint rec_length; /* Length of sorted records */
uint sort_length; /* Length of sorted columns */
uint ref_length; /* Length of record ref. */
uint addon_length; /* Length of added packed fields */
uint res_length; /* Length of records in final sorted file/buffer */
uint keys; /* Max keys / buffer */
ha_rows max_rows,examined_rows;
TABLE *sort_form; /* For quicker make_sortkey */
SORT_FIELD *local_sortorder;
SORT_FIELD *end;
SORT_ADDON_FIELD *addon_field; /* Descriptors for companion fields */
uchar *unique_buff;
bool not_killable;
char* tmp_buffer;

View file

@ -2348,8 +2348,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
if (order)
{
from->io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
bzero((char*) &tables,sizeof(tables));
tables.table = from;
tables.alias = tables.real_name= from->real_name;
@ -2361,9 +2361,9 @@ copy_data_between_tables(TABLE *from,TABLE *to,
setup_order(thd, thd->lex.select_lex.ref_pointer_array,
&tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
(from->found_records = filesort(thd, from, sortorder, length,
(SQL_SELECT *) 0, HA_POS_ERROR,
&examined_rows))
(from->sort.found_records = filesort(thd, from, sortorder, length,
(SQL_SELECT *) 0, HA_POS_ERROR,
&examined_rows))
== HA_POS_ERROR)
goto err;
};

View file

@ -201,14 +201,14 @@ int mysql_update(THD *thd,
bzero((char*) &tables,sizeof(tables));
tables.table = table;
table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
order_num)||
setup_order(thd, thd->lex.select_lex.ref_pointer_array,
&tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
(table->found_records = filesort(thd, table, sortorder, length,
(table->sort.found_records = filesort(thd, table, sortorder, length,
(SQL_SELECT *) 0,
HA_POS_ERROR, &examined_rows))
== HA_POS_ERROR)

View file

@ -3924,7 +3924,7 @@ text_literal:
TEXT_STRING_literal
{
THD *thd= YYTHD;
$$ = new Item_string($1.str,$1.length,thd->variables.literal_collation);
$$ = new Item_string($1.str,$1.length,thd->variables.collation_connection);
}
| NCHAR_STRING
{ $$= new Item_string($1.str,$1.length,national_charset_info); }
@ -3936,7 +3936,7 @@ text_literal:
text_string:
TEXT_STRING_literal
{ $$= new String($1.str,$1.length,YYTHD->variables.literal_collation); }
{ $$= new String($1.str,$1.length,YYTHD->variables.collation_connection); }
| HEX_NUM
{
Item *tmp = new Item_varbinary($1.str,$1.length);
@ -4106,14 +4106,14 @@ TEXT_STRING_literal:
TEXT_STRING
{
THD *thd= YYTHD;
if (my_charset_same(thd->charset(),thd->variables.literal_collation))
if (my_charset_same(thd->charset(),thd->variables.collation_connection))
{
$$=$1;
}
else
{
String ident;
ident.copy($1.str,$1.length,thd->charset(),thd->variables.literal_collation);
ident.copy($1.str,$1.length,thd->charset(),thd->variables.collation_connection);
$$.str= thd->strmake(ident.ptr(),ident.length());
$$.length= ident.length();
}
@ -4405,28 +4405,27 @@ option_value:
{
THD *thd= YYTHD;
LEX *lex= Lex;
$2= $2 ? $2: global_system_variables.client_collation;
$2= $2 ? $2: global_system_variables.collation_client;
$3= $3 ? $3 : $2;
if (!my_charset_same($2,$3))
{
net_printf(YYTHD,ER_COLLATION_CHARSET_MISMATCH,
$3->name,$2->csname);
YYABORT;
net_printf(thd,ER_COLLATION_CHARSET_MISMATCH,$3->name,$2->csname);
YYABORT;
}
lex->var_list.push_back(new set_var_client_collation($3,thd->db_charset,$3));
lex->var_list.push_back(new set_var_collation_client($3,thd->db_charset,$3));
}
| NAMES_SYM charset_name_or_default opt_collate
{
THD *thd= YYTHD;
LEX *lex= Lex;
$2= $2 ? $2 : global_system_variables.client_collation;
$2= $2 ? $2 : global_system_variables.collation_client;
$3= $3 ? $3 : $2;
if (!my_charset_same($2,$3))
{
net_printf(YYTHD,ER_COLLATION_CHARSET_MISMATCH,
$3->name,$2->csname);
YYABORT;
net_printf(thd,ER_COLLATION_CHARSET_MISMATCH,$3->name,$2->csname);
YYABORT;
}
lex->var_list.push_back(new set_var_client_collation($3,$3,$3));
lex->var_list.push_back(new set_var_collation_client($3,$3,$3));
}
| PASSWORD equal text_or_password
{
@ -5014,5 +5013,5 @@ subselect_end:
')'
{
LEX *lex=Lex;
lex->current_select = lex->current_select->outer_select();
lex->current_select = lex->current_select->return_after_parsing();
};

View file

@ -104,6 +104,7 @@ typedef struct st_read_record { /* Parameter to read_record */
uint index;
byte *ref_pos; /* pointer to form->refpos */
byte *record;
byte *rec_buf; /* to read field values after filesort */
byte *cache,*cache_pos,*cache_end,*read_positions;
IO_CACHE *io_cache;
bool print_error, ignore_not_found_rows;

View file

@ -44,6 +44,17 @@ typedef struct st_grant_info
enum tmp_table_type {NO_TMP_TABLE=0, TMP_TABLE=1, TRANSACTIONAL_TMP_TABLE=2};
typedef struct st_filesort_info
{
IO_CACHE *io_cache; /* If sorted through filebyte */
byte *addon_buf; /* Pointer to a buffer if sorted with fields */
uint addon_length; /* Length of the buffer */
struct st_sort_addon_field *addon_field; /* Pointer to the fields info */
void (*unpack)(struct st_sort_addon_field *, byte *); /* To unpack back */
byte *record_pointers; /* If sorted in memory */
ha_rows found_records; /* How many records in sort */
} FILESORT_INFO;
/* Table cache entry struct */
class Field_timestamp;
@ -120,9 +131,7 @@ struct st_table {
table_map map; /* ID bit of table (1,2,4,8,16...) */
ulong version,flush_version;
uchar *null_flags;
IO_CACHE *io_cache; /* If sorted trough filebyte */
byte *record_pointers; /* If sorted in memory */
ha_rows found_records; /* How many records in sort */
FILESORT_INFO sort;
ORDER *group;
ha_rows quick_rows[MAX_KEY];
uint quick_key_parts[MAX_KEY];

View file

@ -95,12 +95,12 @@ bool Unique::flush()
bool Unique::get(TABLE *table)
{
SORTPARAM sort_param;
table->found_records=elements+tree.elements_in_tree;
table->sort.found_records=elements+tree.elements_in_tree;
if (my_b_tell(&file) == 0)
{
/* Whole tree is in memory; Don't use disk if you don't need to */
if ((record_pointers=table->record_pointers= (byte*)
if ((record_pointers=table->sort.record_pointers= (byte*)
my_malloc(tree.size_of_element * tree.elements_in_tree, MYF(0))))
{
(void) tree_walk(&tree, (tree_walk_action) unique_write_to_ptrs,
@ -112,7 +112,7 @@ bool Unique::get(TABLE *table)
if (flush())
return 1;
IO_CACHE *outfile=table->io_cache;
IO_CACHE *outfile=table->sort.io_cache;
BUFFPEK *file_ptr= (BUFFPEK*) file_ptrs.buffer;
uint maxbuffer= file_ptrs.elements - 1;
uchar *sort_buffer;
@ -120,8 +120,8 @@ bool Unique::get(TABLE *table)
bool error=1;
/* Open cached file if it isn't open */
outfile=table->io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
MYF(MY_ZEROFILL));
outfile=table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
MYF(MY_ZEROFILL));
if (!outfile || ! my_b_inited(outfile) &&
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,

View file

@ -84,7 +84,7 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
if (*fmt == 's') /* String parameter */
{
reg2 char *par = va_arg(ap, char *);
uint plen,left_len = (uint)(end-to);
uint plen,left_len = (uint)(end-to)+1;
if (!par) par = (char*)"(null)";
plen = (uint) strlen(par);
if (left_len <= plen)