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

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

Project: server

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
        Item* const_cond= NULL;
        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, &const_cond,
                           join->join_tab[i].select_cond);

        DBUG_EXECUTE("where",print_where(const_cond,"constants",
					 QT_ORDINARY););

        if (const_cond)
        {
          Json_writer_object trace_const_cond(thd);
          trace_const_cond.add("condition_on_constant_tables", const_cond);
          if (const_cond->is_expensive())
          {
            trace_const_cond.add("evaluated", "false")
                            .add("cause", "expensive cond");
          }
          else
          {
            bool const_cond_result;
            {
              Json_writer_array a(thd, "computing_condition");
              const_cond_result= const_cond->val_int() != 0;
            }
            if (!const_cond_result)
            {
              DBUG_PRINT("info",("Found impossible WHERE condition"));
              trace_const_cond.add("evaluated", "true")
                              .add("found", "impossible where");
              join->exec_const_cond= NULL;
              DBUG_RETURN(1);
            }
          }
          join->exec_const_cond= const_cond;
        }

        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
    */
    Json_writer_object trace_wrapper(thd);
    Json_writer_object trace_conditions(thd, "attaching_conditions_to_tables");
    trace_conditions.add("original_condition", cond);
    Json_writer_array trace_attached_comp(thd,
                                        "attached_conditions_computation");
    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 */
        Json_writer_object ref_to_range(thd);
        ref_to_range.add("ref_to_range", true);
        ref_to_range.add("cause", "range uses longer 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_bool(thd, true); // 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();
            if (is_hj && tab->rowid_filter)
	    {
              delete tab->rowid_filter;
              tab->rowid_filter= 0;
	    }
	  }
	  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;

            if (build_tmp_join_prefix_cond(join, tab, &sel->cond))
              return true;

	    /*
              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->is_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, 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, 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 */
            /*
              TODO: the execution also gets here when we will not be using
              join buffer. Review these cases and perhaps, remove this call.
              (The final decision whether to use join buffer is made in
              check_join_cache_usage, so we should only call make_scan_filter()
              there, too).
            */
            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++;
    }

    if (unlikely(thd->trace_started()))
    {
      trace_attached_comp.end();
      Json_writer_array trace_attached_summary(thd,
                                               "attached_conditions_summary");
      for (tab= first_depth_first_tab(join); tab;
           tab= next_depth_first_tab(join, tab))
      {
        if (!tab->table)
          continue;
        Item *const cond = tab->select_cond;
        Json_writer_object trace_one_table(thd);
        trace_one_table.add_table_name(tab);
        trace_one_table.add("attached", cond);
      }
    }
  }
  DBUG_RETURN(0);
}

Project: server

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

  DBUG_PRINT("info", ("select %p (%u) <> JOIN %p",
                      select_lex, select_lex->select_number, this));
  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);
}

Project: server

void calc_group_buffer(TMP_TABLE_PARAM *param, ORDER *group)
{
  uint key_length=0, parts=0, null_parts=0;

  for (; group ; group=group->next)
  {
    Item *group_item= *group->item;
    Field *field= group_item->get_tmp_table_field();
    if (field)
    {
      enum_field_types type;
      if ((type= field->type()) == MYSQL_TYPE_BLOB)
	key_length+=MAX_BLOB_WIDTH;		// Can't be used as a key
      else if (type == MYSQL_TYPE_VARCHAR || type == MYSQL_TYPE_VAR_STRING)
        key_length+= field->field_length + HA_KEY_BLOB_LENGTH;
      else if (type == MYSQL_TYPE_BIT)
      {
        /* Bit is usually stored as a longlong key for group fields */
        key_length+= 8;                         // Big enough
      }
      else
	key_length+= field->pack_length();
    }
    else
    { 
      switch (group_item->cmp_type()) {
      case REAL_RESULT:
        key_length+= sizeof(double);
        break;
      case INT_RESULT:
        key_length+= sizeof(longlong);
        break;
      case DECIMAL_RESULT:
        key_length+= my_decimal_get_binary_size(group_item->max_length - 
                                                (group_item->decimals ? 1 : 0),
                                                group_item->decimals);
        break;
      case TIME_RESULT:
      {
        /*
          As items represented as DATE/TIME fields in the group buffer
          have STRING_RESULT result type, we increase the length 
          by 8 as maximum pack length of such fields.
        */
        key_length+= 8;
        break;
      }
      case STRING_RESULT:
      {
        enum enum_field_types type= group_item->field_type();
        if (type == MYSQL_TYPE_BLOB)
          key_length+= MAX_BLOB_WIDTH;		// Can't be used as a key
        else
        {
          /*
            Group strings are taken as varstrings and require an length field.
            A field is not yet created by create_tmp_field_ex()
            and the sizes should match up.
          */
          key_length+= group_item->max_length + HA_KEY_BLOB_LENGTH;
        }
        break;
      }
      default:
        /* This case should never be choosen */
        DBUG_ASSERT(0);
        my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL));
      }
    }
    parts++;
    if (group_item->maybe_null)
      null_parts++;
  }
  param->group_length= key_length + null_parts;
  param->group_parts= parts;
  param->group_null_parts= null_parts;
}

Project: server

create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
                                    TMP_ENGINE_COLUMNDEF *start_recinfo,
                                    TMP_ENGINE_COLUMNDEF **recinfo, 
                                    int error,
                                    bool ignore_last_dupp_key_error,
                                    bool *is_duplicate)
{
  TABLE new_table;
  TABLE_SHARE share;
  const char *save_proc_info;
  int write_err= 0;
  DBUG_ENTER("create_internal_tmp_table_from_heap");
  if (is_duplicate)
    *is_duplicate= FALSE;

  if (table->s->db_type() != heap_hton || error != HA_ERR_RECORD_FILE_FULL)
  {
    /*
      We don't want this error to be converted to a warning, e.g. in case of
      INSERT IGNORE ... SELECT.
    */
    table->file->print_error(error, MYF(ME_FATAL));
    DBUG_RETURN(1);
  }
  new_table= *table;
  share= *table->s;
  new_table.s= &share;
  new_table.s->db_plugin= ha_lock_engine(thd, TMP_ENGINE_HTON);
  if (unlikely(!(new_table.file= get_new_handler(&share, &new_table.mem_root,
                                                 new_table.s->db_type()))))
    DBUG_RETURN(1);				// End of memory

  if (unlikely(new_table.file->set_ha_share_ref(&share.ha_share)))
  {
    delete new_table.file;
    DBUG_RETURN(1);
  }

  save_proc_info=thd->proc_info;
  THD_STAGE_INFO(thd, stage_converting_heap_to_myisam);

  new_table.no_rows= table->no_rows;
  if (create_internal_tmp_table(&new_table, table->key_info, start_recinfo,
                                recinfo,
                                thd->lex->first_select_lex()->options |
			        thd->variables.option_bits))
    goto err2;
  if (open_tmp_table(&new_table))
    goto err1;
  if (table->file->indexes_are_disabled())
    new_table.file->ha_disable_indexes(HA_KEY_SWITCH_ALL);
  table->file->ha_index_or_rnd_end();
  if (table->file->ha_rnd_init_with_error(1))
    DBUG_RETURN(1);
  if (new_table.no_rows)
    new_table.file->extra(HA_EXTRA_NO_ROWS);
  else
  {
    /* update table->file->stats.records */
    table->file->info(HA_STATUS_VARIABLE);
    new_table.file->ha_start_bulk_insert(table->file->stats.records);
  }

  /*
    copy all old rows from heap table to MyISAM table
    This is the only code that uses record[1] to read/write but this
    is safe as this is a temporary MyISAM table without timestamp/autoincrement
    or partitioning.
  */
  while (!table->file->ha_rnd_next(new_table.record[1]))
  {
    write_err= new_table.file->ha_write_tmp_row(new_table.record[1]);
    DBUG_EXECUTE_IF("raise_error", write_err= HA_ERR_FOUND_DUPP_KEY ;);
    if (write_err)
      goto err;
    if (unlikely(thd->check_killed()))
      goto err_killed;
  }
  if (!new_table.no_rows && new_table.file->ha_end_bulk_insert())
    goto err;
  /* copy row that filled HEAP table */
  if (unlikely((write_err=new_table.file->ha_write_tmp_row(table->record[0]))))
  {
    if (new_table.file->is_fatal_error(write_err, HA_CHECK_DUP) ||
	!ignore_last_dupp_key_error)
      goto err;
    if (is_duplicate)
      *is_duplicate= TRUE;
  }
  else
  {
    if (is_duplicate)
      *is_duplicate= FALSE;
  }

  /* remove heap table and change to use myisam table */
  (void) table->file->ha_rnd_end();
  (void) table->file->ha_close();          // This deletes the table !
  delete table->file;
  table->file=0;
  plugin_unlock(0, table->s->db_plugin);
  share.db_plugin= my_plugin_lock(0, share.db_plugin);
  new_table.s= table->s;                       // Keep old share
  *table= new_table;
  *table->s= share;
  
  table->file->change_table_ptr(table, table->s);
  table->use_all_columns();
  if (save_proc_info)
    thd_proc_info(thd, (!strcmp(save_proc_info,"Copying to tmp table") ?
                  "Copying to tmp table on disk" : save_proc_info));
  DBUG_RETURN(0);

 err:
  DBUG_PRINT("error",("Got error: %d",write_err));
  table->file->print_error(write_err, MYF(0));
err_killed:
  (void) table->file->ha_rnd_end();
  (void) new_table.file->ha_close();
 err1:
  new_table.file->ha_delete_table(new_table.s->path.str);
 err2:
  delete new_table.file;
  thd_proc_info(thd, save_proc_info);
  table->mem_root= new_table.mem_root;
  DBUG_RETURN(1);
}

Project: server

is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
{
  Item_sum **sum_item_ptr;
  bool result= false;

  if (join->table_count != 1 ||                    /* reference more than 1 table */
      join->select_distinct ||                /* or a DISTINCT */
      join->select_lex->olap == ROLLUP_TYPE)  /* Check (B3) for ROLLUP */
    return false;

  if (join->make_sum_func_list(join->all_fields, join->fields_list, true))
    return false;

  Bitmap<MAX_FIELDS> first_aggdistinct_fields;
  bool first_aggdistinct_fields_initialized= false;
  for (sum_item_ptr= join->sum_funcs; *sum_item_ptr; sum_item_ptr++)
  {
    Item_sum *sum_item= *sum_item_ptr;
    Item *expr;
    /* aggregate is not AGGFN(DISTINCT) or more than 1 argument to it */
    switch (sum_item->sum_func())
    {
      case Item_sum::MIN_FUNC:
      case Item_sum::MAX_FUNC:
        continue;
      case Item_sum::COUNT_DISTINCT_FUNC: 
        break;
      case Item_sum::AVG_DISTINCT_FUNC:
      case Item_sum::SUM_DISTINCT_FUNC:
        if (sum_item->get_arg_count() == 1) 
          break;
        /* fall through */
      default: return false;
    }
    /*
      We arrive here for every COUNT(DISTINCT),AVG(DISTINCT) or SUM(DISTINCT).
      Collect the arguments of the aggregate functions to a list.
      We don't worry about duplicates as these will be sorted out later in 
      get_best_group_min_max 
    */
    Bitmap<MAX_FIELDS> cur_aggdistinct_fields;
    cur_aggdistinct_fields.clear_all();
    for (uint i= 0; i < sum_item->get_arg_count(); i++)
    {
      expr= sum_item->get_arg(i);
      /* The AGGFN(DISTINCT) arg is not an attribute? */
      if (expr->real_item()->type() != Item::FIELD_ITEM)
        return false;

      Item_field* item= static_cast<Item_field*>(expr->real_item());
      if (out_args)
        out_args->push_back(item, join->thd->mem_root);

      cur_aggdistinct_fields.set_bit(item->field->field_index);
      result= true;
    }
    /*
      If there are multiple aggregate functions, make sure that they all
      refer to exactly the same set of columns.
    */
    if (!first_aggdistinct_fields_initialized)
    {
      first_aggdistinct_fields= cur_aggdistinct_fields;
      first_aggdistinct_fields_initialized=true;
    }
    else if (first_aggdistinct_fields != cur_aggdistinct_fields)
      return false;
  }

  return result;
}

Project: server

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

Project: server

Field *Item::tmp_table_field_from_field_type_maybe_null(TABLE *table,
                                            Tmp_field_src *src,
                                            const Tmp_field_param *param,
                                            bool is_explicit_null)
{
  /*
    item->type() == CONST_ITEM excluded due to making fields for counter
    With help of Item_uint
  */
  DBUG_ASSERT(!param->make_copy_field() || type() == CONST_ITEM);
  DBUG_ASSERT(!is_result_field());
  Field *result;
  if ((result= tmp_table_field_from_field_type(table)))
  {
    if (result && is_explicit_null)
      result->is_created_from_null_item= true;
  }
  return result;
}

Project: server

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

Project: server

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.
  */

  Json_writer_object trace_wrapper(thd);
  Json_writer_object trace_exec(thd, "join_execution");
  trace_exec.add_select_number(select_lex->select_number);
  Json_writer_array trace_steps(thd, "steps");

  if (!select_lex->outer_select() &&                            // (1)
      select_lex != select_lex->master_unit()->fake_select_lex) // (2)
    thd->lex->set_limit_rows_examined();

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

  if (!tables_list && (table_count || !select_lex->with_sum_func) &&
      !select_lex->have_window_funcs())
  {                                           // Only test of functions
    if (select_options & SELECT_DESCRIBE)
      select_describe(this, FALSE, FALSE, FALSE,
		      (zero_result_cause?zero_result_cause:"No tables used"));
    else
    {
      if (result->send_result_set_metadata(*columns_list,
                                           Protocol::SEND_NUM_ROWS |
                                           Protocol::SEND_EOF))
      {
        DBUG_VOID_RETURN;
      }

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

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

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

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

        The only way to compute the value of window function(s) is to
        run the entire window function computation step (there is no shortcut).
      */
      const_tables= table_count;
      first_select= sub_select_postjoin_aggr;
    }
    else
    {
      (void) return_zero_rows(this, result, select_lex->leaf_tables,
                              *columns_list,
			      send_row_on_empty_set(),
			      select_options,
			      zero_result_cause,
			      having ? having : tmp_having, all_fields);
      DBUG_VOID_RETURN;
    }
  }
  
  /*
    Evaluate all constant expressions with subqueries in the
    ORDER/GROUP clauses to make sure that all subqueries return a
    single row. The evaluation itself will trigger an error if that is
    not the case.
  */
  if (exec_const_order_group_cond.elements &&
      !(select_options & SELECT_DESCRIBE) &&
      !select_lex->pushdown_select)
  {
    List_iterator_fast<Item> const_item_it(exec_const_order_group_cond);
    Item *cur_const_item;
    while ((cur_const_item= const_item_it++))
    {
      cur_const_item->val_str(); // This caches val_str() to Item::str_value
      if (unlikely(thd->is_error()))
      {
        error= thd->is_error();
        DBUG_VOID_RETURN;
      }
    }
  }

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

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

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

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

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

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

  DBUG_VOID_RETURN;
}

Project: server

