best_extension_by_limited_search(JOIN      *join,
                                 table_map remaining_tables,
                                 uint      idx,
                                 double    record_count,
                                 double    read_time,
                                 uint      search_depth,
                                 uint      prune_level,
                                 uint      use_cond_selectivity)
{
  DBUG_ENTER("best_extension_by_limited_search");

  THD *thd= join->thd;

  DBUG_EXECUTE_IF("show_explain_probe_best_ext_lim_search",
                  if (dbug_user_var_equals_int(thd,
                                               "show_explain_probe_select_id",
                                               join->select_lex->select_number))
                        dbug_serve_apcs(thd, 1);
                 );

  if (unlikely(thd->check_killed()))  // Abort
    DBUG_RETURN(TRUE);

  DBUG_EXECUTE("opt", print_plan(join, idx, read_time, record_count, idx,
                                 "SOFAR:"););

  /*
     'join' is a partial plan with lower cost than the best plan so far,
     so continue expanding it further with the tables in 'remaining_tables'.
  */
  JOIN_TAB *s;
  double best_record_count= DBL_MAX;
  double best_read_time=    DBL_MAX;
  bool disable_jbuf= join->thd->variables.join_cache_level == 0;

  DBUG_EXECUTE("opt", print_plan(join, idx, record_count, read_time, read_time,
                                "part_plan"););

  /*
    If we are searching for the execution plan of a materialized semi-join nest
    then allowed_tables contains bits only for the tables from this nest.
  */
  table_map allowed_tables= ~(table_map)0;
  if (join->emb_sjm_nest)
    allowed_tables= join->emb_sjm_nest->sj_inner_tables & ~join->const_table_map;

  for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
  {
    table_map real_table_bit= s->table->map;
    if ((remaining_tables & real_table_bit) &&
        (allowed_tables & real_table_bit) &&
        !(remaining_tables & s->dependent) &&
        (!idx || !check_interleaving_with_nj(s)))
    {
      double current_record_count, current_read_time;
      POSITION *position= join->positions + idx;

      /* Find the best access method from 's' to the current partial plan */
      POSITION loose_scan_pos;
      best_access_path(join, s, remaining_tables, join->positions, idx,
                       disable_jbuf, record_count, position, &loose_scan_pos);

      /* Compute the cost of extending the plan with 's' */
      current_record_count= COST_MULT(record_count, position->records_read);
      current_read_time=COST_ADD(read_time,
                                 COST_ADD(position->read_time,
                                          current_record_count /
                                          (double) TIME_FOR_COMPARE));

      advance_sj_state(join, remaining_tables, idx, &current_record_count,
                       &current_read_time, &loose_scan_pos);

      /* Expand only partial plans with lower cost than the best QEP so far */
      if (current_read_time >= join->best_read)
      {
        DBUG_EXECUTE("opt", print_plan(join, idx+1,
                                       current_record_count,
                                       read_time,
                                       current_read_time,
                                       "prune_by_cost"););
        restore_prev_nj_state(s);
        restore_prev_sj_state(remaining_tables, s, idx);
        continue;
      }

      /*
        Prune some less promising partial plans. This heuristic may miss
        the optimal QEPs, thus it results in a non-exhaustive search.
      */
      if (prune_level == 1)
      {
        if (best_record_count > current_record_count ||
            best_read_time > current_read_time ||
            (idx == join->const_tables &&  // 's' is the first table in the QEP
            s->table == join->sort_by_table))
        {
          if (best_record_count >= current_record_count &&
              best_read_time >= current_read_time &&
              /* TODO: What is the reasoning behind this condition? */
              (!(s->key_dependent & allowed_tables & remaining_tables) ||
               join->positions[idx].records_read < 2.0))
          {
            best_record_count= current_record_count;
            best_read_time=    current_read_time;
          }
        }
        else
        {
          DBUG_EXECUTE("opt", print_plan(join, idx+1,
                                         current_record_count,
                                         read_time,
                                         current_read_time,
                                         "pruned_by_heuristic"););
          restore_prev_nj_state(s);
          restore_prev_sj_state(remaining_tables, s, idx);
          continue;
        }
      }

      double pushdown_cond_selectivity= 1.0;
      if (use_cond_selectivity > 1)
        pushdown_cond_selectivity= table_cond_selectivity(join, idx, s,
				                          remaining_tables &
                                                          ~real_table_bit);
      join->positions[idx].cond_selectivity= pushdown_cond_selectivity;
      double partial_join_cardinality= current_record_count *
                                        pushdown_cond_selectivity;
      if ( (search_depth > 1) && (remaining_tables & ~real_table_bit) & allowed_tables )
      { /* Recursively expand the current partial plan */
        swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
        if (best_extension_by_limited_search(join,
                                             remaining_tables & ~real_table_bit,
                                             idx + 1,
                                             partial_join_cardinality,
                                             current_read_time,
                                             search_depth - 1,
                                             prune_level,
                                             use_cond_selectivity))
          DBUG_RETURN(TRUE);
        swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
      }
      else
      { /*
          'join' is either the best partial QEP with 'search_depth' relations,
          or the best complete QEP so far, whichever is smaller.
        */
        if (join->sort_by_table &&
            join->sort_by_table !=
            join->positions[join->const_tables].table->table)
          /*
             We may have to make a temp table, note that this is only a
             heuristic since we cannot know for sure at this point.
             Hence it may be wrong.
          */
          current_read_time= COST_ADD(current_read_time, current_record_count);
        if (current_read_time < join->best_read)
        {
          memcpy((uchar*) join->best_positions, (uchar*) join->positions,
                 sizeof(POSITION) * (idx + 1));
          join->join_record_count= partial_join_cardinality;
          join->best_read= current_read_time - 0.001;
        }
        DBUG_EXECUTE("opt", print_plan(join, idx+1,
                                       current_record_count,
                                       read_time,
                                       current_read_time,
                                       "full_plan"););
      }
      restore_prev_nj_state(s);
      restore_prev_sj_state(remaining_tables, s, idx);
    }
  }
  DBUG_RETURN(FALSE);
}


MDEV-22464 Server crash on UPDATE with nested subquery

Uninitialized ref_pointer_array[] because setup_fields() got empty
fields list.  mysql_multi_update() for some reason does that by
substituting the fields list with empty total_list for the
mysql_select() call (looks like wrong merge since total_list is not
used anywhere else and is always empty). The fix would be to return
back the original fields list. But this fails update_use_source.test
case:

  --error ER_BAD_FIELD_ERROR
  update v1 set t1c1=2 order by 1;

Actually not failing the above seems to be ok.

The other fix would be to keep resolve_in_select_list false (and that
keeps outer context from being resolved in
Item_ref::fix_fields()). This fix is more consistent with how SELECT
behaves:

  --error ER_SUBQUERY_NO_1_ROW
  select a from t1 where a= (select 2 from t1 having (a = 3));

So this patch implements this fix.

static void calc_group_buffer(JOIN *join, ORDER *group)
{
  if (group)
    join->group= 1;
  calc_group_buffer(&join->tmp_table_param, group);
}

MariaDB through 10.5.9 allows a set_var.cc application crash via certain uses of an UPDATE statement in conjunction with a nested subquery.


static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
                               KEYUSE *org_keyuse, bool allow_full_scan,
                               table_map used_tables)
{
  uint keyparts, length, key;
  TABLE *table;
  KEY *keyinfo;
  KEYUSE *keyuse= org_keyuse;
  bool ftkey= (keyuse->keypart == FT_KEYPART);
  THD *thd= join->thd;
  DBUG_ENTER("create_ref_for_key");

  /*  Use best key from find_best */
  table= j->table;
  key= keyuse->key;
  if (!is_hash_join_key_no(key))
    keyinfo= table->key_info+key;
  else
  {
    if (create_hj_key_for_table(join, j, org_keyuse, used_tables))
      DBUG_RETURN(TRUE);
    keyinfo= j->hj_key;
  }

  if (ftkey)
  {
    Item_func_match *ifm=(Item_func_match *)keyuse->val;

    length=0;
    keyparts=1;
    ifm->join_key=1;
  }
  else
  {
    keyparts=length=0;
    uint found_part_ref_or_null= 0;
    /*
      Calculate length for the used key
      Stop if there is a missing key part or when we find second key_part
      with KEY_OPTIMIZE_REF_OR_NULL
    */
    do
    {
      if (!(~used_tables & keyuse->used_tables) &&
          (!keyuse->validity_ref || *keyuse->validity_ref) &&
	  j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse))
      {
        if  (are_tables_local(j, keyuse->val->used_tables()))
        {
          if ((is_hash_join_key_no(key) && keyuse->keypart != NO_KEYPART) ||
              (!is_hash_join_key_no(key) && keyparts == keyuse->keypart &&
               !(found_part_ref_or_null & keyuse->optimize)))
          {
             length+= keyinfo->key_part[keyparts].store_length;
             keyparts++;
             found_part_ref_or_null|= keyuse->optimize & ~KEY_OPTIMIZE_EQ;
          }
        }
      }
      keyuse++;
    } while (keyuse->table == table && keyuse->key == key);

    if (!keyparts && allow_full_scan)
    {
      /* It's a LooseIndexScan strategy scanning whole index */
      j->type= JT_ALL;
      j->index= key;
      DBUG_RETURN(FALSE);
    }

    DBUG_ASSERT(length > 0);
    DBUG_ASSERT(keyparts != 0);
  } /* not ftkey */

  /* set up fieldref */
  j->ref.key_parts= keyparts;
  j->ref.key_length= length;
  j->ref.key= (int) key;
  if (!(j->ref.key_buff= (uchar*) thd->calloc(ALIGN_SIZE(length)*2)) ||
      !(j->ref.key_copy= (store_key**) thd->alloc((sizeof(store_key*) *
						          (keyparts+1)))) ||
      !(j->ref.items=(Item**) thd->alloc(sizeof(Item*)*keyparts)) ||
      !(j->ref.cond_guards= (bool**) thd->alloc(sizeof(uint*)*keyparts)))
  {
    DBUG_RETURN(TRUE);
  }
  j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length);
  j->ref.key_err=1;
  j->ref.has_record= FALSE;
  j->ref.null_rejecting= 0;
  j->ref.disable_cache= FALSE;
  j->ref.null_ref_part= NO_REF_PART;
  j->ref.const_ref_part_map= 0;
  j->ref.uses_splitting= FALSE;
  keyuse=org_keyuse;

  store_key **ref_key= j->ref.key_copy;
  uchar *key_buff=j->ref.key_buff, *null_ref_key= 0;
  uint null_ref_part= NO_REF_PART;
  bool keyuse_uses_no_tables= TRUE;
  uint not_null_keyparts= 0;
  if (ftkey)
  {
    j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
    /* Predicates pushed down into subquery can't be used FT access */
    j->ref.cond_guards[0]= NULL;
    if (keyuse->used_tables)
      DBUG_RETURN(TRUE);                        // not supported yet. SerG

    j->type=JT_FT;
  }
  else
  {
    uint i;
    for (i=0 ; i < keyparts ; keyuse++,i++)
    {
      while (((~used_tables) & keyuse->used_tables) ||
             (keyuse->validity_ref && !(*keyuse->validity_ref)) ||
	     !j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) ||
             keyuse->keypart == NO_KEYPART ||
	     (keyuse->keypart !=
              (is_hash_join_key_no(key) ?
                 keyinfo->key_part[i].field->field_index : i)) ||
             !are_tables_local(j, keyuse->val->used_tables()))
	 keyuse++;                              	/* Skip other parts */

      uint maybe_null= MY_TEST(keyinfo->key_part[i].null_bit);
      j->ref.items[i]=keyuse->val;		// Save for cond removal
      j->ref.cond_guards[i]= keyuse->cond_guard;

      if (!keyuse->val->maybe_null || keyuse->null_rejecting)
        not_null_keyparts++;
      /*
        Set ref.null_rejecting to true only if we are going to inject a
        "keyuse->val IS NOT NULL" predicate.
      */
      Item *real= (keyuse->val)->real_item();
      if (keyuse->null_rejecting && (real->type() == Item::FIELD_ITEM) &&
          ((Item_field*)real)->field->maybe_null())
        j->ref.null_rejecting|= (key_part_map)1 << i;

      keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables;
      j->ref.uses_splitting |= (keyuse->validity_ref != NULL);
      /*
        We don't want to compute heavy expressions in EXPLAIN, an example would
        select * from t1 where t1.key=(select thats very heavy);

        (select thats very heavy) => is a constant here
        eg: (select avg(order_cost) from orders) => constant but expensive
      */
      if (!keyuse->val->used_tables() && !thd->lex->describe)
      {					// Compare against constant
        store_key_item tmp(thd,
                           keyinfo->key_part[i].field,
                           key_buff + maybe_null,
                           maybe_null ?  key_buff : 0,
                           keyinfo->key_part[i].length,
                           keyuse->val,
                           FALSE);
        if (unlikely(thd->is_fatal_error))
          DBUG_RETURN(TRUE);
        tmp.copy();
        j->ref.const_ref_part_map |= key_part_map(1) << i ;
      }
      else
      {
        *ref_key++= get_store_key(thd,
                                  keyuse,join->const_table_map,
                                  &keyinfo->key_part[i],
                                  key_buff, maybe_null);
        if (!keyuse->val->used_tables())
          j->ref.const_ref_part_map |= key_part_map(1) << i ;
      }
      /*
	Remember if we are going to use REF_OR_NULL
	But only if field _really_ can be null i.e. we force JT_REF
	instead of JT_REF_OR_NULL in case if field can't be null
      */
      if ((keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL) && maybe_null)
      {
	null_ref_key= key_buff;
        null_ref_part= i;
      }
      key_buff+= keyinfo->key_part[i].store_length;
    }
  } /* not ftkey */
  *ref_key=0;				// end_marker
  if (j->type == JT_FT)
    DBUG_RETURN(0);
  ulong key_flags= j->table->actual_key_flags(keyinfo);
  if (j->type == JT_CONST)
    j->table->const_table= 1;
  else if (!((keyparts == keyinfo->user_defined_key_parts &&
              (
                (key_flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME ||
                /* Unique key and all keyparts are NULL rejecting */
                ((key_flags & HA_NOSAME) && keyparts == not_null_keyparts)
              )) ||
              /* true only for extended keys */
              (keyparts > keyinfo->user_defined_key_parts &&
               MY_TEST(key_flags & HA_EXT_NOSAME) &&
               keyparts == keyinfo->ext_key_parts)
            ) ||
            null_ref_key)
  {
    /* Must read with repeat */
    j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
    j->ref.null_ref_key= null_ref_key;
    j->ref.null_ref_part= null_ref_part;
  }
  else if (keyuse_uses_no_tables)
  {
    /*
      This happen if we are using a constant expression in the ON part
      of an LEFT JOIN.
      SELECT * FROM a LEFT JOIN b ON b.key=30
      Here we should not mark the table as a 'const' as a field may
      have a 'normal' value or a NULL value.
    */
    j->type=JT_CONST;
  }
  else
    j->type=JT_EQ_REF;

  j->read_record.unlock_row= (j->type == JT_EQ_REF)?
                             join_read_key_unlock_row : rr_unlock_row;
  DBUG_RETURN(0);
}


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 (!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
}


