Commit message: MDEV-28094 Window function in expression in ORDER BY

call item->split_sum_func() in setup_order() just as
it's done in setup_fields()
CVE: CVE-2022-27451
CWE: NVD-CWE-noinfo
Vulnerability description: MariaDB Server v10.9 and below was discovered to contain a segmentation fault via the component sql/field_conv.cc.

Project: server

Field *Item_default_value::create_tmp_field_ex(TABLE *table,
                                                Tmp_field_src *src,
                                                const Tmp_field_param *param)
{
  if (field->default_value && (field->flags & BLOB_FLAG))
  {
    /*
      We have to use a copy function when using a blob with default value
      as the we have to calculate the default value before we can use it.
    */
     get_tmp_field_src(src, param);
     return tmp_table_field_from_field_type(table);
  }
  /*
    Same code as in Item_field::create_tmp_field_ex, except no default field
    handling
  */
  src->set_field(field);
  return create_tmp_field_from_item_field(table, NULL, param);
}

Project: server

Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels,
                           Item_equal *item_equal)
{
  List<Item> eq_list;
  Item_func_eq *eq_item= 0;
  if (((Item *) item_equal)->const_item() && !item_equal->val_int())
    return new (thd->mem_root) Item_bool(thd, false);
  Item *item_const= item_equal->get_const();
  Item_equal_fields_iterator it(*item_equal);
  Item *head;
  TABLE_LIST *current_sjm= NULL;
  Item *current_sjm_head= NULL;

  DBUG_ASSERT(!cond ||
              cond->is_bool_literal() ||
              (cond->type() == Item::FUNC_ITEM &&
               ((Item_func *) cond)->functype() == Item_func::EQ_FUNC) ||  
              (cond->type() == Item::COND_ITEM  && 
               ((Item_func *) cond)->functype() == Item_func::COND_AND_FUNC));

  /* 
    Pick the "head" item: the constant one or the first in the join order
    (if the first in the join order happends to be inside an SJM nest, that's
    ok, because this is where the value will be unpacked after
    materialization).
  */
  if (item_const)
    head= item_const;
  else
  {
    TABLE_LIST *emb_nest;
    head= item_equal->get_first(NO_PARTICULAR_TAB, NULL);
    it++;
    if ((emb_nest= embedding_sjm(head)))
    {
      current_sjm= emb_nest;
      current_sjm_head= head;
    }
  }

  Item *field_item;
  /*
    For each other item, generate "item=head" equality (except the tables that 
    are within SJ-Materialization nests, for those "head" is defined
    differently)
  */
  while ((field_item= it++))
  {
    Item_equal *upper= field_item->find_item_equal(upper_levels);
    Item *item= field_item;
    TABLE_LIST *field_sjm= embedding_sjm(field_item);
    if (!field_sjm)
    { 
      current_sjm= NULL;
      current_sjm_head= NULL;
    }      

    /* 
      Check if "field_item=head" equality is already guaranteed to be true 
      on upper AND-levels.
    */
    if (upper)
    {
      TABLE_LIST *native_sjm= embedding_sjm(item_equal->context_field);
      Item *upper_const= upper->get_const();
      if (item_const && upper_const)
      {
        /* 
          Upper item also has "field_item=const".
          Don't produce equality if const is equal to item_const.
        */
        Item_func_eq *func= new (thd->mem_root) Item_func_eq(thd, item_const, upper_const);
        func->set_cmp_func();
        func->quick_fix_field();
        if (func->val_int())
          item= 0;
      }
      else
      {
        Item_equal_fields_iterator li(*item_equal);
        while ((item= li++) != field_item)
        {
          if (embedding_sjm(item) == field_sjm && 
              item->find_item_equal(upper_levels) == upper)
            break;
        }
      }
      if (embedding_sjm(field_item) != native_sjm)
        item= NULL; /* Don't produce equality */
    }
    
    bool produce_equality= MY_TEST(item == field_item);
    if (!item_const && field_sjm && field_sjm != current_sjm)
    {
      /* Entering an SJM nest */
      current_sjm_head= field_item;
      if (!field_sjm->sj_mat_info->is_sj_scan)
        produce_equality= FALSE;
    }

    if (produce_equality)
    {
      if (eq_item && eq_list.push_back(eq_item, thd->mem_root))
        return 0;
      
      /*
        If we're inside an SJM-nest (current_sjm!=NULL), and the multi-equality
        doesn't include a constant, we should produce equality with the first
        of the equal items in this SJM (except for the first element inside the
        SJM. For that, we produce the equality with the "head" item).

        In other cases, get the "head" item, which is either first of the
        equals on top level, or the constant.
      */
      Item *head_item= (!item_const && current_sjm && 
                        current_sjm_head != field_item) ? current_sjm_head: head;
      eq_item= new (thd->mem_root) Item_func_eq(thd,
                                                field_item->remove_item_direct_ref(),
                                                head_item->remove_item_direct_ref());

      if (!eq_item || eq_item->set_cmp_func())
        return 0;
      eq_item->quick_fix_field();
    }
    current_sjm= field_sjm;
  }

  /*
    We have produced zero, one, or more pair-wise equalities eq_i. We want to
    return an expression in form:

      cond AND eq_1 AND eq_2 AND eq_3 AND ...
    
    'cond' is a parameter for this function, which may be NULL, an Item_bool(1),
    or an Item_func_eq or an Item_cond_and.

    We want to return a well-formed condition: no nested Item_cond_and objects,
    or Item_cond_and with a single child:
    - if 'cond' is an Item_cond_and, we add eq_i as its tail
    - if 'cond' is Item_bool(1), we return eq_i
    - otherwise, we create our own Item_cond_and and put 'cond' at the front of
      it.
    - if we have only one condition to return, we don't create an Item_cond_and
  */

  if (eq_item && eq_list.push_back(eq_item, thd->mem_root))
    return 0;
  COND *res= 0;
  switch (eq_list.elements)
  {
  case 0:
    res= cond ? cond : new (thd->mem_root) Item_bool(thd, true);
    break;
  case 1:
    if (!cond || cond->is_bool_literal())
      res= eq_item;
    break;
  default:
    break;
  }
  if (!res) 
  {
    if (cond)
    {
      if (cond->type() == Item::COND_ITEM)
      {
        res= cond;
        ((Item_cond *) res)->add_at_end(&eq_list);
      }
      else if (eq_list.push_front(cond, thd->mem_root))
        return 0;
    }
  }  
  if (!res)
    res= new (thd->mem_root) Item_cond_and(thd, eq_list);
  if (res)
  {
    res->quick_fix_field();
    res->update_used_tables();
  }

  return res;
}

Project: server

bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
                                 table_map prefix_tables, 
                                 bool distinct_arg, JOIN_TAB *first_top_tab)
{
  int quick_type;
  CHARSET_INFO *cs= system_charset_info;
  THD *thd=      join->thd;
  TABLE_LIST *table_list= table->pos_in_table_list;
  QUICK_SELECT_I *cur_quick= NULL;
  my_bool key_read;
  char table_name_buffer[SAFE_NAME_LEN];
  KEY *key_info= 0;
  uint key_len= 0;
  quick_type= -1;

  explain_plan= eta;
  eta->key.clear();
  eta->quick_info= NULL;

  SQL_SELECT *tab_select;
  /* 
    We assume that if this table does pre-sorting, then it doesn't do filtering
    with SQL_SELECT.
  */
  DBUG_ASSERT(!(select && filesort));
  tab_select= (filesort)? filesort->select : select;

  if (filesort)
  {
    if (!(eta->pre_join_sort=
          new (thd->mem_root) Explain_aggr_filesort(thd->mem_root,
                                                    thd->lex->analyze_stmt,
                                                    filesort)))
      return 1;
  }
  // psergey-todo: data for filtering!
  tracker= &eta->tracker;
  jbuf_tracker= &eta->jbuf_tracker;

  /* Enable the table access time tracker only for "ANALYZE stmt" */
  if (thd->lex->analyze_stmt)
    table->file->set_time_tracker(&eta->op_tracker);

  /* No need to save id and select_type here, they are kept in Explain_select */

  /* table */
  if (table->derived_select_number)
  {
    /* Derived table name generation */
    size_t len= my_snprintf(table_name_buffer, sizeof(table_name_buffer)-1,
                         "<derived%u>",
                         table->derived_select_number);
    eta->table_name.copy(table_name_buffer, len, cs);
  }
  else if (bush_children)
  {
    JOIN_TAB *ctab= bush_children->start;
    /* table */
    size_t len= my_snprintf(table_name_buffer,
                         sizeof(table_name_buffer)-1,
                         "<subquery%d>", 
                         ctab->emb_sj_nest->sj_subq_pred->get_identifier());
    eta->table_name.copy(table_name_buffer, len, cs);
  }
  else
  {
    TABLE_LIST *real_table= table->pos_in_table_list;
    /*
      When multi-table UPDATE/DELETE does updates/deletes to a VIEW, the view
      is merged in a certain particular way (grep for DT_MERGE_FOR_INSERT).

      As a result, view's underlying tables have $tbl->pos_in_table_list={view}.
      We don't want to print view name in EXPLAIN, we want underlying table's
      alias (like specified in the view definition).
    */
    if (real_table->merged_for_insert)
    {
      TABLE_LIST *view_child=
        real_table->view->first_select_lex()->table_list.first;
      for (;view_child; view_child= view_child->next_local)
      {
        if (view_child->table == table)
        {
          real_table= view_child;
          break;
        }
      }
    }
    eta->table_name.copy(real_table->alias.str, real_table->alias.length, cs);
  }

  /* "partitions" column */
  {
#ifdef WITH_PARTITION_STORAGE_ENGINE
    partition_info *part_info;
    if (!table->derived_select_number && 
        (part_info= table->part_info))
    { //TODO: all thd->mem_root here should be fixed
      make_used_partitions_str(thd->mem_root, part_info, &eta->used_partitions,
                               eta->used_partitions_list);
      eta->used_partitions_set= true;
    }
    else
      eta->used_partitions_set= false;
#else
    /* just produce empty column if partitioning is not compiled in */
    eta->used_partitions_set= false;
#endif
  }

  /* "type" column */
  enum join_type tab_type= type;
  if ((type == JT_ALL || type == JT_HASH) &&
       tab_select && tab_select->quick && use_quick != 2)
  {
    cur_quick= tab_select->quick;
    quick_type= cur_quick->get_type();
    if ((quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) ||
        (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT) ||
        (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) ||
        (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION))
      tab_type= type == JT_ALL ? JT_INDEX_MERGE : JT_HASH_INDEX_MERGE;
    else
      tab_type= type == JT_ALL ? JT_RANGE : JT_HASH_RANGE;
  }
  eta->type= tab_type;

  /* Build "possible_keys" value */
  // psergey-todo: why does this use thd MEM_ROOT??? Doesn't this 
  // break ANALYZE ? thd->mem_root will be freed, and after that we will
  // attempt to print the query plan?
  if (append_possible_keys(thd->mem_root, eta->possible_keys, table, keys))
    return 1;
  // psergey-todo: ^ check for error return code 

  /* Build "key", "key_len", and "ref" */

  if (rowid_filter)
  {
    Range_rowid_filter *range_filter= (Range_rowid_filter *) rowid_filter;
    QUICK_SELECT_I *quick= range_filter->get_select()->quick;

    Explain_rowid_filter *erf= new (thd->mem_root) Explain_rowid_filter;
    erf->quick= quick->get_explain(thd->mem_root);
    erf->selectivity= range_rowid_filter_info->selectivity;
    erf->rows= quick->records;
    if (!(erf->tracker= new Rowid_filter_tracker(thd->lex->analyze_stmt)))
      return 1;
    rowid_filter->set_tracker(erf->tracker);
    eta->rowid_filter= erf;
  }

  if (tab_type == JT_NEXT)
  {
    key_info= table->key_info+index;
    key_len= key_info->key_length;
  }
  else if (ref.key_parts)
  {
    key_info= get_keyinfo_by_key_no(ref.key);
    key_len= ref.key_length;
  }
  
  /*
    In STRAIGHT_JOIN queries, there can be join tabs with JT_CONST type
    that still have quick selects.
  */
  if (tab_select && tab_select->quick && tab_type != JT_CONST)
  {
    if (!(eta->quick_info= tab_select->quick->get_explain(thd->mem_root)))
      return 1;
  }

  if (key_info) /* 'index' or 'ref' access */
  {
    eta->key.set(thd->mem_root, key_info, key_len);

    if (ref.key_parts && tab_type != JT_FT)
    {
      store_key **key_ref= ref.key_copy;
      for (uint kp= 0; kp < ref.key_parts; kp++)
      {
        if ((key_part_map(1) << kp) & ref.const_ref_part_map)
        {
          if (!(eta->ref_list.append_str(thd->mem_root, "const")))
            return 1;
          /*
            create_ref_for_key() handles keypart=const equalities as follows:
              - non-EXPLAIN execution will copy the "const" to lookup tuple
                immediately and will not add an element to ref.key_copy
              - EXPLAIN will put an element into ref.key_copy. Since we've
                just printed "const" for it, we should skip it here
          */
          if (thd->lex->describe)
            key_ref++;
        }
        else
        {
          if (!(eta->ref_list.append_str(thd->mem_root, (*key_ref)->name())))
            return 1;
          key_ref++;
        }
      }
    }
  }

  if (tab_type == JT_HASH_NEXT) /* full index scan + hash join */
  {
    eta->hash_next_key.set(thd->mem_root, 
                           & table->key_info[index], 
                           table->key_info[index].key_length);
    // psergey-todo: ^ is the above correct? are we necessarily joining on all
    // columns?
  }

  if (!key_info)
  {
    if (table_list && /* SJM bushes don't have table_list */
        table_list->schema_table &&
        table_list->schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE)
    {
      IS_table_read_plan *is_table_read_plan= table_list->is_table_read_plan;
      const char *tmp_buff;
      int f_idx;
      StringBuffer<64> key_name_buf;
      if (is_table_read_plan->trivial_show_command ||
          is_table_read_plan->has_db_lookup_value())
      {
        /* The "key" has the name of the column referring to the database */
        f_idx= table_list->schema_table->idx_field1;
        tmp_buff= table_list->schema_table->fields_info[f_idx].field_name;
        key_name_buf.append(tmp_buff, strlen(tmp_buff), cs);
      }          
      if (is_table_read_plan->trivial_show_command ||
          is_table_read_plan->has_table_lookup_value())
      {
        if (is_table_read_plan->trivial_show_command ||
            is_table_read_plan->has_db_lookup_value())
          key_name_buf.append(',');

        f_idx= table_list->schema_table->idx_field2;
        tmp_buff= table_list->schema_table->fields_info[f_idx].field_name;
        key_name_buf.append(tmp_buff, strlen(tmp_buff), cs);
      }

      if (key_name_buf.length())
        eta->key.set_pseudo_key(thd->mem_root, key_name_buf.c_ptr_safe());
    }
  }
  
  /* "rows" */
  if (table_list /* SJM bushes don't have table_list */ &&
      table_list->schema_table)
  {
    /* I_S tables have rows=extra=NULL */
    eta->rows_set= false;
    eta->filtered_set= false;
  }
  else
  {
    ha_rows examined_rows= get_examined_rows();

    eta->rows_set= true;
    eta->rows= examined_rows;

    /* "filtered"  */
    float f= 0.0; 
    if (examined_rows)
    {
      double pushdown_cond_selectivity= cond_selectivity;
      if (pushdown_cond_selectivity == 1.0)
        f= (float) (100.0 * records_read / examined_rows);
      else
        f= (float) (100.0 * pushdown_cond_selectivity);
    }
    set_if_smaller(f, 100.0);
    eta->filtered_set= true;
    eta->filtered= f;
  }

  /* Build "Extra" field and save it */
  key_read= table->file->keyread_enabled();
  if ((tab_type == JT_NEXT || tab_type == JT_CONST) &&
      table->covering_keys.is_set(index))
    key_read=1;
  if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT &&
      !((QUICK_ROR_INTERSECT_SELECT*)cur_quick)->need_to_fetch_row)
    key_read=1;
    
  if (info)
  {
    eta->push_extra(info);
  }
  else if (packed_info & TAB_INFO_HAVE_VALUE)
  {
    if (packed_info & TAB_INFO_USING_INDEX)
      eta->push_extra(ET_USING_INDEX);
    if (packed_info & TAB_INFO_USING_WHERE)
      eta->push_extra(ET_USING_WHERE);
    if (packed_info & TAB_INFO_FULL_SCAN_ON_NULL)
      eta->push_extra(ET_FULL_SCAN_ON_NULL_KEY);
  }
  else
  {
    uint keyno= MAX_KEY;
    if (ref.key_parts)
      keyno= ref.key;
    else if (tab_select && cur_quick)
      keyno = cur_quick->index;

    if (keyno != MAX_KEY && keyno == table->file->pushed_idx_cond_keyno &&
        table->file->pushed_idx_cond)
    {
      eta->push_extra(ET_USING_INDEX_CONDITION);
      eta->pushed_index_cond= table->file->pushed_idx_cond;
    }
    else if (cache_idx_cond)
    {
      eta->push_extra(ET_USING_INDEX_CONDITION_BKA);
      eta->pushed_index_cond= cache_idx_cond;
    }

    if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION || 
        quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT ||
        quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
        quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
    {
      eta->push_extra(ET_USING);
    }
    if (tab_select)
    {
      if (use_quick == 2)
      {
        eta->push_extra(ET_RANGE_CHECKED_FOR_EACH_RECORD);
        eta->range_checked_fer= new (thd->mem_root) Explain_range_checked_fer;
        if (eta->range_checked_fer)
          eta->range_checked_fer->
            append_possible_keys_stat(thd->mem_root, table, keys);
      }
      else if (tab_select->cond ||
               (cache_select && cache_select->cond))
      {
        const COND *pushed_cond= table->file->pushed_cond;

        if ((table->file->ha_table_flags() &
              HA_CAN_TABLE_CONDITION_PUSHDOWN) &&
            pushed_cond)
        {
          eta->push_extra(ET_USING_WHERE_WITH_PUSHED_CONDITION);
        }
        else
        {
          eta->where_cond= tab_select->cond;
          eta->cache_cond= cache_select? cache_select->cond : NULL;
          eta->push_extra(ET_USING_WHERE);
        }
      }
    }
    if (table_list /* SJM bushes don't have table_list */ &&
        table_list->schema_table &&
        table_list->schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE)
    {
      if (!table_list->table_open_method)
        eta->push_extra(ET_SKIP_OPEN_TABLE);
      else if (table_list->table_open_method == OPEN_FRM_ONLY)
        eta->push_extra(ET_OPEN_FRM_ONLY);
      else
        eta->push_extra(ET_OPEN_FULL_TABLE);
      /* psergey-note: the following has a bug.*/
      if (table_list->is_table_read_plan->trivial_show_command ||
          (table_list->is_table_read_plan->has_db_lookup_value() &&
           table_list->is_table_read_plan->has_table_lookup_value()))
        eta->push_extra(ET_SCANNED_0_DATABASES);
      else if (table_list->is_table_read_plan->has_db_lookup_value() ||
               table_list->is_table_read_plan->has_table_lookup_value())
        eta->push_extra(ET_SCANNED_1_DATABASE);
      else
        eta->push_extra(ET_SCANNED_ALL_DATABASES);
    }
    if (key_read)
    {
      if (quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
      {
        QUICK_GROUP_MIN_MAX_SELECT *qgs= 
          (QUICK_GROUP_MIN_MAX_SELECT *) tab_select->quick;
        eta->push_extra(ET_USING_INDEX_FOR_GROUP_BY);
        eta->loose_scan_is_scanning= qgs->loose_scan_is_scanning();
      }
      else
        eta->push_extra(ET_USING_INDEX);
    }
    if (table->reginfo.not_exists_optimize)
      eta->push_extra(ET_NOT_EXISTS);

    if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE)
    {
      explain_append_mrr_info((QUICK_RANGE_SELECT*)(tab_select->quick),
                              &eta->mrr_type);
      if (eta->mrr_type.length() > 0)
        eta->push_extra(ET_USING_MRR);
    }

    if (shortcut_for_distinct)
      eta->push_extra(ET_DISTINCT);

    if (loosescan_match_tab)
    {
      eta->push_extra(ET_LOOSESCAN);
    }

    if (first_weedout_table)
    {
      eta->start_dups_weedout= true;
      eta->push_extra(ET_START_TEMPORARY);
    }
    if (check_weed_out_table)
    {
      eta->push_extra(ET_END_TEMPORARY);
      eta->end_dups_weedout= true;
    }

    else if (do_firstmatch)
    {
      if (do_firstmatch == /*join->join_tab*/ first_top_tab - 1)
        eta->push_extra(ET_FIRST_MATCH);
      else
      {
        eta->push_extra(ET_FIRST_MATCH);
        TABLE *prev_table=do_firstmatch->table;
        if (prev_table->derived_select_number)
        {
          char namebuf[NAME_LEN];
          /* Derived table name generation */
          size_t len= my_snprintf(namebuf, sizeof(namebuf)-1,
                               "<derived%u>",
                               prev_table->derived_select_number);
          eta->firstmatch_table_name.append(namebuf, len);
        }
        else
          eta->firstmatch_table_name.append(&prev_table->pos_in_table_list->alias);
      }
    }

    for (uint part= 0; part < ref.key_parts; part++)
    {
      if (ref.cond_guards[part])
      {
        eta->push_extra(ET_FULL_SCAN_ON_NULL_KEY);
        eta->full_scan_on_null_key= true;
        break;
      }
    }

    if (cache)
    {
      eta->push_extra(ET_USING_JOIN_BUFFER);
      if (cache->save_explain_data(&eta->bka_type))
        return 1;
    }
  }

  /* 
    In case this is a derived table, here we remember the number of 
    subselect that used to produce it.
  */
  if (!(table_list && table_list->is_with_table_recursive_reference()))
    eta->derived_select_number= table->derived_select_number;

  /* The same for non-merged semi-joins */
  eta->non_merged_sjm_number = get_non_merged_semijoin_select();

  return 0;
}

Project: server

COND *Item_cond_and::build_equal_items(THD *thd,
                                       COND_EQUAL *inherited,
                                       bool link_item_fields,
                                       COND_EQUAL **cond_equal_ref)
{
  Item_equal *item_equal;
  COND_EQUAL cond_equal;
  cond_equal.upper_levels= inherited;

  if (check_stack_overrun(thd, STACK_MIN_SIZE, NULL))
    return this;                          // Fatal error flag is set!

  List<Item> eq_list;
  List<Item> *cond_args= argument_list();

  List_iterator<Item> li(*cond_args);
  Item *item;

  DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]);
  /*
     Retrieve all conjuncts of this level detecting the equality
     that are subject to substitution by multiple equality items and
     removing each such predicate from the conjunction after having 
     found/created a multiple equality whose inference the predicate is.
 */
  while ((item= li++))
  {
    /*
      PS/SP note: we can safely remove a node from AND-OR
      structure here because it's restored before each
      re-execution of any prepared statement/stored procedure.
    */
    if (item->check_equality(thd, &cond_equal, &eq_list))
      li.remove();
  }

  /*
    Check if we eliminated all the predicates of the level, e.g.
    (a=a AND b=b AND a=a).
  */
  if (!cond_args->elements && 
      !cond_equal.current_level.elements && 
      !eq_list.elements)
    return new (thd->mem_root) Item_bool(thd, true);

  List_iterator_fast<Item_equal> it(cond_equal.current_level);
  while ((item_equal= it++))
  {
    item_equal->set_link_equal_fields(link_item_fields);
    item_equal->fix_fields(thd, NULL);
    item_equal->update_used_tables();
    set_if_bigger(thd->lex->current_select->max_equal_elems,
                  item_equal->n_field_items());  
  }

  m_cond_equal.copy(cond_equal);
  cond_equal.current_level= m_cond_equal.current_level;
  inherited= &m_cond_equal;

  /*
     Make replacement of equality predicates for lower levels
     of the condition expression.
  */
  li.rewind();
  while ((item= li++))
  { 
    Item *new_item;
    if ((new_item= item->build_equal_items(thd, inherited, false, NULL))
        != item)
    {
      /* This replacement happens only for standalone equalities */
      /*
        This is ok with PS/SP as the replacement is done for
        cond_args of an AND/OR item, which are restored for each
        execution of PS/SP.
      */
      li.replace(new_item);
    }
  }
  cond_args->append(&eq_list);
  cond_args->append((List<Item> *)&cond_equal.current_level);
  update_used_tables();
  if (cond_equal_ref)
    *cond_equal_ref= &m_cond_equal;
  return this;
}

Project: server

test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
                         key_map usable_keys,  int ref_key,
                         ha_rows select_limit_arg,
                         int *new_key, int *new_key_direction,
                         ha_rows *new_select_limit, uint *new_used_key_parts,
                         uint *saved_best_key_parts)
{
  DBUG_ENTER("test_if_cheaper_ordering");
  /*
    Check whether there is an index compatible with the given order
    usage of which is cheaper than usage of the ref_key index (ref_key>=0)
    or a table scan.
    It may be the case if ORDER/GROUP BY is used with LIMIT.
  */
  ha_rows best_select_limit= HA_POS_ERROR;
  JOIN *join= tab ? tab->join : NULL;
  uint nr;
  key_map keys;
  uint best_key_parts= 0;
  int best_key_direction= 0;
  ha_rows best_records= 0;
  double read_time;
  int best_key= -1;
  bool is_best_covering= FALSE;
  double fanout= 1;
  ha_rows table_records= table->stat_records();
  bool group= join && join->group && order == join->group_list;
  ha_rows refkey_rows_estimate= table->quick_condition_rows;
  const bool has_limit= (select_limit_arg != HA_POS_ERROR);
  THD* thd= join ? join->thd : table->in_use;

  Json_writer_object trace_wrapper(thd);
  Json_writer_object trace_cheaper_ordering(
      thd, "reconsidering_access_paths_for_index_ordering");
  trace_cheaper_ordering.add("clause", group ? "GROUP BY" : "ORDER BY");

  /*
    If not used with LIMIT, only use keys if the whole query can be
    resolved with a key;  This is because filesort() is usually faster than
    retrieving all rows through an index.
  */
  if (select_limit_arg >= table_records)
  {
    keys= *table->file->keys_to_use_for_scanning();
    keys.merge(table->covering_keys);

    /*
      We are adding here also the index specified in FORCE INDEX clause, 
      if any.
      This is to allow users to use index in ORDER BY.
    */
    if (table->force_index) 
      keys.merge(group ? table->keys_in_use_for_group_by :
                         table->keys_in_use_for_order_by);
    keys.intersect(usable_keys);
  }
  else
    keys= usable_keys;

  if (join)
  {
    uint tablenr= (uint)(tab - join->join_tab);
    read_time= join->best_positions[tablenr].read_time;
    for (uint i= tablenr+1; i < join->table_count; i++)
    {
      fanout*= join->best_positions[i].records_read; // fanout is always >= 1
      // But selectivity is =< 1 :
      fanout*= join->best_positions[i].cond_selectivity;
    }
  }
  else
    read_time= table->file->scan_time();
  
  trace_cheaper_ordering.add("fanout", fanout);
  /*
    TODO: add cost of sorting here.
  */
  read_time += COST_EPS;
  trace_cheaper_ordering.add("read_time", read_time);
  /*
    Calculate the selectivity of the ref_key for REF_ACCESS. For
    RANGE_ACCESS we use table->quick_condition_rows.
  */
  if (ref_key >= 0 && ref_key != MAX_KEY && tab->type == JT_REF)
  {
    /*
      If ref access uses keypart=const for all its key parts,
      and quick select uses the same # of key parts, then they are equivalent.
      Reuse #rows estimate from quick select as it is more precise.
    */
    if (tab->ref.const_ref_part_map ==
        make_prev_keypart_map(tab->ref.key_parts) &&
        table->quick_keys.is_set(ref_key) &&
        table->quick_key_parts[ref_key] == tab->ref.key_parts)
      refkey_rows_estimate= table->quick_rows[ref_key];
    else
    {
      const KEY *ref_keyinfo= table->key_info + ref_key;
      refkey_rows_estimate= ref_keyinfo->rec_per_key[tab->ref.key_parts - 1];
    }
    set_if_bigger(refkey_rows_estimate, 1);
  }

  if (tab)
    trace_cheaper_ordering.add_table_name(tab);
  else
    trace_cheaper_ordering.add_table_name(table);
  trace_cheaper_ordering.add("rows_estimation", refkey_rows_estimate);

  Json_writer_array possible_keys(thd,"possible_keys");
  for (nr=0; nr < table->s->keys ; nr++)
  {
    int direction;
    ha_rows select_limit= select_limit_arg;
    uint used_key_parts= 0;
    Json_writer_object possible_key(thd);
    possible_key.add("index", table->key_info[nr].name);

    if (keys.is_set(nr) &&
        (direction= test_if_order_by_key(join, order, table, nr,
                                         &used_key_parts)))
    {
      /*
        At this point we are sure that ref_key is a non-ordering
        key (where "ordering key" is a key that will return rows
        in the order required by ORDER BY).
      */
      DBUG_ASSERT (ref_key != (int) nr);

      possible_key.add("can_resolve_order", true);
      bool is_covering= (table->covering_keys.is_set(nr) ||
                         (table->file->index_flags(nr, 0, 1) &
                          HA_CLUSTERED_INDEX));
      /* 
        Don't use an index scan with ORDER BY without limit.
        For GROUP BY without limit always use index scan
        if there is a suitable index. 
        Why we hold to this asymmetry hardly can be explained
        rationally. It's easy to demonstrate that using
        temporary table + filesort could be cheaper for grouping
        queries too.
      */ 
      if (is_covering ||
          select_limit != HA_POS_ERROR || 
          (ref_key < 0 && (group || table->force_index)))
      { 
        double rec_per_key;
        double index_scan_time;
        KEY *keyinfo= table->key_info+nr;
        if (select_limit == HA_POS_ERROR)
          select_limit= table_records;
        if (group)
        {
          /* 
            Used_key_parts can be larger than keyinfo->user_defined_key_parts
            when using a secondary index clustered with a primary 
            key (e.g. as in Innodb). 
            See Bug #28591 for details.
          */  
          uint used_index_parts= keyinfo->user_defined_key_parts;
          uint used_pk_parts= 0;
          if (used_key_parts > used_index_parts)
            used_pk_parts= used_key_parts-used_index_parts;
          rec_per_key= used_key_parts ?
	               keyinfo->actual_rec_per_key(used_key_parts-1) : 1;
          /* Take into account the selectivity of the used pk prefix */
          if (used_pk_parts)
	  {
            KEY *pkinfo=tab->table->key_info+table->s->primary_key;
            /*
              If the values of of records per key for the prefixes
              of the primary key are considered unknown we assume
              they are equal to 1.
	    */
            if (used_key_parts == pkinfo->user_defined_key_parts ||
                pkinfo->rec_per_key[0] == 0)
              rec_per_key= 1;                 
            if (rec_per_key > 1)
	    {
              rec_per_key*= pkinfo->actual_rec_per_key(used_pk_parts-1);
              rec_per_key/= pkinfo->actual_rec_per_key(0);
              /* 
                The value of rec_per_key for the extended key has
                to be adjusted accordingly if some components of
                the secondary key are included in the primary key.
	      */
               for(uint i= 1; i < used_pk_parts; i++)
	      {
	        if (pkinfo->key_part[i].field->key_start.is_set(nr))
	        {
                  /* 
                    We presume here that for any index rec_per_key[i] != 0
                    if rec_per_key[0] != 0.
	          */
                  DBUG_ASSERT(pkinfo->actual_rec_per_key(i));
                  rec_per_key*= pkinfo->actual_rec_per_key(i-1);
                  rec_per_key/= pkinfo->actual_rec_per_key(i);
                }
	      }
            }    
          }
          set_if_bigger(rec_per_key, 1);
          /*
            With a grouping query each group containing on average
            rec_per_key records produces only one row that will
            be included into the result set.
          */  
          if (select_limit > table_records/rec_per_key)
            select_limit= table_records;
          else
            select_limit= (ha_rows) (select_limit*rec_per_key);
        } /* group */

        /* 
          If tab=tk is not the last joined table tn then to get first
          L records from the result set we can expect to retrieve
          only L/fanout(tk,tn) where fanout(tk,tn) says how many
          rows in the record set on average will match each row tk.
          Usually our estimates for fanouts are too pessimistic.
          So the estimate for L/fanout(tk,tn) will be too optimistic
          and as result we'll choose an index scan when using ref/range
          access + filesort will be cheaper.
        */
        select_limit= (ha_rows) (select_limit < fanout ?
                                 1 : select_limit/fanout);

        /*
          refkey_rows_estimate is E(#rows) produced by the table access
          strategy that was picked without regard to ORDER BY ... LIMIT.

          It will be used as the source of selectivity data.
          Use table->cond_selectivity as a better estimate which includes
          condition selectivity too.
        */
        {
          // we use MIN(...), because "Using LooseScan" queries have
          // cond_selectivity=1 while refkey_rows_estimate has a better
          // estimate.
          refkey_rows_estimate= MY_MIN(refkey_rows_estimate,
                                       ha_rows(table_records *
                                               table->cond_selectivity));
        }

        /*
          We assume that each of the tested indexes is not correlated
          with ref_key. Thus, to select first N records we have to scan
          N/selectivity(ref_key) index entries. 
          selectivity(ref_key) = #scanned_records/#table_records =
          refkey_rows_estimate/table_records.
          In any case we can't select more than #table_records.
          N/(refkey_rows_estimate/table_records) > table_records
          <=> N > refkey_rows_estimate.
         */

        if (select_limit > refkey_rows_estimate)
          select_limit= table_records;
        else
          select_limit= (ha_rows) (select_limit *
                                   (double) table_records /
                                    refkey_rows_estimate);
        possible_key.add("updated_limit", select_limit);
        rec_per_key= keyinfo->actual_rec_per_key(keyinfo->user_defined_key_parts-1);
        set_if_bigger(rec_per_key, 1);
        /*
          Here we take into account the fact that rows are
          accessed in sequences rec_per_key records in each.
          Rows in such a sequence are supposed to be ordered
          by rowid/primary key. When reading the data
          in a sequence we'll touch not more pages than the
          table file contains.
          TODO. Use the formula for a disk sweep sequential access
          to calculate the cost of accessing data rows for one 
          index entry.
        */
        index_scan_time= select_limit/rec_per_key *
                         MY_MIN(rec_per_key, table->file->scan_time());
        double range_scan_time;
        if (get_range_limit_read_cost(tab, table, table_records, nr,
                                      select_limit, &range_scan_time))
        {
          possible_key.add("range_scan_time", range_scan_time);
          if (range_scan_time < index_scan_time)
            index_scan_time= range_scan_time;
        }
        possible_key.add("index_scan_time", index_scan_time);

        if ((ref_key < 0 && (group || table->force_index || is_covering)) ||
            index_scan_time < read_time)
        {
          ha_rows quick_records= table_records;
          ha_rows refkey_select_limit= (ref_key >= 0 &&
                                        !is_hash_join_key_no(ref_key) &&
                                        table->covering_keys.is_set(ref_key)) ?
                                        refkey_rows_estimate :
                                        HA_POS_ERROR;
          if (is_best_covering && !is_covering)
          {
            possible_key.add("chosen", false);
            possible_key.add("cause", "covering index already found");
            continue;
          }

          if (is_covering && refkey_select_limit < select_limit)
          {
            possible_key.add("chosen", false);
            possible_key.add("cause", "ref estimates better");
            continue;
          }
          if (table->quick_keys.is_set(nr))
            quick_records= table->quick_rows[nr];
          possible_key.add("records", quick_records);
          if (best_key < 0 ||
              (select_limit <= MY_MIN(quick_records,best_records) ?
               keyinfo->user_defined_key_parts < best_key_parts :
               quick_records < best_records) ||
              (!is_best_covering && is_covering))
          {
            possible_key.add("chosen", true);
            best_key= nr;
            best_key_parts= keyinfo->user_defined_key_parts;
            if (saved_best_key_parts)
              *saved_best_key_parts= used_key_parts;
            best_records= quick_records;
            is_best_covering= is_covering;
            best_key_direction= direction; 
            best_select_limit= select_limit;
          }
          else
          {
            char const *cause;
            possible_key.add("chosen", false);
            if (is_covering)
              cause= "covering index already found";
            else
            {
              if (select_limit <= MY_MIN(quick_records,best_records))
                cause= "keyparts greater than the current best keyparts";
              else
                cause= "rows estimation greater";
            }
            possible_key.add("cause", cause);
          }
        }
        else
        {
          possible_key.add("usable", false);
          possible_key.add("cause", "cost");
        }
      }
      else
      {
        possible_key.add("usable", false);
        if (!group && select_limit == HA_POS_ERROR)
          possible_key.add("cause", "order by without limit");
      }
    }
    else
    {
      if (keys.is_set(nr))
      {
        possible_key.add("can_resolve_order", false);
        possible_key.add("cause", "order can not be resolved by key");
      }
      else
      {
        possible_key.add("can_resolve_order", false);
        possible_key.add("cause", "not usable index for the query");
      }
    }
  }

  if (best_key < 0 || best_key == ref_key)
    DBUG_RETURN(FALSE);
  
  *new_key= best_key;
  *new_key_direction= best_key_direction;
  *new_select_limit= has_limit ? best_select_limit : table_records;
  if (new_used_key_parts != NULL)
    *new_used_key_parts= best_key_parts;

  DBUG_RETURN(TRUE);
}

Project: server

propagate_cond_constants(THD *thd, I_List<COND_CMP> *save_list,
                         COND *and_father, COND *cond)
{
  if (cond->type() == Item::COND_ITEM)
  {
    bool and_level= ((Item_cond*) cond)->functype() ==
      Item_func::COND_AND_FUNC;
    List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
    Item *item;
    I_List<COND_CMP> save;
    while ((item=li++))
    {
      propagate_cond_constants(thd, &save,and_level ? cond : item, item);
    }
    if (and_level)
    {						// Handle other found items
      I_List_iterator<COND_CMP> cond_itr(save);
      COND_CMP *cond_cmp;
      while ((cond_cmp=cond_itr++))
      {
        Item **args= cond_cmp->cmp_func->arguments();
        if (!args[0]->const_item())
          change_cond_ref_to_const(thd, &save,cond_cmp->and_level,
                                   cond_cmp->and_level,
                                   cond_cmp->cmp_func, args[0], args[1]);
      }
    }
  }
  else if (and_father != cond && !cond->marker)		// In a AND group
  {
    if (cond->type() == Item::FUNC_ITEM &&
	(((Item_func*) cond)->functype() == Item_func::EQ_FUNC ||
	 ((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC))
    {
      Item_bool_func2 *func= dynamic_cast<Item_bool_func2*>(cond);
      Item **args= func->arguments();
      bool left_const= args[0]->const_item() && !args[0]->is_expensive();
      bool right_const= args[1]->const_item() && !args[1]->is_expensive();
      if (!(left_const && right_const) &&
          args[0]->cmp_type() == args[1]->cmp_type())
      {
	if (right_const)
	{
          resolve_const_item(thd, &args[1], args[0]);
	  func->update_used_tables();
          change_cond_ref_to_const(thd, save_list, and_father, and_father,
                                   func, args[0], args[1]);
	}
	else if (left_const)
	{
          resolve_const_item(thd, &args[0], args[1]);
	  func->update_used_tables();
          change_cond_ref_to_const(thd, save_list, and_father, and_father,
                                   func, args[1], args[0]);
	}
      }
    }
  }
}

Project: server

void JOIN_TAB::cleanup()
{
  DBUG_ENTER("JOIN_TAB::cleanup");
  
  DBUG_PRINT("enter", ("tab: %p  table %s.%s",
                       this,
                       (table ? table->s->db.str : "?"),
                       (table ? table->s->table_name.str : "?")));
  delete select;
  select= 0;
  delete quick;
  quick= 0;
  if (rowid_filter)
  {
    delete rowid_filter;
    rowid_filter= 0;
  }
  if (cache)
  {
    cache->free();
    cache= 0;
  }
  limit= 0;
  // Free select that was created for filesort outside of create_sort_index
  if (filesort && filesort->select && !filesort->own_select)
    delete filesort->select;
  delete filesort;
  filesort= NULL;
  /* Skip non-existing derived tables/views result tables */
  if (table &&
      (table->s->tmp_table != INTERNAL_TMP_TABLE || table->is_created()))
  {
    table->file->ha_end_keyread();
    table->file->ha_index_or_rnd_end();
  }
  if (table)
  {
    table->file->ha_end_keyread();
    if (type == JT_FT)
      table->file->ha_ft_end();
    else
      table->file->ha_index_or_rnd_end();
    preread_init_done= FALSE;
    if (table->pos_in_table_list && 
        table->pos_in_table_list->jtbm_subselect)
    {
      if (table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab)
      {
        /*
          Set this to NULL so that cleanup_empty_jtbm_semi_joins() doesn't
          attempt to make another free_tmp_table call.
        */
        table->pos_in_table_list->table= NULL;
        free_tmp_table(join->thd, table);
        table= NULL;
      }
      else
      {
        TABLE_LIST *tmp= table->pos_in_table_list;
        end_read_record(&read_record);
        tmp->jtbm_subselect->cleanup();
        /* 
          The above call freed the materializedd temptable. Set it to NULL so
          that we don't attempt to touch it if JOIN_TAB::cleanup() is invoked
          multiple times (it may be)
        */
        tmp->table= NULL;
        table= NULL;
      }
      DBUG_VOID_RETURN;
    }
    /*
      We need to reset this for next select
      (Tested in part_of_refkey)
    */
    table->reginfo.join_tab= 0;
  }
  end_read_record(&read_record);
  explain_plan= NULL;
  DBUG_VOID_RETURN;
}

Project: server

Field *create_tmp_field(TABLE *table, Item *item,
                        Item ***copy_func, Field **from_field,
                        Field **default_field,
                        bool group, bool modify_item,
                        bool table_cant_handle_bit_fields,
                        bool make_copy_field)
{
  Tmp_field_src src;
  Tmp_field_param prm(group, modify_item, table_cant_handle_bit_fields,
                      make_copy_field);
  Field *result= item->create_tmp_field_ex(table, &src, &prm);
  *from_field= src.field();
  *default_field= src.default_field();
  if (src.item_result_field())
    *((*copy_func)++)= src.item_result_field();
  return result;
}

Project: server

COND *Item_func_eq::build_equal_items(THD *thd,
                                      COND_EQUAL *inherited,
                                      bool link_item_fields,
                                      COND_EQUAL **cond_equal_ref)
{
  COND_EQUAL cond_equal;
  cond_equal.upper_levels= inherited;
  List<Item> eq_list;

  DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]);
  /*
    If an equality predicate forms the whole and level,
    we call it standalone equality and it's processed here.
    E.g. in the following where condition
    WHERE a=5 AND (b=5 or a=c)
    (b=5) and (a=c) are standalone equalities.
    In general we can't leave alone standalone eqalities:
    for WHERE a=b AND c=d AND (b=c OR d=5)
    b=c is replaced by =(a,b,c,d).  
   */
  if (Item_func_eq::check_equality(thd, &cond_equal, &eq_list))
  {
    Item_equal *item_equal;
    int n= cond_equal.current_level.elements + eq_list.elements;
    if (n == 0)
      return new (thd->mem_root) Item_bool(thd, true);
    else if (n == 1)
    {
      if ((item_equal= cond_equal.current_level.pop()))
      {
        item_equal->fix_fields(thd, NULL);
        item_equal->update_used_tables();
        set_if_bigger(thd->lex->current_select->max_equal_elems,
                      item_equal->n_field_items());  
        item_equal->upper_levels= inherited;
        if (cond_equal_ref)
          *cond_equal_ref= new (thd->mem_root) COND_EQUAL(item_equal,
                                                          thd->mem_root);
        return item_equal;
      }
      Item *res= eq_list.pop();
      res->update_used_tables();
      DBUG_ASSERT(res->type() == FUNC_ITEM);
      return res;
    }
    else
    {
      /* 
        Here a new AND level must be created. It can happen only
        when a row equality is processed as a standalone predicate.
      */
      Item_cond_and *and_cond= new (thd->mem_root) Item_cond_and(thd, eq_list);
      and_cond->quick_fix_field();
      List<Item> *cond_args= and_cond->argument_list();
      List_iterator_fast<Item_equal> it(cond_equal.current_level);
      while ((item_equal= it++))
      {
        if (item_equal->fix_length_and_dec())
          return NULL;
        item_equal->update_used_tables();
        set_if_bigger(thd->lex->current_select->max_equal_elems,
                      item_equal->n_field_items());  
      }
      and_cond->m_cond_equal.copy(cond_equal);
      cond_equal.current_level= and_cond->m_cond_equal.current_level;
      cond_args->append((List<Item> *)&cond_equal.current_level);
      and_cond->update_used_tables();
      if (cond_equal_ref)
        *cond_equal_ref= &and_cond->m_cond_equal;
      return and_cond;
    }
  }
  return Item_func::build_equal_items(thd, inherited, link_item_fields,
                                      cond_equal_ref);
}

