Commit 1a96948e authored by monty@mashka.mysql.fi's avatar monty@mashka.mysql.fi

Small improvement to alloc_root

Add support for LIMIT # OFFSET #
Changed lock handling:  Now all locks should be stored in TABLE_LIST instead of passed to functions.
Don't call query_cache_invalidate() twice in some cases
mysql_change_user() now clears states to be equal to close + connect.
Fixed a bug with multi-table-update and multi-table-delete when used with LOCK TABLES
Fixed a bug with replicate-do and UPDATE
parent aa67a796
......@@ -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/*
......@@ -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) */
......
......@@ -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)",
......
......@@ -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);
......
......@@ -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;
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;
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;
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);
......
......@@ -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;
--replicate-do-table=test.bar
#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;
--replicate-do-table=test.t1
# 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;
......@@ -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
#
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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;
......
......@@ -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},
......
......@@ -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 &&
......
......@@ -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
......
......@@ -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
......
......@@ -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,
......
......@@ -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
......
......@@ -461,6 +461,8 @@ class THD :public ilink {
THD();
~THD();
void init(void);
void change_user(void);
void cleanup(void);
bool store_globals();
#ifdef SIGNAL_WITH_VIO_CLOSE
......@@ -804,11 +806,9 @@ class Unique :public Sql_alloc
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 @@ class Unique :public Sql_alloc
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 @@ class Unique :public Sql_alloc
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,
......
......@@ -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 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
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);
......
......@@ -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);
}
......
......@@ -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))))
{
......
......@@ -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;
......
......@@ -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 {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment