sql_delete.cc 17.5 KB
Newer Older
1
/* Copyright (C) 2000 MySQL AB
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
7

bk@work.mysql.com's avatar
bk@work.mysql.com committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
12

bk@work.mysql.com's avatar
bk@work.mysql.com committed
13 14 15 16
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

17

bk@work.mysql.com's avatar
bk@work.mysql.com committed
18
/*
19
  Delete of records and truncate of tables.
20

21
  Multi-table deletes were introduced by Monty and Sinisa
bk@work.mysql.com's avatar
bk@work.mysql.com committed
22 23
*/

24 25


26
#include "mysql_priv.h"
27
#include "ha_innodb.h"
28
#include "sql_select.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
29

30
int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
31
                 ha_rows limit, ulong options)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
32 33 34
{
  int		error;
  TABLE		*table;
35
  SQL_SELECT	*select=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
36 37
  READ_RECORD	info;
  bool 		using_limit=limit != HA_POS_ERROR;
38
  bool		transactional_table, log_delayed, safe_update, const_cond; 
39
  ha_rows	deleted;
40 41
  TABLE_LIST    *delete_table_list= (TABLE_LIST*) 
    thd->lex.select_lex.table_list.first;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
42 43
  DBUG_ENTER("mysql_delete");

44
  if ((open_and_lock_tables(thd, table_list)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
45
    DBUG_RETURN(-1);
46
  fix_tables_pointers(thd->lex.all_selects_list);
47
  table= table_list->table;
48
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
49 50
  thd->proc_info="init";
  table->map=1;
51
  if (setup_conds(thd, delete_table_list, &conds) || 
52
      setup_ftfuncs(&thd->lex.select_lex))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
53
    DBUG_RETURN(-1);
54 55 56
  if (find_real_table_in_list(table_list->next, 
			      table_list->db, table_list->real_name))
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
57
    my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
58 59
    DBUG_RETURN(-1);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
60

61 62 63 64 65 66 67 68
  const_cond= (!conds || conds->const_item());
  safe_update=test(thd->options & OPTION_SAFE_UPDATES);
  if (safe_update && const_cond)
  {
    send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
    DBUG_RETURN(1);
  }

69
  /* Test if the user wants to delete all rows */
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
70
  if (!using_limit && const_cond && (!conds || conds->val_int()) &&
71
      !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)))
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
  {
    deleted= table->file->records;
    if (!(error=table->file->delete_all_rows()))
    {
      error= -1;				// ok
      goto cleanup;
    }
    if (error != HA_ERR_WRONG_COMMAND)
    {
      table->file->print_error(error,MYF(0));
      error=0;
      goto cleanup;
    }
    /* Handler didn't support fast delete; Delete rows one by one */
  }

bk@work.mysql.com's avatar
bk@work.mysql.com committed
88 89 90 91
  table->used_keys=table->quick_keys=0;		// Can't use 'only index'
  select=make_select(table,0,0,conds,&error);
  if (error)
    DBUG_RETURN(-1);
92
  if ((select && select->check_quick(safe_update, limit)) || !limit)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
93 94
  {
    delete select;
95
    free_underlaid_joins(thd, &thd->lex.select_lex);
96
    send_ok(thd,0L);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
97
    DBUG_RETURN(0);				// Nothing to delete
bk@work.mysql.com's avatar
bk@work.mysql.com committed
98 99 100
  }

  /* If running in safe sql mode, don't allow updates without keys */
101
  if (!table->quick_keys)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
102
  {
103
    thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
104
    if (safe_update && !using_limit)
105 106
    {
      delete select;
107
      free_underlaid_joins(thd, &thd->lex.select_lex);
108
      send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
109 110
      DBUG_RETURN(1);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
111
  }
112
  if (options & OPTION_QUICK)
113 114 115 116 117 118 119 120 121
    (void) table->file->extra(HA_EXTRA_QUICK);

  if (order)
  {
    uint         length;
    SORT_FIELD  *sortorder;
    TABLE_LIST   tables;
    List<Item>   fields;
    List<Item>   all_fields;
122
    ha_rows examined_rows;
123 124 125 126

    bzero((char*) &tables,sizeof(tables));
    tables.table = table;

127
    table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
128
                                             MYF(MY_FAE | MY_ZEROFILL));
129 130 131 132 133
      if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
			all_fields.elements)||
	  setup_order(thd, thd->lex.select_lex.ref_pointer_array, &tables, 
		      fields, all_fields, order) ||
	  !(sortorder=make_unireg_sortorder(order, &length)) ||
134
	  (table->sort.found_records = filesort(thd, table, sortorder, length,
135 136 137
					   (SQL_SELECT *) 0, HA_POS_ERROR,
					   &examined_rows))
	  == HA_POS_ERROR)