bool JOIN::add_having_as_table_cond(JOIN_TAB *tab)
{
  tmp_having->update_used_tables();
  table_map used_tables= tab->table->map | OUTER_REF_TABLE_BIT;

  /* If tmp table is not used then consider conditions of const table also */
  if (!need_tmp)
    used_tables|= const_table_map;

  DBUG_ENTER("JOIN::add_having_as_table_cond");

  Item* sort_table_cond= make_cond_for_table(thd, tmp_having, used_tables,
                                             (table_map) 0, false,
                                             false, false);
  if (sort_table_cond)
  {
    if (!tab->select)
    {
      if (!(tab->select= new SQL_SELECT))
        DBUG_RETURN(true);
      tab->select->head= tab->table;
    }
    if (!tab->select->cond)
      tab->select->cond= sort_table_cond;
    else
    {
      if (!(tab->select->cond=
	      new (thd->mem_root) Item_cond_and(thd,
                                                tab->select->cond,
                                                sort_table_cond)))
        DBUG_RETURN(true);
    }
    if (tab->pre_idx_push_select_cond)
    {
      if (sort_table_cond->type() == Item::COND_ITEM)
        sort_table_cond= sort_table_cond->copy_andor_structure(thd);
      if (!(tab->pre_idx_push_select_cond=
              new (thd->mem_root) Item_cond_and(thd,
                                                tab->pre_idx_push_select_cond,
                                                sort_table_cond)))
        DBUG_RETURN(true);
    }
    if (tab->select->cond)
      tab->select->cond->fix_fields_if_needed(thd, 0);
    if (tab->pre_idx_push_select_cond)
      tab->pre_idx_push_select_cond->fix_fields_if_needed(thd, 0);
    tab->select->pre_idx_push_select_cond= tab->pre_idx_push_select_cond;
    tab->set_select_cond(tab->select->cond, __LINE__);
    tab->select_cond->top_level_item();
    DBUG_EXECUTE("where",print_where(tab->select->cond,
				     "select and having",
                                     QT_ORDINARY););

    having= make_cond_for_table(thd, tmp_having, ~ (table_map) 0,
                                ~used_tables, false, false, false);
    DBUG_EXECUTE("where",
                 print_where(having, "having after sort", QT_ORDINARY););
  }

  DBUG_RETURN(false);
}


cmp_buffer_with_ref(THD *thd, TABLE *table, TABLE_REF *tab_ref)
{
  bool no_prev_key;
  if (!tab_ref->disable_cache)
  {
    if (!(no_prev_key= tab_ref->key_err))
    {
      /* Previous access found a row. Copy its key */
      memcpy(tab_ref->key_buff2, tab_ref->key_buff, tab_ref->key_length);
    }
  }
  else
    no_prev_key= TRUE;
  if ((tab_ref->key_err= cp_buffer_from_ref(thd, table, tab_ref)) ||
      no_prev_key)
    return 1;
  return memcmp(tab_ref->key_buff2, tab_ref->key_buff, tab_ref->key_length)
    != 0;
}


Item_func_like::add_key_fields(JOIN *join, KEY_FIELD **key_fields,
                               uint *and_level, table_map usable_tables,
                               SARGABLE_PARAM **sargables)
{
  if (is_local_field(args[0]) && with_sargable_pattern())
  {
    /*
      SELECT * FROM t1 WHERE field LIKE const_pattern
      const_pattern starts with a non-wildcard character
    */
    add_key_equal_fields(join, key_fields, *and_level, this,
                         (Item_field*) args[0]->real_item(), false,
                         args + 1, 1, usable_tables, sargables);
  }
}


void JOIN::reset_query_plan()
{
  for (uint i= 0; i < table_count; i++)
  {
    join_tab[i].keyuse= NULL;
    join_tab[i].checked_keys.clear_all();
  }
}


int join_init_read_record(JOIN_TAB *tab)
{
  /*
    Note: the query plan tree for the below operations is constructed in
    save_agg_explain_data.
  */
  if (tab->distinct && tab->remove_duplicates())  // Remove duplicates.
    return 1;
  if (tab->filesort && tab->sort_table())     // Sort table.
    return 1;

  DBUG_EXECUTE_IF("kill_join_init_read_record",
                  tab->join->thd->set_killed(KILL_QUERY););
  if (tab->select && tab->select->quick && tab->select->quick->reset())
  {
    /* Ensures error status is propagated back to client */
    report_error(tab->table,
                 tab->join->thd->killed ? HA_ERR_QUERY_INTERRUPTED : HA_ERR_OUT_OF_MEM);
    return 1;
  }
  /* make sure we won't get ER_QUERY_INTERRUPTED from any code below */
  DBUG_EXECUTE_IF("kill_join_init_read_record",
                  tab->join->thd->reset_killed(););
  if (!tab->preread_init_done  && tab->preread_init())
    return 1;
  if (init_read_record(&tab->read_record, tab->join->thd, tab->table,
                       tab->select, tab->filesort_result, 1,1, FALSE))
    return 1;
  return tab->read_record.read_record();
}


test_if_quick_select(JOIN_TAB *tab)
{
  DBUG_EXECUTE_IF("show_explain_probe_test_if_quick_select",
                  if (dbug_user_var_equals_int(tab->join->thd,
                                               "show_explain_probe_select_id",
                                               tab->join->select_lex->select_number))
                        dbug_serve_apcs(tab->join->thd, 1);
                 );

  delete tab->select->quick;
  tab->select->quick=0;

  if (tab->table->file->inited != handler::NONE)
    tab->table->file->ha_index_or_rnd_end();

  int res= tab->select->test_quick_select(tab->join->thd, tab->keys,
                                          (table_map) 0, HA_POS_ERROR, 0,
                                          FALSE, /*remove where parts*/FALSE);
  if (tab->explain_plan && tab->explain_plan->range_checked_fer)
    tab->explain_plan->range_checked_fer->collect_data(tab->select->quick);

  return res;
}


bool build_tmp_join_prefix_cond(JOIN *join, JOIN_TAB *last_tab, Item **ret)
{
  THD *const thd= join->thd;
  Item_cond_and *all_conds= NULL;

  Item *res= NULL;

  // Pick the ON-expression. Use the same logic as in get_sargable_cond():
  if (last_tab->on_expr_ref)
    res= *last_tab->on_expr_ref;
  else if (last_tab->table->pos_in_table_list &&
           last_tab->table->pos_in_table_list->embedding &&
           !last_tab->table->pos_in_table_list->embedding->sj_on_expr)
  {
    res= last_tab->table->pos_in_table_list->embedding->on_expr;
  }

  for (JOIN_TAB *tab= first_depth_first_tab(join);
       tab;
       tab= next_depth_first_tab(join, tab))
  {
    if (tab->select_cond)
    {
      if (!res)
        res= tab->select_cond;
      else
      {
        if (!all_conds)
        {
          if (!(all_conds= new (thd->mem_root)Item_cond_and(thd, res,
                                                            tab->select_cond)))
            return true;
          res= all_conds;
        }
        else
          all_conds->add(tab->select_cond, thd->mem_root);
      }
    }
    if (tab == last_tab)
      break;
  }
  *ret= all_conds? all_conds: res;
  return false;
}


