~posulliv/drizzle/memcached_applier

« back to all changes in this revision

Viewing changes to drizzled/sql_select.cc

  • Committer: Jay Pipes
  • Date: 2009-08-03 14:23:22 UTC
  • mfrom: (1039.2.68 staging)
  • mto: This revision was merged to the branch mainline in revision 1078.
  • Revision ID: jpipes@serialcoder-20090803142322-1g67h7su9mocg9ig
Merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
*/
25
25
#include "drizzled/server_includes.h"
26
26
#include "drizzled/sql_select.h" /* include join.h */
27
 
#include "drizzled/semi_join_table.h"
28
27
#include "drizzled/table_map_iterator.h"
29
28
 
30
29
#include "drizzled/error.h"
402
401
    }
403
402
  }
404
403
 
405
 
  if (join->flatten_subqueries())
406
 
  {
407
 
    err= 1;
408
 
    goto err;
409
 
  }
410
 
 
411
404
  if ((err= join->optimize()))
412
405
  {
413
406
    goto err;                                   // 1
440
433
  return(join->error);
441
434
}
442
435
 
443
 
int subq_sj_candidate_cmp(Item_in_subselect* const *el1,
444
 
                          Item_in_subselect* const *el2)
445
 
{
446
 
  return ((*el1)->sj_convert_priority < (*el2)->sj_convert_priority) ? 1 :
447
 
         ( ((*el1)->sj_convert_priority == (*el2)->sj_convert_priority)? 0 : -1);
448
 
}
449
 
 
450
436
inline Item *and_items(Item* cond, Item *item)
451
437
{
452
438
  return (cond? (new Item_cond_and(cond, item)) : item);
453
439
}
454
440
 
455
 
static TableList *alloc_join_nest(Session *session)
456
 
{
457
 
  TableList *tbl;
458
 
  if (!(tbl= (TableList*) session->calloc(ALIGN_SIZE(sizeof(TableList))+
459
 
                                       sizeof(nested_join_st))))
460
 
    return NULL;
461
 
  tbl->nested_join= (nested_join_st*) ((unsigned char*)tbl +
462
 
                                    ALIGN_SIZE(sizeof(TableList)));
463
 
  return tbl;
464
 
}
465
 
 
466
441
static void fix_list_after_tbl_changes(Select_Lex *new_parent, List<TableList> *tlist)
467
442
{
468
443
  List_iterator<TableList> it(*tlist);
476
451
  }
477
452
}
478
453
 
479
 
/*
480
 
  Convert a subquery predicate into a TableList semi-join nest
481
 
 
482
 
  SYNOPSIS
483
 
    convert_subq_to_sj()
484
 
       parent_join  Parent join, the one that has subq_pred in its WHERE/ON
485
 
                    clause
486
 
       subq_pred    Subquery predicate to be converted
487
 
 
488
 
  DESCRIPTION
489
 
    Convert a subquery predicate into a TableList semi-join nest. All the
490
 
    prerequisites are already checked, so the conversion is always successfull.
491
 
 
492
 
    Prepared Statements: the transformation is permanent:
493
 
     - Changes in TableList structures are naturally permanent
494
 
     - Item tree changes are performed on statement MEM_ROOT:
495
 
        = we activate statement MEM_ROOT
496
 
        = this function is called before the first fix_prepare_information
497
 
          call.
498
 
 
499
 
    This is intended because the criteria for subquery-to-sj conversion remain
500
 
    constant for the lifetime of the Prepared Statement.
501
 
 
502
 
  RETURN
503
 
    false  OK
504
 
    true   Out of memory error
505
 
*/
506
 
bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
507
 