138 139
    {
      delete select;
140
      free_underlaid_joins(thd, &thd->lex.select_lex);
141 142 143 144 145
      DBUG_RETURN(-1);		// This will force out message
    }
  }

  init_read_record(&info,thd,table,select,1,1);
146
  deleted=0L;
147
  init_ftfuncs(thd, &thd->lex.select_lex, 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
148
  thd->proc_info="updating";
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
149 150
  while (!(error=info.read_record(&info)) && !thd->killed &&
	 !thd->net.report_error)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
151
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
152 153
    // thd->net.report_error is tested to disallow delete row on error
    if (!(select && select->skipp_record())&& !thd->net.report_error )
bk@work.mysql.com's avatar
bk@work.mysql.com committed
154 155 156 157 158 159 160 161 162 163 164 165 166
    {
      if (!(error=table->file->delete_row(table->record[0])))
      {
	deleted++;
	if (!--limit && using_limit)
	{
	  error= -1;
	  break;
	}
      }
      else
      {
	table->file->print_error(error,MYF(0));
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
167 168 169 170 171 172 173 174 175
	/*
	  In < 4.0.14 we set the error number to 0 here, but that
	  was not sensible, because then MySQL would not roll back the
	  failed DELETE, and also wrote it to the binlog. For MyISAM
	  tables a DELETE probably never should fail (?), but for
	  InnoDB it can fail in a FOREIGN KEY error or an
	  out-of-tablespace error.
	*/
 	error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
176 177 178
	break;
      }
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
179 180
    else
      table->file->unlock_row();  // Row failed selection, release lock on it
bk@work.mysql.com's avatar
bk@work.mysql.com committed
181 182 183
  }
  thd->proc_info="end";
  end_read_record(&info);
184
  free_io_cache(table);				// Will not do any harm
185
  if (options & OPTION_QUICK)
186
    (void) table->file->extra(HA_EXTRA_NORMAL);
187 188

cleanup:
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
189 190 191 192 193 194 195 196 197
  /*
    Invalidate the table in the query cache if something changed. This must
    be before binlog writing and ha_autocommit_...
  */
  if (deleted)
  {
    query_cache_invalidate3(thd, table_list, 1);
  }

198 199 200
  transactional_table= table->file->has_transactions();
  log_delayed= (transactional_table || table->tmp_table);
  if (deleted && (error <= 0 || !transactional_table))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
201
  {
202 203 204
    mysql_update_log.write(thd,thd->query, thd->query_length);
    if (mysql_bin_log.is_open())
    {
205
      Query_log_event qinfo(thd, thd->query, thd->query_length, 
206 207
			    log_delayed);
      if (mysql_bin_log.write(&qinfo) && transactional_table)
208
	error=1;
209
    }
210
    if (!log_delayed)
211
      thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
212
  }
213 214 215 216 217
  if (transactional_table)
  {
    if (ha_autocommit_or_rollback(thd,error >= 0))
      error=1;
  }
218

bk@work.mysql.com's avatar
bk@work.mysql.com committed
219 220 221 222 223 224
  if (thd->lock)
  {
    mysql_unlock_tables(thd, thd->lock);
    thd->lock=0;
  }
  delete select;
225
  free_underlaid_joins(thd, &thd->lex.select_lex);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
226
  if (error >= 0 || thd->net.report_error)
227
    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN: 0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
228 229
  else
  {
230
    send_ok(thd,deleted);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
231 232 233 234 235 236
    DBUG_PRINT("info",("%d records deleted",deleted));
  }
  DBUG_RETURN(0);
}


237
/***************************************************************************
238
  Delete multiple tables from join 
239 240
***************************************************************************/

241
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
242

243
extern "C" int refposcmp2(void* arg, const void *a,const void *b)
244
{
245
  /* arg is a pointer to file->ref_length */
246
  return memcmp(a,b, *(int*) arg);
247
}
248