cache_record_length(JOIN *join,uint idx)
{
  uint length=0;
  JOIN_TAB **pos,**end;

  for (pos=join->best_ref+join->const_tables,end=join->best_ref+idx ;
       pos != end ;
       pos++)
  {
    JOIN_TAB *join_tab= *pos;
    length+= join_tab->get_used_fieldlength();
  }
  return length;
}


void *Virtual_tmp_table::operator new(size_t size, THD *thd) throw()
{
  return (Virtual_tmp_table *) alloc_root(thd->mem_root, size);
}


bool Virtual_tmp_table::add(List<Spvar_definition> &field_list)
{
  /* Create all fields and calculate the total length of record */
  Spvar_definition *cdef;            /* column definition */
  List_iterator_fast<Spvar_definition> it(field_list);
  DBUG_ENTER("Virtual_tmp_table::add");
  while ((cdef= it++))
  {
    Field *tmp;
    if (!(tmp= cdef->make_field(s, in_use->mem_root, 0,
                             (uchar*) (f_maybe_null(cdef->pack_flag) ? "" : 0),
                             f_maybe_null(cdef->pack_flag) ? 1 : 0,
                             &cdef->field_name)))
      DBUG_RETURN(true);
     add(tmp);
  }
  DBUG_RETURN(false);
}


init_sum_functions(Item_sum **func_ptr, Item_sum **end_ptr)
{
  for (; func_ptr != end_ptr ;func_ptr++)
  {
    if ((*func_ptr)->reset_and_add())
      return 1;
  }
  /* If rollup, calculate the upper sum levels */
  for ( ; *func_ptr ; func_ptr++)
  {
    if ((*func_ptr)->aggregator_add())
      return 1;
  }
  return 0;
}


static int remove_dup_with_hash_index(THD *thd, TABLE *table,
				      uint field_count,
				      Field **first_field,
				      ulong key_length,
				      Item *having)
{
  uchar *key_buffer, *key_pos, *record=table->record[0];
  int error;
  handler *file= table->file;
  ulong extra_length= ALIGN_SIZE(key_length)-key_length;
  uint *field_lengths, *field_length;
  HASH hash;
  Field **ptr;
  DBUG_ENTER("remove_dup_with_hash_index");

  if (unlikely(!my_multi_malloc(MYF(MY_WME),
                                &key_buffer,
                                (uint) ((key_length + extra_length) *
                                        (long) file->stats.records),
                                &field_lengths,
                                (uint) (field_count*sizeof(*field_lengths)),
                                NullS)))
    DBUG_RETURN(1);

  for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++)
    (*field_length++)= (*ptr)->sort_length();

  if (unlikely(my_hash_init(&hash, &my_charset_bin,
                            (uint) file->stats.records, 0,
                            key_length, (my_hash_get_key) 0, 0, 0)))
  {
    my_free(key_buffer);
    DBUG_RETURN(1);
  }

  if (unlikely((error= file->ha_rnd_init(1))))
    goto err;

  key_pos=key_buffer;
  for (;;)
  {
    uchar *org_key_pos;
    if (unlikely(thd->check_killed()))
    {
      error=0;
      goto err;
    }
    if (unlikely((error= file->ha_rnd_next(record))))
    {
      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;
      continue;
    }

    /* copy fields to key buffer */
    org_key_pos= key_pos;
    field_length=field_lengths;
    for (ptr= first_field ; *ptr ; ptr++)
    {
      (*ptr)->make_sort_key(key_pos, *field_length);
      key_pos+= (*ptr)->maybe_null() + *field_length++;
    }
    /* Check if it exists before */
    if (my_hash_search(&hash, org_key_pos, key_length))
    {
      /* Duplicated found ; Remove the row */
      if (unlikely((error= file->ha_delete_row(record))))
	goto err;
    }
    else
    {
      if (my_hash_insert(&hash, org_key_pos))
        goto err;
    }
    key_pos+=extra_length;
  }
  my_free(key_buffer);
  my_hash_free(&hash);
  file->extra(HA_EXTRA_NO_CACHE);
  (void) file->ha_rnd_end();
  DBUG_RETURN(0);

err:
  my_free(key_buffer);
  my_hash_free(&hash);
  file->extra(HA_EXTRA_NO_CACHE);
  (void) file->ha_rnd_end();
  if (unlikely(error))
    file->print_error(error,MYF(0));
  DBUG_RETURN(1);
}


void JOIN::cache_const_exprs()
{
  bool cache_flag= FALSE;
  bool *analyzer_arg= &cache_flag;

  /* No need in cache if all tables are constant. */
  if (const_tables == table_count)
    return;

  if (conds)
    conds->compile(thd, &Item::cache_const_expr_analyzer, (uchar **)&analyzer_arg,
                  &Item::cache_const_expr_transformer, (uchar *)&cache_flag);
  cache_flag= FALSE;
  if (having)
    having->compile(thd, &Item::cache_const_expr_analyzer, (uchar **)&analyzer_arg,
                    &Item::cache_const_expr_transformer, (uchar *)&cache_flag);

  for (JOIN_TAB *tab= first_depth_first_tab(this); tab;
       tab= next_depth_first_tab(this, tab))
  {
    if (*tab->on_expr_ref)
    {
      cache_flag= FALSE;
      (*tab->on_expr_ref)->compile(thd, &Item::cache_const_expr_analyzer,
                                 (uchar **)&analyzer_arg,
                                 &Item::cache_const_expr_transformer,
                                 (uchar *)&cache_flag);
    }
  }
}


void JOIN_TAB::remove_redundant_bnl_scan_conds()
{
  if (!(select_cond && cache_select && cache &&
        (cache->get_join_alg() == JOIN_CACHE::BNL_JOIN_ALG ||
         cache->get_join_alg() == JOIN_CACHE::BNLH_JOIN_ALG)))
    return;

  /*
    select->cond is not processed separately. This method assumes it is always
    the same as select_cond.
  */
  if (select && select->cond != select_cond)
    return;

  if (is_cond_and(select_cond))
  {
    List_iterator<Item> pushed_cond_li(*((Item_cond*) select_cond)->argument_list());
    Item *pushed_item;
    Item_cond_and *reduced_select_cond= new (join->thd->mem_root)
      Item_cond_and(join->thd);

    if (is_cond_and(cache_select->cond))
    {
      List_iterator<Item> scan_cond_li(*((Item_cond*) cache_select->cond)->argument_list());
      Item *scan_item;
      while ((pushed_item= pushed_cond_li++))
      {
        bool found_cond= false;
        scan_cond_li.rewind();
        while ((scan_item= scan_cond_li++))
        {
          if (pushed_item->eq(scan_item, 0))
          {
            found_cond= true;
            break;
          }
        }
        if (!found_cond)
          reduced_select_cond->add(pushed_item, join->thd->mem_root);
      }
    }
    else
    {
      while ((pushed_item= pushed_cond_li++))
      {
        if (!pushed_item->eq(cache_select->cond, 0))
          reduced_select_cond->add(pushed_item, join->thd->mem_root);
      }
    }

    /*
      JOIN_CACHE::check_match uses JOIN_TAB::select->cond instead of
      JOIN_TAB::select_cond. set_cond() sets both pointers.
    */
    if (reduced_select_cond->argument_list()->is_empty())
      set_cond(NULL);
    else if (reduced_select_cond->argument_list()->elements == 1)
      set_cond(reduced_select_cond->argument_list()->head());
    else
    {
      reduced_select_cond->quick_fix_field();
      set_cond(reduced_select_cond);
    }
  }
  else if (select_cond->eq(cache_select->cond, 0))
    set_cond(NULL);
}


static void print_join(THD *thd,
                       table_map eliminated_tables,
                       String *str,
                       List<TABLE_LIST> *tables,
                       enum_query_type query_type)
{
  /* List is reversed => we should reverse it before using */
  List_iterator_fast<TABLE_LIST> ti(*tables);
  TABLE_LIST **table;
  DBUG_ENTER("print_join");

  /*
    If the QT_NO_DATA_EXPANSION flag is specified, we print the
    original table list, including constant tables that have been
    optimized away, as the constant tables may be referenced in the
    expression printed by Item_field::print() when this flag is given.
    Otherwise, only non-const tables are printed.

    Example:

    Original SQL:
    select * from (select 1) t

    Printed without QT_NO_DATA_EXPANSION:
    select '1' AS `1` from dual

    Printed with QT_NO_DATA_EXPANSION:
    select `t`.`1` from (select 1 AS `1`) `t`
  */
  const bool print_const_tables= (query_type & QT_NO_DATA_EXPANSION);
  size_t tables_to_print= 0;

  for (TABLE_LIST *t= ti++; t ; t= ti++)
  {
    /* See comment in print_table_array() about the second condition */
    if (print_const_tables || !t->optimized_away)
      if (!is_eliminated_table(eliminated_tables, t))
        tables_to_print++;
  }
  if (tables_to_print == 0)
  {
    str->append(STRING_WITH_LEN("dual"));
    DBUG_VOID_RETURN;                   // all tables were optimized away
  }
  ti.rewind();

  if (!(table= static_cast<TABLE_LIST **>(thd->alloc(sizeof(TABLE_LIST*) *
                                                     tables_to_print))))
    DBUG_VOID_RETURN;                   // out of memory

  TABLE_LIST *tmp, **t= table + (tables_to_print - 1);
  while ((tmp= ti++))
  {
    if (tmp->optimized_away && !print_const_tables)
      continue;
    if (is_eliminated_table(eliminated_tables, tmp))
      continue;
    *t--= tmp;
  }

  DBUG_ASSERT(tables->elements >= 1);
  /*
    Assert that the first table in the list isn't eliminated. This comes from
    the fact that the first table can't be inner table of an outer join.
  */
  DBUG_ASSERT(!eliminated_tables ||
              !(((*table)->table && ((*table)->table->map & eliminated_tables)) ||
                ((*table)->nested_join && !((*table)->nested_join->used_tables &
                                           ~eliminated_tables))));
  /*
    If the first table is a semi-join nest, swap it with something that is
    not a semi-join nest.
  */
  if ((*table)->sj_inner_tables)
  {
    TABLE_LIST **end= table + tables_to_print;
    for (TABLE_LIST **t2= table; t2!=end; t2++)
    {
      if (!(*t2)->sj_inner_tables)
      {
        tmp= *t2;
        *t2= *table;
        *table= tmp;
        break;
      }
    }
  }
  print_table_array(thd, eliminated_tables, str, table,
                    table +  tables_to_print, query_type);
  DBUG_VOID_RETURN;
}


Field *Item_sum::create_tmp_field(bool group, TABLE *table)
{
  Field *UNINIT_VAR(new_field);
  MEM_ROOT *mem_root= table->in_use->mem_root;

  switch (cmp_type()) {
  case REAL_RESULT:
  {
    new_field= new (mem_root)
      Field_double(max_char_length(), maybe_null, &name, decimals, TRUE);
    break;
  }
  case INT_RESULT:
  case TIME_RESULT:
  case DECIMAL_RESULT:
  case STRING_RESULT:
    new_field= tmp_table_field_from_field_type(table);
    break;
  case ROW_RESULT:
    // This case should never be choosen
    DBUG_ASSERT(0);
    new_field= 0;
    break;
  }
  if (new_field)
    new_field->init(table);
  return new_field;
}


