Item_func_between::add_key_fields(JOIN *join, KEY_FIELD **key_fields,
                                  uint *and_level, table_map usable_tables,
                                  SARGABLE_PARAM **sargables)
{
  /*
    Build list of possible keys for 'a BETWEEN low AND high'.
    It is handled similar to the equivalent condition
    'a >= low AND a <= high':
  */
  Item_field *field_item;
  bool equal_func= false;
  uint num_values= 2;

  bool binary_cmp= (args[0]->real_item()->type() == Item::FIELD_ITEM)
        ? ((Item_field*) args[0]->real_item())->field->binary()
        : true;
  /*
    Additional optimization: If 'low = high':
    Handle as if the condition was "t.key = low".
  */
  if (!negated && args[1]->eq(args[2], binary_cmp))
  {
    equal_func= true;
    num_values= 1;
  }

  /*
    Append keys for 'field <cmp> value[]' if the
    condition is of the form::
    '<field> BETWEEN value[1] AND value[2]'
  */
  if (is_local_field(args[0]))
  {
    field_item= (Item_field *) (args[0]->real_item());
    add_key_equal_fields(join, key_fields, *and_level, this,
                         field_item, equal_func, &args[1],
                         num_values, usable_tables, sargables);
  }
  /*
    Append keys for 'value[0] <cmp> field' if the
    condition is of the form:
    'value[0] BETWEEN field1 AND field2'
  */
  for (uint i= 1; i <= num_values; i++)
  {
    if (is_local_field(args[i]))
    {
      field_item= (Item_field *) (args[i]->real_item());
      add_key_equal_fields(join, key_fields, *and_level, this,
                           field_item, equal_func, args,
                           1, usable_tables, sargables);
    }
  }
}


  static void *operator new(size_t size, MEM_ROOT *mem_root)
  {
    return alloc_root(mem_root, size);
  }

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.


Virtual_tmp_table::sp_find_field_by_name_or_error(uint *idx,
                                                  const LEX_CSTRING &var_name,
                                                  const LEX_CSTRING &field_name)
                                                  const
{
  if (sp_find_field_by_name(idx, field_name))
  {
    my_error(ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD, MYF(0),
             var_name.str, field_name.str);
    return true;
  }
  return false;
}


static void update_depend_map_for_order(JOIN *join, ORDER *order)
{
  for (; order ; order=order->next)
  {
    table_map depend_map;
    order->item[0]->update_used_tables();
    order->depend_map=depend_map=order->item[0]->used_tables();
    order->used= 0;
    // Not item_sum(), RAND() and no reference to table outside of sub select
    if (!(order->depend_map & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT))
        && !order->item[0]->with_sum_func &&
        join->join_tab)
    {
      for (JOIN_TAB **tab=join->map2table;
	   depend_map ;
	   tab++, depend_map>>=1)
      {
	if (depend_map & 1)
	  order->depend_map|=(*tab)->ref.depend_map;
      }
    }
  }
}


Item_cond::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
                           bool top_level_arg)
{
  bool and_level= functype() == Item_func::COND_AND_FUNC;
  List<Item> *cond_arg_list= argument_list();

  if (and_level)
  {
    /*
      Remove multiple equalities that became always true (e.g. after
      constant row substitution).
      They would be removed later in the function anyway, but the list of
      them cond_equal.current_level also  must be adjusted correspondingly.
      So it's easier  to do it at one pass through the list of the equalities.
    */
     List<Item_equal> *cond_equalities=
      &((Item_cond_and *) this)->m_cond_equal.current_level;
     cond_arg_list->disjoin((List<Item> *) cond_equalities);
     List_iterator<Item_equal> it(*cond_equalities);
     Item_equal *eq_item;
     while ((eq_item= it++))
     {
       if (eq_item->const_item() && eq_item->val_int())
         it.remove();
     }
     cond_arg_list->append((List<Item> *) cond_equalities);
  }

  List<Item_equal> new_equalities;
  List_iterator<Item> li(*cond_arg_list);
  bool should_fix_fields= 0;
  Item::cond_result tmp_cond_value;
  Item *item;

  /*
    If the list cond_arg_list became empty then it consisted only
    of always true multiple equalities.
  */
  *cond_value= cond_arg_list->elements ? Item::COND_UNDEF : Item::COND_TRUE;

  while ((item=li++))
  {
    Item *new_item= item->remove_eq_conds(thd, &tmp_cond_value, false);
    if (!new_item)
    {
      /* This can happen only when item is converted to TRUE or FALSE */
      li.remove();
    }
    else if (item != new_item)
    {
      /*
        This can happen when:
        - item was an OR formula converted to one disjunct
        - item was an AND formula converted to one conjunct
        In these cases the disjunct/conjunct must be merged into the
        argument list of cond.
      */
      if (new_item->type() == Item::COND_ITEM &&
          item->type() == Item::COND_ITEM)
      {
        DBUG_ASSERT(functype() == ((Item_cond *) new_item)->functype());
        List<Item> *new_item_arg_list=
          ((Item_cond *) new_item)->argument_list();
        if (and_level)
        {
          /*
            If new_item is an AND formula then multiple equalities
            of new_item_arg_list must merged into multiple equalities
            of cond_arg_list.
          */
          List<Item_equal> *new_item_equalities=
            &((Item_cond_and *) new_item)->m_cond_equal.current_level;
          if (!new_item_equalities->is_empty())
          {
            /*
              Cut the multiple equalities from the new_item_arg_list and
              append them on the list new_equalities. Later the equalities
              from this list will be merged into the multiple equalities
              of cond_arg_list all together.
            */
            new_item_arg_list->disjoin((List<Item> *) new_item_equalities);
            new_equalities.append(new_item_equalities);
          }
        }
        if (new_item_arg_list->is_empty())
          li.remove();
        else
        {
          uint cnt= new_item_arg_list->elements;
          li.replace(*new_item_arg_list);
          /* Make iterator li ignore new items */
          for (cnt--; cnt; cnt--)
            li++;
          should_fix_fields= 1;
        }
      }
      else if (and_level &&
               new_item->type() == Item::FUNC_ITEM &&
               ((Item_cond*) new_item)->functype() ==
                Item_func::MULT_EQUAL_FUNC)
      {
        li.remove();
        new_equalities.push_back((Item_equal *) new_item, thd->mem_root);
      }
      else
      {
        if (new_item->type() == Item::COND_ITEM &&
            ((Item_cond*) new_item)->functype() ==  functype())
        {
          List<Item> *new_item_arg_list=
            ((Item_cond *) new_item)->argument_list();
          uint cnt= new_item_arg_list->elements;
          li.replace(*new_item_arg_list);
          /* Make iterator li ignore new items */
          for (cnt--; cnt; cnt--)
            li++;
        }
        else
          li.replace(new_item);
        should_fix_fields= 1;
      }
    }
    if (*cond_value == Item::COND_UNDEF)
      *cond_value= tmp_cond_value;
    switch (tmp_cond_value) {
    case Item::COND_OK:                        // Not TRUE or FALSE
      if (and_level || *cond_value == Item::COND_FALSE)
        *cond_value=tmp_cond_value;
      break;
    case Item::COND_FALSE:
      if (and_level)
      {
        *cond_value= tmp_cond_value;
        return (COND*) 0;                        // Always false
      }
      break;
    case Item::COND_TRUE:
      if (!and_level)
      {
        *cond_value= tmp_cond_value;
        return (COND*) 0;                        // Always true
      }
      break;
    case Item::COND_UNDEF:                        // Impossible
      break; /* purecov: deadcode */
    }
  }
  COND *cond= this;
  if (!new_equalities.is_empty())
  {
    DBUG_ASSERT(and_level);
    /*
      Merge multiple equalities that were cut from the results of
      simplification of OR formulas converted into AND formulas.
      These multiple equalities are to be merged into the
      multiple equalities of  cond_arg_list.
    */
    COND_EQUAL *cond_equal= &((Item_cond_and *) this)->m_cond_equal;
    List<Item_equal> *cond_equalities= &cond_equal->current_level;
    cond_arg_list->disjoin((List<Item> *) cond_equalities);
    Item_equal *equality;
    List_iterator_fast<Item_equal> it(new_equalities);
    while ((equality= it++))
    {
      equality->upper_levels= cond_equal->upper_levels;
      equality->merge_into_list(thd, cond_equalities, false, false);
      List_iterator_fast<Item_equal> ei(*cond_equalities);
      while ((equality= ei++))
      {
        if (equality->const_item() && !equality->val_int())
        {
          *cond_value= Item::COND_FALSE;
          return (COND*) 0;
        }
      }
    }
    cond_arg_list->append((List<Item> *) cond_equalities);
    /*
      Propagate the newly formed multiple equalities to
      the all AND/OR levels of cond
    */
    bool is_simplifiable_cond= false;
    propagate_new_equalities(thd, this, cond_equalities,
                             cond_equal->upper_levels,
                             &is_simplifiable_cond);
    /*
      If the above propagation of multiple equalities brings us
      to multiple equalities that are always FALSE then try to
      simplify the condition with remove_eq_cond() again.
    */
    if (is_simplifiable_cond)
    {
      if (!(cond= cond->remove_eq_conds(thd, cond_value, false)))
        return cond;
    }
    should_fix_fields= 1;
  }
  if (should_fix_fields)
    cond->update_used_tables();

  if (!((Item_cond*) cond)->argument_list()->elements ||
      *cond_value != Item::COND_OK)
    return (COND*) 0;
  if (((Item_cond*) cond)->argument_list()->elements == 1)
  {                                                // Remove list
    item= ((Item_cond*) cond)->argument_list()->head();
    ((Item_cond*) cond)->argument_list()->empty();
    return item;
  }
  *cond_value= Item::COND_OK;
  return cond;
}


bool save_agg_explain_data(JOIN *join, Explain_select *xpl_sel)
{
  JOIN_TAB *join_tab=join->join_tab + join->exec_join_tab_cnt();
  Explain_aggr_node *prev_node;
  Explain_aggr_node *node= xpl_sel->aggr_tree;
  bool is_analyze= join->thd->lex->analyze_stmt;
  THD *thd= join->thd;

  for (uint i= 0; i < join->aggr_tables; i++, join_tab++)
  {
    // Each aggregate means a temp.table
    prev_node= node;
    if (!(node= new (thd->mem_root) Explain_aggr_tmp_table))
      return 1;
    node->child= prev_node;

    if (join_tab->window_funcs_step)
    {
      Explain_aggr_node *new_node=
        join_tab->window_funcs_step->save_explain_plan(thd->mem_root,
                                                       is_analyze);
      if (!new_node)
        return 1;

      prev_node=node;
      node= new_node;
      node->child= prev_node;
    }

    /* The below matches execution in join_init_read_record() */
    if (join_tab->distinct)
    {
      prev_node= node;
      if (!(node= new (thd->mem_root) Explain_aggr_remove_dups))
        return 1;
      node->child= prev_node;
    }

    if (join_tab->filesort)
    {
      Explain_aggr_filesort *eaf =
        new (thd->mem_root) Explain_aggr_filesort(thd->mem_root, is_analyze, join_tab->filesort);
      if (!eaf)
        return 1;
      prev_node= node;
      node= eaf;
      node->child= prev_node;
    }
  }
  xpl_sel->aggr_tree= node;
  return 0;
}