249 250
multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
			   uint num_of_tables_arg)
251
  : delete_tables(dt), thd(thd_arg), deleted(0),
252
    num_of_tables(num_of_tables_arg), error(0),
253
    do_delete(0), transactional_tables(0), log_delayed(0), normal_tables(0)
254
{
255 256 257 258 259
  tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
}


int
260
multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
261 262
{
  DBUG_ENTER("multi_delete::prepare");
263
  unit= u;
264
  do_delete= 1;
265
  thd->proc_info="deleting from main table";
266 267 268
  DBUG_RETURN(0);
}

269

270
bool
271 272
multi_delete::initialize_tables(JOIN *join)
{
273
  TABLE_LIST *walk;
274 275 276 277 278 279
  Unique **tempfiles_ptr;
  DBUG_ENTER("initialize_tables");

  if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
    DBUG_RETURN(1);

280 281 282
  table_map tables_to_delete_from=0;
  for (walk= delete_tables ; walk ; walk=walk->next)
    tables_to_delete_from|= walk->table->map;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
283

284
  walk= delete_tables;
285 286 287 288
  for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
       tab < end;
       tab++)
  {
289
    if (tab->table->map & tables_to_delete_from)
290
    {
291
      /* We are going to delete from this table */
292
      TABLE *tbl=walk->table=tab->table;
293
      walk=walk->next;
294
      /* Don't use KEYREAD optimization on this table */
295
      tbl->no_keyread=1;
296
      tbl->used_keys= 0;
297 298 299 300 301 302
      if (tbl->file->has_transactions())
	log_delayed= transactional_tables= 1;
      else if (tbl->tmp_table != NO_TMP_TABLE)
	log_delayed= 1;
      else
	normal_tables= 1;
303 304
    }
  }
305
  walk= delete_tables;
306 307
  tempfiles_ptr= tempfiles;
  for (walk=walk->next ; walk ; walk=walk->next)
308 309
  {
    TABLE *table=walk->table;
310 311 312 313
    *tempfiles_ptr++= new Unique (refposcmp2,
				  (void *) &table->file->ref_length,
				  table->file->ref_length,
				  MEM_STRIP_BUF_SIZE);
314
  }
315
  init_ftfuncs(thd, thd->lex.current_select->select_lex(), 1);
316
  DBUG_RETURN(thd->is_fatal_error != 0);
317
}
318

319

320 321
multi_delete::~multi_delete()
{
322 323 324
  for (table_being_deleted=delete_tables ;
       table_being_deleted ;
       table_being_deleted=table_being_deleted->next)
325 326
  {
    TABLE *t=table_being_deleted->table;
327
    free_io_cache(t);				// Alloced by unique
328 329
    t->no_keyread=0;
  }
330

331
  for (uint counter= 0; counter < num_of_tables-1; counter++)
332
  {
333
    if (tempfiles[counter])
334 335
      delete tempfiles[counter];
  }
336 337
}

338

339 340
bool multi_delete::send_data(List<Item> &values)
{
341
  int secure_counter= -1;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
342 343
  DBUG_ENTER("multi_delete::send_data");

344 345 346
  for (table_being_deleted=delete_tables ;
       table_being_deleted ;
       table_being_deleted=table_being_deleted->next, secure_counter++)
347 348
  {
    TABLE *table=table_being_deleted->table;
349 350 351 352 353 354

    /* 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]);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
355

356
    if (secure_counter < 0)
357
    {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
358
      /* If this is the table we are scanning */
359 360 361
      table->status|= STATUS_DELETED;
      if (!(error=table->file->delete_row(table->record[0])))
	deleted++;
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
362
      else if (!table_being_deleted->next)
363
      {
364
	table->file->print_error(error,MYF(0));
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
365
	DBUG_RETURN(1);
366 367 368 369
      }
    }
    else
    {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
370
      error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
371 372 373
      if (error)
      {
	error=-1;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
374
	DBUG_RETURN(1);
375
      }
376 377
    }
  }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
378
  DBUG_RETURN(0);
379 380 381 382
}

void multi_delete::send_error(uint errcode,const char *err)
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
383 384
  DBUG_ENTER("multi_delete::send_error");

385
  /* First send error what ever it is ... */
386
  ::send_error(thd,errcode,err);
387

388 389
  /* If nothing deleted return */
  if (!deleted)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
