412
387
/***************************************************************************
413
Delete multiple tables from join
414
***************************************************************************/
416
#define MEM_STRIP_BUF_SIZE current_session->variables.sortbuff_size
418
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
420
handler *file= (handler*)arg;
421
return file->cmp_ref((const unsigned char*)a, (const unsigned char*)b);
425
make delete specific preparation and checks after opening tables
428
mysql_multi_delete_prepare()
429
session thread handler
436
int mysql_multi_delete_prepare(Session *session)
438
LEX *lex= session->lex;
439
TableList *aux_tables= (TableList *)lex->auxiliary_table_list.first;
440
TableList *target_tbl;
444
setup_tables() need for VIEWs. JOIN::prepare() will not do it second
447
lex->query_tables also point on local list of DELETE SELECT_LEX
449
if (setup_tables_and_check_access(session, &session->lex->select_lex.context,
450
&session->lex->select_lex.top_join_list,
452
&lex->select_lex.leaf_tables, false))
457
Multi-delete can't be constructed over-union => we always have
458
single SELECT on top and have to check underlying SELECTs of it
460
lex->select_lex.exclude_from_table_unique_test= true;
461
/* Fix tables-to-be-deleted-from list to point at opened tables */
462
for (target_tbl= (TableList*) aux_tables;
464
target_tbl= target_tbl->next_local)
466
if (!(target_tbl->table= target_tbl->correspondent_table->table))
468
assert(target_tbl->correspondent_table->merge_underlying_list &&
469
target_tbl->correspondent_table->merge_underlying_list->
471
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), "", "");
476
Check that table from which we delete is not used somewhere
477
inside subqueries/view.
480
TableList *duplicate;
481
if ((duplicate= unique_table(session, target_tbl->correspondent_table,
482
lex->query_tables, 0)))
484
update_non_unique_table_error(target_tbl->correspondent_table,
485
"DELETE", duplicate);
494
multi_delete::multi_delete(TableList *dt, uint32_t num_of_tables_arg)
495
: delete_tables(dt), deleted(0), found(0),
496
num_of_tables(num_of_tables_arg), error(0),
497
do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0)
499
tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables);
504
multi_delete::prepare(List<Item> &, SELECT_LEX_UNIT *u)
509
session->set_proc_info("deleting from main table");
515
multi_delete::initialize_tables(JOIN *join)
518
Unique **tempfiles_ptr;
521
if ((session->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
524
table_map tables_to_delete_from=0;
525
for (walk= delete_tables; walk; walk= walk->next_local)
526
tables_to_delete_from|= walk->table->map;
529
delete_while_scanning= 1;
530
for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
534
if (tab->table->map & tables_to_delete_from)
536
/* We are going to delete from this table */
537
Table *tbl=walk->table=tab->table;
538
walk= walk->next_local;
539
/* Don't use KEYREAD optimization on this table */
541
/* Don't use record cache */
543
tbl->covering_keys.clear_all();
544
if (tbl->file->has_transactions())
545
transactional_tables= 1;
548
tbl->prepare_for_position();
549
tbl->mark_columns_needed_for_delete();
551
else if ((tab->type != JT_SYSTEM && tab->type != JT_CONST) &&
552
walk == delete_tables)
555
We are not deleting from the table we are scanning. In this
556
case send_data() shouldn't delete any rows a we may touch
557
the rows in the deleted table many times
559
delete_while_scanning= 0;
563
tempfiles_ptr= tempfiles;
564
if (delete_while_scanning)
566
table_being_deleted= delete_tables;
567
walk= walk->next_local;
569
for (;walk ;walk= walk->next_local)
571
Table *table=walk->table;
572
*tempfiles_ptr++= new Unique (refpos_order_cmp,
573
(void *) table->file,
574
table->file->ref_length,
577
return(session->is_fatal_error != 0);
581
multi_delete::~multi_delete()
583
for (table_being_deleted= delete_tables;
585
table_being_deleted= table_being_deleted->next_local)
587
Table *table= table_being_deleted->table;
591
for (uint32_t counter= 0; counter < num_of_tables; counter++)
593
if (tempfiles[counter])
594
delete tempfiles[counter];
599
bool multi_delete::send_data(List<Item> &)
601
int secure_counter= delete_while_scanning ? -1 : 0;
602
TableList *del_table;
605
for (del_table= delete_tables;
607
del_table= del_table->next_local, secure_counter++)
609
Table *table= del_table->table;
611
/* Check if we are using outer join and we didn't find the row */
612
if (table->status & (STATUS_NULL_ROW | STATUS_DELETED))
615
table->file->position(table->record[0]);
618
if (secure_counter < 0)
620
/* We are scanning the current table */
621
assert(del_table == table_being_deleted);
622
table->status|= STATUS_DELETED;
623
if (!(error=table->file->ha_delete_row(table->record[0])))
626
if (!table->file->has_transactions())
627
session->transaction.stmt.modified_non_trans_table= true;
631
table->file->print_error(error,MYF(0));
637
error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
640
error= 1; // Fatal error
649
void multi_delete::send_error(uint32_t errcode,const char *err)
653
/* First send error what ever it is ... */
654
my_message(errcode, err, MYF(0));
660
void multi_delete::abort()
664
/* the error was handled or nothing deleted and no side effects return */
666
(!session->transaction.stmt.modified_non_trans_table && !deleted))
670
If rows from the first table only has been deleted and it is
671
transactional, just do rollback.
672
The same if all tables are transactional, regardless of where we are.
673
In all other cases do attempt deletes ...
675
if (do_delete && normal_tables &&
676
(table_being_deleted != delete_tables ||
677
!table_being_deleted->table->file->has_transactions()))
680
We have to execute the recorded do_deletes() and write info into the
685
assert(error_handled);
689
if (session->transaction.stmt.modified_non_trans_table)
692
there is only side effects; to binlog with the error
694
if (mysql_bin_log.is_open())
696
session->binlog_query(Session::ROW_QUERY_TYPE,
697
session->query, session->query_length,
698
transactional_tables, false);
700
session->transaction.all.modified_non_trans_table= true;
708
Do delete from other tables.
714
int multi_delete::do_deletes()
716
int local_error= 0, counter= 0, tmp_error;
721
do_delete= 0; // Mark called
725
table_being_deleted= (delete_while_scanning ? delete_tables->next_local :
728
for (; table_being_deleted;
729
table_being_deleted= table_being_deleted->next_local, counter++)
731
ha_rows last_deleted= deleted;
732
Table *table = table_being_deleted->table;
733
if (tempfiles[counter]->get(table))
740
init_read_record(&info,session,table,NULL,0,1);
742
Ignore any rows not found in reference tables as they may already have
743
been deleted by foreign key handling
745
info.ignore_not_found_rows= 1;
746
will_batch= !table->file->start_bulk_delete();
747
while (!(local_error=info.read_record(&info)) && !session->killed)
749
if ((local_error=table->file->ha_delete_row(table->record[0])))
751
table->file->print_error(local_error,MYF(0));
756
if (will_batch && (tmp_error= table->file->end_bulk_delete()))
760
local_error= tmp_error;
761
table->file->print_error(local_error,MYF(0));
764
if (last_deleted != deleted && !table->file->has_transactions())
765
session->transaction.stmt.modified_non_trans_table= true;
766
end_read_record(&info);
767
if (session->killed && !local_error)
769
if (local_error == -1) // End of file
777
Send ok to the client
783
bool multi_delete::send_eof()
785
Session::killed_state killed_status= Session::NOT_KILLED;
786
session->set_proc_info("deleting from reference tables");
788
/* Does deletes for the last n - 1 tables, returns 0 if ok */
789
int local_error= do_deletes(); // returns 0 if success
791
/* compute a total error to know if something failed */
792
local_error= local_error || error;
793
killed_status= (local_error == 0)? Session::NOT_KILLED : session->killed;
794
/* reset used flags */
795
session->set_proc_info("end");
797
if ((local_error == 0) || session->transaction.stmt.modified_non_trans_table)
799
if (mysql_bin_log.is_open())
801
if (local_error == 0)
802
session->clear_error();
803
if (session->binlog_query(Session::ROW_QUERY_TYPE,
804
session->query, session->query_length,
805
transactional_tables, false, killed_status) &&
808
local_error=1; // Log write failed: roll back the SQL statement
811
if (session->transaction.stmt.modified_non_trans_table)
812
session->transaction.all.modified_non_trans_table= true;
814
if (local_error != 0)
815
error_handled= true; // to force early leave from ::send_error()
819
session->row_count_func= deleted;
820
::my_ok(session, (ha_rows) session->row_count_func);
826
/***************************************************************************
828
389
****************************************************************************/
848
409
uint32_t path_length;
851
412
memset(&create_info, 0, sizeof(create_info));
852
413
/* If it is a temporary table, close and regenerate it */
853
if (!dont_send_ok && (table= find_temporary_table(session, table_list)))
414
if (!dont_send_ok && (table= session->find_temporary_table(table_list)))
855
handlerton *table_type= table->s->db_type();
856
TABLE_SHARE *share= table->s;
857
bool frm_only= (share->tmp_table == TMP_TABLE_FRM_FILE_ONLY);
416
plugin::StorageEngine *table_type= table->s->db_type();
417
TableShare *share= table->s;
859
if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE))
419
if (!table_type->check_flag(HTON_BIT_CAN_RECREATE))
860
420
goto trunc_by_del;
862
422
table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
864
close_temporary_table(session, table, 0, 0); // Don't free share
865
ha_create_table(session, share->normalized_path.str,
866
share->db.str, share->table_name.str, &create_info, 1);
424
session->close_temporary_table(table, false, false); // Don't free share
425
plugin::StorageEngine::createTable(session, share->normalized_path.str,
426
share->db.str, share->table_name.str,
427
&create_info, 1, NULL);
867
428
// We don't need to call invalidate() because this table is not in cache
868
if ((error= (int) !(open_temporary_table(session, share->path.str,
870
share->table_name.str, 1,
872
(void) rm_temporary_table(table_type, path, frm_only);
873
free_table_share(share);
429
if ((error= (int) !(session->open_temporary_table(share->path.str,
431
share->table_name.str, 1,
433
(void) session->rm_temporary_table(table_type, path);
434
share->free_table_share();
874
435
free((char*) table);
876
437
If we return here we will not have logged the truncation to the bin log