make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
  THD *thd= join->thd;
  DBUG_ENTER("make_join_select");
  if (select)
  {
    add_not_null_conds(join);
    table_map used_tables;
    /*
      Step #1: Extract constant condition
       - Extract and check the constant part of the WHERE
       - Extract constant parts of ON expressions from outer
         joins and attach them appropriately.
    */
    if (cond)                /* Because of QUICK_GROUP_MIN_MAX_SELECT */
    {                        /* there may be a select without a cond. */
      if (join->table_count > 1)
        cond->update_used_tables();		// Tablenr may have changed

      /*
        Extract expressions that depend on constant tables
        1. Const part of the join's WHERE clause can be checked immediately
           and if it is not satisfied then the join has empty result
        2. Constant parts of outer joins' ON expressions must be attached
           there inside the triggers.
      */
      {						// Check const tables
        join->exec_const_cond=
	  make_cond_for_table(thd, cond,
                              join->const_table_map,
                              (table_map) 0, -1, FALSE, FALSE);
        /* Add conditions added by add_not_null_conds(). */
        for (uint i= 0 ; i < join->const_tables ; i++)
          add_cond_and_fix(thd, &join->exec_const_cond,
                           join->join_tab[i].select_cond);

        DBUG_EXECUTE("where",print_where(join->exec_const_cond,"constants",
					 QT_ORDINARY););
        if (join->exec_const_cond && !join->exec_const_cond->is_expensive() &&
            !join->exec_const_cond->val_int())
        {
          DBUG_PRINT("info",("Found impossible WHERE condition"));
          join->exec_const_cond= NULL;
          DBUG_RETURN(1);	 // Impossible const condition
        }

        if (join->table_count != join->const_tables)
        {
          COND *outer_ref_cond= make_cond_for_table(thd, cond,
                                                    join->const_table_map |
                                                    OUTER_REF_TABLE_BIT,
                                                    OUTER_REF_TABLE_BIT,
                                                    -1, FALSE, FALSE);
          if (outer_ref_cond)
          {
            add_cond_and_fix(thd, &outer_ref_cond, join->outer_ref_cond);
            join->outer_ref_cond= outer_ref_cond;
          }
        }
        else
        {
          COND *pseudo_bits_cond=
            make_cond_for_table(thd, cond,
                                join->const_table_map |
                                PSEUDO_TABLE_BITS,
                                PSEUDO_TABLE_BITS,
                                -1, FALSE, FALSE);
          if (pseudo_bits_cond)
          {
            add_cond_and_fix(thd, &pseudo_bits_cond,
                             join->pseudo_bits_cond);
            join->pseudo_bits_cond= pseudo_bits_cond;
          }
        }
      }
    }

    /*
      Step #2: Extract WHERE/ON parts
    */
    uint i;
    for (i= join->top_join_tab_count - 1; i >= join->const_tables; i--)
    {
      if (!join->join_tab[i].bush_children)
        break;
    }
    uint last_top_base_tab_idx= i;

    table_map save_used_tables= 0;
    used_tables=((select->const_tables=join->const_table_map) |
		 OUTER_REF_TABLE_BIT | RAND_TABLE_BIT);
    JOIN_TAB *tab;
    table_map current_map;
    i= join->const_tables;
    for (tab= first_depth_first_tab(join); tab;
         tab= next_depth_first_tab(join, tab))
    {
      bool is_hj;

      /*
        first_inner is the X in queries like:
        SELECT * FROM t1 LEFT OUTER JOIN (t2 JOIN t3) ON X
      */
      JOIN_TAB *first_inner_tab= tab->first_inner;

      if (!tab->bush_children)
        current_map= tab->table->map;
      else
        current_map= tab->bush_children->start->emb_sj_nest->sj_inner_tables;

      bool use_quick_range=0;
      COND *tmp;

      /*
        Tables that are within SJ-Materialization nests cannot have their
        conditions referring to preceding non-const tables.
         - If we're looking at the first SJM table, reset used_tables
           to refer to only allowed tables
      */
      if (tab->emb_sj_nest && tab->emb_sj_nest->sj_mat_info &&
          tab->emb_sj_nest->sj_mat_info->is_used &&
          !(used_tables & tab->emb_sj_nest->sj_inner_tables))
      {
        save_used_tables= used_tables;
        used_tables= join->const_table_map | OUTER_REF_TABLE_BIT |
                     RAND_TABLE_BIT;
      }

      used_tables|=current_map;

      if (tab->type == JT_REF && tab->quick &&
	  (((uint) tab->ref.key == tab->quick->index &&
	    tab->ref.key_length < tab->quick->max_used_key_length) ||
           (!is_hash_join_key_no(tab->ref.key) &&
            tab->table->intersect_keys.is_set(tab->ref.key))))
      {
	/* Range uses longer key;  Use this instead of ref on key */
	tab->type=JT_ALL;
	use_quick_range=1;
	tab->use_quick=1;
        tab->ref.key= -1;
	tab->ref.key_parts=0;		// Don't use ref key.
	join->best_positions[i].records_read= rows2double(tab->quick->records);
        /*
          We will use join cache here : prevent sorting of the first
          table only and sort at the end.
        */
        if (i != join->const_tables &&
            join->table_count > join->const_tables + 1 &&
            join->best_positions[i].use_join_buffer)
          join->full_join= 1;
      }

      tmp= NULL;

      if (cond)
      {
        if (tab->bush_children)
        {
          // Reached the materialization tab
          tmp= make_cond_after_sjm(thd, cond, cond, save_used_tables,
                                   used_tables, /*inside_or_clause=*/FALSE);
          used_tables= save_used_tables | used_tables;
          save_used_tables= 0;
        }
        else
        {
          tmp= make_cond_for_table(thd, cond, used_tables, current_map, i,
                                   FALSE, FALSE);
          if (tab == join->join_tab + last_top_base_tab_idx)
          {
            /*
              This pushes conjunctive conditions of WHERE condition such that:
              - their used_tables() contain RAND_TABLE_BIT
              - the conditions does not refer to any fields
              (such like rand() > 0.5)
            */
            table_map rand_table_bit= (table_map) RAND_TABLE_BIT;
            COND *rand_cond= make_cond_for_table(thd, cond, used_tables,
                                                 rand_table_bit, -1,
                                                 FALSE, FALSE);
            add_cond_and_fix(thd, &tmp, rand_cond);
          }
        }
        /* Add conditions added by add_not_null_conds(). */
        if (tab->select_cond)
          add_cond_and_fix(thd, &tmp, tab->select_cond);
      }

      is_hj= (tab->type == JT_REF || tab->type == JT_EQ_REF) &&
             (join->allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) &&
	     ((join->max_allowed_join_cache_level+1)/2 == 2 ||
              ((join->max_allowed_join_cache_level+1)/2 > 2 &&
	       is_hash_join_key_no(tab->ref.key))) &&
              (!tab->emb_sj_nest ||
               join->allowed_semijoin_with_cache) &&
              (!(tab->table->map & join->outer_join) ||
               join->allowed_outer_join_with_cache);

      if (cond && !tmp && tab->quick)
      {						// Outer join
        if (tab->type != JT_ALL && !is_hj)
        {
          /*
            Don't use the quick method
            We come here in the case where we have 'key=constant' and
            the test is removed by make_cond_for_table()
          */
          delete tab->quick;
          tab->quick= 0;
        }
        else
        {
          /*
            Hack to handle the case where we only refer to a table
            in the ON part of an OUTER JOIN. In this case we want the code
            below to check if we should use 'quick' instead.
          */
          DBUG_PRINT("info", ("Item_int"));
          tmp= new (thd->mem_root) Item_int(thd, (longlong) 1, 1); // Always true
        }

      }
      if (tmp || !cond || tab->type == JT_REF || tab->type == JT_REF_OR_NULL ||
          tab->type == JT_EQ_REF || first_inner_tab)
      {
        DBUG_EXECUTE("where",print_where(tmp,
                                         tab->table? tab->table->alias.c_ptr() :"sjm-nest",
                                         QT_ORDINARY););
	SQL_SELECT *sel= tab->select= ((SQL_SELECT*)
                                       thd->memdup((uchar*) select,
                                                   sizeof(*select)));
	if (!sel)
	  DBUG_RETURN(1);			// End of memory
        /*
          If tab is an inner table of an outer join operation,
          add a match guard to the pushed down predicate.
          The guard will turn the predicate on only after
          the first match for outer tables is encountered.
	*/
        if (cond && tmp)
        {
          /*
            Because of QUICK_GROUP_MIN_MAX_SELECT there may be a select without
            a cond, so neutralize the hack above.
          */
          COND *tmp_cond;
          if (!(tmp_cond= add_found_match_trig_cond(thd, first_inner_tab, tmp,
                                                    0)))
            DBUG_RETURN(1);
          sel->cond= tmp_cond;
          tab->set_select_cond(tmp_cond, __LINE__);
          /* Push condition to storage engine if this is enabled
             and the condition is not guarded */
          if (tab->table)
          {
            tab->table->file->pushed_cond= NULL;
            if ((tab->table->file->ha_table_flags() &
                  HA_CAN_TABLE_CONDITION_PUSHDOWN) &&
                !first_inner_tab)
            {
              COND *push_cond=
              make_cond_for_table(thd, tmp_cond, current_map, current_map,
                                  -1, FALSE, FALSE);
              if (push_cond)
              {
                /* Push condition to handler */
                if (!tab->table->file->cond_push(push_cond))
                  tab->table->file->pushed_cond= push_cond;
              }
            }
          }
        }
        else
        {
          sel->cond= NULL;
          tab->set_select_cond(NULL, __LINE__);
        }

	sel->head=tab->table;
        DBUG_EXECUTE("where",
                     print_where(tmp,
                                 tab->table ? tab->table->alias.c_ptr() :
                                   "(sjm-nest)",
                                 QT_ORDINARY););
	if (tab->quick)
	{
	  /* Use quick key read if it's a constant and it's not used
	     with key reading */
          if ((tab->needed_reg.is_clear_all() && tab->type != JT_EQ_REF &&
              tab->type != JT_FT &&
              ((tab->type != JT_CONST && tab->type != JT_REF) ||
               (uint) tab->ref.key == tab->quick->index)) || is_hj)
          {
            DBUG_ASSERT(tab->quick->is_valid());
	    sel->quick=tab->quick;		// Use value from get_quick_...
	    sel->quick_keys.clear_all();
	    sel->needed_reg.clear_all();
	  }
	  else
	  {
	    delete tab->quick;
	  }
	  tab->quick=0;
	}
	uint ref_key= sel->head? (uint) sel->head->reginfo.join_tab->ref.key+1 : 0;
	if (i == join->const_tables && ref_key)
	{
	  if (!tab->const_keys.is_clear_all() &&
              tab->table->reginfo.impossible_range)
	    DBUG_RETURN(1);
	}
	else if (tab->type == JT_ALL && ! use_quick_range)
	{
	  if (!tab->const_keys.is_clear_all() &&
	      tab->table->reginfo.impossible_range)
	    DBUG_RETURN(1);				// Impossible range
	  /*
	    We plan to scan all rows.
	    Check again if we should use an index.

            There are two cases:
            1) There could be an index usage the refers to a previous
               table that we didn't consider before, but could be consider
               now as a "last resort". For example
               SELECT * from t1,t2 where t1.a between t2.a and t2.b;
            2) If the current table is the first non const table
               and there is a limit it still possibly beneficial
               to use the index even if the index range is big as
               we can stop when we've found limit rows.

            (1) - Don't switch the used index if we are using semi-join
                  LooseScan on this table. Using different index will not
                  produce the desired ordering and de-duplication.
	  */

	  if (!tab->table->is_filled_at_execution() &&
              !tab->loosescan_match_tab &&              // (1)
              ((cond && (!tab->keys.is_subset(tab->const_keys) && i > 0)) ||
               (!tab->const_keys.is_clear_all() && i == join->const_tables &&
                join->unit->select_limit_cnt <
                join->best_positions[i].records_read &&
                !(join->select_options & OPTION_FOUND_ROWS))))
	  {
	    /* Join with outer join condition */
	    COND *orig_cond=sel->cond;
	    sel->cond= and_conds(thd, sel->cond, *tab->on_expr_ref);

	    /*
              We can't call sel->cond->fix_fields,
              as it will break tab->on_expr if it's AND condition
              (fix_fields currently removes extra AND/OR levels).
              Yet attributes of the just built condition are not needed.
              Thus we call sel->cond->quick_fix_field for safety.
	    */
	    if (sel->cond && !sel->cond->fixed)
	      sel->cond->quick_fix_field();

	    if (sel->test_quick_select(thd, tab->keys,
				       ((used_tables & ~ current_map) |
                                        OUTER_REF_TABLE_BIT),
				       (join->select_options &
					OPTION_FOUND_ROWS ?
					HA_POS_ERROR :
					join->unit->select_limit_cnt), 0,
                                        FALSE, FALSE) < 0)
            {
	      /*
		Before reporting "Impossible WHERE" for the whole query
		we have to check isn't it only "impossible ON" instead
	      */
              sel->cond=orig_cond;
              if (!*tab->on_expr_ref ||
                  sel->test_quick_select(thd, tab->keys,
                                         used_tables & ~ current_map,
                                         (join->select_options &
                                          OPTION_FOUND_ROWS ?
                                          HA_POS_ERROR :
                                          join->unit->select_limit_cnt),0,
                                          FALSE, FALSE) < 0)
		DBUG_RETURN(1);			// Impossible WHERE
            }
            else
	      sel->cond=orig_cond;

	    /* Fix for EXPLAIN */
	    if (sel->quick)
	      join->best_positions[i].records_read= (double)sel->quick->records;
	  }
	  else
	  {
	    sel->needed_reg=tab->needed_reg;
	  }
	  sel->quick_keys= tab->table->quick_keys;
	  if (!sel->quick_keys.is_subset(tab->checked_keys) ||
              !sel->needed_reg.is_subset(tab->checked_keys))
	  {
            /*
              "Range checked for each record" is a "last resort" access method
              that should only be used when the other option is a cross-product
              join.

              We use the following condition (it's approximate):
              1. There are potential keys for (sel->needed_reg)
              2. There were no possible ways to construct a quick select, or
                 the quick select would be more expensive than the full table
                 scan.
            */
	    tab->use_quick= (!sel->needed_reg.is_clear_all() &&
			     (sel->quick_keys.is_clear_all() ||
                              (sel->quick &&
                               sel->quick->read_time >
                               tab->table->file->scan_time() +
                               tab->table->file->stats.records/TIME_FOR_COMPARE
                               ))) ?
	      2 : 1;
	    sel->read_tables= used_tables & ~current_map;
            sel->quick_keys.clear_all();
	  }
	  if (i != join->const_tables && tab->use_quick != 2 &&
              !tab->first_inner)
	  {					/* Read with cache */
            if (tab->make_scan_filter())
              DBUG_RETURN(1);
          }
	}
      }

      /*
        Push down conditions from all ON expressions.
        Each of these conditions are guarded by a variable
        that turns if off just before null complemented row for
        outer joins is formed. Thus, the condition from an
        'on expression' are guaranteed not to be checked for
        the null complemented row.
      */

      /*
        First push down constant conditions from ON expressions.
         - Each pushed-down condition is wrapped into trigger which is
           enabled only for non-NULL-complemented record
         - The condition is attached to the first_inner_table.

        With regards to join nests:
         - if we start at top level, don't walk into nests
         - if we start inside a nest, stay within that nest.
      */
      JOIN_TAB *start_from= tab->bush_root_tab?
                               tab->bush_root_tab->bush_children->start :
                               join->join_tab + join->const_tables;
      JOIN_TAB *end_with= tab->bush_root_tab?
                               tab->bush_root_tab->bush_children->end :
                               join->join_tab + join->top_join_tab_count;
      for (JOIN_TAB *join_tab= start_from;
           join_tab != end_with;
           join_tab++)
      {
        if (*join_tab->on_expr_ref)
        {
          JOIN_TAB *cond_tab= join_tab->first_inner;
          COND *tmp_cond= make_cond_for_table(thd, *join_tab->on_expr_ref,
                                              join->const_table_map,
                                              (table_map) 0, -1, FALSE, FALSE);
          if (!tmp_cond)
            continue;
          tmp_cond= new (thd->mem_root) Item_func_trig_cond(thd, tmp_cond,
                                            &cond_tab->not_null_compl);
          if (!tmp_cond)
            DBUG_RETURN(1);
          tmp_cond->quick_fix_field();
          cond_tab->select_cond= !cond_tab->select_cond ? tmp_cond :
                                 new (thd->mem_root) Item_cond_and(thd, cond_tab->select_cond,
                                                   tmp_cond);
          if (!cond_tab->select_cond)
	    DBUG_RETURN(1);
          cond_tab->select_cond->quick_fix_field();
          cond_tab->select_cond->update_used_tables();
          if (cond_tab->select)
            cond_tab->select->cond= cond_tab->select_cond;
        }
      }

      /* Push down non-constant conditions from ON expressions */
      JOIN_TAB *last_tab= tab;

      /*
        while we're inside of an outer join and last_tab is
        the last of its tables ...
      */
      while (first_inner_tab && first_inner_tab->last_inner == last_tab)
      {
        /*
          Table tab is the last inner table of an outer join.
          An on expression is always attached to it.
	*/
        COND *on_expr= *first_inner_tab->on_expr_ref;

        table_map used_tables2= (join->const_table_map |
                                 OUTER_REF_TABLE_BIT | RAND_TABLE_BIT);

        start_from= tab->bush_root_tab?
                      tab->bush_root_tab->bush_children->start :
                      join->join_tab + join->const_tables;
        for (JOIN_TAB *inner_tab= start_from;
             inner_tab <= last_tab;
             inner_tab++)
        {
          DBUG_ASSERT(inner_tab->table);
          current_map= inner_tab->table->map;
          used_tables2|= current_map;
          /*
            psergey: have put the -1 below. It's bad, will need to fix it.
          */
          COND *tmp_cond= make_cond_for_table(thd, on_expr, used_tables2,
                                              current_map,
                                              /*(inner_tab - first_tab)*/ -1,
					      FALSE, FALSE);
          if (tab == last_tab)
          {
            /*
              This pushes conjunctive conditions of ON expression of an outer
              join such that:
              - their used_tables() contain RAND_TABLE_BIT
              - the conditions does not refer to any fields
              (such like rand() > 0.5)
            */
            table_map rand_table_bit= (table_map) RAND_TABLE_BIT;
            COND *rand_cond= make_cond_for_table(thd, on_expr, used_tables2,
                                                 rand_table_bit, -1,
                                                 FALSE, FALSE);
            add_cond_and_fix(thd, &tmp_cond, rand_cond);
          }
          bool is_sjm_lookup_tab= FALSE;
          if (inner_tab->bush_children)
          {
            /*
              'inner_tab' is an SJ-Materialization tab, i.e. we have a join
              order like this:

                ot1 sjm_tab LEFT JOIN ot2 ot3
                         ^          ^
                   'tab'-+          +--- left join we're adding triggers for

              LEFT JOIN's ON expression may not have references to subquery
              columns.  The subquery was in the WHERE clause, so IN-equality
              is in the WHERE clause, also.
              However, equality propagation code may have propagated the
              IN-equality into ON expression, and we may get things like

                subquery_inner_table=const

              in the ON expression. We must not check such conditions during
              SJM-lookup, because 1) subquery_inner_table has no valid current
              row (materialization temp.table has it instead), and 2) they
              would be true anyway.
            */
            SJ_MATERIALIZATION_INFO *sjm=
              inner_tab->bush_children->start->emb_sj_nest->sj_mat_info;
            if (sjm->is_used && !sjm->is_sj_scan)
              is_sjm_lookup_tab= TRUE;
          }

          if (inner_tab == first_inner_tab && inner_tab->on_precond &&
              !is_sjm_lookup_tab)
            add_cond_and_fix(thd, &tmp_cond, inner_tab->on_precond);
          if (tmp_cond && !is_sjm_lookup_tab)
          {
            JOIN_TAB *cond_tab=  (inner_tab < first_inner_tab ?
                                  first_inner_tab : inner_tab);
            Item **sel_cond_ref= (inner_tab < first_inner_tab ?
                                  &first_inner_tab->on_precond :
                                  &inner_tab->select_cond);
            /*
              First add the guards for match variables of
              all embedding outer join operations.
	    */
            if (!(tmp_cond= add_found_match_trig_cond(thd,
                                                     cond_tab->first_inner,
                                                     tmp_cond,
                                                     first_inner_tab)))
              DBUG_RETURN(1);
            /*
              Now add the guard turning the predicate off for
              the null complemented row.
	    */
            DBUG_PRINT("info", ("Item_func_trig_cond"));
            tmp_cond= new (thd->mem_root) Item_func_trig_cond(thd, tmp_cond,
                                              &first_inner_tab->
                                              not_null_compl);
            DBUG_PRINT("info", ("Item_func_trig_cond %p",
                                tmp_cond));
            if (tmp_cond)
              tmp_cond->quick_fix_field();
	    /* Add the predicate to other pushed down predicates */
            DBUG_PRINT("info", ("Item_cond_and"));
            *sel_cond_ref= !(*sel_cond_ref) ?
                             tmp_cond :
                             new (thd->mem_root) Item_cond_and(thd, *sel_cond_ref, tmp_cond);
            DBUG_PRINT("info", ("Item_cond_and %p",
                                (*sel_cond_ref)));
            if (!(*sel_cond_ref))
              DBUG_RETURN(1);
            (*sel_cond_ref)->quick_fix_field();
            (*sel_cond_ref)->update_used_tables();
            if (cond_tab->select)
              cond_tab->select->cond= cond_tab->select_cond;
          }
        }
        first_inner_tab= first_inner_tab->first_upper;
      }
      if (!tab->bush_children)
        i++;
    }
  }
  DBUG_RETURN(0);
}