bool TABLE_REF::tmp_table_index_lookup_init(THD *thd,
                                            KEY *tmp_key,
                                            Item_iterator &it,
                                            bool value,
                                            uint skip)
{
  uint tmp_key_parts= tmp_key->user_defined_key_parts;
  uint i;
  DBUG_ENTER("TABLE_REF::tmp_table_index_lookup_init");

  key= 0; /* The only temp table index. */
  key_length= tmp_key->key_length;
  if (!(key_buff=
        (uchar*) thd->calloc(ALIGN_SIZE(tmp_key->key_length) * 2)) ||
      !(key_copy=
        (store_key**) thd->alloc((sizeof(store_key*) *
                                  (tmp_key_parts + 1)))) ||
      !(items=
        (Item**) thd->alloc(sizeof(Item*) * tmp_key_parts)))
    DBUG_RETURN(TRUE);

  key_buff2= key_buff + ALIGN_SIZE(tmp_key->key_length);

  KEY_PART_INFO *cur_key_part= tmp_key->key_part;
  store_key **ref_key= key_copy;
  uchar *cur_ref_buff= key_buff;

  it.open();
  for (i= 0; i < skip; i++) it.next();
  for (i= 0; i < tmp_key_parts; i++, cur_key_part++, ref_key++)
  {
    Item *item= it.next();
    DBUG_ASSERT(item);
    items[i]= item;
    int null_count= MY_TEST(cur_key_part->field->real_maybe_null());
    *ref_key= new store_key_item(thd, cur_key_part->field,
                                 /* TIMOUR:
                                    the NULL byte is taken into account in
                                    cur_key_part->store_length, so instead of
                                    cur_ref_buff + MY_TEST(maybe_null), we could
                                    use that information instead.
                                 */
                                 cur_ref_buff + null_count,
                                 null_count ? cur_ref_buff : 0,
                                 cur_key_part->length, items[i], value);
    cur_ref_buff+= cur_key_part->store_length;
  }
  *ref_key= NULL; /* End marker. */
  key_err= 1;
  key_parts= tmp_key_parts;
  DBUG_RETURN(FALSE);
}


bool dbug_user_var_equals_int(THD *thd, const char *name, int value)
{
  user_var_entry *var;
  LEX_CSTRING varname= { name, strlen(name)};
  if ((var= get_variable(&thd->user_vars, &varname, FALSE)))
  {
    bool null_value;
    longlong var_value= var->val_int(&null_value);
    if (!null_value && var_value == value)
      return TRUE;
  }
  return FALSE;
}


setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array,
                              TABLE_LIST *tables,
                              List<TABLE_LIST> &leaves,
                              List<Item> &fields,
                              List<Item> &all_fields,
                              COND **conds,
                              ORDER *order,
                              ORDER *group,
                              List<Window_spec> &win_specs,
		              List<Item_window_func> &win_funcs,
                              bool *hidden_group_fields,
                              uint *reserved)
{
  int res;
  enum_parsing_place save_place;
  st_select_lex *const select= thd->lex->current_select;
  nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
  /*
    Need to stave the value, so we can turn off only any new non_agg_field_used
    additions coming from the WHERE
  */
  const bool saved_non_agg_field_used= select->non_agg_field_used();
  DBUG_ENTER("setup_without_group");

  thd->lex->allow_sum_func.clear_bit(select->nest_level);
  res= setup_conds(thd, tables, leaves, conds);
  if (thd->lex->current_select->first_cond_optimization)
  {
    if (!res && *conds && ! thd->lex->current_select->merged_into)
      (*reserved)= (*conds)->exists2in_reserved_items();
    else
      (*reserved)= 0;
  }

  /* it's not wrong to have non-aggregated columns in a WHERE */
  select->set_non_agg_field_used(saved_non_agg_field_used);

  thd->lex->allow_sum_func.set_bit(select->nest_level);

  save_place= thd->lex->current_select->context_analysis_place;
  thd->lex->current_select->context_analysis_place= IN_ORDER_BY;
  res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields,
                          order);
  thd->lex->allow_sum_func.clear_bit(select->nest_level);
  thd->lex->current_select->context_analysis_place= IN_GROUP_BY;
  res= res || setup_group(thd, ref_pointer_array, tables, fields, all_fields,
                          group, hidden_group_fields);
  thd->lex->current_select->context_analysis_place= save_place;
  thd->lex->allow_sum_func.set_bit(select->nest_level);
  res= res || setup_windows(thd, ref_pointer_array, tables, fields, all_fields,
                            win_specs, win_funcs);
  thd->lex->allow_sum_func= save_allow_sum_func;
  DBUG_RETURN(res);
}


const_expression_in_where(COND *cond, Item *comp_item, Field *comp_field,
                          Item **const_item)
{
  DBUG_ASSERT((comp_item == NULL) ^ (comp_field == NULL));

  Item *intermediate= NULL;
  if (const_item == NULL)
    const_item= &intermediate;

  if (cond->type() == Item::COND_ITEM)
  {
    bool and_level= (((Item_cond*) cond)->functype()
		     == Item_func::COND_AND_FUNC);
    List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
    Item *item;
    while ((item=li++))
    {
      bool res=const_expression_in_where(item, comp_item, comp_field,
                                         const_item);
      if (res)					// Is a const value
      {
	if (and_level)
	  return 1;
      }
      else if (!and_level)
	return 0;
    }
    return and_level ? 0 : 1;
  }
  else if (cond->eq_cmp_result() != Item::COND_OK)
  {						// boolean compare function
    Item_func* func= (Item_func*) cond;
    if (func->functype() != Item_func::EQUAL_FUNC &&
	func->functype() != Item_func::EQ_FUNC)
      return 0;
    Item *left_item=	((Item_func*) cond)->arguments()[0];
    Item *right_item= ((Item_func*) cond)->arguments()[1];
    if (equal(left_item, comp_item, comp_field))
    {
      if (test_if_equality_guarantees_uniqueness (left_item, right_item))
      {
	if (*const_item)
	  return right_item->eq(*const_item, 1);
	*const_item=right_item;
	return 1;
      }
    }
    else if (equal(right_item, comp_item, comp_field))
    {
      if (test_if_equality_guarantees_uniqueness (right_item, left_item))
      {
	if (*const_item)
	  return left_item->eq(*const_item, 1);
	*const_item=left_item;
	return 1;
      }
    }
  }
  return 0;
}


make_cond_after_sjm(THD *thd, Item *root_cond, Item *cond, table_map tables,
                    table_map sjm_tables, bool inside_or_clause)
{
  /*
    We assume that conditions that refer to only join prefix tables or
    sjm_tables have already been checked.
  */
  if (!inside_or_clause)
  {
    table_map cond_used_tables= cond->used_tables();
    if((!(cond_used_tables & ~tables) ||
       !(cond_used_tables & ~sjm_tables)))
      return (COND*) 0;				// Already checked
  }

  /* AND/OR recursive descent */
  if (cond->type() == Item::COND_ITEM)
  {
    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
    {
      /* Create new top level AND item */
      Item_cond_and *new_cond= new (thd->mem_root) Item_cond_and(thd);
      if (!new_cond)
	return (COND*) 0;			// OOM /* purecov: inspected */
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
      Item *item;
      while ((item=li++))
      {
        Item *fix=make_cond_after_sjm(thd, root_cond, item, tables, sjm_tables,
                                      inside_or_clause);
	if (fix)
	  new_cond->argument_list()->push_back(fix, thd->mem_root);
      }
      switch (new_cond->argument_list()->elements) {
      case 0:
	return (COND*) 0;			// Always true
      case 1:
	return new_cond->argument_list()->head();
      default:
	/*
	  Item_cond_and do not need fix_fields for execution, its parameters
	  are fixed or do not need fix_fields, too
	*/
	new_cond->quick_fix_field();
	new_cond->used_tables_cache=
	  ((Item_cond_and*) cond)->used_tables_cache &
	  tables;
	return new_cond;
      }
    }
    else
    {						// Or list
      Item_cond_or *new_cond= new (thd->mem_root) Item_cond_or(thd);
      if (!new_cond)
	return (COND*) 0;			// OOM /* purecov: inspected */
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
      Item *item;
      while ((item=li++))
      {
        Item *fix= make_cond_after_sjm(thd, root_cond, item, tables, sjm_tables,
                                       /*inside_or_clause= */TRUE);
	if (!fix)
	  return (COND*) 0;			// Always true
	new_cond->argument_list()->push_back(fix, thd->mem_root);
      }
      /*
	Item_cond_or do not need fix_fields for execution, its parameters
	are fixed or do not need fix_fields, too
      */
      new_cond->quick_fix_field();
      new_cond->used_tables_cache= ((Item_cond_or*) cond)->used_tables_cache;
      new_cond->top_level_item();
      return new_cond;
    }
  }

  /*
    Because the following test takes a while and it can be done
    table_count times, we mark each item that we have examined with the result
    of the test
  */

  if (cond->marker == 3 || (cond->used_tables() & ~(tables | sjm_tables)))
    return (COND*) 0;				// Can't check this yet
  if (cond->marker == 2 || cond->eq_cmp_result() == Item::COND_OK)
    return cond;				// Not boolean op

  /*
    Remove equalities that are guaranteed to be true by use of 'ref' access
    method
  */
  if (((Item_func*) cond)->functype() == Item_func::EQ_FUNC)
  {
    Item *left_item= ((Item_func*) cond)->arguments()[0]->real_item();
    Item *right_item= ((Item_func*) cond)->arguments()[1]->real_item();
    if (left_item->type() == Item::FIELD_ITEM &&
	test_if_ref(root_cond, (Item_field*) left_item,right_item))
    {
      cond->marker=3;			// Checked when read
      return (COND*) 0;
    }
    if (right_item->type() == Item::FIELD_ITEM &&
	test_if_ref(root_cond, (Item_field*) right_item,left_item))
    {
      cond->marker=3;			// Checked when read
      return (COND*) 0;
    }
  }
  cond->marker=2;
  return cond;
}


void JOIN::clear()
{
  clear_tables(this, 0);
  copy_fields(&tmp_table_param);

  if (sum_funcs)
  {
    Item_sum *func, **func_ptr= sum_funcs;
    while ((func= *(func_ptr++)))
      func->clear();
  }
}