int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
{
  DBUG_ENTER("SELECT_LEX::vers_setup_conds");
  const bool update_conds= !skip_setup_conds(thd);

  if (!versioned_tables)
  {
    for (TABLE_LIST *table= tables; table; table= table->next_local)
    {
      if (table->table && table->table->versioned())
        versioned_tables++;
      else if (table->vers_conditions.is_set() &&
              (table->is_non_derived() || !table->vers_conditions.used))
      {
        my_error(ER_VERS_NOT_VERSIONED, MYF(0), table->alias.str);
        DBUG_RETURN(-1);
      }
    }
  }

  if (versioned_tables == 0)
    DBUG_RETURN(0);

  /* For prepared statements we create items on statement arena,
     because they must outlive execution phase for multiple executions. */
  Query_arena_stmt on_stmt_arena(thd);

  // find outer system_time
  SELECT_LEX *outer_slex= outer_select();
  TABLE_LIST* outer_table= NULL;

  if (outer_slex)
  {
    TABLE_LIST* derived= master_unit()->derived;
    // inner SELECT may not be a derived table (derived == NULL)
    while (derived && outer_slex && !derived->vers_conditions.is_set())
    {
      derived= outer_slex->master_unit()->derived;
      outer_slex= outer_slex->outer_select();
    }
    if (derived && outer_slex)
    {
      DBUG_ASSERT(derived->vers_conditions.is_set());
      outer_table= derived;
    }
  }

  bool is_select= false;
  bool use_sysvar= false;
  switch (thd->lex->sql_command)
  {
  case SQLCOM_SELECT:
    use_sysvar= true;
    /* fall through */
  case SQLCOM_CREATE_TABLE:
  case SQLCOM_INSERT_SELECT:
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_DELETE_MULTI:
  case SQLCOM_UPDATE_MULTI:
    is_select= true;
  default:
    break;
  }

  for (TABLE_LIST *table= tables; table; table= table->next_local)
  {
    if (!table->table || table->is_view() || !table->table->versioned())
      continue;

    vers_select_conds_t &vers_conditions= table->vers_conditions;

#ifdef WITH_PARTITION_STORAGE_ENGINE
      /*
        if the history is stored in partitions, then partitions
        themselves are not versioned
      */
      if (table->partition_names && table->table->part_info->vers_info)
      {
        /* If the history is stored in partitions, then partitions
            themselves are not versioned. */
        if (vers_conditions.was_set())
        {
          my_error(ER_VERS_QUERY_IN_PARTITION, MYF(0), table->alias.str);
          DBUG_RETURN(-1);
        }
        else if (!vers_conditions.is_set())
          vers_conditions.set_all();
      }
#endif

    if (outer_table && !vers_conditions.is_set())
    {
      // propagate system_time from nearest outer SELECT_LEX
      vers_conditions= outer_table->vers_conditions;
      outer_table->vers_conditions.used= true;
    }

    // propagate system_time from sysvar
    if (!vers_conditions.is_set() && use_sysvar)
    {
      if (vers_conditions.init_from_sysvar(thd))
        DBUG_RETURN(-1);
    }

    if (vers_conditions.is_set())
    {
      if (vers_conditions.was_set() &&
          table->lock_type > TL_READ_NO_INSERT &&
          !vers_conditions.delete_history)
      {
        my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table->alias.str);
        DBUG_RETURN(-1);
      }

      if (vers_conditions.type == SYSTEM_TIME_ALL)
        continue;
    }

    bool timestamps_only= table->table->versioned(VERS_TIMESTAMP);

    if (vers_conditions.is_set() && vers_conditions.type != SYSTEM_TIME_HISTORY)
    {
      thd->where= "FOR SYSTEM_TIME";
      /* TODO: do resolve fix_length_and_dec(), fix_fields(). This requires
        storing vers_conditions as Item and make some magic related to
        vers_system_time_t/VERS_TRX_ID at stage of fix_fields()
        (this is large refactoring). */
      if (vers_conditions.resolve_units(thd))
        DBUG_RETURN(-1);
      if (timestamps_only && (vers_conditions.start.unit == VERS_TRX_ID ||
        vers_conditions.end.unit == VERS_TRX_ID))
      {
        my_error(ER_VERS_ENGINE_UNSUPPORTED, MYF(0), table->table_name.str);
        DBUG_RETURN(-1);
      }
    }

    if (update_conds)
    {
      vers_conditions.period = &table->table->s->vers;
      Item *cond= period_get_condition(thd, table, this, &vers_conditions,
                                      timestamps_only);
      if (is_select)
        table->on_expr= and_items(thd, table->on_expr, cond);
      else
      {
        if (join)
        {
          where= and_items(thd, join->conds, cond);
          join->conds= where;
        }
        else
          where= and_items(thd, where, cond);
        table->where= and_items(thd, table->where, cond);
      }

      table->vers_conditions.set_all();
    }
  } // for (table= tables; ...)

  DBUG_RETURN(0);
}

Project: server

bool vers_select_conds_t::init_from_sysvar(THD *thd)
{
  vers_asof_timestamp_t &in= thd->variables.vers_asof_timestamp;
  type= (vers_system_time_t) in.type;
  delete_history= false;
  start.unit= VERS_TIMESTAMP;
  if (type != SYSTEM_TIME_UNSPECIFIED && type != SYSTEM_TIME_ALL)
  {
    DBUG_ASSERT(type == SYSTEM_TIME_AS_OF);
    Datetime dt(in.unix_time, in.second_part, thd->variables.time_zone);

    start.item= new (thd->mem_root)
        Item_datetime_literal(thd, &dt, TIME_SECOND_PART_DIGITS);
    if (!start.item)
      return true;
  }
  else
    start.item= NULL;
  end.empty();
  return false;
}

Project: server

