summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore3
-rw-r--r--include/my_alloc.h3
-rw-r--r--libmysql/libmysql.c1
-rw-r--r--myisam/mi_page.c4
-rw-r--r--mysql-test/r/multi_update.result27
-rw-r--r--mysql-test/r/rpl000007.result20
-rw-r--r--mysql-test/r/rpl_replicate_do.result28
-rw-r--r--mysql-test/r/rpl_rotate_logs.result3
-rw-r--r--mysql-test/t/multi_update.test28
-rw-r--r--mysql-test/t/rpl000007-slave.opt1
-rw-r--r--mysql-test/t/rpl000007.test24
-rw-r--r--mysql-test/t/rpl_replicate_do-slave.opt1
-rw-r--r--mysql-test/t/rpl_replicate_do.test30
-rw-r--r--mysql-test/t/rpl_rotate_logs.test4
-rw-r--r--mysys/my_alloc.c15
-rw-r--r--sql/ha_innodb.cc1
-rw-r--r--sql/ha_myisam.cc2
-rw-r--r--sql/lex.h1
-rw-r--r--sql/lock.cc1
-rw-r--r--sql/mysql_priv.h11
-rw-r--r--sql/mysqld.cc11
-rw-r--r--sql/sql_base.cc124
-rw-r--r--sql/sql_class.cc80
-rw-r--r--sql/sql_class.h9
-rw-r--r--sql/sql_delete.cc30
-rw-r--r--sql/sql_insert.cc24
-rw-r--r--sql/sql_parse.cc136
-rw-r--r--sql/sql_update.cc31
-rw-r--r--sql/sql_yacc.yy136
29 files changed, 525 insertions, 264 deletions
diff --git a/.bzrignore b/.bzrignore
index d1ea6c7d70e..76725c4017e 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -497,3 +497,6 @@ vio/test-ssl
vio/test-sslclient
vio/test-sslserver
vio/viotest-ssl
+autom4te.cache/*
+bdb/dist/autom4te.cache/*
+innobase/autom4te.cache/*
diff --git a/include/my_alloc.h b/include/my_alloc.h
index 31f1fb7165f..a3dd35d7ea3 100644
--- a/include/my_alloc.h
+++ b/include/my_alloc.h
@@ -21,7 +21,8 @@
#ifndef _my_alloc_h
#define _my_alloc_h
-#define MAX_BLOCK_USAGE_BEFORE_DROP 10
+#define ALLOC_MAX_BLOCK_TO_DROP 4096
+#define ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP 10
typedef struct st_used_mem
{ /* struct for once_alloc (block) */
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index c9fb2f84a3c..c9a46eaf9ad 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -1524,6 +1524,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
#endif
init_sigpipe_variables
DBUG_ENTER("mysql_real_connect");
+ LINT_INIT(host_info);
DBUG_PRINT("enter",("host: %s db: %s user: %s",
host ? host : "(Null)",
diff --git a/myisam/mi_page.c b/myisam/mi_page.c
index 064e9239e73..1d40980e309 100644
--- a/myisam/mi_page.c
+++ b/myisam/mi_page.c
@@ -66,7 +66,9 @@ int _mi_write_keypage(register MI_INFO *info, register MI_KEYDEF *keyinfo,
page+keyinfo->block_length > info->state->key_file_length ||
(page & (MI_MIN_KEY_BLOCK_LENGTH-1)))
{
- DBUG_PRINT("error",("Trying to write inside key status region: %lu",
+ DBUG_PRINT("error",("Trying to write inside key status region: key_start: %lu length: %lu page: %lu",
+ (long) info->s->base.keystart,
+ (long) info->state->key_file_length,
(long) page));
my_errno=EINVAL;
return(-1);
diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result
index 9dff4fba825..ce3f7e90f6b 100644
--- a/mysql-test/r/multi_update.result
+++ b/mysql-test/r/multi_update.result
@@ -150,4 +150,29 @@ n n
delete t1,t2 from t2 left outer join t1 using (n);
select * from t2 left outer join t1 using (n);
n n
-drop table if exists t1,t2 ;
+drop table t1,t2 ;
+create table t1 (n int(10) not null primary key, d int(10));
+create table t2 (n int(10) not null primary key, d int(10));
+insert into t1 values(1,1);
+insert into t2 values(1,10),(2,20);
+LOCK TABLES t1 write, t2 read;
+DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n;
+Table 't2' was locked with a READ lock and can't be updated
+UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n;
+Table 't2' was locked with a READ lock and can't be updated
+UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n;
+Table 't2' was locked with a READ lock and can't be updated
+unlock tables;
+LOCK TABLES t1 write, t2 write;
+UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n;
+select * from t1;
+n d
+1 10
+DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n;
+select * from t1;
+n d
+select * from t2;
+n d
+2 20
+unlock tables;
+drop table t1,t2;
diff --git a/mysql-test/r/rpl000007.result b/mysql-test/r/rpl000007.result
deleted file mode 100644
index c2823bf1203..00000000000
--- a/mysql-test/r/rpl000007.result
+++ /dev/null
@@ -1,20 +0,0 @@
-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;
-drop table if exists foo;
-create table foo (n int);
-insert into foo values(4);
-drop table if exists foo;
-create table foo (s char(20));
-load data infile '../../std_data/words.dat' into table foo;
-insert into foo values('five');
-drop table if exists bar;
-create table bar (m int);
-insert into bar values(15);
-select foo.n,bar.m from foo,bar;
-n m
-4 15
-drop table if exists bar,foo;
diff --git a/mysql-test/r/rpl_replicate_do.result b/mysql-test/r/rpl_replicate_do.result
new file mode 100644
index 00000000000..372d8c07f64
--- /dev/null
+++ b/mysql-test/r/rpl_replicate_do.result
@@ -0,0 +1,28 @@
+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;
+drop table if exists t11;
+drop table if exists t11;
+create table t2 (n int);
+insert into t2 values(4);
+create table t2 (s char(20));
+load data infile '../../std_data/words.dat' into table t2;
+insert into t2 values('five');
+create table t1 (m int);
+insert into t1 values(15),(16),(17);
+update t1 set m=20 where m=16;
+delete from t1 where m=17;
+create table t11 select * from t1;
+select * from t1;
+m
+15
+20
+select * from t2;
+n
+4
+select * from t11;
+Table 'test.t11' doesn't exist
+drop table if exists t1,t2,t3,t11;
diff --git a/mysql-test/r/rpl_rotate_logs.result b/mysql-test/r/rpl_rotate_logs.result
index 63d5b0b63e1..741c53fe52b 100644
--- a/mysql-test/r/rpl_rotate_logs.result
+++ b/mysql-test/r/rpl_rotate_logs.result
@@ -1,3 +1,5 @@
+drop table if exists t1, t2, t3, t4;
+drop table if exists t1, t2, t3, t4;
slave start;
Could not initialize master info structure, check permisions on master.info
slave start;
@@ -8,7 +10,6 @@ reset slave;
change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root';
reset master;
slave start;
-drop table if exists t1, t2, t3, t4;
create temporary table temp_table (a char(80) not null);
insert into temp_table values ("testing temporary tables");
create table t1 (s text);
diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test
index 7d855dd54ea..b3a51ff65bc 100644
--- a/mysql-test/t/multi_update.test
+++ b/mysql-test/t/multi_update.test
@@ -147,4 +147,30 @@ insert into t2 values (1),(2),(4),(8),(16),(32);
select * from t2 left outer join t1 using (n);
delete t1,t2 from t2 left outer join t1 using (n);
select * from t2 left outer join t1 using (n);
-drop table if exists t1,t2 ;
+drop table t1,t2 ;
+
+#
+# Test with locking
+#
+
+create table t1 (n int(10) not null primary key, d int(10));
+create table t2 (n int(10) not null primary key, d int(10));
+insert into t1 values(1,1);
+insert into t2 values(1,10),(2,20);
+LOCK TABLES t1 write, t2 read;
+--error 1099
+DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n;
+--error 1099
+UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n;
+# The following should be fixed to not give an error
+--error 1099
+UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n;
+unlock tables;
+LOCK TABLES t1 write, t2 write;
+UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n;
+select * from t1;
+DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n;
+select * from t1;
+select * from t2;
+unlock tables;
+drop table t1,t2;
diff --git a/mysql-test/t/rpl000007-slave.opt b/mysql-test/t/rpl000007-slave.opt
deleted file mode 100644
index 9ff99337d1f..00000000000
--- a/mysql-test/t/rpl000007-slave.opt
+++ /dev/null
@@ -1 +0,0 @@
---replicate-do-table=test.bar
diff --git a/mysql-test/t/rpl000007.test b/mysql-test/t/rpl000007.test
deleted file mode 100644
index 8ff1e1782cc..00000000000
--- a/mysql-test/t/rpl000007.test
+++ /dev/null
@@ -1,24 +0,0 @@
-#this one assumes we are ignoring updates on table foo, but doing
-#the ones on bar
-source include/master-slave.inc;
-connection slave;
-drop table if exists foo;
-create table foo (n int);
-insert into foo values(4);
-connection master;
-drop table if exists foo;
-create table foo (s char(20));
-load data infile '../../std_data/words.dat' into table foo;
-insert into foo values('five');
-drop table if exists bar;
-create table bar (m int);
-insert into bar values(15);
-save_master_pos;
-connection slave;
-sync_with_master;
-select foo.n,bar.m from foo,bar;
-connection master;
-drop table if exists bar,foo;
-save_master_pos;
-connection slave;
-sync_with_master;
diff --git a/mysql-test/t/rpl_replicate_do-slave.opt b/mysql-test/t/rpl_replicate_do-slave.opt
new file mode 100644
index 00000000000..da345474216
--- /dev/null
+++ b/mysql-test/t/rpl_replicate_do-slave.opt
@@ -0,0 +1 @@
+--replicate-do-table=test.t1
diff --git a/mysql-test/t/rpl_replicate_do.test b/mysql-test/t/rpl_replicate_do.test
new file mode 100644
index 00000000000..0800062dc05
--- /dev/null
+++ b/mysql-test/t/rpl_replicate_do.test
@@ -0,0 +1,30 @@
+# This test assumes we are ignoring updates on table t2, but doing
+# updates on t1
+
+source include/master-slave.inc;
+drop table if exists t11;
+connection slave;
+drop table if exists t11;
+create table t2 (n int);
+insert into t2 values(4);
+connection master;
+create table t2 (s char(20));
+load data infile '../../std_data/words.dat' into table t2;
+insert into t2 values('five');
+create table t1 (m int);
+insert into t1 values(15),(16),(17);
+update t1 set m=20 where m=16;
+delete from t1 where m=17;
+create table t11 select * from t1;
+save_master_pos;
+connection slave;
+sync_with_master;
+select * from t1;
+select * from t2;
+--error 1146
+select * from t11;
+connection master;
+drop table if exists t1,t2,t3,t11;
+save_master_pos;
+connection slave;
+sync_with_master;
diff --git a/mysql-test/t/rpl_rotate_logs.test b/mysql-test/t/rpl_rotate_logs.test
index 5d8f150cdea..a9bb98932ed 100644
--- a/mysql-test/t/rpl_rotate_logs.test
+++ b/mysql-test/t/rpl_rotate_logs.test
@@ -10,10 +10,12 @@
# - Test creating a duplicate key error and recover from it
#
connect (master,localhost,root,,test,0,master.sock);
+drop table if exists t1, t2, t3, t4;
connect (slave,localhost,root,,test,0,slave.sock);
system cat /dev/null > var/slave-data/master.info;
system chmod 000 var/slave-data/master.info;
connection slave;
+drop table if exists t1, t2, t3, t4;
--error 1201
slave start;
system chmod 600 var/slave-data/master.info;
@@ -31,8 +33,6 @@ connection slave;
slave start;
connection master;
-drop table if exists t1, t2, t3, t4;
-
#
# Test FLUSH LOGS
#
diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
index f494cce8dbe..1ab86476e41 100644
--- a/mysys/my_alloc.c
+++ b/mysys/my_alloc.c
@@ -29,7 +29,7 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
mem_root->min_malloc= 32;
mem_root->block_size= block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8;
mem_root->error_handler= 0;
- mem_root->block_num= 0;
+ mem_root->block_num= 4; /* We shift this with >>2 */
mem_root->first_block_usage= 0;
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
if (pre_alloc_size)
@@ -69,10 +69,11 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
reg2 USED_MEM **prev;
Size= ALIGN_SIZE(Size);
- if ( (*(prev= &mem_root->free)) != NULL )
+ if ((*(prev= &mem_root->free)) != NULL)
{
- if( (*prev)->left < Size &&
- mem_root->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP )
+ if ((*prev)->left < Size &&
+ mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
+ (*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
{
next= *prev;
*prev= next->next; /* Remove block from list */
@@ -85,7 +86,7 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
}
if (! next)
{ /* Time to alloc new block */
- block_size= mem_root->block_size*((mem_root->block_num>>2)+1);
+ block_size= mem_root->block_size * (mem_root->block_num >> 2);
get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
get_size= max(get_size, block_size);
@@ -177,10 +178,8 @@ void free_root(MEM_ROOT *root, myf MyFlags)
root->free=root->pre_alloc;
root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
root->free->next=0;
- root->block_num= 1;
}
- else
- root->block_num= 0;
+ root->block_num= 4;
root->first_block_usage= 0;
DBUG_VOID_RETURN;
}
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index d4e5d0e43cf..2ce7736001b 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -3785,6 +3785,7 @@ ha_innobase::external_lock(
trx_t* trx;
DBUG_ENTER("ha_innobase::external_lock");
+ DBUG_PRINT("enter",("lock_type: %d", lock_type));
update_thd(thd);
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index b4ca822784a..088bad9a84b 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -912,7 +912,7 @@ void ha_myisam::info(uint flag)
if (table->key_parts)
memcpy((char*) table->key_info[0].rec_per_key,
(char*) info.rec_per_key,
- sizeof(ulong)*table->key_parts);
+ sizeof(table->key_info[0].rec_per_key)*table->key_parts);
raid_type=info.raid_type;
raid_chunks=info.raid_chunks;
raid_chunksize=info.raid_chunksize;
diff --git a/sql/lex.h b/sql/lex.h
index dba919ce366..49b6a3811e5 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -255,6 +255,7 @@ static SYMBOL symbols[] = {
{ "NOT", SYM(NOT),0,0},
{ "NULL", SYM(NULL_SYM),0,0},
{ "NUMERIC", SYM(NUMERIC_SYM),0,0},
+ { "OFFSET", SYM(OFFSET_SYM),0,0},
{ "ON", SYM(ON),0,0},
{ "OPEN", SYM(OPEN_SYM),0,0},
{ "OPTIMIZE", SYM(OPTIMIZE),0,0},
diff --git a/sql/lock.cc b/sql/lock.cc
index 9063b1273e0..15878fe7d15 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -167,6 +167,7 @@ static int lock_external(THD *thd, TABLE **tables, uint count)
for (i=1 ; i <= count ; i++, tables++)
{
+ DBUG_ASSERT((*tables)->reginfo.lock_type >= TL_READ);
lock_type=F_WRLCK; /* Lock exclusive */
if ((*tables)->db_stat & HA_READ_ONLY ||
((*tables)->reginfo.lock_type >= TL_READ &&
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a763bdd35ad..db457aa0aa7 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -413,14 +413,12 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &values,COND *conds,
ORDER *order, ha_rows limit,
- enum enum_duplicates handle_duplicates,
- thr_lock_type lock_type);
+ enum enum_duplicates handle_duplicates);
int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
- List<List_item> &values, enum_duplicates flag,
- thr_lock_type lock_type);
+ List<List_item> &values, enum_duplicates flag);
void kill_delayed_threads(void);
int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, ORDER *order,
- ha_rows rows, thr_lock_type lock_type, ulong options);
+ ha_rows rows, ulong options);
int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok=0);
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update);
TABLE *open_table(THD *thd,const char *db,const char *table,const char *alias,
@@ -496,6 +494,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table,LEX_STRING *alias,
thr_lock_type flags=TL_UNLOCK,
List<String> *use_index=0,
List<String> *ignore_index=0);
+void set_lock_for_tables(thr_lock_type lock_type);
void add_join_on(TABLE_LIST *b,Item *expr);
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b);
bool add_proc_to_list(Item *item);
@@ -586,6 +585,8 @@ bool open_log(MYSQL_LOG *log, const char *hostname,
const char *index_file_name,
enum_log_type type, bool read_append = 0,
bool no_auto_events = 0);
+/* mysqld.cc */
+void clear_error_message(THD *thd);
/*
External variables
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index f2a536ada9b..cfb128f6dd6 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1663,6 +1663,17 @@ extern "C" int my_message_sql(uint error, const char *str,
DBUG_RETURN(0);
}
+
+/*
+ Forget last error message (if we got one)
+*/
+
+void clear_error_message(THD *thd)
+{
+ thd->net.last_error[0]= 0;
+}
+
+
#ifdef __WIN__
struct utsname
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 23ba04bd6ed..032882080ff 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1403,6 +1403,61 @@ int open_tables(THD *thd,TABLE_LIST *start)
}
+/*
+ Check that lock is ok for tables; Call start stmt if ok
+
+ SYNOPSIS
+ check_lock_and_start_stmt()
+ thd Thread handle
+ table_list Table to check
+ lock_type Lock used for table
+
+ RETURN VALUES
+ 0 ok
+ 1 error
+*/
+
+static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
+ thr_lock_type lock_type)
+{
+ int error;
+ DBUG_ENTER("check_lock_and_start_stmt");
+
+ if ((int) lock_type >= (int) TL_WRITE_ALLOW_READ &&
+ (int) table->reginfo.lock_type < (int) TL_WRITE_ALLOW_READ)
+ {
+ my_printf_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,
+ ER(ER_TABLE_NOT_LOCKED_FOR_WRITE),
+ MYF(0),table->table_name);
+ DBUG_RETURN(1);
+ }
+ if ((error=table->file->start_stmt(thd)))
+ {
+ table->file->print_error(error,MYF(0));
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Open and lock one table
+
+ SYNOPSIS
+ open_ltable()
+ thd Thread handler
+ table_list Table to open is first table in this list
+ lock_type Lock to use for open
+
+ RETURN VALUES
+ table Opened table
+ 0 Error
+
+ If ok, the following are also set:
+ table_list->lock_type lock_type
+ table_list->table table
+*/
+
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
{
TABLE *table;
@@ -1415,8 +1470,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
&refresh)) && refresh) ;
if (table)
{
- int error;
-
#if defined( __WIN__) || defined(OS2)
/* Win32 can't drop a file that is open */
if (lock_type == TL_WRITE_ALLOW_READ)
@@ -1424,39 +1477,29 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
lock_type= TL_WRITE;
}
#endif /* __WIN__ || OS2 */
-
- table_list->table=table;
+ table_list->lock_type= lock_type;
+ table_list->table= table;
table->grant= table_list->grant;
if (thd->locked_tables)
{
- thd->proc_info=0;
- if ((int) lock_type >= (int) TL_WRITE_ALLOW_READ &&
- (int) table->reginfo.lock_type < (int) TL_WRITE_ALLOW_READ)
- {
- my_printf_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,
- ER(ER_TABLE_NOT_LOCKED_FOR_WRITE),
- MYF(0),table_list->alias);
- table=0;
- }
- else if ((error=table->file->start_stmt(thd)))
- {
- table->file->print_error(error,MYF(0));
- table=0;
- }
- thd->proc_info=0;
- DBUG_RETURN(table);
+ if (check_lock_and_start_stmt(thd, table, lock_type))
+ table= 0;
+ }
+ else
+ {
+ if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK)
+ if (!(thd->lock=mysql_lock_tables(thd,&table_list->table,1)))
+ table= 0;
}
- if ((table->reginfo.lock_type=lock_type) != TL_UNLOCK)
- if (!(thd->lock=mysql_lock_tables(thd,&table_list->table,1)))
- DBUG_RETURN(0);
}
thd->proc_info=0;
DBUG_RETURN(table);
}
+
/*
-** Open all tables in list and locks them for read.
-** The lock will automaticly be freed by the close_thread_tables
+ Open all tables in list and locks them for read.
+ The lock will automaticly be freed by close_thread_tables()
*/
int open_and_lock_tables(THD *thd,TABLE_LIST *tables)
@@ -1466,10 +1509,27 @@ int open_and_lock_tables(THD *thd,TABLE_LIST *tables)
return 0;
}
+
+/*
+ Lock all tables in list
+
+ SYNOPSIS
+ lock_tables()
+ thd Thread handler
+ tables Tables to lock
+
+ RETURN VALUES
+ 0 ok
+ -1 Error
+*/
+
int lock_tables(THD *thd,TABLE_LIST *tables)
{
TABLE_LIST *table;
- if (tables && !thd->locked_tables)
+ if (!tables)
+ return 0;
+
+ if (!thd->locked_tables)
{
uint count=0;
for (table = tables ; table ; table=table->next)
@@ -1486,10 +1546,9 @@ int lock_tables(THD *thd,TABLE_LIST *tables)
{
for (table = tables ; table ; table=table->next)
{
- int error;
- if ((error=table->table->file->start_stmt(thd)))
+ if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
{
- table->table->file->print_error(error,MYF(0));
+ ha_rollback_stmt(thd);
return -1;
}
}
@@ -1497,10 +1556,11 @@ int lock_tables(THD *thd,TABLE_LIST *tables)
return 0;
}
+
/*
-** Open a single table without table caching and don't set it in open_list
-** Used by alter_table to open a temporary table and when creating
-** a temporary table with CREATE TEMPORARY ...
+ Open a single table without table caching and don't set it in open_list
+ Used by alter_table to open a temporary table and when creating
+ a temporary table with CREATE TEMPORARY ...
*/
TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index c30d253828f..a5f14a507f7 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -87,9 +87,6 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
host_or_ip="unknown ip";
locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password=
query_start_used=safe_to_cache_query=0;
- pthread_mutex_lock(&LOCK_global_system_variables);
- variables= global_system_variables;
- pthread_mutex_unlock(&LOCK_global_system_variables);
db_length=query_length=col_access=0;
query_error=0;
next_insert_id=last_insert_id=0;
@@ -129,19 +126,12 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
server_id = ::server_id;
slave_net = 0;
log_pos = 0;
- server_status= SERVER_STATUS_AUTOCOMMIT;
- update_lock_default= (variables.low_priority_updates ?
- TL_WRITE_LOW_PRIORITY :
- TL_WRITE);
- options= thd_startup_options;
- sql_mode=(uint) opt_sql_mode;
- open_options=ha_open_options;
- session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
command=COM_CONNECT;
set_query_id=1;
db_access=NO_ACCESS;
version=refresh_version; // For boot
+ init();
/* Initialize sub structures */
bzero((char*) &mem_root,sizeof(mem_root));
bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root));
@@ -174,6 +164,48 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
}
}
+
+/*
+ Init common variables that has to be reset on start and on change_user
+*/
+
+void THD::init(void)
+{
+ server_status= SERVER_STATUS_AUTOCOMMIT;
+ update_lock_default= (variables.low_priority_updates ?
+ TL_WRITE_LOW_PRIORITY :
+ TL_WRITE);
+ options= thd_startup_options;
+ sql_mode=(uint) opt_sql_mode;
+ open_options=ha_open_options;
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ variables= global_system_variables;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
+}
+
+/*
+ Do what's needed when one invokes change user
+
+ SYNOPSIS
+ change_user()
+
+ IMPLEMENTATION
+ Reset all resources that are connection specific
+*/
+
+
+void THD::change_user(void)
+{
+ cleanup();
+ cleanup_done=0;
+ init();
+ hash_init(&user_vars, USER_VARS_HASH_SIZE, 0, 0,
+ (hash_get_key) get_var_key,
+ (hash_free_key) free_user_var,0);
+}
+
+
/* Do operations that may take a long time */
void THD::cleanup(void)
@@ -191,17 +223,21 @@ void THD::cleanup(void)
close_thread_tables(this);
}
close_temporary_tables(this);
-#ifdef USING_TRANSACTIONS
- if (opt_using_transactions)
+ hash_free(&user_vars);
+ if (global_read_lock)
+ unlock_global_read_lock(this);
+ if (ull)
{
- close_cached_file(&transaction.trans_log);
- ha_close_connection(this);
+ pthread_mutex_lock(&LOCK_user_locks);
+ item_user_lock_release(ull);
+ pthread_mutex_unlock(&LOCK_user_locks);
+ ull= 0;
}
-#endif
cleanup_done=1;
DBUG_VOID_RETURN;
}
+
THD::~THD()
{
THD_CHECK_SENTRY(this);
@@ -218,15 +254,13 @@ THD::~THD()
}
if (!cleanup_done)
cleanup();
- if (global_read_lock)
- unlock_global_read_lock(this);
- if (ull)
+#ifdef USING_TRANSACTIONS
+ if (opt_using_transactions)
{
- pthread_mutex_lock(&LOCK_user_locks);
- item_user_lock_release(ull);
- pthread_mutex_unlock(&LOCK_user_locks);
+ close_cached_file(&transaction.trans_log);
+ ha_close_connection(this);
}
- hash_free(&user_vars);
+#endif
DBUG_PRINT("info", ("freeing host"));
if (host != localhost) // If not pointer to constant
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 0f010b9de28..dba2ad130bf 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -461,6 +461,8 @@ public:
THD();
~THD();
+ void init(void);
+ void change_user(void);
void cleanup(void);
bool store_globals();
#ifdef SIGNAL_WITH_VIO_CLOSE
@@ -804,11 +806,9 @@ public:
ha_rows deleted;
uint num_of_tables;
int error;
- thr_lock_type lock_option;
bool do_delete, transactional_tables, log_delayed, normal_tables;
public:
- multi_delete(THD *thd, TABLE_LIST *dt, thr_lock_type lock_option_arg,
- uint num_of_tables);
+ multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables);
~multi_delete();
int prepare(List<Item> &list);
bool send_fields(List<Item> &list,
@@ -829,7 +829,6 @@ public:
ha_rows updated, found;
List<Item> fields;
List <Item> **fields_by_tables;
- thr_lock_type lock_option;
enum enum_duplicates dupl;
uint num_of_tables, num_fields, num_updated, *save_time_stamps, *field_sequence;
int error;
@@ -837,7 +836,7 @@ public:
public:
multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
enum enum_duplicates handle_duplicates,
- thr_lock_type lock_option_arg, uint num);
+ uint num);
~multi_update();
int prepare(List<Item> &list);
bool send_fields(List<Item> &list,
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index c40e8a4e947..f21ff345845 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -28,7 +28,7 @@
#include "sql_select.h"
int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
- ha_rows limit, thr_lock_type lock_type, ulong options)
+ ha_rows limit, ulong options)
{
int error;
TABLE *table;
@@ -39,15 +39,13 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
ha_rows deleted;
DBUG_ENTER("mysql_delete");
- if (!table_list->db)
- table_list->db=thd->db;
if ((thd->options & OPTION_SAFE_UPDATES) && !conds)
{
send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
DBUG_RETURN(1);
}
- if (!(table = open_ltable(thd,table_list, lock_type)))
+ if (!(table = open_ltable(thd, table_list, table_list->lock_type)))
DBUG_RETURN(-1);
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
thd->proc_info="init";
@@ -176,9 +174,19 @@ cleanup:
if (!log_delayed)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
- if (transactional_table && ha_autocommit_or_rollback(thd,error >= 0))
- error=1;
- if (deleted)
+ if (transactional_table)
+ {
+ if (ha_autocommit_or_rollback(thd,error >= 0))
+ error=1;
+ }
+ /*
+ Only invalidate the query cache if something changed or if we
+ didn't commit the transacion (query cache is automaticly
+ invalidated on commit)
+ */
+ if (deleted &&
+ (!transactional_table ||
+ thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
{
query_cache_invalidate3(thd, table_list, 1);
}
@@ -211,10 +219,9 @@ extern "C" int refposcmp2(void* arg, const void *a,const void *b)
}
multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
- thr_lock_type lock_option_arg,
uint num_of_tables_arg)
: delete_tables (dt), thd(thd_arg), deleted(0),
- num_of_tables(num_of_tables_arg), error(0), lock_option(lock_option_arg),
+ num_of_tables(num_of_tables_arg), error(0),
do_delete(0), transactional_tables(0), log_delayed(0), normal_tables(0)
{
tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
@@ -553,8 +560,9 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
if (!ha_supports_generate(table_type))
{
/* Probably InnoDB table */
- DBUG_RETURN(mysql_delete(thd,table_list, (COND*) 0, (ORDER*) 0,
- HA_POS_ERROR, TL_WRITE, 0));
+ table_list->lock_type= TL_WRITE;
+ DBUG_RETURN(mysql_delete(thd, table_list, (COND*) 0, (ORDER*) 0,
+ HA_POS_ERROR, 0));
}
if (lock_and_wait_for_table_name(thd, table_list))
DBUG_RETURN(-1);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index c83e21ddcae..71f570e4798 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -98,8 +98,7 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
- List<List_item> &values_list,enum_duplicates duplic,
- thr_lock_type lock_type)
+ List<List_item> &values_list,enum_duplicates duplic)
{
int error;
bool log_on= ((thd->options & OPTION_UPDATE_LOG) ||
@@ -114,6 +113,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
List_iterator_fast<List_item> its(values_list);
List_item *values;
char *query=thd->query;
+ thr_lock_type lock_type = table_list->lock_type;
DBUG_ENTER("mysql_insert");
/*
@@ -200,8 +200,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
{
table->file->extra_opt(HA_EXTRA_WRITE_CACHE,
thd->variables.read_buff_size);
- table->file->extra_opt(HA_EXTRA_BULK_INSERT_BEGIN,
- thd->variables.bulk_insert_buff_size);
+ if (thd->variables.bulk_insert_buff_size)
+ table->file->extra_opt(HA_EXTRA_BULK_INSERT_BEGIN,
+ thd->variables.bulk_insert_buff_size);
table->bulk_insert= 1;
}
@@ -266,10 +267,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
info.copied=values_list.elements;
end_delayed_insert(thd);
}
- if (info.copied || info.deleted)
- {
- query_cache_invalidate3(thd, table_list, 1);
- }
+ query_cache_invalidate3(thd, table_list, 1);
}
else
{
@@ -315,7 +313,15 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
}
if (transactional_table)
error=ha_autocommit_or_rollback(thd,error);
- if (info.copied || info.deleted)
+
+ /*
+ Only invalidate the query cache if something changed or if we
+ didn't commit the transacion (query cache is automaticly
+ invalidated on commit)
+ */
+ if ((info.copied || info.deleted) &&
+ (!transactional_table ||
+ thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
{
query_cache_invalidate3(thd, table_list, 1);
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 6424b97b422..0cebde364f7 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -99,7 +99,17 @@ static void init_signals(void)
}
#endif
-inline bool end_active_trans(THD *thd)
+static void unlock_locked_tables(THD *thd)
+{
+ if (thd->locked_tables)
+ {
+ thd->lock=thd->locked_tables;
+ thd->locked_tables=0; // Will be automaticly closed
+ close_thread_tables(thd); // Free tables
+ }
+}
+
+static bool end_active_trans(THD *thd)
{
int error=0;
if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
@@ -698,7 +708,7 @@ pthread_handler_decl(handle_one_connection,arg)
(net->last_errno ? ER(net->last_errno) :
ER(ER_UNKNOWN_ERROR)));
send_error(net,net->last_errno,NullS);
- thread_safe_increment(aborted_threads,&LOCK_status);
+ statistic_increment(aborted_threads,&LOCK_status);
}
end_thread:
@@ -911,7 +921,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->lex.select_lex.options=0; // We store status here
switch (command) {
case COM_INIT_DB:
- thread_safe_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
if (!mysql_change_db(thd,packet))
mysql_log.write(thd,command,"%s",thd->db);
break;
@@ -923,7 +933,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_TABLE_DUMP:
{
- thread_safe_increment(com_other, &LOCK_status);
+ statistic_increment(com_other, &LOCK_status);
slow_command = TRUE;
uint db_len = *(uchar*)packet;
uint tbl_len = *(uchar*)(packet + db_len + 1);
@@ -940,7 +950,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_CHANGE_USER:
{
- thread_safe_increment(com_other,&LOCK_status);
+ thd->change_user();
+ clear_error_message(thd); // If errors from rollback
+
+ statistic_increment(com_other,&LOCK_status);
char *user= (char*) packet;
char *passwd= strend(user)+1;
char *db= strend(passwd)+1;
@@ -1020,7 +1033,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
char *fields;
TABLE_LIST table_list;
- thread_safe_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
bzero((char*) &table_list,sizeof(table_list));
if (!(table_list.db=thd->db))
{
@@ -1055,7 +1068,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_CREATE_DB: // QQ: To be removed
{
- thread_safe_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !strip_sp(db) || check_db_name(db))
@@ -1073,7 +1086,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_DROP_DB: // QQ: To be removed
{
- thread_safe_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !strip_sp(db) || check_db_name(db))
@@ -1094,7 +1107,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_BINLOG_DUMP:
{
- thread_safe_increment(com_other,&LOCK_status);
+ statistic_increment(com_other,&LOCK_status);
slow_command = TRUE;
if (check_global_access(thd, REPL_SLAVE_ACL))
break;
@@ -1118,7 +1131,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_REFRESH:
{
- thread_safe_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
ulong options= (ulong) (uchar) packet[0];
if (check_global_access(thd,RELOAD_ACL))
break;
@@ -1130,7 +1143,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
case COM_SHUTDOWN:
- thread_safe_increment(com_other,&LOCK_status);
+ statistic_increment(com_other,&LOCK_status);
if (check_global_access(thd,SHUTDOWN_ACL))
break; /* purecov: inspected */
DBUG_PRINT("quit",("Got shutdown command"));
@@ -1153,7 +1166,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_STATISTICS:
{
mysql_log.write(thd,command,NullS);
- thread_safe_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
char buff[200];
ulong uptime = (ulong) (thd->start_time - start_time);
sprintf((char*) buff,
@@ -1172,11 +1185,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
case COM_PING:
- thread_safe_increment(com_other,&LOCK_status);
+ statistic_increment(com_other,&LOCK_status);
send_ok(net); // Tell client we are alive
break;
case COM_PROCESS_INFO:
- thread_safe_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
break;
mysql_log.write(thd,command,NullS);
@@ -1185,13 +1198,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
case COM_PROCESS_KILL:
{
- thread_safe_increment(com_stat[SQLCOM_KILL],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
ulong id=(ulong) uint4korr(packet);
kill_one_thread(thd,id);
break;
}
case COM_DEBUG:
- thread_safe_increment(com_other,&LOCK_status);
+ statistic_increment(com_other,&LOCK_status);
if (check_global_access(thd, SUPER_ACL))
break; /* purecov: inspected */
mysql_print_status(thd);
@@ -1291,7 +1304,7 @@ mysql_execute_command(void)
!tables_ok(thd,tables)))
DBUG_VOID_RETURN;
- thread_safe_increment(com_stat[lex->sql_command],&LOCK_status);
+ statistic_increment(com_stat[lex->sql_command],&LOCK_status);
switch (lex->sql_command) {
case SQLCOM_SELECT:
{
@@ -1355,6 +1368,8 @@ mysql_execute_command(void)
Normal select:
Change lock if we are using SELECT HIGH PRIORITY,
FOR UPDATE or IN SHARE MODE
+
+ TODO: Delete the following loop when locks is set by sql_yacc
*/
TABLE_LIST *table;
for (table = tables ; table ; table=table->next)
@@ -1561,6 +1576,7 @@ mysql_execute_command(void)
TABLE_LIST *table;
if (check_table_access(thd, SELECT_ACL, tables->next))
goto error; // Error message is given
+ /* TODO: Delete the following loop when locks is set by sql_yacc */
for (table = tables->next ; table ; table=table->next)
table->lock_type= lex->lock_option;
}
@@ -1802,18 +1818,13 @@ mysql_execute_command(void)
}
if (select_lex->table_list.elements == 1)
{
- res = mysql_update(thd,tables,
- select_lex->item_list,
- lex->value_list,
- select_lex->where,
- (ORDER *) select_lex->order_list.first,
- select_lex->select_limit,
- lex->duplicates,
- lex->lock_option);
-
-#ifdef DELETE_ITEMS
- delete select_lex->where;
-#endif
+ res= mysql_update(thd,tables,
+ select_lex->item_list,
+ lex->value_list,
+ select_lex->where,
+ (ORDER *) select_lex->order_list.first,
+ select_lex->select_limit,
+ lex->duplicates);
}
else
{
@@ -1824,10 +1835,7 @@ mysql_execute_command(void)
lex->sql_command=SQLCOM_MULTI_UPDATE;
for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
- {
table_count++;
- auxi->lock_type=TL_WRITE;
- }
if (select_lex->order_list.elements)
msg="ORDER BY";
else if (select_lex->select_limit && select_lex->select_limit !=
@@ -1848,8 +1856,7 @@ mysql_execute_command(void)
!setup_fields(thd,tables,lex->value_list,0,0,0) &&
! thd->fatal_error &&
(result=new multi_update(thd,tables,select_lex->item_list,
- lex->duplicates, lex->lock_option,
- table_count)))
+ lex->duplicates, table_count)))
{
List <Item> total_list;
List_iterator <Item> field_list(select_lex->item_list);
@@ -1880,8 +1887,7 @@ mysql_execute_command(void)
if (grant_option && check_grant(thd,INSERT_ACL,tables))
goto error;
res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
- lex->duplicates,
- lex->lock_option);
+ lex->duplicates);
break;
case SQLCOM_REPLACE:
if (check_access(thd,INSERT_ACL | DELETE_ACL,
@@ -1892,8 +1898,7 @@ mysql_execute_command(void)
goto error;
res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
- DUP_REPLACE,
- lex->lock_option);
+ DUP_REPLACE);
break;
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
@@ -1928,8 +1933,8 @@ mysql_execute_command(void)
net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
}
- tables->lock_type=TL_WRITE; // update first table
{
+ /* TODO: Delete the following loop when locks is set by sql_yacc */
TABLE_LIST *table;
for (table = tables->next ; table ; table=table->next)
table->lock_type= lex->lock_option;
@@ -1972,8 +1977,7 @@ mysql_execute_command(void)
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
res = mysql_delete(thd,tables, select_lex->where,
(ORDER*) select_lex->order_list.first,
- select_lex->select_limit, lex->lock_option,
- select_lex->options);
+ select_lex->select_limit, select_lex->options);
break;
}
case SQLCOM_DELETE_MULTI:
@@ -2009,12 +2013,12 @@ mysql_execute_command(void)
net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name);
goto error;
}
- auxi->lock_type=walk->lock_type=TL_WRITE;
+ walk->lock_type= auxi->lock_type;
auxi->table= (TABLE *) walk; // Remember corresponding table
}
if (add_item_to_list(new Item_null()))
{
- res = -1;
+ res= -1;
break;
}
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
@@ -2025,7 +2029,6 @@ mysql_execute_command(void)
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
auxi->table= ((TABLE_LIST*) auxi->table)->table;
if (!thd->fatal_error && (result= new multi_delete(thd,aux_tables,
- lex->lock_option,
table_count)))
{
res=mysql_select(thd,tables,select_lex->item_list,
@@ -2212,11 +2215,7 @@ mysql_execute_command(void)
send_ok(&thd->net);
break;
case SQLCOM_UNLOCK_TABLES:
- if (thd->locked_tables)
- {
- thd->lock=thd->locked_tables;
- thd->locked_tables=0; // Will be automaticly closed
- }
+ unlock_locked_tables(thd);
if (thd->options & OPTION_TABLE_LOCK)
{
end_active_trans(thd);
@@ -2227,12 +2226,7 @@ mysql_execute_command(void)
send_ok(&thd->net);
break;
case SQLCOM_LOCK_TABLES:
- if (thd->locked_tables)
- {
- thd->lock=thd->locked_tables;
- thd->locked_tables=0; // Will be automaticly closed
- close_thread_tables(thd);
- }
+ unlock_locked_tables(thd);
if (check_db_used(thd,tables) || end_active_trans(thd))
goto error;
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables))
@@ -3258,6 +3252,37 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
DBUG_RETURN(ptr);
}
+/*
+ Set lock for all tables in current select level
+
+ SYNOPSIS:
+ set_lock_for_tables()
+ lock_type Lock to set for tables
+
+ NOTE:
+ If lock is a write lock, then tables->updating is set 1
+ This is to get tables_ok to know that the table is updated by the
+ query
+*/
+
+void set_lock_for_tables(thr_lock_type lock_type)
+{
+ THD *thd=current_thd;
+ bool for_update= lock_type >= TL_READ_NO_INSERT;
+ DBUG_ENTER("set_lock_for_tables");
+ DBUG_PRINT("enter", ("lock_type: %d for_update: %d", lock_type,
+ for_update));
+
+ for (TABLE_LIST *tables= (TABLE_LIST*) thd->lex.select->table_list.first ;
+ tables ;
+ tables=tables->next)
+ {
+ tables->lock_type= lock_type;
+ tables->updating= for_update;
+ }
+ DBUG_VOID_RETURN;
+}
+
/*
** This is used for UNION to create a new table list of all used tables
@@ -3301,7 +3326,6 @@ static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result)
if (!cursor)
{
/* Add not used table to the total table list */
- aux->lock_type= lex->lock_option;
if (!(cursor = (TABLE_LIST *) thd->memdup((char*) aux,
sizeof(*aux))))
{
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 0b440eb3060..c45ce5b6634 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -50,8 +50,7 @@ int mysql_update(THD *thd,
COND *conds,
ORDER *order,
ha_rows limit,
- enum enum_duplicates handle_duplicates,
- thr_lock_type lock_type)
+ enum enum_duplicates handle_duplicates)
{
bool using_limit=limit != HA_POS_ERROR;
bool used_key_is_modified, transactional_table, log_delayed;
@@ -66,7 +65,7 @@ int mysql_update(THD *thd,
LINT_INIT(used_index);
LINT_INIT(timestamp_query_id);
- if (!(table = open_ltable(thd,table_list,lock_type)))
+ if (!(table = open_ltable(thd,table_list,table_list->lock_type)))
DBUG_RETURN(-1); /* purecov: inspected */
save_time_stamp=table->time_stamp;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
@@ -316,9 +315,19 @@ int mysql_update(THD *thd,
if (!log_delayed)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
- if (transactional_table && ha_autocommit_or_rollback(thd, error >= 0))
- error=1;
- if (updated)
+ if (transactional_table)
+ {
+ if (ha_autocommit_or_rollback(thd, error >= 0))
+ error=1;
+ }
+ /*
+ Only invalidate the query cache if something changed or if we
+ didn't commit the transacion (query cache is automaticly
+ invalidated on commit)
+ */
+ if (updated &&
+ (!transactional_table ||
+ thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
{
query_cache_invalidate3(thd, table_list, 1);
}
@@ -350,10 +359,12 @@ int mysql_update(THD *thd,
Update multiple tables from join
***************************************************************************/
-multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
- enum enum_duplicates handle_duplicates, thr_lock_type lock_option_arg, uint num)
- : update_tables (ut), thd(thd_arg), updated(0), found(0), fields(fs), lock_option(lock_option_arg),
- dupl(handle_duplicates), num_of_tables(num), num_fields(0), num_updated(0) , error(0), do_update(false)
+multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
+ enum enum_duplicates handle_duplicates,
+ uint num)
+ : update_tables (ut), thd(thd_arg), updated(0), found(0), fields(fs),
+ dupl(handle_duplicates), num_of_tables(num), num_fields(0), num_updated(0),
+ error(0), do_update(false)
{
save_time_stamps = (uint *) sql_calloc (sizeof(uint) * num_of_tables);
tmp_tables = (TABLE **)NULL;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 93532d013b5..92b49549a06 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -66,6 +66,7 @@ inline Item *or_or_concat(Item* A, Item* B)
enum enum_tx_isolation tx_isolation;
enum Item_cast cast_type;
enum Item_udftype udf_type;
+ thr_lock_type lock_type;
interval_type interval;
}
@@ -263,6 +264,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token NO_SYM
%token NULL_SYM
%token NUM
+%token OFFSET_SYM
%token ON
%token OPEN_SYM
%token OPTION
@@ -513,7 +515,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
type int_type real_type order_dir opt_field_spec lock_option
udf_type if_exists opt_local opt_table_options table_options
table_option opt_if_not_exists opt_var_type opt_var_ident_type
- opt_temporary
+ opt_temporary
%type <ulong_num>
ULONG_NUM raid_types merge_insert_types
@@ -521,6 +523,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <ulonglong_number>
ulonglong_num
+%type <lock_type>
+ replace_lock_option opt_low_priority insert_lock_option load_data_lock
+
%type <item>
literal text_literal insert_ident order_ident
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
@@ -582,11 +587,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
field_opt_list opt_binary table_lock_list table_lock varchar
references opt_on_delete opt_on_delete_list opt_on_delete_item use
opt_delete_options opt_delete_option
- opt_outer table_list table_name opt_option opt_place opt_low_priority
+ opt_outer table_list table_name opt_option opt_place
opt_attribute opt_attribute_list attribute column_list column_list_id
opt_column_list grant_privileges opt_table user_list grant_option
grant_privilege grant_privilege_list
- flush_options flush_option insert_lock_option replace_lock_option
+ flush_options flush_option
equal optional_braces opt_key_definition key_usage_list2
opt_mi_check_type opt_to mi_check_types normal_join
table_to_table_list table_to_table opt_table_list opt_as
@@ -2249,11 +2254,6 @@ order_clause:
ORDER_SYM BY
{
LEX *lex=Lex;
- if (lex->sql_command == SQLCOM_MULTI_UPDATE)
- {
- net_printf(&lex->thd->net, ER_WRONG_USAGE, "UPDATE", "ORDER BY");
- YYABORT;
- }
if (lex->select->olap != UNSPECIFIED_OLAP_TYPE)
{
net_printf(&lex->thd->net, ER_WRONG_USAGE,
@@ -2278,7 +2278,7 @@ order_dir:
limit_clause:
/* empty */ {}
- | LIMIT ULONG_NUM
+ | LIMIT
{
LEX *lex=Lex;
if (lex->select->olap != UNSPECIFIED_OLAP_TYPE)
@@ -2287,33 +2287,35 @@ limit_clause:
"LIMIT");
YYABORT;
}
- SELECT_LEX *sel=Select;
- sel->select_limit= $2;
- sel->offset_limit= 0L;
}
- | LIMIT ULONG_NUM ',' ULONG_NUM
+ limit_options
+ ;
+
+limit_options:
+ ULONG_NUM
{
- LEX *lex=Lex;
- if (lex->select->olap != UNSPECIFIED_OLAP_TYPE)
- {
- net_printf(&lex->thd->net, ER_WRONG_USAGE, "CUBE/ROLLUP",
- "LIMIT");
- YYABORT;
- }
- SELECT_LEX *sel=lex->select;
- sel->select_limit= $4;
- sel->offset_limit= $2;
- };
+ SELECT_LEX *sel= Select;
+ sel->select_limit= $1;
+ sel->offset_limit= 0L;
+ }
+ | ULONG_NUM ',' ULONG_NUM
+ {
+ SELECT_LEX *sel= Select;
+ sel->select_limit= $3;
+ sel->offset_limit= $1;
+ }
+ | ULONG_NUM OFFSET_SYM ULONG_NUM
+ {
+ SELECT_LEX *sel= Select;
+ sel->select_limit= $1;
+ sel->offset_limit= $3;
+ }
+ ;
delete_limit_clause:
/* empty */
{
LEX *lex=Lex;
- if (lex->sql_command == SQLCOM_MULTI_UPDATE)
- {
- net_printf(&lex->thd->net, ER_WRONG_USAGE, "DELETE", "LIMIT");
- YYABORT;
- }
lex->select->select_limit= HA_POS_ERROR;
}
| LIMIT ulonglong_num
@@ -2448,7 +2450,13 @@ opt_temporary:
*/
insert:
- INSERT { Lex->sql_command = SQLCOM_INSERT; } insert_lock_option opt_ignore insert2 insert_field_spec;
+ INSERT { Lex->sql_command = SQLCOM_INSERT; } insert_lock_option
+ opt_ignore insert2
+ {
+ set_lock_for_tables($3);
+ }
+ insert_field_spec
+ ;
replace:
REPLACE
@@ -2457,17 +2465,23 @@ replace:
lex->sql_command = SQLCOM_REPLACE;
lex->duplicates= DUP_REPLACE;
}
- replace_lock_option insert2 insert_field_spec;
+ replace_lock_option insert2
+ {
+ set_lock_for_tables($3);
+ }
+ insert_field_spec
+ ;
insert_lock_option:
- /* empty */ { Lex->lock_option= TL_WRITE_CONCURRENT_INSERT; }
- | LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; }
- | DELAYED_SYM { Lex->lock_option= TL_WRITE_DELAYED; }
- | HIGH_PRIORITY { Lex->lock_option= TL_WRITE; };
+ /* empty */ { $$= TL_WRITE_CONCURRENT_INSERT; }
+ | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
+ | DELAYED_SYM { $$= TL_WRITE_DELAYED; }
+ | HIGH_PRIORITY { $$= TL_WRITE; }
+ ;
replace_lock_option:
- opt_low_priority {}
- | DELAYED_SYM { Lex->lock_option= TL_WRITE_DELAYED; };
+ opt_low_priority { $$= $1; }
+ | DELAYED_SYM { $$= TL_WRITE_DELAYED; };
insert2:
INTO insert_table {}
@@ -2588,7 +2602,12 @@ update:
lex->select->order_list.first=0;
lex->select->order_list.next= (byte**) &lex->select->order_list.first;
}
- opt_low_priority opt_ignore join_table_list SET update_list where_clause opt_order_clause delete_limit_clause;
+ opt_low_priority opt_ignore join_table_list
+ SET update_list where_clause opt_order_clause delete_limit_clause
+ {
+ set_lock_for_tables($3);
+ }
+ ;
update_list:
update_list ',' simple_ident equal expr
@@ -2603,8 +2622,8 @@ update_list:
};
opt_low_priority:
- /* empty */ { Lex->lock_option= current_thd->update_lock_default; }
- | LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; };
+ /* empty */ { $$= current_thd->update_lock_default; }
+ | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; };
/* Delete rows from a table */
@@ -2618,13 +2637,20 @@ delete:
lex->select->order_list.first=0;
lex->select->order_list.next= (byte**) &lex->select->order_list.first;
}
- opt_delete_options single_multi {};
+ opt_delete_options single_multi {}
+ ;
single_multi:
- FROM table_name where_clause opt_order_clause delete_limit_clause {}
+ FROM table_ident
+ {
+ if (!add_table_to_list($2, NULL, 1, Lex->lock_option))
+ YYABORT;
+ }
+ where_clause opt_order_clause
+ delete_limit_clause
| table_wild_list
{ mysql_init_multi_delete(Lex); }
- FROM join_table_list where_clause
+ FROM join_table_list where_clause
| FROM table_wild_list
{ mysql_init_multi_delete(Lex); }
USING join_table_list where_clause;
@@ -2636,14 +2662,17 @@ table_wild_list:
table_wild_one:
ident opt_wild
{
- if (!add_table_to_list(new Table_ident($1),NULL,1,TL_WRITE))
- YYABORT;
+ if (!add_table_to_list(new Table_ident($1), NULL, 1,
+ Lex->lock_option))
+ YYABORT;
}
| ident '.' ident opt_wild
{
- if (!add_table_to_list(new Table_ident($1,$3,0),NULL,1,TL_WRITE))
+ if (!add_table_to_list(new Table_ident($1,$3,0), NULL, 1,
+ Lex->lock_option))
YYABORT;
- };
+ }
+ ;
opt_wild:
/* empty */ {}
@@ -2667,7 +2696,8 @@ truncate:
lex->select->order_list.elements=0;
lex->select->order_list.first=0;
lex->select->order_list.next= (byte**) &lex->select->order_list.first;
- lex->lock_option= current_thd->update_lock_default; };
+ }
+ ;
opt_table_sym:
/* empty */
@@ -2916,7 +2946,8 @@ load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_LOAD;
- lex->local_file= $4;
+ lex->lock_option= $3;
+ lex->local_file= $4;
if (!(lex->exchange= new sql_exchange($6.str,0)))
YYABORT;
lex->field_list.empty();
@@ -2946,9 +2977,9 @@ opt_local:
| LOCAL_SYM { $$=1;};
load_data_lock:
- /* empty */ { Lex->lock_option= current_thd->update_lock_default; }
- | CONCURRENT { Lex->lock_option= TL_WRITE_CONCURRENT_INSERT ; }
- | LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; };
+ /* empty */ { $$= current_thd->update_lock_default; }
+ | CONCURRENT { $$= TL_WRITE_CONCURRENT_INSERT ; }
+ | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; };
opt_duplicate:
@@ -3201,6 +3232,7 @@ keyword:
| NEW_SYM {}
| NO_SYM {}
| NONE_SYM {}
+ | OFFSET_SYM {}
| OPEN_SYM {}
| PACK_KEYS_SYM {}
| PASSWORD {}