void Virtual_tmp_table::setup_field_pointers()
{
  uchar *null_pos= record[0];
  uchar *field_pos= null_pos + s->null_bytes;
  uint null_bit= 1;

  for (Field **cur_ptr= field; *cur_ptr; ++cur_ptr)
  {
    Field *cur_field= *cur_ptr;
    if ((cur_field->flags & NOT_NULL_FLAG))
      cur_field->move_field(field_pos);
    else
    {
      cur_field->move_field(field_pos, (uchar*) null_pos, null_bit);
      null_bit<<= 1;
      if (null_bit == (uint)1 << 8)
      {
        ++null_pos;
        null_bit= 1;
      }
    }
    if (cur_field->type() == MYSQL_TYPE_BIT &&
        cur_field->key_type() == HA_KEYTYPE_BIT)
    {
      /* This is a Field_bit since key_type is HA_KEYTYPE_BIT */
      static_cast<Field_bit*>(cur_field)->set_bit_ptr(null_pos, null_bit);
      null_bit+= cur_field->field_length & 7;
      if (null_bit > 7)
      {
        null_pos++;
        null_bit-= 8;
      }
    }
    cur_field->reset();
    field_pos+= cur_field->pack_length();
  }
}


bool JOIN::alloc_func_list()
{
  uint func_count, group_parts;
  DBUG_ENTER("alloc_func_list");

  func_count= tmp_table_param.sum_func_count;
  /*
    If we are using rollup, we need a copy of the summary functions for
    each level
  */
  if (rollup.state != ROLLUP::STATE_NONE)
    func_count*= (send_group_parts+1);

  group_parts= send_group_parts;
  /*
    If distinct, reserve memory for possible
    disctinct->group_by optimization
  */
  if (select_distinct)
  {
    group_parts+= fields_list.elements;
    /*
      If the ORDER clause is specified then it's possible that
      it also will be optimized, so reserve space for it too
    */
    if (order)
    {
      ORDER *ord;
      for (ord= order; ord; ord= ord->next)
        group_parts++;
    }
  }

  /* This must use calloc() as rollup_make_fields depends on this */
  sum_funcs= (Item_sum**) thd->calloc(sizeof(Item_sum**) * (func_count+1) +
				      sizeof(Item_sum***) * (group_parts+1));
  sum_funcs_end= (Item_sum***) (sum_funcs+func_count+1);
  DBUG_RETURN(sum_funcs == 0);
}


test_if_subpart(ORDER *a,ORDER *b)
{
  for (; a && b; a=a->next,b=b->next)
  {
    if ((*a->item)->eq(*b->item,1))
      a->direction=b->direction;
    else
      return 0;
  }
  return MY_TEST(!b);
}


end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
	  bool end_of_records)
{
  TABLE *const table= join_tab->table;
  DBUG_ENTER("end_write");

  if (!end_of_records)
  {
    copy_fields(join_tab->tmp_table_param);
    if (copy_funcs(join_tab->tmp_table_param->items_to_copy, join->thd))
      DBUG_RETURN(NESTED_LOOP_ERROR);           /* purecov: inspected */

    if (likely(!join_tab->having || join_tab->having->val_int()))
    {
      int error;
      join->found_records++;
      if ((error= table->file->ha_write_tmp_row(table->record[0])))
      {
        if (likely(!table->file->is_fatal_error(error, HA_CHECK_DUP)))
	  goto end;                             // Ignore duplicate keys
        bool is_duplicate;
	if (create_internal_tmp_table_from_heap(join->thd, table,
                                                join_tab->tmp_table_param->start_recinfo,
                                                &join_tab->tmp_table_param->recinfo,
                                                error, 1, &is_duplicate))
	  DBUG_RETURN(NESTED_LOOP_ERROR);        // Not a table_is_full error
        if (is_duplicate)
          goto end;
	table->s->uniques=0;			// To ensure rows are the same
      }
      if (++join_tab->send_records >=
            join_tab->tmp_table_param->end_write_records &&
	  join->do_send_rows)
      {
	if (!(join->select_options & OPTION_FOUND_ROWS))
	  DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT);
	join->do_send_rows=0;
	join->unit->select_limit_cnt = HA_POS_ERROR;
      }
    }
  }
end:
  if (unlikely(join->thd->check_killed()))
  {
    DBUG_RETURN(NESTED_LOOP_KILLED);             /* purecov: inspected */
  }
  DBUG_RETURN(NESTED_LOOP_OK);
}


change_refs_to_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array,
			  List<Item> &res_selected_fields,
			  List<Item> &res_all_fields, uint elements,
			  List<Item> &all_fields)
{
  List_iterator_fast<Item> it(all_fields);
  Item *item, *new_item;
  res_selected_fields.empty();
  res_all_fields.empty();

  uint i, border= all_fields.elements - elements;
  for (i= 0; (item= it++); i++)
  {
    if (item->type() == Item::SUM_FUNC_ITEM && item->const_item())
      new_item= item;
    else
    {
      if (!(new_item= item->get_tmp_table_item(thd)))
        return 1;
    }

    if (res_all_fields.push_back(new_item, thd->mem_root))
      return 1;
    ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
      new_item;
  }

  List_iterator_fast<Item> itr(res_all_fields);
  for (i= 0; i < border; i++)
    itr++;
  itr.sublist(res_selected_fields, elements);

  return thd->is_fatal_error;
}


static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr)
{
  Item_sum *func;
  DBUG_ENTER("setup_sum_funcs");
  while ((func= *(func_ptr++)))
  {
    if (func->aggregator_setup(thd))
      DBUG_RETURN(TRUE);
  }
  DBUG_RETURN(FALSE);
}


alloc_group_fields(JOIN *join,ORDER *group)
{
  if (group)
  {
    for (; group ; group=group->next)
    {
      Cached_item *tmp=new_Cached_item(join->thd, *group->item, TRUE);
      if (!tmp || join->group_fields.push_front(tmp))
	return TRUE;
    }
  }
  join->sort_and_group=1;			/* Mark for do_select */
  return FALSE;
}


COND *Item_func::build_equal_items(THD *thd, COND_EQUAL *inherited,
                                   bool link_item_fields,
                                   COND_EQUAL **cond_equal_ref)
{
  /*
    For each field reference in cond, not from equal item predicates,
    set a pointer to the multiple equality it belongs to (if there is any)
    as soon the field is not of a string type or the field reference is
    an argument of a comparison predicate.
  */
  COND *cond= propagate_equal_fields(thd, Context_boolean(), inherited);
  cond->update_used_tables();
  DBUG_ASSERT(cond == this);
  DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]);
  return cond;
}


is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part,
	  KEY_PART_INFO *ref_key_part_end)
{
  for (; ref_key_part < ref_key_part_end; key_part++, ref_key_part++)
    if (!key_part->field->eq(ref_key_part->field))
      return 0;
  return 1;
}


void propagate_new_equalities(THD *thd, Item *cond,
                              List<Item_equal> *new_equalities,
                              COND_EQUAL *inherited,
                              bool *is_simplifiable_cond)
{
  if (cond->type() == Item::COND_ITEM)
  {
    bool and_level= ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC;
    if (and_level)
    {
      Item_cond_and *cond_and= (Item_cond_and *) cond;
      List<Item_equal> *cond_equalities= &cond_and->m_cond_equal.current_level;
      cond_and->m_cond_equal.upper_levels= inherited;
      if (!cond_equalities->is_empty() && cond_equalities != new_equalities)
      {
        Item_equal *equal_item;
        List_iterator<Item_equal> it(*new_equalities);
	while ((equal_item= it++))
	{
          equal_item->merge_into_list(thd, cond_equalities, true, true);
        }
        List_iterator<Item_equal> ei(*cond_equalities);
        while ((equal_item= ei++))
	{
          if (equal_item->const_item() && !equal_item->val_int())
	  {
            *is_simplifiable_cond= true;
            return;
          }
        }
      }
    }

    Item *item;
    List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
    while ((item= li++))
    {
      COND_EQUAL *new_inherited= and_level && item->type() == Item::COND_ITEM ?
                                   &((Item_cond_and *) cond)->m_cond_equal :
                                   inherited;
      propagate_new_equalities(thd, item, new_equalities, new_inherited,
                               is_simplifiable_cond);
    }
  }
  else if (cond->type() == Item::FUNC_ITEM &&
           ((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
  {
    Item_equal *equal_item;
    List_iterator<Item_equal> it(*new_equalities);
    Item_equal *equality= (Item_equal *) cond;
    equality->upper_levels= inherited;
    while ((equal_item= it++))
    {
      equality->merge_with_check(thd, equal_item, true);
    }
    if (equality->const_item() && !equality->val_int())
      *is_simplifiable_cond= true;
  }
  else
  {
    cond= cond->propagate_equal_fields(thd,
                                       Item::Context_boolean(), inherited);
    cond->update_used_tables();
  }
}


void revise_cache_usage(JOIN_TAB *join_tab)
{
  JOIN_TAB *tab;
  JOIN_TAB *first_inner;

  if (join_tab->first_inner)
  {
    JOIN_TAB *end_tab= join_tab;
    for (first_inner= join_tab->first_inner;
         first_inner;
         first_inner= first_inner->first_upper)
    {
      for (tab= end_tab; tab >= first_inner; tab--)
        set_join_cache_denial(tab);
      end_tab= first_inner;
    }
  }
  else if (join_tab->first_sj_inner_tab)
  {
    first_inner= join_tab->first_sj_inner_tab;
    for (tab= join_tab; tab >= first_inner; tab--)
    {
      set_join_cache_denial(tab);
    }
  }
  else set_join_cache_denial(join_tab);
}


join_read_prev_same(READ_RECORD *info)
{
  int error;
  TABLE *table= info->table;
  JOIN_TAB *tab=table->reginfo.join_tab;

  if (unlikely((error= table->file->ha_index_prev(table->record[0]))))
    return report_error(table, error);
  if (key_cmp_if_same(table, tab->ref.key_buff, tab->ref.key,
                      tab->ref.key_length))
  {
    table->status=STATUS_NOT_FOUND;
    error= -1;
  }
  return error;
}


Item_func_trig_cond::add_key_fields(JOIN *join, KEY_FIELD **key_fields,
                                    uint *and_level, table_map usable_tables,
                                    SARGABLE_PARAM **sargables)
{
  /*
    Subquery optimization: Conditions that are pushed down into subqueries
    are wrapped into Item_func_trig_cond. We process the wrapped condition
    but need to set cond_guard for KEYUSE elements generated from it.
  */
  if (!join->group_list && !join->order &&
      join->unit->item &&
      join->unit->item->substype() == Item_subselect::IN_SUBS &&
      !join->unit->is_unit_op())
  {
    KEY_FIELD *save= *key_fields;
    args[0]->add_key_fields(join, key_fields, and_level, usable_tables,
                            sargables);
    // Indicate that this ref access candidate is for subquery lookup:
    for (; save != *key_fields; save++)
      save->cond_guard= get_trig_var();
  }
}


int rr_sequential_and_unpack(READ_RECORD *info)
{
  int error;
  if (unlikely((error= rr_sequential(info))))
    return error;

  for (Copy_field *cp= info->copy_field; cp != info->copy_field_end; cp++)
    (*cp->do_copy)(cp);

  return error;
}


Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
                            bool *inherited_fl)
{
  Item_equal *item= 0;
  bool in_upper_level= FALSE;
  while (cond_equal)
  {
    List_iterator_fast<Item_equal> li(cond_equal->current_level);
    while ((item= li++))
    {
      if (item->contains(field))
        goto finish;
    }
    in_upper_level= TRUE;
    cond_equal= cond_equal->upper_levels;
  }
  in_upper_level= FALSE;
finish:
  *inherited_fl= in_upper_level;
  return item;
}


void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
{
  KEYUSE *end,*keyuse= dynamic_element(keyuse_array, 0, KEYUSE*);

  for (end= keyuse+ keyuse_array->elements ; keyuse < end ; keyuse++)
  {
    table_map map;
    /*
      If we find a ref, assume this table matches a proportional
      part of this table.
      For example 100 records matching a table with 5000 records
      gives 5000/100 = 50 records per key
      Constant tables are ignored.
      To avoid bad matches, we don't make ref_table_rows less than 100.
    */
    keyuse->ref_table_rows= ~(ha_rows) 0;	// If no ref
    if (keyuse->used_tables &
	(map= (keyuse->used_tables & ~join->const_table_map &
	       ~OUTER_REF_TABLE_BIT)))
    {
      uint n_tables= my_count_bits(map);
      if (n_tables == 1)			// Only one table
      {
        DBUG_ASSERT(!(map & PSEUDO_TABLE_BITS)); // Must be a real table
        Table_map_iterator it(map);
        int tablenr= it.next_bit();
        DBUG_ASSERT(tablenr != Table_map_iterator::BITMAP_END);
	TABLE *tmp_table=join->table[tablenr];
        if (tmp_table) // already created
          keyuse->ref_table_rows= MY_MAX(tmp_table->file->stats.records, 100);
      }
    }
    /*
      Outer reference (external field) is constant for single executing
      of subquery
    */
    if (keyuse->used_tables == OUTER_REF_TABLE_BIT)
      keyuse->ref_table_rows= 1;
  }
}


is_local_field (Item *field)
{
  return field->real_item()->type() == Item::FIELD_ITEM
     && !(field->used_tables() & OUTER_REF_TABLE_BIT)
    && !((Item_field *)field->real_item())->get_depended_from();
}


uint find_shortest_key(TABLE *table, const key_map *usable_keys)
{
  double min_cost= DBL_MAX;
  uint best= MAX_KEY;
  if (!usable_keys->is_clear_all())
  {
    for (uint nr=0; nr < table->s->keys ; nr++)
    {
      if (usable_keys->is_set(nr))
      {
        double cost= table->file->keyread_time(nr, 1, table->file->records());
        if (cost < min_cost)
        {
          min_cost= cost;
          best=nr;
        }
        DBUG_ASSERT(best < MAX_KEY);
      }
    }
  }
  return best;
}


Item::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;
  }
  *cond_value= Item::COND_OK;
  return this;                                        // Point at next and level
}


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

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

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