change_to_use_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_field,*item;
  DBUG_ENTER("change_to_use_tmp_fields");

  res_selected_fields.empty();
  res_all_fields.empty();

  uint border= all_fields.elements - elements;
  for (uint i= 0; (item= it++); i++)
  {
    Field *field;
    if ((item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM) ||
       item->with_window_func)
      item_field= item;
    else if (item->type() == Item::FIELD_ITEM)
    {
      if (!(item_field= item->get_tmp_table_item(thd)))
        DBUG_RETURN(true);
    }
    else if (item->type() == Item::FUNC_ITEM &&
             ((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC)
    {
      field= item->get_tmp_table_field();
      if (field != NULL)
      {
        /*
          Replace "@:=<expression>" with "@:=<tmp table
          column>". Otherwise, we would re-evaluate <expression>, and
          if expression were a subquery, this would access
          already-unlocked tables.
         */
        Item_func_set_user_var* suv=
          new (thd->mem_root) Item_func_set_user_var(thd, (Item_func_set_user_var*) item);
        Item_field *new_field= new (thd->mem_root) Item_temptable_field(thd, field);
        if (!suv || !new_field)
          DBUG_RETURN(true);                  // Fatal error
        List<Item> list;
        list.push_back(new_field, thd->mem_root);
        suv->set_arguments(thd, list);
        item_field= suv;
      }
      else
        item_field= item;
    }
    else if ((field= item->get_tmp_table_field()))
    {
      if (item->type() == Item::SUM_FUNC_ITEM && field->table->group)
        item_field= ((Item_sum*) item)->result_item(thd, field);
      else
        item_field= (Item *) new (thd->mem_root) Item_temptable_field(thd, field);
      if (!item_field)
        DBUG_RETURN(true);                    // Fatal error

      if (item->real_item()->type() != Item::FIELD_ITEM)
        field->orig_table= 0;
      item_field->name= item->name;
      if (item->type() == Item::REF_ITEM)
      {
        Item_field *ifield= (Item_field *) item_field;
        Item_ref *iref= (Item_ref *) item;
        ifield->table_name= iref->table_name;
        ifield->db_name= iref->db_name;
      }
#ifndef DBUG_OFF
      if (!item_field->name.str)
      {
        char buff[256];
        String str(buff,sizeof(buff),&my_charset_bin);
        str.length(0);
        str.extra_allocation(1024);
        item->print(&str, QT_ORDINARY);
        item_field->name.str= thd->strmake(str.ptr(), str.length());
        item_field->name.length= str.length();
      }
#endif
    }
    else
      item_field= item;

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

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

Project: server

count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, 
                  List<Item> &fields, bool reset_with_sum_func)
{
  List_iterator<Item> li(fields);
  Item *field;

  param->field_count=param->sum_func_count=param->func_count=
    param->hidden_field_count=0;
  param->quick_group=1;
  while ((field=li++))
  {
    Item::Type real_type= field->real_item()->type();
    if (real_type == Item::FIELD_ITEM)
      param->field_count++;
    else if (real_type == Item::SUM_FUNC_ITEM)
    {
      if (! field->const_item())
      {
	Item_sum *sum_item=(Item_sum*) field->real_item();
        if (!sum_item->depended_from() ||
            sum_item->depended_from() == select_lex)
        {
          if (!sum_item->quick_group)
            param->quick_group=0;			// UDF SUM function
          param->sum_func_count++;

          for (uint i=0 ; i < sum_item->get_arg_count() ; i++)
          {
            if (sum_item->get_arg(i)->real_item()->type() == Item::FIELD_ITEM)
              param->field_count++;
            else
              param->func_count++;
          }
        }
        param->func_count++;
      }
    }
    else
    {
      With_sum_func_cache *cache= field->get_with_sum_func_cache();
      param->func_count++;
      // "field" can point to Item_std_field, so "cache" can be NULL here.
      if (reset_with_sum_func && cache)
        cache->reset_with_sum_func();
    }
  }
}

Project: server

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();

    if (unlikely(error > 0 || (join->thd->is_error())))   // Fatal error
      rc= NESTED_LOOP_ERROR;
    else if (error < 0)
      break;
    else if (unlikely(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;
}

Project: server

void Item_result_field::get_tmp_field_src(Tmp_field_src *src,
                                          const Tmp_field_param *param)
{
  if (param->make_copy_field())
  {
    DBUG_ASSERT(result_field);
    src->set_field(result_field);
  }
  else
  {
    src->set_item_result_field(this); // Save for copy_funcs
  }
}

Project: server

JOIN::optimize_inner()
{
  DBUG_ENTER("JOIN::optimize_inner");
  subq_exit_fl= false;
  do_send_rows = (unit->select_limit_cnt) ? 1 : 0;

  DEBUG_SYNC(thd, "before_join_optimize");

  THD_STAGE_INFO(thd, stage_optimizing);

  set_allowed_join_cache_types();
  need_distinct= TRUE;

  Json_writer_object trace_wrapper(thd);
  Json_writer_object trace_prepare(thd, "join_optimization");
  trace_prepare.add_select_number(select_lex->select_number);
  Json_writer_array trace_steps(thd, "steps");

  /*
    Needed in case optimizer short-cuts,
    set properly in make_aggr_tables_info()
  */
  fields= &select_lex->item_list;

  if (select_lex->first_cond_optimization)
  {
    //Do it only for the first execution
    /* Merge all mergeable derived tables/views in this SELECT. */
    if (select_lex->handle_derived(thd->lex, DT_MERGE))
      DBUG_RETURN(TRUE);  
    table_count= select_lex->leaf_tables.elements;
  }

  if (select_lex->first_cond_optimization &&
      transform_in_predicates_into_in_subq(thd))
    DBUG_RETURN(1);

  // Update used tables after all handling derived table procedures
  select_lex->update_used_tables();

  /*
    In fact we transform underlying subqueries after their 'prepare' phase and
    before 'optimize' from upper query 'optimize' to allow semijoin
    conversion happened (which done in the same way.
  */
  if (select_lex->first_cond_optimization &&
      conds && conds->walk(&Item::exists2in_processor, 0, thd))
    DBUG_RETURN(1);
  /*
    TODO
    make view to decide if it is possible to write to WHERE directly or make Semi-Joins able to process ON condition if it is possible
  for (TABLE_LIST *tbl= tables_list; tbl; tbl= tbl->next_local)
  {
    if (tbl->on_expr &&
        tbl->on_expr->walk(&Item::exists2in_processor, 0, thd))
      DBUG_RETURN(1);
  }
  */

  if (transform_max_min_subquery())
    DBUG_RETURN(1); /* purecov: inspected */

  if (select_lex->first_cond_optimization)
  {
    /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */
    if (convert_join_subqueries_to_semijoins(this))
      DBUG_RETURN(1); /* purecov: inspected */
    /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */
    select_lex->update_used_tables();
  }
  
  eval_select_list_used_tables();

  table_count= select_lex->leaf_tables.elements;

  if (select_lex->options & OPTION_SCHEMA_TABLE &&
      optimize_schema_tables_memory_usage(select_lex->leaf_tables))
    DBUG_RETURN(1);

  if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
    DBUG_RETURN(-1);

  row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
	      unit->select_limit_cnt);
  /* select_limit is used to decide if we are likely to scan the whole table */
  select_limit= unit->select_limit_cnt;
  if (having || (select_options & OPTION_FOUND_ROWS))
    select_limit= HA_POS_ERROR;
#ifdef HAVE_REF_TO_FIELDS			// Not done yet
  /* Add HAVING to WHERE if possible */
  if (having && !group_list && !sum_func_count)
  {
    if (!conds)
    {
      conds= having;
      having= 0;
    }
    else if ((conds=new (thd->mem_root) Item_cond_and(conds,having)))
    {
      /*
        Item_cond_and can't be fixed after creation, so we do not check
        conds->is_fixed()
      */
      conds->fix_fields(thd, &conds);
      conds->change_ref_to_fields(thd, tables_list);
      conds->top_level_item();
      having= 0;
    }
  }
#endif

  SELECT_LEX *sel= select_lex;
  if (sel->first_cond_optimization)
  {
    /*
      The following code will allocate the new items in a permanent
      MEMROOT for prepared statements and stored procedures.

      But first we need to ensure that thd->lex->explain is allocated
      in the execution arena
    */
    create_explain_query_if_not_exists(thd->lex, thd->mem_root);

    Query_arena *arena, backup;
    arena= thd->activate_stmt_arena_if_needed(&backup);

    sel->first_cond_optimization= 0;

    /* Convert all outer joins to inner joins if possible */
    conds= simplify_joins(this, join_list, conds, TRUE, FALSE);
    if (thd->is_error() || select_lex->save_leaf_tables(thd))
    {
      if (arena)
        thd->restore_active_arena(arena, &backup);
      DBUG_RETURN(1);
    }
    build_bitmap_for_nested_joins(join_list, 0);

    sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0;

    sel->where= conds;

    select_lex->update_used_tables();

    if (arena)
      thd->restore_active_arena(arena, &backup);
  }

  if (optimize_constant_subqueries())
    DBUG_RETURN(1);

  if (conds && conds->with_subquery())
    (void) conds->walk(&Item::cleanup_is_expensive_cache_processor,
                       0, (void *) 0);
  if (having && having->with_subquery())
    (void) having->walk(&Item::cleanup_is_expensive_cache_processor,
			0, (void *) 0);

  List<Item> eq_list;

  if (setup_degenerate_jtbm_semi_joins(this, join_list, eq_list))
    DBUG_RETURN(1);

  if (eq_list.elements != 0)
  {
    Item *new_cond;

    if (eq_list.elements == 1)
      new_cond= eq_list.pop();
    else
      new_cond= new (thd->mem_root) Item_cond_and(thd, eq_list);

    if (new_cond &&
        ((new_cond->fix_fields(thd, &new_cond) ||
        !(conds= and_items(thd, conds, new_cond)) ||
        conds->fix_fields(thd, &conds))))
      DBUG_RETURN(TRUE);
  }
  eq_list.empty();

  if (select_lex->cond_pushed_into_where)
  {
    conds= and_conds(thd, conds, select_lex->cond_pushed_into_where);
    if (conds && conds->fix_fields(thd, &conds))
      DBUG_RETURN(1);
  }
  if (select_lex->cond_pushed_into_having)
  {
    having= and_conds(thd, having, select_lex->cond_pushed_into_having);
    if (having)
    {
      select_lex->having_fix_field= 1;
      select_lex->having_fix_field_for_pushed_cond= 1;
      if (having->fix_fields(thd, &having))
        DBUG_RETURN(1);
      select_lex->having_fix_field= 0;
      select_lex->having_fix_field_for_pushed_cond= 0;
    }
  }

  bool ignore_on_expr= false;
  /*
    PS/SP note: on_expr of versioned table can not be reallocated
    (see build_equal_items() below) because it can be not rebuilt
    at second invocation.
  */
  if (!thd->stmt_arena->is_conventional() && thd->mem_root != thd->stmt_arena->mem_root)
    for (TABLE_LIST *tbl= tables_list; tbl; tbl= tbl->next_local)
      if (tbl->table && tbl->on_expr && tbl->table->versioned())
      {
        ignore_on_expr= true;
        break;
      }
  conds= optimize_cond(this, conds, join_list, ignore_on_expr,
                       &cond_value, &cond_equal, OPT_LINK_EQUAL_FIELDS);

  if (thd->is_error())
  {
    error= 1;
    DBUG_PRINT("error",("Error from optimize_cond"));
    DBUG_RETURN(1);
  }

  having= optimize_cond(this, having, join_list, TRUE,
                        &having_value, &having_equal);

  if (thd->is_error())
  {
    error= 1;
    DBUG_PRINT("error",("Error from optimize_cond"));
    DBUG_RETURN(1);
  }

  /* Do not push into WHERE from HAVING if cond_value == Item::COND_FALSE */

  if (thd->lex->sql_command == SQLCOM_SELECT &&
      optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING) &&
      cond_value != Item::COND_FALSE)
  {
    having=
      select_lex->pushdown_from_having_into_where(thd, having);
    if (select_lex->attach_to_conds.elements != 0)
    {
      conds= and_new_conditions_to_optimized_cond(thd, conds, &cond_equal,
                                                  select_lex->attach_to_conds,
                                                  &cond_value);
      sel->attach_to_conds.empty();
    }
  }

  if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY))
  {
    TABLE_LIST *tbl;
    List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
    while ((tbl= li++))
      if (tbl->jtbm_subselect)
      {
        if (tbl->jtbm_subselect->pushdown_cond_for_in_subquery(thd, conds))
          DBUG_RETURN(1);
      }
  }

  if (setup_jtbm_semi_joins(this, join_list, eq_list))
    DBUG_RETURN(1);

  if (eq_list.elements != 0)
  {
    conds= and_new_conditions_to_optimized_cond(thd, conds, &cond_equal,
                                                eq_list, &cond_value);

    if (!conds &&
        cond_value != Item::COND_FALSE && cond_value != Item::COND_TRUE)
      DBUG_RETURN(TRUE);
  }

  if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED))
  {
    TABLE_LIST *tbl;
    List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
    while ((tbl= li++))
    {
      /* 
        Do not push conditions from where into materialized inner tables
        of outer joins: this is not valid.
      */
      if (tbl->is_materialized_derived())
      {
        JOIN *join= tbl->get_unit()->first_select()->join;
        if (join &&
            join->optimization_state == JOIN::OPTIMIZATION_PHASE_1_DONE &&
            join->with_two_phase_optimization)
          continue;
        /*
          Do not push conditions from where into materialized inner tables
          of outer joins: this is not valid.
        */
        if (!tbl->is_inner_table_of_outer_join())
	{
          if (pushdown_cond_for_derived(thd, conds, tbl))
	    DBUG_RETURN(1);
        }
	if (mysql_handle_single_derived(thd->lex, tbl, DT_OPTIMIZE))
	  DBUG_RETURN(1);
      }
    }
  }
  else
  {
    /* Run optimize phase for all derived tables/views used in this SELECT. */
    if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE))
      DBUG_RETURN(1);
  }
  {
    if (select_lex->where)
    {
      select_lex->cond_value= cond_value;
      if (sel->where != conds && cond_value == Item::COND_OK)
        thd->change_item_tree(&sel->where, conds);
    }
    if (select_lex->having)
    {
      select_lex->having_value= having_value;
      if (sel->having != having && having_value == Item::COND_OK)
        thd->change_item_tree(&sel->having, having);
    }
    if (cond_value == Item::COND_FALSE || having_value == Item::COND_FALSE ||
        (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
    {                                          /* Impossible cond */
      if (unit->select_limit_cnt)
      {
        DBUG_PRINT("info", (having_value == Item::COND_FALSE ?
                              "Impossible HAVING" : "Impossible WHERE"));
        zero_result_cause=  having_value == Item::COND_FALSE ?
                             "Impossible HAVING" : "Impossible WHERE";
      }
      else
      {
        DBUG_PRINT("info", ("Zero limit"));
        zero_result_cause= "Zero limit";
      }
      table_count= top_join_tab_count= 0;
      handle_implicit_grouping_with_window_funcs();
      error= 0;
      subq_exit_fl= true;
      goto setup_subq_exit;
    }
  }

#ifdef WITH_PARTITION_STORAGE_ENGINE
  {
    TABLE_LIST *tbl;
    List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
    while ((tbl= li++))
    {
      Item **prune_cond= get_sargable_cond(this, tbl->table);
      tbl->table->all_partitions_pruned_away=
        prune_partitions(thd, tbl->table, *prune_cond);
    }
  }
#endif

  /* 
     Try to optimize count(*), MY_MIN() and MY_MAX() to const fields if
     there is implicit grouping (aggregate functions but no
     group_list). In this case, the result set shall only contain one
     row. 
  */
  if (tables_list && implicit_grouping)
  {
    int res;
    /*
      opt_sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match
      to the WHERE conditions,
      or 1 if all items were resolved (optimized away),
      or 0, or an error number HA_ERR_...

      If all items were resolved by opt_sum_query, there is no need to
      open any tables.
    */
    if ((res=opt_sum_query(thd, select_lex->leaf_tables, all_fields, conds)))
    {
      DBUG_ASSERT(res >= 0);
      if (res == HA_ERR_KEY_NOT_FOUND)
      {
        DBUG_PRINT("info",("No matching min/max row"));
	zero_result_cause= "No matching min/max row";
        table_count= top_join_tab_count= 0;
	error=0;
        subq_exit_fl= true;
        handle_implicit_grouping_with_window_funcs();
        goto setup_subq_exit;
      }
      if (res > 1)
      {
        error= res;
        DBUG_PRINT("error",("Error from opt_sum_query"));
        DBUG_RETURN(1);
      }

      DBUG_PRINT("info",("Select tables optimized away"));
      if (!select_lex->have_window_funcs())
        zero_result_cause= "Select tables optimized away";
      tables_list= 0;				// All tables resolved
      select_lex->min_max_opt_list.empty();
      const_tables= top_join_tab_count= table_count;
      handle_implicit_grouping_with_window_funcs();
      /*
        Extract all table-independent conditions and replace the WHERE
        clause with them. All other conditions were computed by opt_sum_query
        and the MIN/MAX/COUNT function(s) have been replaced by constants,
        so there is no need to compute the whole WHERE clause again.
        Notice that make_cond_for_table() will always succeed to remove all
        computed conditions, because opt_sum_query() is applicable only to
        conjunctions.
        Preserve conditions for EXPLAIN.
      */
      if (conds && !(thd->lex->describe & DESCRIBE_EXTENDED))
      {
        COND *table_independent_conds=
          make_cond_for_table(thd, conds, PSEUDO_TABLE_BITS, 0, -1,
                              FALSE, FALSE);
        DBUG_EXECUTE("where",
                     print_where(table_independent_conds,
                                 "where after opt_sum_query()",
                                 QT_ORDINARY););
        conds= table_independent_conds;
      }
    }
  }
  if (!tables_list)
  {
    DBUG_PRINT("info",("No tables"));
    error= 0;
    subq_exit_fl= true;
    goto setup_subq_exit;
  }
  error= -1;					// Error is sent to client
  /* get_sort_by_table() call used to be here: */
  MEM_UNDEFINED(&sort_by_table, sizeof(sort_by_table));

  /*
    We have to remove constants and duplicates from group_list before
    calling make_join_statistics() as this may call get_best_group_min_max()
    which needs a simplfied group_list.
  */
  if (group_list && table_count == 1)
  {
    group_list= remove_const(this, group_list, conds,
                             rollup.state == ROLLUP::STATE_NONE,
                             &simple_group);
    if (unlikely(thd->is_error()))
    {
      error= 1;
      DBUG_RETURN(1);
    }
    if (!group_list)
    {
      /* The output has only one row */
      order=0;
      simple_order=1;
      group_optimized_away= 1;
      select_distinct=0;
    }
  }
  
  /* Calculate how to do the join */
  THD_STAGE_INFO(thd, stage_statistics);
  result->prepare_to_read_rows();
  if (unlikely(make_join_statistics(this, select_lex->leaf_tables,
                                    &keyuse)) ||
      unlikely(thd->is_fatal_error))
  {
    DBUG_PRINT("error",("Error: make_join_statistics() failed"));
    DBUG_RETURN(1);
  }

  /*
    If a splittable materialized derived/view dt_i is embedded into
    into another splittable materialized derived/view dt_o then
    splitting plans for dt_i and dt_o are evaluated independently.
    First the optimizer looks for the best splitting plan sp_i for dt_i.
    It happens when non-splitting plans for dt_o are evaluated.
    The cost of sp_i is considered as the cost of materialization of dt_i
    when evaluating any splitting plan for dt_o.
  */
  if (fix_all_splittings_in_plan())
    DBUG_RETURN(1);

setup_subq_exit:
  with_two_phase_optimization= check_two_phase_optimization(thd);
  if (with_two_phase_optimization)
    optimization_state= JOIN::OPTIMIZATION_PHASE_1_DONE;
  else
  {
    if (optimize_stage2())
      DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}

Project: server

Item_field::create_tmp_field_from_item_field(TABLE *new_table,
                                             Item_ref *orig_item,
                                             const Tmp_field_param *param)
{
  DBUG_ASSERT(!is_result_field());
  Field *result;
  LEX_CSTRING *new_name= (orig_item ? &orig_item->name :
                          !param->modify_item() ? &name :
                          &field->field_name);

  /*
    If item have to be able to store NULLs but underlaid field can't do it,
    create_tmp_field_from_field() can't be used for tmp field creation.
  */
  if (((maybe_null && in_rollup) ||
      (new_table->in_use->create_tmp_table_for_derived && /* for mat. view/dt */
       orig_item && orig_item->maybe_null)) &&
      !field->maybe_null())
  {
    /*
      The item the ref points to may have maybe_null flag set while
      the ref doesn't have it. This may happen for outer fields
      when the outer query decided at some point after name resolution phase
      that this field might be null. Take this into account here.
    */
    Record_addr rec(orig_item ? orig_item->maybe_null : maybe_null);
    const Type_handler *handler= type_handler()->
                                   type_handler_for_tmp_table(this);
    result= handler->make_and_init_table_field(new_name,
                                               rec, *this, new_table);
  }
  else if (param->table_cant_handle_bit_fields() &&
           field->type() == MYSQL_TYPE_BIT)
  {
    const Type_handler *handler= type_handler_long_or_longlong();
    result= handler->make_and_init_table_field(new_name,
                                               Record_addr(maybe_null),
                                               *this, new_table);
  }
  else
  {
    bool tmp_maybe_null= param->modify_item() ? maybe_null :
                                                field->maybe_null();
    result= field->create_tmp_field(new_table->in_use->mem_root, new_table,
                                    tmp_maybe_null);
    if (result && ! param->modify_item())
      result->field_name= *new_name;
  }
  if (result && param->modify_item())
    result_field= result;
  return result;
}

Project: server

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_func*) 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;
}

Project: server

Field *Item_func_user_var::create_tmp_field_ex(TABLE *table,
                                               Tmp_field_src *src,
                                               const Tmp_field_param *param)
{
  DBUG_ASSERT(is_result_field());
  DBUG_ASSERT(type() != NULL_ITEM);
  get_tmp_field_src(src, param);
  Field *result;
  if ((result= create_table_field_from_handler(table)) && param->modify_item())
    result_field= result;
  return result;
}

Project: server

bool JOIN::build_explain()
{
  DBUG_ENTER("JOIN::build_explain");
  have_query_plan= QEP_AVAILABLE;

  /*
    explain data must be created on the Explain_query::mem_root. Because it's
    just a memroot, not an arena, explain data must not contain any Items
  */
  MEM_ROOT *old_mem_root= thd->mem_root;
  Item *old_free_list __attribute__((unused))= thd->free_list;
  thd->mem_root= thd->lex->explain->mem_root;
  bool res= save_explain_data(thd->lex->explain, false /* can overwrite */,
                        need_tmp,
                        !skip_sort_order && !no_order && (order || group_list),
                        select_distinct);
  thd->mem_root= old_mem_root;
  DBUG_ASSERT(thd->free_list == old_free_list); // no Items were created
  if (res)
    DBUG_RETURN(1);
  uint select_nr= select_lex->select_number;
  JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt();
  for (uint i= 0; i < aggr_tables; i++, curr_tab++)
  {
    if (select_nr == INT_MAX)
    {
      /* this is a fake_select_lex of a union */
      select_nr= select_lex->master_unit()->first_select()->select_number;
      curr_tab->tracker= thd->lex->explain->get_union(select_nr)->
                         get_tmptable_read_tracker();
    }
    else if (select_nr < INT_MAX)
    {
      Explain_select *tmp= thd->lex->explain->get_select(select_nr);
      if (tmp)
        curr_tab->tracker= tmp->get_using_temporary_read_tracker();
    }
  }
  DBUG_RETURN(0);
}

Project: server

Field *Item_field::create_tmp_field_ex(TABLE *table,
                                       Tmp_field_src *src,
                                       const Tmp_field_param *param)
{
  DBUG_ASSERT(!is_result_field());
  Field *result;
  src->set_field(field);
  if (!(result= create_tmp_field_from_item_field(table, NULL, param)))
    return NULL;
  if (field->eq_def(result))
    src->set_default_field(field);
  return result;
}

Project: server

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

Project: server