Project: server

Item_bool_func2::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
                                 bool top_level_arg)
{
  if (const_item() && !is_expensive())
  {
    *cond_value= eval_const_cond() ? Item::COND_TRUE : Item::COND_FALSE;
    return (COND*) 0;
  }
  if ((*cond_value= eq_cmp_result()) != Item::COND_OK)
  {
    if (args[0]->eq(args[1], true))
    {
      if (*cond_value == Item::COND_FALSE ||
          !args[0]->maybe_null || functype() == Item_func::EQUAL_FUNC)
        return (COND*) 0;                       // Compare of identical items
    }
  }
  *cond_value= Item::COND_OK;
  return this;                                  // Point at next and level
}

Project: server

void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
{
  join->positions[idx].table= table;
  join->positions[idx].key=key;
  join->positions[idx].records_read=1.0;	/* This is a const table */
  join->positions[idx].cond_selectivity= 1.0;
  join->positions[idx].ref_depend_map= 0;

//  join->positions[idx].loosescan_key= MAX_KEY; /* Not a LooseScan */
  join->positions[idx].sj_strategy= SJ_OPT_NONE;
  join->positions[idx].use_join_buffer= FALSE;
  join->positions[idx].range_rowid_filter_info= 0;

  /* Move the const table as down as possible in best_ref */
  JOIN_TAB **pos=join->best_ref+idx+1;
  JOIN_TAB *next=join->best_ref[idx];
  for (;next != table ; pos++)
  {
    JOIN_TAB *tmp=pos[0];
    pos[0]=next;
    next=tmp;
  }
  join->best_ref[idx]=table;
  join->positions[idx].spl_plan= 0;
}

Project: server

find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array,
                   TABLE_LIST *tables,
                   ORDER *order, List<Item> &fields, List<Item> &all_fields,
                   bool is_group_field, bool add_to_all_fields,
                   bool from_window_spec)
{
  Item *order_item= *order->item; /* The item from the GROUP/ORDER caluse. */
  Item::Type order_item_type;
  Item **select_item; /* The corresponding item from the SELECT clause. */
  Field *from_field;  /* The corresponding field from the FROM clause. */
  uint counter;
  enum_resolution_type resolution;

  if (order_item->is_order_clause_position() && !from_window_spec)
  {						/* Order by position */
    uint count;
    if (order->counter_used)
      count= order->counter; // counter was once resolved
    else
      count= (uint) order_item->val_int();
    if (!count || count > fields.elements)
    {
      my_error(ER_BAD_FIELD_ERROR, MYF(0),
               order_item->full_name(), thd->where);
      return TRUE;
    }
    thd->change_item_tree((Item **)&order->item, (Item *)&ref_pointer_array[count - 1]);
    order->in_field_list= 1;
    order->counter= count;
    order->counter_used= 1;
    return FALSE;
  }
  /* Lookup the current GROUP/ORDER field in the SELECT clause. */
  select_item= find_item_in_list(order_item, fields, &counter,
                                 REPORT_EXCEPT_NOT_FOUND, &resolution);
  if (!select_item)
    return TRUE; /* The item is not unique, or some other error occurred. */


  /* Check whether the resolved field is not ambiguos. */
  if (select_item != not_found_item)
  {
    Item *view_ref= NULL;
    /*
      If we have found field not by its alias in select list but by its
      original field name, we should additionally check if we have conflict
      for this name (in case if we would perform lookup in all tables).
    */
    if (resolution == RESOLVED_BEHIND_ALIAS &&
        order_item->fix_fields_if_needed_for_order_by(thd, order->item))
      return TRUE;

    /* Lookup the current GROUP field in the FROM clause. */
    order_item_type= order_item->type();
    from_field= (Field*) not_found_field;
    if ((is_group_field && order_item_type == Item::FIELD_ITEM) ||
        order_item_type == Item::REF_ITEM)
    {
      from_field= find_field_in_tables(thd, (Item_ident*) order_item, tables,
                                       NULL, &view_ref, IGNORE_ERRORS, FALSE,
                                       FALSE);
      if (!from_field)
        from_field= (Field*) not_found_field;
    }

    if (from_field == not_found_field ||
        (from_field != view_ref_found ?
         /* it is field of base table => check that fields are same */
         ((*select_item)->type() == Item::FIELD_ITEM &&
          ((Item_field*) (*select_item))->field->eq(from_field)) :
         /*
           in is field of view table => check that references on translation
           table are same
         */
         ((*select_item)->type() == Item::REF_ITEM &&
          view_ref->type() == Item::REF_ITEM &&
          ((Item_ref *) (*select_item))->ref ==
          ((Item_ref *) view_ref)->ref)))
    {
      /*
        If there is no such field in the FROM clause, or it is the same field
        as the one found in the SELECT clause, then use the Item created for
        the SELECT field. As a result if there was a derived field that
        'shadowed' a table field with the same name, the table field will be
        chosen over the derived field.
      */
      order->item= &ref_pointer_array[counter];
      order->in_field_list=1;
      return FALSE;
    }
    else
    {
      /*
        There is a field with the same name in the FROM clause. This
        is the field that will be chosen. In this case we issue a
        warning so the user knows that the field from the FROM clause
        overshadows the column reference from the SELECT list.
      */
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_NON_UNIQ_ERROR,
                          ER_THD(thd, ER_NON_UNIQ_ERROR),
                          ((Item_ident*) order_item)->field_name.str,
                          thd->where);
    }
  }
  else if (from_window_spec)
  {
    Item **found_item= find_item_in_list(order_item, all_fields, &counter,
                                         REPORT_EXCEPT_NOT_FOUND, &resolution,
                                         all_fields.elements - fields.elements);
    if (found_item != not_found_item)
    {
      order->item= &ref_pointer_array[all_fields.elements-1-counter];
      order->in_field_list= 0;
      return FALSE;
    }
  }

  order->in_field_list=0;
  /*
    The call to order_item->fix_fields() means that here we resolve
    'order_item' to a column from a table in the list 'tables', or to
    a column in some outer query. Exactly because of the second case
    we come to this point even if (select_item == not_found_item),
    inspite of that fix_fields() calls find_item_in_list() one more
    time.

    We check order_item->is_fixed() because Item_func_group_concat can put
    arguments for which fix_fields already was called.    
  */
  if (order_item->fix_fields_if_needed_for_order_by(thd, order->item) ||
      thd->is_error())
    return TRUE; /* Wrong field. */
  order_item= *order->item; // Item can change during fix_fields()

  if (!add_to_all_fields)
    return FALSE;

  uint el= all_fields.elements;
 /* Add new field to field list. */
  all_fields.push_front(order_item, thd->mem_root);
  ref_pointer_array[el]= order_item;
  /*
     If the order_item is a SUM_FUNC_ITEM, when fix_fields is called
     ref_by is set to order->item which is the address of order_item.
     But this needs to be address of order_item in the all_fields list.
     As a result, when it gets replaced with Item_aggregate_ref
     object in Item::split_sum_func2, we will be able to retrieve the
     newly created object.
  */
  if (order_item->type() == Item::SUM_FUNC_ITEM)
    ((Item_sum *)order_item)->ref_by= all_fields.head_ref();

  order->item= &ref_pointer_array[el];
  return FALSE;
}

Project: server

void TABLE_LIST::print(THD *thd, table_map eliminated_tables, String *str, 
                       enum_query_type query_type)
{
  if (nested_join)
  {
    str->append('(');
    print_join(thd, eliminated_tables, str, &nested_join->join_list, query_type);
    str->append(')');
  }
  else if (jtbm_subselect)
  {
    if (jtbm_subselect->engine->engine_type() ==
          subselect_engine::SINGLE_SELECT_ENGINE)
    {
      /* 
        We get here when conversion into materialization didn't finish (this
        happens when
        - The subquery is a degenerate case which produces 0 or 1 record
        - subquery's optimization didn't finish because of @@max_join_size
          limits
        - ... maybe some other cases like this 
      */
      str->append(STRING_WITH_LEN(" <materialize> ("));
      jtbm_subselect->engine->print(str, query_type);
      str->append(')');
    }
    else
    {
      str->append(STRING_WITH_LEN(" <materialize> ("));
      subselect_hash_sj_engine *hash_engine;
      hash_engine= (subselect_hash_sj_engine*)jtbm_subselect->engine;
      hash_engine->materialize_engine->print(str, query_type);
      str->append(')');
    }
  }
  else
  {
    const char *cmp_name;                         // Name to compare with alias
    if (view_name.str)
    {
      // A view

      if (!(belong_to_view &&
            belong_to_view->compact_view_format) &&
        !(query_type & QT_ITEM_IDENT_SKIP_DB_NAMES))
      {
        append_identifier(thd, str, &view_db);
        str->append('.');
      }
      append_identifier(thd, str, &view_name);
      cmp_name= view_name.str;
    }
    else if (derived)
    {
      if (!is_with_table())
      {
        // A derived table
        str->append('(');
        derived->print(str, query_type);
        str->append(')');
        cmp_name= "";                               // Force printing of alias
      }
      else
      {
        append_identifier(thd, str, &table_name);
        cmp_name= table_name.str;
      }
    }
    else
    {
      // A normal table

      if (!(belong_to_view &&
            belong_to_view->compact_view_format) &&
         !(query_type & QT_ITEM_IDENT_SKIP_DB_NAMES))
      {
        append_identifier(thd, str, &db);
        str->append('.');
      }
      if (schema_table)
      {
        append_identifier(thd, str, &schema_table_name);
        cmp_name= schema_table_name.str;
      }
      else
      {
        append_identifier(thd, str, &table_name);
        cmp_name= table_name.str;
      }
#ifdef WITH_PARTITION_STORAGE_ENGINE
      if (partition_names && partition_names->elements)
      {
        int i, num_parts= partition_names->elements;
        List_iterator<String> name_it(*(partition_names));
        str->append(STRING_WITH_LEN(" PARTITION ("));
        for (i= 1; i <= num_parts; i++)
        {
          String *name= name_it++;
          append_identifier(thd, str, name->c_ptr(), name->length());
          if (i != num_parts)
            str->append(',');
        }
        str->append(')');
      }
#endif /* WITH_PARTITION_STORAGE_ENGINE */
    }
    if (table && table->versioned())
      vers_conditions.print(str, query_type);

    if (my_strcasecmp(table_alias_charset, cmp_name, alias.str))
    {
      char t_alias_buff[MAX_ALIAS_NAME];
      LEX_CSTRING t_alias= alias;

      str->append(' ');
      if (lower_case_table_names == 1)
      {
        if (alias.str && alias.str[0])
        {
          strmov(t_alias_buff, alias.str);
          t_alias.length= my_casedn_str(files_charset_info, t_alias_buff);
          t_alias.str= t_alias_buff;
        }
      }

      append_identifier(thd, str, &t_alias);
    }

    if (index_hints)
    {
      List_iterator<Index_hint> it(*index_hints);
      Index_hint *hint;

      while ((hint= it++))
      {
        str->append (STRING_WITH_LEN(" "));
        hint->print (thd, str);
      }
    }
  }
}

Project: server