static bool are_tables_local(JOIN_TAB *jtab, table_map used_tables)
{
  if (jtab->bush_root_tab)
  {
    /*
      jtab is inside execution join nest. We may not refer to outside tables,
      except the const tables.
    */
    table_map local_tables= jtab->emb_sj_nest->nested_join->used_tables |
                            jtab->join->const_table_map |
                            OUTER_REF_TABLE_BIT;
    return !MY_TEST(used_tables & ~local_tables);
  }

  /*
    If we got here then jtab is at top level.
     - all other tables at top level are accessible,
     - tables in join nests are accessible too, because all their columns that
       are needed at top level will be unpacked when scanning the
       materialization table.
  */
  return TRUE;
}


void JOIN::drop_unused_derived_keys()
{
  JOIN_TAB *tab;
  for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
       tab;
       tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
  {

    TABLE *tmp_tbl= tab->table;
    if (!tmp_tbl)
      continue;
    if (!tmp_tbl->pos_in_table_list->is_materialized_derived())
      continue;
    if (tmp_tbl->max_keys > 1 && !tab->is_ref_for_hash_join())
      tmp_tbl->use_index(tab->ref.key);
    if (tmp_tbl->s->keys)
    {
      if (tab->ref.key >= 0 && tab->ref.key < MAX_KEY)
        tab->ref.key= 0;
      else
        tmp_tbl->s->keys= 0;
    }
    tab->keys= (key_map) (tmp_tbl->s->keys ? 1 : 0);
  }
}


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

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

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

  if (join)
  {
    uint tablenr= (uint)(tab - join->join_tab);
    read_time= join->best_positions[tablenr].read_time;
    for (uint i= tablenr+1; i < join->table_count; i++)
      fanout*= join->best_positions[i].records_read; // fanout is always >= 1
  }
  else
    read_time= table->file->scan_time();

  /*
    TODO: add cost of sorting here.
  */
  read_time += COST_EPS;

  /*
    Calculate the selectivity of the ref_key for REF_ACCESS. For
    RANGE_ACCESS we use table->quick_condition_rows.
  */
  if (ref_key >= 0 && ref_key != MAX_KEY && tab->type == JT_REF)
  {
    /*
      If ref access uses keypart=const for all its key parts,
      and quick select uses the same # of key parts, then they are equivalent.
      Reuse #rows estimate from quick select as it is more precise.
    */
    if (tab->ref.const_ref_part_map ==
        make_prev_keypart_map(tab->ref.key_parts) &&
        table->quick_keys.is_set(ref_key) &&
        table->quick_key_parts[ref_key] == tab->ref.key_parts)
      refkey_rows_estimate= table->quick_rows[ref_key];
    else
    {
      const KEY *ref_keyinfo= table->key_info + ref_key;
      refkey_rows_estimate= ref_keyinfo->rec_per_key[tab->ref.key_parts - 1];
    }
    set_if_bigger(refkey_rows_estimate, 1);
  }

  for (nr=0; nr < table->s->keys ; nr++)
  {
    int direction;
    ha_rows select_limit= select_limit_arg;
    uint used_key_parts= 0;

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

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

        /*
          If tab=tk is not the last joined table tn then to get first
          L records from the result set we can expect to retrieve
          only L/fanout(tk,tn) where fanout(tk,tn) says how many
          rows in the record set on average will match each row tk.
          Usually our estimates for fanouts are too pessimistic.
          So the estimate for L/fanout(tk,tn) will be too optimistic
          and as result we'll choose an index scan when using ref/range
          access + filesort will be cheaper.
        */
        select_limit= (ha_rows) (select_limit < fanout ?
                                 1 : select_limit/fanout);
        /*
          We assume that each of the tested indexes is not correlated
          with ref_key. Thus, to select first N records we have to scan
          N/selectivity(ref_key) index entries.
          selectivity(ref_key) = #scanned_records/#table_records =
          refkey_rows_estimate/table_records.
          In any case we can't select more than #table_records.
          N/(refkey_rows_estimate/table_records) > table_records
          <=> N > refkey_rows_estimate.
         */
        if (select_limit > refkey_rows_estimate)
          select_limit= table_records;
        else
          select_limit= (ha_rows) (select_limit *
                                   (double) table_records /
                                    refkey_rows_estimate);
        rec_per_key= keyinfo->actual_rec_per_key(keyinfo->user_defined_key_parts-1);
        set_if_bigger(rec_per_key, 1);
        /*
          Here we take into account the fact that rows are
          accessed in sequences rec_per_key records in each.
          Rows in such a sequence are supposed to be ordered
          by rowid/primary key. When reading the data
          in a sequence we'll touch not more pages than the
          table file contains.
          TODO. Use the formula for a disk sweep sequential access
          to calculate the cost of accessing data rows for one
          index entry.
        */
        index_scan_time= select_limit/rec_per_key *
                         MY_MIN(rec_per_key, table->file->scan_time());
        double range_scan_time;
        if (get_range_limit_read_cost(tab, table, nr, select_limit,
                                       &range_scan_time))
        {
          if (range_scan_time < index_scan_time)
            index_scan_time= range_scan_time;
        }

        if ((ref_key < 0 && (group || table->force_index || is_covering)) ||
            index_scan_time < read_time)
        {
          ha_rows quick_records= table_records;
          ha_rows refkey_select_limit= (ref_key >= 0 &&
                                        !is_hash_join_key_no(ref_key) &&
                                        table->covering_keys.is_set(ref_key)) ?
                                        refkey_rows_estimate :
                                        HA_POS_ERROR;
          if ((is_best_covering && !is_covering) ||
              (is_covering && refkey_select_limit < select_limit))
            continue;
          if (table->quick_keys.is_set(nr))
            quick_records= table->quick_rows[nr];
          if (best_key < 0 ||
              (select_limit <= MY_MIN(quick_records,best_records) ?
               keyinfo->user_defined_key_parts < best_key_parts :
               quick_records < best_records) ||
              (!is_best_covering && is_covering))
          {
            best_key= nr;
            best_key_parts= keyinfo->user_defined_key_parts;
            if (saved_best_key_parts)
              *saved_best_key_parts= used_key_parts;
            best_records= quick_records;
            is_best_covering= is_covering;
            best_key_direction= direction;
            best_select_limit= select_limit;
          }
        }
      }
    }
  }

  if (best_key < 0 || best_key == ref_key)
    DBUG_RETURN(FALSE);

  *new_key= best_key;
  *new_key_direction= best_key_direction;
  *new_select_limit= has_limit ? best_select_limit : table_records;
  if (new_used_key_parts != NULL)
    *new_used_key_parts= best_key_parts;

  DBUG_RETURN(TRUE);
}


bool Item_func_eq::check_equality(THD *thd, COND_EQUAL *cond_equal,
                                  List<Item> *eq_list)
{
  Item *left_item= arguments()[0];
  Item *right_item= arguments()[1];

  if (left_item->type() == Item::ROW_ITEM &&
      right_item->type() == Item::ROW_ITEM)
  {
    /*
      Item_splocal::type() for ROW variables returns Item::ROW_ITEM.
      Distinguish ROW-type Item_splocal from Item_row.
      Example query:
        SELECT 1 FROM DUAL WHERE row_sp_variable=ROW(100,200);
    */
    if (left_item->get_item_splocal() ||
        right_item->get_item_splocal())
      return false;
    return check_row_equality(thd,
                              cmp.subcomparators(),
                              (Item_row *) left_item,
                              (Item_row *) right_item,
                              cond_equal, eq_list);
  }
  return check_simple_equality(thd,
                               Context(ANY_SUBST,
                                       compare_type_handler(),
                                       compare_collation()),
                               left_item, right_item, cond_equal);
}