create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
		 ORDER *group, bool distinct, bool save_sum_fields,
		 ulonglong select_options, ha_rows rows_limit,
                 const LEX_CSTRING *table_alias, bool do_not_open,
                 bool keep_row_order)
{
  MEM_ROOT *mem_root_save, own_root;
  TABLE *table;
  TABLE_SHARE *share;
  uint	i,field_count,null_count,null_pack_length;
  uint  copy_func_count= param->func_count;
  uint  hidden_null_count, hidden_null_pack_length, hidden_field_count;
  uint  blob_count,group_null_items, string_count;
  uint  temp_pool_slot=MY_BIT_NONE;
  uint fieldnr= 0;
  ulong reclength, string_total_length;
  bool  using_unique_constraint= false;
  bool  use_packed_rows= false;
  bool  not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS);
  bool  save_abort_on_warning;
  char  *tmpname,path[FN_REFLEN];
  uchar	*pos, *group_buff, *bitmaps;
  uchar *null_flags;
  Field **reg_field, **from_field, **default_field;
  uint *blob_field;
  Copy_field *copy=0;
  KEY *keyinfo;
  KEY_PART_INFO *key_part_info;
  Item **copy_func;
  TMP_ENGINE_COLUMNDEF *recinfo;
  /*
    total_uneven_bit_length is uneven bit length for visible fields
    hidden_uneven_bit_length is uneven bit length for hidden fields
  */
  uint total_uneven_bit_length= 0, hidden_uneven_bit_length= 0;
  bool force_copy_fields= param->force_copy_fields;
  /* Treat sum functions as normal ones when loose index scan is used. */
  save_sum_fields|= param->precomputed_group_by;
  DBUG_ENTER("create_tmp_table");
  DBUG_PRINT("enter",
             ("table_alias: '%s'  distinct: %d  save_sum_fields: %d  "
              "rows_limit: %lu  group: %d", table_alias->str,
              (int) distinct, (int) save_sum_fields,
              (ulong) rows_limit, MY_TEST(group)));

  if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES))
    temp_pool_slot = bitmap_lock_set_next(&temp_pool);

  if (temp_pool_slot != MY_BIT_NONE) // we got a slot
    sprintf(path, "%s_%lx_%i", tmp_file_prefix,
            current_pid, temp_pool_slot);
  else
  {
    /* if we run out of slots or we are not using tempool */
    sprintf(path, "%s%lx_%lx_%x", tmp_file_prefix,current_pid,
            (ulong) thd->thread_id, thd->tmp_table++);
  }

  /*
    No need to change table name to lower case as we are only creating
    MyISAM, Aria or HEAP tables here
  */
  fn_format(path, path, mysql_tmpdir, "", MY_REPLACE_EXT|MY_UNPACK_FILENAME);

  if (group)
  {
    ORDER **prev= &group;
    if (!param->quick_group)
      group=0;					// Can't use group key
    else for (ORDER *tmp=group ; tmp ; tmp=tmp->next)
    {
      /* Exclude found constant from the list */
      if ((*tmp->item)->const_item())
      {
        *prev= tmp->next;
        param->group_parts--;
        continue;
      }
      else
        prev= &(tmp->next);
      /*
        marker == 4 means two things:
        - store NULLs in the key, and
        - convert BIT fields to 64-bit long, needed because MEMORY tables
          can't index BIT fields.
      */
      (*tmp->item)->marker=4;			// Store null in key
      if ((*tmp->item)->too_big_for_varchar())
	using_unique_constraint= true;
    }
    if (param->group_length >= MAX_BLOB_WIDTH)
      using_unique_constraint= true;
    if (group)
      distinct=0;				// Can't use distinct
  }

  field_count=param->field_count+param->func_count+param->sum_func_count;
  hidden_field_count=param->hidden_field_count;

  /*
    When loose index scan is employed as access method, it already
    computes all groups and the result of all aggregate functions. We
    make space for the items of the aggregate function in the list of
    functions TMP_TABLE_PARAM::items_to_copy, so that the values of
    these items are stored in the temporary table.
  */
  if (param->precomputed_group_by)
    copy_func_count+= param->sum_func_count;
  
  init_sql_alloc(&own_root, "tmp_table", TABLE_ALLOC_BLOCK_SIZE, 0,
                 MYF(MY_THREAD_SPECIFIC));

  if (!multi_alloc_root(&own_root,
                        &table, sizeof(*table),
                        &share, sizeof(*share),
                        &reg_field, sizeof(Field*) * (field_count+1),
                        &default_field, sizeof(Field*) * (field_count),
                        &blob_field, sizeof(uint)*(field_count+1),
                        &from_field, sizeof(Field*)*field_count,
                        &copy_func, sizeof(*copy_func)*(copy_func_count+1),
                        &param->keyinfo, sizeof(*param->keyinfo),
                        &key_part_info,
                        sizeof(*key_part_info)*(param->group_parts+1),
                        &param->start_recinfo,
                        sizeof(*param->recinfo)*(field_count*2+4),
                        &tmpname, (uint) strlen(path)+1,
                        &group_buff, (group && ! using_unique_constraint ?
                                      param->group_length : 0),
                        &bitmaps, bitmap_buffer_size(field_count)*6,
                        NullS))
  {
    if (temp_pool_slot != MY_BIT_NONE)
      bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
    DBUG_RETURN(NULL);				/* purecov: inspected */
  }
  /* Copy_field belongs to TMP_TABLE_PARAM, allocate it in THD mem_root */
  if (!(param->copy_field= copy= new (thd->mem_root) Copy_field[field_count]))
  {
    if (temp_pool_slot != MY_BIT_NONE)
      bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
    free_root(&own_root, MYF(0));               /* purecov: inspected */
    DBUG_RETURN(NULL);				/* purecov: inspected */
  }
  param->items_to_copy= copy_func;
  strmov(tmpname, path);
  /* make table according to fields */

  bzero((char*) table,sizeof(*table));
  bzero((char*) reg_field,sizeof(Field*)*(field_count+1));
  bzero((char*) default_field, sizeof(Field*) * (field_count));
  bzero((char*) from_field,sizeof(Field*)*field_count);

  table->mem_root= own_root;
  mem_root_save= thd->mem_root;
  thd->mem_root= &table->mem_root;

  table->field=reg_field;
  table->alias.set(table_alias->str, table_alias->length, table_alias_charset);

  table->reginfo.lock_type=TL_WRITE;	/* Will be updated */
  table->map=1;
  table->temp_pool_slot = temp_pool_slot;
  table->copy_blobs= 1;
  table->in_use= thd;
  table->no_rows_with_nulls= param->force_not_null_cols;
  table->update_handler= NULL;
  table->check_unique_buf= NULL;

  table->s= share;
  init_tmp_table_share(thd, share, "", 0, "(temporary)", tmpname);
  share->blob_field= blob_field;
  share->table_charset= param->table_charset;
  share->primary_key= MAX_KEY;               // Indicate no primary key
  if (param->schema_table)
    share->db= INFORMATION_SCHEMA_NAME;

  /* Calculate which type of fields we will store in the temporary table */

  reclength= string_total_length= 0;
  blob_count= string_count= null_count= hidden_null_count= group_null_items= 0;
  param->using_outer_summary_function= 0;

  List_iterator_fast<Item> li(fields);
  Item *item;
  Field **tmp_from_field=from_field;
  while ((item=li++))
  {
    Item::Type type= item->type();
    if (type == Item::COPY_STR_ITEM)
    {
      item= ((Item_copy *)item)->get_item();
      type= item->type();
    }
    if (not_all_columns)
    {
      if (item->with_sum_func() && type != Item::SUM_FUNC_ITEM)
      {
        if (item->used_tables() & OUTER_REF_TABLE_BIT)
          item->update_used_tables();
        if ((item->real_type() == Item::SUBSELECT_ITEM) ||
            (item->used_tables() & ~OUTER_REF_TABLE_BIT))
        {
	  /*
	    Mark that the we have ignored an item that refers to a summary
	    function. We need to know this if someone is going to use
	    DISTINCT on the result.
	  */
	  param->using_outer_summary_function=1;
	  continue;
        }
      }
      if (item->const_item() && (int) hidden_field_count <= 0)
        continue; // We don't have to store this
    }
    if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields)
    {						/* Can't calc group yet */
      Item_sum *sum_item= (Item_sum *) item;
      sum_item->result_field=0;
      for (i=0 ; i < sum_item->get_arg_count() ; i++)
      {
	Item *arg= sum_item->get_arg(i);
	if (!arg->const_item())
	{
          Item *tmp_item;
          Field *new_field=
            create_tmp_field(table, arg, &copy_func,
                             tmp_from_field, &default_field[fieldnr],
                             group != 0,not_all_columns,
                             distinct, false);
	  if (!new_field)
	    goto err;					// Should be OOM
          DBUG_ASSERT(!new_field->field_name.str || strlen(new_field->field_name.str) == new_field->field_name.length);
	  tmp_from_field++;
	  reclength+=new_field->pack_length();
	  if (new_field->flags & BLOB_FLAG)
	  {
	    *blob_field++= fieldnr;
	    blob_count++;
	  }
          if (new_field->type() == MYSQL_TYPE_BIT)
            total_uneven_bit_length+= new_field->field_length & 7;
	  *(reg_field++)= new_field;
          if (new_field->real_type() == MYSQL_TYPE_STRING ||
              new_field->real_type() == MYSQL_TYPE_VARCHAR)
          {
            string_count++;
            string_total_length+= new_field->pack_length();
          }
          thd->mem_root= mem_root_save;
          if (!(tmp_item= new (thd->mem_root)
                Item_temptable_field(thd, new_field)))
            goto err;
          arg= sum_item->set_arg(i, thd, tmp_item);
          thd->mem_root= &table->mem_root;
          if (param->force_not_null_cols)
	  {
            new_field->flags|= NOT_NULL_FLAG;
            new_field->null_ptr= NULL;
          }
	  if (!(new_field->flags & NOT_NULL_FLAG))
          {
	    null_count++;
            /*
              new_field->maybe_null() is still false, it will be
              changed below. But we have to setup Item_field correctly
            */
            arg->maybe_null=1;
          }
          new_field->field_index= fieldnr++;
	}
      }
    }
    else
    {
      /*
	The last parameter to create_tmp_field_ex() is a bit tricky:

	We need to set it to 0 in union, to get fill_record() to modify the
	temporary table.
	We need to set it to 1 on multi-table-update and in select to
	write rows to the temporary table.
	We here distinguish between UNION and multi-table-updates by the fact
	that in the later case group is set to the row pointer.

        The test for item->marker == 4 is ensure we don't create a group-by
        key over a bit field as heap tables can't handle that.
      */
      Field *new_field;
      if (param->schema_table)
      {
        if ((new_field= item->create_field_for_schema(thd, table)))
          new_field->flags|= NO_DEFAULT_VALUE_FLAG;
      }
      else
      {
        new_field=
        create_tmp_field(table, item, &copy_func,
                         tmp_from_field, &default_field[fieldnr],
                         group != 0,
                         !force_copy_fields &&
                           (not_all_columns || group !=0),
                         /*
                           If item->marker == 4 then we force create_tmp_field
                           to create a 64-bit longs for BIT fields because HEAP
                           tables can't index BIT fields directly. We do the
                           same for distinct, as we want the distinct index
                           to be usable in this case too.
                         */
                         item->marker == 4  || param->bit_fields_as_long,
                         force_copy_fields);
      }
      if (unlikely(!new_field))
      {
	if (unlikely(thd->is_fatal_error))
	  goto err;				// Got OOM
	continue;				// Some kind of const item
      }
      DBUG_ASSERT(!new_field->field_name.str || strlen(new_field->field_name.str) == new_field->field_name.length);
      if (type == Item::SUM_FUNC_ITEM)
      {
        Item_sum *agg_item= (Item_sum *) item;
        /*
          Update the result field only if it has never been set, or if the
          created temporary table is not to be used for subquery
          materialization.

          The reason is that for subqueries that require
          materialization as part of their plan, we create the
          'external' temporary table needed for IN execution, after
          the 'internal' temporary table needed for grouping.  Since
          both the external and the internal temporary tables are
          created for the same list of SELECT fields of the subquery,
          setting 'result_field' for each invocation of
          create_tmp_table overrides the previous value of
          'result_field'.

          The condition below prevents the creation of the external
          temp table to override the 'result_field' that was set for
          the internal temp table.
        */
        if (!agg_item->result_field || !param->materialized_subquery)
          agg_item->result_field= new_field;
      }
      tmp_from_field++;
      if (param->force_not_null_cols)
      {
        new_field->flags|= NOT_NULL_FLAG;
        new_field->null_ptr= NULL;
      }
      reclength+=new_field->pack_length();
      if (!(new_field->flags & NOT_NULL_FLAG))
	null_count++;
      if (new_field->type() == MYSQL_TYPE_BIT)
        total_uneven_bit_length+= new_field->field_length & 7;
      if (new_field->flags & BLOB_FLAG)
      {
        *blob_field++= fieldnr;
	blob_count++;
      }

      if (new_field->real_type() == MYSQL_TYPE_STRING ||
          new_field->real_type() == MYSQL_TYPE_VARCHAR)
      {
        string_count++;
        string_total_length+= new_field->pack_length();
      }

      if (item->marker == 4 && item->maybe_null)
      {
	group_null_items++;
	new_field->flags|= GROUP_FLAG;
      }
      new_field->field_index= fieldnr++;
      *(reg_field++)= new_field;
    }
    if (!--hidden_field_count)
    {
      /*
        This was the last hidden field; Remember how many hidden fields could
        have null
      */
      hidden_null_count=null_count;
      /*
	We need to update hidden_field_count as we may have stored group
	functions with constant arguments
      */
      param->hidden_field_count= fieldnr;
      null_count= 0;
      /*
        On last hidden field we store uneven bit length in
        hidden_uneven_bit_length and proceed calculation of
        uneven bits for visible fields into
        total_uneven_bit_length variable.
      */
      hidden_uneven_bit_length= total_uneven_bit_length;
      total_uneven_bit_length= 0;
    }
  }
  DBUG_ASSERT(fieldnr == (uint) (reg_field - table->field));
  DBUG_ASSERT(field_count >= (uint) (reg_field - table->field));
  field_count= fieldnr;
  *reg_field= 0;
  *blob_field= 0;				// End marker
  share->fields= field_count;
  share->column_bitmap_size= bitmap_buffer_size(share->fields);

  /* If result table is small; use a heap */
  /* future: storage engine selection can be made dynamic? */
  if (blob_count || using_unique_constraint
      || (thd->variables.big_tables && !(select_options & SELECT_SMALL_RESULT))
      || (select_options & TMP_TABLE_FORCE_MYISAM)
      || thd->variables.tmp_memory_table_size == 0)
  {
    share->db_plugin= ha_lock_engine(0, TMP_ENGINE_HTON);
    table->file= get_new_handler(share, &table->mem_root,
                                 share->db_type());
    if (group &&
	(param->group_parts > table->file->max_key_parts() ||
	 param->group_length > table->file->max_key_length()))
      using_unique_constraint= true;
  }
  else
  {
    share->db_plugin= ha_lock_engine(0, heap_hton);
    table->file= get_new_handler(share, &table->mem_root,
                                 share->db_type());
  }
  if (!table->file)
    goto err;

  if (table->file->set_ha_share_ref(&share->ha_share))
  {
    delete table->file;
    goto err;
  }

  if (!using_unique_constraint)
    reclength+= group_null_items;	// null flag is stored separately

  share->blob_fields= blob_count;
  if (blob_count == 0)
  {
    /* We need to ensure that first byte is not 0 for the delete link */
    if (param->hidden_field_count)
      hidden_null_count++;
    else
      null_count++;
  }
  hidden_null_pack_length= (hidden_null_count + 7 +
                            hidden_uneven_bit_length) / 8;
  null_pack_length= (hidden_null_pack_length +
                     (null_count + total_uneven_bit_length + 7) / 8);
  reclength+=null_pack_length;
  if (!reclength)
    reclength=1;				// Dummy select
  /* Use packed rows if there is blobs or a lot of space to gain */
  if (blob_count ||
      (string_total_length >= STRING_TOTAL_LENGTH_TO_PACK_ROWS &&
       (reclength / string_total_length <= RATIO_TO_PACK_ROWS ||
        string_total_length / string_count >= AVG_STRING_LENGTH_TO_PACK_ROWS)))
    use_packed_rows= 1;

  share->reclength= reclength;
  {
    uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1);
    share->rec_buff_length= alloc_length;
    if (!(table->record[0]= (uchar*)
                            alloc_root(&table->mem_root, alloc_length*3)))
      goto err;
    table->record[1]= table->record[0]+alloc_length;
    share->default_values= table->record[1]+alloc_length;
  }
  copy_func[0]=0;				// End marker
  param->func_count= (uint)(copy_func - param->items_to_copy); 

  setup_tmp_table_column_bitmaps(table, bitmaps);

  recinfo=param->start_recinfo;
  null_flags=(uchar*) table->record[0];
  pos=table->record[0]+ null_pack_length;
  if (null_pack_length)
  {
    bzero((uchar*) recinfo,sizeof(*recinfo));
    recinfo->type=FIELD_NORMAL;
    recinfo->length=null_pack_length;
    recinfo++;
    bfill(null_flags,null_pack_length,255);	// Set null fields

    table->null_flags= (uchar*) table->record[0];
    share->null_fields= null_count+ hidden_null_count;
    share->null_bytes= share->null_bytes_for_compare= null_pack_length;
  }
  null_count= (blob_count == 0) ? 1 : 0;
  hidden_field_count=param->hidden_field_count;

  /* Protect against warnings in field_conv() in the next loop*/
  save_abort_on_warning= thd->abort_on_warning;
  thd->abort_on_warning= 0;

  for (i=0,reg_field=table->field; i < field_count; i++,reg_field++,recinfo++)
  {
    Field *field= *reg_field;
    uint length;
    bzero((uchar*) recinfo,sizeof(*recinfo));

    if (!(field->flags & NOT_NULL_FLAG))
    {
      recinfo->null_bit= (uint8)1 << (null_count & 7);
      recinfo->null_pos= null_count/8;
      field->move_field(pos,null_flags+null_count/8,
			(uint8)1 << (null_count & 7));
      null_count++;
    }
    else
      field->move_field(pos,(uchar*) 0,0);
    if (field->type() == MYSQL_TYPE_BIT)
    {
      /* We have to reserve place for extra bits among null bits */
      ((Field_bit*) field)->set_bit_ptr(null_flags + null_count / 8,
                                        null_count & 7);
      null_count+= (field->field_length & 7);
    }
    field->reset();

    /*
      Test if there is a default field value. The test for ->ptr is to skip
      'offset' fields generated by initialize_tables
    */
    if (default_field[i] && default_field[i]->ptr)
    {
      /* 
         default_field[i] is set only in the cases  when 'field' can
         inherit the default value that is defined for the field referred
         by the Item_field object from which 'field' has been created.
      */
      Field *orig_field= default_field[i];
      /* Get the value from default_values */
      if (orig_field->is_null_in_record(orig_field->table->s->default_values))
        field->set_null();
      else
      {
        /*
          Copy default value. We have to use field_conv() for copy, instead of
          memcpy(), because bit_fields may be stored differently
        */
        my_ptrdiff_t ptr_diff= (orig_field->table->s->default_values -
                                orig_field->table->record[0]);
        field->set_notnull();
        orig_field->move_field_offset(ptr_diff);
        field_conv(field, orig_field);
        orig_field->move_field_offset(-ptr_diff);
      }
    }

    if (from_field[i])
    {						/* Not a table Item */
      copy->set(field,from_field[i],save_sum_fields);
      copy++;
    }
    length=field->pack_length_in_rec();
    pos+= length;

    /* Make entry for create table */
    recinfo->length=length;
    if (field->flags & BLOB_FLAG)
      recinfo->type= FIELD_BLOB;
    else if (use_packed_rows &&
             field->real_type() == MYSQL_TYPE_STRING &&
	     length >= MIN_STRING_LENGTH_TO_PACK_ROWS)
      recinfo->type= FIELD_SKIP_ENDSPACE;
    else if (field->real_type() == MYSQL_TYPE_VARCHAR)
      recinfo->type= FIELD_VARCHAR;
    else
      recinfo->type= FIELD_NORMAL;

    if (!--hidden_field_count)
      null_count=(null_count+7) & ~7;		// move to next byte

    // fix table name in field entry
    field->set_table_name(&table->alias);
  }
  /* Handle group_null_items */
  bzero(pos, table->s->reclength - (pos - table->record[0]));
  MEM_CHECK_DEFINED(table->record[0], table->s->reclength);

  thd->abort_on_warning= save_abort_on_warning;
  param->copy_field_end=copy;
  param->recinfo= recinfo;              	// Pointer to after last field
  store_record(table,s->default_values);        // Make empty default record

  if (thd->variables.tmp_memory_table_size == ~ (ulonglong) 0)	// No limit
    share->max_rows= ~(ha_rows) 0;
  else
    share->max_rows= (ha_rows) (((share->db_type() == heap_hton) ?
                                 MY_MIN(thd->variables.tmp_memory_table_size,
                                     thd->variables.max_heap_table_size) :
                                 thd->variables.tmp_memory_table_size) /
                                share->reclength);
  set_if_bigger(share->max_rows,1);		// For dummy start options
  /*
    Push the LIMIT clause to the temporary table creation, so that we
    materialize only up to 'rows_limit' records instead of all result records.
  */
  set_if_smaller(share->max_rows, rows_limit);
  param->end_write_records= rows_limit;

  keyinfo= param->keyinfo;

  if (group)
  {
    DBUG_PRINT("info",("Creating group key in temporary table"));
    table->group=group;				/* Table is grouped by key */
    param->group_buff=group_buff;
    share->keys=1;
    share->uniques= MY_TEST(using_unique_constraint);
    table->key_info= table->s->key_info= keyinfo;
    table->keys_in_use_for_query.set_bit(0);
    share->keys_in_use.set_bit(0);
    keyinfo->key_part=key_part_info;
    keyinfo->flags=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
    keyinfo->ext_key_flags= keyinfo->flags;
    keyinfo->usable_key_parts=keyinfo->user_defined_key_parts= param->group_parts;
    keyinfo->ext_key_parts= keyinfo->user_defined_key_parts;
    keyinfo->key_length=0;
    keyinfo->rec_per_key=NULL;
    keyinfo->read_stats= NULL;
    keyinfo->collected_stats= NULL;
    keyinfo->algorithm= HA_KEY_ALG_UNDEF;
    keyinfo->is_statistics_from_stat_tables= FALSE;
    keyinfo->name= group_key;
    ORDER *cur_group= group;
    for (; cur_group ; cur_group= cur_group->next, key_part_info++)
    {
      Field *field=(*cur_group->item)->get_tmp_table_field();
      DBUG_ASSERT(field->table == table);
      bool maybe_null=(*cur_group->item)->maybe_null;
      key_part_info->null_bit=0;
      key_part_info->field=  field;
      key_part_info->fieldnr= field->field_index + 1;
      if (cur_group == group)
        field->key_start.set_bit(0);
      key_part_info->offset= field->offset(table->record[0]);
      key_part_info->length= (uint16) field->key_length();
      key_part_info->type=   (uint8) field->key_type();
      key_part_info->key_type =
	((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
	 (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
	 (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
	0 : FIELDFLAG_BINARY;
      key_part_info->key_part_flag= 0;
      if (!using_unique_constraint)
      {
	cur_group->buff=(char*) group_buff;

        if (maybe_null && !field->null_bit)
        {
          /*
            This can only happen in the unusual case where an outer join
            table was found to be not-nullable by the optimizer and we
            the item can't really be null.
            We solve this by marking the item as !maybe_null to ensure
            that the key,field and item definition match.
          */
          (*cur_group->item)->maybe_null= maybe_null= 0;
        }

	if (!(cur_group->field= field->new_key_field(thd->mem_root,table,
                                                     group_buff +
                                                     MY_TEST(maybe_null),
                                                     key_part_info->length,
                                                     field->null_ptr,
                                                     field->null_bit)))
	  goto err; /* purecov: inspected */

	if (maybe_null)
	{
	  /*
	    To be able to group on NULL, we reserved place in group_buff
	    for the NULL flag just before the column. (see above).
	    The field data is after this flag.
	    The NULL flag is updated in 'end_update()' and 'end_write()'
	  */
	  keyinfo->flags|= HA_NULL_ARE_EQUAL;	// def. that NULL == NULL
	  key_part_info->null_bit=field->null_bit;
	  key_part_info->null_offset= (uint) (field->null_ptr -
					      (uchar*) table->record[0]);
          cur_group->buff++;                        // Pointer to field data
	  group_buff++;                         // Skipp null flag
	}
	group_buff+= cur_group->field->pack_length();
      }
      keyinfo->key_length+=  key_part_info->length;
    }
    /*
      Ensure we didn't overrun the group buffer. The < is only true when
      some maybe_null fields was changed to be not null fields.
    */
    DBUG_ASSERT(using_unique_constraint ||
                group_buff <= param->group_buff + param->group_length);
  }

  if (distinct && field_count != param->hidden_field_count)
  {
    /*
      Create an unique key or an unique constraint over all columns
      that should be in the result.  In the temporary table, there are
      'param->hidden_field_count' extra columns, whose null bits are stored
      in the first 'hidden_null_pack_length' bytes of the row.
    */
    DBUG_PRINT("info",("hidden_field_count: %d", param->hidden_field_count));

    if (blob_count)
    {
      /*
        Special mode for index creation in MyISAM used to support unique
        indexes on blobs with arbitrary length. Such indexes cannot be
        used for lookups.
      */
      share->uniques= 1;
    }
    null_pack_length-=hidden_null_pack_length;
    keyinfo->user_defined_key_parts=
      ((field_count-param->hidden_field_count)+
       (share->uniques ? MY_TEST(null_pack_length) : 0));
    keyinfo->ext_key_parts= keyinfo->user_defined_key_parts;
    keyinfo->usable_key_parts= keyinfo->user_defined_key_parts;
    table->distinct= 1;
    share->keys= 1;
    if (!(key_part_info= (KEY_PART_INFO*)
          alloc_root(&table->mem_root,
                     keyinfo->user_defined_key_parts * sizeof(KEY_PART_INFO))))
      goto err;
    bzero((void*) key_part_info, keyinfo->user_defined_key_parts * sizeof(KEY_PART_INFO));
    table->keys_in_use_for_query.set_bit(0);
    share->keys_in_use.set_bit(0);
    table->key_info= table->s->key_info= keyinfo;
    keyinfo->key_part=key_part_info;
    keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL | HA_BINARY_PACK_KEY | HA_PACK_KEY;
    keyinfo->ext_key_flags= keyinfo->flags;
    keyinfo->key_length= 0;  // Will compute the sum of the parts below.
    keyinfo->name= distinct_key;
    keyinfo->algorithm= HA_KEY_ALG_UNDEF;
    keyinfo->is_statistics_from_stat_tables= FALSE;
    keyinfo->read_stats= NULL;
    keyinfo->collected_stats= NULL;

    /*
      Needed by non-merged semi-joins: SJ-Materialized table must have a valid 
      rec_per_key array, because it participates in join optimization. Since
      the table has no data, the only statistics we can provide is "unknown",
      i.e. zero values.

      (For table record count, we calculate and set JOIN_TAB::found_records,
       see get_delayed_table_estimates()).
    */
    size_t rpk_size= keyinfo->user_defined_key_parts * sizeof(keyinfo->rec_per_key[0]);
    if (!(keyinfo->rec_per_key= (ulong*) alloc_root(&table->mem_root, 
                                                    rpk_size)))
      goto err;
    bzero(keyinfo->rec_per_key, rpk_size);

    /*
      Create an extra field to hold NULL bits so that unique indexes on
      blobs can distinguish NULL from 0. This extra field is not needed
      when we do not use UNIQUE indexes for blobs.
    */
    if (null_pack_length && share->uniques)
    {
      key_part_info->null_bit=0;
      key_part_info->offset=hidden_null_pack_length;
      key_part_info->length=null_pack_length;
      key_part_info->field= new Field_string(table->record[0],
                                             (uint32) key_part_info->length,
                                             (uchar*) 0,
                                             (uint) 0,
                                             Field::NONE,
                                             &null_clex_str, &my_charset_bin);
      if (!key_part_info->field)
        goto err;
      key_part_info->field->init(table);
      key_part_info->key_type=FIELDFLAG_BINARY;
      key_part_info->type=    HA_KEYTYPE_BINARY;
      key_part_info->fieldnr= key_part_info->field->field_index + 1;
      key_part_info++;
    }
    /* Create a distinct key over the columns we are going to return */
    for (i=param->hidden_field_count, reg_field=table->field + i ;
	 i < field_count;
	 i++, reg_field++, key_part_info++)
    {
      key_part_info->field=    *reg_field;
      (*reg_field)->flags |= PART_KEY_FLAG;
      if (key_part_info == keyinfo->key_part)
        (*reg_field)->key_start.set_bit(0);
      key_part_info->null_bit= (*reg_field)->null_bit;
      key_part_info->null_offset= (uint) ((*reg_field)->null_ptr -
                                          (uchar*) table->record[0]);

      key_part_info->offset=   (*reg_field)->offset(table->record[0]);
      key_part_info->length=   (uint16) (*reg_field)->pack_length();
      key_part_info->fieldnr= (*reg_field)->field_index + 1;
      /* TODO:
        The below method of computing the key format length of the
        key part is a copy/paste from opt_range.cc, and table.cc.
        This should be factored out, e.g. as a method of Field.
        In addition it is not clear if any of the Field::*_length
        methods is supposed to compute the same length. If so, it
        might be reused.
      */
      key_part_info->store_length= key_part_info->length;

      if ((*reg_field)->real_maybe_null())
      {
        key_part_info->store_length+= HA_KEY_NULL_LENGTH;
        key_part_info->key_part_flag |= HA_NULL_PART;
      }
      if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
          (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR ||
          (*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
      {
        if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
            (*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
          key_part_info->key_part_flag|= HA_BLOB_PART;
        else
          key_part_info->key_part_flag|= HA_VAR_LENGTH_PART;

        key_part_info->store_length+=HA_KEY_BLOB_LENGTH;
      }

      keyinfo->key_length+= key_part_info->store_length;

      key_part_info->type=     (uint8) (*reg_field)->key_type();
      key_part_info->key_type =
	((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
	 (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
	 (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
	0 : FIELDFLAG_BINARY;
    }
  }

  if (unlikely(thd->is_fatal_error))             // If end of memory
    goto err;					 /* purecov: inspected */
  share->db_record_offset= 1;
  table->used_for_duplicate_elimination= (param->sum_func_count == 0 &&
                                          (table->group || table->distinct));
  table->keep_row_order= keep_row_order;

  if (!do_not_open)
  {
    if (instantiate_tmp_table(table, param->keyinfo, param->start_recinfo,
                              &param->recinfo, select_options))
      goto err;
  }

  /* record[0] and share->default_values should now have been set up */
  MEM_CHECK_DEFINED(table->record[0], table->s->reclength);
  MEM_CHECK_DEFINED(share->default_values, table->s->reclength);

  empty_record(table);
  table->status= STATUS_NO_RECORD;
  thd->mem_root= mem_root_save;

  DBUG_RETURN(table);

err:
  thd->mem_root= mem_root_save;
  free_tmp_table(thd,table);                    /* purecov: inspected */
  if (temp_pool_slot != MY_BIT_NONE)
    bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
  DBUG_RETURN(NULL);				/* purecov: inspected */
}

Project: server

JOIN::prepare(TABLE_LIST *tables_init,
	      uint wild_num, COND *conds_init, uint og_num,
	      ORDER *order_init, bool skip_order_by,
              ORDER *group_init, Item *having_init,
	      ORDER *proc_param_init, SELECT_LEX *select_lex_arg,
	      SELECT_LEX_UNIT *unit_arg)
{
  DBUG_ENTER("JOIN::prepare");

  // to prevent double initialization on EXPLAIN
  if (optimization_state != JOIN::NOT_OPTIMIZED)
    DBUG_RETURN(0);

  conds= conds_init;
  order= order_init;
  group_list= group_init;
  having= having_init;
  proc_param= proc_param_init;
  tables_list= tables_init;
  select_lex= select_lex_arg;
  DBUG_PRINT("info", ("select %p (%u) = JOIN %p",
                      select_lex, select_lex->select_number, this));
  select_lex->join= this;
  join_list= &select_lex->top_join_list;
  union_part= unit_arg->is_unit_op();

  Json_writer_object trace_wrapper(thd);
  Json_writer_object trace_prepare(thd, "join_preparation");
  trace_prepare.add_select_number(select_lex->select_number);
  Json_writer_array trace_steps(thd, "steps");

  // simple check that we got usable conds
  dbug_print_item(conds);

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

  thd->lex->current_select->context_analysis_place= NO_MATTER;
  thd->lex->current_select->is_item_list_lookup= 1;
  /*
    If we have already executed SELECT, then it have not sense to prevent
    its table from update (see unique_table())
    Affects only materialized derived tables.
  */
  /* Check that all tables, fields, conds and order are ok */
  if (!(select_options & OPTION_SETUP_TABLES_DONE) &&
      setup_tables_and_check_access(thd, &select_lex->context, join_list,
                                    tables_list, select_lex->leaf_tables,
                                    FALSE, SELECT_ACL, SELECT_ACL, FALSE))
      DBUG_RETURN(-1);

  /* System Versioning: handle FOR SYSTEM_TIME clause. */
  if (select_lex->vers_setup_conds(thd, tables_list) < 0)
    DBUG_RETURN(-1);

  /*
    TRUE if the SELECT list mixes elements with and without grouping,
    and there is no GROUP BY clause. Mixing non-aggregated fields with
    aggregate functions in the SELECT list is a MySQL extenstion that
    is allowed only if the ONLY_FULL_GROUP_BY sql mode is not set.
  */
  mixed_implicit_grouping= false;
  if ((~thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) &&
      select_lex->with_sum_func && !group_list)
  {
    List_iterator_fast <Item> select_it(fields_list);
    Item *select_el; /* Element of the SELECT clause, can be an expression. */
    bool found_field_elem= false;
    bool found_sum_func_elem= false;

    while ((select_el= select_it++))
    {
      if (select_el->with_sum_func())
        found_sum_func_elem= true;
      if (select_el->with_field)
        found_field_elem= true;
      if (found_sum_func_elem && found_field_elem)
      {
        mixed_implicit_grouping= true;
        break;
      }
    }
  }

  table_count= select_lex->leaf_tables.elements;

  TABLE_LIST *tbl;
  List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
  while ((tbl= li++))
  {
    /*
      If the query uses implicit grouping where the select list contains both
      aggregate functions and non-aggregate fields, any non-aggregated field
      may produce a NULL value. Set all fields of each table as nullable before
      semantic analysis to take into account this change of nullability.

      Note: this loop doesn't touch tables inside merged semi-joins, because
      subquery-to-semijoin conversion has not been done yet. This is intended.
    */
    if (mixed_implicit_grouping && tbl->table)
      tbl->table->maybe_null= 1;
  }
 
  uint real_og_num= og_num;
  if (skip_order_by && 
      select_lex != select_lex->master_unit()->global_parameters())
    real_og_num+= select_lex->order_list.elements;

  DBUG_ASSERT(select_lex->hidden_bit_fields == 0);
  if (setup_wild(thd, tables_list, fields_list, &all_fields, wild_num,
                 &select_lex->hidden_bit_fields))
    DBUG_RETURN(-1);
  if (select_lex->setup_ref_array(thd, real_og_num))
    DBUG_RETURN(-1);

  ref_ptrs= ref_ptr_array_slice(0);
  
  enum_parsing_place save_place=
                     thd->lex->current_select->context_analysis_place;
  thd->lex->current_select->context_analysis_place= SELECT_LIST;
  if (setup_fields(thd, ref_ptrs, fields_list, MARK_COLUMNS_READ,
                   &all_fields, &select_lex->pre_fix, 1))
    DBUG_RETURN(-1);
  thd->lex->current_select->context_analysis_place= save_place;

  if (setup_without_group(thd, ref_ptrs, tables_list,
                          select_lex->leaf_tables, fields_list,
                          all_fields, &conds, order, group_list,
                          select_lex->window_specs,
                          select_lex->window_funcs,
                          &hidden_group_fields,
                          &select_lex->select_n_reserved))
    DBUG_RETURN(-1);

  /*
    Permanently remove redundant parts from the query if
      1) This is a subquery
      2) This is the first time this query is optimized (since the
         transformation is permanent
      3) Not normalizing a view. Removal should take place when a
         query involving a view is optimized, not when the view
         is created
  */
  if (select_lex->master_unit()->item &&                               // 1)
      select_lex->first_cond_optimization &&                           // 2)
      !thd->lex->is_view_context_analysis())                           // 3)
  {
    remove_redundant_subquery_clauses(select_lex);
  }

  /* Resolve the ORDER BY that was skipped, then remove it. */
  if (skip_order_by && select_lex !=
                       select_lex->master_unit()->global_parameters())
  {
    nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
    thd->lex->allow_sum_func.set_bit(select_lex->nest_level);
    thd->where= "order clause";
    for (ORDER *order= select_lex->order_list.first; order; order= order->next)
    {
      /* Don't add the order items to all fields. Just resolve them to ensure
         the query is valid, we'll drop them immediately after. */
      if (find_order_in_list(thd, ref_ptrs, tables_list, order,
                             fields_list, all_fields, false, false, false))
        DBUG_RETURN(-1);
    }
    thd->lex->allow_sum_func= save_allow_sum_func;
    select_lex->order_list.empty();
  }

  if (having)
  {
    nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
    thd->where="having clause";
    thd->lex->allow_sum_func.set_bit(select_lex_arg->nest_level);
    select_lex->having_fix_field= 1;
    /*
      Wrap alone field in HAVING clause in case it will be outer field
      of subquery which need persistent pointer on it, but having
      could be changed by optimizer
    */
    if (having->type() == Item::REF_ITEM &&
        ((Item_ref *)having)->ref_type() == Item_ref::REF)
      wrap_ident(thd, &having);
    bool having_fix_rc= having->fix_fields_if_needed_for_bool(thd, &having);
    select_lex->having_fix_field= 0;

    if (unlikely(having_fix_rc || thd->is_error()))
      DBUG_RETURN(-1);				/* purecov: inspected */
    thd->lex->allow_sum_func= save_allow_sum_func;

    if (having->with_window_func)
    {
      my_error(ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION, MYF(0));
      DBUG_RETURN(-1); 
    }
  }

  /*
     After setting up window functions, we may have discovered additional
     used tables from the PARTITION BY and ORDER BY list. Update all items
     that contain window functions.
  */
  if (select_lex->have_window_funcs())
  {
    List_iterator_fast<Item> it(select_lex->item_list);
    Item *item;
    while ((item= it++))
    {
      if (item->with_window_func)
        item->update_used_tables();
    }
  }

  With_clause *with_clause=select_lex->get_with_clause();
  if (with_clause && with_clause->prepare_unreferenced_elements(thd))
    DBUG_RETURN(1);

  With_element *with_elem= select_lex->get_with_element();
  if (with_elem &&
      select_lex->check_unrestricted_recursive(
                      thd->variables.only_standard_compliant_cte))
    DBUG_RETURN(-1);
  if (!(select_lex->changed_elements & TOUCHED_SEL_COND))
    select_lex->check_subqueries_with_recursive_references();
  
  int res= check_and_do_in_subquery_rewrites(this);

  select_lex->fix_prepare_information(thd, &conds, &having);
  
  if (res)
    DBUG_RETURN(res);

  if (order)
  {
    bool real_order= FALSE;
    ORDER *ord;
    for (ord= order; ord; ord= ord->next)
    {
      Item *item= *ord->item;
      /*
        Disregard sort order if there's only 
        zero length NOT NULL fields (e.g. {VAR}CHAR(0) NOT NULL") or
        zero length NOT NULL string functions there.
        Such tuples don't contain any data to sort.
      */
      if (!real_order &&
           /* Not a zero length NOT NULL field */
          ((item->type() != Item::FIELD_ITEM ||
            ((Item_field *) item)->field->maybe_null() ||
            ((Item_field *) item)->field->sort_length()) &&
           /* AND not a zero length NOT NULL string function. */
           (item->type() != Item::FUNC_ITEM ||
            item->maybe_null ||
            item->result_type() != STRING_RESULT ||
            item->max_length)))
        real_order= TRUE;

      if ((item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM) ||
          item->with_window_func)
        item->split_sum_func(thd, ref_ptrs, all_fields, SPLIT_SUM_SELECT);
    }
    if (!real_order)
      order= NULL;
  }

  if (having && having->with_sum_func())
    having->split_sum_func2(thd, ref_ptrs, all_fields,
                            &having, SPLIT_SUM_SKIP_REGISTERED);
  if (select_lex->inner_sum_func_list)
  {
    Item_sum *end=select_lex->inner_sum_func_list;
    Item_sum *item_sum= end;  
    do
    { 
      item_sum= item_sum->next;
      item_sum->split_sum_func2(thd, ref_ptrs,
                                all_fields, item_sum->ref_by, 0);
    } while (item_sum != end);
  }

  if (select_lex->inner_refs_list.elements &&
      fix_inner_refs(thd, all_fields, select_lex, ref_ptrs))
    DBUG_RETURN(-1);

  if (group_list)
  {
    /*
      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 to a client.
    */
    for (ORDER *ord= group_list; ord; ord= ord->next)
    {
      if ((*ord->item)->type() == Item::FIELD_ITEM &&
          (*ord->item)->field_type() == MYSQL_TYPE_BIT)
      {
        Item_field *field= new (thd->mem_root) Item_field(thd, *(Item_field**)ord->item);
        if (!field)
          DBUG_RETURN(-1);
        int el= all_fields.elements;
        ref_ptrs[el]= field;
        all_fields.push_front(field, thd->mem_root);
        ord->item= &ref_ptrs[el];
      }
    }
  }

  /*
    Check if there are references to un-aggregated columns when computing 
    aggregate functions with implicit grouping (there is no GROUP BY).
  */
  if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !group_list &&
      !(select_lex->master_unit()->item &&
        select_lex->master_unit()->item->is_in_predicate() &&
        ((Item_in_subselect*)select_lex->master_unit()->item)->
        test_set_strategy(SUBS_MAXMIN_INJECTED)) &&
      select_lex->non_agg_field_used() &&
      select_lex->agg_func_used())
  {
    my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS,
               ER_THD(thd, ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0));
    DBUG_RETURN(-1);
  }
  {
    /* Caclulate the number of groups */
    send_group_parts= 0;
    for (ORDER *group_tmp= group_list ; group_tmp ; group_tmp= group_tmp->next)
      send_group_parts++;
  }
  
  procedure= setup_procedure(thd, proc_param, result, fields_list, &error);
  if (unlikely(error))
    goto err;					/* purecov: inspected */
  if (procedure)
  {
    if (setup_new_fields(thd, fields_list, all_fields,
			 procedure->param_fields))
	goto err;				/* purecov: inspected */
    if (procedure->group)
    {
      if (!test_if_subpart(procedure->group,group_list))
      {						/* purecov: inspected */
	my_message(ER_DIFF_GROUPS_PROC, ER_THD(thd, ER_DIFF_GROUPS_PROC),
                   MYF(0));                     /* purecov: inspected */
	goto err;				/* purecov: inspected */
      }
    }
    if (order && (procedure->flags & PROC_NO_SORT))
    {						/* purecov: inspected */
      my_message(ER_ORDER_WITH_PROC, ER_THD(thd, ER_ORDER_WITH_PROC),
                 MYF(0));                       /* purecov: inspected */
      goto err;					/* purecov: inspected */
    }
    if (thd->lex->derived_tables)
    {
      /*
        Queries with derived tables and PROCEDURE are not allowed.
        Many of such queries are disallowed grammatically, but there
        are still some complex cases:
          SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE()
      */
      my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", 
               thd->lex->derived_tables & DERIVED_VIEW ?
               "view" : "subquery"); 
      goto err;
    }
    if (thd->lex->sql_command != SQLCOM_SELECT)
    {
      // EXPLAIN SELECT * FROM t1 PROCEDURE ANALYSE()
      my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "non-SELECT");
      goto err;
    }
  }

  if (thd->trace_started())
  {
    Json_writer_object trace_wrapper(thd);
    opt_trace_print_expanded_query(thd, select_lex, &trace_wrapper);
  }

  if (!procedure && result && result->prepare(fields_list, unit_arg))
    goto err;					/* purecov: inspected */

  unit= unit_arg;
  if (prepare_stage2())
    goto err;

  DBUG_RETURN(0); // All OK

err:
  delete procedure;                /* purecov: inspected */
  procedure= 0;
  DBUG_RETURN(-1);                /* purecov: inspected */
}

Project: server

Field *Item_func_sp::create_tmp_field_ex(TABLE *table,
                                         Tmp_field_src *src,
                                         const Tmp_field_param *param)
{
  Field *result;
  get_tmp_field_src(src, param);
  if ((result= sp_result_field->create_tmp_field(table->in_use->mem_root,
                                                 table)))
  {
    result->field_name= name;
    if (param->modify_item())
      result_field= result;
  }
  return result;
}

Project: server

JOIN_TAB::sort_table()
{
  int rc;
  DBUG_PRINT("info",("Sorting for index"));
  THD_STAGE_INFO(join->thd, stage_creating_sort_index);
  DBUG_ASSERT(join->ordered_index_usage != (filesort->order == join->order ?
                                            JOIN::ordered_index_order_by :
                                            JOIN::ordered_index_group_by));
  rc= create_sort_index(join->thd, join, this, NULL);
  /* Disactivate rowid filter if it was used when creating sort index */
  if (rowid_filter)
    table->file->rowid_filter_is_active= false;
  return (rc != 0);
}

Project: server

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();
  bool is_pushed_union= unit->derived && unit->derived->pushdown_derived;

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

  if (unit->is_unit_op() || 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= unit_operation_text[unit->common_op()];
      unit->fake_select_lex->options|= SELECT_DESCRIBE;
    }
    if (!(res= unit->prepare(unit->derived, result,
                             SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
    {
      if (!is_pushed_union)
        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);
  }

  if (unit->derived && unit->derived->pushdown_derived)
  {
    delete unit->derived->pushdown_derived;
    unit->derived->pushdown_derived= NULL;
  }

  DBUG_RETURN(res || thd->is_error());
}

Project: server

setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
	    List<Item> &fields, List<Item> &all_fields, ORDER *order,
	    bool *hidden_group_fields, bool from_window_spec)
{
  enum_parsing_place context_analysis_place=
                     thd->lex->current_select->context_analysis_place;
  *hidden_group_fields=0;
  ORDER *ord;

  if (!order)
    return 0;				/* Everything is ok */

  uint org_fields=all_fields.elements;

  thd->where="group statement";
  for (ord= order; ord; ord= ord->next)
  {
    if (find_order_in_list(thd, ref_pointer_array, tables, ord, fields,
                           all_fields, true, true, from_window_spec))
      return 1;
    (*ord->item)->marker= UNDEF_POS;		/* Mark found */
    if ((*ord->item)->with_sum_func() && context_analysis_place == IN_GROUP_BY)
    {
      my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*ord->item)->full_name());
      return 1;
    }
    if ((*ord->item)->with_window_func)
    {
      if (context_analysis_place == IN_GROUP_BY)
        my_error(ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION, MYF(0));
      else
        my_error(ER_WINDOW_FUNCTION_IN_WINDOW_SPEC, MYF(0));
      return 1;
    }
    if (from_window_spec && (*ord->item)->with_sum_func() &&
        (*ord->item)->type() != Item::SUM_FUNC_ITEM)
      (*ord->item)->split_sum_func(thd, ref_pointer_array,
                                   all_fields, SPLIT_SUM_SELECT);
  }
  if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
      context_analysis_place == IN_GROUP_BY)
  {
    /*
      Don't allow one to use fields that is not used in GROUP BY
      For each select a list of field references that aren't under an
      aggregate function is created. Each field in this list keeps the
      position of the select list expression which it belongs to.

      First we check an expression from the select list against the GROUP BY
      list. If it's found there then it's ok. It's also ok if this expression
      is a constant or an aggregate function. Otherwise we scan the list
      of non-aggregated fields and if we'll find at least one field reference
      that belongs to this expression and doesn't occur in the GROUP BY list
      we throw an error. If there are no fields in the created list for a
      select list expression this means that all fields in it are used under
      aggregate functions.
    */
    Item *item;
    Item_field *field;
    int cur_pos_in_select_list= 0;
    List_iterator<Item> li(fields);
    List_iterator<Item_field> naf_it(thd->lex->current_select->join->non_agg_fields);

    field= naf_it++;
    while (field && (item=li++))
    {
      if (item->type() != Item::SUM_FUNC_ITEM && item->marker >= 0 &&
          !item->const_item() &&
          !(item->real_item()->type() == Item::FIELD_ITEM &&
            item->used_tables() & OUTER_REF_TABLE_BIT))
      {
        while (field)
        {
          /* Skip fields from previous expressions. */
          if (field->marker < cur_pos_in_select_list)
            goto next_field;
          /* Found a field from the next expression. */
          if (field->marker > cur_pos_in_select_list)
            break;
          /*
            Check whether the field occur in the GROUP BY list.
            Throw the error later if the field isn't found.
          */
          for (ord= order; ord; ord= ord->next)
            if ((*ord->item)->eq((Item*)field, 0))
              goto next_field;
          /*
            TODO: change ER_WRONG_FIELD_WITH_GROUP to more detailed
            ER_NON_GROUPING_FIELD_USED
          */
          my_error(ER_WRONG_FIELD_WITH_GROUP, MYF(0), field->full_name());
          return 1;
next_field:
          field= naf_it++;
        }
      }
      cur_pos_in_select_list++;
    }
  }
  if (org_fields != all_fields.elements)
    *hidden_group_fields=1;			// group fields is not used
  return 0;
}

Project: server

static COND* substitute_for_best_equal_field(THD *thd, JOIN_TAB *context_tab,
                                             COND *cond,
                                             COND_EQUAL *cond_equal,
                                             void *table_join_idx,
                                             bool do_substitution)
{
  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,
                                                      do_substitution);
      /*
        This works OK with PS/SP re-execution as changes are made to
        the arguments of AND/OR items only
      */
      if (new_item && 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;
      bool all_deleted= true;
      while ((item_equal= it++))
      {
        if (item_equal->get_extraction_flag() == DELETION_FL)
          continue;
        all_deleted= false;
        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->is_bool_literal() && !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->is_bool_literal() &&
                 cond_list->push_front(eq_cond, thd->mem_root))
               eq_cond= 0;
          }
	}
      }
      if (!eq_cond && !all_deleted)
      {
        /* 
          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;
    if (item_equal->get_extraction_flag() == DELETION_FL)
      return 0;
    cond= eliminate_item_equal(thd, 0, cond_equal, item_equal);
    return cond ? cond : org_cond;
  }
  else if (do_substitution)
  {
    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};
        if (!(cond= cond->transform(thd, &Item::replace_equal_field,
                                    (uchar *) &arg)))
          return 0;
      }
      cond_equal= cond_equal->upper_levels;
    }
  }
  return cond;
}

Project: server

choose_plan(JOIN *join, table_map join_tables)
{
  uint search_depth= join->thd->variables.optimizer_search_depth;
  uint prune_level=  join->thd->variables.optimizer_prune_level;
  uint use_cond_selectivity= 
         join->thd->variables.optimizer_use_condition_selectivity;
  bool straight_join= MY_TEST(join->select_options & SELECT_STRAIGHT_JOIN);
  THD *thd= join->thd;
  DBUG_ENTER("choose_plan");

  join->cur_embedding_map= 0;
  reset_nj_counters(join, join->join_list);
  qsort2_cmp jtab_sort_func;

  if (join->emb_sjm_nest)
  {
    /* We're optimizing semi-join materialization nest, so put the 
       tables from this semi-join as first
    */
    jtab_sort_func= join_tab_cmp_embedded_first;
  }
  else
  {
    /*
      if (SELECT_STRAIGHT_JOIN option is set)
        reorder tables so dependent tables come after tables they depend 
        on, otherwise keep tables in the order they were specified in the query 
      else
        Apply heuristic: pre-sort all access plans with respect to the number of
        records accessed.
    */
    jtab_sort_func= straight_join ? join_tab_cmp_straight : join_tab_cmp;
  }

  /*
    psergey-todo: if we're not optimizing an SJM nest, 
     - sort that outer tables are first, and each sjm nest follows
     - then, put each [sjm_table1, ... sjm_tableN] sub-array right where 
       WHERE clause pushdown would have put it.
  */
  my_qsort2(join->best_ref + join->const_tables,
            join->table_count - join->const_tables, sizeof(JOIN_TAB*),
            jtab_sort_func, (void*)join->emb_sjm_nest);

  Json_writer_object wrapper(thd);
  Json_writer_array trace_plan(thd,"considered_execution_plans");

  if (!join->emb_sjm_nest)
  {
    choose_initial_table_order(join);
  }
  join->cur_sj_inner_tables= 0;

  if (straight_join)
  {
    optimize_straight_join(join, join_tables);
  }
  else
  {
    DBUG_ASSERT(search_depth <= MAX_TABLES + 1);
    if (search_depth == 0)
      /* Automatically determine a reasonable value for 'search_depth' */
      search_depth= determine_search_depth(join);
    if (greedy_search(join, join_tables, search_depth, prune_level,
                      use_cond_selectivity))
      DBUG_RETURN(TRUE);
  }

  /* 
    Store the cost of this query into a user variable
    Don't update last_query_cost for statements that are not "flat joins" :
    i.e. they have subqueries, unions or call stored procedures.
    TODO: calculate a correct cost for a query with subqueries and UNIONs.
  */
  if (join->thd->lex->is_single_level_stmt())
    join->thd->status_var.last_query_cost= join->best_read;
  DBUG_RETURN(FALSE);
}

