summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <monty@narttu.mysql.fi>2003-03-19 22:25:44 +0200
committerunknown <monty@narttu.mysql.fi>2003-03-19 22:25:44 +0200
commit161942e3cefd8923633e0a7b3b7a9860a95f6fbc (patch)
treeabbee7d78d1399086c301a5bd02f3ba4a9e1ea38
parentd7bedeb998c911c921d7b67dc07049955481d9b7 (diff)
parent7517a59a6dac4580b1f7b5cf87abf6d75b096bbc (diff)
downloadmariadb-git-161942e3cefd8923633e0a7b3b7a9860a95f6fbc.tar.gz
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
-rw-r--r--Docs/internals.texi19
-rw-r--r--client/mysql.cc3
-rw-r--r--client/password.c191
-rw-r--r--include/Makefile.am2
-rw-r--r--include/my_dbug.h (renamed from include/dbug.h)0
-rw-r--r--include/my_global.h2
-rw-r--r--include/mysql_com.h2
-rw-r--r--innobase/row/row0mysql.c2
-rw-r--r--libmysql/Makefile.am8
-rw-r--r--libmysql/get_password.c1
-rwxr-xr-xlibmysql/password.c0
-rw-r--r--libmysqld/Makefile.am4
-rw-r--r--libmysqld/lib_vio.c1
-rw-r--r--mysql-test/r/create.result23
-rw-r--r--mysql-test/r/heap.result2
-rw-r--r--mysql-test/r/innodb.result112
-rw-r--r--mysql-test/r/multi_update.result64
-rw-r--r--mysql-test/r/rpl_relayspace.result13
-rw-r--r--mysql-test/t/create.test15
-rw-r--r--mysql-test/t/heap.test2
-rw-r--r--mysql-test/t/innodb.test73
-rw-r--r--mysql-test/t/multi_update.test28
-rw-r--r--mysql-test/t/rpl_relayspace-slave.opt1
-rw-r--r--mysql-test/t/rpl_relayspace.test33
-rw-r--r--sql/ha_innodb.h3
-rw-r--r--sql/ha_myisam.cc30
-rw-r--r--sql/handler.cc9
-rw-r--r--sql/handler.h1
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/key.cc8
-rw-r--r--sql/lex.h1
-rw-r--r--sql/log.cc2
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/password.c12
-rw-r--r--sql/slave.cc60
-rw-r--r--sql/slave.h7
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_crypt.cc6
-rw-r--r--sql/sql_parse.cc3
-rw-r--r--sql/sql_repl.cc8
-rw-r--r--sql/sql_show.cc4
-rw-r--r--sql/sql_update.cc147
-rw-r--r--sql/sql_yacc.yy3
-rw-r--r--sql/table.cc2
-rw-r--r--strings/strto.c2
45 files changed, 624 insertions, 291 deletions
diff --git a/Docs/internals.texi b/Docs/internals.texi
index 97256d49db6..803eae007df 100644
--- a/Docs/internals.texi
+++ b/Docs/internals.texi
@@ -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}
diff --git a/client/mysql.cc b/client/mysql.cc
index 9e49a6eab2c..32655d1ccd9 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -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));
}
diff --git a/client/password.c b/client/password.c
deleted file mode 100644
index 9b154603b98..00000000000
--- a/client/password.c
+++ /dev/null
@@ -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;
-}
diff --git a/include/Makefile.am b/include/Makefile.am
index 70049a061ff..7372d3ab417 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -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 \
diff --git a/include/dbug.h b/include/my_dbug.h
index 5c88e2e42db..5c88e2e42db 100644
--- a/include/dbug.h
+++ b/include/my_dbug.h
diff --git a/include/my_global.h b/include/my_global.h
index 30785d6a9b6..40cd748699b 100644
--- a/include/my_global.h
+++ b/include/my_global.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 */
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 7eac3b113d2..7a12413bc23 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -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);
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 7cef63d1337..1bb33551da8 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -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
diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am
index 1d5a5b19180..c366c034154 100644
--- a/libmysql/Makefile.am
+++ b/libmysql/Makefile.am
@@ -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
#
diff --git a/libmysql/get_password.c b/libmysql/get_password.c
index 53eeb1080ce..e6221ea556e 100644
--- a/libmysql/get_password.c
+++ b/libmysql/get_password.c
@@ -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
diff --git a/libmysql/password.c b/libmysql/password.c
deleted file mode 100755
index e69de29bb2d..00000000000
--- a/libmysql/password.c
+++ /dev/null
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index daf65cb2f80..b36f8d92490 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -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\
diff --git a/libmysqld/lib_vio.c b/libmysqld/lib_vio.c
index 3f89c544ce9..14c1366e5f9 100644
--- a/libmysqld/lib_vio.c
+++ b/libmysqld/lib_vio.c
@@ -33,7 +33,6 @@
#include <violite.h>
#include <my_net.h>
#include <m_string.h>
-#include <dbug.h>
#include <assert.h>
#ifndef __WIN__
diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index e061a78304f..136b7272c1d 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -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;
diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result
index ffd62ceabb6..76022b66100 100644
--- a/mysql-test/r/heap.result
+++ b/mysql-test/r/heap.result
@@ -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;
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index fd80ef785ea..df33af0709c 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -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;
diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result
index 4dbb3c8adb1..da1c429df63 100644
--- a/mysql-test/r/multi_update.result
+++ b/mysql-test/r/multi_update.result
@@ -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;
diff --git a/mysql-test/r/rpl_relayspace.result b/mysql-test/r/rpl_relayspace.result
new file mode 100644
index 00000000000..5e552ef7400
--- /dev/null
+++ b/mysql-test/r/rpl_relayspace.result
@@ -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
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index 98d76bf2883..cda9307804b 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -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;
diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test
index cd5dbd5afbe..22d9e57a574 100644
--- a/mysql-test/t/heap.test
+++ b/mysql-test/t/heap.test
@@ -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;
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index 95a690e56b7..bfaeee78f8e 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -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;
diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test
index 6156da82ec0..390dd58d806 100644
--- a/mysql-test/t/multi_update.test
+++ b/mysql-test/t/multi_update.test
@@ -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;
diff --git a/mysql-test/t/rpl_relayspace-slave.opt b/mysql-test/t/rpl_relayspace-slave.opt
new file mode 100644
index 00000000000..9365a2a0a26
--- /dev/null
+++ b/mysql-test/t/rpl_relayspace-slave.opt
@@ -0,0 +1 @@
+ -O relay_log_space_limit=1024 \ No newline at end of file
diff --git a/mysql-test/t/rpl_relayspace.test b/mysql-test/t/rpl_relayspace.test
new file mode 100644
index 00000000000..8d4f01339c7
--- /dev/null
+++ b/mysql-test/t/rpl_relayspace.test
@@ -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;
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 55832c0a079..56546e3e8d0 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -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)
{
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 829ec5b0ade..126d0628f79 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -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;
diff --git a/sql/handler.cc b/sql/handler.cc
index d7ae960382c..5353e78cd11 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -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);
diff --git a/sql/handler.h b/sql/handler.h
index 824f02b5a3d..c6a4578a26c 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -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
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 81ea91c5c3d..9abbb0e290b 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -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()
diff --git a/sql/key.cc b/sql/key.cc
index feda9e156b3..37ef6339f20 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -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;
}
diff --git a/sql/lex.h b/sql/lex.h
index 80f84628d27..5b1cbb58c1e 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -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},
diff --git a/sql/log.cc b/sql/log.cc
index 02e34b773ef..00bd44274f9 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -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);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index c0a3527bc75..e9026eb5b00 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -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);
diff --git a/sql/password.c b/sql/password.c
index 5ed05ae6c0e..9752bcc95eb 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -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)
{
diff --git a/sql/slave.cc b/sql/slave.cc
index 61348722d1e..c66f5c307d4 100644
--- a/sql/slave.cc
+++ b/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;
}
/*
diff --git a/sql/slave.h b/sql/slave.h
index 0ebd07bf6d8..a4db7388be5 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -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
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 022a31e7b5c..3a66e906837 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -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);
}
diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc
index f2e4a8934be..930ecfffef7 100644
--- a/sql/sql_crypt.cc
+++ b/sql/sql_crypt.cc
@@ -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++;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 3b27a65f4e1..8ca5bf2f12d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -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);
}
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 63ba519885f..98bbd8bbb98 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -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,
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index db4de2962b7..ba7d7024eaf 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -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;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index d07b4f1a8d5..e5c9d160725 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -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> &not_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;
- 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);
+ uint cnt= table_ref->shared;
+ List<Item> temp_fields= *fields_for_table[cnt];
+ ORDER group;
- /* 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 (table == main_table) // First table in join
+ {
+ 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()
{
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index fe420549a59..e66e896c590 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -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 {}
diff --git a/sql/table.cc b/sql/table.cc
index 58375ecdbeb..b36171cab93 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -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++;
}
diff --git a/strings/strto.c b/strings/strto.c
index 6f12656cb20..0c215ff270c 100644
--- a/strings/strto.c
+++ b/strings/strto.c
@@ -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"