2001-07-10 14:53:08 +02:00
|
|
|
/* Copyright (C) 2000 MySQL AB
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
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.
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
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.
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
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 */
|
|
|
|
|
2001-11-22 16:55:18 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*
|
2001-09-02 12:47:00 +02:00
|
|
|
Delete of records and truncate of tables.
|
2001-11-22 16:55:18 +01:00
|
|
|
|
2001-09-02 12:47:00 +02:00
|
|
|
Multi-table deletes were introduced by Monty and Sinisa
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
|
|
|
|
2001-11-22 16:55:18 +01:00
|
|
|
|
|
|
|
|
2001-09-02 12:47:00 +02:00
|
|
|
#include "mysql_priv.h"
|
2002-01-12 14:42:54 +01:00
|
|
|
#include "ha_innodb.h"
|
2001-09-02 12:47:00 +02:00
|
|
|
#include "sql_select.h"
|
2004-09-07 14:29:46 +02:00
|
|
|
#include "sp_head.h"
|
|
|
|
#include "sql_trigger.h"
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-12-19 19:16:26 +01:00
|
|
|
int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
|
2002-11-16 19:19:10 +01:00
|
|
|
ha_rows limit, ulong options)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
TABLE *table;
|
2001-09-02 12:47:00 +02:00
|
|
|
SQL_SELECT *select=0;
|
2000-07-31 21:29:14 +02:00
|
|
|
READ_RECORD info;
|
|
|
|
bool using_limit=limit != HA_POS_ERROR;
|
2002-11-21 21:25:53 +01:00
|
|
|
bool transactional_table, log_delayed, safe_update, const_cond;
|
2001-09-02 12:47:00 +02:00
|
|
|
ha_rows deleted;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("mysql_delete");
|
|
|
|
|
2004-08-31 09:06:38 +02:00
|
|
|
if ((error= open_and_lock_tables(thd, table_list)))
|
|
|
|
DBUG_RETURN(error);
|
2002-11-25 20:27:14 +01:00
|
|
|
table= table_list->table;
|
2001-03-02 14:05:12 +01:00
|
|
|
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
2000-07-31 21:29:14 +02:00
|
|
|
thd->proc_info="init";
|
|
|
|
table->map=1;
|
2004-04-10 00:14:32 +02:00
|
|
|
|
|
|
|
if ((error= mysql_prepare_delete(thd, table_list, &conds)))
|
|
|
|
DBUG_RETURN(error);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2002-11-20 20:44:32 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2003-11-19 16:59:35 +01:00
|
|
|
if (thd->lex->duplicates == DUP_IGNORE)
|
|
|
|
thd->lex->select_lex.no_error= 1;
|
2003-11-17 21:45:07 +01:00
|
|
|
|
2001-09-02 12:47:00 +02:00
|
|
|
/* Test if the user wants to delete all rows */
|
2003-05-19 15:35:49 +02:00
|
|
|
if (!using_limit && const_cond && (!conds || conds->val_int()) &&
|
2002-11-20 20:44:32 +01:00
|
|
|
!(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)))
|
2001-09-02 12:47:00 +02:00
|
|
|
{
|
|
|
|
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 */
|
|
|
|
}
|
|
|
|
|
2003-10-11 13:06:55 +02:00
|
|
|
table->used_keys.clear_all();
|
|
|
|
table->quick_keys.clear_all(); // Can't use 'only index'
|
2000-07-31 21:29:14 +02:00
|
|
|
select=make_select(table,0,0,conds,&error);
|
|
|
|
if (error)
|
|
|
|
DBUG_RETURN(-1);
|
2003-10-13 14:50:30 +02:00
|
|
|
if ((select && select->check_quick(thd, safe_update, limit)) || !limit)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
delete select;
|
2003-05-05 20:54:37 +02:00
|
|
|
free_underlaid_joins(thd, &thd->lex->select_lex);
|
2004-05-04 13:45:20 +02:00
|
|
|
thd->row_count_func= 0;
|
2002-10-02 12:33:08 +02:00
|
|
|
send_ok(thd,0L);
|
2001-07-16 02:04:30 +02:00
|
|
|
DBUG_RETURN(0); // Nothing to delete
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If running in safe sql mode, don't allow updates without keys */
|
2003-10-11 13:06:55 +02:00
|
|
|
if (table->quick_keys.is_clear_all())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2003-12-06 23:21:09 +01:00
|
|
|
thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
|
2002-11-15 15:37:44 +01:00
|
|
|
if (safe_update && !using_limit)
|
2000-11-20 01:57:02 +01:00
|
|
|
{
|
|
|
|
delete select;
|
2003-05-05 20:54:37 +02:00
|
|
|
free_underlaid_joins(thd, &thd->lex->select_lex);
|
2002-10-02 12:33:08 +02:00
|
|
|
send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
|
2000-11-20 01:57:02 +01:00
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2000-09-20 03:54:10 +02:00
|
|
|
if (options & OPTION_QUICK)
|
2001-04-11 13:04:03 +02:00
|
|
|
(void) table->file->extra(HA_EXTRA_QUICK);
|
|
|
|
|
2003-12-19 19:16:26 +01:00
|
|
|
if (order && order->elements)
|
2001-04-11 13:04:03 +02:00
|
|
|
{
|
|
|
|
uint length;
|
|
|
|
SORT_FIELD *sortorder;
|
|
|
|
TABLE_LIST tables;
|
|
|
|
List<Item> fields;
|
|
|
|
List<Item> all_fields;
|
2001-05-11 01:08:29 +02:00
|
|
|
ha_rows examined_rows;
|
2001-04-11 13:04:03 +02:00
|
|
|
|
|
|
|
bzero((char*) &tables,sizeof(tables));
|
|
|
|
tables.table = table;
|
|
|
|
|
2003-04-26 14:58:39 +02:00
|
|
|
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
|
2001-04-11 13:04:03 +02:00
|
|
|
MYF(MY_FAE | MY_ZEROFILL));
|
2003-12-19 19:18:18 +01:00
|
|
|
if (thd->lex->select_lex.setup_ref_array(thd, order->elements) ||
|
2003-12-20 02:41:04 +01:00
|
|
|
setup_order(thd, thd->lex->select_lex.ref_pointer_array, &tables,
|
2003-12-19 19:16:26 +01:00
|
|
|
fields, all_fields, (ORDER*) order->first) ||
|
|
|
|
!(sortorder=make_unireg_sortorder((ORDER*) order->first, &length)) ||
|
2003-04-26 14:58:39 +02:00
|
|
|
(table->sort.found_records = filesort(thd, table, sortorder, length,
|
2003-12-17 16:35:34 +01:00
|
|
|
select, HA_POS_ERROR,
|
2003-04-09 17:22:17 +02:00
|
|
|
&examined_rows))
|
|
|
|
== HA_POS_ERROR)
|
2001-04-11 13:04:03 +02:00
|
|
|
{
|
|
|
|
delete select;
|
2003-05-05 20:54:37 +02:00
|
|
|
free_underlaid_joins(thd, &thd->lex->select_lex);
|
2003-12-11 05:24:08 +01:00
|
|
|
DBUG_RETURN(-1); // This will force out message
|
2001-04-11 13:04:03 +02:00
|
|
|
}
|
2003-12-11 05:24:08 +01:00
|
|
|
/*
|
|
|
|
Filesort has already found and selected the rows we want to delete,
|
|
|
|
so we don't need the where clause
|
|
|
|
*/
|
|
|
|
delete select;
|
|
|
|
select= 0;
|
2001-04-11 13:04:03 +02:00
|
|
|
}
|
|
|
|
|
2004-03-15 21:11:58 +01:00
|
|
|
/* If quick select is used, initialize it before retrieving rows. */
|
|
|
|
if (select && select->quick && select->quick->reset())
|
|
|
|
{
|
|
|
|
delete select;
|
|
|
|
free_underlaid_joins(thd, &thd->lex->select_lex);
|
|
|
|
DBUG_RETURN(-1); // This will force out message
|
|
|
|
}
|
2001-04-11 13:04:03 +02:00
|
|
|
init_read_record(&info,thd,table,select,1,1);
|
2001-09-02 12:47:00 +02:00
|
|
|
deleted=0L;
|
2003-05-05 20:54:37 +02:00
|
|
|
init_ftfuncs(thd, &thd->lex->select_lex, 1);
|
2000-07-31 21:29:14 +02:00
|
|
|
thd->proc_info="updating";
|
2002-11-30 23:11:22 +01:00
|
|
|
while (!(error=info.read_record(&info)) && !thd->killed &&
|
|
|
|
!thd->net.report_error)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-11-30 23:11:22 +01:00
|
|
|
// thd->net.report_error is tested to disallow delete row on error
|
2004-02-02 17:25:39 +01:00
|
|
|
if (!(select && select->skip_record())&& !thd->net.report_error )
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-09-07 14:29:46 +02:00
|
|
|
|
|
|
|
if (table->triggers)
|
|
|
|
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
|
|
|
|
TRG_ACTION_BEFORE);
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
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));
|
2003-07-08 23:55:07 +02:00
|
|
|
/*
|
|
|
|
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;
|
2000-07-31 21:29:14 +02:00
|
|
|
break;
|
|
|
|
}
|
2004-09-07 14:29:46 +02:00
|
|
|
|
|
|
|
if (table->triggers)
|
|
|
|
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
|
|
|
|
TRG_ACTION_AFTER);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2001-08-21 19:06:00 +02:00
|
|
|
else
|
|
|
|
table->file->unlock_row(); // Row failed selection, release lock on it
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-03-04 17:16:10 +01:00
|
|
|
if (thd->killed && !error)
|
|
|
|
error= 1; // Aborted
|
2000-07-31 21:29:14 +02:00
|
|
|
thd->proc_info="end";
|
|
|
|
end_read_record(&info);
|
2002-01-16 22:02:26 +01:00
|
|
|
free_io_cache(table); // Will not do any harm
|
2000-09-20 03:54:10 +02:00
|
|
|
if (options & OPTION_QUICK)
|
2001-04-11 13:04:03 +02:00
|
|
|
(void) table->file->extra(HA_EXTRA_NORMAL);
|
2001-09-02 12:47:00 +02:00
|
|
|
|
|
|
|
cleanup:
|
2003-05-26 18:10:43 +02:00
|
|
|
/*
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2004-06-23 12:29:05 +02:00
|
|
|
delete select;
|
2002-11-07 03:02:37 +01:00
|
|
|
transactional_table= table->file->has_transactions();
|
|
|
|
log_delayed= (transactional_table || table->tmp_table);
|
2004-06-09 16:07:01 +02:00
|
|
|
/*
|
|
|
|
We write to the binary log even if we deleted no row, because maybe the
|
|
|
|
user is using this command to ensure that a table is clean on master *and
|
|
|
|
on slave*. Think of the case of a user having played separately with the
|
|
|
|
master's table and slave's table and wanting to take a fresh identical
|
|
|
|
start now.
|
|
|
|
error < 0 means "really no error". error <= 0 means "maybe some error".
|
|
|
|
*/
|
|
|
|
if ((deleted || (error < 0)) && (error <= 0 || !transactional_table))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2000-09-16 03:27:21 +02:00
|
|
|
if (mysql_bin_log.is_open())
|
|
|
|
{
|
2003-12-16 11:10:50 +01:00
|
|
|
if (error <= 0)
|
|
|
|
thd->clear_error();
|
2004-06-23 12:29:05 +02:00
|
|
|
Query_log_event qinfo(thd, thd->query, thd->query_length,
|
2002-11-07 03:02:37 +01:00
|
|
|
log_delayed);
|
|
|
|
if (mysql_bin_log.write(&qinfo) && transactional_table)
|
2000-12-07 13:08:48 +01:00
|
|
|
error=1;
|
2000-09-16 03:27:21 +02:00
|
|
|
}
|
2002-11-07 03:02:37 +01:00
|
|
|
if (!log_delayed)
|
2000-11-24 00:51:18 +01:00
|
|
|
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-11-16 19:19:10 +01:00
|
|
|
if (transactional_table)
|
|
|
|
{
|
|
|
|
if (ha_autocommit_or_rollback(thd,error >= 0))
|
|
|
|
error=1;
|
|
|
|
}
|
2002-11-21 23:33:15 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
if (thd->lock)
|
|
|
|
{
|
|
|
|
mysql_unlock_tables(thd, thd->lock);
|
|
|
|
thd->lock=0;
|
|
|
|
}
|
2003-05-05 20:54:37 +02:00
|
|
|
free_underlaid_joins(thd, &thd->lex->select_lex);
|
2002-11-30 23:11:22 +01:00
|
|
|
if (error >= 0 || thd->net.report_error)
|
2003-04-08 16:18:33 +02:00
|
|
|
send_error(thd,thd->killed_errno());
|
2000-07-31 21:29:14 +02:00
|
|
|
else
|
|
|
|
{
|
2004-05-04 13:45:20 +02:00
|
|
|
thd->row_count_func= deleted;
|
2002-10-02 12:33:08 +02:00
|
|
|
send_ok(thd,deleted);
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_PRINT("info",("%d records deleted",deleted));
|
|
|
|
}
|
2004-04-10 00:14:32 +02:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Prepare items in DELETE statement
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_prepare_delete()
|
|
|
|
thd - thread handler
|
2004-07-16 00:15:55 +02:00
|
|
|
table_list - global/local table list
|
2004-04-10 00:14:32 +02:00
|
|
|
conds - conditions
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
0 - OK
|
|
|
|
1 - error (message is sent to user)
|
|
|
|
-1 - error (message is not sent to user)
|
|
|
|
*/
|
|
|
|
int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
|
|
|
|
{
|
2004-05-20 01:02:49 +02:00
|
|
|
SELECT_LEX *select_lex= &thd->lex->select_lex;
|
2004-04-12 02:26:32 +02:00
|
|
|
DBUG_ENTER("mysql_prepare_delete");
|
2004-04-10 00:14:32 +02:00
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
if (setup_tables(thd, table_list, conds) ||
|
|
|
|
setup_conds(thd, table_list, conds) ||
|
2004-05-20 01:02:49 +02:00
|
|
|
setup_ftfuncs(select_lex))
|
2004-04-10 00:14:32 +02:00
|
|
|
DBUG_RETURN(-1);
|
2004-07-16 00:15:55 +02:00
|
|
|
if (!table_list->updatable || check_key_in_view(thd, table_list))
|
2004-04-10 00:14:32 +02:00
|
|
|
{
|
2004-07-16 00:15:55 +02:00
|
|
|
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
|
2004-04-10 00:14:32 +02:00
|
|
|
DBUG_RETURN(-1);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-10-25 16:32:28 +02:00
|
|
|
if (unique_table(table_list, table_list->next_global))
|
2004-05-20 01:02:49 +02:00
|
|
|
{
|
2004-07-16 00:15:55 +02:00
|
|
|
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
|
|
|
DBUG_RETURN(-1);
|
2004-05-20 01:02:49 +02:00
|
|
|
}
|
2004-07-16 00:15:55 +02:00
|
|
|
select_lex->fix_prepare_information(thd, conds);
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-06-03 16:07:26 +02:00
|
|
|
/***************************************************************************
|
2002-06-11 10:20:31 +02:00
|
|
|
Delete multiple tables from join
|
2001-06-03 16:07:26 +02:00
|
|
|
***************************************************************************/
|
|
|
|
|
2002-06-28 18:30:09 +02:00
|
|
|
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
|
2001-06-15 04:03:15 +02:00
|
|
|
|
2004-05-12 23:38:40 +02:00
|
|
|
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
|
2001-06-07 13:10:58 +02:00
|
|
|
{
|
2004-05-12 23:38:40 +02:00
|
|
|
handler *file= (handler*)arg;
|
|
|
|
return file->cmp_ref((const byte*)a, (const byte*)b);
|
2001-06-07 13:10:58 +02:00
|
|
|
}
|
2001-06-03 16:07:26 +02:00
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
/*
|
|
|
|
make delete specific preparation and checks after opening tables
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_multi_delete_prepare()
|
|
|
|
thd thread handler
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 OK
|
|
|
|
-1 Error
|
|
|
|
*/
|
|
|
|
|
|
|
|
int mysql_multi_delete_prepare(THD *thd)
|
|
|
|
{
|
|
|
|
LEX *lex= thd->lex;
|
|
|
|
TABLE_LIST *aux_tables= (TABLE_LIST *)lex->auxilliary_table_list.first;
|
|
|
|
TABLE_LIST *target_tbl;
|
|
|
|
int res= 0;
|
|
|
|
DBUG_ENTER("mysql_multi_delete_prepare");
|
|
|
|
|
|
|
|
/*
|
|
|
|
setup_tables() need for VIEWs. JOIN::prepare() will not do it second
|
|
|
|
time.
|
|
|
|
|
|
|
|
lex->query_tables also point on local list of DELETE SELECT_LEX
|
|
|
|
*/
|
|
|
|
if (setup_tables(thd, lex->query_tables, &lex->select_lex.where))
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
|
|
|
|
/* Fix tables-to-be-deleted-from list to point at opened tables */
|
|
|
|
for (target_tbl= (TABLE_LIST*) aux_tables;
|
|
|
|
target_tbl;
|
|
|
|
target_tbl= target_tbl->next_local)
|
|
|
|
{
|
|
|
|
target_tbl->table= target_tbl->correspondent_table->table;
|
|
|
|
if (!target_tbl->correspondent_table->updatable ||
|
|
|
|
check_key_in_view(thd, target_tbl->correspondent_table))
|
|
|
|
{
|
|
|
|
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), target_tbl->real_name,
|
|
|
|
"DELETE");
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
Check are deleted table used somewhere inside subqueries.
|
|
|
|
|
|
|
|
Multi-delete can't be constructed over-union => we always have
|
|
|
|
single SELECT on top and have to check underlaying SELECTs of it
|
|
|
|
*/
|
|
|
|
for (SELECT_LEX_UNIT *un= lex->select_lex.first_inner_unit();
|
|
|
|
un;
|
|
|
|
un= un->next_unit())
|
|
|
|
{
|
|
|
|
if (un->first_select()->linkage != DERIVED_TABLE_TYPE &&
|
|
|
|
un->check_updateable(target_tbl->correspondent_table->db,
|
|
|
|
target_tbl->correspondent_table->real_name))
|
|
|
|
{
|
|
|
|
my_error(ER_UPDATE_TABLE_USED, MYF(0),
|
|
|
|
target_tbl->correspondent_table->real_name);
|
|
|
|
res= -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DBUG_RETURN(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-06-15 04:03:15 +02:00
|
|
|
multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
|
|
|
|
uint num_of_tables_arg)
|
2003-12-12 22:14:59 +01:00
|
|
|
: delete_tables(dt), thd(thd_arg), deleted(0), found(0),
|
2002-11-16 19:19:10 +01:00
|
|
|
num_of_tables(num_of_tables_arg), error(0),
|
2002-11-07 03:02:37 +01:00
|
|
|
do_delete(0), transactional_tables(0), log_delayed(0), normal_tables(0)
|
2001-06-03 16:07:26 +02:00
|
|
|
{
|
2001-06-15 04:03:15 +02:00
|
|
|
tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-05-08 22:14:40 +02:00
|
|
|
multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
2001-06-15 04:03:15 +02:00
|
|
|
{
|
|
|
|
DBUG_ENTER("multi_delete::prepare");
|
2002-05-08 22:14:40 +02:00
|
|
|
unit= u;
|
2002-11-29 15:40:18 +01:00
|
|
|
do_delete= 1;
|
2001-06-15 04:03:15 +02:00
|
|
|
thd->proc_info="deleting from main table";
|
2001-06-03 16:07:26 +02:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
2001-07-01 12:20:53 +02:00
|
|
|
|
2002-11-29 15:40:18 +01:00
|
|
|
bool
|
2001-07-01 12:20:53 +02:00
|
|
|
multi_delete::initialize_tables(JOIN *join)
|
|
|
|
{
|
2001-07-10 14:53:08 +02:00
|
|
|
TABLE_LIST *walk;
|
2002-11-29 15:40:18 +01:00
|
|
|
Unique **tempfiles_ptr;
|
|
|
|
DBUG_ENTER("initialize_tables");
|
|
|
|
|
|
|
|
if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
2001-07-10 14:53:08 +02:00
|
|
|
table_map tables_to_delete_from=0;
|
2004-07-16 00:15:55 +02:00
|
|
|
for (walk= delete_tables; walk; walk= walk->next_local)
|
2001-07-10 14:53:08 +02:00
|
|
|
tables_to_delete_from|= walk->table->map;
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2001-07-10 14:53:08 +02:00
|
|
|
walk= delete_tables;
|
2001-07-01 12:20:53 +02:00
|
|
|
for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
|
|
|
|
tab < end;
|
|
|
|
tab++)
|
|
|
|
{
|
2001-07-10 14:53:08 +02:00
|
|
|
if (tab->table->map & tables_to_delete_from)
|
2001-07-01 12:20:53 +02:00
|
|
|
{
|
2001-07-10 14:53:08 +02:00
|
|
|
/* We are going to delete from this table */
|
2002-06-11 21:45:51 +02:00
|
|
|
TABLE *tbl=walk->table=tab->table;
|
2004-07-16 00:15:55 +02:00
|
|
|
walk= walk->next_local;
|
2002-06-12 22:54:52 +02:00
|
|
|
/* Don't use KEYREAD optimization on this table */
|
2002-06-11 21:45:51 +02:00
|
|
|
tbl->no_keyread=1;
|
2004-09-19 13:15:01 +02:00
|
|
|
/* Don't use record cache */
|
|
|
|
tbl->no_cache= 1;
|
2003-10-11 13:06:55 +02:00
|
|
|
tbl->used_keys.clear_all();
|
2002-11-07 03:02:37 +01:00
|
|
|
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;
|
2001-07-01 12:20:53 +02:00
|
|
|
}
|
|
|
|
}
|
2002-07-31 18:53:06 +02:00
|
|
|
walk= delete_tables;
|
2002-11-29 15:40:18 +01:00
|
|
|
tempfiles_ptr= tempfiles;
|
2004-07-16 00:15:55 +02:00
|
|
|
for (walk= walk->next_local ;walk ;walk= walk->next_local)
|
2002-07-31 18:53:06 +02:00
|
|
|
{
|
|
|
|
TABLE *table=walk->table;
|
2004-05-12 23:38:40 +02:00
|
|
|
*tempfiles_ptr++= new Unique (refpos_order_cmp,
|
|
|
|
(void *) table->file,
|
2002-11-29 15:40:18 +01:00
|
|
|
table->file->ref_length,
|
|
|
|
MEM_STRIP_BUF_SIZE);
|
2002-07-31 18:53:06 +02:00
|
|
|
}
|
2003-08-26 11:51:09 +02:00
|
|
|
init_ftfuncs(thd, thd->lex->current_select, 1);
|
2003-01-30 21:15:44 +01:00
|
|
|
DBUG_RETURN(thd->is_fatal_error != 0);
|
2001-07-01 12:20:53 +02:00
|
|
|
}
|
2001-06-15 04:03:15 +02:00
|
|
|
|
2001-07-10 14:53:08 +02:00
|
|
|
|
2001-06-03 16:07:26 +02:00
|
|
|
multi_delete::~multi_delete()
|
|
|
|
{
|
2004-07-16 00:15:55 +02:00
|
|
|
for (table_being_deleted= delete_tables;
|
|
|
|
table_being_deleted;
|
|
|
|
table_being_deleted= table_being_deleted->next_local)
|
2002-01-12 18:51:10 +01:00
|
|
|
{
|
|
|
|
TABLE *t=table_being_deleted->table;
|
2002-01-16 22:02:26 +01:00
|
|
|
free_io_cache(t); // Alloced by unique
|
2002-01-12 18:51:10 +01:00
|
|
|
t->no_keyread=0;
|
|
|
|
}
|
2001-07-10 14:53:08 +02:00
|
|
|
|
2002-11-29 15:40:18 +01:00
|
|
|
for (uint counter= 0; counter < num_of_tables-1; counter++)
|
2001-06-15 04:03:15 +02:00
|
|
|
{
|
2001-06-03 16:07:26 +02:00
|
|
|
if (tempfiles[counter])
|
2001-06-15 04:03:15 +02:00
|
|
|
delete tempfiles[counter];
|
|
|
|
}
|
2001-06-03 16:07:26 +02:00
|
|
|
}
|
|
|
|
|
2001-06-15 04:03:15 +02:00
|
|
|
|
2001-06-03 16:07:26 +02:00
|
|
|
bool multi_delete::send_data(List<Item> &values)
|
|
|
|
{
|
2001-06-15 04:03:15 +02:00
|
|
|
int secure_counter= -1;
|
2002-01-29 17:32:16 +01:00
|
|
|
DBUG_ENTER("multi_delete::send_data");
|
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
for (table_being_deleted= delete_tables;
|
|
|
|
table_being_deleted;
|
|
|
|
table_being_deleted= table_being_deleted->next_local, secure_counter++)
|
2001-06-03 16:07:26 +02:00
|
|
|
{
|
|
|
|
TABLE *table=table_being_deleted->table;
|
2001-06-15 04:03:15 +02:00
|
|
|
|
|
|
|
/* 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]);
|
2003-12-12 22:14:59 +01:00
|
|
|
found++;
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2001-06-15 04:03:15 +02:00
|
|
|
if (secure_counter < 0)
|
2001-06-03 16:07:26 +02:00
|
|
|
{
|
2002-01-29 17:32:16 +01:00
|
|
|
/* If this is the table we are scanning */
|
2001-06-15 04:03:15 +02:00
|
|
|
table->status|= STATUS_DELETED;
|
|
|
|
if (!(error=table->file->delete_row(table->record[0])))
|
|
|
|
deleted++;
|
2004-07-16 00:15:55 +02:00
|
|
|
else if (!table_being_deleted->next_local ||
|
|
|
|
table_being_deleted->table->file->has_transactions())
|
2001-06-03 16:07:26 +02:00
|
|
|
{
|
2001-06-15 04:03:15 +02:00
|
|
|
table->file->print_error(error,MYF(0));
|
2002-01-29 17:32:16 +01:00
|
|
|
DBUG_RETURN(1);
|
2001-06-15 04:03:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-09-15 15:22:34 +02:00
|
|
|
error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
|
2001-06-15 04:03:15 +02:00
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
error=-1;
|
2002-01-29 17:32:16 +01:00
|
|
|
DBUG_RETURN(1);
|
2001-06-15 04:03:15 +02:00
|
|
|
}
|
2001-06-03 16:07:26 +02:00
|
|
|
}
|
|
|
|
}
|
2002-01-29 17:32:16 +01:00
|
|
|
DBUG_RETURN(0);
|
2001-06-03 16:07:26 +02:00
|
|
|
}
|
|
|
|
|
2004-03-04 17:16:10 +01:00
|
|
|
|
2001-06-03 16:07:26 +02:00
|
|
|
void multi_delete::send_error(uint errcode,const char *err)
|
|
|
|
{
|
2002-01-29 17:32:16 +01:00
|
|
|
DBUG_ENTER("multi_delete::send_error");
|
|
|
|
|
2001-06-15 04:03:15 +02:00
|
|
|
/* First send error what ever it is ... */
|
2002-10-02 12:33:08 +02:00
|
|
|
::send_error(thd,errcode,err);
|
2001-10-04 20:52:41 +02:00
|
|
|
|
2001-06-15 04:03:15 +02:00
|
|
|
/* If nothing deleted return */
|
|
|
|
if (!deleted)
|
2002-01-29 17:32:16 +01:00
|
|
|
DBUG_VOID_RETURN;
|
2002-01-16 22:02:26 +01:00
|
|
|
|
2002-06-11 10:20:31 +02:00
|
|
|
/* Something already deleted so we have to invalidate cache */
|
2002-04-28 23:33:52 +02:00
|
|
|
query_cache_invalidate3(thd, delete_tables, 1);
|
|
|
|
|
2001-06-15 04:03:15 +02:00
|
|
|
/* Below can happen when thread is killed early ... */
|
|
|
|
if (!table_being_deleted)
|
|
|
|
table_being_deleted=delete_tables;
|
|
|
|
|
|
|
|
/*
|
2002-01-16 22:02:26 +01:00
|
|
|
If rows from the first table only has been deleted and it is
|
|
|
|
transactional, just do rollback.
|
2001-06-15 04:03:15 +02:00
|
|
|
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() &&
|
2002-11-07 03:02:37 +01:00
|
|
|
table_being_deleted == delete_tables) || !normal_tables)
|
2001-10-19 16:43:30 +02:00
|
|
|
ha_rollback_stmt(thd);
|
2001-06-03 16:07:26 +02:00
|
|
|
else if (do_delete)
|
2002-01-29 17:32:16 +01:00
|
|
|
{
|
|
|
|
VOID(do_deletes(1));
|
|
|
|
}
|
|
|
|
DBUG_VOID_RETURN;
|
2001-06-03 16:07:26 +02:00
|
|
|
}
|
|
|
|
|
2001-06-15 04:03:15 +02:00
|
|
|
|
2001-12-13 01:31:19 +01:00
|
|
|
/*
|
|
|
|
Do delete from other tables.
|
|
|
|
Returns values:
|
|
|
|
0 ok
|
|
|
|
1 error
|
|
|
|
*/
|
|
|
|
|
2002-01-29 17:32:16 +01:00
|
|
|
int multi_delete::do_deletes(bool from_send_error)
|
2001-06-03 16:07:26 +02:00
|
|
|
{
|
2002-11-07 02:54:00 +01:00
|
|
|
int local_error= 0, counter= 0;
|
2003-02-17 01:14:37 +01:00
|
|
|
DBUG_ENTER("do_deletes");
|
2001-06-15 04:03:15 +02:00
|
|
|
|
2001-06-03 16:07:26 +02:00
|
|
|
if (from_send_error)
|
|
|
|
{
|
2003-12-12 22:14:59 +01:00
|
|
|
/* Found out table number for 'table_being_deleted*/
|
2004-07-16 00:15:55 +02:00
|
|
|
for (TABLE_LIST *aux= delete_tables;
|
2001-06-15 04:03:15 +02:00
|
|
|
aux != table_being_deleted;
|
2004-07-16 00:15:55 +02:00
|
|
|
aux= aux->next_local)
|
2001-06-03 16:07:26 +02:00
|
|
|
counter++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
table_being_deleted = delete_tables;
|
2001-06-15 04:03:15 +02:00
|
|
|
|
2002-11-29 15:40:18 +01:00
|
|
|
do_delete= 0;
|
2003-12-12 22:14:59 +01:00
|
|
|
if (!found)
|
2003-12-11 23:55:48 +01:00
|
|
|
DBUG_RETURN(0);
|
2004-07-16 00:15:55 +02:00
|
|
|
for (table_being_deleted= table_being_deleted->next_local;
|
|
|
|
table_being_deleted;
|
|
|
|
table_being_deleted= table_being_deleted->next_local, counter++)
|
2001-06-03 16:07:26 +02:00
|
|
|
{
|
2001-06-15 04:03:15 +02:00
|
|
|
TABLE *table = table_being_deleted->table;
|
|
|
|
if (tempfiles[counter]->get(table))
|
|
|
|
{
|
2002-11-07 02:54:00 +01:00
|
|
|
local_error=1;
|
2001-06-15 04:03:15 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
READ_RECORD info;
|
2003-02-17 01:14:37 +01:00
|
|
|
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;
|
2002-11-07 11:49:01 +01:00
|
|
|
while (!(local_error=info.read_record(&info)) && !thd->killed)
|
2001-06-15 04:03:15 +02:00
|
|
|
{
|
2002-11-07 02:54:00 +01:00
|
|
|
if ((local_error=table->file->delete_row(table->record[0])))
|
2001-06-03 16:07:26 +02:00
|
|
|
{
|
2002-11-07 02:54:00 +01:00
|
|
|
table->file->print_error(local_error,MYF(0));
|
2001-06-15 04:03:15 +02:00
|
|
|
break;
|
2001-06-03 16:07:26 +02:00
|
|
|
}
|
2001-12-13 01:31:19 +01:00
|
|
|
deleted++;
|
2001-06-03 16:07:26 +02:00
|
|
|
}
|
2001-06-15 04:03:15 +02:00
|
|
|
end_read_record(&info);
|
2004-03-04 17:16:10 +01:00
|
|
|
if (thd->killed && !local_error)
|
|
|
|
local_error= 1;
|
2002-11-07 02:54:00 +01:00
|
|
|
if (local_error == -1) // End of file
|
|
|
|
local_error = 0;
|
2001-06-03 16:07:26 +02:00
|
|
|
}
|
2003-02-17 01:14:37 +01:00
|
|
|
DBUG_RETURN(local_error);
|
2001-06-03 16:07:26 +02:00
|
|
|
}
|
|
|
|
|
2001-06-15 04:03:15 +02:00
|
|
|
|
2002-01-16 22:02:26 +01:00
|
|
|
/*
|
2002-06-11 10:20:31 +02:00
|
|
|
Send ok to the client
|
|
|
|
|
2002-01-16 22:02:26 +01:00
|
|
|
return: 0 sucess
|
|
|
|
1 error
|
|
|
|
*/
|
|
|
|
|
2001-06-03 16:07:26 +02:00
|
|
|
bool multi_delete::send_eof()
|
|
|
|
{
|
2002-01-16 22:02:26 +01:00
|
|
|
thd->proc_info="deleting from reference tables";
|
2001-10-25 13:41:49 +02:00
|
|
|
|
|
|
|
/* Does deletes for the last n - 1 tables, returns 0 if ok */
|
2002-11-07 02:54:00 +01:00
|
|
|
int local_error= do_deletes(0); // returns 0 if success
|
2001-06-15 04:03:15 +02:00
|
|
|
|
2001-10-04 20:52:41 +02:00
|
|
|
/* reset used flags */
|
2001-06-03 16:07:26 +02:00
|
|
|
thd->proc_info="end";
|
2001-06-15 04:03:15 +02:00
|
|
|
|
2003-05-26 19:48:40 +02:00
|
|
|
/*
|
|
|
|
We must invalidate the query cache before binlog writing and
|
|
|
|
ha_autocommit_...
|
|
|
|
*/
|
2003-05-26 18:10:43 +02:00
|
|
|
if (deleted)
|
2003-12-21 01:07:45 +01:00
|
|
|
{
|
2003-05-26 18:10:43 +02:00
|
|
|
query_cache_invalidate3(thd, delete_tables, 1);
|
2003-12-21 01:07:45 +01:00
|
|
|
}
|
2001-06-15 04:03:15 +02:00
|
|
|
|
2002-01-16 22:02:26 +01:00
|
|
|
/*
|
|
|
|
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.
|
2004-06-09 16:07:01 +02:00
|
|
|
Note that if we deleted nothing we don't write to the binlog (TODO:
|
|
|
|
fix this).
|
2002-01-16 22:02:26 +01:00
|
|
|
*/
|
2002-11-29 15:40:18 +01:00
|
|
|
if (deleted && (error <= 0 || normal_tables))
|
2001-06-03 16:07:26 +02:00
|
|
|
{
|
2001-12-13 01:31:19 +01:00
|
|
|
if (mysql_bin_log.is_open())
|
|
|
|
{
|
2003-12-16 11:10:50 +01:00
|
|
|
if (error <= 0)
|
|
|
|
thd->clear_error();
|
2002-11-07 03:02:37 +01:00
|
|
|
Query_log_event qinfo(thd, thd->query, thd->query_length,
|
|
|
|
log_delayed);
|
|
|
|
if (mysql_bin_log.write(&qinfo) && !normal_tables)
|
2002-11-07 02:54:00 +01:00
|
|
|
local_error=1; // Log write failed: roll back the SQL statement
|
2001-12-13 01:31:19 +01:00
|
|
|
}
|
2002-11-29 15:40:18 +01:00
|
|
|
if (!log_delayed)
|
|
|
|
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
|
2002-04-29 11:24:14 +02:00
|
|
|
}
|
2002-11-29 15:40:18 +01:00
|
|
|
/* Commit or rollback the current SQL statement */
|
|
|
|
if (transactional_tables)
|
|
|
|
if (ha_autocommit_or_rollback(thd,local_error > 0))
|
|
|
|
local_error=1;
|
|
|
|
|
2002-11-07 11:49:01 +01:00
|
|
|
if (local_error)
|
2002-11-21 14:56:48 +01:00
|
|
|
::send_error(thd);
|
2002-11-07 03:02:37 +01:00
|
|
|
else
|
2004-05-04 13:45:20 +02:00
|
|
|
{
|
|
|
|
thd->row_count_func= deleted;
|
2002-11-21 14:56:48 +01:00
|
|
|
::send_ok(thd, deleted);
|
2004-05-04 13:45:20 +02:00
|
|
|
}
|
2001-06-03 16:07:26 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2001-09-02 12:47:00 +02:00
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
2002-06-11 10:20:31 +02:00
|
|
|
TRUNCATE TABLE
|
2001-09-02 12:47:00 +02:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
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
|
2001-09-03 04:16:15 +02:00
|
|
|
- If we want to have a name lock on the table on exit without errors.
|
2001-09-02 12:47:00 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
2004-08-23 16:15:57 +02:00
|
|
|
bzero((char*) &create_info,sizeof(create_info));
|
2001-09-02 12:47:00 +02:00
|
|
|
/* If it is a temporary table, close and regenerate it */
|
2001-09-03 04:16:15 +02:00
|
|
|
if (!dont_send_ok && (table_ptr=find_temporary_table(thd,table_list->db,
|
|
|
|
table_list->real_name)))
|
2001-09-02 12:47:00 +02:00
|
|
|
{
|
|
|
|
TABLE *table= *table_ptr;
|
|
|
|
table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
|
2002-06-04 07:23:57 +02:00
|
|
|
db_type table_type=table->db_type;
|
2001-09-02 12:47:00 +02:00
|
|
|
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);
|
2001-12-02 13:34:01 +01:00
|
|
|
// We don't need to call invalidate() because this table is not in cache
|
2001-09-02 12:47:00 +02:00
|
|
|
if ((error= (int) !(open_temporary_table(thd, path, table_list->db,
|
|
|
|
table_list->real_name, 1))))
|
|
|
|
(void) rm_temporary_table(table_type, path);
|
2002-06-11 10:20:31 +02:00
|
|
|
/*
|
2002-08-30 11:40:40 +02:00
|
|
|
If we return here we will not have logged the truncation to the bin log
|
|
|
|
and we will not send_ok() to the client.
|
2002-04-09 02:20:24 +02:00
|
|
|
*/
|
|
|
|
goto end;
|
2001-09-02 12:47:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
(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)
|
|
|
|
{
|
2002-08-05 10:45:39 +02:00
|
|
|
my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db,
|
|
|
|
table_list->real_name);
|
2001-09-02 12:47:00 +02:00
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
if (!ha_supports_generate(table_type))
|
|
|
|
{
|
|
|
|
/* Probably InnoDB table */
|
2002-11-16 19:19:10 +01:00
|
|
|
table_list->lock_type= TL_WRITE;
|
2004-09-03 17:11:09 +02:00
|
|
|
ha_enable_transaction(thd, FALSE);
|
|
|
|
error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0,
|
|
|
|
HA_POS_ERROR, 0);
|
|
|
|
ha_enable_transaction(thd, TRUE);
|
|
|
|
DBUG_RETURN(error);
|
2001-09-02 12:47:00 +02:00
|
|
|
}
|
|
|
|
if (lock_and_wait_for_table_name(thd, table_list))
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
*fn_ext(path)=0; // Remove the .frm extension
|
|
|
|
error= ha_create_table(path,&create_info,1) ? -1 : 0;
|
2002-03-22 21:55:08 +01:00
|
|
|
query_cache_invalidate3(thd, table_list, 0);
|
2002-11-07 03:02:37 +01:00
|
|
|
|
2002-04-09 02:20:24 +02:00
|
|
|
end:
|
2001-09-03 04:16:15 +02:00
|
|
|
if (!dont_send_ok)
|
2001-09-02 12:47:00 +02:00
|
|
|
{
|
2001-09-03 04:16:15 +02:00
|
|
|
if (!error)
|
2001-09-02 12:47:00 +02:00
|
|
|
{
|
2001-09-03 04:16:15 +02:00
|
|
|
if (mysql_bin_log.is_open())
|
|
|
|
{
|
2003-12-16 11:10:50 +01:00
|
|
|
thd->clear_error();
|
2002-11-07 03:02:37 +01:00
|
|
|
Query_log_event qinfo(thd, thd->query, thd->query_length,
|
|
|
|
thd->tmp_table);
|
2001-09-03 04:16:15 +02:00
|
|
|
mysql_bin_log.write(&qinfo);
|
|
|
|
}
|
2002-10-02 12:33:08 +02:00
|
|
|
send_ok(thd); // This should return record count
|
2001-09-02 12:47:00 +02:00
|
|
|
}
|
2002-06-04 21:59:12 +02:00
|
|
|
VOID(pthread_mutex_lock(&LOCK_open));
|
2001-09-03 04:16:15 +02:00
|
|
|
unlock_table_name(thd, table_list);
|
2002-06-04 21:59:12 +02:00
|
|
|
VOID(pthread_mutex_unlock(&LOCK_open));
|
2001-09-02 12:47:00 +02:00
|
|
|
}
|
2001-09-03 04:16:15 +02:00
|
|
|
else if (error)
|
2002-06-04 21:59:12 +02:00
|
|
|
{
|
|
|
|
VOID(pthread_mutex_lock(&LOCK_open));
|
2001-09-03 04:16:15 +02:00
|
|
|
unlock_table_name(thd, table_list);
|
2002-06-04 21:59:12 +02:00
|
|
|
VOID(pthread_mutex_unlock(&LOCK_open));
|
|
|
|
}
|
2001-09-02 12:47:00 +02:00
|
|
|
DBUG_RETURN(error ? -1 : 0);
|
|
|
|
}
|