Project: server

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_func*) 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();
  }          
}

Project: server

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

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

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

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

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

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

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

      if (ordered_index_usage != ordered_index_order_by &&
          !only_const_tables() &&
          add_sorting_to_table(join_tab + const_tables, order))
        goto err;
      order= NULL;
    }
  }
  if (!(tab->aggr= new (thd->mem_root) AGGR_OP(tab)))
    goto err;
  table->reginfo.join_tab= tab;
  DBUG_RETURN(false);

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

Project: server

void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
{
  DBUG_ASSERT(thd);

  if (tvc)
  {
    tvc->print(thd, str, query_type);
    return;
  }

  if ((query_type & QT_SHOW_SELECT_NUMBER) &&
      thd->lex->all_selects_list &&
      thd->lex->all_selects_list->link_next &&
      select_number != UINT_MAX &&
      select_number != INT_MAX)
  {
    str->append("/* select#");
    str->append_ulonglong(select_number);
    if (thd->lex->describe & DESCRIBE_EXTENDED2)
    {
      str->append("/");
      str->append_ulonglong(nest_level);

      if (master_unit()->fake_select_lex &&
          master_unit()->first_select() == this)
      {
        str->append(" Filter Select: ");
        master_unit()->fake_select_lex->print(thd, str, query_type);
      }
    }
    str->append(" */ ");
  }

  str->append(STRING_WITH_LEN("select "));

  if (join && join->cleaned)
  {
    /*
      JOIN already cleaned up so it is dangerous to print items
      because temporary tables they pointed on could be freed.
    */
    str->append('#');
    str->append(select_number);
    return;
  }

  /* First add options */
  if (options & SELECT_STRAIGHT_JOIN)
    str->append(STRING_WITH_LEN("straight_join "));
  if (options & SELECT_HIGH_PRIORITY)
    str->append(STRING_WITH_LEN("high_priority "));
  if (options & SELECT_DISTINCT)
    str->append(STRING_WITH_LEN("distinct "));
  if (options & SELECT_SMALL_RESULT)
    str->append(STRING_WITH_LEN("sql_small_result "));
  if (options & SELECT_BIG_RESULT)
    str->append(STRING_WITH_LEN("sql_big_result "));
  if (options & OPTION_BUFFER_RESULT)
    str->append(STRING_WITH_LEN("sql_buffer_result "));
  if (options & OPTION_FOUND_ROWS)
    str->append(STRING_WITH_LEN("sql_calc_found_rows "));
  if (this == parent_lex->first_select_lex())
  {
    switch (parent_lex->sql_cache)
    {
      case LEX::SQL_NO_CACHE:
        str->append(STRING_WITH_LEN("sql_no_cache "));
        break;
      case LEX::SQL_CACHE:
        str->append(STRING_WITH_LEN("sql_cache "));
        break;
      case LEX::SQL_CACHE_UNSPECIFIED:
        break;
      default:
        DBUG_ASSERT(0);
    }
  }

  //Item List
  bool first= 1;
  /*
    outer_select() can not be used here because it is for name resolution
    and will return NULL at any end of name resolution chain (view/derived)
  */
  bool top_level= (get_master()->get_master() == 0);
  List_iterator_fast<Item> it(item_list);
  Item *item;
  while ((item= it++))
  {
    if (first)
      first= 0;
    else
      str->append(',');

    if ((is_subquery_function() && item->is_autogenerated_name) ||
        !item->name.str)
    {
      /*
        Do not print auto-generated aliases in subqueries. It has no purpose
        in a view definition or other contexts where the query is printed.
      */
      item->print(str, query_type);
    }
    else
    {
      /*
        Do not print illegal names (if it is not top level SELECT).
        Top level view checked (and correct name are assigned),
        other cases of top level SELECT are not important, because
        it is not "table field".
      */
      if (top_level ||
          !item->is_autogenerated_name ||
          !check_column_name(item->name.str))
        item->print_item_w_name(str, query_type);
      else
        item->print(str, query_type);
    }
  }

  /*
    from clause
    TODO: support USING/FORCE/IGNORE index
  */
  if (table_list.elements)
  {
    str->append(STRING_WITH_LEN(" from "));
    /* go through join tree */
    print_join(thd, join? join->eliminated_tables: 0, str, &top_join_list, query_type);
  }
  else if (where)
  {
    /*
      "SELECT 1 FROM DUAL WHERE 2" should not be printed as 
      "SELECT 1 WHERE 2": the 1st syntax is valid, but the 2nd is not.
    */
    str->append(STRING_WITH_LEN(" from DUAL "));
  }

  // Where
  Item *cur_where= where;
  if (join)
    cur_where= join->conds;
  if (cur_where || cond_value != Item::COND_UNDEF)
  {
    str->append(STRING_WITH_LEN(" where "));
    if (cur_where)
      cur_where->print(str, query_type);
    else
      str->append(cond_value != Item::COND_FALSE ? "1" : "0");
  }

  // group by & olap
  if (group_list.elements)
  {
    str->append(STRING_WITH_LEN(" group by "));
    print_order(str, group_list.first, query_type);
    switch (olap)
    {
      case CUBE_TYPE:
	str->append(STRING_WITH_LEN(" with cube"));
	break;
      case ROLLUP_TYPE:
	str->append(STRING_WITH_LEN(" with rollup"));
	break;
      default:
	;  //satisfy compiler
    }
  }

  // having
  Item *cur_having= having;
  if (join)
    cur_having= join->having;

  if (cur_having || having_value != Item::COND_UNDEF)
  {
    str->append(STRING_WITH_LEN(" having "));
    if (cur_having)
      cur_having->print(str, query_type);
    else
      str->append(having_value != Item::COND_FALSE ? "1" : "0");
  }

  if (order_list.elements)
  {
    str->append(STRING_WITH_LEN(" order by "));
    print_order(str, order_list.first, query_type);
  }

  // limit
  print_limit(thd, str, query_type);

  // lock type
  if (lock_type == TL_READ_WITH_SHARED_LOCKS)
    str->append(" lock in share mode");
  else if (lock_type == TL_WRITE)
    str->append(" for update");

  // PROCEDURE unsupported here
}

Project: server

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

  tab->build_range_rowid_filter_if_needed();

  if (tab->filesort && tab->sort_table())     // Sort table.
    return 1;

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


  if (init_read_record(&tab->read_record, tab->join->thd, tab->table,
                       tab->select, tab->filesort_result, 1,1, FALSE))
    return 1;
  return tab->read_record.read_record();
}

Project: server

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

  table_count=join->table_count;

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

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

  /* The following should be optimized to only clear critical things */
  bzero((void*)stat, sizeof(JOIN_TAB)* table_count);

  /* Initialize POSITION objects */
  for (i=0 ; i <= table_count ; i++)
    (void) new ((char*) (join->positions + i)) POSITION;

  join->best_ref= stat_vector;

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

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

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

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

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

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

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

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

       The classic form of the Warshall's algorithm would look like: 
       for (i= 0; i < table_count; i++)
       {
         for (j= 0; j < table_count; j++)
         {
           for (k= 0; k < table_count; k++)
           {
             if (bitmap_is_set(stat[j].dependent, i) &&
                 bitmap_is_set(stat[i].dependent, k))
               bitmap_set_bit(stat[j].dependent, k);
           }
         }
       }  
    */
    
    for (s= stat ; s < stat_end ; s++)
    {
      table= s->table;
      for (JOIN_TAB *t= stat ; t < stat_end ; t++)
      {
        if (t->dependent & table->map)
          t->dependent |= table->reginfo.join_tab->dependent;
      }
      if (outer_join & s->table->map)
        s->table->maybe_null= 1;
    }
    /* Catch illegal cross references for outer joins */
    for (i= 0, s= stat ; i < table_count ; i++, s++)
    {
      if (s->dependent & s->table->map)
      {
        join->table_count=0;			// Don't use join->table
        my_message(ER_WRONG_OUTER_JOIN,
                   ER_THD(join->thd, ER_WRONG_OUTER_JOIN), MYF(0));
        goto error;
      }
      s->key_dependent= s->dependent;
    }
  }

  if (thd->trace_started())
    trace_table_dependencies(thd, stat, join->table_count);

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

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

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

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

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

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

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

      if (table->is_filled_at_execution())
        continue;

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

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

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

          TABLE_LIST *embedding= table->pos_in_table_list->embedding;
          /*
            TODO (low priority): currently we ignore the const tables that
            are within a semi-join nest which is within an outer join nest.
            The effect of this is that we don't do const substitution for
            such tables.
          */
          KEY *keyinfo= table->key_info + key;
          uint  key_parts= table->actual_n_key_parts(keyinfo);
          if (eq_part.is_prefix(key_parts) &&
              !table->fulltext_searched && 
              (!embedding || (embedding->sj_on_expr && !embedding->embedding)))
	  {
            key_map base_part, base_const_ref, base_eq_part;
            base_part.set_prefix(keyinfo->user_defined_key_parts); 
            base_const_ref= const_ref;
            base_const_ref.intersect(base_part);
            base_eq_part= eq_part;
            base_eq_part.intersect(base_part);
            if (table->actual_key_flags(keyinfo) & HA_NOSAME)
            {
              
	      if (base_const_ref == base_eq_part &&
                  !has_expensive_keyparts &&
                  !((outer_join & table->map) &&
                    (*s->on_expr_ref)->is_expensive()))
	      {					// Found everything for ref.
	        int tmp;
	        ref_changed = 1;
	        s->type= JT_CONST;
	        join->const_table_map|=table->map;
	        set_position(join,const_count++,s,start_keyuse);
                /* create_ref_for_key will set s->table->const_table */
	        if (create_ref_for_key(join, s, start_keyuse, FALSE,
				       found_const_table_map))
                  goto error;
	        if ((tmp=join_read_const_table(join->thd, s,
                                               join->positions+const_count-1)))
	        {
		  if (tmp > 0)
		    goto error;			// Fatal error
	        }
	        else
		  found_const_table_map|= table->map;
	        break;
	      }
	    }
            else if (base_const_ref == base_eq_part)
              s->const_keys.set_bit(key);
          }
	}
      }
    }
  } while (ref_changed);
 
  join->sort_by_table= get_sort_by_table(join->order, join->group_list,
                                         join->select_lex->leaf_tables,
                                         join->const_table_map);
  /* 
    Update info on indexes that can be used for search lookups as
    reading const tables may has added new sargable predicates. 
  */
  if (const_count && sargables)
  {
    for( ; sargables->field ; sargables++)
    {
      Field *field= sargables->field;
      JOIN_TAB *join_tab= field->table->reginfo.join_tab;
      key_map possible_keys= field->key_start;
      possible_keys.intersect(field->table->keys_in_use_for_query);
      bool is_const= 1;
      for (uint j=0; j < sargables->num_values; j++)
        is_const&= sargables->arg_value[j]->const_item();
      if (is_const)
        join_tab[0].const_keys.merge(possible_keys);
    }
  }

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

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

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

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

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

  /*
    Todo: add a function so that we can add these Json_writer_objects
    easily.
    Another way would be to enclose them in a scope {};
  */
  {
    Json_writer_object rows_estimation_wrapper(thd);
    Json_writer_array rows_estimation(thd, "rows_estimation");

    for (s=stat ; s < stat_end ; s++)
    {
      s->startup_cost= 0;
      if (s->type == JT_SYSTEM || s->type == JT_CONST)
      {

        Json_writer_object table_records(thd);
        /* Only one matching row */
        s->found_records= s->records= 1;
        s->read_time=1.0;
        s->worst_seeks=1.0;
        table_records.add_table_name(s)
                     .add("rows", s->found_records)
                     .add("cost", s->read_time)
                     .add("table_type", s->type == JT_CONST ?
                                        "const" :
                                        "system");
        continue;
      }
      /* Approximate found rows and time to read them */
      if (s->table->is_filled_at_execution())
      {
        get_delayed_table_estimates(s->table, &s->records, &s->read_time,
                                    &s->startup_cost);
        s->found_records= s->records;
        table->quick_condition_rows=s->records;
      }
      else
        s->scan_time();

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

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

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

      s->table->cond_selectivity= 1.0;

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

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

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

          if (is_sargable_cond_of_where &&
              join->conds && join->conds->type() == Item::COND_ITEM &&
              ((Item_cond*) (join->conds))->functype() ==
              Item_func::COND_AND_FUNC)
            join->cond_equal= &((Item_cond_and*) (join->conds))->m_cond_equal;

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

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

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

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

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

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

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

#ifdef HAVE_valgrind
      // JOIN::positions holds the current query plan. We've already
      // made the plan choice, so we should only use JOIN::best_positions
      for (uint k=join->const_tables; k < join->table_count; k++)
        MEM_UNDEFINED(&join->positions[k], sizeof(join->positions[k]));
#endif
    }
    else
    {
      memcpy((uchar*) join->best_positions,(uchar*) join->positions,
	     sizeof(POSITION)*join->const_tables);
      join->join_record_count= 1.0;
      join->best_read=1.0;
    }
  
    if (!(join->select_options & SELECT_DESCRIBE) &&
        unit->derived && unit->derived->is_materialized_derived())
    {
      /*
        Calculate estimated number of rows for materialized derived
        table/view.
      */
      for (i= 0; i < join->table_count ; i++)
        if (double rr= join->best_positions[i].records_read)
          records= COST_MULT(records, rr);
      ha_rows rows= records > (double) HA_ROWS_MAX ? HA_ROWS_MAX : (ha_rows) records;
      set_if_smaller(rows, unit->select_limit_cnt);
      join->select_lex->increase_derived_records(rows);
    }
  }

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

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

  DBUG_RETURN(0);

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

