Commit a06f391e authored by monty@hundin.mysql.fi's avatar monty@hundin.mysql.fi

Fixed multi-table-delete

Optimize fixed length MyISAM rows to use pread/pwrite.
parent 595d087e
......@@ -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));
......
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
int
multi_delete::prepare(List<Item> &values)
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)
{
DBUG_ENTER("multi_delete::prepare");
uint counter = 0;
uint counter=0;
#ifdef SINISAS_STRIP
tempfiles = (IO_CACHE **) sql_calloc(sizeof(IO_CACHE *)*(num_of_tables));
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));
tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
#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++)
(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=table_being_deleted->table;
if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys)
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_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0));
DBUG_RETURN(1);
my_error(ER_CANT_OPEN_FILE,MYF(0),(tempfiles[counter])->file_name,errno);
thd->fatal_error=1;
return;
}
(void) table->file->extra(HA_EXTRA_NO_READCHECK);
if (counter < num_of_tables)
#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");
do_delete = true;
thd->proc_info="deleting from main table";
if (thd->options & OPTION_SAFE_UPDATES)
{
TABLE_LIST *table_ref;
for (table_ref=delete_tables; table_ref; table_ref=table_ref->next)
{
#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;
}
......@@ -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;
}
......@@ -543,7 +543,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
opt_mi_check_type opt_to mi_check_types normal_join
table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_rkey_mode handler_read_or_scan
single_multi table_multi_delete table_sini_wild union union_list
single_multi table_wild_list table_wild_one opt_wild union union_list
precision
END_OF_INPUT
%type <NONE>
......@@ -650,7 +651,6 @@ master_def:
}
/* create a table */
create:
......@@ -674,36 +674,41 @@ create:
| CREATE opt_unique_or_fulltext INDEX ident ON table_ident
{
Lex->sql_command= SQLCOM_CREATE_INDEX;
LEX *lex=Lex;
lex->sql_command= SQLCOM_CREATE_INDEX;
if (!add_table_to_list($6,NULL,1))
YYABORT;
Lex->create_list.empty();
Lex->key_list.empty();
Lex->col_list.empty();
Lex->change=NullS;
lex->create_list.empty();
lex->key_list.empty();
lex->col_list.empty();
lex->change=NullS;
}
'(' key_list ')'
{
Lex->key_list.push_back(new Key($2,$4.str,Lex->col_list));
Lex->col_list.empty();
LEX *lex=Lex;
lex->key_list.push_back(new Key($2,$4.str,lex->col_list));
lex->col_list.empty();
}
| CREATE DATABASE opt_if_not_exists ident
{
Lex->sql_command=SQLCOM_CREATE_DB;
Lex->name=$4.str;
Lex->create_info.options=$3;
LEX *lex=Lex;
lex->sql_command=SQLCOM_CREATE_DB;
lex->name=$4.str;
lex->create_info.options=$3;
}
| CREATE udf_func_type UDF_SYM ident
{
Lex->sql_command = SQLCOM_CREATE_FUNCTION;
Lex->udf.name=$4.str;
Lex->udf.name_length=$4.length;
Lex->udf.type= $2;
LEX *lex=Lex;
lex->sql_command = SQLCOM_CREATE_FUNCTION;
lex->udf.name=$4.str;
lex->udf.name_length=$4.length;
lex->udf.type= $2;
}
UDF_RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING
{
Lex->udf.returns=(Item_result) $7;
Lex->udf.dl=$9.str;
LEX *lex=Lex;
lex->udf.returns=(Item_result) $7;
lex->udf.dl=$9.str;
}
create2:
......@@ -714,8 +719,9 @@ create3:
/* empty */ {}
| opt_duplicate opt_as SELECT_SYM
{
Lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
mysql_init_select(Lex);
LEX *lex=Lex;
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
mysql_init_select(lex);
}
select_options select_item_list opt_select_from {}
......@@ -823,8 +829,9 @@ field_list_item:
}
| key_type opt_ident '(' key_list ')'
{
Lex->key_list.push_back(new Key($1,$2,Lex->col_list));
Lex->col_list.empty(); /* Alloced by sql_alloc */
LEX *lex=Lex;
lex->key_list.push_back(new Key($1,$2,lex->col_list));
lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
{
......@@ -842,16 +849,18 @@ opt_constraint:
field_spec:
field_ident
{
Lex->length=Lex->dec=0; Lex->type=0; Lex->interval=0;
Lex->default_value=0;
LEX *lex=Lex;
lex->length=lex->dec=0; lex->type=0; lex->interval=0;
lex->default_value=0;
}
type opt_attribute
{
LEX *lex=Lex;
if (add_field_to_list($1.str,
(enum enum_field_types) $3,
Lex->length,Lex->dec,Lex->type,
Lex->default_value,Lex->change,
Lex->interval))
lex->length,lex->dec,lex->type,
lex->default_value,lex->change,
lex->interval))
YYABORT;
}
......@@ -903,12 +912,14 @@ type:
{ $$=FIELD_TYPE_DECIMAL;}
| ENUM {Lex->interval_list.empty();} '(' string_list ')'
{
Lex->interval=typelib(Lex->interval_list);
LEX *lex=Lex;
lex->interval=typelib(lex->interval_list);
$$=FIELD_TYPE_ENUM;
}
| SET { Lex->interval_list.empty();} '(' string_list ')'
{
Lex->interval=typelib(Lex->interval_list);
LEX *lex=Lex;
lex->interval=typelib(lex->interval_list);
$$=FIELD_TYPE_SET;
}
......@@ -940,7 +951,14 @@ real_type:
float_options:
/* empty */ {}
| '(' NUM ')' { Lex->length=$2.str; }
| '(' NUM ',' NUM ')' { Lex->length=$2.str; Lex->dec=$4.str; }
| precision {}
precision:
'(' NUM ',' NUM ')'
{
LEX *lex=Lex;
lex->length=$2.str; lex->dec=$4.str;
}
field_options:
/* empty */ {}
......@@ -960,7 +978,7 @@ opt_len:
opt_precision:
/* empty */ {}
| '(' NUM ',' NUM ')' { Lex->length=$2.str; Lex->dec=$4.str; }
| precision {}
opt_attribute:
/* empty */ {}
......@@ -1088,42 +1106,69 @@ add_column:
alter_list_item:
add_column field_list_item opt_place { Lex->simple_alter=0; }
| add_column '(' field_list ')' { Lex->simple_alter=0; }
| CHANGE opt_column field_ident { Lex->change= $3.str; Lex->simple_alter=0; }
| CHANGE opt_column field_ident
{
LEX *lex=Lex;
lex->change= $3.str; lex->simple_alter=0;
}
field_spec
| MODIFY_SYM opt_column field_ident
{
Lex->length=Lex->dec=0; Lex->type=0; Lex->interval=0;
Lex->default_value=0;
Lex->simple_alter=0;
LEX *lex=Lex;
lex->length=lex->dec=0; lex->type=0; lex->interval=0;
lex->default_value=0;
lex->simple_alter=0;
}
type opt_attribute
{
LEX *lex=Lex;
if (add_field_to_list($3.str,
(enum enum_field_types) $5,
Lex->length,Lex->dec,Lex->type,
Lex->default_value, $3.str,
Lex->interval))
lex->length,lex->dec,lex->type,
lex->default_value, $3.str,
lex->interval))
YYABORT;
Lex->simple_alter=0;
lex->simple_alter=0;
}
| DROP opt_column field_ident opt_restrict
{ Lex->drop_list.push_back(new Alter_drop(Alter_drop::COLUMN,
$3.str)); Lex->simple_alter=0; }
| DROP PRIMARY_SYM KEY_SYM { Lex->drop_primary=1; Lex->simple_alter=0; }
{
LEX *lex=Lex;
lex->drop_list.push_back(new Alter_drop(Alter_drop::COLUMN,
$3.str)); lex->simple_alter=0;
}
| DROP PRIMARY_SYM KEY_SYM
{
LEX *lex=Lex;
lex->drop_primary=1; lex->simple_alter=0;
}
| DROP FOREIGN KEY_SYM opt_ident { Lex->simple_alter=0; }
| DROP key_or_index field_ident
{ Lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
$3.str)); Lex->simple_alter=0; }
{
LEX *lex=Lex;
lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
$3.str));
lex->simple_alter=0;
}
| DISABLE_SYM KEYS { Lex->alter_keys_onoff=DISABLE; }
| ENABLE_SYM KEYS { Lex->alter_keys_onoff=ENABLE; }
| ALTER opt_column field_ident SET DEFAULT literal
{ Lex->alter_list.push_back(new Alter_column($3.str,$6)); Lex->simple_alter=0; }
{
LEX *lex=Lex;
lex->alter_list.push_back(new Alter_column($3.str,$6));
lex->simple_alter=0;
}
| ALTER opt_column field_ident DROP DEFAULT
{ Lex->alter_list.push_back(new Alter_column($3.str,(Item*) 0)); Lex->simple_alter=0; }
{
LEX *lex=Lex;
lex->alter_list.push_back(new Alter_column($3.str,(Item*) 0));
lex->simple_alter=0;
}
| RENAME opt_to table_alias table_ident
{
LEX *lex=Lex;
lex->select->db=$4->db.str ; lex->name= $4->table.str; lex->simple_alter=0;
lex->select->db=$4->db.str;
lex->name= $4->table.str;
lex->simple_alter=0;
}
| create_table_options { Lex->simple_alter=0; }
| order_clause { Lex->simple_alter=0; }
......@@ -1154,14 +1199,16 @@ opt_to:
slave:
SLAVE START_SYM
{
Lex->sql_command = SQLCOM_SLAVE_START;
Lex->type = 0;
LEX *lex=Lex;
lex->sql_command = SQLCOM_SLAVE_START;
lex->type = 0;
}
|
SLAVE STOP_SYM
{
Lex->sql_command = SQLCOM_SLAVE_STOP;
Lex->type = 0;
LEX *lex=Lex;
lex->sql_command = SQLCOM_SLAVE_STOP;
lex->type = 0;
};
restore:
......@@ -1187,8 +1234,9 @@ backup:
repair:
REPAIR table_or_tables
{
Lex->sql_command = SQLCOM_REPAIR;
Lex->check_opt.init();
LEX *lex=Lex;
lex->sql_command = SQLCOM_REPAIR;
lex->check_opt.init();
}
table_list opt_mi_check_type
......@@ -1212,24 +1260,27 @@ mi_check_type:
analyze:
ANALYZE_SYM table_or_tables
{
Lex->sql_command = SQLCOM_ANALYZE;
Lex->check_opt.init();
LEX *lex=Lex;
lex->sql_command = SQLCOM_ANALYZE;
lex->check_opt.init();
}
table_list opt_mi_check_type
check:
CHECK_SYM table_or_tables
{
Lex->sql_command = SQLCOM_CHECK;
Lex->check_opt.init();
LEX *lex=Lex;
lex->sql_command = SQLCOM_CHECK;
lex->check_opt.init();
}
table_list opt_mi_check_type
optimize:
OPTIMIZE table_or_tables
{
Lex->sql_command = SQLCOM_OPTIMIZE;
Lex->check_opt.init();
LEX *lex=Lex;
lex->sql_command = SQLCOM_OPTIMIZE;
lex->check_opt.init();
}
table_list opt_mi_check_type
......@@ -1753,13 +1804,15 @@ when_list:
when_list2:
expr THEN_SYM expr
{
Select->when_list.head()->push_back($1);
Select->when_list.head()->push_back($3);
SELECT_LEX *sel=Select;
sel->when_list.head()->push_back($1);
sel->when_list.head()->push_back($3);
}
| when_list2 WHEN_SYM expr THEN_SYM expr
{
Select->when_list.head()->push_back($3);
Select->when_list.head()->push_back($5);
SELECT_LEX *sel=Select;
sel->when_list.head()->push_back($3);
sel->when_list.head()->push_back($5);
}
opt_pad:
......@@ -1774,15 +1827,21 @@ join_table_list:
| join_table_list INNER_SYM JOIN_SYM join_table ON expr
{ add_join_on($4,$6); $$=$4; }
| join_table_list INNER_SYM JOIN_SYM join_table
{ Select->db1=$1->db; Select->table1=$1->name;
Select->db2=$4->db; Select->table2=$4->name; }
{
SELECT_LEX *sel=Select;
sel->db1=$1->db; sel->table1=$1->name;
sel->db2=$4->db; sel->table2=$4->name;
}
USING '(' using_list ')'
{ add_join_on($4,$8); $$=$4; }
| join_table_list LEFT opt_outer JOIN_SYM join_table ON expr
{ add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
| join_table_list LEFT opt_outer JOIN_SYM join_table
{ Select->db1=$1->db; Select->table1=$1->name;
Select->db2=$5->db; Select->table2=$5->name; }
{
SELECT_LEX *sel=Select;
sel->db1=$1->db; sel->table1=$1->name;
sel->db2=$5->db; sel->table2=$5->name;
}
USING '(' using_list ')'
{ add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
| join_table_list NATURAL LEFT opt_outer JOIN_SYM join_table
......@@ -1790,8 +1849,11 @@ join_table_list:
| join_table_list RIGHT opt_outer JOIN_SYM join_table ON expr
{ add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; }
| join_table_list RIGHT opt_outer JOIN_SYM join_table
{ Select->db1=$1->db; Select->table1=$1->name;
Select->db2=$5->db; Select->table2=$5->name; }
{
SELECT_LEX *sel=Select;
sel->db1=$1->db; sel->table1=$1->name;
sel->db2=$5->db; sel->table2=$5->name;
}
USING '(' using_list ')'
{ add_join_on($1,$9); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; }
| join_table_list NATURAL RIGHT opt_outer JOIN_SYM join_table
......@@ -1805,10 +1867,16 @@ normal_join:
| CROSS JOIN_SYM {}
join_table:
{ Select->use_index_ptr=Select->ignore_index_ptr=0; }
{
SELECT_LEX *sel=Select;
sel->use_index_ptr=sel->ignore_index_ptr=0;
}
table_ident opt_table_alias opt_key_definition
{ if (!($$=add_table_to_list($2,$3,0,TL_UNLOCK, Select->use_index_ptr,
Select->ignore_index_ptr))) YYABORT; }
{
SELECT_LEX *sel=Select;
if (!($$=add_table_to_list($2,$3,0,TL_UNLOCK, sel->use_index_ptr,
sel->ignore_index_ptr))) YYABORT;
}
| '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}'
{ add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
......@@ -1819,9 +1887,17 @@ opt_outer:
opt_key_definition:
/* empty */ {}
| USE_SYM key_usage_list
{ Select->use_index= *$2; Select->use_index_ptr= &Select->use_index; }
{
SELECT_LEX *sel=Select;
sel->use_index= *$2;
sel->use_index_ptr= &sel->use_index;
}
| IGNORE_SYM key_usage_list
{ Select->ignore_index= *$2; Select->ignore_index_ptr= &Select->ignore_index;}
{
SELECT_LEX *sel=Select;
sel->ignore_index= *$2;
sel->ignore_index_ptr= &sel->ignore_index;
}
key_usage_list:
key_or_index { Select->interval_list.empty() } '(' key_usage_list2 ')'
......@@ -1837,12 +1913,15 @@ key_usage_list2:
using_list:
ident
{ if (!($$= new Item_func_eq(new Item_field(Select->db1,Select->table1, $1.str), new Item_field(Select->db2,Select->table2,$1.str))))
{
SELECT_LEX *sel=Select;
if (!($$= new Item_func_eq(new Item_field(sel->db1,sel->table1, $1.str), new Item_field(sel->db2,sel->table2,$1.str))))
YYABORT;
}
| using_list ',' ident
{
if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(Select->db1,Select->table1,$3.str), new Item_field(Select->db2,Select->table2,$3.str)), $1)))
SELECT_LEX *sel=Select;
if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(sel->db1,sel->table1,$3.str), new Item_field(sel->db2,sel->table2,$3.str)), $1)))
YYABORT;
}
......@@ -1879,7 +1958,10 @@ where_clause:
having_clause:
/* empty */
| HAVING { Select->create_refs=1; } expr
{ Select->having= $3; Select->create_refs=0; }
{
SELECT_LEX *sel=Select;
sel->having= $3; sel->create_refs=0;
}
opt_escape:
ESCAPE_SYM TEXT_STRING { $$= $2.str; }
......@@ -1926,14 +2008,21 @@ order_dir:
limit_clause:
/* empty */
{
Select->select_limit= (Lex->sql_command == SQLCOM_HA_READ) ?
SELECT_LEX *sel=Select;
sel->select_limit= (Lex->sql_command == SQLCOM_HA_READ) ?
1 : current_thd->default_select_limit;
Select->offset_limit= 0L;
sel->offset_limit= 0L;
}
| LIMIT ULONG_NUM
{ Select->select_limit= $2; Select->offset_limit=0L; }
{
SELECT_LEX *sel=Select;
sel->select_limit= $2; sel->offset_limit=0L;
}
| LIMIT ULONG_NUM ',' ULONG_NUM
{ Select->select_limit= $4; Select->offset_limit=$2; }
{
SELECT_LEX *sel=Select;
sel->select_limit= $4; sel->offset_limit=$2;
}
delete_limit_clause:
/* empty */
......@@ -1944,14 +2033,14 @@ delete_limit_clause:
{ Select->select_limit= (ha_rows) $2; }
ULONG_NUM:
NUM { $$= strtoul($1.str,NULL,10); }
| REAL_NUM { $$= strtoul($1.str,NULL,10); }
NUM { $$= strtoul($1.str,NULL,10); }
| REAL_NUM { $$= strtoul($1.str,NULL,10); }
| FLOAT_NUM { $$= strtoul($1.str,NULL,10); }
ULONGLONG_NUM:
NUM { $$= (ulonglong) strtoul($1.str,NULL,10); }
| LONG_NUM { $$= strtoull($1.str,NULL,10); }
| REAL_NUM { $$= strtoull($1.str,NULL,10); }
NUM { $$= (ulonglong) strtoul($1.str,NULL,10); }
| LONG_NUM { $$= strtoull($1.str,NULL,10); }
| REAL_NUM { $$= strtoull($1.str,NULL,10); }
| FLOAT_NUM { $$= strtoull($1.str,NULL,10); }
procedure_clause:
......@@ -2006,28 +2095,32 @@ opt_into:
drop:
DROP TABLE_SYM if_exists table_list opt_restrict
{
Lex->sql_command = SQLCOM_DROP_TABLE;
Lex->drop_if_exists = $3;
LEX *lex=Lex;
lex->sql_command = SQLCOM_DROP_TABLE;
lex->drop_if_exists = $3;
}
| DROP INDEX ident ON table_ident {}
{
Lex->sql_command= SQLCOM_DROP_INDEX;
Lex->drop_list.empty();
Lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
LEX *lex=Lex;
lex->sql_command= SQLCOM_DROP_INDEX;
lex->drop_list.empty();
lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
$3.str));
if (!add_table_to_list($5,NULL, 1))
YYABORT;
}
| DROP DATABASE if_exists ident
{
Lex->sql_command= SQLCOM_DROP_DB;
Lex->drop_if_exists=$3;
Lex->name=$4.str;
LEX *lex=Lex;
lex->sql_command= SQLCOM_DROP_DB;
lex->drop_if_exists=$3;
lex->name=$4.str;
}
| DROP UDF_SYM ident
{
Lex->sql_command = SQLCOM_DROP_FUNCTION;
Lex->udf.name=$3.str;
LEX *lex=Lex;
lex->sql_command = SQLCOM_DROP_FUNCTION;
lex->udf.name=$3.str;
}
......@@ -2070,17 +2163,19 @@ insert2:
insert_table:
table_name
{
Lex->field_list.empty();
Lex->many_values.empty();
Lex->insert_list=0;
LEX *lex=Lex;
lex->field_list.empty();
lex->many_values.empty();
lex->insert_list=0;
}
insert_field_spec:
opt_field_spec insert_values {}
| SET
{
if (!(Lex->insert_list = new List_item) ||
Lex->many_values.push_back(Lex->insert_list))
LEX *lex=Lex;
if (!(lex->insert_list = new List_item) ||
lex->many_values.push_back(lex->insert_list))
YYABORT;
}
ident_eq_list
......@@ -2118,8 +2213,9 @@ ident_eq_list:
ident_eq_value:
simple_ident equal expr
{
if (Lex->field_list.push_back($1) ||
Lex->insert_list->push_back($3))
LEX *lex=Lex;
if (lex->field_list.push_back($1) ||
lex->insert_list->push_back($3))
YYABORT;
}
......@@ -2134,7 +2230,8 @@ no_braces:
}
opt_values ')'
{
if (Lex->many_values.push_back(Lex->insert_list))
LEX *lex=Lex;
if (lex->many_values.push_back(lex->insert_list))
YYABORT;
}
......@@ -2163,10 +2260,11 @@ update:
opt_order_clause
delete_limit_clause
{
Lex->sql_command = SQLCOM_UPDATE;
Select->order_list.elements=0;
Select->order_list.first=0;
Select->order_list.next= (byte**) &Select->order_list.first;
LEX *lex=Lex;
lex->sql_command = SQLCOM_UPDATE;
lex->select->order_list.elements=0;
lex->select->order_list.first=0;
lex->select->order_list.next= (byte**) &lex->select->order_list.first;
}
update_list:
......@@ -2190,49 +2288,60 @@ opt_low_priority:
delete:
DELETE_SYM
{
Lex->sql_command= SQLCOM_DELETE; Select->options=0;
Lex->lock_option= current_thd->update_lock_default;
Select->order_list.elements=0;
Select->order_list.first=0;
Select->order_list.next= (byte**) &Select->order_list.first;
}
opt_delete_options single_multi {}
LEX *lex=Lex;
lex->sql_command= SQLCOM_DELETE; lex->select->options=0;
lex->lock_option= lex->thd->update_lock_default;
lex->select->order_list.elements=0;
lex->select->order_list.first=0;
lex->select->order_list.next= (byte**) &lex->select->order_list.first;
}
opt_delete_options single_multi {}
single_multi:
FROM table_name where_clause opt_order_clause delete_limit_clause {}
| table_multi_delete
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_MULTI_DELETE;
mysql_init_select(lex);
lex->select->select_limit=HA_POS_ERROR;
lex->auxilliary_table_list.elements=0;
lex->auxilliary_table_list.first=0;
lex->auxilliary_table_list.next= (byte**) &(lex->auxilliary_table_list.first);
}
FROM
{
current_thd->lex.auxilliary_table_list=current_thd->lex.select_lex.table_list;
current_thd->lex.select->table_list.elements=0;
current_thd->lex.select->table_list.first=0;
current_thd->lex.select->table_list.next= (byte**) &(current_thd->lex.select->table_list.first);
} join_table_list where_clause
table_multi_delete:
table_sini_wild {}
| table_multi_delete ',' table_sini_wild {}
table_sini_wild:
ident '.' '*' { if (!add_table_to_list(new Table_ident($1),NULL,1,TL_WRITE)) YYABORT; }
| ident '.' ident '.' '*'
{ if (!add_table_to_list(new Table_ident($1,$3,0),NULL,1,TL_WRITE)) YYABORT;}
| ident { if (!add_table_to_list(new Table_ident($1),NULL,1,TL_WRITE)) YYABORT; }
| ident '.' ident
{ if (!add_table_to_list(new Table_ident($1,$3,0),NULL,1,TL_WRITE)) YYABORT;}
FROM table_name where_clause opt_order_clause delete_limit_clause {}
| table_wild_list
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_MULTI_DELETE;
mysql_init_select(lex);
lex->select->select_limit=HA_POS_ERROR;
lex->auxilliary_table_list.elements=0;
lex->auxilliary_table_list.first=0;
lex->auxilliary_table_list.next= (byte**) &(lex->auxilliary_table_list.first);
}
FROM
{
LEX *lex=Lex;
lex->auxilliary_table_list=lex->select_lex.table_list;
lex->select->table_list.elements=0;
lex->select->table_list.first=0;
lex->select->table_list.next= (byte**) &(lex->select->table_list.first);
} join_table_list where_clause
table_wild_list:
table_wild_one {}
| table_wild_list ',' table_wild_one {}
table_wild_one:
ident opt_wild
{
if (!add_table_to_list(new Table_ident($1),NULL,1,TL_WRITE))
YYABORT;
}
| ident '.' ident opt_wild
{
if (!add_table_to_list(new Table_ident($1,$3,0),NULL,1,TL_WRITE))
YYABORT;
}
opt_wild:
/* empty */ {}
| '.' '*' {}
opt_delete_options:
/* empty */ {}
/* empty */ {}
| opt_delete_option opt_delete_options {}
opt_delete_option:
......@@ -2244,11 +2353,10 @@ truncate:
{
LEX* lex = Lex;
lex->sql_command= SQLCOM_TRUNCATE;
Select->options=0;
Select->order_list.elements=0;
Select->order_list.first=0;
Select->order_list.next= (byte**) &Select->order_list.first;
lex->select->options=0;
lex->select->order_list.elements=0;
lex->select->order_list.first=0;
lex->select->order_list.next= (byte**) &lex->select->order_list.first;
lex->lock_option= current_thd->update_lock_default; }
opt_table_sym:
......@@ -2263,16 +2371,24 @@ show_param:
DATABASES wild
{ Lex->sql_command= SQLCOM_SHOW_DATABASES; }
| TABLES opt_db wild
{ Lex->sql_command= SQLCOM_SHOW_TABLES; Select->db= $2; Select->options=0;}
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_SHOW_TABLES;
lex->select->db= $2; lex->select->options=0;
}
| TABLE_SYM STATUS_SYM opt_db wild
{ Lex->sql_command= SQLCOM_SHOW_TABLES;
Select->options|= SELECT_DESCRIBE;
Select->db= $3;
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_SHOW_TABLES;
lex->select->options|= SELECT_DESCRIBE;
lex->select->db= $3;
}
| OPEN_SYM TABLES opt_db wild
{ Lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
Select->db= $3;
Select->options=0;
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
lex->select->db= $3;
lex->select->options=0;
}
| opt_full COLUMNS FROM table_ident opt_db wild
{
......@@ -2307,8 +2423,12 @@ show_param:
| LOGS_SYM
{ Lex->sql_command= SQLCOM_SHOW_LOGS; }
| GRANTS FOR_SYM user
{ Lex->sql_command= SQLCOM_SHOW_GRANTS;
Lex->grant_user=$3; Lex->grant_user->password.str=NullS; }
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_SHOW_GRANTS;
lex->grant_user=$3;
lex->grant_user->password.str=NullS;
}
| CREATE TABLE_SYM table_ident
{
Lex->sql_command = SQLCOM_SHOW_CREATE;
......@@ -2340,9 +2460,10 @@ opt_full:
describe:
describe_command table_ident
{
Lex->wild=0;
Lex->verbose=0;
Lex->sql_command=SQLCOM_SHOW_FIELDS;
LEX *lex=Lex;
lex->wild=0;
lex->verbose=0;
lex->sql_command=SQLCOM_SHOW_FIELDS;
if (!add_table_to_list($2, NULL,0))
YYABORT;
}
......@@ -2363,7 +2484,12 @@ opt_describe_column:
/* flush things */
flush:
FLUSH_SYM {Lex->sql_command= SQLCOM_FLUSH; Lex->type=0; } flush_options
FLUSH_SYM
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_FLUSH; lex->type=0;
}
flush_options
flush_options:
flush_options ',' flush_option
......@@ -2384,8 +2510,11 @@ opt_table_list:
| table_list {}
reset:
RESET_SYM {Lex->sql_command= SQLCOM_RESET; Lex->type=0; } reset_options
RESET_SYM
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_RESET; lex->type=0;
} reset_options
reset_options:
reset_options ',' reset_option
| reset_option
......@@ -2395,7 +2524,12 @@ reset_option:
| MASTER_SYM { Lex->type|= REFRESH_MASTER; }
purge:
PURGE { Lex->sql_command = SQLCOM_PURGE; Lex->type=0;}
PURGE
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_PURGE;
lex->type=0;
}
MASTER_SYM LOGS_SYM TO_SYM TEXT_STRING
{
Lex->to_log = $6.str;
......@@ -2406,29 +2540,34 @@ purge:
kill:
KILL_SYM expr
{
if ($2->fix_fields(current_thd,0))
{
send_error(&current_thd->net, ER_SET_CONSTANTS_ONLY);
YYABORT;
}
Lex->sql_command=SQLCOM_KILL;
Lex->thread_id= (ulong) $2->val_int();
LEX *lex=Lex;
if ($2->fix_fields(lex->thd,0))
{
send_error(&lex->thd->net, ER_SET_CONSTANTS_ONLY);
YYABORT;
}
lex->sql_command=SQLCOM_KILL;
lex->thread_id= (ulong) $2->val_int();
}
/* change database */
use: USE_SYM ident
{ Lex->sql_command=SQLCOM_CHANGE_DB; Select->db= $2.str; }
{
LEX *lex=Lex;
lex->sql_command=SQLCOM_CHANGE_DB; lex->select->db= $2.str;
}
/* import, export of files */
load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING
{
Lex->sql_command= SQLCOM_LOAD;
Lex->local_file= $4;
if (!(Lex->exchange= new sql_exchange($6.str,0)))
LEX *lex=Lex;
lex->sql_command= SQLCOM_LOAD;
lex->local_file= $4;
if (!(lex->exchange= new sql_exchange($6.str,0)))
YYABORT;
Lex->field_list.empty();
lex->field_list.empty();
}
opt_duplicate INTO TABLE_SYM table_ident opt_field_term opt_line_term
opt_ignore_lines opt_field_spec
......@@ -2476,7 +2615,11 @@ field_term_list:
field_term:
TERMINATED BY text_string { Lex->exchange->field_term= $3;}
| OPTIONALLY ENCLOSED BY text_string
{ Lex->exchange->enclosed= $4; Lex->exchange->opt_enclosed=1;}
{
LEX *lex=Lex;
lex->exchange->enclosed= $4;
lex->exchange->opt_enclosed=1;
}
| ENCLOSED BY text_string { Lex->exchange->enclosed= $3;}
| ESCAPED BY text_string { Lex->exchange->escaped= $3;}
......@@ -2546,13 +2689,25 @@ order_ident:
simple_ident:
ident
{ $$ = !Select->create_refs || Select->in_sum_expr > 0 ? (Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_ref(NullS,NullS,$1.str); }
{
SELECT_LEX *sel=Select;
$$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_ref(NullS,NullS,$1.str);
}
| ident '.' ident
{ $$ = !Select->create_refs || Select->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$1.str,$3.str) : (Item*) new Item_ref(NullS,$1.str,$3.str); }
{
SELECT_LEX *sel=Select;
$$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$1.str,$3.str) : (Item*) new Item_ref(NullS,$1.str,$3.str);
}
| '.' ident '.' ident
{ $$ = !Select->create_refs || Select->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$2.str,$4.str) : (Item*) new Item_ref(NullS,$2.str,$4.str); }
{
SELECT_LEX *sel=Select;
$$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$2.str,$4.str) : (Item*) new Item_ref(NullS,$2.str,$4.str);
}
| ident '.' ident '.' ident
{ $$ = !Select->create_refs || Select->in_sum_expr > 0 ? (Item*) new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str); }
{
SELECT_LEX *sel=Select;
$$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str);
}
field_ident:
......@@ -2569,10 +2724,11 @@ ident:
IDENT { $$=$1; }
| keyword
{
LEX *lex;
$$.str=sql_strmake($1.str,$1.length);
$$.length=$1.length;
if (Lex->next_state != STATE_END)
Lex->next_state=STATE_OPERATOR_OR_IDENT;
if ((lex=Lex)->next_state != STATE_END)
lex->next_state=STATE_OPERATOR_OR_IDENT;
}
ident_or_text:
......@@ -2724,12 +2880,12 @@ keyword:
set:
SET opt_option
{
THD *thd=current_thd;
Lex->sql_command= SQLCOM_SET_OPTION;
Select->options=thd->options;
Select->select_limit=thd->default_select_limit;
Lex->gemini_spin_retries=thd->gemini_spin_retries;
Lex->tx_isolation=thd->tx_isolation;
LEX *lex=Lex;
lex->sql_command= SQLCOM_SET_OPTION;
lex->select->options=lex->thd->options;
lex->select->select_limit=lex->thd->default_select_limit;
lex->gemini_spin_retries=lex->thd->gemini_spin_retries;
lex->tx_isolation=lex->thd->tx_isolation;
}
option_value_list
......@@ -2744,18 +2900,20 @@ option_value_list:
option_value:
set_option equal NUM
{
SELECT_LEX *sel=Select;
if (atoi($3.str) == 0)
Select->options&= ~$1;
sel->options&= ~$1;
else
Select->options|= $1;
sel->options|= $1;
}
| set_isolation
| AUTOCOMMIT equal NUM
{
SELECT_LEX *sel=Select;
if (atoi($3.str) != 0) /* Test NOT AUTOCOMMIT */
Select->options&= ~(OPTION_NOT_AUTO_COMMIT);
sel->options&= ~(OPTION_NOT_AUTO_COMMIT);
else
Select->options|= OPTION_NOT_AUTO_COMMIT;
sel->options|= OPTION_NOT_AUTO_COMMIT;
}
| SQL_SELECT_LIMIT equal ULONG_NUM
{
......@@ -2767,8 +2925,9 @@ option_value:
}
| SQL_MAX_JOIN_SIZE equal ULONG_NUM
{
current_thd->max_join_size= $3;
Select->options&= ~OPTION_BIG_SELECTS;
LEX *lex=Lex;
lex->thd->max_join_size= $3;
lex->select->options&= ~OPTION_BIG_SELECTS;
}
| SQL_MAX_JOIN_SIZE equal DEFAULT
{
......@@ -2891,7 +3050,10 @@ set_isolation:
default_tx_isolation_name=tx_isolation_typelib.type_names[default_tx_isolation];
}
| SESSION_SYM tx_isolation
{ current_thd->session_tx_isolation= Lex->tx_isolation= $2; }
{
LEX *lex=Lex;
lex->thd->session_tx_isolation= lex->tx_isolation= $2;
}
| tx_isolation
{ Lex->tx_isolation= $1; }
......@@ -2975,8 +3137,9 @@ handler_rkey_function:
| LAST_SYM { Lex->ha_read_mode = RLAST; }
| handler_rkey_mode
{
Lex->ha_read_mode = RKEY;
if (!(Lex->insert_list = new List_item))
LEX *lex=Lex;
lex->ha_read_mode = RKEY;
if (!(lex->insert_list = new List_item))
YYABORT;
} '(' values ')' { }
......@@ -2992,22 +3155,24 @@ handler_rkey_mode:
revoke:
REVOKE
{
Lex->sql_command = SQLCOM_REVOKE;
Lex->users_list.empty();
Lex->columns.empty();
Lex->grant= Lex->grant_tot_col=0;
Select->db=0;
LEX *lex=Lex;
lex->sql_command = SQLCOM_REVOKE;
lex->users_list.empty();
lex->columns.empty();
lex->grant= lex->grant_tot_col=0;
lex->select->db=0;
}
grant_privileges ON opt_table FROM user_list
grant:
GRANT
{
Lex->sql_command = SQLCOM_GRANT;
Lex->users_list.empty();
Lex->columns.empty();
Lex->grant= Lex->grant_tot_col=0;
Select->db=0;
LEX *lex=Lex;
lex->sql_command = SQLCOM_GRANT;
lex->users_list.empty();
lex->columns.empty();
lex->grant= lex->grant_tot_col=0;
lex->select->db=0;
}
grant_privileges ON opt_table TO_SYM user_list
grant_option
......@@ -3047,43 +3212,47 @@ grant_privilege:
opt_table:
'*'
{
Select->db=current_thd->db;
if (Lex->grant == UINT_MAX)
Lex->grant = DB_ACLS & ~GRANT_ACL;
else if (Lex->columns.elements)
LEX *lex=Lex;
lex->select->db=lex->thd->db;
if (lex->grant == UINT_MAX)
lex->grant = DB_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
{
net_printf(&current_thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
net_printf(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
YYABORT;
}
}
}
| ident '.' '*'
{
Select->db = $1.str;
if (Lex->grant == UINT_MAX)
Lex->grant = DB_ACLS & ~GRANT_ACL;
else if (Lex->columns.elements)
LEX *lex=Lex;
lex->select->db = $1.str;
if (lex->grant == UINT_MAX)
lex->grant = DB_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
{
net_printf(&current_thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
net_printf(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
YYABORT;
}
}
| '*' '.' '*'
{
Select->db = NULL;
if (Lex->grant == UINT_MAX)
Lex->grant = GLOBAL_ACLS & ~GRANT_ACL;
else if (Lex->columns.elements)
LEX *lex=Lex;
lex->select->db = NULL;
if (lex->grant == UINT_MAX)
lex->grant = GLOBAL_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
{
net_printf(&current_thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
net_printf(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
YYABORT;
}
}
| table_ident
{
LEX *lex=Lex;
if (!add_table_to_list($1,NULL,0))
YYABORT;
if (Lex->grant == UINT_MAX)
Lex->grant = TABLE_ACLS & ~GRANT_ACL;
if (lex->grant == UINT_MAX)
lex->grant = TABLE_ACLS & ~GRANT_ACL;
}
......@@ -3114,7 +3283,11 @@ grant_user:
opt_column_list:
/* empty */ { Lex->grant |= Lex->which_columns; }
/* empty */
{
LEX *lex=Lex;
lex->grant |= lex->which_columns;
}
| '(' column_list ')'
column_list:
......@@ -3127,16 +3300,17 @@ column_list_id:
String *new_str = new String((const char*) $1.str,$1.length);
List_iterator <LEX_COLUMN> iter(Lex->columns);
class LEX_COLUMN *point;
LEX *lex=Lex;
while ((point=iter++))
{
if (!my_strcasecmp(point->column.ptr(),new_str->ptr()))
break;
}
Lex->grant_tot_col|= Lex->which_columns;
lex->grant_tot_col|= lex->which_columns;
if (point)
point->rights |= Lex->which_columns;
point->rights |= lex->which_columns;
else
Lex->columns.push_back(new LEX_COLUMN (*new_str,Lex->which_columns));
lex->columns.push_back(new LEX_COLUMN (*new_str,lex->which_columns));
}
grant_option:
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment