~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_delete.cc

  • Committer: Padraig O'Sullivan
  • Date: 2009-08-07 14:14:58 UTC
  • mfrom: (1112 staging)
  • mto: (1115.3.4 captain)
  • mto: This revision was merged to the branch mainline in revision 1117.
  • Revision ID: osullivan.padraig@gmail.com-20090807141458-qrc3don58s304ore
MergeĀ fromĀ trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
52
52
  Session::killed_state killed_status= Session::NOT_KILLED;
53
53
 
54
54
 
55
 
  if (session->open_and_lock_tables(table_list))
56
 
    return(true);
 
55
  if (session->openTablesLock(table_list))
 
56
    return true;
57
57
 
58
58
  table= table_list->table;
59
59
  assert(table);
360
360
                                    &session->lex->select_lex.top_join_list,
361
361
                                    table_list,
362
362
                                    &select_lex->leaf_tables, false) ||
363
 
      setup_conds(session, table_list, conds))
 
363
      session->setup_conds(table_list, conds))
364
364
    return(true);
365
365
  {
366
366
    TableList *duplicate;
380
380
 
381
381
 
382
382
/***************************************************************************
383
 
  Delete multiple tables from join
384
 
***************************************************************************/
385
 
 
386
 
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
387
 
{
388
 
  handler *file= (handler*)arg;
389
 
  return file->cmp_ref((const unsigned char*)a, (const unsigned char*)b);
390
 
}
391
 
 
392
 
/*
393
 
  make delete specific preparation and checks after opening tables
394
 
 
395
 
  SYNOPSIS
396
 
    mysql_multi_delete_prepare()
397
 
    session         thread handler
398
 
 
399
 
  RETURN
400
 
    false OK
401
 
    true  Error
402
 
*/
403
 
 
404
 
int mysql_multi_delete_prepare(Session *session)
405
 
{
406
 
  LEX *lex= session->lex;
407
 
  TableList *aux_tables= (TableList *)lex->auxiliary_table_list.first;
408
 
  TableList *target_tbl;
409
 
 
410
 
 
411
 
  /*
412
 
    setup_tables() need for VIEWs. JOIN::prepare() will not do it second
413
 
    time.
414
 
 
415
 
    lex->query_tables also point on local list of DELETE Select_Lex
416
 
  */
417
 
  if (setup_tables_and_check_access(session, &session->lex->select_lex.context,
418
 
                                    &session->lex->select_lex.top_join_list,
419
 
                                    lex->query_tables,
420
 
                                    &lex->select_lex.leaf_tables, false))
421
 
    return(true);
422
 
 
423
 
 
424
 
  /*
425
 
    Multi-delete can't be constructed over-union => we always have
426
 
    single SELECT on top and have to check underlying SELECTs of it
427
 
  */
428
 
  lex->select_lex.exclude_from_table_unique_test= true;
429
 
  /* Fix tables-to-be-deleted-from list to point at opened tables */
430
 
  for (target_tbl= (TableList*) aux_tables;
431
 
       target_tbl;
432
 
       target_tbl= target_tbl->next_local)
433
 
  {
434
 
    target_tbl->table= target_tbl->correspondent_table->table;
435
 
    assert(target_tbl->table);
436
 
 
437
 
    /*
438
 
      Check that table from which we delete is not used somewhere
439
 
      inside subqueries/view.
440
 
    */
441
 
    {
442
 
      TableList *duplicate;
443
 
      if ((duplicate= unique_table(session, target_tbl->correspondent_table,
444
 
                                   lex->query_tables, 0)))
445
 
      {
446
 
        my_error(ER_UPDATE_TABLE_USED, MYF(0), target_tbl->correspondent_table->alias);
447
 
 
448
 
        return true;
449
 
      }
450
 
    }
451
 
  }
452
 
 
453
 
  return false;
454
 
}
455
 
 
456
 
 
457
 
multi_delete::multi_delete(TableList *dt, uint32_t num_of_tables_arg)
458
 
  : delete_tables(dt), deleted(0), found(0),
459
 
    num_of_tables(num_of_tables_arg), error(0),
460
 
    do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0)