Project: server

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

Project: server

return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
		 List<Item> &fields, bool send_row, ulonglong select_options,
		 const char *info, Item *having, List<Item> &all_fields)
{
  DBUG_ENTER("return_zero_rows");

  if (select_options & SELECT_DESCRIBE)
  {
    select_describe(join, FALSE, FALSE, FALSE, info);
    DBUG_RETURN(0);
  }

  if (send_row)
  {
    /*
      Set all tables to have NULL row. This is needed as we will be evaluating
      HAVING condition.
    */
    List_iterator<TABLE_LIST> ti(tables);
    TABLE_LIST *table;
    while ((table= ti++))
    {
      /*
        Don't touch semi-join materialization tables, as the above join_free()
        call has freed them (and HAVING clause can't have references to them 
        anyway).
      */
      if (!table->is_jtbm())
        mark_as_null_row(table->table);		// All fields are NULL
    }
    List_iterator_fast<Item> it(all_fields);
    Item *item;
    /*
      Inform all items (especially aggregating) to calculate HAVING correctly,
      also we will need it for sending results.
    */
    while ((item= it++))
      item->no_rows_in_result();
    if (having && having->val_int() == 0)
      send_row=0;
  }

  /* Update results for FOUND_ROWS */
  if (!join->send_row_on_empty_set())
  {
    join->thd->set_examined_row_count(0);
    join->thd->limit_found_rows= 0;
  }

  if (!(result->send_result_set_metadata(fields,
                              Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)))
  {
    bool send_error= FALSE;
    if (send_row)
      send_error= result->send_data(fields) > 0;
    if (likely(!send_error))
      result->send_eof();				// Should be safe
  }
  /*
    JOIN::join_free() must be called after the virtual method
    select::send_result_set_metadata() returned control since
    implementation of this method could use data strutcures
    that are released by the method JOIN::join_free().
  */
  join->join_free();

  DBUG_RETURN(0);
}

