Fixed multi-table-delete

Optimize fixed length MyISAM rows to use pread/pwrite.
This commit is contained in:
monty@hundin.mysql.fi 2001-06-15 05:03:15 +03:00
parent 595d087e05
commit a06f391e7a
16 changed files with 728 additions and 487 deletions

View File

@ -8,6 +8,6 @@ c_warnings="$c_warnings $debug_extra_warnings"
cxx_warnings="$cxx_warnings $debug_extra_warnings" cxx_warnings="$cxx_warnings $debug_extra_warnings"
extra_configs="$pentium_configs $debug_configs" 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" . "$path/FINISH.sh"

View File

@ -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 */ #endif /* HAVE_VIO */

View File

@ -27,17 +27,16 @@ int _mi_write_static_record(MI_INFO *info, const byte *record)
{ {
my_off_t filepos=info->s->state.dellink; my_off_t filepos=info->s->state.dellink;
info->rec_cache.seek_not_done=1; /* We have done a seek */ 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_pread(info->dfile,(char*) &temp[0],info->s->base.rec_reflength,
info->s->state.dellink+1,
if (my_read(info->dfile,(char*) &temp[0],info->s->base.rec_reflength, MYF(MY_NABP)))
MYF(MY_NABP)))
goto err; goto err;
info->s->state.dellink= _mi_rec_pos(info->s,temp); info->s->state.dellink= _mi_rec_pos(info->s,temp);
info->state->del--; info->state->del--;
info->state->empty-=info->s->base.pack_reclength; info->state->empty-=info->s->base.pack_reclength;
VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0))); if (my_pwrite(info->dfile, (char*) record, info->s->base.reclength,
if (my_write(info->dfile, (char*) record, info->s->base.reclength, filepos,
MYF(MY_NABP))) MYF(MY_NABP)))
goto err; goto err;
} }
else else
@ -64,16 +63,18 @@ int _mi_write_static_record(MI_INFO *info, const byte *record)
else else
{ {
info->rec_cache.seek_not_done=1; /* We have done a seek */ info->rec_cache.seek_not_done=1; /* We have done a seek */
VOID(my_seek(info->dfile,info->state->data_file_length, if (my_pwrite(info->dfile,(char*) record,info->s->base.reclength,
MY_SEEK_SET,MYF(0))); info->state->data_file_length,
if (my_write(info->dfile,(char*) record,info->s->base.reclength, info->s->write_flag))
info->s->write_flag))
goto err; goto err;
if (info->s->base.pack_reclength != info->s->base.reclength) if (info->s->base.pack_reclength != info->s->base.reclength)
{ {
uint length=info->s->base.pack_reclength - info->s->base.reclength; uint length=info->s->base.pack_reclength - info->s->base.reclength;
bzero((char*) temp,length); 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; 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) 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 */ 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_pwrite(info->dfile,
return (my_write(info->dfile,(char*) record,info->s->base.reclength, (char*) record,info->s->base.reclength,
MYF(MY_NABP)) != 0); 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); _mi_dpointer(info,temp+1,info->s->state.dellink);
info->s->state.dellink = info->lastpos; info->s->state.dellink = info->lastpos;
info->rec_cache.seek_not_done=1; info->rec_cache.seek_not_done=1;
VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0))); return (my_pwrite(info->dfile,(byte*) temp, 1+info->s->rec_reflength,
return (my_write(info->dfile,(byte*) temp, 1+info->s->rec_reflength, info->lastpos, MYF(MY_NABP)) != 0);
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 ((info->opt_flag & READ_CHECK_USED))
{ /* If check isn't disabled */ { /* If check isn't disabled */
info->rec_cache.seek_not_done=1; /* We have done a seek */ 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_pread(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength, info->lastpos,
MYF(MY_NABP))) MYF(MY_NABP)))
DBUG_RETURN(-1); DBUG_RETURN(-1);
if (memcmp((byte*) info->rec_buff, (byte*) old, if (memcmp((byte*) info->rec_buff, (byte*) old,
(uint) info->s->base.reclength)) (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"); DBUG_ENTER("_mi_cmp_static_unique");
info->rec_cache.seek_not_done=1; /* We have done a seek */ 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_pread(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength, pos, MYF(MY_NABP)))
MYF(MY_NABP)))
DBUG_RETURN(-1); DBUG_RETURN(-1);
DBUG_RETURN(mi_unique_comp(def, record, info->rec_buff, DBUG_RETURN(mi_unique_comp(def, record, info->rec_buff,
def->null_are_equal)); def->null_are_equal));

View File

@ -1,21 +1,11 @@
id1 t id1 t
1 3 1 3
2 2 2 2
3 1
id2 t id2 t
3 3
3 2
3 1
2 3
2 2
2 1
1 3 1 3
1 2 1 2
1 1 1 1
id3 t id3 t
3 3
3 2
3 1
2 3 2 3
2 2 2 2
2 1 2 1

View File

@ -16,10 +16,11 @@ while ($1)
dec $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 t1;
select * from t2; select * from t2;
select * from t3; select * from t3;
delete t1,t2 from t1,t2 where 1;
delete from t1,t2 where t1.id = t2.id and t1.id = 3; drop table t1,t2,t3;
select * from t1;
select * from t2;

View File

@ -724,6 +724,8 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
{ {
error=1; goto err; /* purecov: inspected */ error=1; goto err; /* purecov: inspected */
} }
buffpek->key+=sort_length;
queue_replaced(&queue); // Top element has been used
} }
else else
cmp=0; // Not unique cmp=0; // Not unique