461
 
{
462
 
  tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables);
463
 
}
464
 
 
465
 
 
466
 
int
467
 
multi_delete::prepare(List<Item> &, Select_Lex_Unit *u)
468
 
{
469
 
 
470
 
  unit= u;
471
 
  do_delete= 1;
472
 
  session->set_proc_info("deleting from main table");
473
 
  return(0);
474
 
}
475
 
 
476
 
 
477
 
bool
478
 
multi_delete::initialize_tables(JOIN *join)
479
 
{
480
 
  TableList *walk;
481
 
  Unique **tempfiles_ptr;
482
 
 
483
 
 
484
 
  if ((session->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
485
 
    return(1);
486
 
 
487
 
  table_map tables_to_delete_from=0;
488
 
  for (walk= delete_tables; walk; walk= walk->next_local)
489
 
    tables_to_delete_from|= walk->table->map;
490
 
 
491
 
  walk= delete_tables;
492
 
  delete_while_scanning= 1;
493
 
  for (JoinTable *tab=join->join_tab, *end=join->join_tab+join->tables;
494
 
       tab < end;
495
 
       tab++)
496
 
  {
497
 
    if (tab->table->map & tables_to_delete_from)
498
 
    {
499
 
      /* We are going to delete from this table */
500
 
      Table *tbl=walk->table=tab->table;
501
 
      walk= walk->next_local;
502
 
      /* Don't use KEYREAD optimization on this table */
503
 
      tbl->no_keyread=1;
504
 
      /* Don't use record cache */
505
 
      tbl->no_cache= 1;
506
 
      tbl->covering_keys.reset();
507
 
      if (tbl->file->has_transactions())
508
 
        transactional_tables= 1;
509
 
      else
510
 
        normal_tables= 1;
511
 
      tbl->prepare_for_position();
512
 
      tbl->mark_columns_needed_for_delete();
513
 
    }
514
 
    else if ((tab->type != JT_SYSTEM && tab->type != JT_CONST) &&
515
 
             walk == delete_tables)
516
 
    {
517
 
      /*
518
 
        We are not deleting from the table we are scanning. In this
519
 
        case send_data() shouldn't delete any rows a we may touch
520
 
        the rows in the deleted table many times
521
 
      */
522
 
      delete_while_scanning= 0;
523
 
    }
524
 
  }
525
 
  walk= delete_tables;
526
 
  tempfiles_ptr= tempfiles;
527
 
  if (delete_while_scanning)
528
 
  {
529
 
    table_being_deleted= delete_tables;
530
 
    walk= walk->next_local;
531
 
  }
532
 
  for (;walk ;walk= walk->next_local)
533
 
  {
534
 
    Table *table=walk->table;
535
 
    *tempfiles_ptr++= new Unique (refpos_order_cmp,
536
 
                                  (void *) table->file,
537
 
                                  table->file->ref_length,
538
 
                                  current_session->variables.sortbuff_size);
539
 
  }
540
 
  return(session->is_fatal_error != 0);
541
 
}
542
 
 
543
 
 
544
 
multi_delete::~multi_delete()
545
 
{
546
 
  for (table_being_deleted= delete_tables;
547
 
       table_being_deleted;
548
 
       table_being_deleted= table_being_deleted->next_local)
549
 
  {
550
 
    Table *table= table_being_deleted->table;
551
 
    table->no_keyread=0;
552
 
  }
553
 
 
554
 
  for (uint32_t counter= 0; counter < num_of_tables; counter++)
555
 
  {
556
 
    if (tempfiles[counter])
557
 
      delete tempfiles[counter];
558
 
  }
559
 
}
560
 
 
561
 
 
562
 
bool multi_delete::send_data(List<Item> &)
563
 
{
564
 
  int secure_counter= delete_while_scanning ? -1 : 0;
565
 
  TableList *del_table;
566
 
 
567
 
 
568
 
  for (del_table= delete_tables;
569
 
       del_table;
570
 
       del_table= del_table->next_local, secure_counter++)
571
 
  {
572
 
    Table *table= del_table->table;
573
 
 
574
 
    /* Check if we are using outer join and we didn't find the row */
575
 
    if (table->status & (STATUS_NULL_ROW | STATUS_DELETED))
576
 
      continue;
577
 
 
578
 
    table->file->position(table->record[0]);
579
 
    found++;
580
 
 
581
 
    if (secure_counter < 0)
582
 
    {
583
 
      /* We are scanning the current table */
584
 
      assert(del_table == table_being_deleted);
585
 
      table->status|= STATUS_DELETED;
586
 
      if (!(error=table->file->ha_delete_row(table->record[0])))
587
 
      {
588
 
        deleted++;
589
 
        if (!table->file->has_transactions())
590
 
          session->transaction.stmt.modified_non_trans_table= true;
591
 
      }
592
 
      else
593
 
      {
594
 
        table->file->print_error(error,MYF(0));
595
 
        return(1);
596
 
      }
597
 
    }
598
 
    else
599
 
    {
600
 
      error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
601
 
      if (error)
602
 
      {
603
 
        error= 1;                               // Fatal error
604
 
        return(1);
605
 
      }
606
 
    }
607
 
  }
608
 
  return(0);
609
 
}
610
 
 
611
 
 
612
 
void multi_delete::send_error(uint32_t errcode,const char *err)
613
 
{
614
 
 
615
 
 
616
 
  /* First send error what ever it is ... */
617
 
  my_message(errcode, err, MYF(0));
618
 
 
619
 
  return;
620
 
}
621
 
 
622
 
 
623
 
void multi_delete::abort()
624
 
{
625
 
 
626
 
 
627
 
  /* the error was handled or nothing deleted and no side effects return */
628
 
  if (error_handled ||
629
 
      (!session->transaction.stmt.modified_non_trans_table && !deleted))
630
 
    return;
631
 
 
632
 
  /*
633
 
    If rows from the first table only has been deleted and it is
634
 
    transactional, just do rollback.
635
 
    The same if all tables are transactional, regardless of where we are.
636
 
    In all other cases do attempt deletes ...
637
 
  */
638
 
  if (do_delete && normal_tables &&
639
 
      (table_being_deleted != delete_tables ||
640
 
       !table_being_deleted->table->file->has_transactions()))
641
 
  {
642
 
    /*
643
 
      We have to execute the recorded do_deletes() and write info into the
644
 
      error log
645
 
    */
646
 
    error= 1;
647
 
    send_eof();
648
 
    assert(error_handled);
649
 
    return;
650
 
  }
651
 
 
652
 
  if (session->transaction.stmt.modified_non_trans_table)
653
 
  {
654
 
    session->transaction.all.modified_non_trans_table= true;
655
 
  }
656
 
  return;
657
 
}
658
 
 
659
 
 
660
 
 
661
 
/*
662
 
  Do delete from other tables.
663
 
  Returns values:
664
 
        0 ok
665
 
        1 error
666
 
*/
667
 
 
668
 
int multi_delete::do_deletes()
669
 
{
670
 
  int local_error= 0, counter= 0, tmp_error;
671
 
  bool will_batch;
672
 
 
673
 
  assert(do_delete);
674
 
 
675
 
  do_delete= 0;                                 // Mark called
676
 
  if (!found)
677
 
    return(0);
678
 
 
679
 
  table_being_deleted= (delete_while_scanning ? delete_tables->next_local :
680
 
                        delete_tables);
681
 
 
682
 
  for (; table_being_deleted;
683
 
       table_being_deleted= table_being_deleted->next_local, counter++)
684
 
  {
685
 
    ha_rows last_deleted= deleted;
686
 
    Table *table = table_being_deleted->table;
687
 
    if (tempfiles[counter]->get(table))
688
 
    {
689
 
      local_error=1;
690
 
      break;
691
 
    }
692
 
 
693
 
    READ_RECORD info;
694
 
    init_read_record(&info,session,table,NULL,0,1);
695
 
    /*
696
 
      Ignore any rows not found in reference tables as they may already have
697
 
      been deleted by foreign key handling
698
 
    */
699
 
    info.ignore_not_found_rows= 1;
700
 
    will_batch= !table->file->start_bulk_delete();
701
 
    while (!(local_error=info.read_record(&info)) && !session->killed)
702
 
    {
703
 
      if ((local_error=table->file->ha_delete_row(table->record[0])))
704
 
      {
705
 
        table->file->print_error(local_error,MYF(0));
706
 
        break;
707
 
      }
708
 
      deleted++;
709
 
    }
710
 
    if (will_batch && (tmp_error= table->file->end_bulk_delete()))
711
 
    {
712
 
      if (!local_error)
713
 
      {
714
 
        local_error= tmp_error;
715
 
        table->file->print_error(local_error,MYF(0));
716
 
      }
717
 
    }
718
 
    if (last_deleted != deleted && !table->file->has_transactions())
719
 
      session->transaction.stmt.modified_non_trans_table= true;
720
 
    end_read_record(&info);
721
 
    if (session->killed && !local_error)
722
 
      local_error= 1;
723
 
    if (local_error == -1)                              // End of file
724
 
      local_error = 0;
725
 
  }
726
 
  return(local_error);
727
 
}
728
 
 
729
 
 
730
 
/*
731
 
  Send ok to the client
732
 
 
733
 
  return:  0 sucess
734
 
           1 error
735
 
*/
736
 
 
737
 
bool multi_delete::send_eof()
738
 
{
739
 
  Session::killed_state killed_status= Session::NOT_KILLED;
740
 
  session->set_proc_info("deleting from reference tables");
741
 
 
742
 
  /* Does deletes for the last n - 1 tables, returns 0 if ok */
743
 
  int local_error= do_deletes();                // returns 0 if success
744
 
 
745
 
  /* compute a total error to know if something failed */
746
 
  local_error= local_error || error;
747
 
  killed_status= (local_error == 0)? Session::NOT_KILLED : session->killed;
748
 
  /* reset used flags */
749
 
  session->set_proc_info("end");
750
 
 
751
 
  if ((local_error == 0) || session->transaction.stmt.modified_non_trans_table)
752
 
  {
753
 
    if (session->transaction.stmt.modified_non_trans_table)
754
 
      session->transaction.all.modified_non_trans_table= true;
755
 
  }
756
 
  if (local_error != 0)
757
 
    error_handled= true; // to force early leave from ::send_error()
758
 
 
759
 
  if (!local_error)
760
 
  {
761
 
    session->row_count_func= deleted;
762
 
    session->my_ok((ha_rows) session->row_count_func);
763
 
  }
764
 
  return 0;
765
 
}
766
 
 
767
 
 
768
 
/***************************************************************************
769
383
  TRUNCATE Table
770
384
****************************************************************************/
771
385
 
807
421
                    share->db.str, share->table_name.str, &create_info, 1,
808
422
                    NULL);
809
423
    // We don't need to call invalidate() because this table is not in cache
810
 
    if ((error= (int) !(open_temporary_table(session, share->path.str,
811
 
                                             share->db.str,
812
 
                                             share->table_name.str, 1,
813
 
                                             OTM_OPEN))))
814
 
      (void) rm_temporary_table(table_type, path);
 
424
    if ((error= (int) !(session->open_temporary_table(share->path.str,
 
425
                                                      share->db.str,
 
426
                                                      share->table_name.str, 1,
 
427
                                                      OTM_OPEN))))
 
428
      (void) session->rm_temporary_table(table_type, path);
815
429
    share->free_table_share();
816
430
    free((char*) table);
817
431
    /*