bool JOIN::make_aggr_tables_info()
{
  List<Item> *curr_all_fields= &all_fields;
  List<Item> *curr_fields_list= &fields_list;
  JOIN_TAB *curr_tab= join_tab + const_tables;
  TABLE *exec_tmp_table= NULL;
  bool distinct= false;
  bool keep_row_order= false;
  bool is_having_added_as_table_cond= false;
  DBUG_ENTER("JOIN::make_aggr_tables_info");

  const bool has_group_by= this->group;
  
  sort_and_group_aggr_tab= NULL;

  if (group_optimized_away)
    implicit_grouping= true;

  bool implicit_grouping_with_window_funcs= implicit_grouping &&
                                            select_lex->have_window_funcs();
  bool implicit_grouping_without_tables= implicit_grouping &&
                                         !tables_list;

  /*
    Setup last table to provide fields and all_fields lists to the next
    node in the plan.
  */
  if (join_tab && top_join_tab_count && tables_list)
  {
    join_tab[top_join_tab_count - 1].fields= &fields_list;
    join_tab[top_join_tab_count - 1].all_fields= &all_fields;
  }

  /*
    All optimization is done. Check if we can use the storage engines
    group by handler to evaluate the group by.
    Some storage engines, like spider can also do joins, group by and
    distinct in the engine, so we do this for all queries, not only
    GROUP BY queries.
  */
  if (tables_list && top_join_tab_count && !procedure)
  {
    /*
      At the moment we only support push down for queries where
      all tables are in the same storage engine
    */
    TABLE_LIST *tbl= tables_list;
    handlerton *ht= tbl && tbl->table ? tbl->table->file->partition_ht() : 0;
    for (tbl= tbl->next_local; ht && tbl; tbl= tbl->next_local)
    {
      if (!tbl->table || tbl->table->file->partition_ht() != ht)
        ht= 0;
    }

    if (ht && ht->create_group_by)
    {
      /*
        Check if the storage engine can intercept the query.

        JOIN::optimize_stage2() might convert DISTINCT into GROUP BY and then
        optimize away GROUP BY (group_list). In such a case, we need to notify
        a storage engine supporting a group by handler of the existence of the
        original DISTINCT. Thus, we set select_distinct || group_optimized_away
        to Query::distinct.
      */
      Query query= {&all_fields, select_distinct || group_optimized_away, tables_list,
                    conds, group_list, order ? order : group_list, having};
      group_by_handler *gbh= ht->create_group_by(thd, &query);

      if (gbh)
      {
        if (!(pushdown_query= new (thd->mem_root) Pushdown_query(select_lex, gbh)))
          DBUG_RETURN(1);
        /*
          We must store rows in the tmp table if we need to do an ORDER BY
          or DISTINCT and the storage handler can't handle it.
        */
        need_tmp= query.order_by || query.group_by || query.distinct;
        distinct= query.distinct;
        keep_row_order= query.order_by || query.group_by;
        
        order= query.order_by;

        aggr_tables++;
        curr_tab= join_tab + exec_join_tab_cnt();
        bzero((void*)curr_tab, sizeof(JOIN_TAB));
        curr_tab->ref.key= -1;
        curr_tab->join= this;

        if (!(curr_tab->tmp_table_param= new TMP_TABLE_PARAM(tmp_table_param)))
          DBUG_RETURN(1);
        TABLE* table= create_tmp_table(thd, curr_tab->tmp_table_param,
                                       all_fields,
                                       NULL, query.distinct,
                                       TRUE, select_options, HA_POS_ERROR,
                                       &empty_clex_str, !need_tmp,
                                       query.order_by || query.group_by);
        if (!table)
          DBUG_RETURN(1);

        if (!(curr_tab->aggr= new (thd->mem_root) AGGR_OP(curr_tab)))
          DBUG_RETURN(1);
        curr_tab->aggr->set_write_func(::end_send);
        curr_tab->table= table;
        /*
          Setup reference fields, used by summary functions and group by fields,
          to point to the temporary table.
          The actual switching to the temporary tables fields for HAVING
          and ORDER BY is done in do_select() by calling
          set_items_ref_array(items1).
        */
        init_items_ref_array();
        items1= ref_ptr_array_slice(2);
        //items1= items0 + all_fields.elements;
        if (change_to_use_tmp_fields(thd, items1,
                                     tmp_fields_list1, tmp_all_fields1,
                                     fields_list.elements, all_fields))
          DBUG_RETURN(1);

        /* Give storage engine access to temporary table */
        gbh->table= table;
        pushdown_query->store_data_in_temp_table= need_tmp;
        pushdown_query->having= having;

        /*
          Group by and having is calculated by the group_by handler.
          Reset the group by and having
        */
        DBUG_ASSERT(query.group_by == NULL);
        group= 0; group_list= 0;
        having= tmp_having= 0;
        /*
          Select distinct is handled by handler or by creating an unique index
          over all fields in the temporary table
        */
        select_distinct= 0;
        order= query.order_by;
        tmp_table_param.field_count+= tmp_table_param.sum_func_count;
        tmp_table_param.sum_func_count= 0;

        fields= curr_fields_list;

        //todo: new:
        curr_tab->ref_array= &items1;
        curr_tab->all_fields= &tmp_all_fields1;
        curr_tab->fields= &tmp_fields_list1;

        DBUG_RETURN(thd->is_fatal_error);
      }
    }
  }


  /*
    The loose index scan access method guarantees that all grouping or
    duplicate row elimination (for distinct) is already performed
    during data retrieval, and that all MIN/MAX functions are already
    computed for each group. Thus all MIN/MAX functions should be
    treated as regular functions, and there is no need to perform
    grouping in the main execution loop.
    Notice that currently loose index scan is applicable only for
    single table queries, thus it is sufficient to test only the first
    join_tab element of the plan for its access method.
  */
  if (join_tab && top_join_tab_count && tables_list &&
      join_tab->is_using_loose_index_scan())
    tmp_table_param.precomputed_group_by=
      !join_tab->is_using_agg_loose_index_scan();

  group_list_for_estimates= group_list;
  /* Create a tmp table if distinct or if the sort is too complicated */
  if (need_tmp)
  {
    aggr_tables++;
    curr_tab= join_tab + exec_join_tab_cnt();
    bzero((void*)curr_tab, sizeof(JOIN_TAB));
    curr_tab->ref.key= -1;
    if (only_const_tables())
      first_select= sub_select_postjoin_aggr;

    /*
      Create temporary table on first execution of this join.
      (Will be reused if this is a subquery that is executed several times.)
    */
    init_items_ref_array();

    ORDER *tmp_group= (ORDER *) 0;
    if (!simple_group && !procedure && !(test_flags & TEST_NO_KEY_GROUP))
      tmp_group= group_list;

    tmp_table_param.hidden_field_count= 
      all_fields.elements - fields_list.elements;

    distinct= select_distinct && !group_list && 
              !select_lex->have_window_funcs();
    keep_row_order= false;
    bool save_sum_fields= (group_list && simple_group) ||
                           implicit_grouping_with_window_funcs;
    if (create_postjoin_aggr_table(curr_tab,
                                   &all_fields, tmp_group,
                                   save_sum_fields,
                                   distinct, keep_row_order))
      DBUG_RETURN(true);
    exec_tmp_table= curr_tab->table;

    if (exec_tmp_table->distinct)
      optimize_distinct();

   /* Change sum_fields reference to calculated fields in tmp_table */
    items1= ref_ptr_array_slice(2);
    if ((sort_and_group || curr_tab->table->group ||
         tmp_table_param.precomputed_group_by) && 
         !implicit_grouping_without_tables)
    {
      if (change_to_use_tmp_fields(thd, items1,
                                   tmp_fields_list1, tmp_all_fields1,
                                   fields_list.elements, all_fields))
        DBUG_RETURN(true);
    }
    else
    {
      if (change_refs_to_tmp_fields(thd, items1,
                                    tmp_fields_list1, tmp_all_fields1,
                                    fields_list.elements, all_fields))
        DBUG_RETURN(true);
    }
    curr_all_fields= &tmp_all_fields1;
    curr_fields_list= &tmp_fields_list1;
    // Need to set them now for correct group_fields setup, reset at the end.
    set_items_ref_array(items1);
    curr_tab->ref_array= &items1;
    curr_tab->all_fields= &tmp_all_fields1;
    curr_tab->fields= &tmp_fields_list1;
    set_postjoin_aggr_write_func(curr_tab);

    /*
      If having is not handled here, it will be checked before the row is sent
      to the client.
    */
    if (tmp_having &&
        (sort_and_group || (exec_tmp_table->distinct && !group_list) ||
	 select_lex->have_window_funcs()))
    {
      /*
        If there is no select distinct and there are no window functions
        then move the having to table conds of tmp table.
        NOTE : We cannot apply having after distinct or window functions
               If columns of having are not part of select distinct,
               then distinct may remove rows which can satisfy having.
               In the case of window functions we *must* make sure to not
               store any rows which don't match HAVING within the temp table,
               as rows will end up being used during their computation.
      */
      if (!select_distinct && !select_lex->have_window_funcs() &&
          add_having_as_table_cond(curr_tab))
        DBUG_RETURN(true);
      is_having_added_as_table_cond= tmp_having != having;

      /*
        Having condition which we are not able to add as tmp table conds are
        kept as before. And, this will be applied before storing the rows in
        tmp table.
      */
      curr_tab->having= having;
      having= NULL; // Already done
    }

    tmp_table_param.func_count= 0;
    tmp_table_param.field_count+= tmp_table_param.func_count;
    if (sort_and_group || curr_tab->table->group)
    {
      tmp_table_param.field_count+= tmp_table_param.sum_func_count;
      tmp_table_param.sum_func_count= 0;
    }

    if (exec_tmp_table->group)
    {						// Already grouped
      if (!order && !no_order && !skip_sort_order)
        order= group_list;  /* order by group */
      group_list= NULL;
    }

    /*
      If we have different sort & group then we must sort the data by group
      and copy it to another tmp table
      This code is also used if we are using distinct something
      we haven't been able to store in the temporary table yet
      like SEC_TO_TIME(SUM(...)).
    */
    if ((group_list &&
         (!test_if_subpart(group_list, order) || select_distinct)) ||
        (select_distinct && tmp_table_param.using_outer_summary_function))
    {					/* Must copy to another table */
      DBUG_PRINT("info",("Creating group table"));

      calc_group_buffer(this, group_list);
      count_field_types(select_lex, &tmp_table_param, tmp_all_fields1,
                        select_distinct && !group_list);
      tmp_table_param.hidden_field_count=
        tmp_all_fields1.elements - tmp_fields_list1.elements;

      curr_tab++;
      aggr_tables++;
      bzero((void*)curr_tab, sizeof(JOIN_TAB));
      curr_tab->ref.key= -1;

      /* group data to new table */
      /*
        If the access method is loose index scan then all MIN/MAX
        functions are precomputed, and should be treated as regular
        functions. See extended comment above.
      */
      if (join_tab->is_using_loose_index_scan())
        tmp_table_param.precomputed_group_by= TRUE;

      tmp_table_param.hidden_field_count=
        curr_all_fields->elements - curr_fields_list->elements;
      ORDER *dummy= NULL; //TODO can use table->group here also

      if (create_postjoin_aggr_table(curr_tab, curr_all_fields, dummy, true,
                                     distinct, keep_row_order))
	DBUG_RETURN(true);

      if (group_list)
      {
        if (!only_const_tables())        // No need to sort a single row
        {
          if (add_sorting_to_table(curr_tab - 1, group_list))
            DBUG_RETURN(true);
        }

        if (make_group_fields(this, this))
          DBUG_RETURN(true);
      }

      // Setup sum funcs only when necessary, otherwise we might break info
      // for the first table
      if (group_list || tmp_table_param.sum_func_count)
      {
        if (make_sum_func_list(*curr_all_fields, *curr_fields_list, true, true))
          DBUG_RETURN(true);
        if (prepare_sum_aggregators(sum_funcs,
                                    !join_tab->is_using_agg_loose_index_scan()))
          DBUG_RETURN(true);
        group_list= NULL;
        if (setup_sum_funcs(thd, sum_funcs))
          DBUG_RETURN(true);
      }
      // No sum funcs anymore
      DBUG_ASSERT(items2.is_null());

      items2= ref_ptr_array_slice(3);
      if (change_to_use_tmp_fields(thd, items2,
                                   tmp_fields_list2, tmp_all_fields2, 
                                   fields_list.elements, tmp_all_fields1))
        DBUG_RETURN(true);

      curr_fields_list= &tmp_fields_list2;
      curr_all_fields= &tmp_all_fields2;
      set_items_ref_array(items2);
      curr_tab->ref_array= &items2;
      curr_tab->all_fields= &tmp_all_fields2;
      curr_tab->fields= &tmp_fields_list2;
      set_postjoin_aggr_write_func(curr_tab);

      tmp_table_param.field_count+= tmp_table_param.sum_func_count;
      tmp_table_param.sum_func_count= 0;
    }
    if (curr_tab->table->distinct)
      select_distinct= false;               /* Each row is unique */

    if (select_distinct && !group_list)
    {
      if (having)
      {
        curr_tab->having= having;
        having->update_used_tables();
      }
      /*
        We only need DISTINCT operation if the join is not degenerate.
        If it is, we must not request DISTINCT processing, because
        remove_duplicates() assumes there is a preceding computation step (and
        in the degenerate join, there's none)
      */
      if (top_join_tab_count && tables_list)
        curr_tab->distinct= true;

      having= NULL;
      select_distinct= false;
    }
    /* Clean tmp_table_param for the next tmp table. */
    tmp_table_param.field_count= tmp_table_param.sum_func_count=
      tmp_table_param.func_count= 0;

    tmp_table_param.copy_field= tmp_table_param.copy_field_end=0;
    first_record= sort_and_group=0;

    if (!group_optimized_away || implicit_grouping_with_window_funcs)
    {
      group= false;
    }
    else
    {
      /*
        If grouping has been optimized away, a temporary table is
        normally not needed unless we're explicitly requested to create
        one (e.g. due to a SQL_BUFFER_RESULT hint or INSERT ... SELECT).

        In this case (grouping was optimized away), temp_table was
        created without a grouping expression and JOIN::exec() will not
        perform the necessary grouping (by the use of end_send_group()
        or end_write_group()) if JOIN::group is set to false.
      */
      // the temporary table was explicitly requested
      DBUG_ASSERT(select_options & OPTION_BUFFER_RESULT);
      // the temporary table does not have a grouping expression
      DBUG_ASSERT(!curr_tab->table->group); 
    }
    calc_group_buffer(this, group_list);
    count_field_types(select_lex, &tmp_table_param, *curr_all_fields, false);
  }

  if (group ||
      (implicit_grouping  && !implicit_grouping_with_window_funcs) ||
      tmp_table_param.sum_func_count)
  {
    if (make_group_fields(this, this))
      DBUG_RETURN(true);

    DBUG_ASSERT(items3.is_null());

    if (items0.is_null())
      init_items_ref_array();
    items3= ref_ptr_array_slice(4);
    setup_copy_fields(thd, &tmp_table_param,
                      items3, tmp_fields_list3, tmp_all_fields3,
                      curr_fields_list->elements, *curr_all_fields);

    curr_fields_list= &tmp_fields_list3;
    curr_all_fields= &tmp_all_fields3;
    set_items_ref_array(items3);
    if (join_tab)
    {
      JOIN_TAB *last_tab= join_tab + top_join_tab_count + aggr_tables - 1;
      // Set grouped fields on the last table
      last_tab->ref_array= &items3;
      last_tab->all_fields= &tmp_all_fields3;
      last_tab->fields= &tmp_fields_list3;
    }
    if (make_sum_func_list(*curr_all_fields, *curr_fields_list, true, true))
      DBUG_RETURN(true);
    if (prepare_sum_aggregators(sum_funcs,
                                !join_tab ||
                                !join_tab-> is_using_agg_loose_index_scan()))
      DBUG_RETURN(true);
    if (unlikely(setup_sum_funcs(thd, sum_funcs) || thd->is_fatal_error))
      DBUG_RETURN(true);
  }
  if (group_list || order)
  {
    DBUG_PRINT("info",("Sorting for send_result_set_metadata"));
    THD_STAGE_INFO(thd, stage_sorting_result);
    /* If we have already done the group, add HAVING to sorted table */
    if (tmp_having && !is_having_added_as_table_cond &&
        !group_list && !sort_and_group)
    {
      if (add_having_as_table_cond(curr_tab))
        DBUG_RETURN(true);
    }

    if (group)
      select_limit= HA_POS_ERROR;
    else if (!need_tmp)
    {
      /*
        We can abort sorting after thd->select_limit rows if there are no
        filter conditions for any tables after the sorted one.
        Filter conditions come in several forms:
         1. as a condition item attached to the join_tab, or
         2. as a keyuse attached to the join_tab (ref access).
      */
      for (uint i= const_tables + 1; i < top_join_tab_count; i++)
      {
        JOIN_TAB *const tab= join_tab + i;
        if (tab->select_cond ||                                // 1
            (tab->keyuse && !tab->first_inner))                // 2
        {
          /* We have to sort all rows */
          select_limit= HA_POS_ERROR;
          break;
        }
      }
    }
    /*
      Here we add sorting stage for ORDER BY/GROUP BY clause, if the
      optimiser chose FILESORT to be faster than INDEX SCAN or there is
      no suitable index present.
      OPTION_FOUND_ROWS supersedes LIMIT and is taken into account.
    */
    DBUG_PRINT("info",("Sorting for order by/group by"));
    ORDER *order_arg= group_list ?  group_list : order;
    if (top_join_tab_count + aggr_tables > const_tables &&
        ordered_index_usage !=
        (group_list ? ordered_index_group_by : ordered_index_order_by) &&
        curr_tab->type != JT_CONST &&
        curr_tab->type != JT_EQ_REF) // Don't sort 1 row
    {
      // Sort either first non-const table or the last tmp table
      JOIN_TAB *sort_tab= curr_tab;

      if (add_sorting_to_table(sort_tab, order_arg))
        DBUG_RETURN(true);
      /*
        filesort_limit:	 Return only this many rows from filesort().
        We can use select_limit_cnt only if we have no group_by and 1 table.
        This allows us to use Bounded_queue for queries like:
          "select SQL_CALC_FOUND_ROWS * from t1 order by b desc limit 1;"
        m_select_limit == HA_POS_ERROR (we need a full table scan)
        unit->select_limit_cnt == 1 (we only need one row in the result set)
      */
      sort_tab->filesort->limit=
        (has_group_by || (join_tab + table_count > curr_tab + 1)) ?
         select_limit : unit->select_limit_cnt;
    }
    if (!only_const_tables() &&
        !join_tab[const_tables].filesort &&
        !(select_options & SELECT_DESCRIBE))
    {
      /*
        If no IO cache exists for the first table then we are using an
        INDEX SCAN and no filesort. Thus we should not remove the sorted
        attribute on the INDEX SCAN.
      */
      skip_sort_order= true;
    }
  }

  /*
    Window functions computation step should be attached to the last join_tab
    that's doing aggregation.
    The last join_tab reads the data from the temp. table.  It also may do
    - sorting
    - duplicate value removal
    Both of these operations are done after window function computation step.
  */
  curr_tab= join_tab + total_join_tab_cnt();
  if (select_lex->window_funcs.elements)
  {
    if (!(curr_tab->window_funcs_step= new Window_funcs_computation))
      DBUG_RETURN(true);
    if (curr_tab->window_funcs_step->setup(thd, &select_lex->window_funcs,
                                           curr_tab))
      DBUG_RETURN(true);
    /* Count that we're using window functions. */
    status_var_increment(thd->status_var.feature_window_functions);
  }
  if (select_lex->custom_agg_func_used())
    status_var_increment(thd->status_var.feature_custom_aggregate_functions);

  fields= curr_fields_list;
  // Reset before execution
  set_items_ref_array(items0);
  if (join_tab)
    join_tab[exec_join_tab_cnt() + aggr_tables - 1].next_select=
      setup_end_select_func(this, NULL);
  group= has_group_by;

  DBUG_RETURN(false);
}

Project: server