{
508
 
  Select_Lex *parent_lex= parent_join->select_lex;
509
 
  TableList *emb_tbl_nest= NULL;
510
 
  List<TableList> *emb_join_list= &parent_lex->top_join_list;
511
 
  Session *session= parent_join->session;
512
 
 
513
 
  /*
514
 
    1. Find out where to put the predicate into.
515
 
     Note: for "t1 LEFT JOIN t2" this will be t2, a leaf.
516
 
  */
517
 
  if ((void*)subq_pred->expr_join_nest != (void*)1)
518
 
  {
519
 
    if (subq_pred->expr_join_nest->nested_join)
520
 
    {
521
 
      /*
522
 
        We're dealing with
523
 
 
524
 
          ... [LEFT] JOIN  ( ... ) ON (subquery AND whatever) ...
525
 
 
526
 
        The sj-nest will be inserted into the brackets nest.
527
 
      */
528
 
      emb_tbl_nest=  subq_pred->expr_join_nest;
529
 
      emb_join_list= &emb_tbl_nest->nested_join->join_list;
530
 
    }
531
 
    else if (!subq_pred->expr_join_nest->outer_join)
532
 
    {
533
 
      /*
534
 
        We're dealing with
535
 
 
536
 
          ... INNER JOIN tblX ON (subquery AND whatever) ...
537
 
 
538
 
        The sj-nest will be tblX's "sibling", i.e. another child of its
539
 
        parent. This is ok because tblX is joined as an inner join.
540
 
      */
541
 
      emb_tbl_nest= subq_pred->expr_join_nest->embedding;
542
 
      if (emb_tbl_nest)
543
 
        emb_join_list= &emb_tbl_nest->nested_join->join_list;
544
 
    }
545
 
    else if (!subq_pred->expr_join_nest->nested_join)
546
 
    {
547
 
      TableList *outer_tbl= subq_pred->expr_join_nest;
548
 
      TableList *wrap_nest;
549
 
      /*
550
 
        We're dealing with
551
 
 
552
 
          ... LEFT JOIN tbl ON (on_expr AND subq_pred) ...
553
 
 
554
 
        we'll need to convert it into:
555
 
 
556
 
          ... LEFT JOIN ( tbl SJ (subq_tables) ) ON (on_expr AND subq_pred) ...
557
 
                        |                      |
558
 
                        |<----- wrap_nest ---->|
559
 
 
560
 
        Q:  other subqueries may be pointing to this element. What to do?
561
 
        A1: simple solution: copy *subq_pred->expr_join_nest= *parent_nest.
562
 
            But we'll need to fix other pointers.
563
 
        A2: Another way: have TableList::next_ptr so the following
564
 
            subqueries know the table has been nested.
565
 
        A3: changes in the TableList::outer_join will make everything work
566
 
            automatically.
567
 
      */
568
 
      if (!(wrap_nest= alloc_join_nest(parent_join->session)))
569
 
      {
570
 
        return(true);
571
 
      }
572
 
      wrap_nest->embedding= outer_tbl->embedding;
573
 
      wrap_nest->join_list= outer_tbl->join_list;
574
 
      wrap_nest->alias= (char*) "(sj-wrap)";
575
 
 
576
 
      wrap_nest->nested_join->join_list.empty();
577
 
      wrap_nest->nested_join->join_list.push_back(outer_tbl);
578
 
 
579
 
      outer_tbl->embedding= wrap_nest;
580
 
      outer_tbl->join_list= &wrap_nest->nested_join->join_list;
581
 
 
582
 
      /*
583
 
        wrap_nest will take place of outer_tbl, so move the outer join flag
584
 
        and on_expr
585
 
      */
586
 
      wrap_nest->outer_join= outer_tbl->outer_join;
587
 
      outer_tbl->outer_join= 0;
588
 
 
589
 
      wrap_nest->on_expr= outer_tbl->on_expr;
590
 
      outer_tbl->on_expr= NULL;
591
 
 
592
 
      List_iterator<TableList> li(*wrap_nest->join_list);
593
 
      TableList *tbl;
594
 
      while ((tbl= li++))
595
 
      {
596
 
        if (tbl == outer_tbl)
597
 
        {
598
 
          li.replace(wrap_nest);
599
 
          break;
600
 
        }
601
 
      }
602
 
      /*
603
 
        Ok now wrap_nest 'contains' outer_tbl and we're ready to add the
604
 
        semi-join nest into it
605
 
      */
606
 
      emb_join_list= &wrap_nest->nested_join->join_list;
607
 
      emb_tbl_nest=  wrap_nest;
608
 
    }
609
 
  }
610
 
 
611
 
  TableList *sj_nest;
612
 
  nested_join_st *nested_join;
613
 
  if (!(sj_nest= alloc_join_nest(parent_join->session)))
614
 
  {
615
 
    return(true);
616
 
  }
617
 
  nested_join= sj_nest->nested_join;
618
 
 
619
 
  sj_nest->join_list= emb_join_list;
620
 
  sj_nest->embedding= emb_tbl_nest;
621
 
  sj_nest->alias= (char*) "(sj-nest)";
622
 
  /* Nests do not participate in those 'chains', so: */
623
 
  /* sj_nest->next_leaf= sj_nest->next_local= sj_nest->next_global == NULL*/
624
 
  emb_join_list->push_back(sj_nest);
625
 
 
626
 
  /*
627
 
    nested_join->used_tables and nested_join->not_null_tables are
628
 
    initialized in simplify_joins().
629
 
  */
630
 
 
631
 
  /*
632
 
    2. Walk through subquery's top list and set 'embedding' to point to the
633
 
       sj-nest.
634
 
  */
635
 
  Select_Lex *subq_lex= subq_pred->unit->first_select();
636
 
  nested_join->join_list.empty();
637
 
  List_iterator_fast<TableList> li(subq_lex->top_join_list);
638
 
  TableList *tl, *last_leaf;
639
 
  while ((tl= li++))
640
 
  {
641
 
    tl->embedding= sj_nest;
642
 
    tl->join_list= &nested_join->join_list;
643
 
    nested_join->join_list.push_back(tl);
644
 
  }
645
 
 
646
 
  /*
647
 
    Reconnect the next_leaf chain.
648
 
    TODO: Do we have to put subquery's tables at the end of the chain?
649
 
          Inserting them at the beginning would be a bit faster.
650
 
    NOTE: We actually insert them at the front! That's because the order is
651
 
          reversed in this list.
652
 
  */
653
 
  for (tl= parent_lex->leaf_tables; tl->next_leaf; tl= tl->next_leaf) {};
654
 
  tl->next_leaf= subq_lex->leaf_tables;
655
 
  last_leaf= tl;
656
 
 
657
 
  /*
658
 
    Same as above for next_local chain
659
 
    (a theory: a next_local chain always starts with ::leaf_tables
660
 
     because view's tables are inserted after the view)
661
 
  */
662
 
  for (tl= parent_lex->leaf_tables; tl->next_local; tl= tl->next_local) {};
663
 
  tl->next_local= subq_lex->leaf_tables;
664
 
 
665
 
  /* A theory: no need to re-connect the next_global chain */
666
 
 
667
 
  /* 3. Remove the original subquery predicate from the WHERE/ON */
668
 
 
669
 
  // The subqueries were replaced for Item_int(1) earlier
670
 
  subq_pred->exec_method= Item_in_subselect::SEMI_JOIN; // for subsequent executions
671
 
  /*TODO: also reset the 'with_subselect' there. */
672
 
 
673
 
  /* n. Adjust the parent_join->tables counter */
674
 
  uint32_t table_no= parent_join->tables;
675
 
  /* n. Walk through child's tables and adjust table->map */
676
 
  for (tl= subq_lex->leaf_tables; tl; tl= tl->next_leaf, table_no++)
677
 
  {
678
 
    tl->table->tablenr= table_no;
679
 
    tl->table->map= ((table_map)1) << table_no;
680
 
    Select_Lex *old_sl= tl->select_lex;
681
 
    tl->select_lex= parent_join->select_lex;
682
 
    for(TableList *emb= tl->embedding; emb && emb->select_lex == old_sl; emb= emb->embedding)
683
 
      emb->select_lex= parent_join->select_lex;
684
 
  }
685
 
  parent_join->tables += subq_lex->join->tables;
686
 
 
687
 
  /*
688
 
    Put the subquery's WHERE into semi-join's sj_on_expr
689
 
    Add the subquery-induced equalities too.
690
 
  */
691
 
  Select_Lex *save_lex= session->lex->current_select;
692
 
  session->lex->current_select=subq_lex;
693
 
  if (!subq_pred->left_expr->fixed &&
694
 
       subq_pred->left_expr->fix_fields(session, &subq_pred->left_expr))
695
 
    return(true);
696
 
  session->lex->current_select=save_lex;
697
 
 
698
 
  sj_nest->nested_join->sj_corr_tables= subq_pred->used_tables();
699
 
  sj_nest->nested_join->sj_depends_on=  subq_pred->used_tables() |
700
 
                                        subq_pred->left_expr->used_tables();
701
 
  sj_nest->sj_on_expr= subq_lex->where;
702
 
 
703
 
  /*
704
 
    Create the IN-equalities and inject them into semi-join's ON expression.
705
 
    Additionally, for InsideOut strategy
706
 
     - Record the number of IN-equalities.
707
 
     - Create list of pointers to (oe1, ..., ieN). We'll need the list to
708
 
       see which of the expressions are bound and which are not (for those
709
 
       we'll produce a distinct stream of (ie_i1,...ie_ik).
710
 
 
711
 
       (TODO: can we just create a list of pointers and hope the expressions
712
 
       will not substitute themselves on fix_fields()? or we need to wrap
713
 
       them into Item_direct_view_refs and store pointers to those. The
714
 
       pointers to Item_direct_view_refs are guaranteed to be stable as
715
 
       Item_direct_view_refs doesn't substitute itself with anything in
716
 
       Item_direct_view_ref::fix_fields.
717
 
  */
718
 
  sj_nest->sj_in_exprs= subq_pred->left_expr->cols();
719
 
  sj_nest->nested_join->sj_outer_expr_list.empty();
720
 
 
721
 
  if (subq_pred->left_expr->cols() == 1)
722
 
  {
723
 
    nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr);
724
 
 
725
 
    Item *item_eq= new Item_func_eq(subq_pred->left_expr,
726
 
                                    subq_lex->ref_pointer_array[0]);
727
 
    item_eq->name= (char*)subq_sj_cond_name;
728
 
    sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq);