390
    DBUG_VOID_RETURN;
391

392
  /* Something already deleted so we have to invalidate cache */
393 394
  query_cache_invalidate3(thd, delete_tables, 1);

395 396 397 398 399
  /* Below can happen when thread is killed early ... */
  if (!table_being_deleted)
    table_being_deleted=delete_tables;

  /*
400 401
    If rows from the first table only has been deleted and it is
    transactional, just do rollback.
402 403 404 405
    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() &&
406
       table_being_deleted == delete_tables) || !normal_tables)
407
    ha_rollback_stmt(thd);
408
  else if (do_delete)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
409 410 411 412
  {
    VOID(do_deletes(1));
  }
  DBUG_VOID_RETURN;
413 414
}

415

416 417 418 419 420 421 422
/*
  Do delete from other tables.
  Returns values:
	0 ok
	1 error
*/

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
423
int multi_delete::do_deletes(bool from_send_error)
424
{
425
  int local_error= 0, counter= 0;
426
  DBUG_ENTER("do_deletes");
427

428 429
  if (from_send_error)
  {
430 431 432 433
    /* Found out table number for 'table_being_deleted' */
    for (TABLE_LIST *aux=delete_tables;
	 aux != table_being_deleted;
	 aux=aux->next)
434 435 436 437
      counter++;
  }
  else
    table_being_deleted = delete_tables;
438

439
  do_delete= 0;
440 441 442
  for (table_being_deleted=table_being_deleted->next;
       table_being_deleted ;
       table_being_deleted=table_being_deleted->next, counter++)
443
  { 
444 445 446
    TABLE *table = table_being_deleted->table;
    if (tempfiles[counter]->get(table))
    {
447
      local_error=1;
448 449 450 451
      break;
    }

    READ_RECORD	info;
452 453 454 455 456 457
    init_read_record(&info,thd,table,NULL,0,1);
    /*
      Ignore any rows not found in reference tables as they may already have
      been deleted by foreign key handling
    */
    info.ignore_not_found_rows= 1;
monty@butch's avatar
merge  
monty@butch committed
458
    while (!(local_error=info.read_record(&info)) && !thd->killed)
459
    {
460
      if ((local_error=table->file->delete_row(table->record[0])))
461
      {
462
	table->file->print_error(local_error,MYF(0));
463
	break;
464
      }
465
      deleted++;
466
    }
467
    end_read_record(&info);
468 469
    if (local_error == -1)				// End of file
      local_error = 0;
470
  }
471
  DBUG_RETURN(local_error);
472 473
}

474

475
/*
476 477
  Send ok to the client

478 479 480 481
  return:  0 sucess
	   1 error
*/

482 483
bool multi_delete::send_eof()
{
484
  thd->proc_info="deleting from reference tables";
485 486

  /* Does deletes for the last n - 1 tables, returns 0 if ok */
487
  int local_error= do_deletes(0);		// returns 0 if success
488

489
  /* reset used flags */
490
  thd->proc_info="end";
491

492 493 494 495
  /*
    We must invalidate the query cache before binlog writing and
    ha_autocommit_...
  */
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
496 497
  if (deleted)
    query_cache_invalidate3(thd, delete_tables, 1);
498

499 500 501 502 503 504
  /*
    Write the SQL statement to the binlog if we deleted
    rows and we succeeded, or also in an error case when there
    was a non-transaction-safe table involved, since
    modifications in it cannot be rolled back.
  */
505
  if (deleted && (error <= 0 || normal_tables))
506 507
  {
    mysql_update_log.write(thd,thd->query,thd->query_length);
508 509
    if (mysql_bin_log.is_open())
    {
510 511 512
      Query_log_event qinfo(thd, thd->query, thd->query_length,
			    log_delayed);
      if (mysql_bin_log.write(&qinfo) && !normal_tables)
513
	local_error=1;  // Log write failed: roll back the SQL statement
514
    }
515 516
    if (!log_delayed)
      thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
517
  }
518 519 520 521 522
  /* Commit or rollback the current SQL statement */ 
  if (transactional_tables)
    if (ha_autocommit_or_rollback(thd,local_error > 0))
      local_error=1;

monty@butch's avatar
merge  
monty@butch committed
523
  if (local_error)
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
524
    ::send_error(thd);
525
  else
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
526
    ::send_ok(thd, deleted);
527 528
  return 0;
}
529 530 531