MDEV-21028 Server crashes in Query_arena::set_query_arena upon SELECT from view

if the view has algorithm=temptable it is not updatable,
so DEFAULT() for its fields is meaningless,
and thus it's NULL or 0/'' for NOT NULL columns.

void 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;
    node= new (thd->mem_root) Explain_aggr_tmp_table;
    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)
      {
        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;
      node= new (thd->mem_root) Explain_aggr_remove_dups;
      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);
      prev_node= node;
      node= eaf;
      node->child= prev_node;
    }
  }
  xpl_sel->aggr_tree= node;
}

MariaDB Server v10.7 and below was discovered to contain a segmentation fault via the component sql/sql_class.cc.


int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
                List<Item> &fields, List<Item> &all_fields, ORDER *order,
                bool from_window_spec)
{
  SELECT_LEX *select = thd->lex->current_select;
  enum_parsing_place context_analysis_place=
                     thd->lex->current_select->context_analysis_place;
  thd->where="order clause";
  const bool for_union = select->master_unit()->is_union() &&
                         select == select->master_unit()->fake_select_lex;
  for (uint number = 1; order; order=order->next, number++)
  {
    if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
                           all_fields, false, true, from_window_spec))
      return 1;
    if ((*order->item)->with_window_func &&
        context_analysis_place != IN_ORDER_BY)
    {
      my_error(ER_WINDOW_FUNCTION_IN_WINDOW_SPEC, MYF(0));
      return 1;
    }

    /*
      UNION queries cannot be used with an aggregate function in
      an ORDER BY clause
    */

    if (for_union &&
        ((*order->item)->with_sum_func ||
         (*order->item)->with_window_func))
    {
      my_error(ER_AGGREGATE_ORDER_FOR_UNION, MYF(0), number);
      return 1;
    }

    if (from_window_spec && (*order->item)->with_sum_func &&
        (*order->item)->type() != Item::SUM_FUNC_ITEM)
      (*order->item)->split_sum_func(thd, ref_pointer_array,
                                     all_fields, SPLIT_SUM_SELECT);
  }
  return 0;
}


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&= ~((nesting_map)1 << 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|= (nesting_map)1 << 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&= ~((nesting_map)1 << 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|= (nesting_map)1 << 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);
}


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

  THD_STAGE_INFO(thd, stage_executing);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  THD_STAGE_INFO(thd, stage_sending_data);
  DBUG_PRINT("info", ("%s", thd->proc_info));
  result->send_result_set_metadata(
                 procedure ? procedure_fields_list : *fields,
                 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
  error= do_select(this, procedure);
  /* Accumulate the counts from all join iterations of all join parts. */
  thd->inc_examined_row_count(join_examined_rows);
  DBUG_PRINT("counts", ("thd->examined_row_count: %lu",
                        (ulong) thd->get_examined_row_count()));

  DBUG_VOID_RETURN;
}


static bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
                                   bool skip_unprefixed_keyparts)
{
  KEYUSE key_end, *prev, *save_pos, *use;
  uint found_eq_constant, i;

  DBUG_ASSERT(keyuse->elements);

  my_qsort(keyuse->buffer, keyuse->elements, sizeof(KEYUSE),
           (qsort_cmp) sort_keyuse);

  bzero((char*) &key_end, sizeof(key_end));    /* Add for easy testing */
  if (insert_dynamic(keyuse, (uchar*) &key_end))
    return TRUE;

  if (optimizer_flag(thd, OPTIMIZER_SWITCH_DERIVED_WITH_KEYS))
    generate_derived_keys(keyuse);

  use= save_pos= dynamic_element(keyuse,0,KEYUSE*);
  prev= &key_end;
  found_eq_constant= 0;
  for (i=0 ; i < keyuse->elements-1 ; i++,use++)
  {
    if (!use->is_for_hash_join())
    {
      if (!(use->used_tables & ~OUTER_REF_TABLE_BIT) &&
          use->optimize != KEY_OPTIMIZE_REF_OR_NULL)
        use->table->const_key_parts[use->key]|= use->keypart_map;
      if (use->keypart != FT_KEYPART)
      {
        if (use->key == prev->key && use->table == prev->table)
        {
          if ((prev->keypart+1 < use->keypart && skip_unprefixed_keyparts) ||
              (prev->keypart == use->keypart && found_eq_constant))
            continue;				/* remove */
        }
        else if (use->keypart != 0 && skip_unprefixed_keyparts)
          continue; /* remove - first found must be 0 */
      }

      prev= use;
      found_eq_constant= !use->used_tables;
      use->table->reginfo.join_tab->checked_keys.set_bit(use->key);
    }
    /*
      Old gcc used a memcpy(), which is undefined if save_pos==use:
      http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19410
      http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39480
      This also disables a valgrind warning, so better to have the test.
    */
    if (save_pos != use)
      *save_pos= *use;
    /* Save ptr to first use */
    if (!use->table->reginfo.join_tab->keyuse)
      use->table->reginfo.join_tab->keyuse= save_pos;
    save_pos++;
  }
  i= (uint) (save_pos-(KEYUSE*) keyuse->buffer);
  (void) set_dynamic(keyuse,(uchar*) &key_end,i);
  keyuse->elements= i;

  return FALSE;
}