add_key_equal_fields(JOIN *join, KEY_FIELD **key_fields, uint and_level,
                     Item_bool_func *cond, Item *field_item,
                     bool eq_func, Item **val,
                     uint num_values, table_map usable_tables,
                     SARGABLE_PARAM **sargables, uint row_col_no= 0)
{
  Field *field= ((Item_field *) (field_item->real_item()))->field;
  add_key_field(join, key_fields, and_level, cond, field,
                eq_func, val, num_values, usable_tables, sargables,
                row_col_no);
  Item_equal *item_equal= field_item->get_item_equal();
  if (item_equal)
  {
    /*
      Add to the set of possible key values every substitution of
      the field for an equal field included into item_equal
    */
    Item_equal_fields_iterator it(*item_equal);
    while (it++)
    {
      Field *equal_field= it.get_curr_field();
      if (!field->eq(equal_field))
      {
        add_key_field(join, key_fields, and_level, cond, equal_field,
                      eq_func, val, num_values, usable_tables,
                      sargables, row_col_no);
      }
    }
  }
}


evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab)
{
  /*
    The table join_tab is the first inner table of a outer join operation
    and no matches has been found for the current outer row.
  */
  JOIN_TAB *last_inner_tab= join_tab->last_inner;
  /* Cache variables for faster loop */
  COND *select_cond;
  for ( ; join_tab <= last_inner_tab ; join_tab++)
  {
    /* Change the the values of guard predicate variables. */
    join_tab->found= 1;
    join_tab->not_null_compl= 0;
    /* The outer row is complemented by nulls for each inner tables */
    restore_record(join_tab->table,s->default_values);  // Make empty record
    mark_as_null_row(join_tab->table);       // For group by without error
    select_cond= join_tab->select_cond;
    /* Check all attached conditions for inner table rows. */
    if (select_cond && !select_cond->val_int())
      return NESTED_LOOP_OK;
  }
  join_tab--;
  /*
    The row complemented by nulls might be the first row
    of embedding outer joins.
    If so, perform the same actions as in the code
    for the first regular outer join row above.
  */
  for ( ; ; )
  {
    JOIN_TAB *first_unmatched= join_tab->first_unmatched;
    if ((first_unmatched= first_unmatched->first_upper) &&
        first_unmatched->last_inner != join_tab)
      first_unmatched= 0;
    join_tab->first_unmatched= first_unmatched;
    if (!first_unmatched)
      break;
    first_unmatched->found= 1;
    for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++)
    {
      if (tab->select_cond && !tab->select_cond->val_int())
      {
        join->return_tab= tab;
        return NESTED_LOOP_OK;
      }
    }
  }
  /*
    The row complemented by nulls satisfies all conditions
    attached to inner tables.
  */
  if (join_tab->check_weed_out_table)
  {
    int res= join_tab->check_weed_out_table->sj_weedout_check_row(join->thd);
    if (res == -1)
      return NESTED_LOOP_ERROR;
    else if (res == 1)
      return NESTED_LOOP_OK;
  }
  else if (join_tab->do_firstmatch)
  {
    /*
      We should return to the join_tab->do_firstmatch after we have
      enumerated all the suffixes for current prefix row combination
    */
    if (join_tab->do_firstmatch < join->return_tab)
      join->return_tab= join_tab->do_firstmatch;
  }

  /*
    Send the row complemented by nulls to be joined with the
    remaining tables.
  */
  return (*join_tab->next_select)(join, join_tab+1, 0);
}


void free_underlaid_joins(THD *thd, SELECT_LEX *select)
{
  for (SELECT_LEX_UNIT *unit= select->first_inner_unit();
       unit;
       unit= unit->next_unit())
    unit->cleanup();
}


static TABLE_LIST* get_emb_subq(JOIN_TAB *tab)
{
  TABLE_LIST *tlist= tab->table->pos_in_table_list;
  if (tlist->jtbm_subselect)
    return tlist;
  TABLE_LIST *embedding= tlist->embedding;
  if (!embedding || !embedding->sj_subq_pred)
    return NULL;
  return embedding;
}


static int compare_fields_by_table_order(Item *field1,
                                         Item *field2,
                                         void *table_join_idx)
{
  int cmp= 0;
  bool outer_ref= 0;
  Item *field1_real= field1->real_item();
  Item *field2_real= field2->real_item();

  if (field1->const_item() || field1_real->const_item())
    return -1;
  if (field2->const_item() || field2_real->const_item())
    return 1;
  Item_field *f1= (Item_field *) field1_real;
  Item_field *f2= (Item_field *) field2_real;
  if (f1->used_tables() & OUTER_REF_TABLE_BIT)
  {
    outer_ref= 1;
    cmp= -1;
  }
  if (f2->used_tables() & OUTER_REF_TABLE_BIT)
  {
    outer_ref= 1;
    cmp++;
  }
  if (outer_ref)
    return cmp;
  JOIN_TAB **idx= (JOIN_TAB **) table_join_idx;

  JOIN_TAB *tab1= idx[f1->field->table->tablenr];
  JOIN_TAB *tab2= idx[f2->field->table->tablenr];

  /*
    if one of the table is inside a merged SJM nest and another one isn't,
    compare SJM bush roots of the tables.
  */
  if (tab1->bush_root_tab != tab2->bush_root_tab)
  {
    if (tab1->bush_root_tab)
      tab1= tab1->bush_root_tab;

    if (tab2->bush_root_tab)
      tab2= tab2->bush_root_tab;
  }

  cmp= (int)(tab1 - tab2);

  if (!cmp)
  {
    /* Fields f1, f2 belong to the same table */

    JOIN_TAB *tab= idx[f1->field->table->tablenr];
    uint keyno= MAX_KEY;
    if (tab->ref.key_parts)
      keyno= tab->ref.key;
    else if (tab->select && tab->select->quick)
       keyno = tab->select->quick->index;
    if (keyno != MAX_KEY)
    {
      if (f1->field->part_of_key.is_set(keyno))
        cmp= -1;
      if (f2->field->part_of_key.is_set(keyno))
        cmp++;
      /*
        Here:
        if both f1, f2 are components of the key tab->ref.key then cmp==0,
        if only f1 is a component of the key then cmp==-1 (f1 is better),
        if only f2 is a component of the key then cmp==1, (f2 is better),
        if none of f1,f1 is component of the key cmp==0.
      */
      if (!cmp)
      {
        KEY *key_info= tab->table->key_info + keyno;
        for (uint i= 0; i < key_info->user_defined_key_parts; i++)
	{
          Field *fld= key_info->key_part[i].field;
          if (fld->eq(f1->field))
	  {
	    cmp= -1; // f1 is better
            break;
          }
          if (fld->eq(f2->field))
	  {
	    cmp= 1;  // f2 is better
            break;
          }
        }
      }
    }
    if (!cmp)
      cmp= f1->field->field_index-f2->field->field_index;
  }
  return cmp < 0 ? -1 : (cmp ? 1 : 0);
}


bool Virtual_tmp_table::open()
{
  // Make sure that we added all the fields we planned to:
  DBUG_ASSERT(s->fields == m_alloced_field_count);
  field[s->fields]= NULL;            // mark the end of the list
  s->blob_field[s->blob_fields]= 0;  // mark the end of the list

  uint null_pack_length= (s->null_fields + 7) / 8; // NULL-bit array length
  s->reclength+= null_pack_length;
  s->rec_buff_length= ALIGN_SIZE(s->reclength + 1);
  if (!(record[0]= (uchar*) in_use->alloc(s->rec_buff_length)))
    return true;
  if (null_pack_length)
  {
    null_flags= (uchar*) record[0];
    s->null_bytes= s->null_bytes_for_compare= null_pack_length;
  }
  setup_field_pointers();
  return false;
}


find_field_in_item_list (Field *field, void *data)
{
  List<Item> *fields= (List<Item> *) data;
  bool part_found= 0;
  List_iterator<Item> li(*fields);
  Item *item;

  while ((item= li++))
  {
    if (item->real_item()->type() == Item::FIELD_ITEM &&
	((Item_field*) (item->real_item()))->field->eq(field))
    {
      part_found= 1;
      break;
    }
  }
  return part_found;
}


Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
                                  bool top_level_arg)
{
  Item *real_item= args[0]->real_item();
  if (real_item->type() == Item::FIELD_ITEM)
  {
    Field *field= ((Item_field*) real_item)->field;

    if (((field->type() == MYSQL_TYPE_DATE) ||
         (field->type() == MYSQL_TYPE_DATETIME)) &&
         (field->flags & NOT_NULL_FLAG))
    {
      /* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */
      /*
        See BUG#12594011
        Documentation says that
        SELECT datetime_notnull d FROM t1 WHERE d IS NULL
        shall return rows where d=='0000-00-00'

        Thus, for DATE and DATETIME columns defined as NOT NULL,
        "date_notnull IS NULL" has to be modified to
        "date_notnull IS NULL OR date_notnull == 0" (if outer join)
        "date_notnull == 0"                         (otherwise)

      */

      Item *item0= new(thd->mem_root) Item_int(thd, (longlong) 0, 1);
      Item *eq_cond= new(thd->mem_root) Item_func_eq(thd, args[0], item0);
      if (!eq_cond)
        return this;

      COND *cond= this;
      if (field->table->pos_in_table_list->is_inner_table_of_outer_join())
      {
        // outer join: transform "col IS NULL" to "col IS NULL or col=0"
        Item *or_cond= new(thd->mem_root) Item_cond_or(thd, eq_cond, this);
        if (!or_cond)
          return this;
        cond= or_cond;
      }
      else
      {
        // not outer join: transform "col IS NULL" to "col=0"
        cond= eq_cond;
      }

      cond->fix_fields(thd, &cond);
      /*
        Note: although args[0] is a field, cond can still be a constant
        (in case field is a part of a dependent subquery).

        Note: we call cond->Item::remove_eq_conds() non-virtually (statically)
        for performance purpose.
        A non-qualified call, i.e. just cond->remove_eq_conds(),
        would call Item_bool_func2::remove_eq_conds() instead, which would
        try to do some extra job to detect if args[0] and args[1] are
        equivalent items. We know they are not (we have field=0 here).
      */
      return cond->Item::remove_eq_conds(thd, cond_value, false);
    }

    /*
      Handles this special case for some ODBC applications:
      The are requesting the row that was just updated with a auto_increment
      value with this construct:

      SELECT * from table_name where auto_increment_column IS NULL
      This will be changed to:
      SELECT * from table_name where auto_increment_column = LAST_INSERT_ID

      Note, this substitution is done if the NULL test is the only condition!
      If the NULL test is a part of a more complex condition, it is not
      substituted and is treated normally:
        WHERE auto_increment IS NULL AND something_else
    */

    if (top_level_arg) // "auto_increment_column IS NULL" is the only condition
    {
      if (field->flags & AUTO_INCREMENT_FLAG && !field->table->maybe_null &&
          (thd->variables.option_bits & OPTION_AUTO_IS_NULL) &&
          (thd->first_successful_insert_id_in_prev_stmt > 0 &&
           thd->substitute_null_with_insert_id))
      {
  #ifdef HAVE_QUERY_CACHE
        query_cache_abort(thd, &thd->query_cache_tls);
  #endif
        COND *new_cond, *cond= this;
        /* If this fails, we will catch it later before executing query */
        if ((new_cond= new (thd->mem_root) Item_func_eq(thd, args[0],
                                        new (thd->mem_root) Item_int(thd, "last_insert_id()",
                                                     thd->read_first_successful_insert_id_in_prev_stmt(),
                                                     MY_INT64_NUM_DECIMAL_DIGITS))))
        {
          cond= new_cond;
          /*
            Item_func_eq can't be fixed after creation so we do not check
            cond->fixed, also it do not need tables so we use 0 as second
            argument.
          */
          cond->fix_fields(thd, &cond);
        }
        /*
          IS NULL should be mapped to LAST_INSERT_ID only for first row, so
          clear for next row
        */
        thd->substitute_null_with_insert_id= FALSE;

        *cond_value= Item::COND_OK;
        return cond;
      }
    }
  }
  return Item::remove_eq_conds(thd, cond_value, top_level_arg);
}