best_access_path(JOIN      *join,
                 JOIN_TAB  *s,
                 table_map remaining_tables,
                 const POSITION *join_positions,
                 uint      idx,
                 bool      disable_jbuf,
                 double    record_count,
                 POSITION *pos,
                 POSITION *loose_scan_pos)
{
  THD *thd= join->thd;
  uint use_cond_selectivity= thd->variables.optimizer_use_condition_selectivity;
  KEYUSE *best_key=         0;
  uint best_max_key_part=   0;
  my_bool found_constraint= 0;
  double best=              DBL_MAX;
  double best_time=         DBL_MAX;
  double records=           DBL_MAX;
  table_map best_ref_depends_map= 0;
  Range_rowid_filter_cost_info *best_filter= 0;
  double tmp;
  ha_rows rec;
  bool best_uses_jbuf= FALSE;
  MY_BITMAP *eq_join_set= &s->table->eq_join_set;
  KEYUSE *hj_start_key= 0;
  SplM_plan_info *spl_plan= 0;
  Range_rowid_filter_cost_info *filter= 0;
  const char* cause= NULL;
  enum join_type best_type= JT_UNKNOWN, type= JT_UNKNOWN;

  disable_jbuf= disable_jbuf || idx == join->const_tables;  

  Loose_scan_opt loose_scan_opt;
  DBUG_ENTER("best_access_path");

  Json_writer_object trace_wrapper(thd, "best_access_path");
  Json_writer_array trace_paths(thd, "considered_access_paths");

  bitmap_clear_all(eq_join_set);

  loose_scan_opt.init(join, s, remaining_tables);

  if (s->table->is_splittable())
    spl_plan= s->choose_best_splitting(record_count, remaining_tables);

  if (s->keyuse)
  {                                            /* Use key if possible */
    KEYUSE *keyuse;
    KEYUSE *start_key=0;
    TABLE *table= s->table;
    double best_records= DBL_MAX;
    uint max_key_part=0;

    /* Test how we can use keys */
    rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE;  // Assumed records/key
    for (keyuse=s->keyuse ; keyuse->table == table ;)
    {
      KEY *keyinfo;
      ulong key_flags;
      uint key_parts;
      key_part_map found_part= 0;
      key_part_map notnull_part=0; // key parts which won't have NULL in lookup tuple.
      table_map found_ref= 0;
      uint key= keyuse->key;
      filter= 0;
      bool ft_key=  (keyuse->keypart == FT_KEYPART);
      /* Bitmap of keyparts where the ref access is over 'keypart=const': */
      key_part_map const_part= 0;
      /* The or-null keypart in ref-or-null access: */
      key_part_map ref_or_null_part= 0;
      if (is_hash_join_key_no(key))
      {
        /* 
          Hash join as any join employing join buffer can be used to join
          only those tables that are joined after the first non const table
	*/  
        if (!(remaining_tables & keyuse->used_tables) &&
            idx > join->const_tables)
        {
          if (!hj_start_key)
            hj_start_key= keyuse;
          bitmap_set_bit(eq_join_set, keyuse->keypart);
        }
        keyuse++;
        continue;
      }

      keyinfo= table->key_info+key;
      key_parts= table->actual_n_key_parts(keyinfo);
      key_flags= table->actual_key_flags(keyinfo);

      /* Calculate how many key segments of the current key we can use */
      start_key= keyuse;

      loose_scan_opt.next_ref_key();
      DBUG_PRINT("info", ("Considering ref access on key %s",
                          keyuse->table->key_info[keyuse->key].name.str));

      do /* For each keypart */
      {
        uint keypart= keyuse->keypart;
        table_map best_part_found_ref= 0;
        double best_prev_record_reads= DBL_MAX;
        
        do /* For each way to access the keypart */
        {
          /*
            if 1. expression doesn't refer to forward tables
               2. we won't get two ref-or-null's
          */
          if (!(remaining_tables & keyuse->used_tables) &&
              (!keyuse->validity_ref || *keyuse->validity_ref) &&
              s->access_from_tables_is_allowed(keyuse->used_tables,
                                               join->sjm_lookup_tables) &&
              !(ref_or_null_part && (keyuse->optimize &
                                     KEY_OPTIMIZE_REF_OR_NULL)))
          {
            found_part|= keyuse->keypart_map;
            if (!(keyuse->used_tables & ~join->const_table_map))
              const_part|= keyuse->keypart_map;

            if (!keyuse->val->maybe_null || keyuse->null_rejecting)
              notnull_part|=keyuse->keypart_map;

            double tmp2= prev_record_reads(join_positions, idx,
                                           (found_ref | keyuse->used_tables));
            if (tmp2 < best_prev_record_reads)
            {
              best_part_found_ref= keyuse->used_tables & ~join->const_table_map;
              best_prev_record_reads= tmp2;
            }
            if (rec > keyuse->ref_table_rows)
              rec= keyuse->ref_table_rows;
	    /*
	      If there is one 'key_column IS NULL' expression, we can
	      use this ref_or_null optimisation of this field
	    */
            if (keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL)
              ref_or_null_part |= keyuse->keypart_map;
          }
          loose_scan_opt.add_keyuse(remaining_tables, keyuse);
          keyuse++;
        } while (keyuse->table == table && keyuse->key == key &&
                 keyuse->keypart == keypart);
	found_ref|= best_part_found_ref;
      } while (keyuse->table == table && keyuse->key == key);

      /*
        Assume that that each key matches a proportional part of table.
      */
      if (!found_part && !ft_key && !loose_scan_opt.have_a_case())
        continue;                               // Nothing usable found

      if (rec < MATCHING_ROWS_IN_OTHER_TABLE)
        rec= MATCHING_ROWS_IN_OTHER_TABLE;      // Fix for small tables

      Json_writer_object trace_access_idx(thd);
      /*
        full text keys require special treatment
      */
      if (ft_key)
      {
        /*
          Really, there should be records=0.0 (yes!)
          but 1.0 would be probably safer
        */
        tmp= prev_record_reads(join_positions, idx, found_ref);
        records= 1.0;
        type= JT_FT;
        trace_access_idx.add("access_type", join_type_str[type])
                        .add("full-text index", keyinfo->name);
      }
      else
      {
        found_constraint= MY_TEST(found_part);
        loose_scan_opt.check_ref_access_part1(s, key, start_key, found_part);

        /* Check if we found full key */
        const key_part_map all_key_parts= PREV_BITS(uint, key_parts);
        if (found_part == all_key_parts && !ref_or_null_part)
        {                                         /* use eq key */
          max_key_part= (uint) ~0;
          /*
            If the index is a unique index (1), and
            - all its columns are not null (2), or
            - equalities we are using reject NULLs (3)
            then the estimate is rows=1.
          */
          if ((key_flags & (HA_NOSAME | HA_EXT_NOSAME)) &&   // (1)
              (!(key_flags & HA_NULL_PART_KEY) ||            //  (2)
               all_key_parts == notnull_part))               //  (3)
          {
            type= JT_EQ_REF;
            trace_access_idx.add("access_type", join_type_str[type])
                            .add("index", keyinfo->name);
            tmp = prev_record_reads(join_positions, idx, found_ref);
            records=1.0;
          }
          else
          {
            type= JT_REF;
            trace_access_idx.add("access_type", join_type_str[type])
                            .add("index", keyinfo->name);
            if (!found_ref)
            {                                     /* We found a const key */
              /*
                ReuseRangeEstimateForRef-1:
                We get here if we've found a ref(const) (c_i are constants):
                  "(keypart1=c1) AND ... AND (keypartN=cN)"   [ref_const_cond]
                
                If range optimizer was able to construct a "range" 
                access on this index, then its condition "quick_cond" was
                eqivalent to ref_const_cond (*), and we can re-use E(#rows)
                from the range optimizer.
                
                Proof of (*): By properties of range and ref optimizers 
                quick_cond will be equal or tighther than ref_const_cond. 
                ref_const_cond already covers "smallest" possible interval - 
                a singlepoint interval over all keyparts. Therefore, 
                quick_cond is equivalent to ref_const_cond (if it was an 
                empty interval we wouldn't have got here).
              */
              if (table->quick_keys.is_set(key))
              {
                records= (double) table->quick_rows[key];
                trace_access_idx.add("used_range_estimates", true);
              }
              else
              {
                /* quick_range couldn't use key! */
                records= (double) s->records/rec;
                trace_access_idx.add("used_range_estimates", false)
                                .add("cause", "not available");
              }
            }
            else
            {
              if (!(records= keyinfo->actual_rec_per_key(key_parts-1)))
              {                                   /* Prefer longer keys */
                records=
                  ((double) s->records / (double) rec *
                   (1.0 +
                    ((double) (table->s->max_key_length-keyinfo->key_length) /
                     (double) table->s->max_key_length)));
                if (records < 2.0)
                  records=2.0;               /* Can't be as good as a unique */
              }
              /*
                ReuseRangeEstimateForRef-2:  We get here if we could not reuse
                E(#rows) from range optimizer. Make another try:
                
                If range optimizer produced E(#rows) for a prefix of the ref
                access we're considering, and that E(#rows) is lower then our
                current estimate, make an adjustment. The criteria of when we
                can make an adjustment is a special case of the criteria used
                in ReuseRangeEstimateForRef-3.
              */
              if (table->quick_keys.is_set(key) &&
                  (const_part &
                    (((key_part_map)1 << table->quick_key_parts[key])-1)) ==
                  (((key_part_map)1 << table->quick_key_parts[key])-1) &&
                  table->quick_n_ranges[key] == 1 &&
                  records > (double) table->quick_rows[key])
              {

                records= (double) table->quick_rows[key];
                trace_access_idx.add("used_range_estimates", true);
              }
              else
              {
                if (table->quick_keys.is_set(key))
                {
                  trace_access_idx.add("used_range_estimates",false)
                                  .add("cause",
                                       "not better than ref estimates");
                }
                else
                {
                  trace_access_idx.add("used_range_estimates", false)
                                  .add("cause", "not available");
                }
              }
            }
            /* Limit the number of matched rows */
            tmp= records;
            set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
            if (table->covering_keys.is_set(key))
              tmp= table->file->keyread_time(key, 1, (ha_rows) tmp);
            else
              tmp= table->file->read_time(key, 1,
                                          (ha_rows) MY_MIN(tmp,s->worst_seeks));
            tmp= COST_MULT(tmp, record_count);
          }
        }
        else
        {
          type = ref_or_null_part ? JT_REF_OR_NULL : JT_REF;
          trace_access_idx.add("access_type", join_type_str[type])
                          .add("index", keyinfo->name);
          /*
            Use as much key-parts as possible and a uniq key is better
            than a not unique key
            Set tmp to (previous record count) * (records / combination)
          */
          if ((found_part & 1) &&
              (!(table->file->index_flags(key, 0, 0) & HA_ONLY_WHOLE_INDEX) ||
               found_part == PREV_BITS(uint,keyinfo->user_defined_key_parts)))
          {
            max_key_part= max_part_bit(found_part);
            /*
              ReuseRangeEstimateForRef-3:
              We're now considering a ref[or_null] access via
              (t.keypart1=e1 AND ... AND t.keypartK=eK) [ OR  
              (same-as-above but with one cond replaced 
               with "t.keypart_i IS NULL")]  (**)
              
              Try re-using E(#rows) from "range" optimizer:
              We can do so if "range" optimizer used the same intervals as
              in (**). The intervals used by range optimizer may be not 
              available at this point (as "range" access might have choosen to
              create quick select over another index), so we can't compare
              them to (**). We'll make indirect judgements instead.
              The sufficient conditions for re-use are:
              (C1) All e_i in (**) are constants, i.e. found_ref==FALSE. (if
                   this is not satisfied we have no way to know which ranges
                   will be actually scanned by 'ref' until we execute the 
                   join)
              (C2) max #key parts in 'range' access == K == max_key_part (this
                   is apparently a necessary requirement)

              We also have a property that "range optimizer produces equal or 
              tighter set of scan intervals than ref(const) optimizer". Each
              of the intervals in (**) are "tightest possible" intervals when 
              one limits itself to using keyparts 1..K (which we do in #2).              
              From here it follows that range access used either one, or
              both of the (I1) and (I2) intervals:
              
               (t.keypart1=c1 AND ... AND t.keypartK=eK)  (I1) 
               (same-as-above but with one cond replaced  
                with "t.keypart_i IS NULL")               (I2)

              The remaining part is to exclude the situation where range
              optimizer used one interval while we're considering
              ref-or-null and looking for estimate for two intervals. This
              is done by last limitation:

              (C3) "range optimizer used (have ref_or_null?2:1) intervals"
            */
            if (table->quick_keys.is_set(key) && !found_ref &&          //(C1)
                table->quick_key_parts[key] == max_key_part &&          //(C2)
                table->quick_n_ranges[key] == 1 + MY_TEST(ref_or_null_part)) //(C3)
            {
              tmp= records= (double) table->quick_rows[key];
              trace_access_idx.add("used_range_estimates", true);
            }
            else
            {
              /* Check if we have statistic about the distribution */
              if ((records= keyinfo->actual_rec_per_key(max_key_part-1)))
              {
                /* 
                  Fix for the case where the index statistics is too
                  optimistic: If 
                  (1) We're considering ref(const) and there is quick select
                      on the same index, 
                  (2) and that quick select uses more keyparts (i.e. it will
                      scan equal/smaller interval then this ref(const))
                  (3) and E(#rows) for quick select is higher then our
                      estimate,
                  Then 
                    We'll use E(#rows) from quick select.

                  Q: Why do we choose to use 'ref'? Won't quick select be
                  cheaper in some cases ?
                  TODO: figure this out and adjust the plan choice if needed.
                */
                if (!found_ref && table->quick_keys.is_set(key) &&    // (1)
                    table->quick_key_parts[key] > max_key_part &&     // (2)
                    records < (double)table->quick_rows[key])         // (3)
                {
                  trace_access_idx.add("used_range_estimates", true);
                  records= (double)table->quick_rows[key];
                }
                else
                {
                  if (table->quick_keys.is_set(key) &&
                      table->quick_key_parts[key] < max_key_part)
                  {
                    trace_access_idx.add("chosen", false);
                    cause= "range uses more keyparts";
                  }
                }

                tmp= records;
              }
              else
              {
                /*
                  Assume that the first key part matches 1% of the file
                  and that the whole key matches 10 (duplicates) or 1
                  (unique) records.
                  Assume also that more key matches proportionally more
                  records
                  This gives the formula:
                  records = (x * (b-a) + a*c-b)/(c-1)

                  b = records matched by whole key
                  a = records matched by first key part (1% of all records?)
                  c = number of key parts in key
                  x = used key parts (1 <= x <= c)
                */
                double rec_per_key;
                if (!(rec_per_key=(double)
                      keyinfo->rec_per_key[keyinfo->user_defined_key_parts-1]))
                  rec_per_key=(double) s->records/rec+1;

                if (!s->records)
                  tmp = 0;
                else if (rec_per_key/(double) s->records >= 0.01)
                  tmp = rec_per_key;
                else
                {
                  double a=s->records*0.01;
                  if (keyinfo->user_defined_key_parts > 1)
                    tmp= (max_key_part * (rec_per_key - a) +
                          a*keyinfo->user_defined_key_parts - rec_per_key)/
                         (keyinfo->user_defined_key_parts-1);
                  else
                    tmp= a;
                  set_if_bigger(tmp,1.0);
                }
                records = (ulong) tmp;
              }

              if (ref_or_null_part)
              {
                /* We need to do two key searches to find key */
                tmp *= 2.0;
                records *= 2.0;
              }

              /*
                ReuseRangeEstimateForRef-4:  We get here if we could not reuse
                E(#rows) from range optimizer. Make another try:
                
                If range optimizer produced E(#rows) for a prefix of the ref 
                access we're considering, and that E(#rows) is lower then our
                current estimate, make the adjustment.

                The decision whether we can re-use the estimate from the range
                optimizer is the same as in ReuseRangeEstimateForRef-3,
                applied to first table->quick_key_parts[key] key parts.
              */
              if (table->quick_keys.is_set(key) &&
                  table->quick_key_parts[key] <= max_key_part &&
                  const_part &
                    ((key_part_map)1 << table->quick_key_parts[key]) &&
                  table->quick_n_ranges[key] == 1 + MY_TEST(ref_or_null_part &
                                                            const_part) &&
                  records > (double) table->quick_rows[key])
              {
                tmp= records= (double) table->quick_rows[key];
              }
            }

            /* Limit the number of matched rows */
            set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
            if (table->covering_keys.is_set(key))
              tmp= table->file->keyread_time(key, 1, (ha_rows) tmp);
            else
              tmp= table->file->read_time(key, 1,
                                          (ha_rows) MY_MIN(tmp,s->worst_seeks));
            tmp= COST_MULT(tmp, record_count);
          }
          else
          {
            if (!(found_part & 1))
              cause= "no predicate for first keypart";
            tmp= best_time;                    // Do nothing
          }
        }

        tmp= COST_ADD(tmp, s->startup_cost);
        loose_scan_opt.check_ref_access_part2(key, start_key, records, tmp,
                                              found_ref);
      } /* not ft_key */

      if (records < DBL_MAX &&
	  (found_part & 1))   // start_key->key can be used for index access
      {
        double rows= record_count * records;
        double access_cost_factor= MY_MIN(tmp / rows, 1.0);
        filter=
          table->best_range_rowid_filter_for_partial_join(start_key->key, rows,
                                                          access_cost_factor);
        if (filter)
	{
          filter->get_cmp_gain(rows);
          tmp-= filter->get_adjusted_gain(rows) - filter->get_cmp_gain(rows);
          DBUG_ASSERT(tmp >= 0);
          trace_access_idx.add("rowid_filter_key",
                               s->table->key_info[filter->key_no].name);
        }
      }
      trace_access_idx.add("rows", records).add("cost", tmp);

      if (tmp + 0.0001 < best_time - records/(double) TIME_FOR_COMPARE)
      {
        trace_access_idx.add("chosen", true);
        best_time= COST_ADD(tmp, records/(double) TIME_FOR_COMPARE);
        best= tmp;
        best_records= records;
        best_key= start_key;
        best_max_key_part= max_key_part;
        best_ref_depends_map= found_ref;
        best_filter= filter;
        best_type= type;
      }
      else
      {
        trace_access_idx.add("chosen", false)
                        .add("cause", cause ? cause : "cost");
      }
      cause= NULL;
    } /* for each key */
    records= best_records;
  }

  /* 
    If there is no key to access the table, but there is an equi-join
    predicate connecting the table with the privious tables then we
    consider the possibility of using hash join.
    We need also to check that:
    (1) s is inner table of semi-join -> join cache is allowed for semijoins
    (2) s is inner table of outer join -> join cache is allowed for outer joins
  */  
  if (idx > join->const_tables && best_key == 0 &&
      (join->allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) &&
      join->max_allowed_join_cache_level > 2 &&
     !bitmap_is_clear_all(eq_join_set) &&  !disable_jbuf &&
      (!s->emb_sj_nest ||                     
       join->allowed_semijoin_with_cache) &&    // (1)
      (!(s->table->map & join->outer_join) ||
       join->allowed_outer_join_with_cache))    // (2)
  {
    Json_writer_object trace_access_hash(thd);
    double join_sel= 0.1;
    /* Estimate the cost of  the hash join access to the table */
    double rnd_records= matching_candidates_in_table(s, found_constraint,
                                                     use_cond_selectivity);

    tmp= s->quick ? s->quick->read_time : s->scan_time();
    double cmp_time= (s->records - rnd_records)/(double) TIME_FOR_COMPARE;
    tmp= COST_ADD(tmp, cmp_time);

    /* We read the table as many times as join buffer becomes full. */

    double refills= (1.0 + floor((double) cache_record_length(join,idx) *
                           record_count /
			   (double) thd->variables.join_buff_size));
    tmp= COST_MULT(tmp, refills);
    best_time= COST_ADD(tmp,
                        COST_MULT((record_count*join_sel) / TIME_FOR_COMPARE,
                                  rnd_records));
    best= tmp;
    records= rnd_records;
    best_key= hj_start_key;
    best_ref_depends_map= 0;
    best_uses_jbuf= TRUE;
    best_filter= 0;
    best_type= JT_HASH;
    trace_access_hash.add("type", "hash");
    trace_access_hash.add("index", "hj-key");
    trace_access_hash.add("cost", rnd_records);
    trace_access_hash.add("cost", best);
    trace_access_hash.add("chosen", true);
  }

  /*
    Don't test table scan if it can't be better.
    Prefer key lookup if we would use the same key for scanning.

    Don't do a table scan on InnoDB tables, if we can read the used
    parts of the row from any of the used index.
    This is because table scans uses index and we would not win
    anything by using a table scan.

    A word for word translation of the below if-statement in sergefp's
    understanding: we check if we should use table scan if:
    (1) The found 'ref' access produces more records than a table scan
        (or index scan, or quick select), or 'ref' is more expensive than
        any of them.
    (2) This doesn't hold: the best way to perform table scan is to to perform
        'range' access using index IDX, and the best way to perform 'ref' 
        access is to use the same index IDX, with the same or more key parts.
        (note: it is not clear how this rule is/should be extended to 
        index_merge quick selects). Also if we have a hash join we prefer that
        over a table scan
    (3) See above note about InnoDB.
    (4) NOT ("FORCE INDEX(...)" is used for table and there is 'ref' access
             path, but there is no quick select)
        If the condition in the above brackets holds, then the only possible
        "table scan" access method is ALL/index (there is no quick select).
        Since we have a 'ref' access path, and FORCE INDEX instructs us to
        choose it over ALL/index, there is no need to consider a full table
        scan.
    (5) Non-flattenable semi-joins: don't consider doing a scan of temporary
        table if we had an option to make lookups into it. In real-world cases,
        lookups are cheaper than full scans, but when the table is small, they
        can be [considered to be] more expensive, which causes lookups not to 
        be used for cases with small datasets, which is annoying.
  */
  Json_writer_object trace_access_scan(thd);
  if ((records >= s->found_records || best > s->read_time) &&            // (1)
      !(best_key && best_key->key == MAX_KEY) &&                         // (2)
      !(s->quick && best_key && s->quick->index == best_key->key &&      // (2)
        best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&// (2)
      !((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) &&   // (3)
        ! s->table->covering_keys.is_clear_all() && best_key && !s->quick) &&// (3)
      !(s->table->force_index && best_key && !s->quick) &&               // (4)
      !(best_key && s->table->pos_in_table_list->jtbm_subselect))        // (5)
  {                                             // Check full join
    double rnd_records= matching_candidates_in_table(s, found_constraint,
                                                      use_cond_selectivity);

    /*
      Range optimizer never proposes a RANGE if it isn't better
      than FULL: so if RANGE is present, it's always preferred to FULL.
      Here we estimate its cost.
    */

    filter= 0;
    if (s->quick)
    {
      /*
        For each record we:
        - read record range through 'quick'
        - skip rows which does not satisfy WHERE constraints
        TODO: 
        We take into account possible use of join cache for ALL/index
        access (see first else-branch below), but we don't take it into 
        account here for range/index_merge access. Find out why this is so.
      */
      double cmp_time= (s->found_records - rnd_records)/(double) TIME_FOR_COMPARE;
      tmp= COST_MULT(record_count,
                     COST_ADD(s->quick->read_time, cmp_time));

      if ( s->quick->get_type() == QUICK_SELECT_I::QS_TYPE_RANGE)
      {
        double rows= record_count * s->found_records;
        double access_cost_factor= MY_MIN(tmp / rows, 1.0);
        uint key_no= s->quick->index;
        filter=
        s->table->best_range_rowid_filter_for_partial_join(key_no, rows,
                                                           access_cost_factor);
        if (filter)
        {
          tmp-= filter->get_adjusted_gain(rows);
          DBUG_ASSERT(tmp >= 0);
        }
        type= JT_RANGE;
      }
      else
      {
        type= JT_INDEX_MERGE;
        best_filter= 0;
      }
      loose_scan_opt.check_range_access(join, idx, s->quick);
    }
    else
    {
      /* Estimate cost of reading table. */
      if (s->table->force_index && !best_key) // index scan
      {
        type= JT_NEXT;
        tmp= s->table->file->read_time(s->ref.key, 1, s->records);
      }
      else // table scan
      {
        tmp= s->scan_time();
        type= JT_ALL;
      }

      if ((s->table->map & join->outer_join) || disable_jbuf)     // Can't use join cache
      {
        /*
          For each record we have to:
          - read the whole table record 
          - skip rows which does not satisfy join condition
        */
        double cmp_time= (s->records - rnd_records)/(double) TIME_FOR_COMPARE;
        tmp= COST_MULT(record_count, COST_ADD(tmp,cmp_time));
      }
      else
      {
        double refills= (1.0 + floor((double) cache_record_length(join,idx) *
                        (record_count /
                         (double) thd->variables.join_buff_size)));
        tmp= COST_MULT(tmp, refills);
        /* 
            We don't make full cartesian product between rows in the scanned
           table and existing records because we skip all rows from the
           scanned table, which does not satisfy join condition when 
           we read the table (see flush_cached_records for details). Here we
           take into account cost to read and skip these records.
        */
        double cmp_time= (s->records - rnd_records)/(double) TIME_FOR_COMPARE;
        tmp= COST_ADD(tmp, cmp_time);
      }
    }

    trace_access_scan.add("access_type", type == JT_ALL ?
                                         "scan" :
                                         join_type_str[type]);
    /* Splitting technique cannot be used with join cache */
    if (s->table->is_splittable())
      tmp+= s->table->get_materialization_cost();
    else
      tmp+= s->startup_cost;

    /*
      We estimate the cost of evaluating WHERE clause for found records
      as record_count * rnd_records / TIME_FOR_COMPARE. This cost plus
      tmp give us total cost of using TABLE SCAN
    */

    const double best_filter_cmp_gain= best_filter
      ? best_filter->get_cmp_gain(record_count * records)
      : 0;
    trace_access_scan.add("resulting_rows", rnd_records);
    trace_access_scan.add("cost", tmp);

    if (best == DBL_MAX ||
        COST_ADD(tmp, record_count/(double) TIME_FOR_COMPARE*rnd_records) <
         (best_key->is_for_hash_join() ? best_time :
          COST_ADD(best - best_filter_cmp_gain,
                   record_count/(double) TIME_FOR_COMPARE*records)))
    {
      /*
        If the table has a range (s->quick is set) make_join_select()
        will ensure that this will be used
      */
      best= tmp;
      records= rnd_records;
      best_key= 0;
      best_filter= 0;
      if (s->quick && s->quick->get_type() == QUICK_SELECT_I::QS_TYPE_RANGE)
        best_filter= filter;
      /* range/index_merge/ALL/index access method are "independent", so: */
      best_ref_depends_map= 0;
      best_uses_jbuf= MY_TEST(!disable_jbuf && !((s->table->map &
                                                  join->outer_join)));
      spl_plan= 0;
      best_type= type;
    }
    trace_access_scan.add("chosen", best_key == NULL);
  }
  else
  {
    trace_access_scan.add("type", "scan");
    trace_access_scan.add("chosen", false);
    trace_access_scan.add("cause", "cost");
  }

  /* Update the cost information for the current partial plan */
  pos->records_read= records;
  pos->read_time=    best;
  pos->key=          best_key;
  pos->table=        s;
  pos->ref_depend_map= best_ref_depends_map;
  pos->loosescan_picker.loosescan_key= MAX_KEY;
  pos->use_join_buffer= best_uses_jbuf;
  pos->spl_plan= spl_plan;
  pos->range_rowid_filter_info= best_filter;

  loose_scan_opt.save_to_position(s, loose_scan_pos);

  if (!best_key &&
      idx == join->const_tables &&
      s->table == join->sort_by_table &&
      join->unit->select_limit_cnt >= records)
  {
    trace_access_scan.add("use_tmp_table", true);
    join->sort_by_table= (TABLE*) 1;  // Must use temporary table
  }
  trace_access_scan.end();
  trace_paths.end();

  if (unlikely(thd->trace_started()))
    print_best_access_for_table(thd, pos, best_type);

  DBUG_VOID_RETURN;
}

Project: server

simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
               bool in_sj)
{
  TABLE_LIST *table;
  NESTED_JOIN *nested_join;
  TABLE_LIST *prev_table= 0;
  List_iterator<TABLE_LIST> li(*join_list);
  bool straight_join= MY_TEST(join->select_options & SELECT_STRAIGHT_JOIN);
  DBUG_ENTER("simplify_joins");

  /* 
    Try to simplify join operations from join_list.
    The most outer join operation is checked for conversion first. 
  */
  while ((table= li++))
  {
    table_map used_tables;
    table_map not_null_tables= (table_map) 0;

    if ((nested_join= table->nested_join))
    {
      /* 
         If the element of join_list is a nested join apply
         the procedure to its nested join list first.
      */
      if (table->on_expr)
      {
        Item *expr= table->on_expr;
        /* 
           If an on expression E is attached to the table, 
           check all null rejected predicates in this expression.
           If such a predicate over an attribute belonging to
           an inner table of an embedded outer join is found,
           the outer join is converted to an inner join and
           the corresponding on expression is added to E. 
	*/ 
        expr= simplify_joins(join, &nested_join->join_list,
                             expr, FALSE, in_sj || table->sj_on_expr);

        if (!table->prep_on_expr || expr != table->on_expr)
        {
          DBUG_ASSERT(expr);

          table->on_expr= expr;
          table->prep_on_expr= expr->copy_andor_structure(join->thd);
        }
      }
      nested_join->used_tables= (table_map) 0;
      nested_join->not_null_tables=(table_map) 0;
      conds= simplify_joins(join, &nested_join->join_list, conds, top, 
                            in_sj || table->sj_on_expr);
      used_tables= nested_join->used_tables;
      not_null_tables= nested_join->not_null_tables;  
      /* The following two might become unequal after table elimination: */
      nested_join->n_tables= nested_join->join_list.elements;
    }
    else
    {
      if (!table->prep_on_expr)
        table->prep_on_expr= table->on_expr;
      used_tables= table->get_map();
      if (conds)
        not_null_tables= conds->not_null_tables();
    }
      
    if (table->embedding)
    {
      table->embedding->nested_join->used_tables|= used_tables;
      table->embedding->nested_join->not_null_tables|= not_null_tables;
    }

    if (!(table->outer_join & (JOIN_TYPE_LEFT | JOIN_TYPE_RIGHT)) ||
        (used_tables & not_null_tables))
    {
      /* 
        For some of the inner tables there are conjunctive predicates
        that reject nulls => the outer join can be replaced by an inner join.
      */
      if (table->outer_join && !table->embedding && table->table)
        table->table->maybe_null= FALSE;
      table->outer_join= 0;
      if (!(straight_join || table->straight))
      {
        table->dep_tables= 0;
        TABLE_LIST *embedding= table->embedding;
        while (embedding)
        {
          if (embedding->nested_join->join_list.head()->outer_join)
          {
            if (!embedding->sj_subq_pred)
              table->dep_tables= embedding->dep_tables;
            break;
          }
          embedding= embedding->embedding;
        }
      }
      if (table->on_expr)
      {
        /* Add ON expression to the WHERE or upper-level ON condition. */
        if (conds)
        {
          conds= and_conds(join->thd, conds, table->on_expr);
          conds->top_level_item();
          /* conds is always a new item as both cond and on_expr existed */
          DBUG_ASSERT(!conds->is_fixed());
          conds->fix_fields(join->thd, &conds);
        }
        else
          conds= table->on_expr; 
        table->prep_on_expr= table->on_expr= 0;
      }
    }

    /* 
      Only inner tables of non-convertible outer joins
      remain with on_expr.
    */ 
    if (table->on_expr)
    {
      table_map table_on_expr_used_tables= table->on_expr->used_tables();
      table->dep_tables|= table_on_expr_used_tables;
      if (table->embedding)
      {
        table->dep_tables&= ~table->embedding->nested_join->used_tables;   
        /*
           Embedding table depends on tables used
           in embedded on expressions. 
        */
        table->embedding->on_expr_dep_tables|= table_on_expr_used_tables;
      }
      else
        table->dep_tables&= ~table->get_map();
    }

    if (prev_table)
    {
      /* The order of tables is reverse: prev_table follows table */
      if (prev_table->straight || straight_join)
        prev_table->dep_tables|= used_tables;
      if (prev_table->on_expr)
      {
        prev_table->dep_tables|= table->on_expr_dep_tables;
        table_map prev_used_tables= prev_table->nested_join ?
	                            prev_table->nested_join->used_tables :
	                            prev_table->get_map();
        /* 
          If on expression contains only references to inner tables
          we still make the inner tables dependent on the outer tables.
          It would be enough to set dependency only on one outer table
          for them. Yet this is really a rare case.
          Note:
          RAND_TABLE_BIT mask should not be counted as it
          prevents update of inner table dependences.
          For example it might happen if RAND() function
          is used in JOIN ON clause.
	*/  
        if (!((prev_table->on_expr->used_tables() &
               ~(OUTER_REF_TABLE_BIT | RAND_TABLE_BIT)) &
              ~prev_used_tables))
          prev_table->dep_tables|= used_tables;
      }
    }
    prev_table= table;
  }
    
  /* 
    Flatten nested joins that can be flattened.
    no ON expression and not a semi-join => can be flattened.
  */
  li.rewind();
  while ((table= li++))
  {
    nested_join= table->nested_join;
    if (table->sj_on_expr && !in_sj)
    {
      /*
        If this is a semi-join that is not contained within another semi-join
        leave it intact (otherwise it is flattened)
      */
      /*
        Make sure that any semi-join appear in
        the join->select_lex->sj_nests list only once
      */
      List_iterator_fast<TABLE_LIST> sj_it(join->select_lex->sj_nests);
      TABLE_LIST *sj_nest;
      while ((sj_nest= sj_it++))
      {
        if (table == sj_nest)
          break;
      }
      if (sj_nest)
        continue;
      join->select_lex->sj_nests.push_back(table, join->thd->mem_root);

      /* 
        Also, walk through semi-join children and mark those that are now
        top-level
      */
      TABLE_LIST *tbl;
      List_iterator<TABLE_LIST> it(nested_join->join_list);
      while ((tbl= it++))
      {
        if (!tbl->on_expr && tbl->table)
          tbl->table->maybe_null= FALSE;
      }
    }
    else if (nested_join && !table->on_expr)
    {
      TABLE_LIST *tbl;
      List_iterator<TABLE_LIST> it(nested_join->join_list);
      List<TABLE_LIST> repl_list;  
      while ((tbl= it++))
      {
        tbl->embedding= table->embedding;
        if (!tbl->embedding && !tbl->on_expr && tbl->table)
          tbl->table->maybe_null= FALSE;
        tbl->join_list= table->join_list;
        repl_list.push_back(tbl, join->thd->mem_root);
        tbl->dep_tables|= table->dep_tables;
      }
      li.replace(repl_list);
    }
  }
  DBUG_RETURN(conds); 
}