729
 
  }
730
 
  else
731
 
  {
732
 
    for (uint32_t i= 0; i < subq_pred->left_expr->cols(); i++)
733
 
    {
734
 
      nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr->
735
 
                                                element_index(i));
736
 
      Item *item_eq=
737
 
        new Item_func_eq(subq_pred->left_expr->element_index(i),
738
 
                         subq_lex->ref_pointer_array[i]);
739
 
      item_eq->name= (char*)subq_sj_cond_name + (i % 64);
740
 
      sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq);
741
 
    }
742
 
  }
743
 
  /* Fix the created equality and AND */
744
 
  sj_nest->sj_on_expr->fix_fields(parent_join->session, &sj_nest->sj_on_expr);
745
 
 
746
 
  /*
747
 
    Walk through sj nest's WHERE and ON expressions and call
748
 
    item->fix_table_changes() for all items.
749
 
  */
750
 
  sj_nest->sj_on_expr->fix_after_pullout(parent_lex, &sj_nest->sj_on_expr);
751
 
  fix_list_after_tbl_changes(parent_lex, &sj_nest->nested_join->join_list);
752
 
 
753
 
 
754
 
  /* Unlink the child select_lex so it doesn't show up in EXPLAIN: */
755
 
  subq_lex->master_unit()->exclude_level();