static bool check_interleaving_with_nj(JOIN_TAB *next_tab)
{
  TABLE_LIST *next_emb= next_tab->table->pos_in_table_list->embedding;
  JOIN *join= next_tab->join;

  if (join->cur_embedding_map & ~next_tab->embedding_map)
  {
    /*
      next_tab is outside of the "pair of brackets" we're currently in.
      Cannot add it.
    */
    return TRUE;
  }

  /*
    Do update counters for "pairs of brackets" that we've left (marked as
    X,Y,Z in the above picture)
  */
  for (;next_emb && next_emb != join->emb_sjm_nest; next_emb= next_emb->embedding)
  {
    if (!next_emb->sj_on_expr)
    {
      next_emb->nested_join->counter++;
      if (next_emb->nested_join->counter == 1)
      {
        /*
          next_emb is the first table inside a nested join we've "entered". In
          the picture above, we're looking at the 'X' bracket. Don't exit yet as
          X bracket might have Y pair bracket.
        */
        join->cur_embedding_map |= next_emb->nested_join->nj_map;
      }

      if (next_emb->nested_join->n_tables !=
          next_emb->nested_join->counter)
        break;

      /*
        We're currently at Y or Z-bracket as depicted in the above picture.
        Mark that we've left it and continue walking up the brackets hierarchy.
      */
      join->cur_embedding_map &= ~next_emb->nested_join->nj_map;
    }
  }
  return FALSE;
}


get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
	      KEY_PART_INFO *key_part, uchar *key_buff, uint maybe_null)
{
  if (!((~used_tables) & keyuse->used_tables))		// if const item
  {
    return new store_key_const_item(thd,
				    key_part->field,
				    key_buff + maybe_null,
				    maybe_null ? key_buff : 0,
				    key_part->length,
				    keyuse->val);
  }
  else if (keyuse->val->type() == Item::FIELD_ITEM ||
           (keyuse->val->type() == Item::REF_ITEM &&
	    ((((Item_ref*)keyuse->val)->ref_type() == Item_ref::OUTER_REF &&
              (*(Item_ref**)((Item_ref*)keyuse->val)->ref)->ref_type() ==
              Item_ref::DIRECT_REF) ||
             ((Item_ref*)keyuse->val)->ref_type() == Item_ref::VIEW_REF) &&
            keyuse->val->real_item()->type() == Item::FIELD_ITEM))
    return new store_key_field(thd,
			       key_part->field,
			       key_buff + maybe_null,
			       maybe_null ? key_buff : 0,
			       key_part->length,
			       ((Item_field*) keyuse->val->real_item())->field,
			       keyuse->val->real_item()->full_name());

  return new store_key_item(thd,
			    key_part->field,
			    key_buff + maybe_null,
			    maybe_null ? key_buff : 0,
			    key_part->length,
			    keyuse->val, FALSE);
}


bool JOIN_TAB::keyuse_is_valid_for_access_in_chosen_plan(JOIN *join,
                                                         KEYUSE *keyuse)
{
  if (!access_from_tables_is_allowed(keyuse->used_tables,
                                     join->sjm_lookup_tables))
    return false;
  if (join->sjm_scan_tables & table->map)
    return true;
  table_map keyuse_sjm_scan_tables= keyuse->used_tables &
                                    join->sjm_scan_tables;
  if (!keyuse_sjm_scan_tables)
    return true;
  uint sjm_tab_nr= 0;
  while (!(keyuse_sjm_scan_tables & table_map(1) << sjm_tab_nr))
    sjm_tab_nr++;
  JOIN_TAB *sjm_tab= join->map2table[sjm_tab_nr];
  TABLE_LIST *emb_sj_nest= sjm_tab->emb_sj_nest;
  if (!(emb_sj_nest->sj_mat_info && emb_sj_nest->sj_mat_info->is_used &&
        emb_sj_nest->sj_mat_info->is_sj_scan))
    return true;
  st_select_lex *sjm_sel= emb_sj_nest->sj_subq_pred->unit->first_select();
  for (uint i= 0; i < sjm_sel->item_list.elements; i++)
  {
    DBUG_ASSERT(sjm_sel->ref_pointer_array[i]->real_item()->type() == Item::FIELD_ITEM);
    if (keyuse->val->real_item()->type() == Item::FIELD_ITEM)
    {
      Field *field = ((Item_field*)sjm_sel->ref_pointer_array[i]->real_item())->field;
      if (field->eq(((Item_field*)keyuse->val->real_item())->field))
        return true;
    }
  }
  return false;
}


void compute_part_of_sort_key_for_equals(JOIN *join, TABLE *table,
                                         Item_field *item_field,
                                         key_map *col_keys)
{
  col_keys->clear_all();
  col_keys->merge(item_field->field->part_of_sortkey);

  if (!optimizer_flag(join->thd, OPTIMIZER_SWITCH_ORDERBY_EQ_PROP))
    return;

  Item_equal *item_eq= NULL;

  if (item_field->item_equal)
  {
    /*
      The item_field is from ORDER structure, but it already has an item_equal
      pointer set (UseMultipleEqualitiesToRemoveTempTable code have set it)
    */
    item_eq= item_field->item_equal;
  }
  else
  {
    /*
      Walk through join's muliple equalities and find the one that contains
      item_field.
    */
    if (!join->cond_equal)
      return;
    table_map needed_tbl_map= item_field->used_tables() | table->map;
    List_iterator<Item_equal> li(join->cond_equal->current_level);
    Item_equal *cur_item_eq;
    while ((cur_item_eq= li++))
    {
      if ((cur_item_eq->used_tables() & needed_tbl_map) &&
          cur_item_eq->contains(item_field->field))
      {
        item_eq= cur_item_eq;
        item_field->item_equal= item_eq; // Save the pointer to our Item_equal.
        break;
      }
    }
  }

  if (item_eq)
  {
    Item_equal_fields_iterator it(*item_eq);
    Item *item;
    /* Loop through other members that belong to table table */
    while ((item= it++))
    {
      if (item->type() == Item::FIELD_ITEM &&
          ((Item_field*)item)->field->table == table)
      {
        col_keys->merge(((Item_field*)item)->field->part_of_sortkey);
      }
    }
  }
}


end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
	   bool end_of_records)
{
  TABLE *const table= join_tab->table;
  ORDER   *group;
  int	  error;
  DBUG_ENTER("end_update");

  if (end_of_records)
    DBUG_RETURN(NESTED_LOOP_OK);

  join->found_records++;
  copy_fields(join_tab->tmp_table_param);	// Groups are copied twice.
  /* Make a key of group index */
  for (group=table->group ; group ; group=group->next)
  {
    Item *item= *group->item;
    if (group->fast_field_copier_setup != group->field)
    {
      DBUG_PRINT("info", ("new setup %p -> %p",
                          group->fast_field_copier_setup,
                          group->field));
      group->fast_field_copier_setup= group->field;
      group->fast_field_copier_func=
        item->setup_fast_field_copier(group->field);
    }
    item->save_org_in_field(group->field, group->fast_field_copier_func);
    /* Store in the used key if the field was 0 */
    if (item->maybe_null)
      group->buff[-1]= (char) group->field->is_null();
  }
  if (!table->file->ha_index_read_map(table->record[1],
                                      join_tab->tmp_table_param->group_buff,
                                      HA_WHOLE_KEY,
                                      HA_READ_KEY_EXACT))
  {						/* Update old record */
    restore_record(table,record[1]);
    update_tmptable_sum_func(join->sum_funcs,table);
    if (unlikely((error= table->file->ha_update_tmp_row(table->record[1],
                                                        table->record[0]))))
    {
      table->file->print_error(error,MYF(0));	/* purecov: inspected */
      DBUG_RETURN(NESTED_LOOP_ERROR);            /* purecov: inspected */
    }
    goto end;
  }

  init_tmptable_sum_functions(join->sum_funcs);
  if (unlikely(copy_funcs(join_tab->tmp_table_param->items_to_copy,
                          join->thd)))
    DBUG_RETURN(NESTED_LOOP_ERROR);           /* purecov: inspected */
  if (unlikely((error= table->file->ha_write_tmp_row(table->record[0]))))
  {
    if (create_internal_tmp_table_from_heap(join->thd, table,
                                       join_tab->tmp_table_param->start_recinfo,
                                            &join_tab->tmp_table_param->recinfo,
                                            error, 0, NULL))
      DBUG_RETURN(NESTED_LOOP_ERROR);            // Not a table_is_full error
    /* Change method to update rows */
    if (unlikely((error= table->file->ha_index_init(0, 0))))
    {
      table->file->print_error(error, MYF(0));
      DBUG_RETURN(NESTED_LOOP_ERROR);
    }

    join_tab->aggr->set_write_func(end_unique_update);
  }
  join_tab->send_records++;
end:
  if (unlikely(join->thd->check_killed()))
  {
    DBUG_RETURN(NESTED_LOOP_KILLED);             /* purecov: inspected */
  }
  DBUG_RETURN(NESTED_LOOP_OK);
}


JOIN::create_postjoin_aggr_table(JOIN_TAB *tab, List<Item> *table_fields,
                                 ORDER *table_group,
                                 bool save_sum_fields,
                                 bool distinct,
                                 bool keep_row_order)
{
  DBUG_ENTER("JOIN::create_postjoin_aggr_table");
  THD_STAGE_INFO(thd, stage_creating_tmp_table);

  /*
    Pushing LIMIT to the post-join temporary table creation is not applicable
    when there is ORDER BY or GROUP BY or there is no GROUP BY, but
    there are aggregate functions, because in all these cases we need
    all result rows.
  */
  ha_rows table_rows_limit= ((order == NULL || skip_sort_order) &&
                              !table_group &&
                              !select_lex->with_sum_func) ? select_limit
                                                          : HA_POS_ERROR;

  if (!(tab->tmp_table_param= new TMP_TABLE_PARAM(tmp_table_param)))
    DBUG_RETURN(true);
  if (tmp_table_keep_current_rowid)
    add_fields_for_current_rowid(tab, table_fields);
  tab->tmp_table_param->skip_create_table= true;
  TABLE* table= create_tmp_table(thd, tab->tmp_table_param, *table_fields,
                                 table_group, distinct,
                                 save_sum_fields, select_options, table_rows_limit,
                                 &empty_clex_str, true, keep_row_order);
  if (!table)
    DBUG_RETURN(true);
  tmp_table_param.using_outer_summary_function=
    tab->tmp_table_param->using_outer_summary_function;
  tab->join= this;
  DBUG_ASSERT(tab > tab->join->join_tab || !top_join_tab_count || !tables_list);
  if (tab > join_tab)
    (tab - 1)->next_select= sub_select_postjoin_aggr;
  if (!(tab->aggr= new (thd->mem_root) AGGR_OP(tab)))
    goto err;
  tab->table= table;
  table->reginfo.join_tab= tab;

  /* if group or order on first table, sort first */
  if ((group_list && simple_group) ||
      (implicit_grouping && select_lex->have_window_funcs()))
  {
    DBUG_PRINT("info",("Sorting for group"));
    THD_STAGE_INFO(thd, stage_sorting_for_group);

    if (ordered_index_usage != ordered_index_group_by &&
        !only_const_tables() &&
        (join_tab + const_tables)->type != JT_CONST && // Don't sort 1 row
        !implicit_grouping &&
        add_sorting_to_table(join_tab + const_tables, group_list))
      goto err;

    if (alloc_group_fields(this, group_list))
      goto err;
    if (make_sum_func_list(all_fields, fields_list, true))
      goto err;
    if (prepare_sum_aggregators(sum_funcs,
                                !(tables_list &&
                                  join_tab->is_using_agg_loose_index_scan())))
      goto err;
    if (setup_sum_funcs(thd, sum_funcs))
      goto err;
    group_list= NULL;
  }
  else
  {
    if (make_sum_func_list(all_fields, fields_list, false))
      goto err;
    if (prepare_sum_aggregators(sum_funcs,
                                !join_tab->is_using_agg_loose_index_scan()))
      goto err;
    if (setup_sum_funcs(thd, sum_funcs))
      goto err;

    if (!group_list && !table->distinct && order && simple_order &&
        tab == join_tab + const_tables)
    {
      DBUG_PRINT("info",("Sorting for order"));
      THD_STAGE_INFO(thd, stage_sorting_for_order);

      if (ordered_index_usage != ordered_index_order_by &&
          !only_const_tables() &&
          add_sorting_to_table(join_tab + const_tables, order))
        goto err;
      order= NULL;
    }
  }

  DBUG_RETURN(false);

err:
  if (table != NULL)
    free_tmp_table(thd, table);
  DBUG_RETURN(true);
}