create_distinct_group(THD *thd, Ref_ptr_array ref_pointer_array,
                      ORDER *order_list, List<Item> &fields,
                      List<Item> &all_fields,
		      bool *all_order_by_fields_used)
{
  List_iterator<Item> li(fields);
  Item *item;
  Ref_ptr_array orig_ref_pointer_array= ref_pointer_array;
  ORDER *order,*group,**prev;
  uint idx= 0;

  *all_order_by_fields_used= 1;
  while ((item=li++))
    item->marker=0;			/* Marker that field is not used */

  prev= &group;  group=0;
  for (order=order_list ; order; order=order->next)
  {
    if (order->in_field_list)
    {
      ORDER *ord=(ORDER*) thd->memdup((char*) order,sizeof(ORDER));
      if (!ord)
	return 0;
      *prev=ord;
      prev= &ord->next;
      (*ord->item)->marker=1;
    }
    else
      *all_order_by_fields_used= 0;
  }

  li.rewind();
  while ((item=li++))
  {
    if (!item->const_item() && !item->with_sum_func && !item->marker)
    {
      /*
        Don't put duplicate columns from the SELECT list into the
        GROUP BY list.
      */
      ORDER *ord_iter;
      for (ord_iter= group; ord_iter; ord_iter= ord_iter->next)
        if ((*ord_iter->item)->eq(item, 1))
          goto next_item;

      ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER));
      if (!ord)
	return 0;

      if (item->type() == Item::FIELD_ITEM &&
          item->field_type() == MYSQL_TYPE_BIT)
      {
        /*
          Because HEAP tables can't index BIT fields we need to use an
          additional hidden field for grouping because later it will be
          converted to a LONG field. Original field will remain of the
          BIT type and will be returned [el]client.
        */
        Item_field *new_item= new (thd->mem_root) Item_field(thd, (Item_field*)item);
        if (!new_item)
          return 0;
        int el= all_fields.elements;
        orig_ref_pointer_array[el]= new_item;
        all_fields.push_front(new_item, thd->mem_root);
        ord->item=&orig_ref_pointer_array[el];
     }
      else
      {
        /*
          We have here only field_list (not all_field_list), so we can use
          simple indexing of ref_pointer_array (order in the array and in the
          list are same)
        */
        ord->item= &ref_pointer_array[idx];
      }
      ord->direction= ORDER::ORDER_ASC;
      *prev=ord;
      prev= &ord->next;
    }
next_item:
    idx++;
  }
  *prev=0;
  return group;
}


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

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

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

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

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

    bool produce_equality= MY_TEST(item == field_item);
    if (!item_const && field_sjm && field_sjm != current_sjm)
    {
      /* Entering an SJM nest */
      current_sjm_head= field_item;
      if (!field_sjm->sj_mat_info->is_sj_scan)
        produce_equality= FALSE;
    }

    if (produce_equality)
    {
      if (eq_item && eq_list.push_back(eq_item, thd->mem_root))
        return 0;

      /*
        If we're inside an SJM-nest (current_sjm!=NULL), and the multi-equality
        doesn't include a constant, we should produce equality with the first
        of the equal items in this SJM (except for the first element inside the
        SJM. For that, we produce the equality with the "head" item).

        In other cases, get the "head" item, which is either first of the
        equals on top level, or the constant.
      */
      Item *head_item= (!item_const && current_sjm &&
                        current_sjm_head != field_item) ? current_sjm_head: head;
      Item *head_real_item=  head_item->real_item();
      if (head_real_item->type() == Item::FIELD_ITEM)
        head_item= head_real_item;

      eq_item= new (thd->mem_root) Item_func_eq(thd, field_item->real_item(), head_item);

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

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

      cond AND eq_1 AND eq_2 AND eq_3 AND ...

    'cond' is a parameter for this function, which may be NULL, an Item_int(1),
    or an Item_func_eq or an Item_cond_and.

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

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

  return res;
}


part_of_refkey(TABLE *table,Field *field)
{
  JOIN_TAB *join_tab= table->reginfo.join_tab;
  if (!join_tab)
    return (Item*) 0;             // field from outer non-select (UPDATE,...)

  uint ref_parts= join_tab->ref.key_parts;
  if (ref_parts) /* if it's ref/eq_ref/ref_or_null */
  {
    uint key= join_tab->ref.key;
    KEY *key_info= join_tab->get_keyinfo_by_key_no(key);
    KEY_PART_INFO *key_part= key_info->key_part;

    for (uint part=0 ; part < ref_parts ; part++,key_part++)
    {
      if (field->eq(key_part->field))
      {
        /*
          Found the field in the key. Check that
           1. ref_or_null doesn't alternate this component between a value and
              a NULL
           2. index fully covers the key
        */
        if (part != join_tab->ref.null_ref_part &&            // (1)
            !(key_part->key_part_flag & HA_PART_KEY_SEG))     // (2)
        {
          return join_tab->ref.items[part];
        }
        break;
      }
    }
  }
  return (Item*) 0;
}


join_read_key_unlock_row(st_join_table *tab)
{
  DBUG_ASSERT(tab->ref.use_count);
  if (tab->ref.use_count)
    tab->ref.use_count--;
}


static COND *build_equal_items(JOIN *join, COND *cond,
                               COND_EQUAL *inherited,
                               List<TABLE_LIST> *join_list,
                               bool ignore_on_conds,
                               COND_EQUAL **cond_equal_ref,
                               bool link_equal_fields)
{
  THD *thd= join->thd;

  *cond_equal_ref= NULL;

  if (cond)
  {
    cond= cond->build_equal_items(thd, inherited, link_equal_fields,
                                  cond_equal_ref);
    if (*cond_equal_ref)
    {
      (*cond_equal_ref)->upper_levels= inherited;
      inherited= *cond_equal_ref;
    }
  }

  if (join_list && !ignore_on_conds)
  {
    TABLE_LIST *table;
    List_iterator<TABLE_LIST> li(*join_list);

    while ((table= li++))
    {
      if (table->on_expr)
      {
        List<TABLE_LIST> *nested_join_list= table->nested_join ?
          &table->nested_join->join_list : NULL;
        /*
          We can modify table->on_expr because its old value will
          be restored before re-execution of PS/SP.
        */
        table->on_expr= build_equal_items(join, table->on_expr, inherited,
                                          nested_join_list, ignore_on_conds,
                                          &table->cond_equal);
      }
    }
  }

  return cond;
}


JOIN::destroy()
{
  DBUG_ENTER("JOIN::destroy");
  select_lex->join= 0;

  cond_equal= 0;
  having_equal= 0;

  cleanup(1);

  if (join_tab)
  {
    for (JOIN_TAB *tab= first_linear_tab(this, WITH_BUSH_ROOTS,
                                         WITH_CONST_TABLES);
         tab; tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
    {
      if (tab->aggr)
      {
        free_tmp_table(thd, tab->table);
        delete tab->tmp_table_param;
        tab->tmp_table_param= NULL;
        tab->aggr= NULL;
      }
      tab->table= NULL;
    }
  }

  /* Cleanup items referencing temporary table columns */
  cleanup_item_list(tmp_all_fields1);
  cleanup_item_list(tmp_all_fields3);
  destroy_sj_tmp_tables(this);
  delete_dynamic(&keyuse);
  if (save_qep)
    delete(save_qep);
  if (ext_keyuses_for_splitting)
    delete(ext_keyuses_for_splitting);
  delete procedure;
  DBUG_RETURN(error);
}


merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
		 uint and_level)
{
  if (start == new_fields)
    return start;				// Impossible or
  if (new_fields == end)
    return start;				// No new fields, skip all

  KEY_FIELD *first_free=new_fields;

  /* Mark all found fields in old array */
  for (; new_fields != end ; new_fields++)
  {
    for (KEY_FIELD *old=start ; old != first_free ; old++)
    {
      if (old->field == new_fields->field)
      {
        /*
          NOTE: below const_item() call really works as "!used_tables()", i.e.
          it can return FALSE where it is feasible to make it return TRUE.

          The cause is as follows: Some of the tables are already known to be
          const tables (the detection code is in make_join_statistics(),
          above the update_ref_and_keys() call), but we didn't propagate
          information about this: TABLE::const_table is not set to TRUE, and
          Item::update_used_tables() hasn't been called for each item.
          The result of this is that we're missing some 'ref' accesses.
          TODO: OptimizerTeam: Fix this
        */
	if (!new_fields->val->const_item())
	{
	  /*
	    If the value matches, we can use the key reference.
	    If not, we keep it until we have examined all new values
	  */
	  if (old->val->eq(new_fields->val, old->field->binary()))
	  {
	    old->level= and_level;
	    old->optimize= ((old->optimize & new_fields->optimize &
			     KEY_OPTIMIZE_EXISTS) |
			    ((old->optimize | new_fields->optimize) &
			     KEY_OPTIMIZE_REF_OR_NULL));
            old->null_rejecting= (old->null_rejecting &&
                                  new_fields->null_rejecting);
	  }
	}
	else if (old->eq_func && new_fields->eq_func &&
                 old->val->eq_by_collation(new_fields->val,
                                           old->field->binary(),
                                           old->field->charset()))

	{
	  old->level= and_level;
	  old->optimize= ((old->optimize & new_fields->optimize &
			   KEY_OPTIMIZE_EXISTS) |
			  ((old->optimize | new_fields->optimize) &
			   KEY_OPTIMIZE_REF_OR_NULL));
          old->null_rejecting= (old->null_rejecting &&
                                new_fields->null_rejecting);
	}
	else if (old->eq_func && new_fields->eq_func &&
		 ((old->val->const_item() && !old->val->is_expensive() &&
                   old->val->is_null()) ||
                  (!new_fields->val->is_expensive() &&
                   new_fields->val->is_null())))
	{
	  /* field = expression OR field IS NULL */
	  old->level= and_level;
          if (old->field->maybe_null())
	  {
	    old->optimize= KEY_OPTIMIZE_REF_OR_NULL;
            /* The referred expression can be NULL: */
            old->null_rejecting= 0;
	  }
	  /*
            Remember the NOT NULL value unless the value does not depend
            on other tables.
          */
	  if (!old->val->used_tables() && !old->val->is_expensive() &&
              old->val->is_null())
	    old->val= new_fields->val;
	}
	else
	{
	  /*
	    We are comparing two different const.  In this case we can't
	    use a key-lookup on this so it's better to remove the value
	    and let the range optimzier handle it
	  */
	  if (old == --first_free)		// If last item
	    break;
	  *old= *first_free;			// Remove old value
	  old--;				// Retry this value
	}
      }
    }
  }
  /* Remove all not used items */
  for (KEY_FIELD *old=start ; old != first_free ;)
  {
    if (old->level != and_level)
    {						// Not used in all levels
      if (old == --first_free)
	break;
      *old= *first_free;			// Remove old value
      continue;
    }
    old++;
  }
  return first_free;
}