756
 
 
757
 
  /* Inject sj_on_expr into the parent's WHERE or ON */
758
 
  if (emb_tbl_nest)
759
 
  {
760
 
    emb_tbl_nest->on_expr= and_items(emb_tbl_nest->on_expr,
761
 
                                     sj_nest->sj_on_expr);
762
 
    emb_tbl_nest->on_expr->fix_fields(parent_join->session, &emb_tbl_nest->on_expr);
763
 
  }
764
 
  else
765
 
  {
766
 
    /* Inject into the WHERE */
767
 
    parent_join->conds= and_items(parent_join->conds, sj_nest->sj_on_expr);
768
 
    parent_join->conds->fix_fields(parent_join->session, &parent_join->conds);
769
 
    parent_join->select_lex->where= parent_join->conds;
770
 
  }
771
 
 
772
 
  return(false);
773
 
}
774
 
 
775
 
/*
776
 
  Check if table's KeyUse elements have an eq_ref(outer_tables) candidate
777
 
 
778
 
  SYNOPSIS
779
 
    find_eq_ref_candidate()
780
 
      table             Table to be checked
781
 
      sj_inner_tables   Bitmap of inner tables. eq_ref(inner_table) doesn't
782
 
                        count.
783
 
 
784
 
  DESCRIPTION
785
 
    Check if table's KeyUse elements have an eq_ref(outer_tables) candidate
786
 
 
787
 
  TODO
788
 
    Check again if it is feasible to factor common parts with constant table
789
 
    search
790
 
 
791
 
  RETURN
792
 
    true  - There exists an eq_ref(outer-tables) candidate
793
 
    false - Otherwise
794
 
*/
795
 