Project: server

select_handler *SELECT_LEX::find_select_handler(THD *thd)
{
  if (next_select())
      return 0;
  if (master_unit()->outer_select())
    return 0;
  for (TABLE_LIST *tbl= join->tables_list; tbl; tbl= tbl->next_global)
  {
    if (!tbl->table)
      continue;
    handlerton *ht= tbl->table->file->partition_ht();
    if (!ht->create_select)
      continue;
    select_handler *sh= ht->create_select(thd, this);
    return sh;
  }
  return 0;
}

Project: server

void JOIN_TAB::build_range_rowid_filter_if_needed()
{
  if (rowid_filter && !is_rowid_filter_built)
  {
    /**
      The same handler object (table->file) is used to build a filter
      and to perfom a primary table access (by the main query).

      To estimate the time for filter building tracker should be changed
      and after building of the filter has been finished it should be
      switched back to the previos tracker.
    */
    Exec_time_tracker *table_tracker= table->file->get_time_tracker();
    Rowid_filter_tracker *rowid_tracker= rowid_filter->get_tracker();
    table->file->set_time_tracker(rowid_tracker->get_time_tracker());
    rowid_tracker->start_tracking();
    if (!rowid_filter->build())
    {
      is_rowid_filter_built= true;
    }
    else
    {
      delete rowid_filter;
      rowid_filter= 0;
    }
    rowid_tracker->stop_tracking();
    table->file->set_time_tracker(table_tracker);
  }
}

Project: server

bool handle_select(THD *thd, LEX *lex, select_result *result,
                   ulong setup_tables_done_option)
{
  bool res;
  SELECT_LEX *select_lex= lex->first_select_lex();
  DBUG_ENTER("handle_select");
  MYSQL_SELECT_START(thd->query());

  if (select_lex->master_unit()->is_unit_op() ||
      select_lex->master_unit()->fake_select_lex)
    res= mysql_union(thd, lex, result, &lex->unit, setup_tables_done_option);
  else
  {
    SELECT_LEX_UNIT *unit= &lex->unit;
    unit->set_limit(unit->global_parameters());
    /*
      'options' of mysql_select will be set in JOIN, as far as JOIN for
      every PS/SP execution new, we will not need reset this flag if 
      setup_tables_done_option changed for next rexecution
    */
    res= mysql_select(thd,
		      select_lex->table_list.first,
		      select_lex->with_wild, select_lex->item_list,
		      select_lex->where,
		      select_lex->order_list.elements +
		      select_lex->group_list.elements,
		      select_lex->order_list.first,
		      select_lex->group_list.first,
		      select_lex->having,
		      lex->proc_list.first,
		      select_lex->options | thd->variables.option_bits |
                      setup_tables_done_option,
		      result, unit, select_lex);
  }
  DBUG_PRINT("info",("res: %d  report_error: %d", res,
		     thd->is_error()));
  res|= thd->is_error();
  if (unlikely(res))
    result->abort_result_set();
  if (unlikely(thd->killed == ABORT_QUERY && !thd->no_errors))
  {
    /*
      If LIMIT ROWS EXAMINED interrupted query execution, issue a warning,
      continue with normal processing and produce an incomplete query result.
    */
    bool saved_abort_on_warning= thd->abort_on_warning;
    thd->abort_on_warning= false;
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                        ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT,
                        ER_THD(thd, ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT),
                        thd->accessed_rows_and_keys,
                        thd->lex->limit_rows_examined->val_uint());
    thd->abort_on_warning= saved_abort_on_warning;
    thd->reset_killed();
  }
  /* Disable LIMIT ROWS EXAMINED after query execution. */
  thd->lex->limit_rows_examined_cnt= ULONGLONG_MAX;

  MYSQL_SELECT_DONE((int) res, (ulong) thd->limit_found_rows);
  DBUG_RETURN(res);
}

Project: server