JOIN_TAB *first_explain_order_tab(JOIN* join)
{
  JOIN_TAB* tab;
  tab= join->join_tab;
  if (!tab)
    return NULL; /* Can happen when when the tables were optimized away */
  return (tab->bush_children) ? tab->bush_children->start : tab;
}


end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
	 bool end_of_records)
{
  DBUG_ENTER("end_send");
  /*
    When all tables are const this function is called with jointab == NULL.
    This function shouldn't be called for the first join_tab as it needs
    to get fields from previous tab.
  */
  DBUG_ASSERT(join_tab == NULL || join_tab != join->join_tab);
  //TODO pass fields via argument
  List<Item> *fields= join_tab ? (join_tab-1)->fields : join->fields;

  if (!end_of_records)
  {
    if (join->table_count &&
        join->join_tab->is_using_loose_index_scan())
    {
      /* Copy non-aggregated fields when loose index scan is used. */
      copy_fields(&join->tmp_table_param);
    }
    if (join->having && join->having->val_int() == 0)
      DBUG_RETURN(NESTED_LOOP_OK);               // Didn't match having
    if (join->procedure)
    {
      if (join->procedure->send_row(join->procedure_fields_list))
        DBUG_RETURN(NESTED_LOOP_ERROR);
      DBUG_RETURN(NESTED_LOOP_OK);
    }
    if (join->do_send_rows)
    {
      int error;
      /* result < 0 if row was not accepted and should not be counted */
      if (unlikely((error= join->result->send_data(*fields))))
      {
        if (error > 0)
          DBUG_RETURN(NESTED_LOOP_ERROR);
        // error < 0 => duplicate row
        join->duplicate_rows++;
      }
    }

    ++join->send_records;
    if (join->send_records >= join->unit->select_limit_cnt &&
        !join->do_send_rows)
    {
      /*
        If we have used Priority Queue for optimizing order by with limit,
        then stop here, there are no more records to consume.
        When this optimization is used, end_send is called on the next
        join_tab.
      */
      if (join->order &&
          join->select_options & OPTION_FOUND_ROWS &&
          join_tab > join->join_tab &&
          (join_tab - 1)->filesort && (join_tab - 1)->filesort->using_pq)
      {
        DBUG_PRINT("info", ("filesort NESTED_LOOP_QUERY_LIMIT"));
        DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT);
      }
    }
    if (join->send_records >= join->unit->select_limit_cnt &&
	join->do_send_rows)
    {
      if (join->select_options & OPTION_FOUND_ROWS)
      {
	JOIN_TAB *jt=join->join_tab;
	if ((join->table_count == 1) && !join->sort_and_group
	    && !join->send_group_parts && !join->having && !jt->select_cond &&
	    !(jt->select && jt->select->quick) &&
	    (jt->table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
            (jt->ref.key < 0))
	{
	  /* Join over all rows in table;  Return number of found rows */
	  TABLE *table=jt->table;

	  if (jt->filesort_result)                     // If filesort was used
	  {
	    join->send_records= jt->filesort_result->found_rows;
	  }
	  else
	  {
	    table->file->info(HA_STATUS_VARIABLE);
	    join->send_records= table->file->stats.records;
	  }
	}
	else
	{
	  join->do_send_rows= 0;
	  if (join->unit->fake_select_lex)
	    join->unit->fake_select_lex->select_limit= 0;
	  DBUG_RETURN(NESTED_LOOP_OK);
	}
      }
      DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT);      // Abort nicely
    }
    else if (join->send_records >= join->fetch_limit)
    {
      /*
        There is a server side cursor and all rows for
        this fetch request are sent.
      */
      DBUG_RETURN(NESTED_LOOP_CURSOR_LIMIT);
    }
  }
  else
  {
    if (join->procedure && join->procedure->end_of_records())
      DBUG_RETURN(NESTED_LOOP_ERROR);
  }
  DBUG_RETURN(NESTED_LOOP_OK);
}


bool JOIN::prepare_stage2()
{
  bool res= TRUE;
  DBUG_ENTER("JOIN::prepare_stage2");

  /* Init join struct */
  count_field_types(select_lex, &tmp_table_param, all_fields, 0);
  this->group= group_list != 0;

  if (tmp_table_param.sum_func_count && !group_list)
  {
    implicit_grouping= TRUE;
    // Result will contain zero or one row - ordering is meaningless
    order= NULL;
  }

#ifdef RESTRICTED_GROUP
  if (implicit_grouping)
  {
    my_message(ER_WRONG_SUM_SELECT,ER_THD(thd, ER_WRONG_SUM_SELECT),MYF(0));
    goto err;
  }
#endif
  if (select_lex->olap == ROLLUP_TYPE && rollup_init())
    goto err;
  if (alloc_func_list())
    goto err;

  res= FALSE;
err:
  DBUG_RETURN(res);				/* purecov: inspected */
}


add_key_field(JOIN *join,
              KEY_FIELD **key_fields,uint and_level, Item_bool_func *cond,
              Field *field, bool eq_func, Item **value, uint num_values,
              table_map usable_tables, SARGABLE_PARAM **sargables,
              uint row_col_no= 0)
{
  uint optimize= 0;
  if (eq_func &&
      ((join->is_allowed_hash_join_access() &&
        field->hash_join_is_possible() &&
        !(field->table->pos_in_table_list->is_materialized_derived() &&
          field->table->is_created())) ||
       (field->table->pos_in_table_list->is_materialized_derived() &&
        !field->table->is_created() && !(field->flags & BLOB_FLAG))))
  {
    optimize= KEY_OPTIMIZE_EQ;
  }
  else if (!(field->flags & PART_KEY_FLAG))
  {
    // Don't remove column IS NULL on a LEFT JOIN table
    if (eq_func && (*value)->type() == Item::NULL_ITEM &&
        field->table->maybe_null && !field->null_ptr)
    {
      optimize= KEY_OPTIMIZE_EXISTS;
      DBUG_ASSERT(num_values == 1);
    }
  }
  if (optimize != KEY_OPTIMIZE_EXISTS)
  {
    table_map used_tables=0;
    bool optimizable=0;
    for (uint i=0; i<num_values; i++)
    {
      Item *curr_val;
      if (row_col_no && value[i]->real_item()->type() == Item::ROW_ITEM)
      {
        Item_row *value_tuple= (Item_row *) (value[i]->real_item());
        curr_val= value_tuple->element_index(row_col_no - 1);
      }
      else
        curr_val= value[i];
      table_map value_used_tables= curr_val->used_tables();
      used_tables|= value_used_tables;
      if (!(value_used_tables & (field->table->map | RAND_TABLE_BIT)))
        optimizable=1;
    }
    if (!optimizable)
      return;
    if (!(usable_tables & field->table->map))
    {
      if (!eq_func || (*value)->type() != Item::NULL_ITEM ||
          !field->table->maybe_null || field->null_ptr)
	return;					// Can't use left join optimize
      optimize= KEY_OPTIMIZE_EXISTS;
    }
    else
    {
      JOIN_TAB *stat=field->table->reginfo.join_tab;
      key_map possible_keys=field->get_possible_keys();
      possible_keys.intersect(field->table->keys_in_use_for_query);
      stat[0].keys.merge(possible_keys);             // Add possible keys

      /*
	Save the following cases:
	Field op constant
	Field LIKE constant where constant doesn't start with a wildcard
	Field = field2 where field2 is in a different table
	Field op formula
	Field IS NULL
	Field IS NOT NULL
         Field BETWEEN ...
         Field IN ...
      */
      if (field->flags & PART_KEY_FLAG)
        stat[0].key_dependent|=used_tables;

      bool is_const=1;
      for (uint i=0; i<num_values; i++)
      {
        Item *curr_val;
        if (row_col_no && value[i]->real_item()->type() == Item::ROW_ITEM)
	{
          Item_row *value_tuple= (Item_row *) (value[i]->real_item());
          curr_val= value_tuple->element_index(row_col_no - 1);
        }
        else
          curr_val= value[i];
        if (!(is_const&= curr_val->const_item()))
          break;
      }
      if (is_const)
      {
        stat[0].const_keys.merge(possible_keys);
        bitmap_set_bit(&field->table->cond_set, field->field_index);
      }
      else if (!eq_func)
      {
        /*
          Save info to be able check whether this predicate can be
          considered as sargable for range analisis after reading const tables.
          We do not save info about equalities as update_const_equal_items
          will take care of updating info on keys from sargable equalities.
        */
        (*sargables)--;
        (*sargables)->field= field;
        (*sargables)->arg_value= value;
        (*sargables)->num_values= num_values;
      }
      if (!eq_func) // eq_func is NEVER true when num_values > 1
        return;
    }
  }
  /*
    For the moment eq_func is always true. This slot is reserved for future
    extensions where we want to remembers other things than just eq comparisons
  */
  DBUG_ASSERT(eq_func);
  /* Store possible eq field */
  (*key_fields)->field=		field;
  (*key_fields)->eq_func=	eq_func;
  (*key_fields)->val=		*value;
  (*key_fields)->cond=          cond;
  (*key_fields)->level=         and_level;
  (*key_fields)->optimize=      optimize;
  /*
    If the condition we are analyzing is NULL-rejecting and at least
    one side of the equalities is NULLable, mark the KEY_FIELD object as
    null-rejecting. This property is used by:
    - add_not_null_conds() to add "column IS NOT NULL" conditions
    - best_access_path() to produce better estimates for NULL-able unique keys.
  */
  {
    if ((cond->functype() == Item_func::EQ_FUNC ||
         cond->functype() == Item_func::MULT_EQUAL_FUNC) &&
        ((*value)->maybe_null || field->real_maybe_null()))
      (*key_fields)->null_rejecting= true;
    else
      (*key_fields)->null_rejecting= false;
  }
  (*key_fields)->cond_guard= NULL;

  (*key_fields)->sj_pred_no= get_semi_join_select_list_index(field);
  (*key_fields)++;
}


JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab)
{
  /* If we're inside SJM nest and have reached its end, get out */
  if (tab->last_leaf_in_bush)
    return tab->bush_root_tab;

  /* Move to next tab in the array we're traversing */
  tab++;

  if (tab == join->join_tab +join->top_join_tab_count)
    return NULL; /* Outside SJM nest and reached EOF */

  if (tab->bush_children)
    return tab->bush_children->start;

  return tab;
}


void JOIN::exec_inner()
{
  List<Item> *columns_list= &fields_list;
  DBUG_ENTER("JOIN::exec_inner");
  DBUG_ASSERT(optimization_state == JOIN::OPTIMIZATION_DONE);

  THD_STAGE_INFO(thd, stage_executing);

  /*
    Enable LIMIT ROWS EXAMINED during query execution if:
    (1) This JOIN is the outermost query (not a subquery or derived table)
        This ensures that the limit is enabled when actual execution begins, and
        not if a subquery is evaluated during optimization of the outer query.
    (2) This JOIN is not the result of a UNION. In this case do not apply the
        limit in order to produce the partial query result stored in the
        UNION temp table.
  */
  if (!select_lex->outer_select() &&                            // (1)
      select_lex != select_lex->master_unit()->fake_select_lex) // (2)
    thd->lex->set_limit_rows_examined();

  if (procedure)
  {
    procedure_fields_list= fields_list;
    if (procedure->change_columns(thd, procedure_fields_list) ||
	result->prepare(procedure_fields_list, unit))
    {
      thd->set_examined_row_count(0);
      thd->limit_found_rows= 0;
      DBUG_VOID_RETURN;
    }
    columns_list= &procedure_fields_list;
  }
  if (result->prepare2(this))
    DBUG_VOID_RETURN;

  if (!tables_list && (table_count || !select_lex->with_sum_func) &&
      !select_lex->have_window_funcs())
  {                                           // Only test of functions
    if (select_options & SELECT_DESCRIBE)
      select_describe(this, FALSE, FALSE, FALSE,
		      (zero_result_cause?zero_result_cause:"No tables used"));

    else
    {
      if (result->send_result_set_metadata(*columns_list,
                                           Protocol::SEND_NUM_ROWS |
                                           Protocol::SEND_EOF))
      {
        DBUG_VOID_RETURN;
      }

      /*
        We have to test for 'conds' here as the WHERE may not be constant
        even if we don't have any tables for prepared statements or if
        conds uses something like 'rand()'.
        If the HAVING clause is either impossible or always true, then
        JOIN::having is set to NULL by optimize_cond.
        In this case JOIN::exec must check for JOIN::having_value, in the
        same way it checks for JOIN::cond_value.
      */
      DBUG_ASSERT(error == 0);
      if (cond_value != Item::COND_FALSE &&
          having_value != Item::COND_FALSE &&
          (!conds || conds->val_int()) &&
          (!having || having->val_int()))
      {
	if (do_send_rows &&
            (procedure ? (procedure->send_row(procedure_fields_list) ||
             procedure->end_of_records()) : result->send_data(fields_list)> 0))
	  error= 1;
	else
	  send_records= ((select_options & OPTION_FOUND_ROWS) ? 1 :
                         thd->get_sent_row_count());
      }
      else
        send_records= 0;
      if (likely(!error))
      {
        join_free();                      // Unlock all cursors
        error= (int) result->send_eof();
      }
    }
    /* Single select (without union) always returns 0 or 1 row */
    thd->limit_found_rows= send_records;
    thd->set_examined_row_count(0);
    DBUG_VOID_RETURN;
  }

  /*
    Evaluate expensive constant conditions that were not evaluated during
    optimization. Do not evaluate them for EXPLAIN statements as these
    condtions may be arbitrarily costly, and because the optimize phase
    might not have produced a complete executable plan for EXPLAINs.
  */
  if (!zero_result_cause &&
      exec_const_cond && !(select_options & SELECT_DESCRIBE) &&
      !exec_const_cond->val_int())
    zero_result_cause= "Impossible WHERE noticed after reading const tables";

  /*
    We've called exec_const_cond->val_int(). This may have caused an error.
  */
  if (unlikely(thd->is_error()))
  {
    error= thd->is_error();
    DBUG_VOID_RETURN;
  }

  if (zero_result_cause)
  {
    if (select_lex->have_window_funcs() && send_row_on_empty_set())
    {
      /*
        The query produces just one row but it has window functions.

        The only way to compute the value of window function(s) is to
        run the entire window function computation step (there is no shortcut).
      */
      const_tables= table_count;
      first_select= sub_select_postjoin_aggr;
    }
    else
    {
      (void) return_zero_rows(this, result, select_lex->leaf_tables,
                              *columns_list,
			      send_row_on_empty_set(),
			      select_options,
			      zero_result_cause,
			      having ? having : tmp_having, all_fields);
      DBUG_VOID_RETURN;
    }
  }

  /*
    Evaluate all constant expressions with subqueries in the
    ORDER/GROUP clauses to make sure that all subqueries return a
    single row. The evaluation itself will trigger an error if that is
    not the case.
  */
  if (exec_const_order_group_cond.elements &&
      !(select_options & SELECT_DESCRIBE))
  {
    List_iterator_fast<Item> const_item_it(exec_const_order_group_cond);
    Item *cur_const_item;
    while ((cur_const_item= const_item_it++))
    {
      cur_const_item->val_str(); // This caches val_str() to Item::str_value
      if (unlikely(thd->is_error()))
      {
        error= thd->is_error();
        DBUG_VOID_RETURN;
      }
    }
  }

  if ((this->select_lex->options & OPTION_SCHEMA_TABLE) &&
      get_schema_tables_result(this, PROCESSED_BY_JOIN_EXEC))
    DBUG_VOID_RETURN;

  if (select_options & SELECT_DESCRIBE)
  {
    select_describe(this, need_tmp,
		    order != 0 && !skip_sort_order,
		    select_distinct,
                    !table_count ? "No tables used" : NullS);
    DBUG_VOID_RETURN;
  }
  else
  {
    /* it's a const select, materialize it. */
    select_lex->mark_const_derived(zero_result_cause);
  }

  /*
    Initialize examined rows here because the values from all join parts
    must be accumulated in examined_row_count. Hence every join
    iteration must count from zero.
  */
  join_examined_rows= 0;

  /* XXX: When can we have here thd->is_error() not zero? */
  if (unlikely(thd->is_error()))
  {
    error= thd->is_error();
    DBUG_VOID_RETURN;
  }

  THD_STAGE_INFO(thd, stage_sending_data);
  DBUG_PRINT("info", ("%s", thd->proc_info));
  result->send_result_set_metadata(
                 procedure ? procedure_fields_list : *fields,
                 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);

  error= result->view_structure_only() ? false : do_select(this, procedure);
  /* Accumulate the counts from all join iterations of all join parts. */
  thd->inc_examined_row_count(join_examined_rows);
  DBUG_PRINT("counts", ("thd->examined_row_count: %lu",
                        (ulong) thd->get_examined_row_count()));

  DBUG_VOID_RETURN;
}


void vers_select_conds_t::print(String *str, enum_query_type query_type) const
{
  switch (orig_type) {
  case SYSTEM_TIME_UNSPECIFIED:
    break;
  case SYSTEM_TIME_AS_OF:
    start.print(str, query_type, STRING_WITH_LEN(" FOR SYSTEM_TIME AS OF "));
    break;
  case SYSTEM_TIME_FROM_TO:
    start.print(str, query_type, STRING_WITH_LEN(" FOR SYSTEM_TIME FROM "));
    end.print(str, query_type, STRING_WITH_LEN(" TO "));
    break;
  case SYSTEM_TIME_BETWEEN:
    start.print(str, query_type, STRING_WITH_LEN(" FOR SYSTEM_TIME BETWEEN "));
    end.print(str, query_type, STRING_WITH_LEN(" AND "));
    break;
  case SYSTEM_TIME_BEFORE:
  case SYSTEM_TIME_HISTORY:
    DBUG_ASSERT(0);
    break;
  case SYSTEM_TIME_ALL:
    str->append(" FOR SYSTEM_TIME ALL");
    break;
  }
}


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))
      {
        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))
      {
        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);
      }
    }
  }
}