View File

@ -147,7 +147,7 @@ void kill_one_thread(THD *thd, ulong id);
#define SELECT_BIG_RESULT 16 #define SELECT_BIG_RESULT 16
#define OPTION_FOUND_ROWS 32 #define OPTION_FOUND_ROWS 32
#define SELECT_HIGH_PRIORITY 64 /* Intern */ #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_TABLES 512 /* for SQL OPTION */
#define OPTION_BIG_SELECTS 1024 /* for SQL OPTION */ #define OPTION_BIG_SELECTS 1024 /* for SQL OPTION */

View File

@ -600,7 +600,6 @@ public:
#else #else
Unique **tempfiles; Unique **tempfiles;
#endif #endif
byte * dup_checking;
THD *thd; THD *thd;
ha_rows deleted; ha_rows deleted;
uint num_of_tables; uint num_of_tables;
@ -608,12 +607,8 @@ public:
thr_lock_type lock_option; thr_lock_type lock_option;
bool do_delete; bool do_delete;
public: public:
multi_delete(TABLE_LIST *dt, thr_lock_type lock_option_arg, uint n) multi_delete(THD *thd, TABLE_LIST *dt, thr_lock_type lock_option_arg,
: delete_tables (dt), deleted(0), num_of_tables(n), error(0), uint num_of_tables);
lock_option(lock_option_arg)
{
thd = current_thd; do_delete = false;
}
~multi_delete(); ~multi_delete();
int prepare(List<Item> &list); int prepare(List<Item> &list);
bool send_fields(List<Item> &list, bool send_fields(List<Item> &list,

View File

@ -286,112 +286,157 @@ int mysql_delete(THD *thd,
} }
/*************************************************************************** /***************************************************************************
** delete multiple tables from join ** delete multiple tables from join
***************************************************************************/ ***************************************************************************/
#ifndef DBUG_OFF
#define MEM_STRIP_BUF_SIZE 2048 #define MEM_STRIP_BUF_SIZE 2048
#else
#define MEM_STRIP_BUF_SIZE sortbuffer_size
#endif
#ifndef SINISAS_STRIP #ifndef SINISAS_STRIP
int refposcmp2(void* arg, const void *a,const void *b) int refposcmp2(void* arg, const void *a,const void *b)
{ {
return memcmp(a,b,(int)arg); return memcmp(a,b,(int) arg);
} }
#endif #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 int
multi_delete::prepare(List<Item> &values) multi_delete::prepare(List<Item> &values)
{ {
DBUG_ENTER("multi_delete::prepare"); 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; do_delete = true;
dup_checking = (byte *) sql_calloc(MAX_REFLENGTH * (num_of_tables + 1)); thd->proc_info="deleting from main table";
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++) if (thd->options & OPTION_SAFE_UPDATES)
{ {
TABLE *table=table_being_deleted->table; TABLE_LIST *table_ref;
if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys) for (table_ref=delete_tables; table_ref; table_ref=table_ref->next)
{ {
my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0)); TABLE *table=table_ref->table;
DBUG_RETURN(1); if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys)
}
(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)))
{ {
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); 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); DBUG_RETURN(0);
} }
multi_delete::~multi_delete() 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]) if (tempfiles[counter])
{
#ifdef SINISAS_STRIP #ifdef SINISAS_STRIP
// end_io_cache(tempfiles[counter]); // end_io_cache(tempfiles[counter]);
#else #else
delete tempfiles[counter]; delete tempfiles[counter];
#endif #endif
// Here it crashes ... }
}
} }
bool multi_delete::send_data(List<Item> &values) bool multi_delete::send_data(List<Item> &values)
{ {
int secure_counter = -1; int secure_counter= -1;
for (table_being_deleted=delete_tables ; table_being_deleted ; table_being_deleted=table_being_deleted->next, secure_counter++) 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 *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; /* Check if we are using outer join and we didn't find the row */
if (!table->null_row && memcmp(dup_check,table->file->ref, rl)) 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); table->status|= STATUS_DELETED;
if (secure_counter == -1) if (!(error=table->file->delete_row(table->record[0])))
{ deleted++;
if (!(error=table->file->delete_row(table->record[0])))
deleted++;
else
{
send_error(error,"An error occured in deleting rows");
return 1;
}
}
else else
{ {
table->file->print_error(error,MYF(0));
return 1;
}
}
else
{
#ifdef SINISAS_STRIP #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 #else
if (tempfiles[secure_counter]->unique_add(table->file->ref)) error=tempfiles[secure_counter]->unique_add(table->file->ref);
#endif #endif
{ if (error)
error=-1; {
return 1; error=-1;
} return 1;
} }
} }
} }
return 0; return 0;
} }
#ifdef SINISAS_STRIP #ifdef SINISAS_STRIP
static inline int COMP (byte *ml,uint len,unsigned int left, unsigned int right) 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) static bool some_table_is_not_transaction_safe (TABLE_LIST *tl)
{ {
TABLE_LIST *deleting = tl; for (; tl ; tl=tl->next)
for (deleting=deleting->next; deleting ; deleting=deleting->next)
{ {
if (!(deleting->table->file->has_transactions())) if (!(tl->table->file->has_transactions()))
return true; return true;
} }
return false; 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) 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); ::send_error(&thd->net,errcode,err);
// If nothing deleted return /* If nothing deleted return */
if (!deleted) return; if (!deleted)
// Below can happen when thread is killed ... return;
if (!table_being_deleted) table_being_deleted=delete_tables; /* Below can happen when thread is killed early ... */
// If rows from the first table only has been deleted and it is transactional, just do rollback if (!table_being_deleted)
// The same if all tables are transactional, regardless of where we are. In all other cases do attempt deletes ... table_being_deleted=delete_tables;
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 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) else if (do_delete)
VOID(do_deletes(true)); 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; int error = 0, counter = 0, count;
if (from_send_error) 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++; counter++;
} }
else else
table_being_deleted = delete_tables; table_being_deleted = delete_tables;
do_delete = false; 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 #ifdef SINISAS_STRIP
int num_of_positions = (int)my_b_tell(tempfiles[counter])/rl; int num_of_positions = (int)my_b_tell(tempfiles[counter])/rl;
if (!num_of_positions) continue; if (!num_of_positions) continue;
@ -766,11 +829,20 @@ int multi_delete::do_deletes (bool from_send_error)
error=1; break; error=1; break;
} }
#else #else
tempfiles[counter]->get(table); if (tempfiles[counter]->get(table))
{
error=1;
break;
}
#endif #endif
#if 0
if (num_of_positions == table->file->records) // nice little optimization .... #if USE_REGENERATE_TABLE
{ // but Monty has to fix generate_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; TABLE_LIST table_list;
bzero((char*) &table_list,sizeof(table_list)); bzero((char*) &table_list,sizeof(table_list));
table_list.name=table->table_name; table_list.real_name=table_being_deleted->real_name; 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); error=generate_table(thd,&table_list,(TABLE *)0);
if (error <= 0) {error = 1; break;} if (error <= 0) {error = 1; break;}
deleted += num_of_positions; deleted += num_of_positions;
continue;
} }
else #endif /* USE_REGENERATE_TABLE */
{
#endif READ_RECORD info;
READ_RECORD info; error=0; error=0;
#ifdef SINISAS_STRIP #ifdef SINISAS_STRIP
SQL_SELECT *select= new SQL_SELECT; SQL_SELECT *select= new SQL_SELECT;
select->head=table; select->head=table;
select->file=*tempfiles[counter]; select->file=*tempfiles[counter];
init_read_record(&info,thd,table,select,0,0); init_read_record(&info,thd,table,select,0,0);
#else #else
init_read_record(&info,thd,table,NULL,0,0); init_read_record(&info,thd,table,NULL,0,0);
#endif #endif
bool not_trans_safe = some_table_is_not_transaction_safe(delete_tables); 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)) 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]); table->file->print_error(error,MYF(0));
if (error) break;
{
table->file->print_error(error,MYF(0));
break;
}
else
deleted++;
} }
end_read_record(&info); else
#ifdef SINISAS_STRIP deleted++;
delete select;
#endif
if (error == -1)
error = 0;
#if 0
} }
end_read_record(&info);
#ifdef SINISAS_STRIP
delete select;
#endif #endif
if (error == -1)
error = 0;
} }
return error; return error;
} }
bool multi_delete::send_eof() bool multi_delete::send_eof()
{ {
int error = 0; thd->proc_info="deleting from reference tables";
error = do_deletes(false); int error = do_deletes(false);
thd->proc_info="end"; thd->proc_info="end";
if (error && error != -1) if (error && error != -1)
{ {
::send_error(&thd->net); ::send_error(&thd->net);
return 1; return 1;
} }
for (table_being_deleted=delete_tables ; table_being_deleted ; table_being_deleted=table_being_deleted->next)
{ if (deleted &&
TABLE *table=table_being_deleted->table; (error <= 0 || some_table_is_not_transaction_safe(delete_tables)))
if (table)
VOID(table->file->extra(HA_EXTRA_READCHECK));
}
if (deleted && (error <= 0 || some_table_is_not_transaction_safe(delete_tables)))
{ {
mysql_update_log.write(thd,thd->query,thd->query_length); mysql_update_log.write(thd,thd->query,thd->query_length);
Query_log_event qinfo(thd, thd->query); Query_log_event qinfo(thd, thd->query);
if (mysql_bin_log.write(&qinfo) && !some_table_is_not_transaction_safe(delete_tables)) if (mysql_bin_log.write(&qinfo) &&
error=1; !some_table_is_not_transaction_safe(delete_tables))
error=1; // Rollback
VOID(ha_autocommit_or_rollback(thd,error >= 0)); VOID(ha_autocommit_or_rollback(thd,error >= 0));
} }
::send_ok(&thd->net,deleted); ::send_ok(&thd->net,deleted);
return 0; return 0;
} }