int JOIN::optimize_stage2()
{
  ulonglong select_opts_for_readinfo;
  uint no_jbuf_after;
  JOIN_TAB *tab;
  DBUG_ENTER("JOIN::optimize_stage2");

  if (subq_exit_fl)
    goto setup_subq_exit;

  if (unlikely(thd->check_killed()))
    DBUG_RETURN(1);

  /* Generate an execution plan from the found optimal join order. */
  if (get_best_combination())
    DBUG_RETURN(1);

  if (make_range_rowid_filters())
    DBUG_RETURN(1);

  if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE))
    DBUG_RETURN(1);

  if (optimizer_flag(thd, OPTIMIZER_SWITCH_DERIVED_WITH_KEYS))
    drop_unused_derived_keys();

  if (rollup.state != ROLLUP::STATE_NONE)
  {
    if (rollup_process_const_fields())
    {
      DBUG_PRINT("error", ("Error: rollup_process_fields() failed"));
      DBUG_RETURN(1);
    }
  }
  else
  {
    /* Remove distinct if only const tables */
    select_distinct= select_distinct && (const_tables != table_count);
  }

  THD_STAGE_INFO(thd, stage_preparing);
  if (result->initialize_tables(this))
  {
    DBUG_PRINT("error",("Error: initialize_tables() failed"));
    DBUG_RETURN(1);				// error == -1
  }
  if (const_table_map != found_const_table_map &&
      !(select_options & SELECT_DESCRIBE))
  {
    // There is at least one empty const table
    zero_result_cause= "no matching row in const table";
    DBUG_PRINT("error",("Error: %s", zero_result_cause));
    error= 0;
    handle_implicit_grouping_with_window_funcs();
    goto setup_subq_exit;
  }
  if (!(thd->variables.option_bits & OPTION_BIG_SELECTS) &&
      best_read > (double) thd->variables.max_join_size &&
      !(select_options & SELECT_DESCRIBE))
  {						/* purecov: inspected */
    my_message(ER_TOO_BIG_SELECT, ER_THD(thd, ER_TOO_BIG_SELECT), MYF(0));
    error= -1;
    DBUG_RETURN(1);
  }
  if (const_tables && !thd->locked_tables_mode &&
      !(select_options & SELECT_NO_UNLOCK))
  {
    /*
      Unlock all tables, except sequences, as accessing these may still
      require table updates
    */
    mysql_unlock_some_tables(thd, table, const_tables,
                             GET_LOCK_SKIP_SEQUENCES);
  }
  if (!conds && outer_join)
  {
    /* Handle the case where we have an OUTER JOIN without a WHERE */
    conds= new (thd->mem_root) Item_bool(thd, true); // Always true
  }

  if (impossible_where)
  {
    zero_result_cause=
      "Impossible WHERE noticed after reading const tables";
    select_lex->mark_const_derived(zero_result_cause);
    handle_implicit_grouping_with_window_funcs();
    goto setup_subq_exit;
  }

  select= make_select(*table, const_table_map,
                      const_table_map, conds, (SORT_INFO*) 0, 1, &error);
  if (unlikely(error))
  {						/* purecov: inspected */
    error= -1;					/* purecov: inspected */
    DBUG_PRINT("error",("Error: make_select() failed"));
    DBUG_RETURN(1);
  }
  
  reset_nj_counters(this, join_list);
  if (make_outerjoin_info(this))
  {
    DBUG_RETURN(1);
  }

  /*
    Among the equal fields belonging to the same multiple equality
    choose the one that is to be retrieved first and substitute
    all references to these in where condition for a reference for
    the selected field.
  */
  if (conds)
  {
    conds= substitute_for_best_equal_field(thd, NO_PARTICULAR_TAB, conds,
                                           cond_equal, map2table, true);
    if (unlikely(thd->is_error()))
    {
      error= 1;
      DBUG_PRINT("error",("Error from substitute_for_best_equal"));
      DBUG_RETURN(1);
    }
    conds->update_used_tables();
    DBUG_EXECUTE("where",
                 print_where(conds,
                             "after substitute_best_equal",
                             QT_ORDINARY););
  }
  if (having)
  {
    having= substitute_for_best_equal_field(thd, NO_PARTICULAR_TAB, having,
                                            having_equal, map2table, false);
    if (thd->is_error())
    {
      error= 1;
      DBUG_PRINT("error",("Error from substitute_for_best_equal"));
      DBUG_RETURN(1);
    }
    if (having)
      having->update_used_tables();
    DBUG_EXECUTE("having",
                 print_where(having,
                             "after substitute_best_equal",
                             QT_ORDINARY););
  }

  /*
    Perform the optimization on fields evaluation mentioned above
    for all on expressions.
  */
  for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES); tab;
       tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
  {
    if (*tab->on_expr_ref)
    {
      *tab->on_expr_ref= substitute_for_best_equal_field(thd, NO_PARTICULAR_TAB,
                                                         *tab->on_expr_ref,
                                                         tab->cond_equal,
                                                         map2table, true);
      if (unlikely(thd->is_error()))
      {
        error= 1;
        DBUG_PRINT("error",("Error from substitute_for_best_equal"));
        DBUG_RETURN(1);
      }
      (*tab->on_expr_ref)->update_used_tables();
    }
  }

  /*
    Perform the optimization on fields evaliation mentioned above
    for all used ref items.
  */
  for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES); tab;
       tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
  {
    uint key_copy_index=0;
    for (uint i=0; i < tab->ref.key_parts; i++)
    {
      Item **ref_item_ptr= tab->ref.items+i;
      Item *ref_item= *ref_item_ptr;
      if (!ref_item->used_tables() && !(select_options & SELECT_DESCRIBE))
        continue;
      COND_EQUAL *equals= cond_equal;
      JOIN_TAB *first_inner= tab->first_inner;
      while (equals)
      {
        ref_item= substitute_for_best_equal_field(thd, tab, ref_item,
                                                  equals, map2table, true);
        if (unlikely(thd->is_fatal_error))
          DBUG_RETURN(1);

        if (first_inner)
	{
          equals= first_inner->cond_equal;
          first_inner= first_inner->first_upper;
        }
        else
          equals= 0;
      }  
      ref_item->update_used_tables();
      if (*ref_item_ptr != ref_item)
      {
        *ref_item_ptr= ref_item;
        Item *item= ref_item->real_item();
        store_key *key_copy= tab->ref.key_copy[key_copy_index];
        if (key_copy->type() == store_key::FIELD_STORE_KEY)
        {
          if (item->basic_const_item())
          {
            /* It is constant propagated here */
            tab->ref.key_copy[key_copy_index]=
              new store_key_const_item(*tab->ref.key_copy[key_copy_index],
                                       item);
          }
          else if (item->const_item())
	  {
            tab->ref.key_copy[key_copy_index]=
              new store_key_item(*tab->ref.key_copy[key_copy_index],
                                 item, TRUE);
          }            
          else
          {
            store_key_field *field_copy= ((store_key_field *)key_copy);
            DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
            field_copy->change_source_field((Item_field *) item);
          }
        }
      }
      key_copy_index++;
    }
  }

  if (conds && const_table_map != found_const_table_map &&
      (select_options & SELECT_DESCRIBE))
  {
    conds=new (thd->mem_root) Item_bool(thd, false); // Always false
  }

  /* Cache constant expressions in WHERE, HAVING, ON clauses. */
  cache_const_exprs();

  if (setup_semijoin_loosescan(this))
    DBUG_RETURN(1);

  if (make_join_select(this, select, conds))
  {
    zero_result_cause=
      "Impossible WHERE noticed after reading const tables";
    select_lex->mark_const_derived(zero_result_cause);
    handle_implicit_grouping_with_window_funcs();
    goto setup_subq_exit;
  }

  error= -1;					/* if goto err */

  /* Optimize distinct away if possible */
  {
    ORDER *org_order= order;
    order=remove_const(this, order,conds,1, &simple_order);
    if (unlikely(thd->is_error()))
    {
      error= 1;
      DBUG_RETURN(1);
    }

    /*
      If we are using ORDER BY NULL or ORDER BY const_expression,
      return result in any order (even if we are using a GROUP BY)
    */
    if (!order && org_order)
      skip_sort_order= 1;
  }
  /*
     Check if we can optimize away GROUP BY/DISTINCT.
     We can do that if there are no aggregate functions, the
     fields in DISTINCT clause (if present) and/or columns in GROUP BY
     (if present) contain direct references to all key parts of
     an unique index (in whatever order) and if the key parts of the
     unique index cannot contain NULLs.
     Note that the unique keys for DISTINCT and GROUP BY should not
     be the same (as long as they are unique).

     The FROM clause must contain a single non-constant table.
  */
  if (table_count - const_tables == 1 && (group || select_distinct) &&
      !tmp_table_param.sum_func_count &&
      (!join_tab[const_tables].select ||
       !join_tab[const_tables].select->quick ||
       join_tab[const_tables].select->quick->get_type() != 
       QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) &&
      !select_lex->have_window_funcs())
  {
    if (group && rollup.state == ROLLUP::STATE_NONE &&
       list_contains_unique_index(join_tab[const_tables].table,
                                 find_field_in_order_list,
                                 (void *) group_list))
    {
      /*
        We have found that grouping can be removed since groups correspond to
        only one row anyway, but we still have to guarantee correct result
        order. The line below effectively rewrites the query from GROUP BY
        <fields> to ORDER BY <fields>. There are three exceptions:
        - if skip_sort_order is set (see above), then we can simply skip
          GROUP BY;
        - if we are in a subquery, we don't have to maintain order unless there
	  is a limit clause in the subquery.
        - we can only rewrite ORDER BY if the ORDER BY fields are 'compatible'
          with the GROUP BY ones, i.e. either one is a prefix of another.
          We only check if the ORDER BY is a prefix of GROUP BY. In this case
          test_if_subpart() copies the ASC/DESC attributes from the original
          ORDER BY fields.
          If GROUP BY is a prefix of ORDER BY, then it is safe to leave
          'order' as is.
       */
      if (!order || test_if_subpart(group_list, order))
      {
        if (skip_sort_order ||
            (select_lex->master_unit()->item && select_limit == HA_POS_ERROR)) // This is a subquery
          order= NULL;
        else
          order= group_list;
      }
      /*
        If we have an IGNORE INDEX FOR GROUP BY(fields) clause, this must be 
        rewritten to IGNORE INDEX FOR ORDER BY(fields).
      */
      join_tab->table->keys_in_use_for_order_by=
        join_tab->table->keys_in_use_for_group_by;
      group_list= 0;
      group= 0;
    }
    if (select_distinct &&
       list_contains_unique_index(join_tab[const_tables].table,
                                 find_field_in_item_list,
                                 (void *) &fields_list))
    {
      select_distinct= 0;
    }
  }
  if (group || tmp_table_param.sum_func_count)
  {
    if (! hidden_group_fields && rollup.state == ROLLUP::STATE_NONE
        && !select_lex->have_window_funcs())
      select_distinct=0;
  }
  else if (select_distinct && table_count - const_tables == 1 &&
           rollup.state == ROLLUP::STATE_NONE &&
           !select_lex->have_window_funcs())
  {
    /*
      We are only using one table. In this case we change DISTINCT to a
      GROUP BY query if:
      - The GROUP BY can be done through indexes (no sort) and the ORDER
        BY only uses selected fields.
	(In this case we can later optimize away GROUP BY and ORDER BY)
      - We are scanning the whole table without LIMIT
        This can happen if:
        - We are using CALC_FOUND_ROWS
        - We are using an ORDER BY that can't be optimized away.

      We don't want to use this optimization when we are using LIMIT
      because in this case we can just create a temporary table that
      holds LIMIT rows and stop when this table is full.
    */
    bool all_order_fields_used;

    tab= &join_tab[const_tables];
    if (order)
    {
      skip_sort_order=
        test_if_skip_sort_order(tab, order, select_limit,
                                true,           // no_changes
                                &tab->table->keys_in_use_for_order_by);
    }
    if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array,
                                          order, fields_list, all_fields,
				          &all_order_fields_used)))
    {
      const bool skip_group=
        skip_sort_order &&
        test_if_skip_sort_order(tab, group_list, select_limit,
                                  true,         // no_changes
                                  &tab->table->keys_in_use_for_group_by);
      count_field_types(select_lex, &tmp_table_param, all_fields, 0);
      if ((skip_group && all_order_fields_used) ||
	  select_limit == HA_POS_ERROR ||
	  (order && !skip_sort_order))
      {
	/*  Change DISTINCT to GROUP BY */
	select_distinct= 0;
	no_order= !order;
	if (all_order_fields_used)
	{
	  if (order && skip_sort_order)
	  {
	    /*
	      Force MySQL to read the table in sorted order to get result in
	      ORDER BY order.
	    */
	    tmp_table_param.quick_group=0;
	  }
	  order=0;
        }
	group=1;				// For end_write_group
      }
      else
	group_list= 0;
    }
    else if (thd->is_fatal_error)			// End of memory
      DBUG_RETURN(1);
  }
  simple_group= rollup.state == ROLLUP::STATE_NONE;
  if (group)
  {
    /*
      Update simple_group and group_list as we now have more information, like
      which tables or columns are constant.
    */
    group_list= remove_const(this, group_list, conds,
                             rollup.state == ROLLUP::STATE_NONE,
                             &simple_group);
    if (unlikely(thd->is_error()))
    {
      error= 1;
      DBUG_RETURN(1);
    }
    if (!group_list)
    {
      /* The output has only one row */
      order=0;
      simple_order=1;
      select_distinct= 0;
      group_optimized_away= 1;
    }
  }

  calc_group_buffer(this, group_list);
  send_group_parts= tmp_table_param.group_parts; /* Save org parts */
  if (procedure && procedure->group)
  {
    group_list= procedure->group= remove_const(this, procedure->group, conds,
					       1, &simple_group);
    if (unlikely(thd->is_error()))
    {
      error= 1;
      DBUG_RETURN(1);
    }   
    calc_group_buffer(this, group_list);
  }

  if (test_if_subpart(group_list, order) ||
      (!group_list && tmp_table_param.sum_func_count))
  {
    order=0;
    if (is_indexed_agg_distinct(this, NULL))
      sort_and_group= 0;
  }

  // Can't use sort on head table if using join buffering
  if (full_join || hash_join)
  {
    TABLE *stable= (sort_by_table == (TABLE *) 1 ? 
      join_tab[const_tables].table : sort_by_table);
    /* 
      FORCE INDEX FOR ORDER BY can be used to prevent join buffering when
      sorting on the first table.
    */
    if (!stable || (!stable->force_index_order &&
                    !map2table[stable->tablenr]->keep_current_rowid))
    {
      if (group_list)
        simple_group= 0;
      if (order)
        simple_order= 0;
    }
  }

  need_tmp= test_if_need_tmp_table();

  /*
    If window functions are present then we can't have simple_order set to
    TRUE as the window function needs a temp table for computation.
    ORDER BY is computed after the window function computation is done, so
    the sort will be done on the temp table.
  */
  if (select_lex->have_window_funcs())
    simple_order= FALSE;


  /*
    If the hint FORCE INDEX FOR ORDER BY/GROUP BY is used for the table
    whose columns are required to be returned in a sorted order, then
    the proper value for no_jbuf_after should be yielded by a call to
    the make_join_orderinfo function.
    Yet the current implementation of FORCE INDEX hints does not
    allow us to do it in a clean manner.
  */
  no_jbuf_after= 1 ? table_count : make_join_orderinfo(this);

  // Don't use join buffering when we use MATCH
  select_opts_for_readinfo=
    (select_options & (SELECT_DESCRIBE | SELECT_NO_JOIN_CACHE)) |
    (select_lex->ftfunc_list->elements ?  SELECT_NO_JOIN_CACHE : 0);

  if (select_lex->options & OPTION_SCHEMA_TABLE &&
       optimize_schema_tables_reads(this))
    DBUG_RETURN(1);

  if (make_join_readinfo(this, select_opts_for_readinfo, no_jbuf_after))
    DBUG_RETURN(1);

  /* Perform FULLTEXT search before all regular searches */
  if (!(select_options & SELECT_DESCRIBE))
    if (init_ftfuncs(thd, select_lex, MY_TEST(order)))
      DBUG_RETURN(1);

  /*
    It's necessary to check const part of HAVING cond as
    there is a chance that some cond parts may become
    const items after make_join_statistics(for example
    when Item is a reference to cost table field from
    outer join).
    This check is performed only for those conditions
    which do not use aggregate functions. In such case
    temporary table may not be used and const condition
    elements may be lost during further having
    condition transformation in JOIN::exec.
  */
  if (having && const_table_map && !having->with_sum_func())
  {
    having->update_used_tables();
    having= having->remove_eq_conds(thd, &select_lex->having_value, true);
    if (select_lex->having_value == Item::COND_FALSE)
    {
      having= new (thd->mem_root) Item_bool(thd, false);
      zero_result_cause= "Impossible HAVING noticed after reading const tables";
      error= 0;
      select_lex->mark_const_derived(zero_result_cause);
      goto setup_subq_exit;
    }
  }

  if (optimize_unflattened_subqueries())
    DBUG_RETURN(1);
  
  int res;
  if ((res= rewrite_to_index_subquery_engine(this)) != -1)
    DBUG_RETURN(res);
  if (setup_subquery_caches())
    DBUG_RETURN(-1);

  /*
    Need to tell handlers that to play it safe, it should fetch all
    columns of the primary key of the tables: this is because MySQL may
    build row pointers for the rows, and for all columns of the primary key
    the read set has not necessarily been set by the server code.
  */
  if (need_tmp || select_distinct || group_list || order)
  {
    for (uint i= 0; i < table_count; i++)
    {
      if (!(table[i]->map & const_table_map))
        table[i]->prepare_for_position();
    }
  }

  DBUG_EXECUTE("info",TEST_join(this););

  if (!only_const_tables())
  {
     JOIN_TAB *tab= &join_tab[const_tables];

    if (order && !need_tmp)
    {
      /*
        Force using of tmp table if sorting by a SP or UDF function due to
        their expensive and probably non-deterministic nature.
      */
      for (ORDER *tmp_order= order; tmp_order ; tmp_order=tmp_order->next)
      {
        Item *item= *tmp_order->item;
        if (item->is_expensive())
        {
          /* Force tmp table without sort */
          need_tmp=1; simple_order=simple_group=0;
          break;
        }
      }
    }

    /*
      Because filesort always does a full table scan or a quick range scan
      we must add the removed reference to the select for the table.
      We only need to do this when we have a simple_order or simple_group
      as in other cases the join is done before the sort.
    */
    if ((order || group_list) &&
        tab->type != JT_ALL &&
        tab->type != JT_FT &&
        tab->type != JT_REF_OR_NULL &&
        ((order && simple_order) || (group_list && simple_group)))
    {
      if (add_ref_to_table_cond(thd,tab)) {
        DBUG_RETURN(1);
      }
    }
    /*
      Investigate whether we may use an ordered index as part of either
      DISTINCT, GROUP BY or ORDER BY execution. An ordered index may be
      used for only the first of any of these terms to be executed. This
      is reflected in the order which we check for test_if_skip_sort_order()
      below. However we do not check for DISTINCT here, as it would have
      been transformed to a GROUP BY at this stage if it is a candidate for 
      ordered index optimization.
      If a decision was made to use an ordered index, the availability
      of such an access path is stored in 'ordered_index_usage' for later
      use by 'execute' or 'explain'
    */
    DBUG_ASSERT(ordered_index_usage == ordered_index_void);

    if (group_list)   // GROUP BY honoured first
                      // (DISTINCT was rewritten to GROUP BY if skippable)
    {
      /*
        When there is SQL_BIG_RESULT do not sort using index for GROUP BY,
        and thus force sorting on disk unless a group min-max optimization
        is going to be used as it is applied now only for one table queries
        with covering indexes.
      */
      if (!(select_options & SELECT_BIG_RESULT) ||
            (tab->select &&
             tab->select->quick &&
             tab->select->quick->get_type() ==
             QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX))
      {
        if (simple_group &&              // GROUP BY is possibly skippable
            !select_distinct)            // .. if not preceded by a DISTINCT
        {
          /*
            Calculate a possible 'limit' of table rows for 'GROUP BY':
            A specified 'LIMIT' is relative to the final resultset.
            'need_tmp' implies that there will be more postprocessing 
            so the specified 'limit' should not be enforced yet.
           */
          const ha_rows limit = need_tmp ? HA_POS_ERROR : select_limit;
          if (test_if_skip_sort_order(tab, group_list, limit, false, 
                                      &tab->table->keys_in_use_for_group_by))
          {
            ordered_index_usage= ordered_index_group_by;
          }
        }

	/*
	  If we are going to use semi-join LooseScan, it will depend
	  on the selected index scan to be used.  If index is not used
	  for the GROUP BY, we risk that sorting is put on the LooseScan
	  table.  In order to avoid this, force use of temporary table.
	  TODO: Explain the quick_group part of the test below.
	 */
        if ((ordered_index_usage != ordered_index_group_by) &&
            ((tmp_table_param.quick_group && !procedure) || 
	     (tab->emb_sj_nest && 
	      best_positions[const_tables].sj_strategy == SJ_OPT_LOOSE_SCAN)))
        {
          need_tmp=1;
          simple_order= simple_group= false; // Force tmp table without sort
        }
      }
    }
    else if (order &&                      // ORDER BY wo/ preceding GROUP BY
             (simple_order || skip_sort_order)) // which is possibly skippable
    {
      if (test_if_skip_sort_order(tab, order, select_limit, false, 
                                  &tab->table->keys_in_use_for_order_by))
      {
        ordered_index_usage= ordered_index_order_by;
      }
    }
  }

  if (having)
    having_is_correlated= MY_TEST(having->used_tables() & OUTER_REF_TABLE_BIT);
  tmp_having= having;

  if (unlikely(thd->is_error()))
    DBUG_RETURN(TRUE);

  /*
    The loose index scan access method guarantees that all grouping or
    duplicate row elimination (for distinct) is already performed
    during data retrieval, and that all MIN/MAX functions are already
    computed for each group. Thus all MIN/MAX functions should be
    treated as regular functions, and there is no need to perform
    grouping in the main execution loop.
    Notice that currently loose index scan is applicable only for
    single table queries, thus it is sufficient to test only the first
    join_tab element of the plan for its access method.
  */
  if (join_tab->is_using_loose_index_scan())
  {
    tmp_table_param.precomputed_group_by= TRUE;
    if (join_tab->is_using_agg_loose_index_scan())
    {
      need_distinct= FALSE;
      tmp_table_param.precomputed_group_by= FALSE;
    }
  }

  if (make_aggr_tables_info())
    DBUG_RETURN(1);

  if (init_join_caches())
    DBUG_RETURN(1);

  if (init_range_rowid_filters())
    DBUG_RETURN(1);

  error= 0;

  if (select_options & SELECT_DESCRIBE)
    goto derived_exit;

  DBUG_RETURN(0);

setup_subq_exit:
  /* Choose an execution strategy for this JOIN. */
  if (!tables_list || !table_count)
  {
    choose_tableless_subquery_plan();

    /* The output has atmost one row */
    if (group_list)
    {
      group_list= NULL;
      group_optimized_away= 1;
      rollup.state= ROLLUP::STATE_NONE;
    }
    order= NULL;
    simple_order= TRUE;
    select_distinct= FALSE;

    if (select_lex->have_window_funcs())
    {
      if (!(join_tab= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB))))
        DBUG_RETURN(1);
      need_tmp= 1;
    }
    if (make_aggr_tables_info())
      DBUG_RETURN(1);

    /*
      It could be that we've only done optimization stage 1 for
      some of the derived tables, and never did stage 2.
      Do it now, otherwise Explain data structure will not be complete.
    */
    if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE))
      DBUG_RETURN(1);
  }
  /*
    Even with zero matching rows, subqueries in the HAVING clause may
    need to be evaluated if there are aggregate functions in the query.
  */
  if (optimize_unflattened_subqueries())
    DBUG_RETURN(1);
  error= 0;

derived_exit:

  select_lex->mark_const_derived(zero_result_cause);
  DBUG_RETURN(0);
}

Project: server

evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
                     int error)
{
  bool shortcut_for_distinct= join_tab->shortcut_for_distinct;
  ha_rows found_records=join->found_records;
  COND *select_cond= join_tab->select_cond;
  bool select_cond_result= TRUE;

  DBUG_ENTER("evaluate_join_record");
  DBUG_PRINT("enter",
             ("evaluate_join_record join: %p join_tab: %p"
              " cond: %p error: %d  alias %s",
              join, join_tab, select_cond, error,
              join_tab->table->alias.ptr()));

  if (error > 0 || unlikely(join->thd->is_error())) // Fatal error
    DBUG_RETURN(NESTED_LOOP_ERROR);
  if (error < 0)
    DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
  if (unlikely(join->thd->check_killed()))       // Aborted by user
  {
    DBUG_RETURN(NESTED_LOOP_KILLED);            /* purecov: inspected */
  }

  join_tab->tracker->r_rows++;

  if (select_cond)
  {
    select_cond_result= MY_TEST(select_cond->val_int());

    /* check for errors evaluating the condition */
    if (unlikely(join->thd->is_error()))
      DBUG_RETURN(NESTED_LOOP_ERROR);
  }

  if (!select_cond || select_cond_result)
  {
    /*
      There is no select condition or the attached pushed down
      condition is true => a match is found.
    */
    join_tab->tracker->r_rows_after_where++;

    bool found= 1;
    while (join_tab->first_unmatched && found)
    {
      /*
        The while condition is always false if join_tab is not
        the last inner join table of an outer join operation.
      */
      JOIN_TAB *first_unmatched= join_tab->first_unmatched;
      /*
        Mark that a match for current outer table is found.
        This activates push down conditional predicates attached
        to the all inner tables of the outer join.
      */
      first_unmatched->found= 1;
      for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++)
      {
        /*
          Check whether 'not exists' optimization can be used here.
          If  tab->table->reginfo.not_exists_optimize is set to true
          then WHERE contains a conjunctive predicate IS NULL over
          a non-nullable field of tab. When activated this predicate
          will filter out all records with matches for the left part
          of the outer join whose inner tables start from the
          first_unmatched table and include table tab. To safely use
          'not exists' optimization we have to check that the
          IS NULL predicate is really activated, i.e. all guards
          that wrap it are in the 'open' state. 
	*/  
	bool not_exists_opt_is_applicable=
               tab->table->reginfo.not_exists_optimize;
	for (JOIN_TAB *first_upper= first_unmatched->first_upper;
             not_exists_opt_is_applicable && first_upper;
             first_upper= first_upper->first_upper)
        {
          if (!first_upper->found)
            not_exists_opt_is_applicable= false;
        }
        /* Check all predicates that has just been activated. */
        /*
          Actually all predicates non-guarded by first_unmatched->found
          will be re-evaluated again. It could be fixed, but, probably,
          it's not worth doing now.
        */
        if (tab->select_cond)
        {
          const longlong res= tab->select_cond->val_int();
          if (join->thd->is_error())
            DBUG_RETURN(NESTED_LOOP_ERROR);

          if (!res)
          {
            /* The condition attached to table tab is false */
            if (tab == join_tab)
            {
              found= 0;
              if (not_exists_opt_is_applicable)
                DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
            }
            else
            {
              /*
                Set a return point if rejected predicate is attached
                not to the last table of the current nest level.
              */
              join->return_tab= tab;
              if (not_exists_opt_is_applicable)
                DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
              else
                DBUG_RETURN(NESTED_LOOP_OK);
            }
          }
        }
      }
      /*
        Check whether join_tab is not the last inner table
        for another embedding outer join.
      */
      if ((first_unmatched= first_unmatched->first_upper) &&
          first_unmatched->last_inner != join_tab)
        first_unmatched= 0;
      join_tab->first_unmatched= first_unmatched;
    }

    JOIN_TAB *return_tab= join->return_tab;
    join_tab->found_match= TRUE;

    if (join_tab->check_weed_out_table && found)
    {
      int res= join_tab->check_weed_out_table->sj_weedout_check_row(join->thd);
      DBUG_PRINT("info", ("weedout_check: %d", res));
      if (res == -1)
        DBUG_RETURN(NESTED_LOOP_ERROR);
      else if (res == 1)
        found= FALSE;
    }
    else if (join_tab->do_firstmatch)
    {
      /* 
        We should return to the join_tab->do_firstmatch after we have 
        enumerated all the suffixes for current prefix row combination
      */
      return_tab= join_tab->do_firstmatch;
    }

    /*
      It was not just a return to lower loop level when one
      of the newly activated predicates is evaluated as false
      (See above join->return_tab= tab).
    */
    join->join_examined_rows++;
    DBUG_PRINT("counts", ("join->examined_rows++: %lu  found: %d",
                          (ulong) join->join_examined_rows, (int) found));

    if (found)
    {
      enum enum_nested_loop_state rc;
      /* A match from join_tab is found for the current partial join. */
      rc= (*join_tab->next_select)(join, join_tab+1, 0);
      join->thd->get_stmt_da()->inc_current_row_for_warning();
      if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
        DBUG_RETURN(rc);
      if (return_tab < join->return_tab)
        join->return_tab= return_tab;

      /* check for errors evaluating the condition */
      if (unlikely(join->thd->is_error()))
        DBUG_RETURN(NESTED_LOOP_ERROR);

      if (join->return_tab < join_tab)
        DBUG_RETURN(NESTED_LOOP_OK);
      /*
        Test if this was a SELECT DISTINCT query on a table that
        was not in the field list;  In this case we can abort if
        we found a row, as no new rows can be added to the result.
      */
      if (shortcut_for_distinct && found_records != join->found_records)
        DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);

      DBUG_RETURN(NESTED_LOOP_OK);
    }
  }
  else
  {
    /*
      The condition pushed down to the table join_tab rejects all rows
      with the beginning coinciding with the current partial join.
    */
    join->join_examined_rows++;
  }

  join->thd->get_stmt_da()->inc_current_row_for_warning();
  join_tab->read_record.unlock_row(join_tab);

  DBUG_RETURN(NESTED_LOOP_OK);
}

Project: server