make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
                     DYNAMIC_ARRAY *keyuse_array)
{
  int error= 0;
  TABLE *UNINIT_VAR(table); /* inited in all loops */
  uint i,table_count,const_count,key;
  table_map found_const_table_map, all_table_map;
  key_map const_ref, eq_part;
  bool has_expensive_keyparts;
  TABLE **table_vector;
  JOIN_TAB *stat,*stat_end,*s,**stat_ref, **stat_vector;
  KEYUSE *keyuse,*start_keyuse;
  table_map outer_join=0;
  table_map no_rows_const_tables= 0;
  SARGABLE_PARAM *sargables= 0;
  List_iterator<TABLE_LIST> ti(tables_list);
  TABLE_LIST *tables;
  DBUG_ENTER("make_join_statistics");

  table_count=join->table_count;

  /*
    best_positions is ok to allocate with alloc() as we copy things to it with
    memcpy()
  */

  if (!multi_alloc_root(join->thd->mem_root,
                        &stat, sizeof(JOIN_TAB)*(table_count),
                        &stat_ref, sizeof(JOIN_TAB*)* MAX_TABLES,
                        &stat_vector, sizeof(JOIN_TAB*)* (table_count +1),
                        &table_vector, sizeof(TABLE*)*(table_count*2),
                        &join->positions, sizeof(POSITION)*(table_count + 1),
                        &join->best_positions,
                        sizeof(POSITION)*(table_count + 1),
                        NullS))
    DBUG_RETURN(1);

  /* The following should be optimized to only clear critical things */
  bzero((void*)stat, sizeof(JOIN_TAB)* table_count);
  /* Initialize POSITION objects */
  for (i=0 ; i <= table_count ; i++)
    (void) new ((char*) (join->positions + i)) POSITION;

  join->best_ref= stat_vector;

  stat_end=stat+table_count;
  found_const_table_map= all_table_map=0;
  const_count=0;

  for (s= stat, i= 0; (tables= ti++); s++, i++)
  {
    TABLE_LIST *embedding= tables->embedding;
    stat_vector[i]=s;
    s->keys.init();
    s->const_keys.init();
    s->checked_keys.init();
    s->needed_reg.init();
    table_vector[i]=s->table=table=tables->table;
    s->tab_list= tables;
    table->pos_in_table_list= tables;
    error= tables->fetch_number_of_rows();
    set_statistics_for_table(join->thd, table);
    bitmap_clear_all(&table->cond_set);

#ifdef WITH_PARTITION_STORAGE_ENGINE
    const bool all_partitions_pruned_away= table->all_partitions_pruned_away;
#else
    const bool all_partitions_pruned_away= FALSE;
#endif

    DBUG_EXECUTE_IF("bug11747970_raise_error",
                    { join->thd->set_killed(KILL_QUERY_HARD); });
    if (unlikely(error))
    {
      table->file->print_error(error, MYF(0));
      goto error;
    }
    table->quick_keys.clear_all();
    table->intersect_keys.clear_all();
    table->reginfo.join_tab=s;
    table->reginfo.not_exists_optimize=0;
    bzero((char*) table->const_key_parts, sizeof(key_part_map)*table->s->keys);
    all_table_map|= table->map;
    s->preread_init_done= FALSE;
    s->join=join;

    s->dependent= tables->dep_tables;
    if (tables->schema_table)
      table->file->stats.records= table->used_stat_records= 2;
    table->quick_condition_rows= table->stat_records();

    s->on_expr_ref= &tables->on_expr;
    if (*s->on_expr_ref)
    {
      /* s is the only inner table of an outer join */
      if (!table->is_filled_at_execution() &&
          ((!table->file->stats.records &&
            (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT)) ||
           all_partitions_pruned_away) && !embedding)
      {						// Empty table
        s->dependent= 0;                        // Ignore LEFT JOIN depend.
        no_rows_const_tables |= table->map;
	set_position(join,const_count++,s,(KEYUSE*) 0);
	continue;
      }
      outer_join|= table->map;
      s->embedding_map= 0;
      for (;embedding; embedding= embedding->embedding)
        s->embedding_map|= embedding->nested_join->nj_map;
      continue;
    }
    if (embedding)
    {
      /* s belongs to a nested join, maybe to several embedded joins */
      s->embedding_map= 0;
      bool inside_an_outer_join= FALSE;
      do
      {
        /*
          If this is a semi-join nest, skip it, and proceed upwards. Maybe
          we're in some outer join nest
        */
        if (embedding->sj_on_expr)
        {
          embedding= embedding->embedding;
          continue;
        }
        inside_an_outer_join= TRUE;
        NESTED_JOIN *nested_join= embedding->nested_join;
        s->embedding_map|=nested_join->nj_map;
        s->dependent|= embedding->dep_tables;
        embedding= embedding->embedding;
        outer_join|= nested_join->used_tables;
      }
      while (embedding);
      if (inside_an_outer_join)
        continue;
    }
    if (!table->is_filled_at_execution() &&
        (table->s->system ||
         (table->file->stats.records <= 1 &&
          (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT)) ||
         all_partitions_pruned_away) &&
	!s->dependent &&
        !table->fulltext_searched && !join->no_const_tables)
    {
      set_position(join,const_count++,s,(KEYUSE*) 0);
      no_rows_const_tables |= table->map;
    }

    /* SJ-Materialization handling: */
    if (table->pos_in_table_list->jtbm_subselect &&
        table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab)
    {
      set_position(join,const_count++,s,(KEYUSE*) 0);
      no_rows_const_tables |= table->map;
    }
  }

  stat_vector[i]=0;
  join->outer_join=outer_join;

  if (join->outer_join)
  {
    /*
       Build transitive closure for relation 'to be dependent on'.
       This will speed up the plan search for many cases with outer joins,
       as well as allow us to catch illegal cross references/
       Warshall's algorithm is used to build the transitive closure.
       As we use bitmaps to represent the relation the complexity
       of the algorithm is O((number of tables)^2).

       The classic form of the Warshall's algorithm would look like:
       for (i= 0; i < table_count; i++)
       {
         for (j= 0; j < table_count; j++)
         {
           for (k= 0; k < table_count; k++)
           {
             if (bitmap_is_set(stat[j].dependent, i) &&
                 bitmap_is_set(stat[i].dependent, k))
               bitmap_set_bit(stat[j].dependent, k);
           }
         }
       }
    */

    for (s= stat ; s < stat_end ; s++)
    {
      table= s->table;
      for (JOIN_TAB *t= stat ; t < stat_end ; t++)
      {
        if (t->dependent & table->map)
          t->dependent |= table->reginfo.join_tab->dependent;
      }
      if (outer_join & s->table->map)
        s->table->maybe_null= 1;
    }
    /* Catch illegal cross references for outer joins */
    for (i= 0, s= stat ; i < table_count ; i++, s++)
    {
      if (s->dependent & s->table->map)
      {
        join->table_count=0;			// Don't use join->table
        my_message(ER_WRONG_OUTER_JOIN,
                   ER_THD(join->thd, ER_WRONG_OUTER_JOIN), MYF(0));
        goto error;
      }
      s->key_dependent= s->dependent;
    }
  }

  if (join->conds || outer_join)
  {
    if (update_ref_and_keys(join->thd, keyuse_array, stat, join->table_count,
                            join->conds, ~outer_join, join->select_lex, &sargables))
      goto error;
    /*
      Keyparts without prefixes may be useful if this JOIN is a subquery, and
      if the subquery may be executed via the IN-EXISTS strategy.
    */
    bool skip_unprefixed_keyparts=
      !(join->is_in_subquery() &&
        ((Item_in_subselect*)join->unit->item)->test_strategy(SUBS_IN_TO_EXISTS));

    if (keyuse_array->elements &&
        sort_and_filter_keyuse(join->thd, keyuse_array,
                               skip_unprefixed_keyparts))
      goto error;
    DBUG_EXECUTE("opt", print_keyuse_array(keyuse_array););
  }

  join->const_table_map= no_rows_const_tables;
  join->const_tables= const_count;
  eliminate_tables(join);
  join->const_table_map &= ~no_rows_const_tables;
  const_count= join->const_tables;
  found_const_table_map= join->const_table_map;

  /* Read tables with 0 or 1 rows (system tables) */
  for (POSITION *p_pos=join->positions, *p_end=p_pos+const_count;
       p_pos < p_end ;
       p_pos++)
  {
    s= p_pos->table;
    if (! (s->table->map & join->eliminated_tables))
    {
      int tmp;
      s->type=JT_SYSTEM;
      join->const_table_map|=s->table->map;
      if ((tmp=join_read_const_table(join->thd, s, p_pos)))
      {
        if (tmp > 0)
          goto error;		// Fatal error
      }
      else
      {
        found_const_table_map|= s->table->map;
        s->table->pos_in_table_list->optimized_away= TRUE;
      }
    }
  }

  /* loop until no more const tables are found */
  int ref_changed;
  do
  {
    ref_changed = 0;
  more_const_tables_found:

    /*
      We only have to loop from stat_vector + const_count as
      set_position() will move all const_tables first in stat_vector
    */

    for (JOIN_TAB **pos=stat_vector+const_count ; (s= *pos) ; pos++)
    {
      table=s->table;

      if (table->is_filled_at_execution())
        continue;

      /*
        If equi-join condition by a key is null rejecting and after a
        substitution of a const table the key value happens to be null
        then we can state that there are no matches for this equi-join.
      */
      if ((keyuse= s->keyuse) && *s->on_expr_ref && !s->embedding_map &&
         !(table->map & join->eliminated_tables))
      {
        /*
          When performing an outer join operation if there are no matching rows
          for the single row of the outer table all the inner tables are to be
          null complemented and thus considered as constant tables.
          Here we apply this consideration to the case of outer join operations
          with a single inner table only because the case with nested tables
          would require a more thorough analysis.
          TODO. Apply single row substitution to null complemented inner tables
          for nested outer join operations.
	*/
        while (keyuse->table == table)
        {
          if (!keyuse->is_for_hash_join() &&
              !(keyuse->val->used_tables() & ~join->const_table_map) &&
              keyuse->val->is_null() && keyuse->null_rejecting)
          {
            s->type= JT_CONST;
            s->table->const_table= 1;
            mark_as_null_row(table);
            found_const_table_map|= table->map;
	    join->const_table_map|= table->map;
	    set_position(join,const_count++,s,(KEYUSE*) 0);
            goto more_const_tables_found;
           }
	  keyuse++;
        }
      }

      if (s->dependent)				// If dependent on some table
      {
	// All dep. must be constants
	if (s->dependent & ~(found_const_table_map))
	  continue;
	if (table->file->stats.records <= 1L &&
	    (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
            !table->pos_in_table_list->embedding &&
	      !((outer_join & table->map) &&
		(*s->on_expr_ref)->is_expensive()))
	{					// system table
	  int tmp= 0;
	  s->type=JT_SYSTEM;
	  join->const_table_map|=table->map;
	  set_position(join,const_count++,s,(KEYUSE*) 0);
	  if ((tmp= join_read_const_table(join->thd, s, join->positions+const_count-1)))
	  {
	    if (tmp > 0)
	      goto error;			// Fatal error
	  }
	  else
	    found_const_table_map|= table->map;
	  continue;
	}
      }
      /* check if table can be read by key or table only uses const refs */
      if ((keyuse=s->keyuse))
      {
	s->type= JT_REF;
	while (keyuse->table == table)
	{
          if (keyuse->is_for_hash_join())
	  {
            keyuse++;
            continue;
          }
	  start_keyuse=keyuse;
	  key=keyuse->key;
	  s->keys.set_bit(key);               // TODO: remove this ?

          const_ref.clear_all();
	  eq_part.clear_all();
          has_expensive_keyparts= false;
	  do
	  {
            if (keyuse->val->type() != Item::NULL_ITEM &&
                !keyuse->optimize &&
                keyuse->keypart != FT_KEYPART)
	    {
	      if (!((~found_const_table_map) & keyuse->used_tables))
              {
		const_ref.set_bit(keyuse->keypart);
                if (keyuse->val->is_expensive())
                  has_expensive_keyparts= true;
              }
	      eq_part.set_bit(keyuse->keypart);
	    }
	    keyuse++;
	  } while (keyuse->table == table && keyuse->key == key);

          TABLE_LIST *embedding= table->pos_in_table_list->embedding;
          /*
            TODO (low priority): currently we ignore the const tables that
            are within a semi-join nest which is within an outer join nest.
            The effect of this is that we don't do const substitution for
            such tables.
          */
          KEY *keyinfo= table->key_info + key;
          uint  key_parts= table->actual_n_key_parts(keyinfo);
          if (eq_part.is_prefix(key_parts) &&
              !table->fulltext_searched &&
              (!embedding || (embedding->sj_on_expr && !embedding->embedding)))
	  {
            key_map base_part, base_const_ref, base_eq_part;
            base_part.set_prefix(keyinfo->user_defined_key_parts);
            base_const_ref= const_ref;
            base_const_ref.intersect(base_part);
            base_eq_part= eq_part;
            base_eq_part.intersect(base_part);
            if (table->actual_key_flags(keyinfo) & HA_NOSAME)
            {

	      if (base_const_ref == base_eq_part &&
                  !has_expensive_keyparts &&
                  !((outer_join & table->map) &&
                    (*s->on_expr_ref)->is_expensive()))
	      {					// Found everything for ref.
	        int tmp;
	        ref_changed = 1;
	        s->type= JT_CONST;
	        join->const_table_map|=table->map;
	        set_position(join,const_count++,s,start_keyuse);
                /* create_ref_for_key will set s->table->const_table */
	        if (create_ref_for_key(join, s, start_keyuse, FALSE,
				       found_const_table_map))
                  goto error;
	        if ((tmp=join_read_const_table(join->thd, s,
                                               join->positions+const_count-1)))
	        {
		  if (tmp > 0)
		    goto error;			// Fatal error
	        }
	        else
		  found_const_table_map|= table->map;
	        break;
	      }
	    }
            else if (base_const_ref == base_eq_part)
              s->const_keys.set_bit(key);
          }
	}
      }
    }
  } while (ref_changed);

  join->sort_by_table= get_sort_by_table(join->order, join->group_list,
                                         join->select_lex->leaf_tables,
                                         join->const_table_map);
  /*
    Update info on indexes that can be used for search lookups as
    reading const tables may has added new sargable predicates.
  */
  if (const_count && sargables)
  {
    for( ; sargables->field ; sargables++)
    {
      Field *field= sargables->field;
      JOIN_TAB *join_tab= field->table->reginfo.join_tab;
      key_map possible_keys= field->key_start;
      possible_keys.intersect(field->table->keys_in_use_for_query);
      bool is_const= 1;
      for (uint j=0; j < sargables->num_values; j++)
        is_const&= sargables->arg_value[j]->const_item();
      if (is_const)
        join_tab[0].const_keys.merge(possible_keys);
    }
  }

  join->impossible_where= false;
  if (join->conds && const_count)
  {
    Item* &conds= join->conds;
    COND_EQUAL *orig_cond_equal = join->cond_equal;

    conds->update_used_tables();
    conds= conds->remove_eq_conds(join->thd, &join->cond_value, true);
    if (conds && conds->type() == Item::COND_ITEM &&
        ((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
      join->cond_equal= &((Item_cond_and*) conds)->m_cond_equal;
    join->select_lex->where= conds;
    if (join->cond_value == Item::COND_FALSE)
    {
      join->impossible_where= true;
      conds= new (join->thd->mem_root) Item_int(join->thd, (longlong) 0, 1);
    }

    join->cond_equal= NULL;
    if (conds)
    {
      if (conds->type() == Item::COND_ITEM &&
	  ((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
        join->cond_equal= (&((Item_cond_and *) conds)->m_cond_equal);
      else if (conds->type() == Item::FUNC_ITEM &&
	       ((Item_func*) conds)->functype() == Item_func::MULT_EQUAL_FUNC)
      {
        if (!join->cond_equal)
          join->cond_equal= new COND_EQUAL;
        join->cond_equal->current_level.empty();
        join->cond_equal->current_level.push_back((Item_equal*) conds,
                                                  join->thd->mem_root);
      }
    }

    if (orig_cond_equal != join->cond_equal)
    {
      /*
        If join->cond_equal has changed all references to it from COND_EQUAL
        objects associated with ON expressions must be updated.
      */
      for (JOIN_TAB **pos=stat_vector+const_count ; (s= *pos) ; pos++)
      {
        if (*s->on_expr_ref && s->cond_equal &&
	    s->cond_equal->upper_levels == orig_cond_equal)
          s->cond_equal->upper_levels= join->cond_equal;
      }
    }
  }

  /* Calc how many (possible) matched records in each table */

  for (s=stat ; s < stat_end ; s++)
  {
    s->startup_cost= 0;
    if (s->type == JT_SYSTEM || s->type == JT_CONST)
    {
      /* Only one matching row */
      s->found_records= s->records= 1;
      s->read_time=1.0;
      s->worst_seeks=1.0;
      continue;
    }
    /* Approximate found rows and time to read them */
    if (s->table->is_filled_at_execution())
    {
      get_delayed_table_estimates(s->table, &s->records, &s->read_time,
                                  &s->startup_cost);
      s->found_records= s->records;
      table->quick_condition_rows=s->records;
    }
    else
    {
       s->scan_time();
    }

    if (s->table->is_splittable())
      s->add_keyuses_for_splitting();

    /*
      Set a max range of how many seeks we can expect when using keys
      This is can't be to high as otherwise we are likely to use
      table scan.
    */
    s->worst_seeks= MY_MIN((double) s->found_records / 10,
			(double) s->read_time*3);
    if (s->worst_seeks < 2.0)			// Fix for small tables
      s->worst_seeks=2.0;

    /*
      Add to stat->const_keys those indexes for which all group fields or
      all select distinct fields participate in one index.
    */
    add_group_and_distinct_keys(join, s);

    s->table->cond_selectivity= 1.0;

    /*
      Perform range analysis if there are keys it could use (1).
      Don't do range analysis for materialized subqueries (2).
      Don't do range analysis for materialized derived tables (3)
    */
    if ((!s->const_keys.is_clear_all() ||
	 !bitmap_is_clear_all(&s->table->cond_set)) &&              // (1)
        !s->table->is_filled_at_execution() &&                      // (2)
        !(s->table->pos_in_table_list->derived &&                   // (3)
          s->table->pos_in_table_list->is_materialized_derived()))  // (3)
    {
      bool impossible_range= FALSE;
      ha_rows records= HA_POS_ERROR;
      SQL_SELECT *select= 0;
      Item **sargable_cond= NULL;
      if (!s->const_keys.is_clear_all())
      {
        sargable_cond= get_sargable_cond(join, s->table);

        select= make_select(s->table, found_const_table_map,
			    found_const_table_map,
                            *sargable_cond,
                            (SORT_INFO*) 0,
			    1, &error);
        if (!select)
          goto error;
        records= get_quick_record_count(join->thd, select, s->table,
				        &s->const_keys, join->row_limit);

        /*
          Range analyzer might have modified the condition. Put it the new
          condition to where we got it from.
        */
        *sargable_cond= select->cond;

        s->quick=select->quick;
        s->needed_reg=select->needed_reg;
        select->quick=0;
        impossible_range= records == 0 && s->table->reginfo.impossible_range;
      }
      if (!impossible_range)
      {
        if (!sargable_cond)
          sargable_cond= get_sargable_cond(join, s->table);
        if (join->thd->variables.optimizer_use_condition_selectivity > 1)
          calculate_cond_selectivity_for_table(join->thd, s->table,
                                               sargable_cond);
        if (s->table->reginfo.impossible_range)
	{
          impossible_range= TRUE;
          records= 0;
        }
      }
      if (impossible_range)
      {
        /*
          Impossible WHERE or ON expression
          In case of ON, we mark that the we match one empty NULL row.
          In case of WHERE, don't set found_const_table_map to get the
          caller to abort with a zero row result.
        */
        TABLE_LIST *emb= s->table->pos_in_table_list->embedding;
        if (emb && !emb->sj_on_expr)
        {
          /* Mark all tables in a multi-table join nest as const */
          mark_join_nest_as_const(join, emb, &found_const_table_map,
                                &const_count);
        }
        else
        {
          join->const_table_map|= s->table->map;
          set_position(join,const_count++,s,(KEYUSE*) 0);
          s->type= JT_CONST;
          s->table->const_table= 1;
          if (*s->on_expr_ref)
          {
            /* Generate empty row */
            s->info= ET_IMPOSSIBLE_ON_CONDITION;
            found_const_table_map|= s->table->map;
            mark_as_null_row(s->table);		// All fields are NULL
          }
        }
      }
      if (records != HA_POS_ERROR)
      {
	s->found_records=records;
	s->read_time= s->quick ? s->quick->read_time : 0.0;
      }
      if (select)
        delete select;
    }

  }

  if (pull_out_semijoin_tables(join))
    DBUG_RETURN(TRUE);

  join->join_tab=stat;
  join->top_join_tab_count= table_count;
  join->map2table=stat_ref;
  join->table= table_vector;
  join->const_tables=const_count;
  join->found_const_table_map=found_const_table_map;

  if (join->const_tables != join->table_count)
    optimize_keyuse(join, keyuse_array);

  DBUG_ASSERT(!join->conds || !join->cond_equal ||
              !join->cond_equal->current_level.elements ||
              (join->conds->type() == Item::COND_ITEM &&
	       ((Item_cond*) (join->conds))->functype() ==
               Item_func::COND_AND_FUNC &&
               join->cond_equal ==
	       &((Item_cond_and *) (join->conds))->m_cond_equal) ||
              (join->conds->type() == Item::FUNC_ITEM &&
	       ((Item_func*) (join->conds))->functype() ==
               Item_func::MULT_EQUAL_FUNC &&
	       join->cond_equal->current_level.elements == 1 &&
               join->cond_equal->current_level.head() == join->conds));

  if (optimize_semijoin_nests(join, all_table_map))
    DBUG_RETURN(TRUE); /* purecov: inspected */

  {
    double records= 1;
    SELECT_LEX_UNIT *unit= join->select_lex->master_unit();

    /* Find an optimal join order of the non-constant tables. */
    if (join->const_tables != join->table_count)
    {
      if (choose_plan(join, all_table_map & ~join->const_table_map))
        goto error;

#ifdef HAVE_valgrind
      // JOIN::positions holds the current query plan. We've already
      // made the plan choice, so we should only use JOIN::best_positions
      for (uint k=join->const_tables; k < join->table_count; k++)
        MEM_UNDEFINED(&join->positions[k], sizeof(join->positions[k]));
#endif
    }
    else
    {
      memcpy((uchar*) join->best_positions,(uchar*) join->positions,
	     sizeof(POSITION)*join->const_tables);
      join->join_record_count= 1.0;
      join->best_read=1.0;
    }

    if (!(join->select_options & SELECT_DESCRIBE) &&
        unit->derived && unit->derived->is_materialized_derived())
    {
      /*
        Calculate estimated number of rows for materialized derived
        table/view.
      */
      for (i= 0; i < join->table_count ; i++)
        if (double rr= join->best_positions[i].records_read)
          records= COST_MULT(records, rr);
      ha_rows rows= records > (double) HA_ROWS_MAX ? HA_ROWS_MAX : (ha_rows) records;
      set_if_smaller(rows, unit->select_limit_cnt);
      join->select_lex->increase_derived_records(rows);
    }
  }

  if (join->choose_subquery_plan(all_table_map & ~join->const_table_map))
    goto error;

  DEBUG_SYNC(join->thd, "inside_make_join_statistics");

  DBUG_RETURN(0);

error:
  /*
    Need to clean up join_tab from TABLEs in case of error.
    They won't get cleaned up by JOIN::cleanup() because JOIN::join_tab
    may not be assigned yet by this function (which is building join_tab).
    Dangling TABLE::reginfo.join_tab may cause part_of_refkey to choke.
  */
  {
    TABLE_LIST *tmp_table;
    List_iterator<TABLE_LIST> ti2(tables_list);
    while ((tmp_table= ti2++))
      tmp_table->table->reginfo.join_tab= NULL;
  }
  DBUG_RETURN (1);
}


static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
				      TABLE *table,
				      const key_map *keys,ha_rows limit)
{
  int error;
  DBUG_ENTER("get_quick_record_count");
  uchar buff[STACK_BUFF_ALLOC];
  if (unlikely(check_stack_overrun(thd, STACK_MIN_SIZE, buff)))
    DBUG_RETURN(0);                           // Fatal error flag is set
  if (select)
  {
    select->head=table;
    table->reginfo.impossible_range=0;
    if (likely((error=
                select->test_quick_select(thd, *(key_map *)keys,
                                          (table_map) 0,
                                          limit, 0, FALSE,
                                          TRUE /* remove_where_parts*/)) ==
               1))
      DBUG_RETURN(select->quick->records);
    if (unlikely(error == -1))
    {
      table->reginfo.impossible_range=1;
      DBUG_RETURN(0);
    }
    DBUG_PRINT("warning",("Couldn't use record count on const keypart"));
  }
  DBUG_RETURN(HA_POS_ERROR);			/* This shouldn't happend */
}