make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond,
                              table_map tables, table_map used_table,
                              int join_tab_idx_arg,
                              bool exclude_expensive_cond __attribute__
                              ((unused)),
                              bool retain_ref_cond,
                              bool is_top_and_level)

{
  table_map rand_table_bit= (table_map) RAND_TABLE_BIT;

  if (used_table && !(cond->used_tables() & used_table))
    return (COND*) 0;				// Already checked

  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++))
      {
        /*
          Special handling of top level conjuncts with RAND_TABLE_BIT:
          if such a conjunct contains a reference to a field that is not
          an outer field then it is pushed to the corresponding table by
          the same rule as all other conjuncts. Otherwise, if the conjunct
          is used in WHERE is is pushed to the last joined table, if is it
          is used in ON condition of an outer join it is pushed into the
          last inner table of the outer join. Such conjuncts are pushed in
          a call of make_cond_for_table_from_pred() with the
          parameter 'used_table' equal to PSEUDO_TABLE_BITS.
        */
        if (is_top_and_level && used_table == rand_table_bit &&
            (item->used_tables() & ~OUTER_REF_TABLE_BIT) != rand_table_bit)
        {
          /* The conjunct with RAND_TABLE_BIT has been allready pushed */
          continue;
        }
	Item *fix=make_cond_for_table_from_pred(thd, root_cond, item,
                                                tables, used_table,
                                                join_tab_idx_arg,
                                                exclude_expensive_cond,
                                                retain_ref_cond, false);
	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:
	/*
          Call fix_fields to propagate all properties of the children to
          the new parent Item. This should not be expensive because all
	  children of Item_cond_and should be fixed by now.
	*/
	if (new_cond->fix_fields(thd, 0))
          return (COND*) 0;
	new_cond->used_tables_cache=
	  ((Item_cond_and*) cond)->used_tables_cache &
	  tables;
	return new_cond;
      }
    }
    else
    {						// Or list
      if (is_top_and_level && used_table == rand_table_bit &&
          (cond->used_tables() & ~OUTER_REF_TABLE_BIT) != rand_table_bit)
      {
        /* This top level formula with RAND_TABLE_BIT has been already pushed */
        return (COND*) 0;
      }

      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_for_table_from_pred(thd, root_cond, item,
                                                tables, 0L,
                                                join_tab_idx_arg,
                                                exclude_expensive_cond,
                                                retain_ref_cond, false);
	if (!fix)
	  return (COND*) 0;			// Always true
	new_cond->argument_list()->push_back(fix, thd->mem_root);
      }
      /*
        Call fix_fields to propagate all properties of the children to
        the new parent Item. This should not be expensive because all
        children of Item_cond_and should be fixed by now.
      */
      new_cond->fix_fields(thd, 0);
      new_cond->used_tables_cache= ((Item_cond_or*) cond)->used_tables_cache;
      new_cond->top_level_item();
      return new_cond;
    }
  }

  if (is_top_and_level && used_table == rand_table_bit &&
      (cond->used_tables() & ~OUTER_REF_TABLE_BIT) != rand_table_bit)
  {
    /* This top level formula with RAND_TABLE_BIT has been already pushed */
    return (COND*) 0;
  }

  /*
    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 && !retain_ref_cond) ||
      (cond->used_tables() & ~tables))
    return (COND*) 0;				// Can't check this yet

  if (cond->marker == 2 || cond->eq_cmp_result() == Item::COND_OK)
  {
    cond->set_join_tab_idx(join_tab_idx_arg);
    return cond;				// Not boolean op
  }

  if (cond->type() == Item::FUNC_ITEM &&
      ((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 && !retain_ref_cond &&
	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 && !retain_ref_cond &&
	test_if_ref(root_cond, (Item_field*) right_item,left_item))
    {
      cond->marker=3;			// Checked when read
      return (COND*) 0;
    }
  }
  cond->marker=2;
  cond->set_join_tab_idx(join_tab_idx_arg);
  return cond;
}


pick_table_access_method(JOIN_TAB *tab)
{
  switch (tab->type)
  {
  case JT_REF:
    tab->read_first_record= join_read_always_key;
    tab->read_record.read_record= join_read_next_same;
    break;

  case JT_REF_OR_NULL:
    tab->read_first_record= join_read_always_key_or_null;
    tab->read_record.read_record= join_read_next_same_or_null;
    break;

  case JT_CONST:
    tab->read_first_record= join_read_const;
    tab->read_record.read_record= join_no_more_records;
    break;

  case JT_EQ_REF:
    tab->read_first_record= join_read_key;
    tab->read_record.read_record= join_no_more_records;
    break;

  case JT_FT:
    tab->read_first_record= join_ft_read_first;
    tab->read_record.read_record= join_ft_read_next;
    break;

  case JT_SYSTEM:
    tab->read_first_record= join_read_system;
    tab->read_record.read_record= join_no_more_records;
    break;

  /* keep gcc happy */
  default:
    break;
  }
}


