Merge with 4.0.12
Docs/internals.texi: Auto merged include/my_global.h: Auto merged include/mysql_com.h: Auto merged innobase/row/row0mysql.c: Auto merged innobase/row/row0sel.c: Auto merged libmysql/Makefile.am: Auto merged libmysqld/Makefile.am: Auto merged libmysqld/lib_vio.c: Auto merged mysql-test/r/heap.result: Auto merged mysql-test/r/innodb.result: Auto merged mysql-test/t/heap.test: Auto merged sql/ha_innodb.h: Auto merged sql/ha_myisam.cc: Auto merged BitKeeper/deleted/.del-password.c~76f30876e68eddb4: Auto merged sql/handler.cc: Auto merged sql/handler.h: Auto merged sql/item_func.cc: Auto merged sql/key.cc: Auto merged sql/lex.h: Auto merged sql/log.cc: Auto merged sql/mysqld.cc: Auto merged sql/slave.cc: Auto merged sql/slave.h: Auto merged sql/sql_class.cc: Auto merged sql/sql_repl.cc: Auto merged sql/sql_show.cc: Auto merged sql/sql_yacc.yy: Auto merged sql/table.cc: Auto merged strings/strto.c: Auto merged
This commit is contained in:
commit
161942e3ce
@ -2798,11 +2798,11 @@ Storage: same as TINYINT.
|
||||
@strong{DATE}
|
||||
@itemize @bullet
|
||||
@item
|
||||
Storage: fixed-length series of binary integers, always three bytes
|
||||
long.
|
||||
Storage: 3 byte integer, low byte first.
|
||||
Packed as: 'day + month*32 + year*16*32'
|
||||
@item
|
||||
Example: a DATE column containing '0001-01-01' looks like:@*
|
||||
@code{hexadecimal 21 02 00}
|
||||
Example: a DATE column containing '1962-01-02' looks like:@*
|
||||
@code{hexadecimal 22 54 0F}
|
||||
@end itemize
|
||||
|
||||
@strong{DATETIME}
|
||||
@ -2821,16 +2821,19 @@ Example: a DATETIME column for '0001-01-01 01:01:01' looks like:@*
|
||||
@strong{TIME}
|
||||
@itemize @bullet
|
||||
@item
|
||||
Storage: a value offset from 8385959, always three bytes long.
|
||||
Storage: 3 bytes, low byte first.
|
||||
This is stored as seconds: days*24*3600+hours*3600+minutes*60+seconds
|
||||
@item
|
||||
Example: a TIME column containing '01:01:01' looks like:@*
|
||||
@code{hexadecimal 75 27 00}
|
||||
Example: a TIME column containing '1 02:03:04' (1 day 2 hour 3 minutes and 4 seconds) looks like:@*
|
||||
@code{hexadecimal 58 6E 01}
|
||||
@end itemize
|
||||
|
||||
@strong{TIMESTAMP}
|
||||
@itemize @bullet
|
||||
@item
|
||||
Storage: four bytes long (NOTE TO SELF: not figured out)
|
||||
Storage: 4 bytes, low byte first.
|
||||
Stored as unix @code{time()}, which is seconds since the Epoch
|
||||
(00:00:00 UTC, January 1, 1970).
|
||||
@item
|
||||
Example: a TIMESTAMP column containing '2003-01-01 01:01:01' looks like:@*
|
||||
@code{hexadecimal 4D AE 12 23}
|
||||
|
@ -40,7 +40,7 @@
|
||||
#include <signal.h>
|
||||
#include <violite.h>
|
||||
|
||||
const char *VER= "13.4";
|
||||
const char *VER= "13.5";
|
||||
|
||||
/* Don't try to make a nice table if the data is too big */
|
||||
#define MAX_COLUMN_LENGTH 1024
|
||||
@ -799,6 +799,7 @@ static int get_options(int argc, char **argv)
|
||||
}
|
||||
if (argc == 1)
|
||||
{
|
||||
skip_updates= 0;
|
||||
my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
|
||||
current_db= my_strdup(*argv, MYF(MY_WME));
|
||||
}
|
||||
|
@ -1,191 +0,0 @@
|
||||
/* Copyright (C) 2000 MySQL 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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/* password checking routines */
|
||||
/*****************************************************************************
|
||||
The main idea is that no password are sent between client & server on
|
||||
connection and that no password are saved in mysql in a decodable form.
|
||||
|
||||
On connection a random string is generated and sent to the client.
|
||||
The client generates a new string with a random generator inited with
|
||||
the hash values from the password and the sent string.
|
||||
This 'check' string is sent to the server where it is compared with
|
||||
a string generated from the stored hash_value of the password and the
|
||||
random string.
|
||||
|
||||
The password is saved (in user.password) by using the PASSWORD() function in
|
||||
mysql.
|
||||
|
||||
Example:
|
||||
update user set password=PASSWORD("hello") where user="test"
|
||||
This saves a hashed number as a string in the password field.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
#include <m_string.h>
|
||||
#include "mysql.h"
|
||||
|
||||
|
||||
void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
|
||||
{ /* For mysql 3.21.# */
|
||||
#ifdef HAVE_purify
|
||||
bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
|
||||
#endif
|
||||
rand_st->max_value= 0x3FFFFFFFL;
|
||||
rand_st->max_value_dbl=(double) rand_st->max_value;
|
||||
rand_st->seed1=seed1%rand_st->max_value ;
|
||||
rand_st->seed2=seed2%rand_st->max_value;
|
||||
}
|
||||
|
||||
static void old_randominit(struct rand_struct *rand_st,ulong seed1)
|
||||
{ /* For mysql 3.20.# */
|
||||
rand_st->max_value= 0x01FFFFFFL;
|
||||
rand_st->max_value_dbl=(double) rand_st->max_value;
|
||||
seed1%=rand_st->max_value;
|
||||
rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
|
||||
}
|
||||
|
||||
double rnd(struct rand_struct *rand_st)
|
||||
{
|
||||
rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
|
||||
rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
|
||||
return (((double) rand_st->seed1)/rand_st->max_value_dbl);
|
||||
}
|
||||
|
||||
void hash_password(ulong *result, const char *password)
|
||||
{
|
||||
register ulong nr=1345345333L, add=7, nr2=0x12345671L;
|
||||
ulong tmp;
|
||||
for (; *password ; password++)
|
||||
{
|
||||
if (*password == ' ' || *password == '\t')
|
||||
continue; /* skipp space in password */
|
||||
tmp= (ulong) (uchar) *password;
|
||||
nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
|
||||
nr2+=(nr2 << 8) ^ nr;
|
||||
add+=tmp;
|
||||
}
|
||||
result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
|
||||
result[1]=nr2 & (((ulong) 1L << 31) -1L);
|
||||
return;
|
||||
}
|
||||
|
||||
void make_scrambled_password(char *to,const char *password)
|
||||
{
|
||||
ulong hash_res[2];
|
||||
hash_password(hash_res,password);
|
||||
sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
|
||||
}
|
||||
|
||||
static inline uint char_val(char X)
|
||||
{
|
||||
return (uint) (X >= '0' && X <= '9' ? X-'0' :
|
||||
X >= 'A' && X <= 'Z' ? X-'A'+10 :
|
||||
X-'a'+10);
|
||||
}
|
||||
|
||||
/*
|
||||
** This code assumes that len(password) is divideable with 8 and that
|
||||
** res is big enough (2 in mysql)
|
||||
*/
|
||||
|
||||
void get_salt_from_password(ulong *res,const char *password)
|
||||
{
|
||||
res[0]=res[1]=0;
|
||||
if (password)
|
||||
{
|
||||
while (*password)
|
||||
{
|
||||
ulong val=0;
|
||||
uint i;
|
||||
for (i=0 ; i < 8 ; i++)
|
||||
val=(val << 4)+char_val(*password++);
|
||||
*res++=val;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void make_password_from_salt(char *to, ulong *hash_res)
|
||||
{
|
||||
sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Genererate a new message based on message and password
|
||||
* The same thing is done in client and server and the results are checked.
|
||||
*/
|
||||
|
||||
char *scramble(char *to,const char *message,const char *password,
|
||||
my_bool old_ver)
|
||||
{
|
||||
struct rand_struct rand_st;
|
||||
ulong hash_pass[2],hash_message[2];
|
||||
if (password && password[0])
|
||||
{
|
||||
char *to_start=to;
|
||||
hash_password(hash_pass,password);
|
||||
hash_password(hash_message,message);
|
||||
if (old_ver)
|
||||
old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
|
||||
else
|
||||
randominit(&rand_st,hash_pass[0] ^ hash_message[0],
|
||||
hash_pass[1] ^ hash_message[1]);
|
||||
while (*message++)
|
||||
*to++= (char) (floor(rnd(&rand_st)*31)+64);
|
||||
if (!old_ver)
|
||||
{ /* Make it harder to break */
|
||||
char extra=(char) (floor(rnd(&rand_st)*31));
|
||||
while (to_start != to)
|
||||
*(to_start++)^=extra;
|
||||
}
|
||||
}
|
||||
*to=0;
|
||||
return to;
|
||||
}
|
||||
|
||||
|
||||
my_bool check_scramble(const char *scrambled, const char *message,
|
||||
ulong *hash_pass, my_bool old_ver)
|
||||
{
|
||||
struct rand_struct rand_st;
|
||||
ulong hash_message[2];
|
||||
char buff[16],*to,extra; /* Big enough for check */
|
||||
const char *pos;
|
||||
|
||||
hash_password(hash_message,message);
|
||||
if (old_ver)
|
||||
old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
|
||||
else
|
||||
randominit(&rand_st,hash_pass[0] ^ hash_message[0],
|
||||
hash_pass[1] ^ hash_message[1]);
|
||||
to=buff;
|
||||
for (pos=scrambled ; *pos ; pos++)
|
||||
*to++=(char) (floor(rnd(&rand_st)*31)+64);
|
||||
if (old_ver)
|
||||
extra=0;
|
||||
else
|
||||
extra=(char) (floor(rnd(&rand_st)*31));
|
||||
to=buff;
|
||||
while (*scrambled)
|
||||
{
|
||||
if (*scrambled++ != (char) (*to++ ^ extra))
|
||||
return 1; /* Wrong password */
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
# MA 02111-1307, USA
|
||||
|
||||
BUILT_SOURCES = mysql_version.h m_ctype.h my_config.h
|
||||
pkginclude_HEADERS = dbug.h m_string.h my_sys.h my_list.h my_xml.h \
|
||||
pkginclude_HEADERS = my_dbug.h m_string.h my_sys.h my_list.h my_xml.h \
|
||||
mysql.h mysql_com.h mysqld_error.h mysql_embed.h \
|
||||
my_semaphore.h my_pthread.h my_no_pthread.h raid.h \
|
||||
errmsg.h my_global.h my_net.h my_alloc.h \
|
||||
|
@ -417,7 +417,7 @@ typedef unsigned short ushort;
|
||||
#define DBUG_OFF
|
||||
#endif
|
||||
|
||||
#include <dbug.h>
|
||||
#include <my_dbug.h>
|
||||
|
||||
#define MIN_ARRAY_SIZE 0 /* Zero or One. Gcc allows zero*/
|
||||
#define ASCII_BITS_USED 8 /* Bit char used */
|
||||
|
@ -298,7 +298,7 @@ extern unsigned long net_buffer_length;
|
||||
|
||||
void randominit(struct rand_struct *,unsigned long seed1,
|
||||
unsigned long seed2);
|
||||
double rnd(struct rand_struct *);
|
||||
double my_rnd(struct rand_struct *);
|
||||
void make_scrambled_password(char *to,const char *password,
|
||||
my_bool force_old_scramble,struct rand_struct *rand_st);
|
||||
int get_password_length(my_bool force_old_scramble);
|
||||
|
@ -6,7 +6,7 @@ Contains also create table and other data dictionary operations.
|
||||
|
||||
Created 9/17/2000 Heikki Tuuri
|
||||
*******************************************************/
|
||||
|
||||
|
||||
#include "row0mysql.h"
|
||||
|
||||
#ifdef UNIV_NONINL
|
||||
|
@ -48,10 +48,6 @@ link_sources:
|
||||
rm -f $(srcdir)/$$f; \
|
||||
@LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \
|
||||
done; \
|
||||
for f in $$qs; do \
|
||||
rm -f $(srcdir)/$$f; \
|
||||
@LN_CP_F@ $(srcdir)/../sql/$$f $(srcdir)/$$f; \
|
||||
done; \
|
||||
for f in $$ds; do \
|
||||
rm -f $(srcdir)/$$f; \
|
||||
@LN_CP_F@ $(srcdir)/../dbug/$$f $(srcdir)/$$f; \
|
||||
@ -61,7 +57,9 @@ link_sources:
|
||||
@LN_CP_F@ $(srcdir)/../mysys/$$f $(srcdir)/$$f; \
|
||||
done; \
|
||||
rm -f $(srcdir)/net.c; \
|
||||
@LN_CP_F@ $(srcdir)/../sql/net_serv.cc $(srcdir)/net.c
|
||||
@LN_CP_F@ $(srcdir)/../sql/net_serv.cc $(srcdir)/net.c ; \
|
||||
rm -f $(srcdir)/password.c; \
|
||||
@LN_CP_F@ $(srcdir)/../sql/password.c $(srcdir)/password.c
|
||||
|
||||
# This part requires GNUmake
|
||||
#
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "mysql.h"
|
||||
#include <m_string.h>
|
||||
#include <m_ctype.h>
|
||||
#include <dbug.h>
|
||||
|
||||
#if defined(HAVE_BROKEN_GETPASS) && !defined(HAVE_GETPASSPHRASE)
|
||||
#undef HAVE_GETPASS
|
||||
|
@ -32,14 +32,14 @@ noinst_LIBRARIES = libmysqld_int.a
|
||||
pkglib_LIBRARIES = libmysqld.a
|
||||
SUBDIRS = . examples
|
||||
libmysqld_sources= libmysqld.c lib_sql.cc
|
||||
libmysqlsources = errmsg.c get_password.c password.c
|
||||
libmysqlsources = errmsg.c get_password.c
|
||||
|
||||
noinst_HEADERS = embedded_priv.h
|
||||
|
||||
sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \
|
||||
ha_innodb.cc ha_berkeley.cc ha_heap.cc ha_isam.cc ha_isammrg.cc \
|
||||
ha_myisam.cc ha_myisammrg.cc handler.cc sql_handler.cc \
|
||||
hostname.cc init.cc \
|
||||
hostname.cc init.cc password.c \
|
||||
item.cc item_buff.cc item_cmpfunc.cc item_create.cc \
|
||||
item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \
|
||||
item_uniq.cc item_subselect.cc item_row.cc\
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include <violite.h>
|
||||
#include <my_net.h>
|
||||
#include <m_string.h>
|
||||
#include <dbug.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef __WIN__
|
||||
|
@ -253,3 +253,26 @@ Incorrect table name 'a/a'
|
||||
drop table t1, t2, t3;
|
||||
drop table t3;
|
||||
drop database test_$1;
|
||||
SET SESSION table_type="heap";
|
||||
SELECT @@table_type;
|
||||
@@table_type
|
||||
HEAP
|
||||
CREATE TABLE t1 (a int not null);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL default '0'
|
||||
) TYPE=HEAP
|
||||
drop table t1;
|
||||
SET SESSION table_type="gemini";
|
||||
SELECT @@table_type;
|
||||
@@table_type
|
||||
GEMINI
|
||||
CREATE TABLE t1 (a int not null);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL default '0'
|
||||
) TYPE=MyISAM
|
||||
SET SESSION table_type=default;
|
||||
drop table t1;
|
||||
|
@ -23,7 +23,7 @@ a b
|
||||
4 6
|
||||
alter table t1 add c int not null, add key (c,a);
|
||||
drop table t1;
|
||||
create table t1 (a int not null,b int not null, primary key (a)) type=heap comment="testing heaps";
|
||||
create table t1 (a int not null,b int not null, primary key (a)) type=memory comment="testing heaps";
|
||||
insert into t1 values(1,1),(2,2),(3,3),(4,4);
|
||||
delete from t1 where a > 0;
|
||||
select * from t1;
|
||||
|
@ -1,4 +1,4 @@
|
||||
drop table if exists t1,t2;
|
||||
drop table if exists t1,t2,t3;
|
||||
create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) type=innodb;
|
||||
insert into t1 (code, name) values (1, 'Tim'), (1, 'Monty'), (2, 'David'), (2, 'Erik'), (3, 'Sasha'), (3, 'Jeremy'), (4, 'Matt');
|
||||
select id, code, name from t1 order by id;
|
||||
@ -1093,3 +1093,113 @@ SELECT * from t1;
|
||||
id
|
||||
3
|
||||
DROP TABLE t1,t2;
|
||||
set autocommit=0;
|
||||
CREATE TABLE t1 (id CHAR(15) NOT NULL, value CHAR(40) NOT NULL, PRIMARY KEY(id)) TYPE=InnoDB;
|
||||
CREATE TABLE t2 (id CHAR(15) NOT NULL, value CHAR(40) NOT NULL, PRIMARY KEY(id)) TYPE=InnoDB;
|
||||
CREATE TABLE t3 (id1 CHAR(15) NOT NULL, id2 CHAR(15) NOT NULL, PRIMARY KEY(id1, id2)) TYPE=InnoDB;
|
||||
INSERT INTO t3 VALUES("my-test-1", "my-test-2");
|
||||
COMMIT;
|
||||
INSERT INTO t1 VALUES("this-key", "will disappear");
|
||||
INSERT INTO t2 VALUES("this-key", "will also disappear");
|
||||
DELETE FROM t3 WHERE id1="my-test-1";
|
||||
SELECT * FROM t1;
|
||||
id value
|
||||
this-key will disappear
|
||||
SELECT * FROM t2;
|
||||
id value
|
||||
this-key will also disappear
|
||||
SELECT * FROM t3;
|
||||
id1 id2
|
||||
ROLLBACK;
|
||||
SELECT * FROM t1;
|
||||
id value
|
||||
SELECT * FROM t2;
|
||||
id value
|
||||
SELECT * FROM t3;
|
||||
id1 id2
|
||||
my-test-1 my-test-2
|
||||
SELECT * FROM t3 WHERE id1="my-test-1" LOCK IN SHARE MODE;
|
||||
id1 id2
|
||||
my-test-1 my-test-2
|
||||
COMMIT;
|
||||
set autocommit=1;
|
||||
DROP TABLE t1,t2,t3;
|
||||
CREATE TABLE t1 (a int not null primary key, b int not null, unique (b)) type=innodb;
|
||||
INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
|
||||
UPDATE t1 set a=a+100 where b between 2 and 3 and a < 1000;
|
||||
SELECT * from t1;
|
||||
a b
|
||||
1 1
|
||||
102 2
|
||||
103 3
|
||||
4 4
|
||||
5 5
|
||||
6 6
|
||||
7 7
|
||||
8 8
|
||||
9 9
|
||||
drop table t1;
|
||||
CREATE TABLE t1 (a int not null primary key, b int not null, key (b)) type=innodb;
|
||||
CREATE TABLE t2 (a int not null primary key, b int not null, key (b)) type=innodb;
|
||||
INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
|
||||
INSERT INTO t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
|
||||
update t1,t2 set t1.a=t1.a+100;
|
||||
select * from t1;
|
||||
a b
|
||||
101 1
|
||||
102 2
|
||||
103 3
|
||||
104 4
|
||||
105 5
|
||||
106 6
|
||||
107 7
|
||||
108 8
|
||||
109 9
|
||||
update t1,t2 set t1.a=t1.a+100 where t1.a=101;
|
||||
select * from t1;
|
||||
a b
|
||||
201 1
|
||||
102 2
|
||||
103 3
|
||||
104 4
|
||||
105 5
|
||||
106 6
|
||||
107 7
|
||||
108 8
|
||||
109 9
|
||||
update t1,t2 set t1.b=t1.b+10 where t1.b=2;
|
||||
select * from t1;
|
||||
a b
|
||||
201 1
|
||||
103 3
|
||||
104 4
|
||||
105 5
|
||||
106 6
|
||||
107 7
|
||||
108 8
|
||||
109 9
|
||||
102 12
|
||||
update t1,t2 set t1.b=t1.b+2,t2.b=t1.b where t1.b between 3 and 5;
|
||||
select * from t1;
|
||||
a b
|
||||
201 1
|
||||
103 5
|
||||
104 6
|
||||
106 6
|
||||
105 7
|
||||
107 7
|
||||
108 8
|
||||
109 9
|
||||
102 12
|
||||
select * from t2;
|
||||
a b
|
||||
1 5
|
||||
2 5
|
||||
3 5
|
||||
4 5
|
||||
5 5
|
||||
6 5
|
||||
7 5
|
||||
8 5
|
||||
9 5
|
||||
drop table t1,t2;
|
||||
|
@ -260,3 +260,67 @@ INSERT INTO t3 VALUES (1,'jedan'),(2,'dva');
|
||||
update t1,t2 set t1.naziv="aaaa" where t1.broj=t2.broj;
|
||||
update t1,t2,t3 set t1.naziv="bbbb", t2.naziv="aaaa" where t1.broj=t2.broj and t2.broj=t3.broj;
|
||||
drop table t1,t2,t3;
|
||||
CREATE TABLE t1 (a int not null primary key, b int not null, key (b));
|
||||
CREATE TABLE t2 (a int not null primary key, b int not null, key (b));
|
||||
INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
|
||||
INSERT INTO t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
|
||||
update t1,t2 set t1.a=t1.a+100;
|
||||
select * from t1;
|
||||
a b
|
||||
101 1
|
||||
102 2
|
||||
103 3
|
||||
104 4
|
||||
105 5
|
||||
106 6
|
||||
107 7
|
||||
108 8
|
||||
109 9
|
||||
update t1,t2 set t1.a=t1.a+100 where t1.a=101;
|
||||
select * from t1;
|
||||
a b
|
||||
201 1
|
||||
102 2
|
||||
103 3
|
||||
104 4
|
||||
105 5
|
||||
106 6
|
||||
107 7
|
||||
108 8
|
||||
109 9
|
||||
update t1,t2 set t1.b=t1.b+10 where t1.b=2;
|
||||
select * from t1;
|
||||
a b
|
||||
201 1
|
||||
102 12
|
||||
103 3
|
||||
104 4
|
||||
105 5
|
||||
106 6
|
||||
107 7
|
||||
108 8
|
||||
109 9
|
||||
update t1,t2 set t1.b=t1.b+2,t2.b=t1.b where t1.b between 3 and 5;
|
||||
select * from t1;
|
||||
a b
|
||||
201 1
|
||||
102 12
|
||||
103 5
|
||||
104 6
|
||||
105 7
|
||||
106 6
|
||||
107 7
|
||||
108 8
|
||||
109 9
|
||||
select * from t2;
|
||||
a b
|
||||
1 3
|
||||
2 3
|
||||
3 3
|
||||
4 3
|
||||
5 3
|
||||
6 3
|
||||
7 3
|
||||
8 3
|
||||
9 3
|
||||
drop table t1,t2;
|
||||
|
13
mysql-test/r/rpl_relayspace.result
Normal file
13
mysql-test/r/rpl_relayspace.result
Normal file
@ -0,0 +1,13 @@
|
||||
slave stop;
|
||||
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;
|
||||
slave start;
|
||||
stop slave;
|
||||
create table t1 (a int);
|
||||
reset slave;
|
||||
start slave;
|
||||
select master_pos_wait('master-bin.001',5000,45)=-1;
|
||||
master_pos_wait('master-bin.001',5000,45)=-1
|
||||
0
|
@ -167,3 +167,18 @@ drop table t1, t2, t3;
|
||||
drop table t3;
|
||||
drop database test_$1;
|
||||
|
||||
#
|
||||
# Test default table type
|
||||
#
|
||||
SET SESSION table_type="heap";
|
||||
SELECT @@table_type;
|
||||
CREATE TABLE t1 (a int not null);
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
# Test what happens when using a non existing table type
|
||||
SET SESSION table_type="gemini";
|
||||
SELECT @@table_type;
|
||||
CREATE TABLE t1 (a int not null);
|
||||
show create table t1;
|
||||
SET SESSION table_type=default;
|
||||
drop table t1;
|
||||
|
@ -20,7 +20,7 @@ select * from t1;
|
||||
alter table t1 add c int not null, add key (c,a);
|
||||
drop table t1;
|
||||
|
||||
create table t1 (a int not null,b int not null, primary key (a)) type=heap comment="testing heaps";
|
||||
create table t1 (a int not null,b int not null, primary key (a)) type=memory comment="testing heaps";
|
||||
insert into t1 values(1,1),(2,2),(3,3),(4,4);
|
||||
delete from t1 where a > 0;
|
||||
select * from t1;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1,t2;
|
||||
drop table if exists t1,t2,t3;
|
||||
--enable_warnings
|
||||
|
||||
create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) type=innodb;
|
||||
@ -728,3 +728,74 @@ SELECT * from t1;
|
||||
UPDATE t1,t2 SET t1.id=t1.id+1 where t1.id!=t2.id;
|
||||
SELECT * from t1;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
#
|
||||
# Test of range_optimizer
|
||||
#
|
||||
|
||||
set autocommit=0;
|
||||
|
||||
CREATE TABLE t1 (id CHAR(15) NOT NULL, value CHAR(40) NOT NULL, PRIMARY KEY(id)) TYPE=InnoDB;
|
||||
|
||||
CREATE TABLE t2 (id CHAR(15) NOT NULL, value CHAR(40) NOT NULL, PRIMARY KEY(id)) TYPE=InnoDB;
|
||||
|
||||
CREATE TABLE t3 (id1 CHAR(15) NOT NULL, id2 CHAR(15) NOT NULL, PRIMARY KEY(id1, id2)) TYPE=InnoDB;
|
||||
|
||||
INSERT INTO t3 VALUES("my-test-1", "my-test-2");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO t1 VALUES("this-key", "will disappear");
|
||||
INSERT INTO t2 VALUES("this-key", "will also disappear");
|
||||
DELETE FROM t3 WHERE id1="my-test-1";
|
||||
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
SELECT * FROM t3;
|
||||
ROLLBACK;
|
||||
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
SELECT * FROM t3;
|
||||
SELECT * FROM t3 WHERE id1="my-test-1" LOCK IN SHARE MODE;
|
||||
COMMIT;
|
||||
set autocommit=1;
|
||||
DROP TABLE t1,t2,t3;
|
||||
|
||||
#
|
||||
# Check update with conflicting key
|
||||
#
|
||||
|
||||
CREATE TABLE t1 (a int not null primary key, b int not null, unique (b)) type=innodb;
|
||||
INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
|
||||
# We need the a < 1000 test here to quard against the halloween problems
|
||||
UPDATE t1 set a=a+100 where b between 2 and 3 and a < 1000;
|
||||
SELECT * from t1;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Test multi update with different join methods
|
||||
#
|
||||
|
||||
CREATE TABLE t1 (a int not null primary key, b int not null, key (b)) type=innodb;
|
||||
CREATE TABLE t2 (a int not null primary key, b int not null, key (b)) type=innodb;
|
||||
INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
|
||||
INSERT INTO t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
|
||||
|
||||
# Full join, without key
|
||||
update t1,t2 set t1.a=t1.a+100;
|
||||
select * from t1;
|
||||
|
||||
# unique key
|
||||
update t1,t2 set t1.a=t1.a+100 where t1.a=101;
|
||||
select * from t1;
|
||||
|
||||
# ref key
|
||||
update t1,t2 set t1.b=t1.b+10 where t1.b=2;
|
||||
select * from t1;
|
||||
|
||||
# Range key (in t1)
|
||||
update t1,t2 set t1.b=t1.b+2,t2.b=t1.b where t1.b between 3 and 5;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
drop table t1,t2;
|
||||
|
@ -232,3 +232,31 @@ INSERT INTO t3 VALUES (1,'jedan'),(2,'dva');
|
||||
update t1,t2 set t1.naziv="aaaa" where t1.broj=t2.broj;
|
||||
update t1,t2,t3 set t1.naziv="bbbb", t2.naziv="aaaa" where t1.broj=t2.broj and t2.broj=t3.broj;
|
||||
drop table t1,t2,t3;
|
||||
|
||||
#
|
||||
# Test multi update with different join methods
|
||||
#
|
||||
|
||||
CREATE TABLE t1 (a int not null primary key, b int not null, key (b));
|
||||
CREATE TABLE t2 (a int not null primary key, b int not null, key (b));
|
||||
INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
|
||||
INSERT INTO t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
|
||||
|
||||
# Full join, without key
|
||||
update t1,t2 set t1.a=t1.a+100;
|
||||
select * from t1;
|
||||
|
||||
# unique key
|
||||
update t1,t2 set t1.a=t1.a+100 where t1.a=101;
|
||||
select * from t1;
|
||||
|
||||
# ref key
|
||||
update t1,t2 set t1.b=t1.b+10 where t1.b=2;
|
||||
select * from t1;
|
||||
|
||||
# Range key (in t1)
|
||||
update t1,t2 set t1.b=t1.b+2,t2.b=t1.b where t1.b between 3 and 5;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
|
||||
drop table t1,t2;
|
||||
|
1
mysql-test/t/rpl_relayspace-slave.opt
Normal file
1
mysql-test/t/rpl_relayspace-slave.opt
Normal file
@ -0,0 +1 @@
|
||||
-O relay_log_space_limit=1024
|
33
mysql-test/t/rpl_relayspace.test
Normal file
33
mysql-test/t/rpl_relayspace.test
Normal file
@ -0,0 +1,33 @@
|
||||
# The slave is started with relay_log_space_limit=1024 bytes,
|
||||
# to force the deadlock
|
||||
|
||||
source include/master-slave.inc;
|
||||
connection slave;
|
||||
stop slave;
|
||||
connection master;
|
||||
create table t1 (a int);
|
||||
let $1=200;
|
||||
disable_query_log;
|
||||
while ($1)
|
||||
{
|
||||
# eval means expand $ expressions
|
||||
eval insert into t1 values( $1 );
|
||||
dec $1;
|
||||
}
|
||||
# This will generate one 10kB master's binlog
|
||||
enable_query_log;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
reset slave;
|
||||
start slave;
|
||||
# The I/O thread stops filling the relay log when
|
||||
# it's 1kB. And the SQL thread cannot purge this relay log
|
||||
# as purge is done only when the SQL thread switches to another
|
||||
# relay log, which does not exist here.
|
||||
# So we should have a deadlock.
|
||||
# if it is not resolved automatically we'll detect
|
||||
# it with master_pos_wait that waits for farther than 1kB;
|
||||
# it will timeout after 45 seconds;
|
||||
# also the slave will probably not cooperate to shutdown
|
||||
# (as 2 threads are locked)
|
||||
select master_pos_wait('master-bin.001',5000,45)=-1;
|
@ -82,8 +82,7 @@ class ha_innobase: public handler
|
||||
HA_PRIMARY_KEY_IN_READ_INDEX |
|
||||
HA_DROP_BEFORE_CREATE |
|
||||
HA_NO_PREFIX_CHAR_KEYS |
|
||||
HA_TABLE_SCAN_ON_INDEX |
|
||||
HA_NOT_MULTI_UPDATE),
|
||||
HA_TABLE_SCAN_ON_INDEX),
|
||||
last_dup_key((uint) -1),
|
||||
start_of_scan(0)
|
||||
{
|
||||
|
@ -1258,6 +1258,35 @@ longlong ha_myisam::get_auto_increment()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Find out how many rows there is in the given range
|
||||
|
||||
SYNOPSIS
|
||||
records_in_range()
|
||||
inx Index to use
|
||||
start_key Start of range. Null pointer if from first key
|
||||
start_key_len Length of start key
|
||||
start_search_flag Flag if start key should be included or not
|
||||
end_key End of range. Null pointer if to last key
|
||||
end_key_len Length of end key
|
||||
end_search_flag Flag if start key should be included or not
|
||||
|
||||
NOTES
|
||||
start_search_flag can have one of the following values:
|
||||
HA_READ_KEY_EXACT Include the key in the range
|
||||
HA_READ_AFTER_KEY Don't include key in range
|
||||
|
||||
end_search_flag can have one of the following values:
|
||||
HA_READ_BEFORE_KEY Don't include key in range
|
||||
HA_READ_AFTER_KEY Include all 'end_key' values in the range
|
||||
|
||||
RETURN
|
||||
HA_POS_ERROR Something is wrong with the index tree.
|
||||
0 There is no matching keys in the given range
|
||||
number > 0 There is approximately 'number' matching rows in
|
||||
the range.
|
||||
*/
|
||||
|
||||
ha_rows ha_myisam::records_in_range(int inx,
|
||||
const byte *start_key,uint start_key_len,
|
||||
enum ha_rkey_function start_search_flag,
|
||||
@ -1272,6 +1301,7 @@ ha_rows ha_myisam::records_in_range(int inx,
|
||||
end_search_flag);
|
||||
}
|
||||
|
||||
|
||||
int ha_myisam::ft_read(byte * buf)
|
||||
{
|
||||
int error;
|
||||
|
@ -121,8 +121,15 @@ handler *get_new_handler(TABLE *table, enum db_type db_type)
|
||||
#endif
|
||||
case DB_TYPE_HEAP:
|
||||
return new ha_heap(table);
|
||||
case DB_TYPE_MYISAM:
|
||||
default: // should never happen
|
||||
{
|
||||
enum db_type def=(enum db_type) current_thd->variables.table_type;
|
||||
/* Try first with 'default table type' */
|
||||
if (db_type != def)
|
||||
return get_new_handler(table, def);
|
||||
}
|
||||
/* Fall back to MyISAM */
|
||||
case DB_TYPE_MYISAM:
|
||||
return new ha_myisam(table);
|
||||
case DB_TYPE_MRG_MYISAM:
|
||||
return new ha_myisammrg(table);
|
||||
|
@ -67,7 +67,6 @@
|
||||
#define HA_CAN_FULLTEXT (HA_NO_PREFIX_CHAR_KEYS*2)
|
||||
#define HA_CAN_SQL_HANDLER (HA_CAN_FULLTEXT*2)
|
||||
#define HA_NO_AUTO_INCREMENT (HA_CAN_SQL_HANDLER*2)
|
||||
#define HA_NOT_MULTI_UPDATE (HA_NO_AUTO_INCREMENT*2)
|
||||
|
||||
/*
|
||||
Next record gives next record according last record read (even
|
||||
|
@ -851,7 +851,7 @@ void Item_func_rand::fix_length_and_dec()
|
||||
|
||||
double Item_func_rand::val()
|
||||
{
|
||||
return rnd(rand);
|
||||
return my_rnd(rand);
|
||||
}
|
||||
|
||||
longlong Item_func_sign::val_int()
|
||||
|
@ -271,5 +271,13 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
If table handler has primary key as part of the index, check that primary
|
||||
key is not updated
|
||||
*/
|
||||
if (idx != table->primary_key && table->primary_key < MAX_KEY &&
|
||||
(table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
|
||||
return check_if_key_used(table, table->primary_key, fields);
|
||||
return 0;
|
||||
}
|
||||
|
@ -257,6 +257,7 @@ static SYMBOL symbols[] = {
|
||||
{ "MEDIUMINT", SYM(MEDIUMINT),0,0},
|
||||
{ "MERGE", SYM(MERGE_SYM),0,0},
|
||||
{ "MEDIUM", SYM(MEDIUM_SYM),0,0},
|
||||
{ "MEMORY", SYM(MEMORY_SYM),0,0},
|
||||
{ "MIDDLEINT", SYM(MEDIUMINT),0,0}, /* For powerbuilder */
|
||||
{ "MIN_ROWS", SYM(MIN_ROWS),0,0},
|
||||
{ "MINUTE", SYM(MINUTE_SYM),0,0},
|
||||
|
@ -654,6 +654,8 @@ int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli)
|
||||
*/
|
||||
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);
|
||||
|
||||
|
@ -2761,7 +2761,7 @@ static void create_new_thread(THD *thd)
|
||||
max_used_connections=thread_count-delayed_insert_threads;
|
||||
thd->thread_id=thread_id++;
|
||||
for (uint i=0; i < 8 ; i++) // Generate password teststring
|
||||
thd->scramble[i]= (char) (rnd(&sql_rand)*94+33);
|
||||
thd->scramble[i]= (char) (my_rnd(&sql_rand)*94+33);
|
||||
thd->scramble[8]=0;
|
||||
// Back it up as old clients may need it
|
||||
memcpy(thd->old_scramble,thd->scramble,9);
|
||||
|
@ -125,7 +125,7 @@ static void old_randominit(struct rand_struct *rand_st,ulong seed1)
|
||||
Generated pseudo random number
|
||||
*/
|
||||
|
||||
double rnd(struct rand_struct *rand_st)
|
||||
double my_rnd(struct rand_struct *rand_st)
|
||||
{
|
||||
rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
|
||||
rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
|
||||
@ -435,7 +435,7 @@ char get_password_version(const char *password)
|
||||
|
||||
|
||||
|
||||
inline uint char_val(char X)
|
||||
static inline unsigned int char_val(char X)
|
||||
{
|
||||
return (uint) (X >= '0' && X <= '9' ? X-'0' :
|
||||
X >= 'A' && X <= 'Z' ? X-'A'+10 :
|
||||
@ -652,10 +652,10 @@ char *scramble(char *to,const char *message,const char *password,
|
||||
randominit(&rand_st,hash_pass[0] ^ hash_message[0],
|
||||
hash_pass[1] ^ hash_message[1]);
|
||||
while (*msg++)
|
||||
*to++= (char) (floor(rnd(&rand_st)*31)+64);
|
||||
*to++= (char) (floor(my_rnd(&rand_st)*31)+64);
|
||||
if (!old_ver)
|
||||
{ /* Make it harder to break */
|
||||
char extra=(char) (floor(rnd(&rand_st)*31));
|
||||
char extra=(char) (floor(my_rnd(&rand_st)*31));
|
||||
while (to_start != to)
|
||||
*(to_start++)^=extra;
|
||||
}
|
||||
@ -711,11 +711,11 @@ my_bool check_scramble(const char *scrambled, const char *message,
|
||||
hash_pass[1] ^ hash_message[1]);
|
||||
to=buff;
|
||||
for (pos=scrambled ; *pos ; pos++)
|
||||
*to++=(char) (floor(rnd(&rand_st)*31)+64);
|
||||
*to++=(char) (floor(my_rnd(&rand_st)*31)+64);
|
||||
if (old_ver)
|
||||
extra=0;
|
||||
else
|
||||
extra=(char) (floor(rnd(&rand_st)*31));
|
||||
extra=(char) (floor(my_rnd(&rand_st)*31));
|
||||
to=buff;
|
||||
while (*scrambled)
|
||||
{
|
||||
|
60
sql/slave.cc
60
sql/slave.cc
@ -263,7 +263,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
|
||||
if (log) // If not first log
|
||||
{
|
||||
if (strcmp(log, rli->linfo.log_file_name))
|
||||
rli->skip_log_purge=1; // Different name; Don't purge
|
||||
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";
|
||||
@ -298,6 +298,12 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
|
||||
my_b_seek(rli->cur_log,(off_t)pos);
|
||||
|
||||
err:
|
||||
/*
|
||||
If we don't purge, we can't honour relay_log_space_limit ;
|
||||
silently discard it
|
||||
*/
|
||||
if (rli->skip_log_purge)
|
||||
rli->log_space_limit= 0;
|
||||
pthread_cond_broadcast(&rli->data_cond);
|
||||
if (need_data_lock)
|
||||
pthread_mutex_unlock(&rli->data_lock);
|
||||
@ -1386,7 +1392,8 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
|
||||
thd->proc_info = "Waiting for relay log space to free";
|
||||
|
||||
while (rli->log_space_limit < rli->log_space_total &&
|
||||
!(slave_killed=io_slave_killed(thd,mi)))
|
||||
!(slave_killed=io_slave_killed(thd,mi)) &&
|
||||
!rli->ignore_log_space_limit)
|
||||
{
|
||||
pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
|
||||
}
|
||||
@ -1667,7 +1674,7 @@ 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),
|
||||
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),
|
||||
@ -2378,7 +2385,8 @@ reconnect done to recover from failed read");
|
||||
}
|
||||
flush_master_info(mi);
|
||||
if (mi->rli.log_space_limit && mi->rli.log_space_limit <
|
||||
mi->rli.log_space_total)
|
||||
mi->rli.log_space_total &&
|
||||
!mi->rli.ignore_log_space_limit)
|
||||
if (wait_for_relay_log_space(&mi->rli))
|
||||
{
|
||||
sql_print_error("Slave I/O thread aborted while waiting for relay \
|
||||
@ -2491,6 +2499,10 @@ slave_begin:
|
||||
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,
|
||||
@ -3199,11 +3211,41 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
|
||||
update. If we do not, show slave status will block
|
||||
*/
|
||||
pthread_mutex_unlock(&rli->data_lock);
|
||||
/* 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
|
||||
pthread_mutex_lock(&rli->data_lock);
|
||||
|
||||
/*
|
||||
Possible deadlock :
|
||||
- the I/O thread has reached log_space_limit
|
||||
- the SQL thread has read all relay logs, but cannot purge for some
|
||||
reason:
|
||||
* it has already purged all logs except the current one
|
||||
* there are other logs than the current one but they're involved in
|
||||
a transaction that finishes in the current one (or is not finished)
|
||||
Solution :
|
||||
Wake up the possibly waiting I/O thread, and set a boolean asking
|
||||
the I/O thread to temporarily ignore the log_space_limit
|
||||
constraint, because we do not want the I/O thread to block because of
|
||||
space (it's ok if it blocks for any other reason (e.g. because the
|
||||
master does not send anything). Then the I/O thread stops waiting
|
||||
and reads more events.
|
||||
The SQL thread decides when the I/O thread should take log_space_limit
|
||||
into account again : ignore_log_space_limit is reset to 0
|
||||
in purge_first_log (when the SQL thread purges the just-read relay
|
||||
log), and also when the SQL thread starts. We should also reset
|
||||
ignore_log_space_limit to 0 when the user does RESET SLAVE, but in
|
||||
fact, no need as RESET SLAVE requires that the slave
|
||||
be stopped, and when the SQL thread is later restarted
|
||||
ignore_log_space_limit will be reset to 0.
|
||||
*/
|
||||
pthread_mutex_lock(&rli->log_space_lock);
|
||||
// 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);
|
||||
// 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
|
||||
pthread_mutex_lock(&rli->data_lock);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
|
@ -156,7 +156,14 @@ typedef struct st_relay_log_info
|
||||
extra offset to be added to the position.
|
||||
*/
|
||||
ulonglong relay_log_pos, pending;
|
||||
|
||||
/*
|
||||
Handling of the relay_log_space_limit optional constraint.
|
||||
ignore_log_space_limit is used to resolve a deadlock between I/O and SQL
|
||||
threads, it makes the I/O thread temporarily forget about the constraint
|
||||
*/
|
||||
ulonglong log_space_limit,log_space_total;
|
||||
bool ignore_log_space_limit;
|
||||
|
||||
/*
|
||||
InnoDB internally stores the master log position it has processed
|
||||
|
@ -186,7 +186,7 @@ THD::THD():user_time(0), is_fatal_error(0),
|
||||
*/
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_thread_count);
|
||||
ulong tmp=(ulong) (rnd(&sql_rand) * 0xffffffff); /* make all bits random */
|
||||
ulong tmp=(ulong) (my_rnd(&sql_rand) * 0xffffffff); /* make all bits random */
|
||||
pthread_mutex_unlock(&LOCK_thread_count);
|
||||
randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ void SQL_CRYPT::crypt_init(ulong *rand_nr)
|
||||
|
||||
for (i=0 ; i<= 255 ; i++)
|
||||
{
|
||||
int idx= (uint) (rnd(&rand)*255.0);
|
||||
int idx= (uint) (my_rnd(&rand)*255.0);
|
||||
char a= decode_buff[idx];
|
||||
decode_buff[idx]= decode_buff[i];
|
||||
decode_buff[+i]=a;
|
||||
@ -62,7 +62,7 @@ void SQL_CRYPT::encode(char *str,uint length)
|
||||
{
|
||||
for (uint i=0; i < length; i++)
|
||||
{
|
||||
shift^=(uint) (rnd(&rand)*255.0);
|
||||
shift^=(uint) (my_rnd(&rand)*255.0);
|
||||
uint idx= (uint) (uchar) str[0];
|
||||
*str++ = (char) ((uchar) encode_buff[idx] ^ shift);
|
||||
shift^= idx;
|
||||
@ -74,7 +74,7 @@ void SQL_CRYPT::decode(char *str,uint length)
|
||||
{
|
||||
for (uint i=0; i < length; i++)
|
||||
{
|
||||
shift^=(uint) (rnd(&rand)*255.0);
|
||||
shift^=(uint) (my_rnd(&rand)*255.0);
|
||||
uint idx= (uint) ((unsigned char) str[0] ^ shift);
|
||||
*str = decode_buff[idx];
|
||||
shift^= (uint) (uchar) *str++;
|
||||
|
@ -563,7 +563,10 @@ check_connections(THD *thd)
|
||||
thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
|
||||
/* Cut very long hostnames to avoid possible overflows */
|
||||
if (thd->host)
|
||||
{
|
||||
thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
|
||||
thd->host_or_ip= thd->host;
|
||||
}
|
||||
if (connect_errors > max_connect_errors)
|
||||
return(ER_HOST_IS_BLOCKED);
|
||||
}
|
||||
|
@ -900,22 +900,21 @@ int change_master(THD* thd, MASTER_INFO* mi)
|
||||
|
||||
if (lex_mi->relay_log_name)
|
||||
{
|
||||
need_relay_log_purge = 0;
|
||||
mi->rli.skip_log_purge=1;
|
||||
need_relay_log_purge= 0;
|
||||
strmake(mi->rli.relay_log_name,lex_mi->relay_log_name,
|
||||
sizeof(mi->rli.relay_log_name)-1);
|
||||
}
|
||||
|
||||
if (lex_mi->relay_log_pos)
|
||||
{
|
||||
need_relay_log_purge=0;
|
||||
need_relay_log_purge= 0;
|
||||
mi->rli.relay_log_pos=lex_mi->relay_log_pos;
|
||||
}
|
||||
|
||||
flush_master_info(mi);
|
||||
if (need_relay_log_purge)
|
||||
{
|
||||
mi->rli.skip_log_purge=0;
|
||||
mi->rli.skip_log_purge= 0;
|
||||
thd->proc_info="purging old relay logs";
|
||||
if (purge_relay_logs(&mi->rli, thd,
|
||||
0 /* not only reset, but also reinit */,
|
||||
@ -929,6 +928,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
|
||||
else
|
||||
{
|
||||
const char* msg;
|
||||
mi->rli.skip_log_purge= 1;
|
||||
/* Relay log is already initialized */
|
||||
if (init_relay_log_pos(&mi->rli,
|
||||
mi->rli.relay_log_name,
|
||||
|
@ -1334,10 +1334,10 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
|
||||
{
|
||||
if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1)))
|
||||
my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
|
||||
"%s:%u", thd->host_or_ip, tmp->peer_port);
|
||||
"%s:%u", tmp->host_or_ip, tmp->peer_port);
|
||||
}
|
||||
else
|
||||
thd_info->host= thd->strdup(thd->host_or_ip);
|
||||
thd_info->host= thd->strdup(tmp->host_or_ip);
|
||||
if ((thd_info->db=tmp->db)) // Safe test
|
||||
thd_info->db=thd->strdup(thd_info->db);
|
||||
thd_info->command=(int) tmp->command;
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "sql_acl.h"
|
||||
#include "sql_select.h"
|
||||
|
||||
static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields);
|
||||
|
||||
/* Return 0 if row hasn't changed */
|
||||
|
||||
static bool compare_record(TABLE *table, ulong query_id)
|
||||
@ -547,11 +549,12 @@ int multi_update::prepare(List<Item> ¬_used_values, SELECT_LEX_UNIT *unit)
|
||||
|
||||
|
||||
/*
|
||||
Store first used table in main_table as this should be updated first
|
||||
This is because we know that no row in this table will be read twice.
|
||||
Initialize table for multi table
|
||||
|
||||
Create temporary tables to store changed values for all other tables
|
||||
that are updated.
|
||||
IMPLEMENTATION
|
||||
- Update first table in join on the fly, if possible
|
||||
- Create temporary tables to store changed values for all other tables
|
||||
that are updated (and main_table if the above doesn't hold).
|
||||
*/
|
||||
|
||||
bool
|
||||
@ -565,53 +568,113 @@ multi_update::initialize_tables(JOIN *join)
|
||||
main_table=join->join_tab->table;
|
||||
trans_safe= transactional_tables= main_table->file->has_transactions();
|
||||
log_delayed= trans_safe || main_table->tmp_table != NO_TMP_TABLE;
|
||||
table_to_update= (main_table->file->table_flags() & HA_NOT_MULTI_UPDATE) ?
|
||||
(TABLE *) 0 : main_table;
|
||||
/* Create a temporary table for all tables after except main table */
|
||||
table_to_update= 0;
|
||||
|
||||
/* Create a temporary table for keys to all tables, except main table */
|
||||
for (table_ref= update_tables; table_ref; table_ref=table_ref->next)
|
||||
{
|
||||
TABLE *table=table_ref->table;
|
||||
if (table != table_to_update)
|
||||
uint cnt= table_ref->shared;
|
||||
List<Item> temp_fields= *fields_for_table[cnt];
|
||||
ORDER group;
|
||||
|
||||
if (table == main_table) // First table in join
|
||||
{
|
||||
uint cnt= table_ref->shared;
|
||||
ORDER group;
|
||||
List<Item> temp_fields= *fields_for_table[cnt];
|
||||
TMP_TABLE_PARAM *tmp_param= tmp_table_param+cnt;
|
||||
|
||||
/*
|
||||
Create a temporary table to store all fields that are changed for this
|
||||
table. The first field in the temporary table is a pointer to the
|
||||
original row so that we can find and update it
|
||||
*/
|
||||
|
||||
/* ok to be on stack as this is not referenced outside of this func */
|
||||
Field_string offset(table->file->ref_length, 0, "offset",
|
||||
table, &my_charset_bin);
|
||||
if (temp_fields.push_front(new Item_field(((Field *) &offset))))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
/* Make an unique key over the first field to avoid duplicated updates */
|
||||
bzero((char*) &group, sizeof(group));
|
||||
group.asc= 1;
|
||||
group.item= (Item**) temp_fields.head_ref();
|
||||
|
||||
tmp_param->quick_group=1;
|
||||
tmp_param->field_count=temp_fields.elements;
|
||||
tmp_param->group_parts=1;
|
||||
tmp_param->group_length= table->file->ref_length;
|
||||
if (!(tmp_tables[cnt]=create_tmp_table(thd,
|
||||
tmp_param,
|
||||
temp_fields,
|
||||
(ORDER*) &group, 0, 0,
|
||||
TMP_TABLE_ALL_COLUMNS,
|
||||
HA_POS_ERROR)))
|
||||
DBUG_RETURN(1);
|
||||
tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
if (safe_update_on_fly(join->join_tab, &temp_fields))
|
||||
{
|
||||
table_to_update= main_table; // Update table on the fly
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
TMP_TABLE_PARAM *tmp_param= tmp_table_param+cnt;
|
||||
|
||||
/*
|
||||
Create a temporary table to store all fields that are changed for this
|
||||
table. The first field in the temporary table is a pointer to the
|
||||
original row so that we can find and update it
|
||||
*/
|
||||
|
||||
/* ok to be on stack as this is not referenced outside of this func */
|
||||
Field_string offset(table->file->ref_length, 0, "offset",
|
||||
table, 1, &my_charset_bin);
|
||||
if (temp_fields.push_front(new Item_field(((Field *) &offset))))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
/* Make an unique key over the first field to avoid duplicated updates */
|
||||
bzero((char*) &group, sizeof(group));
|
||||
group.asc= 1;
|
||||
group.item= (Item**) temp_fields.head_ref();
|
||||
|
||||
tmp_param->quick_group=1;
|
||||
tmp_param->field_count=temp_fields.elements;
|
||||
tmp_param->group_parts=1;
|
||||
tmp_param->group_length= table->file->ref_length;
|
||||
if (!(tmp_tables[cnt]=create_tmp_table(thd,
|
||||
tmp_param,
|
||||
temp_fields,
|
||||
(ORDER*) &group, 0, 0,
|
||||
TMP_TABLE_ALL_COLUMNS,
|
||||
HA_POS_ERROR)))
|
||||
DBUG_RETURN(1);
|
||||
tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
Check if table is safe to update on fly
|
||||
|
||||
SYNOPSIS
|
||||
safe_update_on_fly
|
||||
join_tab How table is used in join
|
||||
fields Fields that are updated
|
||||
|
||||
NOTES
|
||||
We can update the first table in join on the fly if we know that
|
||||
a row in this tabel will never be read twice. This is true under
|
||||
the folloing conditions:
|
||||
|
||||
- We are doing a table scan and the data is in a separate file (MyISAM) or
|
||||
if we don't update a clustered key.
|
||||
|
||||
- We are doing a range scan and we don't update the scan key or
|
||||
the primary key for a clustered table handler.
|
||||
|
||||
WARNING
|
||||
This code is a bit dependent of how make_join_readinfo() works.
|
||||
|
||||
RETURN
|
||||
0 Not safe to update
|
||||
1 Safe to update
|
||||
*/
|
||||
|
||||
static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
|
||||
{
|
||||
TABLE *table= join_tab->table;
|
||||
switch (join_tab->type) {
|
||||
case JT_SYSTEM:
|
||||
case JT_CONST:
|
||||
case JT_EQ_REF:
|
||||
return 1; // At most one matching row
|
||||
case JT_REF:
|
||||
return !check_if_key_used(table, join_tab->ref.key, *fields);
|
||||
case JT_ALL:
|
||||
/* If range search on index */
|
||||
if (join_tab->quick)
|
||||
return !check_if_key_used(table, join_tab->quick->index,
|
||||
*fields);
|
||||
/* If scanning in clustered key */
|
||||
if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
|
||||
table->primary_key < MAX_KEY)
|
||||
return !check_if_key_used(table, table->primary_key, *fields);
|
||||
return 1;
|
||||
default:
|
||||
break; // Avoid compler warning
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
multi_update::~multi_update()
|
||||
{
|
||||
|
@ -283,6 +283,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
||||
%token MAX_UPDATES_PER_HOUR
|
||||
%token MEDIUM_SYM
|
||||
%token MERGE_SYM
|
||||
%token MEMORY_SYM
|
||||
%token MIN_ROWS
|
||||
%token MYISAM_SYM
|
||||
%token NAMES_SYM
|
||||
@ -1009,6 +1010,7 @@ table_types:
|
||||
| MYISAM_SYM { $$= DB_TYPE_MYISAM; }
|
||||
| MERGE_SYM { $$= DB_TYPE_MRG_MYISAM; }
|
||||
| HEAP_SYM { $$= DB_TYPE_HEAP; }
|
||||
| MEMORY_SYM { $$= DB_TYPE_HEAP; }
|
||||
| BERKELEY_DB_SYM { $$= DB_TYPE_BERKELEY_DB; }
|
||||
| INNOBASE_SYM { $$= DB_TYPE_INNODB; };
|
||||
|
||||
@ -4088,6 +4090,7 @@ keyword:
|
||||
| MAX_UPDATES_PER_HOUR {}
|
||||
| MEDIUM_SYM {}
|
||||
| MERGE_SYM {}
|
||||
| MEMORY_SYM {}
|
||||
| MINUTE_SYM {}
|
||||
| MIN_ROWS {}
|
||||
| MODIFY_SYM {}
|
||||
|
@ -1245,7 +1245,7 @@ bool check_table_name(const char *name, uint length)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (*name == '/' || *name == FN_LIBCHAR || *name == FN_EXTCHAR)
|
||||
if (*name == '/' || *name == '\\' || *name == FN_EXTCHAR)
|
||||
return 1;
|
||||
name++;
|
||||
}
|
||||
|
@ -35,6 +35,8 @@
|
||||
it can be compiled with the UNSIGNED and/or LONGLONG flag set
|
||||
*/
|
||||
|
||||
#define strtoll glob_strtoll /* Fix for True64 */
|
||||
|
||||
#include <my_global.h>
|
||||
#include "m_string.h"
|
||||
#include "m_ctype.h"
|
||||
|
Loading…
x
Reference in New Issue
Block a user