Project: server

setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
		  Ref_ptr_array ref_pointer_array,
		  List<Item> &res_selected_fields, List<Item> &res_all_fields,
		  uint elements, List<Item> &all_fields)
{
  Item *pos;
  List_iterator_fast<Item> li(all_fields);
  Copy_field *copy= NULL;
  Copy_field *copy_start __attribute__((unused));
  res_selected_fields.empty();
  res_all_fields.empty();
  List_iterator_fast<Item> itr(res_all_fields);
  List<Item> extra_funcs;
  uint i, border= all_fields.elements - elements;
  DBUG_ENTER("setup_copy_fields");

  if (param->field_count && 
      !(copy=param->copy_field= new (thd->mem_root) Copy_field[param->field_count]))
    goto err2;

  param->copy_funcs.empty();
  copy_start= copy;
  for (i= 0; (pos= li++); i++)
  {
    Field *field;
    uchar *tmp;
    Item *real_pos= pos->real_item();
    /*
      Aggregate functions can be substituted for fields (by e.g. temp tables).
      We need to filter those substituted fields out.
    */
    if (real_pos->type() == Item::FIELD_ITEM &&
        !(real_pos != pos &&
          ((Item_ref *)pos)->ref_type() == Item_ref::AGGREGATE_REF))
    {
      Item_field *item;
      if (!(item= new (thd->mem_root) Item_field(thd, ((Item_field*) real_pos))))
	goto err;
      if (pos->type() == Item::REF_ITEM)
      {
        /* preserve the names of the ref when dereferncing */
        Item_ref *ref= (Item_ref *) pos;
        item->db_name= ref->db_name;
        item->table_name= ref->table_name;
        item->name= ref->name;
      }
      pos= item;
      if (item->field->flags & BLOB_FLAG)
      {
	if (!(pos= new (thd->mem_root) Item_copy_string(thd, pos)))
	  goto err;
       /*
         Item_copy_string::copy for function can call 
         Item_copy_string::val_int for blob via Item_ref.
         But if Item_copy_string::copy for blob isn't called before,
         it's value will be wrong
         so let's insert Item_copy_string for blobs in the beginning of 
         copy_funcs
         (to see full test case look at having.test, BUG #4358) 
       */
	if (param->copy_funcs.push_front(pos, thd->mem_root))
	  goto err;
      }
      else
      {
	/* 
	   set up save buffer and change result_field to point at 
	   saved value
	*/
	field= item->field;
	item->result_field=field->make_new_field(thd->mem_root,
                                                 field->table, 1);
        /*
          We need to allocate one extra byte for null handling and
          another extra byte to not get warnings from purify in
          Field_string::val_int
        */
	if (!(tmp= (uchar*) thd->alloc(field->pack_length()+2)))
	  goto err;
        if (copy)
        {
          DBUG_ASSERT (param->field_count > (uint) (copy - copy_start));
          copy->set(tmp, item->result_field);
          item->result_field->move_field(copy->to_ptr,copy->to_null_ptr,1);
#ifdef HAVE_valgrind
          copy->to_ptr[copy->from_length]= 0;
#endif
          copy++;
        }
      }
    }
    else if ((real_pos->type() == Item::FUNC_ITEM ||
	      real_pos->real_type() == Item::SUBSELECT_ITEM ||
	      real_pos->type() == Item::CACHE_ITEM ||
	      real_pos->type() == Item::COND_ITEM) &&
	     !real_pos->with_sum_func())
    {						// Save for send fields
      LEX_CSTRING real_name= pos->name;
      pos= real_pos;
      pos->name= real_name;
      /* TODO:
	 In most cases this result will be sent to the user.
	 This should be changed to use copy_int or copy_real depending
	 on how the value is to be used: In some cases this may be an
	 argument in a group function, like: IF(ISNULL(col),0,COUNT(*))
      */
      if (!(pos= pos->type_handler()->create_item_copy(thd, pos)))
	goto err;
      if (i < border)                           // HAVING, ORDER and GROUP BY
      {
        if (extra_funcs.push_back(pos, thd->mem_root))
          goto err;
      }
      else if (param->copy_funcs.push_back(pos, thd->mem_root))
	goto err;
    }
    res_all_fields.push_back(pos, thd->mem_root);
    ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
      pos;
  }
  param->copy_field_end= copy;

  for (i= 0; i < border; i++)
    itr++;
  itr.sublist(res_selected_fields, elements);
  /*
    Put elements from HAVING, ORDER BY and GROUP BY last to ensure that any
    reference used in these will resolve to a item that is already calculated
  */
  param->copy_funcs.append(&extra_funcs);

  DBUG_RETURN(0);

 err:
  if (copy)
    delete [] param->copy_field;			// This is never 0
  param->copy_field= 0;
err2:
  DBUG_RETURN(TRUE);
}

Project: server

bool JOIN::make_range_rowid_filters()
{
  DBUG_ENTER("make_range_rowid_filters");

  /*
    Do not build range filters with detected impossible WHERE.
    Anyway conditions cannot be used anymore to extract ranges for filters.
  */
  if (const_table_map != found_const_table_map)
    DBUG_RETURN(0);

  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))
  {
    if (!tab->range_rowid_filter_info)
      continue;

    DBUG_ASSERT(!(tab->ref.key >= 0 &&
                  tab->ref.key == (int) tab->range_rowid_filter_info->key_no));
    DBUG_ASSERT(!(tab->ref.key == -1 && tab->quick &&
                  tab->quick->index == tab->range_rowid_filter_info->key_no));

    int err;
    SQL_SELECT *sel= NULL;
    Rowid_filter_container *filter_container= NULL;
    Item **sargable_cond= get_sargable_cond(this, tab->table);
    sel= make_select(tab->table, const_table_map, const_table_map,
                     *sargable_cond, (SORT_INFO*) 0, 1, &err);
    if (!sel)
      continue;

    key_map filter_map;
    filter_map.clear_all();
    filter_map.set_bit(tab->range_rowid_filter_info->key_no);
    filter_map.merge(tab->table->with_impossible_ranges);
    bool force_index_save= tab->table->force_index;
    tab->table->force_index= true;
    int rc= sel->test_quick_select(thd, filter_map, (table_map) 0,
                                   (ha_rows) HA_POS_ERROR,
                                   true, false, true, true);
    tab->table->force_index= force_index_save;
    if (thd->is_error())
      goto no_filter;
    /*
      If SUBS_IN_TO_EXISTS strtrategy is chosen for the subquery then
      additional conditions are injected into WHERE/ON/HAVING and it may
      happen that the call of test_quick_select() discovers impossible range.
    */
    if (rc == -1)
    {
      const_table_map|= tab->table->map;
      goto no_filter;
    }
    DBUG_ASSERT(sel->quick);
    filter_container=
      tab->range_rowid_filter_info->create_container();
    if (filter_container)
    {
      tab->rowid_filter=
        new (thd->mem_root) Range_rowid_filter(tab->table,
                                               tab->range_rowid_filter_info,
                                               filter_container, sel);
      if (tab->rowid_filter)
        continue;
    }
  no_filter:
    if (sel->quick)
      delete sel->quick;
    delete sel;
  }

  DBUG_RETURN(0);
}

Project: server

Field *Item_result_field::create_tmp_field_ex(TABLE *table,
                                              Tmp_field_src *src,
                                              const Tmp_field_param *param)
{
  /*
    Possible Item types:
    - Item_cache_wrapper  (only for CREATE..SELECT ?)
    - Item_func
    - Item_subselect
  */
  DBUG_ASSERT(is_result_field());
  DBUG_ASSERT(type() != NULL_ITEM);
  get_tmp_field_src(src, param);
  Field *result;
  if ((result= tmp_table_field_from_field_type(table)) && param->modify_item())
    result_field= result;
  return result;
}

Project: server

bool instantiate_tmp_table(TABLE *table, KEY *keyinfo, 
                           TMP_ENGINE_COLUMNDEF *start_recinfo,
                           TMP_ENGINE_COLUMNDEF **recinfo,
                           ulonglong options)
{
  if (table->s->db_type() == TMP_ENGINE_HTON)
  {
    /*
      If it is not heap (in-memory) table then convert index to unique
      constrain.
    */
    MEM_CHECK_DEFINED(table->record[0], table->s->reclength);
    if (create_internal_tmp_table(table, keyinfo, start_recinfo, recinfo,
                                  options))
      return TRUE;
    // Make empty record so random data is not written to disk
    empty_record(table);
    table->status= STATUS_NO_RECORD;
  }
  if (open_tmp_table(table))
    return TRUE;

  return FALSE;
}

Project: server

ORDER *simple_remove_const(ORDER *order, COND *where)
{
  if (!order || !where)
    return order;

  ORDER *first= NULL, *prev= NULL;
  for (; order; order= order->next)
  {
    DBUG_ASSERT(!order->item[0]->with_sum_func()); // should never happen
    if (!const_expression_in_where(where, order->item[0]))
    {
      if (!first)
        first= order;
      if (prev)
        prev->next= order;
      prev= order;
    }
  }
  if (prev)
    prev->next= NULL;
  return first;
}