bool JOIN::change_result(select_result *new_result, select_result *old_result)
{
  DBUG_ENTER("JOIN::change_result");
  if (old_result == NULL || result == old_result)
  {
    result= new_result;
    if (result->prepare(fields_list, select_lex->master_unit()) ||
        result->prepare2())
      DBUG_RETURN(true); /* purecov: inspected */
    DBUG_RETURN(false);
  }
  DBUG_RETURN(result->change_result(new_result));
}


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

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

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

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


bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
{
  DBUG_ENTER("mysql_explain_union");
  bool res= 0;
  SELECT_LEX *first= unit->first_select();

  for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
  {
    sl->set_explain_type(FALSE);
    sl->options|= SELECT_DESCRIBE;
  }

  if (unit->is_union() || unit->fake_select_lex)
  {
    ulonglong save_options= 0;

    if (unit->union_needs_tmp_table() && unit->fake_select_lex)
    {
      save_options= unit->fake_select_lex->options;
      unit->fake_select_lex->select_number= FAKE_SELECT_LEX_ID; // just for initialization
      unit->fake_select_lex->type= "UNION RESULT";
      unit->fake_select_lex->options|= SELECT_DESCRIBE;
    }
    if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
      res= unit->exec();

    if (unit->union_needs_tmp_table() && unit->fake_select_lex)
      unit->fake_select_lex->options= save_options;
  }
  else
  {
    thd->lex->current_select= first;
    unit->set_limit(unit->global_parameters());
    res= mysql_select(thd,
                      first->table_list.first,
                      first->with_wild, first->item_list,
                      first->where,
                      first->order_list.elements + first->group_list.elements,
                      first->order_list.first,
                      first->group_list.first,
                      first->having,
                      thd->lex->proc_list.first,
                      first->options | thd->variables.option_bits | SELECT_DESCRIBE,
                      result, unit, first);
  }
  DBUG_RETURN(res || thd->is_error());
}


fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
               Ref_ptr_array ref_pointer_array)
{
  Item_outer_ref *ref;

  /*
    Mark the references from  the inner_refs_list that are occurred in
    the group by expressions. Those references will contain direct
    references to the referred fields. The markers are set in
    the found_in_group_by field of the references from the list.
  */
  List_iterator_fast <Item_outer_ref> ref_it(select->inner_refs_list);
  for (ORDER *group= select->join->group_list; group;  group= group->next)
  {
    (*group->item)->walk(&Item::check_inner_refs_processor, TRUE, &ref_it);
  }

  while ((ref= ref_it++))
  {
    bool direct_ref= false;
    Item *item= ref->outer_ref;
    Item **item_ref= ref->ref;
    Item_ref *new_ref;
    /*
      TODO: this field item already might be present in the select list.
      In this case instead of adding new field item we could use an
      existing one. The change will lead to less operations for copying fields,
      smaller temporary tables and less data passed through filesort.
    */
    if (!ref_pointer_array.is_null() && !ref->found_in_select_list)
    {
      int el= all_fields.elements;
      ref_pointer_array[el]= item;
      /* Add the field item to the select list of the current select. */
      all_fields.push_front(item, thd->mem_root);
      /*
        If it's needed reset each Item_ref item that refers this field with
        a new reference taken from ref_pointer_array.
      */
      item_ref= &ref_pointer_array[el];
    }

    if (ref->in_sum_func)
    {
      Item_sum *sum_func;
      if (ref->in_sum_func->nest_level > select->nest_level)
        direct_ref= TRUE;
      else
      {
        for (sum_func= ref->in_sum_func; sum_func &&
             sum_func->aggr_level >= select->nest_level;
             sum_func= sum_func->in_sum_func)
        {
          if (sum_func->aggr_level == select->nest_level)
          {
            direct_ref= TRUE;
            break;
          }
        }
      }
    }
    else if (ref->found_in_group_by)
      direct_ref= TRUE;

    new_ref= direct_ref ?
              new (thd->mem_root) Item_direct_ref(thd, ref->context, item_ref, ref->table_name,
                          ref->field_name, ref->alias_name_used) :
              new (thd->mem_root) Item_ref(thd, ref->context, item_ref, ref->table_name,
                          ref->field_name, ref->alias_name_used);
    if (!new_ref)
      return TRUE;
    ref->outer_ref= new_ref;
    ref->ref= &ref->outer_ref;

    if (!ref->fixed && ref->fix_fields(thd, 0))
      return TRUE;
    thd->lex->used_tables|= item->used_tables();
    thd->lex->current_select->select_list_tables|= item->used_tables();
  }
  return false;
}


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


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;
    }
    if ((table->nested_join && !is_eliminated_nest) ||
        (!table->nested_join && (table->table->map & ~join->eliminated_tables)))
      n++;
  }
  DBUG_RETURN(n);
}


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


int append_possible_keys(MEM_ROOT *alloc, String_list &list, TABLE *table,
                         key_map possible_keys)
{
  uint j;
  for (j=0 ; j < table->s->keys ; j++)
  {
    if (possible_keys.is_set(j))
      list.append_str(alloc, table->key_info[j].name);
  }
  return 0;
}


AGGR_OP::end_send()
{
  enum_nested_loop_state rc= NESTED_LOOP_OK;
  TABLE *table= join_tab->table;
  JOIN *join= join_tab->join;

  // All records were stored, send them further
  int tmp, new_errno= 0;

  if ((rc= put_record(true)) < NESTED_LOOP_OK)
    return rc;

  if ((tmp= table->file->extra(HA_EXTRA_NO_CACHE)))
  {
    DBUG_PRINT("error",("extra(HA_EXTRA_NO_CACHE) failed"));
    new_errno= tmp;
  }
  if ((tmp= table->file->ha_index_or_rnd_end()))
  {
    DBUG_PRINT("error",("ha_index_or_rnd_end() failed"));
    new_errno= tmp;
  }
  if (new_errno)
  {
    table->file->print_error(new_errno,MYF(0));
    return NESTED_LOOP_ERROR;
  }

  // Update ref array
  join_tab->join->set_items_ref_array(*join_tab->ref_array);
  bool keep_last_filesort_result = join_tab->filesort ? false : true;
  if (join_tab->window_funcs_step)
  {
    if (join_tab->window_funcs_step->exec(join, keep_last_filesort_result))
      return NESTED_LOOP_ERROR;
  }

  table->reginfo.lock_type= TL_UNLOCK;

  bool in_first_read= true;

  /*
     Reset the counter before copying rows from internal temporary table to
     INSERT table.
  */
  join_tab->join->thd->get_stmt_da()->reset_current_row_for_warning();
  while (rc == NESTED_LOOP_OK)
  {
    int error;
    if (in_first_read)
    {
      in_first_read= false;
      error= join_init_read_record(join_tab);
    }
    else
      error= join_tab->read_record.read_record(&join_tab->read_record);

    if (error > 0 || (join->thd->is_error()))   // Fatal error
      rc= NESTED_LOOP_ERROR;
    else if (error < 0)
      break;
    else if (join->thd->killed)		  // Aborted by user
    {
      join->thd->send_kill_message();
      rc= NESTED_LOOP_KILLED;
    }
    else
    {
      rc= evaluate_join_record(join, join_tab, 0);
    }
  }

  if (keep_last_filesort_result)
  {
    delete join_tab->filesort_result;
    join_tab->filesort_result= NULL;
  }

  // Finish rnd scn after sending records
  if (join_tab->table->file->inited)
    join_tab->table->file->ha_rnd_end();

  return rc;
}


int safe_index_read(JOIN_TAB *tab)
{
  int error;
  TABLE *table= tab->table;
  if ((error= table->file->ha_index_read_map(table->record[0],
                                             tab->ref.key_buff,
                                             make_prev_keypart_map(tab->ref.key_parts),
                                             HA_READ_KEY_EXACT)))
    return report_error(table, error);
  return 0;
}


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);
  delete procedure;
  DBUG_RETURN(error);
}


join_read_prev(READ_RECORD *info)
{
  int error;
  if ((error= info->table->file->ha_index_prev(info->record)))
    return report_error(info->table, error);
  return 0;
}


