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"
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"

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 */

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;
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));

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -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,

View File

@ -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;
}

View File

@ -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) &&

View File

@ -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) ||

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));
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);

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)
{
}
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_UPDATED 16 /* Record is updated by formula */
#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 */
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;