View File

@ -1649,97 +1649,98 @@ mysql_execute_command(void)
if (lex->sql_command == SQLCOM_TRUNCATE && end_active_trans(thd)) if (lex->sql_command == SQLCOM_TRUNCATE && end_active_trans(thd))
res= -1; res= -1;
else else
res = mysql_delete(thd,tables, select_lex->where, (ORDER*)select_lex->order_list.first, res = mysql_delete(thd,tables, select_lex->where,
select_lex->select_limit, lex->lock_option, select_lex->options); (ORDER*) select_lex->order_list.first,
select_lex->select_limit, lex->lock_option,
select_lex->options);
break; break;
} }
case SQLCOM_MULTI_DELETE: case SQLCOM_MULTI_DELETE:
{ {
TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first; TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first;
multi_delete *result; TABLE_LIST *auxi;
uint table_count=0;
multi_delete *result;
if (!tables || !aux_tables || /* sql_yacc guarantees that tables and aux_tables are not zero */
check_table_access(thd,SELECT_ACL, tables) || if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
check_table_access(thd,DELETE_ACL,aux_tables)) check_table_access(thd,SELECT_ACL, tables) ||
{ check_table_access(thd,DELETE_ACL, aux_tables))
res=-1; goto error;
goto error; if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
} {
if (!tables->db) send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
tables->db=thd->db; goto error;
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where) }
{ for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); {
res=1; goto error; table_count++;
} /* All tables in aux_tables must be found in FROM PART */
uint howmuch=0; TABLE_LIST *walk, *auxi; TABLE_LIST *walk;
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next, howmuch++) for (walk=(TABLE_LIST*) tables ; walk ; walk=walk->next)
{ {
if (!auxi->db) if (!strcmp(auxi->real_name,walk->real_name) &&
auxi->db=thd->db; !strcmp(walk->db,auxi->db))
if (!auxi->real_name) break;
auxi->real_name=auxi->name; }
for (walk=(TABLE_LIST*) tables ; walk ; walk=walk->next) if (!walk)
{ {
if (!walk->db) walk->db=thd->db; net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name);
if (!strcmp(auxi->real_name,walk->real_name) && !strcmp(walk->db,auxi->db)) goto error;
break; }
} auxi->lock_type=walk->lock_type=TL_WRITE;
if (!walk) auxi->table= (TABLE *) walk; // Remember corresponding table
{ }
net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name); tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
res=-2; goto error; if (add_item_to_list(new Item_null()))
} {
else res= -1;
{ break;
auxi->lock_type=walk->lock_type=TL_WRITE; }
auxi->table= (TABLE *) walk; thd->proc_info="init";
} if ((res=open_and_lock_tables(thd,tables)))
} break;
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); /* Fix tables-to-be-deleted-from list to point at opened tables */
if (add_item_to_list(new Item_null())) goto error; for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
thd->proc_info="init"; auxi->table= ((TABLE_LIST*) auxi->table)->table;
if (open_and_lock_tables(thd,tables)) if ((result=new multi_delete(thd,aux_tables,lex->lock_option,
{ table_count)) && ! thd->fatal_error)
res=-1; goto error; {
} res=mysql_select(thd,tables,select_lex->item_list,
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next) select_lex->where,select_lex->ftfunc_list,
auxi->table= ((TABLE_LIST*) auxi->table)->table; (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
if ((result=new multi_delete(aux_tables,lex->lock_option,howmuch))) (ORDER *)NULL,
{ select_lex->options | thd->options |
res=mysql_select(thd,tables,select_lex->item_list, SELECT_NO_JOIN_CACHE,
select_lex->where,select_lex->ftfunc_list, result);
(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL, }
(ORDER *)NULL, else
select_lex->options | thd->options, res= -1; // Error is not sent
result); delete result;
delete result; close_thread_tables(thd);
} break;
else }
res= -1;
close_thread_tables(thd);
break;
}
case SQLCOM_UNION_SELECT: case SQLCOM_UNION_SELECT:
{ {
uint total_selects = select_lex->select_number; total_selects++;
SQL_LIST *total=(SQL_LIST *) thd->calloc(sizeof(SQL_LIST)); SQL_LIST *total=(SQL_LIST *) thd->calloc(sizeof(SQL_LIST));
if (select_lex->options & SELECT_DESCRIBE) if (select_lex->options & SELECT_DESCRIBE)
lex->exchange=0; lex->exchange=0;
res = link_in_large_list_and_check_acl(thd,lex,total); if ((res = link_in_large_list_and_check_acl(thd,lex,total)) == -1)
if (res == -1)
{ {
res=0; res=0;
break; 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; res=0;
break; break;
} }
if (!(res=open_and_lock_tables(thd,(TABLE_LIST *)total->first))) 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; if (res==-1) res=0;
} }
break; break;
@ -1768,7 +1769,7 @@ mysql_execute_command(void)
break; break;
case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_DATABASES:
#if defined(DONT_ALLOW_SHOW_COMMANDS) #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; DBUG_VOID_RETURN;
#else #else
if ((specialflag & SPECIAL_SKIP_SHOW_DB) && if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&

View File

@ -484,8 +484,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
(group && order) || (group && order) ||
test(select_options & OPTION_BUFFER_RESULT))); test(select_options & OPTION_BUFFER_RESULT)));
make_join_readinfo(&join, (select_options & SELECT_DESCRIBE) | // No cache for MATCH
(ftfuncs.elements ? 0 : SELECT_USE_CACHE)); // 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 /* Need to tell Innobase that to play it safe, it should fetch all
columns of the tables: this is because MySQL columns of the tables: this is because MySQL
@ -2465,7 +2468,7 @@ make_join_readinfo(JOIN *join,uint options)
** if previous table use cache ** if previous table use cache
*/ */
table->status=STATUS_NO_RECORD; 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) tab->use_quick != 2 && !tab->on_expr)
{ {
if ((options & SELECT_DESCRIBE) || if ((options & SELECT_DESCRIBE) ||

View File

@ -59,9 +59,9 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
VOID(pthread_mutex_lock(&LOCK_open)); VOID(pthread_mutex_lock(&LOCK_open));
pthread_mutex_unlock(&thd->mysys_var->mutex); 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), my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,MYF(0),
tables->real_name); tables->real_name);

View File

@ -30,4 +30,5 @@ int mysql_union(THD *thd,LEX *lex,uint no_of_selects)
for (sl=&lex->select_lex;sl;sl=sl->next) for (sl=&lex->select_lex;sl;sl=sl->next)
{ {
} }
return 0;
} }