double JOIN_TAB::scan_time()
{
  double res;
  if (table->is_created())
  {
    if (table->is_filled_at_execution())
    {
      get_delayed_table_estimates(table, &records, &read_time,
                                    &startup_cost);
      found_records= records;
      table->quick_condition_rows= records;
    }
    else
    {
      found_records= records= table->stat_records();
      read_time= table->file->scan_time();
      /*
        table->quick_condition_rows has already been set to
        table->file->stats.records
      */
    }
    res= read_time;
  }
  else
  {
    found_records= records=table->stat_records();
    read_time= found_records ? (double)found_records: 10.0;// TODO:fix this stub
    res= read_time;
  }
  return res;
}


static uint reset_nj_counters(JOIN *join, List<TABLE_LIST> *join_list)
{
  List_iterator<TABLE_LIST> li(*join_list);
  TABLE_LIST *table;
  DBUG_ENTER("reset_nj_counters");
  uint n=0;
  while ((table= li++))
  {
    NESTED_JOIN *nested_join;
    bool is_eliminated_nest= FALSE;
    if ((nested_join= table->nested_join))
    {
      nested_join->counter= 0;
      nested_join->n_tables= reset_nj_counters(join, &nested_join->join_list);
      if (!nested_join->n_tables)
        is_eliminated_nest= TRUE;
    }
    const table_map removed_tables= join->eliminated_tables |
                                    join->const_table_map;

    if ((table->nested_join && !is_eliminated_nest) ||
        (!table->nested_join && (table->table->map & ~removed_tables)))
      n++;
  }
  DBUG_RETURN(n);
}


do_select(JOIN *join, Procedure *procedure)
{
  int rc= 0;
  enum_nested_loop_state error= NESTED_LOOP_OK;
  DBUG_ENTER("do_select");

  if (join->pushdown_query)
  {
    /* Select fields are in the temporary table */
    join->fields= &join->tmp_fields_list1;
    /* Setup HAVING to work with fields in temporary table */
    join->set_items_ref_array(join->items1);
    /* The storage engine will take care of the group by query result */
    int res= join->pushdown_query->execute(join);

    if (res)
      DBUG_RETURN(res);

    if (join->pushdown_query->store_data_in_temp_table)
    {
      JOIN_TAB *last_tab= join->join_tab + join->table_count -
                          join->exec_join_tab_cnt();
      last_tab->next_select= end_send;

      enum_nested_loop_state state= last_tab->aggr->end_send();
      if (state >= NESTED_LOOP_OK)
        state= sub_select(join, last_tab, true);

      if (state < NESTED_LOOP_OK)
        res= 1;

      if (join->result->send_eof())
        res= 1;
    }
    DBUG_RETURN(res);
  }

  join->procedure= procedure;
  join->duplicate_rows= join->send_records=0;
  if (join->only_const_tables() && !join->need_tmp)
  {
    Next_select_func end_select= setup_end_select_func(join, NULL);

    /*
      HAVING will be checked after processing aggregate functions,
      But WHERE should checked here (we alredy have read tables).
      Notice that make_join_select() splits all conditions in this case
      into two groups exec_const_cond and outer_ref_cond.
      If join->table_count == join->const_tables then it is
      sufficient to check only the condition pseudo_bits_cond.
    */
    DBUG_ASSERT(join->outer_ref_cond == NULL);
    if (!join->pseudo_bits_cond || join->pseudo_bits_cond->val_int())
    {
      // HAVING will be checked by end_select
      error= (*end_select)(join, 0, 0);
      if (error >= NESTED_LOOP_OK)
	error= (*end_select)(join, 0, 1);

      /*
        If we don't go through evaluate_join_record(), do the counting
        here.  join->send_records is increased on success in end_send(),
        so we don't touch it here.
      */
      join->join_examined_rows++;
      DBUG_ASSERT(join->join_examined_rows <= 1);
    }
    else if (join->send_row_on_empty_set())
    {
      table_map cleared_tables= (table_map) 0;
      if (end_select == end_send_group)
      {
        /*
          Was a grouping query but we did not find any rows. In this case
          we clear all tables to get null in any referenced fields,
          like in case of:
          SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL
        */
        clear_tables(join, &cleared_tables);
      }
      if (!join->having || join->having->val_int())
      {
        List<Item> *columns_list= (procedure ? &join->procedure_fields_list :
                                   join->fields);
        rc= join->result->send_data(*columns_list) > 0;
      }
      /*
        We have to remove the null markings from the tables as this table
        may be part of a sub query that is re-evaluated
      */
      if (cleared_tables)
        unclear_tables(join, &cleared_tables);
    }
    /*
      An error can happen when evaluating the conds
      (the join condition and piece of where clause
      relevant to this join table).
    */
    if (unlikely(join->thd->is_error()))
      error= NESTED_LOOP_ERROR;
  }
  else
  {
    DBUG_EXECUTE_IF("show_explain_probe_do_select",
                    if (dbug_user_var_equals_int(join->thd,
                                                 "show_explain_probe_select_id",
                                                 join->select_lex->select_number))
                          dbug_serve_apcs(join->thd, 1);
                   );

    JOIN_TAB *join_tab= join->join_tab +
                        (join->tables_list ? join->const_tables : 0);
    if (join->outer_ref_cond && !join->outer_ref_cond->val_int())
      error= NESTED_LOOP_NO_MORE_ROWS;
    else
      error= join->first_select(join,join_tab,0);
    if (error >= NESTED_LOOP_OK && likely(join->thd->killed != ABORT_QUERY))
      error= join->first_select(join,join_tab,1);
  }

  join->thd->limit_found_rows= join->send_records - join->duplicate_rows;

  if (error == NESTED_LOOP_NO_MORE_ROWS ||
      unlikely(join->thd->killed == ABORT_QUERY))
    error= NESTED_LOOP_OK;

  /*
    For "order by with limit", we cannot rely on send_records, but need
    to use the rowcount read originally into the join_tab applying the
    filesort. There cannot be any post-filtering conditions, nor any
    following join_tabs in this case, so this rowcount properly represents
    the correct number of qualifying rows.
  */
  if (join->order)
  {
    // Save # of found records prior to cleanup
    JOIN_TAB *sort_tab;
    JOIN_TAB *join_tab= join->join_tab;
    uint const_tables= join->const_tables;

    // Take record count from first non constant table or from last tmp table
    if (join->aggr_tables > 0)
      sort_tab= join_tab + join->top_join_tab_count + join->aggr_tables - 1;
    else
    {
      DBUG_ASSERT(!join->only_const_tables());
      sort_tab= join_tab + const_tables;
    }
    if (sort_tab->filesort &&
        join->select_options & OPTION_FOUND_ROWS &&
        sort_tab->filesort->sortorder &&
        sort_tab->filesort->limit != HA_POS_ERROR)
    {
      join->thd->limit_found_rows= sort_tab->records;
    }
  }

  {
    /*
      The following will unlock all cursors if the command wasn't an
      update command
    */
    join->join_free();			// Unlock all cursors
  }
  if (error == NESTED_LOOP_OK)
  {
    /*
      Sic: this branch works even if rc != 0, e.g. when
      send_data above returns an error.
    */
    if (unlikely(join->result->send_eof()))
      rc= 1;                                  // Don't send error
    DBUG_PRINT("info",("%ld records output", (long) join->send_records));
  }
  else
    rc= -1;
#ifndef DBUG_OFF
  if (rc)
  {
    DBUG_PRINT("error",("Error: do_select() failed"));
  }
#endif
  rc= join->thd->is_error() ? -1 : rc;
  DBUG_RETURN(rc);
}


JOIN::reinit()
{
  DBUG_ENTER("JOIN::reinit");

  unit->offset_limit_cnt= (ha_rows)(select_lex->offset_limit ?
                                    select_lex->offset_limit->val_uint() : 0);

  first_record= false;
  group_sent= false;
  cleaned= false;

  if (aggr_tables)
  {
    JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt();
    JOIN_TAB *end_tab= curr_tab + aggr_tables;
    for ( ; curr_tab < end_tab; curr_tab++)
    {
      TABLE *tmp_table= curr_tab->table;
      if (!tmp_table->is_created())
        continue;
      tmp_table->file->extra(HA_EXTRA_RESET_STATE);
      tmp_table->file->ha_delete_all_rows();
    }
  }
  clear_sj_tmp_tables(this);
  if (current_ref_ptrs != items0)
  {
    set_items_ref_array(items0);
    set_group_rpa= false;
  }

  /* need to reset ref access state (see join_read_key) */
  if (join_tab)
  {
    JOIN_TAB *tab;
    for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITH_CONST_TABLES); tab;
         tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
    {
      tab->ref.key_err= TRUE;
    }
  }

  /* Reset of sum functions */
  if (sum_funcs)
  {
    Item_sum *func, **func_ptr= sum_funcs;
    while ((func= *(func_ptr++)))
      func->clear();
  }

  if (no_rows_in_result_called)
  {
    /* Reset effect of possible no_rows_in_result() */
    List_iterator_fast<Item> it(fields_list);
    Item *item;
    no_rows_in_result_called= 0;
    while ((item= it++))
      item->restore_to_before_no_rows_in_result();
  }

  if (!(select_options & SELECT_DESCRIBE))
    if (init_ftfuncs(thd, select_lex, MY_TEST(order)))
      DBUG_RETURN(1);

  DBUG_RETURN(0);
}


Next_select_func setup_end_select_func(JOIN *join, JOIN_TAB *tab)
{
  TMP_TABLE_PARAM *tmp_tbl= tab ? tab->tmp_table_param : &join->tmp_table_param;

  /*
     Choose method for presenting result to user. Use end_send_group
     if the query requires grouping (has a GROUP BY clause and/or one or
     more aggregate functions). Use end_send if the query should not
     be grouped.
   */
  if (join->sort_and_group && !tmp_tbl->precomputed_group_by)
  {
    DBUG_PRINT("info",("Using end_send_group"));
    return end_send_group;
  }
  DBUG_PRINT("info",("Using end_send"));
  return end_send;
}


bool JOIN::inject_cond_into_where(Item *injected_cond)
{
  Item *where_item= injected_cond;
  List<Item> *and_args= NULL;
  if (conds && conds->type() == Item::COND_ITEM &&
      ((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
  {
    and_args= ((Item_cond*) conds)->argument_list();
    if (cond_equal)
      and_args->disjoin((List<Item> *) &cond_equal->current_level);
  }

  where_item= and_items(thd, conds, where_item);
  if (where_item->fix_fields_if_needed(thd, 0))
    return true;
  thd->change_item_tree(&select_lex->where, where_item);
  select_lex->where->top_level_item();
  conds= select_lex->where;

  if (and_args && cond_equal)
  {
    and_args= ((Item_cond*) conds)->argument_list();
    List_iterator<Item_equal> li(cond_equal->current_level);
    Item_equal *elem;
    while ((elem= li++))
    {
      and_args->push_back(elem, thd->mem_root);
    }
  }

  return false;

}


bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
                               TMP_ENGINE_COLUMNDEF *start_recinfo,
                               TMP_ENGINE_COLUMNDEF **recinfo,
                               ulonglong options)
{
  int error;
  MI_KEYDEF keydef;
  MI_UNIQUEDEF uniquedef;
  TABLE_SHARE *share= table->s;
  DBUG_ENTER("create_internal_tmp_table");

  if (share->keys)
  {						// Get keys for ni_create
    bool using_unique_constraint=0;
    HA_KEYSEG *seg= (HA_KEYSEG*) alloc_root(&table->mem_root,
                                            sizeof(*seg) * keyinfo->user_defined_key_parts);
    if (!seg)
      goto err;

    bzero(seg, sizeof(*seg) * keyinfo->user_defined_key_parts);
    /*
       Note that a similar check is performed during
       subquery_types_allow_materialization. See MDEV-7122 for more details as
       to why. Whenever this changes, it must be updated there as well, for
       all tmp_table engines.
    */
    if (keyinfo->key_length > table->file->max_key_length() ||
	keyinfo->user_defined_key_parts > table->file->max_key_parts() ||
	share->uniques)
    {
      /* Can't create a key; Make a unique constraint instead of a key */
      share->keys=    0;
      share->uniques= 1;
      using_unique_constraint=1;
      bzero((char*) &uniquedef,sizeof(uniquedef));
      uniquedef.keysegs=keyinfo->user_defined_key_parts;
      uniquedef.seg=seg;
      uniquedef.null_are_equal=1;

      /* Create extra column for hash value */
      bzero((uchar*) *recinfo,sizeof(**recinfo));
      (*recinfo)->type= FIELD_CHECK;
      (*recinfo)->length=MI_UNIQUE_HASH_LENGTH;
      (*recinfo)++;
      /* Avoid warnings from valgrind */
      bzero(table->record[0]+ share->reclength, MI_UNIQUE_HASH_LENGTH);
      bzero(share->default_values+ share->reclength, MI_UNIQUE_HASH_LENGTH);
      share->reclength+= MI_UNIQUE_HASH_LENGTH;
    }
    else
    {
      /* Create an unique key */
      bzero((char*) &keydef,sizeof(keydef));
      keydef.flag= ((keyinfo->flags & HA_NOSAME) | HA_BINARY_PACK_KEY |
                    HA_PACK_KEY);
      keydef.keysegs=  keyinfo->user_defined_key_parts;
      keydef.seg= seg;
    }
    for (uint i=0; i < keyinfo->user_defined_key_parts ; i++,seg++)
    {
      Field *field=keyinfo->key_part[i].field;
      seg->flag=     0;
      seg->language= field->charset()->number;
      seg->length=   keyinfo->key_part[i].length;
      seg->start=    keyinfo->key_part[i].offset;
      if (field->flags & BLOB_FLAG)
      {
	seg->type=
	((keyinfo->key_part[i].key_type & FIELDFLAG_BINARY) ?
	 HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2);
	seg->bit_start= (uint8)(field->pack_length() - portable_sizeof_char_ptr);
	seg->flag= HA_BLOB_PART;
	seg->length=0;			// Whole blob in unique constraint
      }
      else
      {
	seg->type= keyinfo->key_part[i].type;
        /* Tell handler if it can do suffic space compression */
	if (field->real_type() == MYSQL_TYPE_STRING &&
	    keyinfo->key_part[i].length > 4)
	  seg->flag|= HA_SPACE_PACK;
      }
      if (!(field->flags & NOT_NULL_FLAG))
      {
	seg->null_bit= field->null_bit;
	seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]);
	/*
	  We are using a GROUP BY on something that contains NULL
	  In this case we have to tell MyISAM that two NULL should
	  on INSERT be regarded at the same value
	*/
	if (!using_unique_constraint)
	  keydef.flag|= HA_NULL_ARE_EQUAL;
      }
    }
  }
  MI_CREATE_INFO create_info;
  bzero((char*) &create_info,sizeof(create_info));
  create_info.data_file_length= table->in_use->variables.tmp_disk_table_size;

  if (unlikely((error= mi_create(share->path.str, share->keys, &keydef,
		                 (uint) (*recinfo-start_recinfo),
                                 start_recinfo,
		                 share->uniques, &uniquedef,
                                 &create_info,
		                 HA_CREATE_TMP_TABLE |
                                 HA_CREATE_INTERNAL_TABLE |
                                 ((share->db_create_options &
                                   HA_OPTION_PACK_RECORD) ?
                                  HA_PACK_RECORD : 0)
                                 ))))
  {
    table->file->print_error(error,MYF(0));	/* purecov: inspected */
    table->db_stat=0;
    goto err;
  }
  table->in_use->inc_status_created_tmp_disk_tables();
  table->in_use->inc_status_created_tmp_tables();
  share->db_record_offset= 1;
  table->set_created();
  DBUG_RETURN(0);
 err:
  DBUG_RETURN(1);
}


uint get_next_field_for_derived_key_simple(uchar *arg)
{
  KEYUSE *keyuse= *(KEYUSE **) arg;
  if (!keyuse)
    return (uint) (-1);
  TABLE *table= keyuse->table;
  uint key= keyuse->key;
  uint fldno= keyuse->keypart;
  for ( ;
        keyuse->table == table && keyuse->key == key && keyuse->keypart == fldno;
        keyuse++)
    ;
  if (keyuse->key != key)
    keyuse= 0;
  *((KEYUSE **) arg)= keyuse;
  return fldno;
}


copy_funcs(Item **func_ptr, const THD *thd)
{
  Item *func;
  for (; (func = *func_ptr) ; func_ptr++)
  {
    if (func->type() == Item::FUNC_ITEM &&
        ((Item_func *) func)->with_window_func)
      continue;
    func->save_in_result_field(1);
    /*
      Need to check the THD error state because Item::val_xxx() don't
      return error code, but can generate errors
      TODO: change it for a real status check when Item::val_xxx()
      are extended to return status code.
    */
    if (unlikely(thd->is_error()))
      return TRUE;
  }
  return FALSE;
}


bool error_if_full_join(JOIN *join)
{
  for (JOIN_TAB *tab=first_top_level_tab(join, WITH_CONST_TABLES); tab;
       tab= next_top_level_tab(join, tab))
  {
    if (tab->type == JT_ALL && (!tab->select || !tab->select->quick))
    {
      my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
                 ER_THD(join->thd,
                        ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
      return(1);
    }
  }
  return(0);
}


void JOIN::cleanup_item_list(List<Item> &items) const
{
  DBUG_ENTER("JOIN::cleanup_item_list");
  if (!items.is_empty())
  {
    List_iterator_fast<Item> it(items);
    Item *item;
    while ((item= it++))
      item->cleanup();
  }
  DBUG_VOID_RETURN;
}


uint get_next_field_for_derived_key(uchar *arg)
{
  KEYUSE *keyuse= *(KEYUSE **) arg;
  if (!keyuse)
    return (uint) (-1);
  TABLE *table= keyuse->table;
  uint key= keyuse->key;
  uint fldno= keyuse->keypart;
  uint keypart= keyuse->keypart_map == (key_part_map) 1 ?
                                         0 : (keyuse-1)->keypart+1;
  for ( ;
        keyuse->table == table && keyuse->key == key && keyuse->keypart == fldno;
        keyuse++)
    keyuse->keypart= keypart;
  if (keyuse->key != key)
    keyuse= 0;
  *((KEYUSE **) arg)= keyuse;
  return fldno;
}


make_outerjoin_info(JOIN *join)
{
  DBUG_ENTER("make_outerjoin_info");

  /*
    Create temp. tables for merged SJ-Materialization nests. We need to do
    this now, because further code relies on tab->table and
    tab->table->pos_in_table_list being set.
  */
  JOIN_TAB *tab;
  for (tab= first_linear_tab(join, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
       tab;
       tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
  {
    if (tab->bush_children)
    {
      if (setup_sj_materialization_part1(tab))
        DBUG_RETURN(TRUE);
      tab->table->reginfo.join_tab= tab;
    }
  }

  for (tab= first_linear_tab(join, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
       tab;
       tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
  {
    TABLE *table= tab->table;
    TABLE_LIST *tbl= table->pos_in_table_list;
    TABLE_LIST *embedding= tbl->embedding;

    if (tbl->outer_join & (JOIN_TYPE_LEFT | JOIN_TYPE_RIGHT))
    {
      /*
        Table tab is the only one inner table for outer join.
        (Like table t4 for the table reference t3 LEFT JOIN t4 ON t3.a=t4.a
        is in the query above.)
      */
      tab->last_inner= tab->first_inner= tab;
      tab->on_expr_ref= &tbl->on_expr;
      tab->cond_equal= tbl->cond_equal;
      if (embedding && !embedding->is_active_sjm())
        tab->first_upper= embedding->nested_join->first_nested;
    }
    else if (!embedding)
      tab->table->reginfo.not_exists_optimize= 0;

    for ( ; embedding ; embedding= embedding->embedding)
    {
      if (embedding->is_active_sjm())
      {
        /* We're trying to walk out of an SJ-Materialization nest. Don't do this.  */
        break;
      }
      /* Ignore sj-nests: */
      if (!(embedding->on_expr && embedding->outer_join))
      {
        tab->table->reginfo.not_exists_optimize= 0;
        continue;
      }
      NESTED_JOIN *nested_join= embedding->nested_join;
      if (!nested_join->counter)
      {
        /*
          Table tab is the first inner table for nested_join.
          Save reference to it in the nested join structure.
        */
        nested_join->first_nested= tab;
        tab->on_expr_ref= &embedding->on_expr;
        tab->cond_equal= tbl->cond_equal;
        if (embedding->embedding)
          tab->first_upper= embedding->embedding->nested_join->first_nested;
      }
      if (!tab->first_inner)
        tab->first_inner= nested_join->first_nested;
      if (++nested_join->counter < nested_join->n_tables)
        break;
      /* Table tab is the last inner table for nested join. */
      nested_join->first_nested->last_inner= tab;
    }
  }
  DBUG_RETURN(FALSE);
}