Merge with 4.0.12
This commit is contained in:
commit
b883a9c01c
@ -2798,11 +2798,11 @@ Storage: same as TINYINT.
|
|||||||
@strong{DATE}
|
@strong{DATE}
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@item
|
||||||
Storage: fixed-length series of binary integers, always three bytes
|
Storage: 3 byte integer, low byte first.
|
||||||
long.
|
Packed as: 'day + month*32 + year*16*32'
|
||||||
@item
|
@item
|
||||||
Example: a DATE column containing '0001-01-01' looks like:@*
|
Example: a DATE column containing '1962-01-02' looks like:@*
|
||||||
@code{hexadecimal 21 02 00}
|
@code{hexadecimal 22 54 0F}
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@strong{DATETIME}
|
@strong{DATETIME}
|
||||||
@ -2821,16 +2821,19 @@ Example: a DATETIME column for '0001-01-01 01:01:01' looks like:@*
|
|||||||
@strong{TIME}
|
@strong{TIME}
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@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
|
@item
|
||||||
Example: a TIME column containing '01:01:01' looks like:@*
|
Example: a TIME column containing '1 02:03:04' (1 day 2 hour 3 minutes and 4 seconds) looks like:@*
|
||||||
@code{hexadecimal 75 27 00}
|
@code{hexadecimal 58 6E 01}
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@strong{TIMESTAMP}
|
@strong{TIMESTAMP}
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@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
|
@item
|
||||||
Example: a TIMESTAMP column containing '2003-01-01 01:01:01' looks like:@*
|
Example: a TIMESTAMP column containing '2003-01-01 01:01:01' looks like:@*
|
||||||
@code{hexadecimal 4D AE 12 23}
|
@code{hexadecimal 4D AE 12 23}
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <violite.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 */
|
/* Don't try to make a nice table if the data is too big */
|
||||||
#define MAX_COLUMN_LENGTH 1024
|
#define MAX_COLUMN_LENGTH 1024
|
||||||
@ -799,6 +799,7 @@ static int get_options(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
if (argc == 1)
|
if (argc == 1)
|
||||||
{
|
{
|
||||||
|
skip_updates= 0;
|
||||||
my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
|
my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
|
||||||
current_db= my_strdup(*argv, MYF(MY_WME));
|
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
|
# MA 02111-1307, USA
|
||||||
|
|
||||||
BUILT_SOURCES = mysql_version.h m_ctype.h my_config.h
|
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 \
|
mysql.h mysql_com.h mysqld_error.h mysql_embed.h \
|
||||||
my_semaphore.h my_pthread.h my_no_pthread.h raid.h \
|
my_semaphore.h my_pthread.h my_no_pthread.h raid.h \
|
||||||
errmsg.h my_global.h my_net.h my_alloc.h \
|
errmsg.h my_global.h my_net.h my_alloc.h \
|
||||||
|
@ -417,7 +417,7 @@ typedef unsigned short ushort;
|
|||||||
#define DBUG_OFF
|
#define DBUG_OFF
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <dbug.h>
|
#include <my_dbug.h>
|
||||||
|
|
||||||
#define MIN_ARRAY_SIZE 0 /* Zero or One. Gcc allows zero*/
|
#define MIN_ARRAY_SIZE 0 /* Zero or One. Gcc allows zero*/
|
||||||
#define ASCII_BITS_USED 8 /* Bit char used */
|
#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,
|
void randominit(struct rand_struct *,unsigned long seed1,
|
||||||
unsigned long seed2);
|
unsigned long seed2);
|
||||||
double rnd(struct rand_struct *);
|
double my_rnd(struct rand_struct *);
|
||||||
void make_scrambled_password(char *to,const char *password,
|
void make_scrambled_password(char *to,const char *password,
|
||||||
my_bool force_old_scramble,struct rand_struct *rand_st);
|
my_bool force_old_scramble,struct rand_struct *rand_st);
|
||||||
int get_password_length(my_bool force_old_scramble);
|
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
|
Created 9/17/2000 Heikki Tuuri
|
||||||
*******************************************************/
|
*******************************************************/
|
||||||
|
|
||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
|
|
||||||
#ifdef UNIV_NONINL
|
#ifdef UNIV_NONINL
|
||||||
|
@ -48,10 +48,6 @@ link_sources:
|
|||||||
rm -f $(srcdir)/$$f; \
|
rm -f $(srcdir)/$$f; \
|
||||||
@LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \
|
@LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \
|
||||||
done; \
|
done; \
|
||||||
for f in $$qs; do \
|
|
||||||
rm -f $(srcdir)/$$f; \
|
|
||||||
@LN_CP_F@ $(srcdir)/../sql/$$f $(srcdir)/$$f; \
|
|
||||||
done; \
|
|
||||||
for f in $$ds; do \
|
for f in $$ds; do \
|
||||||
rm -f $(srcdir)/$$f; \
|
rm -f $(srcdir)/$$f; \
|
||||||
@LN_CP_F@ $(srcdir)/../dbug/$$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; \
|
@LN_CP_F@ $(srcdir)/../mysys/$$f $(srcdir)/$$f; \
|
||||||
done; \
|
done; \
|
||||||
rm -f $(srcdir)/net.c; \
|
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
|
# This part requires GNUmake
|
||||||
#
|
#
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "mysql.h"
|
#include "mysql.h"
|
||||||
#include <m_string.h>
|
#include <m_string.h>
|
||||||
#include <m_ctype.h>
|
#include <m_ctype.h>
|
||||||
#include <dbug.h>
|
|
||||||
|
|
||||||
#if defined(HAVE_BROKEN_GETPASS) && !defined(HAVE_GETPASSPHRASE)
|
#if defined(HAVE_BROKEN_GETPASS) && !defined(HAVE_GETPASSPHRASE)
|
||||||
#undef HAVE_GETPASS
|
#undef HAVE_GETPASS
|
||||||
|
@ -32,14 +32,14 @@ noinst_LIBRARIES = libmysqld_int.a
|
|||||||
pkglib_LIBRARIES = libmysqld.a
|
pkglib_LIBRARIES = libmysqld.a
|
||||||
SUBDIRS = . examples
|
SUBDIRS = . examples
|
||||||
libmysqld_sources= libmysqld.c lib_sql.cc
|
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
|
noinst_HEADERS = embedded_priv.h
|
||||||
|
|
||||||
sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \
|
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_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 \
|
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.cc item_buff.cc item_cmpfunc.cc item_create.cc \
|
||||||
item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \
|
item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \
|
||||||
item_uniq.cc item_subselect.cc item_row.cc\
|
item_uniq.cc item_subselect.cc item_row.cc\
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#include <violite.h>
|
#include <violite.h>
|
||||||
#include <my_net.h>
|
#include <my_net.h>
|
||||||
#include <m_string.h>
|
#include <m_string.h>
|
||||||
#include <dbug.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#ifndef __WIN__
|
#ifndef __WIN__
|
||||||
|
@ -253,3 +253,26 @@ Incorrect table name 'a/a'
|
|||||||
drop table t1, t2, t3;
|
drop table t1, t2, t3;
|
||||||
drop table t3;
|
drop table t3;
|
||||||
drop database test_$1;
|
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
|
4 6
|
||||||
alter table t1 add c int not null, add key (c,a);
|
alter table t1 add c int not null, add key (c,a);
|
||||||
drop table t1;
|
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);
|
insert into t1 values(1,1),(2,2),(3,3),(4,4);
|
||||||
delete from t1 where a > 0;
|
delete from t1 where a > 0;
|
||||||
select * from t1;
|
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;
|
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');
|
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;
|
select id, code, name from t1 order by id;
|
||||||
@ -1093,3 +1093,113 @@ SELECT * from t1;
|
|||||||
id
|
id
|
||||||
3
|
3
|
||||||
DROP TABLE t1,t2;
|
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 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;
|
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;
|
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 table t3;
|
||||||
drop database test_$1;
|
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);
|
alter table t1 add c int not null, add key (c,a);
|
||||||
drop table t1;
|
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);
|
insert into t1 values(1,1),(2,2),(3,3),(4,4);
|
||||||
delete from t1 where a > 0;
|
delete from t1 where a > 0;
|
||||||
select * from t1;
|
select * from t1;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
--disable_warnings
|
--disable_warnings
|
||||||
drop table if exists t1,t2;
|
drop table if exists t1,t2,t3;
|
||||||
--enable_warnings
|
--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;
|
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;
|
UPDATE t1,t2 SET t1.id=t1.id+1 where t1.id!=t2.id;
|
||||||
SELECT * from t1;
|
SELECT * from t1;
|
||||||
DROP TABLE t1,t2;
|
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 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;
|
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;
|
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_PRIMARY_KEY_IN_READ_INDEX |
|
||||||
HA_DROP_BEFORE_CREATE |
|
HA_DROP_BEFORE_CREATE |
|
||||||
HA_NO_PREFIX_CHAR_KEYS |
|
HA_NO_PREFIX_CHAR_KEYS |
|
||||||
HA_TABLE_SCAN_ON_INDEX |
|
HA_TABLE_SCAN_ON_INDEX),
|
||||||
HA_NOT_MULTI_UPDATE),
|
|
||||||
last_dup_key((uint) -1),
|
last_dup_key((uint) -1),
|
||||||
start_of_scan(0)
|
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,
|
ha_rows ha_myisam::records_in_range(int inx,
|
||||||
const byte *start_key,uint start_key_len,
|
const byte *start_key,uint start_key_len,
|
||||||
enum ha_rkey_function start_search_flag,
|
enum ha_rkey_function start_search_flag,
|
||||||
@ -1272,6 +1301,7 @@ ha_rows ha_myisam::records_in_range(int inx,
|
|||||||
end_search_flag);
|
end_search_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ha_myisam::ft_read(byte * buf)
|
int ha_myisam::ft_read(byte * buf)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
@ -121,8 +121,15 @@ handler *get_new_handler(TABLE *table, enum db_type db_type)
|
|||||||
#endif
|
#endif
|
||||||
case DB_TYPE_HEAP:
|
case DB_TYPE_HEAP:
|
||||||
return new ha_heap(table);
|
return new ha_heap(table);
|
||||||
case DB_TYPE_MYISAM:
|
|
||||||
default: // should never happen
|
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);
|
return new ha_myisam(table);
|
||||||
case DB_TYPE_MRG_MYISAM:
|
case DB_TYPE_MRG_MYISAM:
|
||||||
return new ha_myisammrg(table);
|
return new ha_myisammrg(table);
|
||||||
|
@ -67,7 +67,6 @@
|
|||||||
#define HA_CAN_FULLTEXT (HA_NO_PREFIX_CHAR_KEYS*2)
|
#define HA_CAN_FULLTEXT (HA_NO_PREFIX_CHAR_KEYS*2)
|
||||||
#define HA_CAN_SQL_HANDLER (HA_CAN_FULLTEXT*2)
|
#define HA_CAN_SQL_HANDLER (HA_CAN_FULLTEXT*2)
|
||||||
#define HA_NO_AUTO_INCREMENT (HA_CAN_SQL_HANDLER*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
|
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()
|
double Item_func_rand::val()
|
||||||
{
|
{
|
||||||
return rnd(rand);
|
return my_rnd(rand);
|
||||||
}
|
}
|
||||||
|
|
||||||
longlong Item_func_sign::val_int()
|
longlong Item_func_sign::val_int()
|
||||||
|
@ -271,5 +271,13 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields)
|
|||||||
return 1;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -257,6 +257,7 @@ static SYMBOL symbols[] = {
|
|||||||
{ "MEDIUMINT", SYM(MEDIUMINT),0,0},
|
{ "MEDIUMINT", SYM(MEDIUMINT),0,0},
|
||||||
{ "MERGE", SYM(MERGE_SYM),0,0},
|
{ "MERGE", SYM(MERGE_SYM),0,0},
|
||||||
{ "MEDIUM", SYM(MEDIUM_SYM),0,0},
|
{ "MEDIUM", SYM(MEDIUM_SYM),0,0},
|
||||||
|
{ "MEMORY", SYM(MEMORY_SYM),0,0},
|
||||||
{ "MIDDLEINT", SYM(MEDIUMINT),0,0}, /* For powerbuilder */
|
{ "MIDDLEINT", SYM(MEDIUMINT),0,0}, /* For powerbuilder */
|
||||||
{ "MIN_ROWS", SYM(MIN_ROWS),0,0},
|
{ "MIN_ROWS", SYM(MIN_ROWS),0,0},
|
||||||
{ "MINUTE", SYM(MINUTE_SYM),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);
|
pthread_mutex_lock(&rli->log_space_lock);
|
||||||
rli->log_space_total -= rli->relay_log_pos;
|
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_mutex_unlock(&rli->log_space_lock);
|
||||||
pthread_cond_broadcast(&rli->log_space_cond);
|
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;
|
max_used_connections=thread_count-delayed_insert_threads;
|
||||||
thd->thread_id=thread_id++;
|
thd->thread_id=thread_id++;
|
||||||
for (uint i=0; i < 8 ; i++) // Generate password teststring
|
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;
|
thd->scramble[8]=0;
|
||||||
// Back it up as old clients may need it
|
// Back it up as old clients may need it
|
||||||
memcpy(thd->old_scramble,thd->scramble,9);
|
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
|
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->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;
|
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' :
|
return (uint) (X >= '0' && X <= '9' ? X-'0' :
|
||||||
X >= 'A' && X <= 'Z' ? X-'A'+10 :
|
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],
|
randominit(&rand_st,hash_pass[0] ^ hash_message[0],
|
||||||
hash_pass[1] ^ hash_message[1]);
|
hash_pass[1] ^ hash_message[1]);
|
||||||
while (*msg++)
|
while (*msg++)
|
||||||
*to++= (char) (floor(rnd(&rand_st)*31)+64);
|
*to++= (char) (floor(my_rnd(&rand_st)*31)+64);
|
||||||
if (!old_ver)
|
if (!old_ver)
|
||||||
{ /* Make it harder to break */
|
{ /* 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)
|
while (to_start != to)
|
||||||
*(to_start++)^=extra;
|
*(to_start++)^=extra;
|
||||||
}
|
}
|
||||||
@ -711,11 +711,11 @@ my_bool check_scramble(const char *scrambled, const char *message,
|
|||||||
hash_pass[1] ^ hash_message[1]);
|
hash_pass[1] ^ hash_message[1]);
|
||||||
to=buff;
|
to=buff;
|
||||||
for (pos=scrambled ; *pos ; pos++)
|
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)
|
if (old_ver)
|
||||||
extra=0;
|
extra=0;
|
||||||
else
|
else
|
||||||
extra=(char) (floor(rnd(&rand_st)*31));
|
extra=(char) (floor(my_rnd(&rand_st)*31));
|
||||||
to=buff;
|
to=buff;
|
||||||
while (*scrambled)
|
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 (log) // If not first log
|
||||||
{
|
{
|
||||||
if (strcmp(log, rli->linfo.log_file_name))
|
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))
|
if (rli->relay_log.find_log_pos(&rli->linfo, log, 1))
|
||||||
{
|
{
|
||||||
*errmsg="Could not find target log during relay log initialization";
|
*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);
|
my_b_seek(rli->cur_log,(off_t)pos);
|
||||||
|
|
||||||
err:
|
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);
|
pthread_cond_broadcast(&rli->data_cond);
|
||||||
if (need_data_lock)
|
if (need_data_lock)
|
||||||
pthread_mutex_unlock(&rli->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";
|
thd->proc_info = "Waiting for relay log space to free";
|
||||||
|
|
||||||
while (rli->log_space_limit < rli->log_space_total &&
|
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);
|
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()
|
st_relay_log_info::st_relay_log_info()
|
||||||
:info_fd(-1), cur_log_fd(-1), master_log_pos(0), save_temporary_tables(0),
|
: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),
|
slave_skip_counter(0), abort_pos_wait(0), slave_run_id(0),
|
||||||
sql_thd(0), last_slave_errno(0), inited(0), abort_slave(0),
|
sql_thd(0), last_slave_errno(0), inited(0), abort_slave(0),
|
||||||
slave_running(0), skip_log_purge(0),
|
slave_running(0), skip_log_purge(0),
|
||||||
@ -2378,7 +2385,8 @@ reconnect done to recover from failed read");
|
|||||||
}
|
}
|
||||||
flush_master_info(mi);
|
flush_master_info(mi);
|
||||||
if (mi->rli.log_space_limit && mi->rli.log_space_limit <
|
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))
|
if (wait_for_relay_log_space(&mi->rli))
|
||||||
{
|
{
|
||||||
sql_print_error("Slave I/O thread aborted while waiting for relay \
|
sql_print_error("Slave I/O thread aborted while waiting for relay \
|
||||||
@ -2491,6 +2499,10 @@ slave_begin:
|
|||||||
pthread_cond_broadcast(&rli->start_cond);
|
pthread_cond_broadcast(&rli->start_cond);
|
||||||
// This should always be set to 0 when the slave thread is started
|
// This should always be set to 0 when the slave thread is started
|
||||||
rli->pending = 0;
|
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,
|
if (init_relay_log_pos(rli,
|
||||||
rli->relay_log_name,
|
rli->relay_log_name,
|
||||||
rli->relay_log_pos,
|
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
|
update. If we do not, show slave status will block
|
||||||
*/
|
*/
|
||||||
pthread_mutex_unlock(&rli->data_lock);
|
pthread_mutex_unlock(&rli->data_lock);
|
||||||
/* Note that wait_for_update unlocks lock_log ! */
|
|
||||||
rli->relay_log.wait_for_update(rli->sql_thd);
|
/*
|
||||||
|
Possible deadlock :
|
||||||
// re-acquire data lock since we released it earlier
|
- the I/O thread has reached log_space_limit
|
||||||
pthread_mutex_lock(&rli->data_lock);
|
- 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;
|
continue;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -156,7 +156,14 @@ typedef struct st_relay_log_info
|
|||||||
extra offset to be added to the position.
|
extra offset to be added to the position.
|
||||||
*/
|
*/
|
||||||
ulonglong relay_log_pos, pending;
|
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;
|
ulonglong log_space_limit,log_space_total;
|
||||||
|
bool ignore_log_space_limit;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
InnoDB internally stores the master log position it has processed
|
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);
|
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);
|
pthread_mutex_unlock(&LOCK_thread_count);
|
||||||
randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
|
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++)
|
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];
|
char a= decode_buff[idx];
|
||||||
decode_buff[idx]= decode_buff[i];
|
decode_buff[idx]= decode_buff[i];
|
||||||
decode_buff[+i]=a;
|
decode_buff[+i]=a;
|
||||||
@ -62,7 +62,7 @@ void SQL_CRYPT::encode(char *str,uint length)
|
|||||||
{
|
{
|
||||||
for (uint i=0; i < length; i++)
|
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];
|
uint idx= (uint) (uchar) str[0];
|
||||||
*str++ = (char) ((uchar) encode_buff[idx] ^ shift);
|
*str++ = (char) ((uchar) encode_buff[idx] ^ shift);
|
||||||
shift^= idx;
|
shift^= idx;
|
||||||
@ -74,7 +74,7 @@ void SQL_CRYPT::decode(char *str,uint length)
|
|||||||
{
|
{
|
||||||
for (uint i=0; i < length; i++)
|
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);
|
uint idx= (uint) ((unsigned char) str[0] ^ shift);
|
||||||
*str = decode_buff[idx];
|
*str = decode_buff[idx];
|
||||||
shift^= (uint) (uchar) *str++;
|
shift^= (uint) (uchar) *str++;
|
||||||
|
@ -563,7 +563,10 @@ check_connections(THD *thd)
|
|||||||
thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
|
thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
|
||||||
/* Cut very long hostnames to avoid possible overflows */
|
/* Cut very long hostnames to avoid possible overflows */
|
||||||
if (thd->host)
|
if (thd->host)
|
||||||
|
{
|
||||||
thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
|
thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
|
||||||
|
thd->host_or_ip= thd->host;
|
||||||
|
}
|
||||||
if (connect_errors > max_connect_errors)
|
if (connect_errors > max_connect_errors)
|
||||||
return(ER_HOST_IS_BLOCKED);
|
return(ER_HOST_IS_BLOCKED);
|
||||||
}
|
}
|
||||||
|
@ -900,22 +900,21 @@ int change_master(THD* thd, MASTER_INFO* mi)
|
|||||||
|
|
||||||
if (lex_mi->relay_log_name)
|
if (lex_mi->relay_log_name)
|
||||||
{
|
{
|
||||||
need_relay_log_purge = 0;
|
need_relay_log_purge= 0;
|
||||||
mi->rli.skip_log_purge=1;
|
|
||||||
strmake(mi->rli.relay_log_name,lex_mi->relay_log_name,
|
strmake(mi->rli.relay_log_name,lex_mi->relay_log_name,
|
||||||
sizeof(mi->rli.relay_log_name)-1);
|
sizeof(mi->rli.relay_log_name)-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lex_mi->relay_log_pos)
|
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;
|
mi->rli.relay_log_pos=lex_mi->relay_log_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
flush_master_info(mi);
|
flush_master_info(mi);
|
||||||
if (need_relay_log_purge)
|
if (need_relay_log_purge)
|
||||||
{
|
{
|
||||||
mi->rli.skip_log_purge=0;
|
mi->rli.skip_log_purge= 0;
|
||||||
thd->proc_info="purging old relay logs";
|
thd->proc_info="purging old relay logs";
|
||||||
if (purge_relay_logs(&mi->rli, thd,
|
if (purge_relay_logs(&mi->rli, thd,
|
||||||
0 /* not only reset, but also reinit */,
|
0 /* not only reset, but also reinit */,
|
||||||
@ -929,6 +928,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
const char* msg;
|
const char* msg;
|
||||||
|
mi->rli.skip_log_purge= 1;
|
||||||
/* Relay log is already initialized */
|
/* Relay log is already initialized */
|
||||||
if (init_relay_log_pos(&mi->rli,
|
if (init_relay_log_pos(&mi->rli,
|
||||||
mi->rli.relay_log_name,
|
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)))
|
if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1)))
|
||||||
my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
|
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
|
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
|
if ((thd_info->db=tmp->db)) // Safe test
|
||||||
thd_info->db=thd->strdup(thd_info->db);
|
thd_info->db=thd->strdup(thd_info->db);
|
||||||
thd_info->command=(int) tmp->command;
|
thd_info->command=(int) tmp->command;
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include "sql_acl.h"
|
#include "sql_acl.h"
|
||||||
#include "sql_select.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 */
|
/* Return 0 if row hasn't changed */
|
||||||
|
|
||||||
static bool compare_record(TABLE *table, ulong query_id)
|
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
|
Initialize table for multi table
|
||||||
This is because we know that no row in this table will be read twice.
|
|
||||||
|
|
||||||
Create temporary tables to store changed values for all other tables
|
IMPLEMENTATION
|
||||||
that are updated.
|
- 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
|
bool
|
||||||
@ -565,53 +568,113 @@ multi_update::initialize_tables(JOIN *join)
|
|||||||
main_table=join->join_tab->table;
|
main_table=join->join_tab->table;
|
||||||
trans_safe= transactional_tables= main_table->file->has_transactions();
|
trans_safe= transactional_tables= main_table->file->has_transactions();
|
||||||
log_delayed= trans_safe || main_table->tmp_table != NO_TMP_TABLE;
|
log_delayed= trans_safe || main_table->tmp_table != NO_TMP_TABLE;
|
||||||
table_to_update= (main_table->file->table_flags() & HA_NOT_MULTI_UPDATE) ?
|
table_to_update= 0;
|
||||||
(TABLE *) 0 : main_table;
|
|
||||||
/* Create a temporary table for all tables after except main table */
|
/* Create a temporary table for keys to all tables, except main table */
|
||||||
for (table_ref= update_tables; table_ref; table_ref=table_ref->next)
|
for (table_ref= update_tables; table_ref; table_ref=table_ref->next)
|
||||||
{
|
{
|
||||||
TABLE *table=table_ref->table;
|
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;
|
if (safe_update_on_fly(join->join_tab, &temp_fields))
|
||||||
ORDER group;
|
{
|
||||||
List<Item> temp_fields= *fields_for_table[cnt];
|
table_to_update= main_table; // Update table on the fly
|
||||||
TMP_TABLE_PARAM *tmp_param= tmp_table_param+cnt;
|
continue;
|
||||||
|
}
|
||||||
/*
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
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()
|
multi_update::~multi_update()
|
||||||
{
|
{
|
||||||
|
@ -283,6 +283,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
%token MAX_UPDATES_PER_HOUR
|
%token MAX_UPDATES_PER_HOUR
|
||||||
%token MEDIUM_SYM
|
%token MEDIUM_SYM
|
||||||
%token MERGE_SYM
|
%token MERGE_SYM
|
||||||
|
%token MEMORY_SYM
|
||||||
%token MIN_ROWS
|
%token MIN_ROWS
|
||||||
%token MYISAM_SYM
|
%token MYISAM_SYM
|
||||||
%token NAMES_SYM
|
%token NAMES_SYM
|
||||||
@ -1009,6 +1010,7 @@ table_types:
|
|||||||
| MYISAM_SYM { $$= DB_TYPE_MYISAM; }
|
| MYISAM_SYM { $$= DB_TYPE_MYISAM; }
|
||||||
| MERGE_SYM { $$= DB_TYPE_MRG_MYISAM; }
|
| MERGE_SYM { $$= DB_TYPE_MRG_MYISAM; }
|
||||||
| HEAP_SYM { $$= DB_TYPE_HEAP; }
|
| HEAP_SYM { $$= DB_TYPE_HEAP; }
|
||||||
|
| MEMORY_SYM { $$= DB_TYPE_HEAP; }
|
||||||
| BERKELEY_DB_SYM { $$= DB_TYPE_BERKELEY_DB; }
|
| BERKELEY_DB_SYM { $$= DB_TYPE_BERKELEY_DB; }
|
||||||
| INNOBASE_SYM { $$= DB_TYPE_INNODB; };
|
| INNOBASE_SYM { $$= DB_TYPE_INNODB; };
|
||||||
|
|
||||||
@ -4088,6 +4090,7 @@ keyword:
|
|||||||
| MAX_UPDATES_PER_HOUR {}
|
| MAX_UPDATES_PER_HOUR {}
|
||||||
| MEDIUM_SYM {}
|
| MEDIUM_SYM {}
|
||||||
| MERGE_SYM {}
|
| MERGE_SYM {}
|
||||||
|
| MEMORY_SYM {}
|
||||||
| MINUTE_SYM {}
|
| MINUTE_SYM {}
|
||||||
| MIN_ROWS {}
|
| MIN_ROWS {}
|
||||||
| MODIFY_SYM {}
|
| MODIFY_SYM {}
|
||||||
|
@ -1245,7 +1245,7 @@ bool check_table_name(const char *name, uint length)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (*name == '/' || *name == FN_LIBCHAR || *name == FN_EXTCHAR)
|
if (*name == '/' || *name == '\\' || *name == FN_EXTCHAR)
|
||||||
return 1;
|
return 1;
|
||||||
name++;
|
name++;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
it can be compiled with the UNSIGNED and/or LONGLONG flag set
|
it can be compiled with the UNSIGNED and/or LONGLONG flag set
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define strtoll glob_strtoll /* Fix for True64 */
|
||||||
|
|
||||||
#include <my_global.h>
|
#include <my_global.h>
|
||||||
#include "m_string.h"
|
#include "m_string.h"
|
||||||
#include "m_ctype.h"
|
#include "m_ctype.h"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user