File diff suppressed because it is too large Load Diff

View File

@ -164,3 +164,4 @@ typedef struct st_lex_user {
#define STATUS_NOT_READ 8 /* Record isn't read */ #define STATUS_NOT_READ 8 /* Record isn't read */
#define STATUS_UPDATED 16 /* Record is updated by formula */ #define STATUS_UPDATED 16 /* Record is updated by formula */
#define STATUS_NULL_ROW 32 /* table->null_row is set */ #define STATUS_NULL_ROW 32 /* table->null_row is set */
#define STATUS_DELETED 64

View File

@ -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 */ /* If the following fail's the next add will also fail */
init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16); init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16);
max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size); 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; SORTPARAM sort_param;
table->found_records=elements+tree.elements_in_tree; 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 */ /* Whole tree is in memory; Don't use disk if you don't need to */
if ((record_pointers=table->record_pointers= (byte*) if ((record_pointers=table->record_pointers= (byte*)
@ -110,17 +111,16 @@ bool Unique::get(TABLE *table)
if (flush()) if (flush())
return 1; return 1;
IO_CACHE *outfile=table->io_cache, tempfile; IO_CACHE *outfile=table->io_cache;
BUFFPEK *file_ptr= (BUFFPEK*) file_ptrs.buffer; BUFFPEK *file_ptr= (BUFFPEK*) file_ptrs.buffer;
uint maxbuffer= file_ptrs.elements - 1; uint maxbuffer= file_ptrs.elements - 1;
uchar *sort_buffer; uchar *sort_buffer;
my_off_t save_pos; my_off_t save_pos;
bool error=1; bool error=1;
my_b_clear(&tempfile);
/* Open cached file if it isn't open */ /* 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) && if (!outfile || ! my_b_inited(outfile) &&
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER, 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; sort_param.keys= max_in_memory_size / sort_param.sort_length;
if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) * if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) *
sort_param.sort_length, sort_param.sort_length,
MYF(0)))) MYF(0))))
return 1; return 1;
sort_param.unique_buff= sort_buffer+(sort_param.keys* sort_param.unique_buff= sort_buffer+(sort_param.keys*
sort_param.sort_length); sort_param.sort_length);
/* Merge the buffers to one file, removing duplicates */ /* 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; goto err;
if (flush_io_cache(&tempfile) || if (flush_io_cache(&file) ||
reinit_io_cache(&tempfile,READ_CACHE,0L,0,0)) reinit_io_cache(&file,READ_CACHE,0L,0,0))
goto err; 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)) file_ptr, file_ptr+maxbuffer,0))
goto err; goto err;
error=0; error=0;
err: err:
x_free((gptr) sort_buffer); x_free((gptr) sort_buffer);
close_cached_file(&tempfile);
if (flush_io_cache(outfile)) if (flush_io_cache(outfile))
error=1; error=1;