uint check_join_cache_usage(JOIN_TAB *tab,
                            ulonglong options,
                            uint no_jbuf_after,
                            uint table_index,
                            JOIN_TAB *prev_tab)
{
  Cost_estimate cost;
  uint flags= 0;
  ha_rows rows= 0;
  uint bufsz= 4096;
  JOIN_CACHE *prev_cache=0;
  JOIN *join= tab->join;
  MEM_ROOT *root= join->thd->mem_root;
  uint cache_level= tab->used_join_cache_level;
  bool force_unlinked_cache=
         !(join->allowed_join_cache_types & JOIN_CACHE_INCREMENTAL_BIT);
  bool no_hashed_cache=
         !(join->allowed_join_cache_types & JOIN_CACHE_HASHED_BIT);
  bool no_bka_cache=
         !(join->allowed_join_cache_types & JOIN_CACHE_BKA_BIT);

  join->return_tab= 0;

  /*
    Don't use join cache if @@join_cache_level==0 or this table is the first
    one join suborder (either at top level or inside a bush)
  */
  if (cache_level == 0 || !prev_tab)
    return 0;

  if (force_unlinked_cache && (cache_level%2 == 0))
    cache_level--;

  if (options & SELECT_NO_JOIN_CACHE)
    goto no_join_cache;

  if (tab->use_quick == 2)
    goto no_join_cache;

  if (tab->table->map & join->complex_firstmatch_tables)
    goto no_join_cache;

  /*
    Don't use join cache if we're inside a join tab range covered by LooseScan
    strategy (TODO: LooseScan is very similar to FirstMatch so theoretically it
    should be possible to use join buffering in the same way we're using it for
    multi-table firstmatch ranges).
  */
  if (tab->inside_loosescan_range)
    goto no_join_cache;

  if (tab->is_inner_table_of_semijoin() &&
      !join->allowed_semijoin_with_cache)
    goto no_join_cache;
  if (tab->is_inner_table_of_outer_join() &&
      !join->allowed_outer_join_with_cache)
    goto no_join_cache;

  /*
    Non-linked join buffers can't guarantee one match
  */
  if (tab->is_nested_inner())
  {
    if (force_unlinked_cache || cache_level == 1)
      goto no_join_cache;
    if (cache_level & 1)
      cache_level--;
  }

  /*
    Don't use BKA for materialized tables. We could actually have a
    meaningful use of BKA when linked join buffers are used.

    The problem is, the temp.table is not filled (actually not even opened
    properly) yet, and this doesn't let us call
    handler->multi_range_read_info(). It is possible to come up with
    estimates, etc. without acessing the table, but it seems not to worth the
    effort now.
  */
  if (tab->table->pos_in_table_list->is_materialized_derived())
  {
    no_bka_cache= true;
    /*
      Don't use hash join algorithm if the temporary table for the rows
      of the derived table will be created with an equi-join key.
    */
    if (tab->table->s->keys)
      no_hashed_cache= true;
  }

  /*
    Don't use join buffering if we're dictated not to by no_jbuf_after
    (This is not meaningfully used currently)
  */
  if (table_index > no_jbuf_after)
    goto no_join_cache;

  /*
    TODO: BNL join buffer should be perfectly ok with tab->bush_children.
  */
  if (tab->loosescan_match_tab || tab->bush_children)
    goto no_join_cache;

  for (JOIN_TAB *first_inner= tab->first_inner; first_inner;
       first_inner= first_inner->first_upper)
  {
    if (first_inner != tab &&
        (!first_inner->use_join_cache || !(tab-1)->use_join_cache))
      goto no_join_cache;
  }
  if (tab->first_sj_inner_tab && tab->first_sj_inner_tab != tab &&
      (!tab->first_sj_inner_tab->use_join_cache || !(tab-1)->use_join_cache))
    goto no_join_cache;
  if (!prev_tab->use_join_cache)
  {
    /*
      Check whether table tab and the previous one belong to the same nest of
      inner tables and if so do not use join buffer when joining table tab.
    */
    if (tab->first_inner && tab != tab->first_inner)
    {
      for (JOIN_TAB *first_inner= tab[-1].first_inner;
           first_inner;
           first_inner= first_inner->first_upper)
      {
        if (first_inner == tab->first_inner)
          goto no_join_cache;
      }
    }
    else if (tab->first_sj_inner_tab && tab != tab->first_sj_inner_tab &&
             tab->first_sj_inner_tab == tab[-1].first_sj_inner_tab)
      goto no_join_cache;
  }

  prev_cache= prev_tab->cache;

  switch (tab->type) {
  case JT_ALL:
    if (cache_level == 1)
      prev_cache= 0;
    if ((tab->cache= new (root) JOIN_CACHE_BNL(join, tab, prev_cache)))
    {
      tab->icp_other_tables_ok= FALSE;
      return (2 - MY_TEST(!prev_cache));
    }
    goto no_join_cache;
  case JT_SYSTEM:
  case JT_CONST:
  case JT_REF:
  case JT_EQ_REF:
    if (cache_level <=2 || (no_hashed_cache && no_bka_cache))
      goto no_join_cache;
    if (tab->ref.is_access_triggered())
      goto no_join_cache;

    if (!tab->is_ref_for_hash_join() && !no_bka_cache)
    {
      flags= HA_MRR_NO_NULL_ENDPOINTS | HA_MRR_SINGLE_POINT;
      if (tab->table->covering_keys.is_set(tab->ref.key))
        flags|= HA_MRR_INDEX_ONLY;
      rows= tab->table->file->multi_range_read_info(tab->ref.key, 10, 20,
                                                    tab->ref.key_parts,
                                                    &bufsz, &flags, &cost);
    }

    if ((cache_level <=4 && !no_hashed_cache) || no_bka_cache ||
        tab->is_ref_for_hash_join() ||
	((flags & HA_MRR_NO_ASSOCIATION) && cache_level <=6))
    {
      if (!tab->hash_join_is_possible() ||
          tab->make_scan_filter())
        goto no_join_cache;
      if (cache_level == 3)
        prev_cache= 0;
      if ((tab->cache= new (root) JOIN_CACHE_BNLH(join, tab, prev_cache)))
      {
        tab->icp_other_tables_ok= FALSE;
        return (4 - MY_TEST(!prev_cache));
      }
      goto no_join_cache;
    }
    if (cache_level > 4 && no_bka_cache)
      goto no_join_cache;

    if ((flags & HA_MRR_NO_ASSOCIATION) &&
	(cache_level <= 6 || no_hashed_cache))
      goto no_join_cache;

    if ((rows != HA_POS_ERROR) && !(flags & HA_MRR_USE_DEFAULT_IMPL))
    {
      if (cache_level <= 6 || no_hashed_cache)
      {
        if (cache_level == 5)
          prev_cache= 0;
        if ((tab->cache= new (root) JOIN_CACHE_BKA(join, tab, flags, prev_cache)))
          return (6 - MY_TEST(!prev_cache));
        goto no_join_cache;
      }
      else
      {
        if (cache_level == 7)
          prev_cache= 0;
        if ((tab->cache= new (root) JOIN_CACHE_BKAH(join, tab, flags, prev_cache)))
	{
          tab->idx_cond_fact_out= FALSE;
          return (8 - MY_TEST(!prev_cache));
        }
        goto no_join_cache;
      }
    }
    goto no_join_cache;
  default : ;
  }

no_join_cache:
  if (tab->type != JT_ALL && tab->is_ref_for_hash_join())
  {
    tab->type= JT_ALL;
    tab->ref.key_parts= 0;
  }
  revise_cache_usage(tab);
  return 0;
}