bool find_eq_ref_candidate(Table *table, table_map sj_inner_tables)
796
 
{
797
 
  KeyUse *keyuse= table->reginfo.join_tab->keyuse;
798
 
  uint32_t key;
799
 
 
800
 
  if (keyuse)
801
 
  {
802
 
    while (1) /* For each key */
803
 
    {
804
 
      key= keyuse->key;
805
 
      KEY *keyinfo= table->key_info + key;
806
 
      key_part_map bound_parts= 0;
807
 
      if ((keyinfo->flags & HA_NOSAME) == HA_NOSAME)
808
 
      {
809
 
        do  /* For all equalities on all key parts */
810
 
        {
811
 
          /* Check if this is "t.keypart = expr(outer_tables) */
812
 
          if (!(keyuse->used_tables & sj_inner_tables) &&
813
 
              !(keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL))
814
 
          {
815
 
            bound_parts |= 1 << keyuse->keypart;
816
 
          }
817
 
          keyuse++;
818
 
        } while (keyuse->key == key && keyuse->table == table);
819
 
 
820
 
        if (bound_parts == PREV_BITS(uint, keyinfo->key_parts))
821
 
          return true;
822
 
        if (keyuse->table != table)
823
 
          return false;
824
 
      }
825
 
      else
826
 
      {
827
 
        do
828
 
        {
829
 
          keyuse++;
830
 
          if (keyuse->table != table)
831
 
            return false;
832
 
        }
833
 
        while (keyuse->key == key);
834
 
      }
835
 
    }
836
 
  }
837
 
  return false;
838
 
}
839
 
 
840
454
/*****************************************************************************
841
455
  Create JoinTableS, make a guess about the table types,
842
456
  Approximate how many records will be used in each table
1166
780
                                  ((*value)->type() == Item::FIELD_ITEM) &&
1167
781
                                  ((Item_field*)*value)->field->maybe_null());
1168
782
  (*key_fields)->cond_guard= NULL;
1169
 
  (*key_fields)->sj_pred_no= (cond->name >= subq_sj_cond_name &&
1170
 
                              cond->name < subq_sj_cond_name + 64)?
1171
 
                              cond->name - subq_sj_cond_name: UINT_MAX;
1172
783
  (*key_fields)++;
1173
784
}
1174
785
 
1461
1072
          keyuse.keypart_map= (key_part_map) 1 << part;
1462
1073
          keyuse.used_tables=key_field->val->used_tables();
1463
1074
          keyuse.optimize= key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL;
1464
 
                keyuse.null_rejecting= key_field->null_rejecting;
1465
 
                keyuse.cond_guard= key_field->cond_guard;
1466
 
                keyuse.sj_pred_no= key_field->sj_pred_no;
 
1075
          keyuse.null_rejecting= key_field->null_rejecting;
 
1076
          keyuse.cond_guard= key_field->cond_guard;
1467
1077
          insert_dynamic(keyuse_array,(unsigned char*) &keyuse);
1468
1078
        }
1469
1079
      }
1827
1437
    join_tab->const_keys|= possible_keys;
1828
1438
}
1829
1439
 
1830
 
/*****************************************************************************
1831
 
  Go through all combinations of not marked tables and find the one
1832
 
  which uses least records
1833
 
*****************************************************************************/
1834
 
 
1835
 