/***************************************************************************
532
  TRUNCATE TABLE
533 534 535 536 537 538 539 540 541 542 543
****************************************************************************/

/*
  Optimize delete of all rows by doing a full generate of the table
  This will work even if the .ISM and .ISD tables are destroyed

  dont_send_ok should be set if:
  - We should always wants to generate the table (even if the table type
    normally can't safely do this.
  - We don't want an ok to be sent to the end user.
  - We don't want to log the truncate command
544
  - If we want to have a name lock on the table on exit without errors.
545 546 547 548 549 550 551 552 553 554 555
*/

int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
{
  HA_CREATE_INFO create_info;
  char path[FN_REFLEN];
  TABLE **table_ptr;
  int error;
  DBUG_ENTER("mysql_truncate");

  /* If it is a temporary table, close and regenerate it */
556 557
  if (!dont_send_ok && (table_ptr=find_temporary_table(thd,table_list->db,
						       table_list->real_name)))
558 559 560 561 562 563
  {
    TABLE *table= *table_ptr;
    HA_CREATE_INFO create_info;
    table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
    bzero((char*) &create_info,sizeof(create_info));
    create_info.auto_increment_value= table->file->auto_increment_value;
564
    create_info.table_charset=table->table_charset;
565

566
    db_type table_type=table->db_type;
567 568 569 570 571
    strmov(path,table->path);
    *table_ptr= table->next;			// Unlink table from list
    close_temporary(table,0);
    *fn_ext(path)=0;				// Remove the .frm extension
    ha_create_table(path, &create_info,1);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
572
    // We don't need to call invalidate() because this table is not in cache
573 574 575
    if ((error= (int) !(open_temporary_table(thd, path, table_list->db,
					     table_list->real_name, 1))))
      (void) rm_temporary_table(table_type, path);
576
    /*
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
577 578
      If we return here we will not have logged the truncation to the bin log
      and we will not send_ok() to the client.
579 580
    */
    goto end; 
581 582 583 584 585 586 587 588 589 590 591
  }

  (void) sprintf(path,"%s/%s/%s%s",mysql_data_home,table_list->db,
		 table_list->real_name,reg_ext);
  fn_format(path,path,"","",4);

  if (!dont_send_ok)
  {
    db_type table_type;
    if ((table_type=get_table_type(path)) == DB_TYPE_UNKNOWN)
    {
592 593
      my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db,
	       table_list->real_name);
594 595 596 597 598
      DBUG_RETURN(-1);
    }
    if (!ha_supports_generate(table_type))
    {
      /* Probably InnoDB table */
599 600 601
      table_list->lock_type= TL_WRITE;
      DBUG_RETURN(mysql_delete(thd, table_list, (COND*) 0, (ORDER*) 0,
			       HA_POS_ERROR, 0));
602 603 604 605 606 607
    }
    if (lock_and_wait_for_table_name(thd, table_list))
      DBUG_RETURN(-1);
  }

  bzero((char*) &create_info,sizeof(create_info));
608
  create_info.table_charset=table_list->table->table_charset;
609

610 611
  *fn_ext(path)=0;				// Remove the .frm extension
  error= ha_create_table(path,&create_info,1) ? -1 : 0;
612
  query_cache_invalidate3(thd, table_list, 0); 
613

614
end:
615
  if (!dont_send_ok)
616
  {
617
    if (!error)
618
    {
619 620 621
      mysql_update_log.write(thd,thd->query,thd->query_length);
      if (mysql_bin_log.is_open())
      {
622 623
	Query_log_event qinfo(thd, thd->query, thd->query_length,
			      thd->tmp_table);
624 625
	mysql_bin_log.write(&qinfo);
      }
626
      send_ok(thd);		// This should return record count
627
    }
628
    VOID(pthread_mutex_lock(&LOCK_open));
629
    unlock_table_name(thd, table_list);
630
    VOID(pthread_mutex_unlock(&LOCK_open));
631
  }
632
  else if (error)
633 634
  {
    VOID(pthread_mutex_lock(&LOCK_open));
635
    unlock_table_name(thd, table_list);
636 637
    VOID(pthread_mutex_unlock(&LOCK_open));
  }
638 639
  DBUG_RETURN(error ? -1 : 0);
}