join_read_const(JOIN_TAB *tab)
{
  int error;
  TABLE *table= tab->table;
  if (table->status & STATUS_GARBAGE)		// If first read
  {
    table->status= 0;
    if (cp_buffer_from_ref(tab->join->thd, table, &tab->ref))
      error=HA_ERR_KEY_NOT_FOUND;
    else
    {
      error= table->file->ha_index_read_idx_map(table->record[0],tab->ref.key,
                                                (uchar*) tab->ref.key_buff,
                                                make_prev_keypart_map(tab->ref.key_parts),
                                                HA_READ_KEY_EXACT);
    }
    if (error)
    {
      table->status= STATUS_NOT_FOUND;
      mark_as_null_row(tab->table);
      empty_record(table);
      if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
	return report_error(table, error);
      return -1;
    }
    store_record(table,record[1]);
  }
  else if (!(table->status & ~STATUS_NULL_ROW))	// Only happens with left join
  {
    table->status=0;
    restore_record(table,record[1]);			// restore old record
  }
  table->null_row=0;
  return table->status ? -1 : 0;
}


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

  DBUG_ENTER("evaluate_join_record");
  DBUG_PRINT("enter",
             ("evaluate_join_record join: %p join_tab: %p"
              " cond: %p error: %d  alias %s",
              join, join_tab, select_cond, error,
              join_tab->table->alias.ptr()));
  if (error > 0 || (join->thd->is_error()))     // Fatal error
    DBUG_RETURN(NESTED_LOOP_ERROR);
  if (error < 0)
    DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
  if (join->thd->check_killed())			// Aborted by user
  {
    join->thd->send_kill_message();
    DBUG_RETURN(NESTED_LOOP_KILLED);            /* purecov: inspected */
  }

  join_tab->tracker->r_rows++;

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

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

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

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

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

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

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

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

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

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

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

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

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

  DBUG_RETURN(NESTED_LOOP_OK);
}


sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
{
  enum_nested_loop_state rc;
  JOIN_CACHE *cache= join_tab->cache;
  DBUG_ENTER("sub_select_cache");

  /*
    This function cannot be called if join_tab has no associated join
    buffer
  */
  DBUG_ASSERT(cache != NULL);

  join_tab->cache->reset_join(join);

  if (end_of_records)
  {
    rc= cache->join_records(FALSE);
    if (rc == NESTED_LOOP_OK || rc == NESTED_LOOP_NO_MORE_ROWS ||
        rc == NESTED_LOOP_QUERY_LIMIT)
      rc= sub_select(join, join_tab, end_of_records);
    DBUG_RETURN(rc);
  }
  if (join->thd->check_killed())
  {
    /* The user has aborted the execution of the query */
    join->thd->send_kill_message();
    DBUG_RETURN(NESTED_LOOP_KILLED);
  }
  if (!test_if_use_dynamic_range_scan(join_tab))
  {
    if (!cache->put_record())
      DBUG_RETURN(NESTED_LOOP_OK);
    /*
      We has decided that after the record we've just put into the buffer
      won't add any more records. Now try to find all the matching
      extensions for all records in the buffer.
    */
    rc= cache->join_records(FALSE);
    DBUG_RETURN(rc);
  }
  /*
     TODO: Check whether we really need the call below and we can't do
           without it. If it's not the case remove it.
  */
  rc= cache->join_records(TRUE);
  if (rc == NESTED_LOOP_OK || rc == NESTED_LOOP_NO_MORE_ROWS ||
      rc == NESTED_LOOP_QUERY_LIMIT)
    rc= sub_select(join, join_tab, end_of_records);
  DBUG_RETURN(rc);
}


int read_first_record_seq(JOIN_TAB *tab)
{
  if (tab->read_record.table->file->ha_rnd_init_with_error(1))
    return 1;
  return (*tab->read_record.read_record)(&tab->read_record);
}


static COND* substitute_for_best_equal_field(THD *thd, JOIN_TAB *context_tab,
                                             COND *cond,
                                             COND_EQUAL *cond_equal,
                                             void *table_join_idx)
{
  Item_equal *item_equal;
  COND *org_cond= cond;                 // Return this in case of fatal error

  if (cond->type() == Item::COND_ITEM)
  {
    List<Item> *cond_list= ((Item_cond*) cond)->argument_list();

    bool and_level= ((Item_cond*) cond)->functype() ==
                      Item_func::COND_AND_FUNC;
    if (and_level)
    {
      cond_equal= &((Item_cond_and *) cond)->m_cond_equal;
      cond_list->disjoin((List<Item> *) &cond_equal->current_level);/* remove Item_equal objects from the AND. */

      List_iterator_fast<Item_equal> it(cond_equal->current_level);
      while ((item_equal= it++))
      {
        item_equal->sort(&compare_fields_by_table_order, table_join_idx);
      }
    }

    List_iterator<Item> li(*cond_list);
    Item *item;
    while ((item= li++))
    {
      Item *new_item= substitute_for_best_equal_field(thd, context_tab,
                                                      item, cond_equal,
                                                      table_join_idx);
      /*
        This works OK with PS/SP re-execution as changes are made to
        the arguments of AND/OR items only
      */
      if (new_item != item)
        li.replace(new_item);
    }

    if (and_level)
    {
      COND *eq_cond= 0;
      List_iterator_fast<Item_equal> it(cond_equal->current_level);
      bool false_eq_cond= FALSE;
      while ((item_equal= it++))
      {
        eq_cond= eliminate_item_equal(thd, eq_cond, cond_equal->upper_levels,
                                      item_equal);
        if (!eq_cond)
	{
          eq_cond= 0;
          break;
        }
        else if (eq_cond->type() == Item::INT_ITEM && !eq_cond->val_bool())
	{
          /*
            This occurs when eliminate_item_equal() founds that cond is
            always false and substitutes it with Item_int 0.
            Due to this, value of item_equal will be 0, so just return it.
	  */
          cond= eq_cond;
          false_eq_cond= TRUE;
          break;
        }
      }
      if (eq_cond && !false_eq_cond)
      {
        /* Insert the generated equalities before all other conditions */
        if (eq_cond->type() == Item::COND_ITEM)
          ((Item_cond *) cond)->add_at_head(
                                  ((Item_cond *) eq_cond)->argument_list());
        else
	{
          if (cond_list->is_empty())
            cond= eq_cond;
          else
	  {
             /* Do not add an equality condition if it's always true */
             if (eq_cond->type() != Item::INT_ITEM &&
                 cond_list->push_front(eq_cond, thd->mem_root))
               eq_cond= 0;
          }
	}
      }
      if (!eq_cond)
      {
        /*
          We are out of memory doing the transformation.
          This is a fatal error now. However we bail out by returning the
          original condition that we had before we started the transformation.
	*/
	cond_list->append((List<Item> *) &cond_equal->current_level);
      }
    }
  }
  else if (cond->type() == Item::FUNC_ITEM &&
           ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
  {
    item_equal= (Item_equal *) cond;
    item_equal->sort(&compare_fields_by_table_order, table_join_idx);
    cond_equal= item_equal->upper_levels;
    if (cond_equal && cond_equal->current_level.head() == item_equal)
      cond_equal= cond_equal->upper_levels;
    cond= eliminate_item_equal(thd, 0, cond_equal, item_equal);
    return cond ? cond : org_cond;
  }
  else
  {
    while (cond_equal)
    {
      List_iterator_fast<Item_equal> it(cond_equal->current_level);
      while((item_equal= it++))
      {
        REPLACE_EQUAL_FIELD_ARG arg= {item_equal, context_tab};
        cond= cond->transform(thd, &Item::replace_equal_field, (uchar *) &arg);
      }
      cond_equal= cond_equal->upper_levels;
    }
  }
  return cond;
}