/*
1836
 
  Given a semi-join nest, find out which of the IN-equalities are bound
1837
 
 
1838
 
  SYNOPSIS
1839
 
    get_bound_sj_equalities()
1840
 
      sj_nest           Semi-join nest
1841
 
      remaining_tables  Tables that are not yet bound
1842
 
 
1843
 
  DESCRIPTION
1844
 
    Given a semi-join nest, find out which of the IN-equalities have their
1845
 
    left part expression bound (i.e. the said expression doesn't refer to
1846
 
    any of remaining_tables and can be evaluated).
1847
 
 
1848
 
  RETURN
1849
 
    Bitmap of bound IN-equalities.
1850
 
*/
1851
 
uint64_t get_bound_sj_equalities(TableList *sj_nest, table_map remaining_tables)
1852
 
{
1853
 
  List_iterator<Item> li(sj_nest->nested_join->sj_outer_expr_list);
1854
 
  Item *item;
1855
 
  uint32_t i= 0;
1856
 
  uint64_t res= 0;
1857
 
  while ((item= li++))
1858
 
  {
1859
 
    /*
1860
 
      Q: should this take into account equality propagation and how?
1861
 
      A: If e->outer_side is an Item_field, walk over the equality
1862
 
         class and see if there is an element that is bound?
1863
 
      (this is an optional feature)
1864
 
    */
1865
 
    if (!(item->used_tables() & remaining_tables))
1866
 
    {
1867
 
      res |= 1UL < i;
1868
 
    }
1869
 
  }
1870
 
  return res;
1871
 
}
1872
 
 
1873
1440
/**
1874
1441
  Compare two JoinTable objects based on the number of accessed records.
1875
1442
 
4039
3606
  return false;
4040
3607
}
4041
3608
 
4042
 
void advance_sj_state(const table_map remaining_tables, const JoinTable *tab)
4043
 
{
4044
 
  TableList *emb_sj_nest;
4045
 
  if ((emb_sj_nest= tab->emb_sj_nest))
4046
 
  {
4047
 
    tab->join->cur_emb_sj_nests |= emb_sj_nest->sj_inner_tables;
4048
 
    /* Remove the sj_nest if all of its SJ-inner tables are in cur_table_map */
4049
 
    if (!(remaining_tables & emb_sj_nest->sj_inner_tables))
4050
 
      tab->join->cur_emb_sj_nests &= ~emb_sj_nest->sj_inner_tables;
4051
 
  }
4052
 
}
4053
 
 
4054
 
/*
4055
 
  we assume remaining_tables doesnt contain @tab.
4056
 
*/
4057
 
void restore_prev_sj_state(const table_map remaining_tables, const JoinTable *tab)
4058
 
