Fixed multi-table-delete
Optimize fixed length MyISAM rows to use pread/pwrite.
This commit is contained in:
parent
595d087e05
commit
a06f391e7a
@ -8,6 +8,6 @@ c_warnings="$c_warnings $debug_extra_warnings"
|
||||
cxx_warnings="$cxx_warnings $debug_extra_warnings"
|
||||
extra_configs="$pentium_configs $debug_configs"
|
||||
|
||||
extra_configs="$extra_configs --with-berkeley-db --with-innodb"
|
||||
extra_configs="$extra_configs --with-berkeley-db --with-innodb --with-embedded-server"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
|
@ -233,4 +233,9 @@ void vio_in_addr(Vio *vio, struct in_addr *in)
|
||||
{
|
||||
}
|
||||
|
||||
my_bool vio_poll_read(Vio *vio,uint timeout)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_VIO */
|
||||
|
@ -27,17 +27,16 @@ int _mi_write_static_record(MI_INFO *info, const byte *record)
|
||||
{
|
||||
my_off_t filepos=info->s->state.dellink;
|
||||
info->rec_cache.seek_not_done=1; /* We have done a seek */
|
||||
VOID(my_seek(info->dfile,info->s->state.dellink+1,MY_SEEK_SET,MYF(0)));
|
||||
|
||||
if (my_read(info->dfile,(char*) &temp[0],info->s->base.rec_reflength,
|
||||
MYF(MY_NABP)))
|
||||
if (my_pread(info->dfile,(char*) &temp[0],info->s->base.rec_reflength,
|
||||
info->s->state.dellink+1,
|
||||
MYF(MY_NABP)))
|
||||
goto err;
|
||||
info->s->state.dellink= _mi_rec_pos(info->s,temp);
|
||||
info->state->del--;
|
||||
info->state->empty-=info->s->base.pack_reclength;
|
||||
VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0)));
|
||||
if (my_write(info->dfile, (char*) record, info->s->base.reclength,
|
||||
MYF(MY_NABP)))
|
||||
if (my_pwrite(info->dfile, (char*) record, info->s->base.reclength,
|
||||
filepos,
|
||||
MYF(MY_NABP)))
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
@ -64,16 +63,18 @@ int _mi_write_static_record(MI_INFO *info, const byte *record)
|
||||
else
|
||||
{
|
||||
info->rec_cache.seek_not_done=1; /* We have done a seek */
|
||||
VOID(my_seek(info->dfile,info->state->data_file_length,
|
||||
MY_SEEK_SET,MYF(0)));
|
||||
if (my_write(info->dfile,(char*) record,info->s->base.reclength,
|
||||
info->s->write_flag))
|
||||
if (my_pwrite(info->dfile,(char*) record,info->s->base.reclength,
|
||||
info->state->data_file_length,
|
||||
info->s->write_flag))
|
||||
goto err;
|
||||
if (info->s->base.pack_reclength != info->s->base.reclength)
|
||||
{
|
||||
uint length=info->s->base.pack_reclength - info->s->base.reclength;
|
||||
bzero((char*) temp,length);
|
||||
if (my_write(info->dfile, (byte*) temp,length, info->s->write_flag))
|
||||
if (my_pwrite(info->dfile, (byte*) temp,length,
|
||||
info->state->data_file_length+
|
||||
info->s->base.pack_reclength,
|
||||
info->s->write_flag))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@ -88,9 +89,10 @@ int _mi_write_static_record(MI_INFO *info, const byte *record)
|
||||
int _mi_update_static_record(MI_INFO *info, my_off_t pos, const byte *record)
|
||||
{
|
||||
info->rec_cache.seek_not_done=1; /* We have done a seek */
|
||||
VOID(my_seek(info->dfile,pos,MY_SEEK_SET,MYF(0)));
|
||||
return (my_write(info->dfile,(char*) record,info->s->base.reclength,
|
||||
MYF(MY_NABP)) != 0);
|
||||
return (my_pwrite(info->dfile,
|
||||
(char*) record,info->s->base.reclength,
|
||||
pos,
|
||||
MYF(MY_NABP)) != 0);
|
||||
}
|
||||
|
||||
|
||||
@ -104,9 +106,8 @@ int _mi_delete_static_record(MI_INFO *info)
|
||||
_mi_dpointer(info,temp+1,info->s->state.dellink);
|
||||
info->s->state.dellink = info->lastpos;
|
||||
info->rec_cache.seek_not_done=1;
|
||||
VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0)));
|
||||
return (my_write(info->dfile,(byte*) temp, 1+info->s->rec_reflength,
|
||||
MYF(MY_NABP)) != 0);
|
||||
return (my_pwrite(info->dfile,(byte*) temp, 1+info->s->rec_reflength,
|
||||
info->lastpos, MYF(MY_NABP)) != 0);
|
||||
}
|
||||
|
||||
|
||||
@ -129,9 +130,9 @@ int _mi_cmp_static_record(register MI_INFO *info, register const byte *old)
|
||||
if ((info->opt_flag & READ_CHECK_USED))
|
||||
{ /* If check isn't disabled */
|
||||
info->rec_cache.seek_not_done=1; /* We have done a seek */
|
||||
VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0)));
|
||||
if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
|
||||
MYF(MY_NABP)))
|
||||
if (my_pread(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
|
||||
info->lastpos,
|
||||
MYF(MY_NABP)))
|
||||
DBUG_RETURN(-1);
|
||||
if (memcmp((byte*) info->rec_buff, (byte*) old,
|
||||
(uint) info->s->base.reclength))
|
||||
@ -152,9 +153,8 @@ int _mi_cmp_static_unique(MI_INFO *info, MI_UNIQUEDEF *def,
|
||||
DBUG_ENTER("_mi_cmp_static_unique");
|
||||
|
||||
info->rec_cache.seek_not_done=1; /* We have done a seek */
|
||||
VOID(my_seek(info->dfile,pos,MY_SEEK_SET,MYF(0)));
|
||||
if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
|
||||
MYF(MY_NABP)))
|
||||
if (my_pread(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
|
||||
pos, MYF(MY_NABP)))
|
||||
DBUG_RETURN(-1);
|
||||
DBUG_RETURN(mi_unique_comp(def, record, info->rec_buff,
|
||||
def->null_are_equal));
|
||||
|
@ -1,21 +1,11 @@
|
||||
id1 t
|
||||
1 3
|
||||
2 2
|
||||
3 1
|
||||
id2 t
|
||||
3 3
|
||||
3 2
|
||||
3 1
|
||||
2 3
|
||||
2 2
|
||||
2 1
|
||||
1 3
|
||||
1 2
|
||||
1 1
|
||||
id3 t
|
||||
3 3
|
||||
3 2
|
||||
3 1
|
||||
2 3
|
||||
2 2
|
||||
2 1
|
||||
|
@ -16,10 +16,11 @@ while ($1)
|
||||
dec $1;
|
||||
}
|
||||
|
||||
delete t1.*,t2.* from t1,t2 where t1.id1 = t2.id2 and t1.id1 = 3;
|
||||
delete t3 from t3 left join t1 on (id1=id3) where t1.id1 is null;
|
||||
delete t2 from t1,t2,t3 where id1=id2 and id2=id3 and id1=2;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
select * from t3;
|
||||
|
||||
delete from t1,t2 where t1.id = t2.id and t1.id = 3;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
delete t1,t2 from t1,t2 where 1;
|
||||
drop table t1,t2,t3;
|
||||
|
@ -724,6 +724,8 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
|
||||
{
|
||||
error=1; goto err; /* purecov: inspected */
|
||||
}
|
||||
buffpek->key+=sort_length;
|
||||
queue_replaced(&queue); // Top element has been used
|
||||
}
|
||||
else
|
||||
cmp=0; // Not unique
|
||||
|
@ -147,7 +147,7 @@ void kill_one_thread(THD *thd, ulong id);
|
||||
#define SELECT_BIG_RESULT 16
|
||||
#define OPTION_FOUND_ROWS 32
|
||||
#define SELECT_HIGH_PRIORITY 64 /* Intern */
|
||||
#define SELECT_USE_CACHE 256 /* Intern */
|
||||
#define SELECT_NO_JOIN_CACHE 256 /* Intern */
|
||||
|
||||
#define OPTION_BIG_TABLES 512 /* for SQL OPTION */
|
||||
#define OPTION_BIG_SELECTS 1024 /* for SQL OPTION */
|
||||
|
@ -600,7 +600,6 @@ public:
|
||||
#else
|
||||
Unique **tempfiles;
|
||||
#endif
|
||||
byte * dup_checking;
|
||||
THD *thd;
|
||||
ha_rows deleted;
|
||||
uint num_of_tables;
|
||||
@ -608,12 +607,8 @@ public:
|
||||
thr_lock_type lock_option;
|
||||
bool do_delete;
|
||||
public:
|
||||
multi_delete(TABLE_LIST *dt, thr_lock_type lock_option_arg, uint n)
|
||||
: delete_tables (dt), deleted(0), num_of_tables(n), error(0),
|
||||
lock_option(lock_option_arg)
|
||||
{
|
||||
thd = current_thd; do_delete = false;
|
||||
}
|
||||
multi_delete(THD *thd, TABLE_LIST *dt, thr_lock_type lock_option_arg,
|
||||
uint num_of_tables);
|
||||
~multi_delete();
|
||||
int prepare(List<Item> &list);
|
||||
bool send_fields(List<Item> &list,
|
||||
|
@ -286,112 +286,157 @@ int mysql_delete(THD *thd,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** delete multiple tables from join
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
#define MEM_STRIP_BUF_SIZE 2048
|
||||
#else
|
||||
#define MEM_STRIP_BUF_SIZE sortbuffer_size
|
||||
#endif
|
||||
|
||||
#ifndef SINISAS_STRIP
|
||||
int refposcmp2(void* arg, const void *a,const void *b)
|
||||
{
|
||||
return memcmp(a,b,(int)arg);
|
||||
return memcmp(a,b,(int) arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
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),
|
||||
do_delete(false)
|
||||
{
|
||||
uint counter=0;
|
||||
#ifdef SINISAS_STRIP
|
||||
tempfiles = (IO_CACHE **) sql_calloc(sizeof(IO_CACHE *)* num_of_tables);
|
||||
memory_lane = (byte *)sql_alloc(MAX_REFLENGTH*MEM_STRIP_BUF_SIZE);
|
||||
#else
|
||||
tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
|
||||
#endif
|
||||
|
||||
(void) dt->table->file->extra(HA_EXTRA_NO_READCHECK);
|
||||
/* Don't use key read with MULTI-TABLE-DELETE */
|
||||
dt->table->used_keys=0;
|
||||
for (dt=dt->next ; dt ; dt=dt->next,counter++)
|
||||
{
|
||||
TABLE *table=dt->table;
|
||||
(void) table->file->extra(HA_EXTRA_NO_READCHECK);
|
||||
#ifdef SINISAS_STRIP
|
||||
tempfiles[counter]=(IO_CACHE *) sql_alloc(sizeof(IO_CACHE));
|
||||
if (open_cached_file(tempfiles[counter], mysql_tmpdir,TEMP_PREFIX,
|
||||
DISK_BUFFER_SIZE, MYF(MY_WME)))
|
||||
{
|
||||
my_error(ER_CANT_OPEN_FILE,MYF(0),(tempfiles[counter])->file_name,errno);
|
||||
thd->fatal_error=1;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
tempfiles[counter] = new Unique (refposcmp2,
|
||||
(void *) table->file->ref_length,
|
||||
table->file->ref_length,
|
||||
MEM_STRIP_BUF_SIZE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
multi_delete::prepare(List<Item> &values)
|
||||
{
|
||||
DBUG_ENTER("multi_delete::prepare");
|
||||
uint counter = 0;
|
||||
#ifdef SINISAS_STRIP
|
||||
tempfiles = (IO_CACHE **) sql_calloc(sizeof(IO_CACHE *)*(num_of_tables));
|
||||
memory_lane = (byte *)sql_alloc(MAX_REFLENGTH*MEM_STRIP_BUF_SIZE);
|
||||
#else
|
||||
tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables));
|
||||
#endif
|
||||
do_delete = true;
|
||||
dup_checking = (byte *) sql_calloc(MAX_REFLENGTH * (num_of_tables + 1));
|
||||
memset(dup_checking,'\xFF', MAX_REFLENGTH * (num_of_tables + 1));
|
||||
for (table_being_deleted=delete_tables; table_being_deleted; table_being_deleted=table_being_deleted->next, counter++)
|
||||
thd->proc_info="deleting from main table";
|
||||
|
||||
if (thd->options & OPTION_SAFE_UPDATES)
|
||||
{
|
||||
TABLE *table=table_being_deleted->table;
|
||||
if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys)
|
||||
TABLE_LIST *table_ref;
|
||||
for (table_ref=delete_tables; table_ref; table_ref=table_ref->next)
|
||||
{
|
||||
my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
(void) table->file->extra(HA_EXTRA_NO_READCHECK);
|
||||
if (counter < num_of_tables)
|
||||
{
|
||||
#ifdef SINISAS_STRIP
|
||||
tempfiles[counter]=(IO_CACHE *)sql_alloc(sizeof(IO_CACHE));
|
||||
if (open_cached_file(tempfiles[counter], mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
|
||||
TABLE *table=table_ref->table;
|
||||
if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys)
|
||||
{
|
||||
my_error(ER_CANT_OPEN_FILE,MYF(0),(tempfiles[counter])->file_name,errno);
|
||||
my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
#else
|
||||
tempfiles[counter] = new Unique (refposcmp2,(void *)table->file->ref_length,table->file->ref_length,MEM_STRIP_BUF_SIZE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
thd->proc_info="updating";
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
multi_delete::~multi_delete()
|
||||
{
|
||||
for (uint counter = 0; counter < num_of_tables; counter++)
|
||||
|
||||
/* Add back EXTRA_READCHECK; In 4.0.1 we shouldn't need this anymore */
|
||||
for (table_being_deleted=delete_tables ;
|
||||
table_being_deleted ;
|
||||
table_being_deleted=table_being_deleted->next)
|
||||
{
|
||||
VOID(table_being_deleted->table->file->extra(HA_EXTRA_READCHECK));
|
||||
}
|
||||
for (uint counter = 0; counter < num_of_tables-1; counter++)
|
||||
{
|
||||
if (tempfiles[counter])
|
||||
{
|
||||
#ifdef SINISAS_STRIP
|
||||
// end_io_cache(tempfiles[counter]);
|
||||
#else
|
||||
delete tempfiles[counter];
|
||||
delete tempfiles[counter];
|
||||
#endif
|
||||
// Here it crashes ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool multi_delete::send_data(List<Item> &values)
|
||||
{
|
||||
int secure_counter = -1;
|
||||
for (table_being_deleted=delete_tables ; table_being_deleted ; table_being_deleted=table_being_deleted->next, secure_counter++)
|
||||
int secure_counter= -1;
|
||||
for (table_being_deleted=delete_tables ;
|
||||
table_being_deleted ;
|
||||
table_being_deleted=table_being_deleted->next, secure_counter++)
|
||||
{
|
||||
TABLE *table=table_being_deleted->table;
|
||||
table->file->position(table->record[0]); int rl = table->file->ref_length;
|
||||
byte *dup_check = dup_checking + (secure_counter + 1)*MAX_REFLENGTH;
|
||||
if (!table->null_row && memcmp(dup_check,table->file->ref, rl))
|
||||
|
||||
/* Check if we are using outer join and we didn't find the row */
|
||||
if (table->status & (STATUS_NULL_ROW | STATUS_DELETED))
|
||||
continue;
|
||||
|
||||
table->file->position(table->record[0]);
|
||||
int rl = table->file->ref_length;
|
||||
|
||||
if (secure_counter < 0)
|
||||
{
|
||||
memcpy(dup_check,table->file->ref,rl);
|
||||
if (secure_counter == -1)
|
||||
{
|
||||
if (!(error=table->file->delete_row(table->record[0])))
|
||||
deleted++;
|
||||
else
|
||||
{
|
||||
send_error(error,"An error occured in deleting rows");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
table->status|= STATUS_DELETED;
|
||||
if (!(error=table->file->delete_row(table->record[0])))
|
||||
deleted++;
|
||||
else
|
||||
{
|
||||
table->file->print_error(error,MYF(0));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef SINISAS_STRIP
|
||||
if (my_b_write(tempfiles[secure_counter],table->file->ref,rl))
|
||||
error=my_b_write(tempfiles[secure_counter],table->file->ref,rl);
|
||||
#else
|
||||
if (tempfiles[secure_counter]->unique_add(table->file->ref))
|
||||
error=tempfiles[secure_counter]->unique_add(table->file->ref);
|
||||
#endif
|
||||
{
|
||||
error=-1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
error=-1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef SINISAS_STRIP
|
||||
static inline int COMP (byte *ml,uint len,unsigned int left, unsigned int right)
|
||||
{
|
||||
@ -712,14 +757,15 @@ static IO_CACHE *strip_duplicates_from_temp (byte *memory_lane, IO_CACHE *ptr, u
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SINISAS_STRIP */
|
||||
|
||||
/* Return true if some table is not transaction safe */
|
||||
|
||||
static bool some_table_is_not_transaction_safe (TABLE_LIST *tl)
|
||||
{
|
||||
TABLE_LIST *deleting = tl;
|
||||
for (deleting=deleting->next; deleting ; deleting=deleting->next)
|
||||
for (; tl ; tl=tl->next)
|
||||
{
|
||||
if (!(deleting->table->file->has_transactions()))
|
||||
if (!(tl->table->file->has_transactions()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -728,35 +774,52 @@ static bool some_table_is_not_transaction_safe (TABLE_LIST *tl)
|
||||
|
||||
void multi_delete::send_error(uint errcode,const char *err)
|
||||
{
|
||||
// First send error what ever it is ...
|
||||
/* First send error what ever it is ... */
|
||||
::send_error(&thd->net,errcode,err);
|
||||
// If nothing deleted return
|
||||
if (!deleted) return;
|
||||
// Below can happen when thread is killed ...
|
||||
if (!table_being_deleted) table_being_deleted=delete_tables;
|
||||
// If rows from the first table only has been deleted and it is transactional, just do rollback
|
||||
// The same if all tables are transactional, regardless of where we are. In all other cases do attempt deletes ...
|
||||
if ((table_being_deleted->table->file->has_transactions() && table_being_deleted == delete_tables) || !some_table_is_not_transaction_safe(delete_tables))
|
||||
ha_rollback(current_thd);
|
||||
/* If nothing deleted return */
|
||||
if (!deleted)
|
||||
return;
|
||||
/* Below can happen when thread is killed early ... */
|
||||
if (!table_being_deleted)
|
||||
table_being_deleted=delete_tables;
|
||||
|
||||
/*
|
||||
If rows from the first table only has been deleted and it is transactional,
|
||||
just do rollback.
|
||||
The same if all tables are transactional, regardless of where we are.
|
||||
In all other cases do attempt deletes ...
|
||||
*/
|
||||
if ((table_being_deleted->table->file->has_transactions() &&
|
||||
table_being_deleted == delete_tables) ||
|
||||
!some_table_is_not_transaction_safe(delete_tables->next))
|
||||
ha_rollback(thd);
|
||||
else if (do_delete)
|
||||
VOID(do_deletes(true));
|
||||
}
|
||||
|
||||
int multi_delete::do_deletes (bool from_send_error)
|
||||
|
||||
int multi_delete::do_deletes (bool from_send_error)
|
||||
{
|
||||
TABLE *table;
|
||||
int error = 0, counter = 0, count;
|
||||
|
||||
if (from_send_error)
|
||||
{
|
||||
for (TABLE_LIST *aux=delete_tables; aux != table_being_deleted; aux=aux->next)
|
||||
/* Found out table number for 'table_being_deleted' */
|
||||
for (TABLE_LIST *aux=delete_tables;
|
||||
aux != table_being_deleted;
|
||||
aux=aux->next)
|
||||
counter++;
|
||||
}
|
||||
else
|
||||
table_being_deleted = delete_tables;
|
||||
|
||||
do_delete = false;
|
||||
for (table_being_deleted=table_being_deleted->next; table_being_deleted ; counter++, table_being_deleted=table_being_deleted->next)
|
||||
for (table_being_deleted=table_being_deleted->next;
|
||||
table_being_deleted ;
|
||||
table_being_deleted=table_being_deleted->next, counter++)
|
||||
{
|
||||
table = table_being_deleted->table; int rl = table->file->ref_length;
|
||||
TABLE *table = table_being_deleted->table;
|
||||
int rl = table->file->ref_length;
|
||||
#ifdef SINISAS_STRIP
|
||||
int num_of_positions = (int)my_b_tell(tempfiles[counter])/rl;
|
||||
if (!num_of_positions) continue;
|
||||
@ -766,11 +829,20 @@ int multi_delete::do_deletes (bool from_send_error)
|
||||
error=1; break;
|
||||
}
|
||||
#else
|
||||
tempfiles[counter]->get(table);
|
||||
if (tempfiles[counter]->get(table))
|
||||
{
|
||||
error=1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
if (num_of_positions == table->file->records) // nice little optimization ....
|
||||
{ // but Monty has to fix generate_table...
|
||||
|
||||
#if USE_REGENERATE_TABLE
|
||||
// nice little optimization ....
|
||||
// but Monty has to fix generate_table...
|
||||
// This will not work for transactional tables because for other types
|
||||
// records is not absolute
|
||||
if (num_of_positions == table->file->records)
|
||||
{
|
||||
TABLE_LIST table_list;
|
||||
bzero((char*) &table_list,sizeof(table_list));
|
||||
table_list.name=table->table_name; table_list.real_name=table_being_deleted->real_name;
|
||||
@ -780,69 +852,66 @@ int multi_delete::do_deletes (bool from_send_error)
|
||||
error=generate_table(thd,&table_list,(TABLE *)0);
|
||||
if (error <= 0) {error = 1; break;}
|
||||
deleted += num_of_positions;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
READ_RECORD info; error=0;
|
||||
#endif /* USE_REGENERATE_TABLE */
|
||||
|
||||
READ_RECORD info;
|
||||
error=0;
|
||||
#ifdef SINISAS_STRIP
|
||||
SQL_SELECT *select= new SQL_SELECT;
|
||||
select->head=table;
|
||||
select->file=*tempfiles[counter];
|
||||
init_read_record(&info,thd,table,select,0,0);
|
||||
SQL_SELECT *select= new SQL_SELECT;
|
||||
select->head=table;
|
||||
select->file=*tempfiles[counter];
|
||||
init_read_record(&info,thd,table,select,0,0);
|
||||
#else
|
||||
init_read_record(&info,thd,table,NULL,0,0);
|
||||
init_read_record(&info,thd,table,NULL,0,0);
|
||||
#endif
|
||||
bool not_trans_safe = some_table_is_not_transaction_safe(delete_tables);
|
||||
while (!(error=info.read_record(&info)) && (!thd->killed || from_send_error || not_trans_safe))
|
||||
bool not_trans_safe = some_table_is_not_transaction_safe(delete_tables);
|
||||
while (!(error=info.read_record(&info)) &&
|
||||
(!thd->killed || from_send_error || not_trans_safe))
|
||||
{
|
||||
error=table->file->delete_row(table->record[0]);
|
||||
if (error)
|
||||
{
|
||||
error=table->file->delete_row(table->record[0]);
|
||||
if (error)
|
||||
{
|
||||
table->file->print_error(error,MYF(0));
|
||||
break;
|
||||
}
|
||||
else
|
||||
deleted++;
|
||||
table->file->print_error(error,MYF(0));
|
||||
break;
|
||||
}
|
||||
end_read_record(&info);
|
||||
#ifdef SINISAS_STRIP
|
||||
delete select;
|
||||
#endif
|
||||
if (error == -1)
|
||||
error = 0;
|
||||
#if 0
|
||||
else
|
||||
deleted++;
|
||||
}
|
||||
end_read_record(&info);
|
||||
#ifdef SINISAS_STRIP
|
||||
delete select;
|
||||
#endif
|
||||
if (error == -1)
|
||||
error = 0;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
bool multi_delete::send_eof()
|
||||
{
|
||||
int error = 0;
|
||||
error = do_deletes(false);
|
||||
thd->proc_info="deleting from reference tables";
|
||||
int error = do_deletes(false);
|
||||
|
||||
thd->proc_info="end";
|
||||
if (error && error != -1)
|
||||
{
|
||||
::send_error(&thd->net);
|
||||
return 1;
|
||||
}
|
||||
for (table_being_deleted=delete_tables ; table_being_deleted ; table_being_deleted=table_being_deleted->next)
|
||||
{
|
||||
TABLE *table=table_being_deleted->table;
|
||||
if (table)
|
||||
VOID(table->file->extra(HA_EXTRA_READCHECK));
|
||||
}
|
||||
if (deleted && (error <= 0 || some_table_is_not_transaction_safe(delete_tables)))
|
||||
|
||||
if (deleted &&
|
||||
(error <= 0 || some_table_is_not_transaction_safe(delete_tables)))
|
||||
{
|
||||
mysql_update_log.write(thd,thd->query,thd->query_length);
|
||||
Query_log_event qinfo(thd, thd->query);
|
||||
if (mysql_bin_log.write(&qinfo) && !some_table_is_not_transaction_safe(delete_tables))
|
||||
error=1;
|
||||
if (mysql_bin_log.write(&qinfo) &&
|
||||
!some_table_is_not_transaction_safe(delete_tables))
|
||||
error=1; // Rollback
|
||||
VOID(ha_autocommit_or_rollback(thd,error >= 0));
|
||||
}
|
||||
::send_ok(&thd->net,deleted);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
149
sql/sql_parse.cc
149
sql/sql_parse.cc
@ -1649,97 +1649,98 @@ mysql_execute_command(void)
|
||||
if (lex->sql_command == SQLCOM_TRUNCATE && end_active_trans(thd))
|
||||
res= -1;
|
||||
else
|
||||
res = mysql_delete(thd,tables, select_lex->where, (ORDER*)select_lex->order_list.first,
|
||||
select_lex->select_limit, lex->lock_option, select_lex->options);
|
||||
res = mysql_delete(thd,tables, select_lex->where,
|
||||
(ORDER*) select_lex->order_list.first,
|
||||
select_lex->select_limit, lex->lock_option,
|
||||
select_lex->options);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_MULTI_DELETE:
|
||||
{
|
||||
TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first;
|
||||
multi_delete *result;
|
||||
case SQLCOM_MULTI_DELETE:
|
||||
{
|
||||
TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first;
|
||||
TABLE_LIST *auxi;
|
||||
uint table_count=0;
|
||||
multi_delete *result;
|
||||
|
||||
if (!tables || !aux_tables ||
|
||||
check_table_access(thd,SELECT_ACL, tables) ||
|
||||
check_table_access(thd,DELETE_ACL,aux_tables))
|
||||
{
|
||||
res=-1;
|
||||
goto error;
|
||||
}
|
||||
if (!tables->db)
|
||||
tables->db=thd->db;
|
||||
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
|
||||
{
|
||||
send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
|
||||
res=1; goto error;
|
||||
}
|
||||
uint howmuch=0; TABLE_LIST *walk, *auxi;
|
||||
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next, howmuch++)
|
||||
{
|
||||
if (!auxi->db)
|
||||
auxi->db=thd->db;
|
||||
if (!auxi->real_name)
|
||||
auxi->real_name=auxi->name;
|
||||
for (walk=(TABLE_LIST*) tables ; walk ; walk=walk->next)
|
||||
{
|
||||
if (!walk->db) walk->db=thd->db;
|
||||
if (!strcmp(auxi->real_name,walk->real_name) && !strcmp(walk->db,auxi->db))
|
||||
break;
|
||||
}
|
||||
if (!walk)
|
||||
{
|
||||
net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name);
|
||||
res=-2; goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
auxi->lock_type=walk->lock_type=TL_WRITE;
|
||||
auxi->table= (TABLE *) walk;
|
||||
}
|
||||
}
|
||||
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
|
||||
if (add_item_to_list(new Item_null())) goto error;
|
||||
thd->proc_info="init";
|
||||
if (open_and_lock_tables(thd,tables))
|
||||
{
|
||||
res=-1; goto error;
|
||||
}
|
||||
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
|
||||
auxi->table= ((TABLE_LIST*) auxi->table)->table;
|
||||
if ((result=new multi_delete(aux_tables,lex->lock_option,howmuch)))
|
||||
{
|
||||
res=mysql_select(thd,tables,select_lex->item_list,
|
||||
select_lex->where,select_lex->ftfunc_list,
|
||||
(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
|
||||
(ORDER *)NULL,
|
||||
select_lex->options | thd->options,
|
||||
result);
|
||||
delete result;
|
||||
}
|
||||
else
|
||||
res= -1;
|
||||
close_thread_tables(thd);
|
||||
break;
|
||||
}
|
||||
/* sql_yacc guarantees that tables and aux_tables are not zero */
|
||||
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
|
||||
check_table_access(thd,SELECT_ACL, tables) ||
|
||||
check_table_access(thd,DELETE_ACL, aux_tables))
|
||||
goto error;
|
||||
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
|
||||
{
|
||||
send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
|
||||
goto error;
|
||||
}
|
||||
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
|
||||
{
|
||||
table_count++;
|
||||
/* All tables in aux_tables must be found in FROM PART */
|
||||
TABLE_LIST *walk;
|
||||
for (walk=(TABLE_LIST*) tables ; walk ; walk=walk->next)
|
||||
{
|
||||
if (!strcmp(auxi->real_name,walk->real_name) &&
|
||||
!strcmp(walk->db,auxi->db))
|
||||
break;
|
||||
}
|
||||
if (!walk)
|
||||
{
|
||||
net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name);
|
||||
goto error;
|
||||
}
|
||||
auxi->lock_type=walk->lock_type=TL_WRITE;
|
||||
auxi->table= (TABLE *) walk; // Remember corresponding table
|
||||
}
|
||||
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
|
||||
if (add_item_to_list(new Item_null()))
|
||||
{
|
||||
res= -1;
|
||||
break;
|
||||
}
|
||||
thd->proc_info="init";
|
||||
if ((res=open_and_lock_tables(thd,tables)))
|
||||
break;
|
||||
/* Fix tables-to-be-deleted-from list to point at opened tables */
|
||||
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
|
||||
auxi->table= ((TABLE_LIST*) auxi->table)->table;
|
||||
if ((result=new multi_delete(thd,aux_tables,lex->lock_option,
|
||||
table_count)) && ! thd->fatal_error)
|
||||
{
|
||||
res=mysql_select(thd,tables,select_lex->item_list,
|
||||
select_lex->where,select_lex->ftfunc_list,
|
||||
(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
|
||||
(ORDER *)NULL,
|
||||
select_lex->options | thd->options |
|
||||
SELECT_NO_JOIN_CACHE,
|
||||
result);
|
||||
}
|
||||
else
|
||||
res= -1; // Error is not sent
|
||||
delete result;
|
||||
close_thread_tables(thd);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_UNION_SELECT:
|
||||
{
|
||||
uint total_selects = select_lex->select_number; total_selects++;
|
||||
SQL_LIST *total=(SQL_LIST *) thd->calloc(sizeof(SQL_LIST));
|
||||
if (select_lex->options & SELECT_DESCRIBE)
|
||||
lex->exchange=0;
|
||||
res = link_in_large_list_and_check_acl(thd,lex,total);
|
||||
if (res == -1)
|
||||
if ((res = link_in_large_list_and_check_acl(thd,lex,total)) == -1)
|
||||
{
|
||||
res=0;
|
||||
break;
|
||||
}
|
||||
if (res && (res=check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL, any_db)))
|
||||
if (res &&
|
||||
(res=check_access(thd,
|
||||
lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
|
||||
any_db)))
|
||||
{
|
||||
res=0;
|
||||
break;
|
||||
}
|
||||
if (!(res=open_and_lock_tables(thd,(TABLE_LIST *)total->first)))
|
||||
{
|
||||
res=mysql_union(thd,lex,total_selects);
|
||||
res=mysql_union(thd,lex, select_lex->select_number+1);
|
||||
if (res==-1) res=0;
|
||||
}
|
||||
break;
|
||||
@ -1768,7 +1769,7 @@ mysql_execute_command(void)
|
||||
break;
|
||||
case SQLCOM_SHOW_DATABASES:
|
||||
#if defined(DONT_ALLOW_SHOW_COMMANDS)
|
||||
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
|
||||
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
|
||||
DBUG_VOID_RETURN;
|
||||
#else
|
||||
if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
|
||||
|
@ -484,8 +484,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
(group && order) ||
|
||||
test(select_options & OPTION_BUFFER_RESULT)));
|
||||
|
||||
make_join_readinfo(&join, (select_options & SELECT_DESCRIBE) |
|
||||
(ftfuncs.elements ? 0 : SELECT_USE_CACHE)); // No cache for MATCH
|
||||
// No cache for MATCH
|
||||
make_join_readinfo(&join,
|
||||
(select_options & (SELECT_DESCRIBE |
|
||||
SELECT_NO_JOIN_CACHE)) |
|
||||
(ftfuncs.elements ? SELECT_NO_JOIN_CACHE : 0));
|
||||
|
||||
/* Need to tell Innobase that to play it safe, it should fetch all
|
||||
columns of the tables: this is because MySQL
|
||||
@ -2465,7 +2468,7 @@ make_join_readinfo(JOIN *join,uint options)
|
||||
** if previous table use cache
|
||||
*/
|
||||
table->status=STATUS_NO_RECORD;
|
||||
if (i != join->const_tables && (options & SELECT_USE_CACHE) &&
|
||||
if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) &&
|
||||
tab->use_quick != 2 && !tab->on_expr)
|
||||
{
|
||||
if ((options & SELECT_DESCRIBE) ||
|
||||
|
@ -59,9 +59,9 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
pthread_mutex_unlock(&thd->mysys_var->mutex);
|
||||
|
||||
if(global_read_lock)
|
||||
if (global_read_lock)
|
||||
{
|
||||
if(thd->global_read_lock)
|
||||
if (thd->global_read_lock)
|
||||
{
|
||||
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,MYF(0),
|
||||
tables->real_name);
|
||||
|
@ -30,4 +30,5 @@ int mysql_union(THD *thd,LEX *lex,uint no_of_selects)
|
||||
for (sl=&lex->select_lex;sl;sl=sl->next)
|
||||
{
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
638
sql/sql_yacc.yy
638
sql/sql_yacc.yy
File diff suppressed because it is too large
Load Diff
@ -164,3 +164,4 @@ typedef struct st_lex_user {
|
||||
#define STATUS_NOT_READ 8 /* Record isn't read */
|
||||
#define STATUS_UPDATED 16 /* Record is updated by formula */
|
||||
#define STATUS_NULL_ROW 32 /* table->null_row is set */
|
||||
#define STATUS_DELETED 64
|
||||
|
@ -44,7 +44,8 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
|
||||
/* If the following fail's the next add will also fail */
|
||||
init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16);
|
||||
max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size);
|
||||
open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME));
|
||||
open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE,
|
||||
MYF(MY_WME));
|
||||
}
|
||||
|
||||
|
||||
@ -95,7 +96,7 @@ bool Unique::get(TABLE *table)
|
||||
SORTPARAM sort_param;
|
||||
table->found_records=elements+tree.elements_in_tree;
|
||||
|
||||
if (!my_b_inited(&file))
|
||||
if (my_b_tell(&file) == 0)
|
||||
{
|
||||
/* Whole tree is in memory; Don't use disk if you don't need to */
|
||||
if ((record_pointers=table->record_pointers= (byte*)
|
||||
@ -110,17 +111,16 @@ bool Unique::get(TABLE *table)
|
||||
if (flush())
|
||||
return 1;
|
||||
|
||||
IO_CACHE *outfile=table->io_cache, tempfile;
|
||||
IO_CACHE *outfile=table->io_cache;
|
||||
BUFFPEK *file_ptr= (BUFFPEK*) file_ptrs.buffer;
|
||||
uint maxbuffer= file_ptrs.elements - 1;
|
||||
uchar *sort_buffer;
|
||||
my_off_t save_pos;
|
||||
bool error=1;
|
||||
|
||||
my_b_clear(&tempfile);
|
||||
|
||||
/* Open cached file if it isn't open */
|
||||
outfile=table->io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),MYF(MY_ZEROFILL));
|
||||
outfile=table->io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
|
||||
MYF(MY_ZEROFILL));
|
||||
|
||||
if (!outfile || ! my_b_inited(outfile) &&
|
||||
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
|
||||
@ -134,25 +134,24 @@ bool Unique::get(TABLE *table)
|
||||
sort_param.keys= max_in_memory_size / sort_param.sort_length;
|
||||
|
||||
if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) *
|
||||
sort_param.sort_length,
|
||||
MYF(0))))
|
||||
sort_param.sort_length,
|
||||
MYF(0))))
|
||||
return 1;
|
||||
sort_param.unique_buff= sort_buffer+(sort_param.keys*
|
||||
sort_param.sort_length);
|
||||
|
||||
/* Merge the buffers to one file, removing duplicates */
|
||||
if (merge_many_buff(&sort_param,sort_buffer,file_ptr,&maxbuffer,&tempfile))
|
||||
if (merge_many_buff(&sort_param,sort_buffer,file_ptr,&maxbuffer,&file))
|
||||
goto err;
|
||||
if (flush_io_cache(&tempfile) ||
|
||||
reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
|
||||
if (flush_io_cache(&file) ||
|
||||
reinit_io_cache(&file,READ_CACHE,0L,0,0))
|
||||
goto err;
|
||||
if (merge_buffers(&sort_param, &tempfile, outfile, sort_buffer, file_ptr,
|
||||
if (merge_buffers(&sort_param, &file, outfile, sort_buffer, file_ptr,
|
||||
file_ptr, file_ptr+maxbuffer,0))
|
||||
goto err;
|
||||
error=0;
|
||||
err:
|
||||
x_free((gptr) sort_buffer);
|
||||
close_cached_file(&tempfile);
|
||||
if (flush_io_cache(outfile))
|
||||
error=1;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user