mysql_select(THD *thd,
	     TABLE_LIST *tables, uint wild_num, List<Item> &fields,
	     COND *conds, uint og_num,  ORDER *order, ORDER *group,
	     Item *having, ORDER *proc_param, ulonglong select_options,
	     select_result *result, SELECT_LEX_UNIT *unit,
	     SELECT_LEX *select_lex)
{
  int err= 0;
  bool free_join= 1;
  DBUG_ENTER("mysql_select");

  if (!fields.is_empty())
    select_lex->context.resolve_in_select_list= true;
  JOIN *join;
  if (select_lex->join != 0)
  {
    join= select_lex->join;
    /*
      is it single SELECT in derived table, called in derived table
      creation
    */
    if (select_lex->get_linkage() != DERIVED_TABLE_TYPE ||
	(select_options & SELECT_DESCRIBE))
    {
      if (select_lex->get_linkage() != GLOBAL_OPTIONS_TYPE)
      {
        /*
          Original join tabs might be overwritten at first
          subselect execution. So we need to restore them.
        */
        Item_subselect *subselect= select_lex->master_unit()->item;
        if (subselect && subselect->is_uncacheable() && join->reinit())
          DBUG_RETURN(TRUE);
      }
      else
      {
        if ((err= join->prepare( tables, wild_num,
                                conds, og_num, order, false, group, having,
                                proc_param, select_lex, unit)))
	{
	  goto err;
	}
      }
    }
    free_join= 0;
    join->select_options= select_options;
  }
  else
  {
    if (thd->lex->describe)
      select_options|= SELECT_DESCRIBE;

    /*
      When in EXPLAIN, delay deleting the joins so that they are still
      available when we're producing EXPLAIN EXTENDED warning text.
    */
    if (select_options & SELECT_DESCRIBE)
      free_join= 0;

    if (!(join= new (thd->mem_root) JOIN(thd, fields, select_options, result)))
	DBUG_RETURN(TRUE);
    THD_STAGE_INFO(thd, stage_init);
    thd->lex->used_tables=0;
    if ((err= join->prepare(tables, wild_num,
                            conds, og_num, order, false, group, having, proc_param,
                            select_lex, unit)))
    {
      goto err;
    }
  }

  /* Look for a table owned by an engine with the select_handler interface */
  select_lex->select_h= select_lex->find_select_handler(thd);
  if (select_lex->select_h)
  {
    /* Create a Pushdown_select object for later execution of the query */
    if (!(select_lex->pushdown_select=
      new (thd->mem_root) Pushdown_select(select_lex,
                                          select_lex->select_h)))
    {
      delete select_lex->select_h;
      select_lex->select_h= NULL;
      DBUG_RETURN(TRUE);
    }
  }

  if ((err= join->optimize()))
  {
    goto err;					// 1
  }

  if (thd->lex->describe & DESCRIBE_EXTENDED)
  {
    join->conds_history= join->conds;
    join->having_history= (join->having?join->having:join->tmp_having);
  }

  if (unlikely(thd->is_error()))
    goto err;

  join->exec();

  if (thd->lex->describe & DESCRIBE_EXTENDED)
  {
    select_lex->where= join->conds_history;
    select_lex->having= join->having_history;
  }

err:

  if (select_lex->pushdown_select)
  {
    delete select_lex->pushdown_select;
    select_lex->pushdown_select= NULL;
  }

  if (free_join)
  {
    THD_STAGE_INFO(thd, stage_end);
    err|= (int)(select_lex->cleanup());
    DBUG_RETURN(err || thd->is_error());
  }
  DBUG_RETURN(join->error ? join->error: err);
}

Project: server

optimize_cond(JOIN *join, COND *conds,
              List<TABLE_LIST> *join_list, bool ignore_on_conds,
              Item::cond_result *cond_value, COND_EQUAL **cond_equal,
              int flags)
{
  THD *thd= join->thd;
  DBUG_ENTER("optimize_cond");

  if (!conds)
  {
    *cond_value= Item::COND_TRUE;
    if (!ignore_on_conds)
      build_equal_items(join, NULL, NULL, join_list, ignore_on_conds,
                        cond_equal);
  }  
  else
  {
    /* 
      Build all multiple equality predicates and eliminate equality
      predicates that can be inferred from these multiple equalities.
      For each reference of a field included into a multiple equality
      that occurs in a function set a pointer to the multiple equality
      predicate. Substitute a constant instead of this field if the
      multiple equality contains a constant.
    */

    Json_writer_object trace_wrapper(thd);
    Json_writer_object trace_cond(thd, "condition_processing");
    trace_cond.add("condition", join->conds == conds ? "WHERE" : "HAVING")
              .add("original_condition", conds);

    Json_writer_array trace_steps(thd, "steps");
    DBUG_EXECUTE("where", print_where(conds, "original", QT_ORDINARY););
    conds= build_equal_items(join, conds, NULL, join_list, 
                             ignore_on_conds, cond_equal,
                             MY_TEST(flags & OPT_LINK_EQUAL_FIELDS));
    DBUG_EXECUTE("where",print_where(conds,"after equal_items", QT_ORDINARY););
    {
      Json_writer_object equal_prop_wrapper(thd);
      equal_prop_wrapper.add("transformation", "equality_propagation")
                        .add("resulting_condition", conds);
    }

    /* change field = field to field = const for each found field = const */
    propagate_cond_constants(thd, (I_List<COND_CMP> *) 0, conds, conds);
    /*
      Remove all instances of item == item
      Remove all and-levels where CONST item != CONST item
    */
    DBUG_EXECUTE("where",print_where(conds,"after const change", QT_ORDINARY););
    {
      Json_writer_object const_prop_wrapper(thd);
      const_prop_wrapper.add("transformation", "constant_propagation")
                        .add("resulting_condition", conds);
    }
    conds= conds->remove_eq_conds(thd, cond_value, true);
    if (conds && conds->type() == Item::COND_ITEM &&
        ((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
      *cond_equal= &((Item_cond_and*) conds)->m_cond_equal;

    {
      Json_writer_object cond_removal_wrapper(thd);
      cond_removal_wrapper.add("transformation", "trivial_condition_removal")
                          .add("resulting_condition", conds);
    }
    DBUG_EXECUTE("info",print_where(conds,"after remove", QT_ORDINARY););
  }
  DBUG_RETURN(conds);
}

Project: server

bool Virtual_tmp_table::sp_set_all_fields_from_item(THD *thd, Item *value)
{
  DBUG_ASSERT(value->is_fixed());
  DBUG_ASSERT(value->cols() == s->fields);
  for (uint i= 0; i < value->cols(); i++)
  {
    if (field[i]->sp_prepare_and_store_item(thd, value->addr(i)))
      return true;
  }
  return false;
}

Project: server

double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
                              table_map rem_tables)
{
  uint16 ref_keyuse_steps_buf[MAX_REF_PARTS];
  uint   ref_keyuse_size= MAX_REF_PARTS;
  uint16 *ref_keyuse_steps= ref_keyuse_steps_buf;
  Field *field;
  TABLE *table= s->table;
  MY_BITMAP *read_set= table->read_set;
  double sel= s->table->cond_selectivity;
  POSITION *pos= &join->positions[idx];
  uint keyparts= 0;
  uint found_part_ref_or_null= 0;

  if (pos->key != 0)
  {
    /* 
      A ref access or hash join is used for this table. ref access is created
      from

        tbl.keypart1=expr1 AND tbl.keypart2=expr2 AND ...
      
      and it will only return rows for which this condition is satisified.
      Suppose, certain expr{i} is a constant. Since ref access only returns
      rows that satisfy
        
         tbl.keypart{i}=const       (*)

      then selectivity of this equality should not be counted in return value 
      of this function. This function uses the value of 
       
         table->cond_selectivity=selectivity(COND(tbl)) (**)
      
      as a starting point. This value includes selectivity of equality (*). We
      should somehow discount it. 
      
      Looking at calculate_cond_selectivity_for_table(), one can see that that
      the value is not necessarily a direct multiplicand in 
      table->cond_selectivity

      There are three possible ways to discount
      1. There is a potential range access on t.keypart{i}=const. 
         (an important special case: the used ref access has a const prefix for
          which a range estimate is available)
      
      2. The field has a histogram. field[x]->cond_selectivity has the data.
      
      3. Use index stats on this index:
         rec_per_key[key_part+1]/rec_per_key[key_part]

      (TODO: more details about the "t.key=othertable.col" case)
    */
    KEYUSE *keyuse= pos->key;
    KEYUSE *prev_ref_keyuse= keyuse;
    uint key= keyuse->key;
    bool used_range_selectivity= false;
    
    /*
      Check if we have a prefix of key=const that matches a quick select.
    */
    if (!is_hash_join_key_no(key) && table->quick_keys.is_set(key))
    {
      key_part_map quick_key_map= (key_part_map(1) << table->quick_key_parts[key]) - 1;
      if (table->quick_rows[key] && 
          !(quick_key_map & ~table->const_key_parts[key]))
      {
        /* 
          Ok, there is an equality for each of the key parts used by the
          quick select. This means, quick select's estimate can be reused to
          discount the selectivity of a prefix of a ref access.
        */
        for (; quick_key_map & 1 ; quick_key_map>>= 1)
        {
          while (keyuse->table == table && keyuse->key == key && 
                 keyuse->keypart == keyparts)
          {
            keyuse++;
          }
          keyparts++;
        }
        /*
          Here we discount selectivity of the constant range CR. To calculate
          this selectivity we use elements from the quick_rows[] array.
          If we have indexes i1,...,ik with the same prefix compatible
          with CR any of the estimate quick_rows[i1], ... quick_rows[ik] could
          be used for this calculation but here we don't know which one was
          actually used. So sel could be greater than 1 and we have to cap it.
          However if sel becomes greater than 2 then with high probability
          something went wrong.
	*/
        sel /= (double)table->quick_rows[key] / (double) table->stat_records();
        set_if_smaller(sel, 1.0);
        used_range_selectivity= true;
      }
    }
    
    /*
      Go through the "keypart{N}=..." equalities and find those that were
      already taken into account in table->cond_selectivity.
    */
    keyuse= pos->key;
    keyparts=0;
    while (keyuse->table == table && keyuse->key == key)
    {
      if (!(keyuse->used_tables & (rem_tables | table->map)))
      {
        if (are_tables_local(s, keyuse->val->used_tables()))
	{
          if (is_hash_join_key_no(key))
	  {
            if (keyparts == keyuse->keypart)
              keyparts++;
          }
          else
	  {
            if (keyparts == keyuse->keypart &&
                !((keyuse->val->used_tables()) & ~pos->ref_depend_map) &&
                !(found_part_ref_or_null & keyuse->optimize))
	    {
              /* Found a KEYUSE object that will be used by ref access */
              keyparts++;
              found_part_ref_or_null|= keyuse->optimize & ~KEY_OPTIMIZE_EQ;
            }
          }

          if (keyparts > keyuse->keypart)
	  {
            /* Ok this is the keyuse that will be used for ref access */
            if (!used_range_selectivity && keyuse->val->const_item())
            { 
              uint fldno;
              if (is_hash_join_key_no(key))
                fldno= keyuse->keypart;
              else
                fldno= table->key_info[key].key_part[keyparts-1].fieldnr - 1;

              if (table->field[fldno]->cond_selectivity > 0)
              {
                sel /= table->field[fldno]->cond_selectivity;
                set_if_smaller(sel, 1.0);
              }
              /* 
               TODO: we could do better here:
                 1. cond_selectivity might be =1 (the default) because quick 
                    select on some index prevented us from analyzing 
                    histogram for this column.
                 2. we could get an estimate through this?
                     rec_per_key[key_part-1] / rec_per_key[key_part]
              */
            }
            if (keyparts > 1)
	    {
              /*
                Prepare to set ref_keyuse_steps[keyparts-2]: resize the array
                if it is not large enough
              */
              if (keyparts - 2 >= ref_keyuse_size)
              {
                uint new_size= MY_MAX(ref_keyuse_size*2, keyparts);
                void *new_buf;
                if (!(new_buf= my_malloc(sizeof(*ref_keyuse_steps)*new_size,
                                         MYF(0))))
                {
                  sel= 1.0; // As if no selectivity was computed
                  goto exit;
                }
                memcpy(new_buf, ref_keyuse_steps,
                       sizeof(*ref_keyuse_steps)*ref_keyuse_size);
                if (ref_keyuse_steps != ref_keyuse_steps_buf)
                  my_free(ref_keyuse_steps);

                ref_keyuse_steps= (uint16*)new_buf;
                ref_keyuse_size= new_size;
              }

              ref_keyuse_steps[keyparts-2]= (uint16)(keyuse - prev_ref_keyuse);
              prev_ref_keyuse= keyuse;
            }
          }
	}
      }
      keyuse++;
    }
  }
  else
  {
    /*
      The table is accessed with full table scan, or quick select.
      Selectivity of COND(table) is already accounted for in 
      matching_candidates_in_table().
    */
    sel= 1;
  }

  /* 
    If the field f from the table is equal to a field from one the
    earlier joined tables then the selectivity of the range conditions
    over the field f must be discounted.

    We need to discount selectivity only if we're using ref-based 
    access method (and have sel!=1).
    If we use ALL/range/index_merge, then sel==1, and no need to discount.
  */
  if (pos->key != NULL)
  {
    for (Field **f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
    {
      if (!bitmap_is_set(read_set, field->field_index) ||
          !field->next_equal_field)
        continue; 
      for (Field *next_field= field->next_equal_field; 
           next_field != field; 
           next_field= next_field->next_equal_field)
      {
        if (!(next_field->table->map & rem_tables) && next_field->table != table)
        {
          if (field->cond_selectivity > 0)
          {
            sel/= field->cond_selectivity;
            set_if_smaller(sel, 1.0);
          }
          break;
        }
      }
    }
  }

  sel*= table_multi_eq_cond_selectivity(join, idx, s, rem_tables,
                                        keyparts, ref_keyuse_steps);
exit:
  if (ref_keyuse_steps != ref_keyuse_steps_buf)
    my_free(ref_keyuse_steps);
  return sel;
}

Project: server

void JOIN::join_free()
{
  SELECT_LEX_UNIT *tmp_unit;
  SELECT_LEX *sl;
  /*
    Optimization: if not EXPLAIN and we are done with the JOIN,
    free all tables.
  */
  bool full= !(select_lex->uncacheable) &&  !(thd->lex->describe);
  bool can_unlock= full;
  DBUG_ENTER("JOIN::join_free");

  cleanup(full);

  for (tmp_unit= select_lex->first_inner_unit();
       tmp_unit;
       tmp_unit= tmp_unit->next_unit())
  {
    if (tmp_unit->with_element && tmp_unit->with_element->is_recursive)
      continue;
    for (sl= tmp_unit->first_select(); sl; sl= sl->next_select())
    {
      Item_subselect *subselect= sl->master_unit()->item;
      bool full_local= full && (!subselect || subselect->is_evaluated());
      /*
        If this join is evaluated, we can fully clean it up and clean up all
        its underlying joins even if they are correlated -- they will not be
        used any more anyway.
        If this join is not yet evaluated, we still must clean it up to
        close its table cursors -- it may never get evaluated, as in case of
        ... HAVING FALSE OR a IN (SELECT ...))
        but all table cursors must be closed before the unlock.
      */
      sl->cleanup_all_joins(full_local);
      /* Can't unlock if at least one JOIN is still needed */
      can_unlock= can_unlock && full_local;
    }
  }
  /*
    We are not using tables anymore
    Unlock all tables. We may be in an INSERT .... SELECT statement.
  */
  if (can_unlock && lock && thd->lock && ! thd->locked_tables_mode &&
      !(select_options & SELECT_NO_UNLOCK) &&
      !select_lex->subquery_in_having &&
      (select_lex == (thd->lex->unit.fake_select_lex ?
                      thd->lex->unit.fake_select_lex :
                      thd->lex->first_select_lex())))
  {
    /*
      TODO: unlock tables even if the join isn't top level select in the
      tree.
    */
    mysql_unlock_read_tables(thd, lock);           // Don't free join->lock
    lock= 0;
  }

  DBUG_VOID_RETURN;
}

Project: server

static void trace_table_dependencies(THD *thd,
                                     JOIN_TAB *join_tabs, uint table_count)
{
  DBUG_ASSERT(thd->trace_started());
  Json_writer_object trace_wrapper(thd);
  Json_writer_array trace_dep(thd, "table_dependencies");

  for (uint i= 0; i < table_count; i++)
  {
    TABLE_LIST *table_ref= join_tabs[i].tab_list;
    Json_writer_object trace_one_table(thd);
    trace_one_table.add_table_name(&join_tabs[i]);
    trace_one_table.add("row_may_be_null",
                       (bool)table_ref->table->maybe_null);
    const table_map map= table_ref->get_map();
    DBUG_ASSERT(map < (1ULL << table_count));
    for (uint j= 0; j < table_count; j++)
    {
      if (map & (1ULL << j))
      {
        trace_one_table.add("map_bit", j);
        break;
      }
    }
    Json_writer_array depends_on(thd, "depends_on_map_bits");
    Table_map_iterator it(join_tabs[i].dependent);
    uint dep_bit;
    while ((dep_bit= it++) != Table_map_iterator::BITMAP_END)
       depends_on.add(static_cast<longlong>(dep_bit));
  }
}

Project: server

static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
				   Item *having)
{
  handler *file=table->file;
  uchar *record=table->record[0];
  int error;
  DBUG_ENTER("remove_dup_with_compare");

  if (unlikely(file->ha_rnd_init_with_error(1)))
    DBUG_RETURN(1);

  error= file->ha_rnd_next(record);
  for (;;)
  {
    if (unlikely(thd->check_killed()))
    {
      error=0;
      goto err;
    }
    if (unlikely(error))
    {
      if (error == HA_ERR_END_OF_FILE)
	break;
      goto err;
    }
    if (having && !having->val_int())
    {
      if (unlikely((error= file->ha_delete_row(record))))
	goto err;
      error= file->ha_rnd_next(record);
      continue;
    }
    if (unlikely(copy_blobs(first_field)))
    {
      my_message(ER_OUTOFMEMORY, ER_THD(thd,ER_OUTOFMEMORY),
                 MYF(ME_FATAL));
      error=0;
      goto err;
    }
    store_record(table,record[1]);

    /* Read through rest of file and mark duplicated rows deleted */
    bool found=0;
    for (;;)
    {
      if (unlikely((error= file->ha_rnd_next(record))))
      {
	if (error == HA_ERR_END_OF_FILE)
	  break;
	goto err;
      }
      if (compare_record(table, first_field) == 0)
      {
	if (unlikely((error= file->ha_delete_row(record))))
	  goto err;
      }
      else if (!found)
      {
	found=1;
        if (unlikely((error= file->remember_rnd_pos())))
          goto err;
      }
    }
    if (!found)
      break;					// End of file
    /* Restart search on saved row */
    if (unlikely((error= file->restart_rnd_next(record))))
      goto err;
  }

  file->extra(HA_EXTRA_NO_CACHE);
  (void) file->ha_rnd_end();
  DBUG_RETURN(0);
err:
  file->extra(HA_EXTRA_NO_CACHE);
  (void) file->ha_rnd_end();
  if (error)
    file->print_error(error,MYF(0));
  DBUG_RETURN(1);
}

Project: server

void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab, 
                                table_map last_remaining_tables, 
                                bool first_alt, uint no_jbuf_before,
                                double *outer_rec_count, double *reopt_cost)
{
  double cost, rec_count;
  table_map reopt_remaining_tables= last_remaining_tables;
  uint i;
  THD *thd= join->thd;
  Json_writer_temp_disable trace_wo_join_buffering(thd);

  if (first_tab > join->const_tables)
  {
    cost=      join->positions[first_tab - 1].prefix_cost.total_cost();
    rec_count= join->positions[first_tab - 1].prefix_record_count;
  }
  else
  {
    cost= 0.0;
    rec_count= 1;
  }

  *outer_rec_count= rec_count;
  for (i= first_tab; i <= last_tab; i++)
    reopt_remaining_tables |= join->positions[i].table->table->map;
  
  /*
    best_access_path() optimization depends on the value of 
    join->cur_sj_inner_tables. Our goal in this function is to do a
    re-optimization with disabled join buffering, but no other changes.
    In order to achieve this, cur_sj_inner_tables needs have the same 
    value it had during the original invocations of best_access_path. 

    We know that this function, optimize_wo_join_buffering() is called to
    re-optimize semi-join join order range, which allows to conclude that 
    the "original" value of cur_sj_inner_tables was 0.
  */
  table_map save_cur_sj_inner_tables= join->cur_sj_inner_tables;
  join->cur_sj_inner_tables= 0;

  for (i= first_tab; i <= last_tab; i++)
  {
    JOIN_TAB *rs= join->positions[i].table;
    POSITION pos, loose_scan_pos;

    if ((i == first_tab && first_alt) || join->positions[i].use_join_buffer)
    {
      /* Find the best access method that would not use join buffering */
      best_access_path(join, rs, reopt_remaining_tables,
                       join->positions, i,
                       TRUE, rec_count,
                       &pos, &loose_scan_pos);
    }
    else 
      pos= join->positions[i];

    if ((i == first_tab && first_alt))
      pos= loose_scan_pos;

    reopt_remaining_tables &= ~rs->table->map;
    rec_count= COST_MULT(rec_count, pos.records_read);
    cost= COST_ADD(cost, pos.read_time);
    cost= COST_ADD(cost, rec_count / (double) TIME_FOR_COMPARE);
    //TODO: take into account join condition selectivity here
    double pushdown_cond_selectivity= 1.0;
    table_map real_table_bit= rs->table->map;
    if (join->thd->variables.optimizer_use_condition_selectivity > 1)
    {
      pushdown_cond_selectivity= table_cond_selectivity(join, i, rs,
                                                        reopt_remaining_tables &
                                                        ~real_table_bit);
    }
    (*outer_rec_count) *= pushdown_cond_selectivity;
    if (!rs->emb_sj_nest)
      *outer_rec_count= COST_MULT(*outer_rec_count, pos.records_read);

  }
  join->cur_sj_inner_tables= save_cur_sj_inner_tables;

  *reopt_cost= cost;
}