{
4059
 
  TableList *emb_sj_nest;
4060
 
  if ((emb_sj_nest= tab->emb_sj_nest))
4061
 
  {
4062
 
    /* If we're removing the last SJ-inner table, remove the sj-nest */
4063
 
    if ((remaining_tables & emb_sj_nest->sj_inner_tables) ==
4064
 
        (emb_sj_nest->sj_inner_tables & ~tab->table->map))
4065
 
    {
4066
 
      tab->join->cur_emb_sj_nests &= ~emb_sj_nest->sj_inner_tables;
4067
 
    }
4068
 
  }
4069
 
}
4070
 
 
4071
3609
COND *optimize_cond(JOIN *join, COND *conds, List<TableList> *join_list, Item::cond_result *cond_value)
4072
3610
{
4073
3611
  Session *session= join->session;
4700
4238
  enum_nested_loop_state rc;
4701
4239
  READ_RECORD *info= &join_tab->read_record;
4702
4240
 
4703
 
  if (join_tab->flush_weedout_table)
4704
 
  {
4705
 
    join_tab->flush_weedout_table->reset();
4706
 
  }
4707
 
 
4708
4241
  if (join->resume_nested_loop)
4709
4242
  {
4710
4243
    /* If not the last table, plunge down the nested loop */
8102
7635
        if (table->reginfo.not_exists_optimize)
8103
7636
          extra.append(STRING_WITH_LEN("; Not exists"));
8104
7637
 
8105
 
        if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE &&
8106
 
            !(((QUICK_RANGE_SELECT*)(tab->select->quick))->mrr_flags &
8107
 
             HA_MRR_USE_DEFAULT_IMPL))
8108
 
        {
8109
 
          extra.append(STRING_WITH_LEN("; Using MRR"));
8110
 
        }
8111
 
 
8112
7638
        if (table_list->schema_table &&
8113
7639
            table_list->schema_table->getRequestedObject() & OPTIMIZE_I_S_TABLE)
8114
7640
        {
8145
7671
          extra.append(STRING_WITH_LEN("; LooseScan"));
8146
7672
        }
8147
7673
 
8148
 
        if (tab->flush_weedout_table)
8149
 
          extra.append(STRING_WITH_LEN("; Start temporary"));
8150
 
        else if (tab->check_weed_out_table)
8151
 
          extra.append(STRING_WITH_LEN("; End temporary"));
8152
 
        else if (tab->do_firstmatch)
8153
 
        {
8154
 
          extra.append(STRING_WITH_LEN("; FirstMatch("));
8155
 
          Table *prev_table=tab->do_firstmatch->table;
8156
 
          if (prev_table->derived_select_number)
8157
 
          {
8158
 
            char namebuf[NAME_LEN];
8159
 
            /* Derived table name generation */
8160
 
            int len= snprintf(namebuf, sizeof(namebuf)-1,
8161
 
                              "<derived%u>",
8162
 
                              prev_table->derived_select_number);
8163
 
            extra.append(namebuf, len);
8164
 
          }
8165
 
          else
8166
 
            extra.append(prev_table->pos_in_table_list->alias);
8167
 
          extra.append(STRING_WITH_LEN(")"));
8168
 
        }
8169
 
 
8170
7674
        for (uint32_t part= 0; part < tab->ref.key_parts; part++)
8171
7675
        {
8172
7676
          if (tab->ref.cond_guards[part])
8275
7779
    }
8276
7780
    else if (curr->straight)
8277
7781
      str->append(STRING_WITH_LEN(" straight_join "));
8278
 
    else if (curr->sj_inner_tables)
8279
 
      str->append(STRING_WITH_LEN(" semi join "));
8280
7782
    else
8281
7783
      str->append(STRING_WITH_LEN(" join "));
8282
7784
    curr->print(session, str, QT_ORDINARY);
8308
7810
 
8309
7811
  for (TableList **t= table + (tables->elements - 1); t >= table; t--)
8310
7812
    *t= ti++;
8311
 
 
8312
 
  /*
8313
 
    If the first table is a semi-join nest, swap it with something that is
8314
 
    not a semi-join nest.
8315
 
  */
8316
 
  if ((*table)->sj_inner_tables)
8317
 
  {
8318
 
    TableList **end= table + tables->elements;
8319
 
    for (TableList **t2= table; t2!=end; t2++)
8320
 
    {
8321
 
      if (!(*t2)->sj_inner_tables)
8322
 
      {
8323
 
        TableList *tmp= *t2;
8324
 
        *t2= *table;
8325
 
        *table= tmp;
8326
 
        break;
8327
 
      }
8328
 
    }
8329
 
  }
8330
7813
  assert(tables->elements >= 1);
8331
7814
  print_table_array(session, str, table, table + tables->elements);
8332
7815
}