mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
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:
commit
0c94064bbd
66 changed files with 1582 additions and 780 deletions
|
@ -605,3 +605,4 @@ vio/viotest-ssl
|
|||
myisam/ftbench/var/*
|
||||
myisam/ftbench/data
|
||||
myisam/ftbench/t
|
||||
client/ssl_test
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 };
|
||||
|
|
114
client/mysql.cc
114
client/mysql.cc
|
@ -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*) ¤t_db,
|
||||
(gptr*) ¤t_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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -753,10 +753,10 @@ lower(utf8_f)
|
|||
Ú
|
||||
Ö
|
||||
Ö
|
||||
<EFBFBD>
|
||||
£
|
||||
Å
|
||||
£
|
||||
<EFBFBD>
|
||||
Ä
|
||||
Ä
|
||||
Ç
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
18
mysql-test/r/rpl_relayrotate.result
Normal file
18
mysql-test/r/rpl_relayrotate.result
Normal 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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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("");
|
||||
|
||||
|
|
4
mysql-test/t/rpl_relayrotate-slave.opt
Normal file
4
mysql-test/t/rpl_relayrotate-slave.opt
Normal file
|
@ -0,0 +1,4 @@
|
|||
-O max_binlog_size=16384
|
||||
--innodb
|
||||
--log-warnings
|
||||
|
61
mysql-test/t/rpl_relayrotate.test
Normal file
61
mysql-test/t/rpl_relayrotate.test
Normal 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.
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
483
sql/filesort.cc
483
sql/filesort.cc
|
@ -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*) ¶m,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,
|
||||
¶m.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(¶m,(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= ¤t_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= ¬_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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
****************************************************************************/
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -603,6 +603,7 @@ public:
|
|||
item(it)
|
||||
{}
|
||||
bool fix_fields(THD *, struct st_table_list *, Item ** ref);
|
||||
Item **storage() {return &item;}
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)},
|
||||
|
|
167
sql/log.cc
167
sql/log.cc
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 ||
|
||||
|
|
101
sql/records.cc
101
sql/records.cc
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
104
sql/set_var.cc
104
sql/set_var.cc
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
204
sql/slave.cc
204
sql/slave.cc
|
@ -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
|
||||
|
|
91
sql/slave.h
91
sql/slave.h
|
@ -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")
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
15
sql/table.h
15
sql/table.h
|
@ -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];
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue