Commit message: MDEV-22464 Server crash on UPDATE with nested subquery

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

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

Actually not failing the above seems to be ok.

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

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

So this patch implements this fix.
CVE: CVE-2021-46662
CWE: NVD-CWE-noinfo
Vulnerability description: MariaDB through 10.5.9 allows a set_var.cc application crash via certain uses of an UPDATE statement in conjunction with a nested subquery.

Project: server

test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
			bool no_changes, const key_map *map)
{
  int ref_key;
  uint UNINIT_VAR(ref_key_parts);
  int order_direction= 0;
  uint used_key_parts= 0;
  TABLE *table=tab->table;
  SQL_SELECT *select=tab->select;
  key_map usable_keys;
  QUICK_SELECT_I *save_quick= select ? select->quick : 0;
  Item *orig_cond= 0;
  bool orig_cond_saved= false;
  int best_key= -1;
  bool changed_key= false;
  DBUG_ENTER("test_if_skip_sort_order");

  /* Check that we are always called with first non-const table */
  DBUG_ASSERT(tab == tab->join->join_tab + tab->join->const_tables);

  /*
    Keys disabled by ALTER TABLE ... DISABLE KEYS should have already
    been taken into account.
  */
  usable_keys= *map;
  
  /* Find indexes that cover all ORDER/GROUP BY fields */
  for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
  {
    Item *item= (*tmp_order->item)->real_item();
    if (item->type() != Item::FIELD_ITEM)
    {
      usable_keys.clear_all();
      DBUG_RETURN(0);
    }

    /*
      Take multiple-equalities into account. Suppose we have
        ORDER BY col1, col10
      and there are
         multiple-equal(col1, col2, col3),
         multiple-equal(col10, col11).

      Then, 
      - when item=col1, we find the set of indexes that cover one of {col1,
        col2, col3}
      - when item=col10, we find the set of indexes that cover one of {col10,
        col11}

      And we compute an intersection of these sets to find set of indexes that
      cover all ORDER BY components.
    */
    key_map col_keys;
    compute_part_of_sort_key_for_equals(tab->join, table, (Item_field*)item,
                                        &col_keys);
    usable_keys.intersect(col_keys);
    if (usable_keys.is_clear_all())
      goto use_filesort;                        // No usable keys
  }

  ref_key= -1;
  /* Test if constant range in WHERE */
  if (tab->ref.key >= 0 && tab->ref.key_parts)
  {
    ref_key=	   tab->ref.key;
    ref_key_parts= tab->ref.key_parts;
    /* 
      todo: why does JT_REF_OR_NULL mean filesort? We could find another index
      that satisfies the ordering. I would just set ref_key=MAX_KEY here...
    */
    if (tab->type == JT_REF_OR_NULL || tab->type == JT_FT ||
        tab->ref.uses_splitting)
      goto use_filesort;
  }
  else if (select && select->quick)		// Range found by opt_range
  {
    int quick_type= select->quick->get_type();
    /* 
      assume results are not ordered when index merge is used 
      TODO: sergeyp: Results of all index merge selects actually are ordered 
      by clustered PK values.
    */
  
    if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
        quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
        quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION || 
        quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT)
    {
      /*
        we set ref_key=MAX_KEY instead of -1, because test_if_cheaper ordering
        assumes that "ref_key==-1" means doing full index scan. 
        (This is not very straightforward and we got into this situation for 
         historical reasons. Should be fixed at some point).
      */
      ref_key= MAX_KEY;
    }
    else
    {
      ref_key= select->quick->index;
      ref_key_parts= select->quick->used_key_parts;
    }
  }

  if (ref_key >= 0 && ref_key != MAX_KEY)
  {
    /* Current access method uses index ref_key with ref_key_parts parts */
    if (!usable_keys.is_set(ref_key))
    {
      /* However, ref_key doesn't match the needed ordering */
      uint new_ref_key;

      /*
	If using index only read, only consider other possible index only
	keys
      */
      if (table->covering_keys.is_set(ref_key))
	usable_keys.intersect(table->covering_keys);
      if (tab->pre_idx_push_select_cond)
      {
        orig_cond= tab->set_cond(tab->pre_idx_push_select_cond);
        orig_cond_saved= true;
      }

      if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts,
				       &usable_keys)) < MAX_KEY)
      {
        /*
          Index new_ref_key 
          - produces the required ordering, 
          - also has the same columns as ref_key for #ref_key_parts (this
            means we will read the same number of rows as with ref_key).
        */

        /*
          If new_ref_key allows to construct a quick select which uses more key
          parts than ref(new_ref_key) would, do that.

          Otherwise, construct a ref access (todo: it's not clear what is the
          win in using ref access when we could use quick select also?)
        */
        if ((table->quick_keys.is_set(new_ref_key) && 
             table->quick_key_parts[new_ref_key] > ref_key_parts) ||
             !(tab->ref.key >= 0))
	{
          /*
            The range optimizer constructed QUICK_RANGE for ref_key, and
            we want to use instead new_ref_key as the index. We can't
            just change the index of the quick select, because this may
            result in an inconsistent QUICK_SELECT object. Below we
            create a new QUICK_SELECT from scratch so that all its
            parameters are set correctly by the range optimizer.
           */
          key_map new_ref_key_map;
          COND *save_cond;
          bool res;
          new_ref_key_map.clear_all();  // Force the creation of quick select
          new_ref_key_map.set_bit(new_ref_key); // only for new_ref_key.

          /* Reset quick;  This will be restored in 'use_filesort' if needed */
          select->quick= 0;
          save_cond= select->cond;
          if (select->pre_idx_push_select_cond)
            select->cond= select->pre_idx_push_select_cond;
          res= select->test_quick_select(tab->join->thd, new_ref_key_map, 0,
                                         (tab->join->select_options &
                                          OPTION_FOUND_ROWS) ?
                                         HA_POS_ERROR :
                                         tab->join->unit->select_limit_cnt,TRUE,
                                         TRUE, FALSE) <= 0;
          if (res)
          {
            select->cond= save_cond;
            goto use_filesort;
          }
          DBUG_ASSERT(tab->select->quick);
          tab->type= JT_ALL;
          tab->ref.key= -1;
          tab->ref.key_parts= 0;
          tab->use_quick= 1;
          best_key= new_ref_key;
          /*
            We don't restore select->cond as we want to use the
            original condition as index condition pushdown is not
            active for the new index.
            todo: why not perform index condition pushdown for the new index?
          */
	}
        else
	{
          /*
            We'll use ref access method on key new_ref_key. In general case 
            the index search tuple for new_ref_key will be different (e.g.
            when one index is defined as (part1, part2, ...) and another as
            (part1, part2(N), ...) and the WHERE clause contains 
            "part1 = const1 AND part2=const2". 
            So we build tab->ref from scratch here.
          */
          KEYUSE *keyuse= tab->keyuse;
          while (keyuse->key != new_ref_key && keyuse->table == tab->table)
            keyuse++;
          if (create_ref_for_key(tab->join, tab, keyuse, FALSE,
                                 (tab->join->const_table_map |
                                  OUTER_REF_TABLE_BIT)))
            goto use_filesort;

          pick_table_access_method(tab);
	}

        ref_key= new_ref_key;
        changed_key= true;
     }
    }
    /* Check if we get the rows in requested sorted order by using the key */
    if (usable_keys.is_set(ref_key) &&
        (order_direction= test_if_order_by_key(tab->join, order,table,ref_key,
					       &used_key_parts)))
      goto check_reverse_order;
  }
  {
    uint UNINIT_VAR(best_key_parts);
    uint saved_best_key_parts= 0;
    int best_key_direction= 0;
    JOIN *join= tab->join;
    ha_rows table_records= table->stat_records();

    test_if_cheaper_ordering(tab, order, table, usable_keys,
                             ref_key, select_limit,
                             &best_key, &best_key_direction,
                             &select_limit, &best_key_parts,
                             &saved_best_key_parts);

    /*
      filesort() and join cache are usually faster than reading in 
      index order and not using join cache, except in case that chosen
      index is clustered key.
    */
    if (best_key < 0 ||
        ((select_limit >= table_records) &&
         (tab->type == JT_ALL &&
         tab->join->table_count > tab->join->const_tables + 1) &&
         !(table->file->index_flags(best_key, 0, 1) & HA_CLUSTERED_INDEX)))
      goto use_filesort;

    if (select && // psergey:  why doesn't this use a quick?
        table->quick_keys.is_set(best_key) && best_key != ref_key)
    {
      key_map tmp_map;
      tmp_map.clear_all();       // Force the creation of quick select
      tmp_map.set_bit(best_key); // only best_key.
      select->quick= 0;

      bool cond_saved= false;
      Item *saved_cond;

      /*
        Index Condition Pushdown may have removed parts of the condition for
        this table. Temporarily put them back because we want the whole
        condition for the range analysis.
      */
      if (select->pre_idx_push_select_cond)
      {
        saved_cond= select->cond;
        select->cond= select->pre_idx_push_select_cond;
        cond_saved= true;
      }

      select->test_quick_select(join->thd, tmp_map, 0,
                                join->select_options & OPTION_FOUND_ROWS ?
                                HA_POS_ERROR :
                                join->unit->select_limit_cnt,
                                TRUE, FALSE, FALSE);

      if (cond_saved)
        select->cond= saved_cond;
    }
    order_direction= best_key_direction;
    /*
      saved_best_key_parts is actual number of used keyparts found by the
      test_if_order_by_key function. It could differ from keyinfo->user_defined_key_parts,
      thus we have to restore it in case of desc order as it affects
      QUICK_SELECT_DESC behaviour.
    */
    used_key_parts= (order_direction == -1) ?
      saved_best_key_parts :  best_key_parts;
    changed_key= true;
  }

check_reverse_order:                  
  DBUG_ASSERT(order_direction != 0);

  if (order_direction == -1)		// If ORDER BY ... DESC
  {
    int quick_type;
    if (select && select->quick)
    {
      /*
	Don't reverse the sort order, if it's already done.
        (In some cases test_if_order_by_key() can be called multiple times
      */
      if (select->quick->reverse_sorted())
        goto skipped_filesort;

      quick_type= select->quick->get_type();
      if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
          quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
          quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT ||
          quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
          quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
      {
        tab->limit= 0;
        goto use_filesort;               // Use filesort
      }
    }
  }

  /*
    Update query plan with access pattern for doing ordered access
    according to what we have decided above.
  */
  if (!no_changes) // We are allowed to update QEP
  {
    if (best_key >= 0)
    {
      bool quick_created= 
        (select && select->quick && select->quick!=save_quick);

      /* 
         If ref_key used index tree reading only ('Using index' in EXPLAIN),
         and best_key doesn't, then revert the decision.
      */
      if (table->covering_keys.is_set(best_key))
        table->file->ha_start_keyread(best_key);
      else
        table->file->ha_end_keyread();

      if (!quick_created)
      {
        if (select)                  // Throw any existing quick select
          select->quick= 0;          // Cleanup either reset to save_quick,
                                     // or 'delete save_quick'
        tab->index= best_key;
        tab->read_first_record= order_direction > 0 ?
                                join_read_first:join_read_last;
        tab->type=JT_NEXT;           // Read with index_first(), index_next()

        if (tab->pre_idx_push_select_cond)
        {
          tab->set_cond(tab->pre_idx_push_select_cond);
          /*
            orig_cond is a part of pre_idx_push_cond,
            no need to restore it.
          */
          orig_cond= 0;
          orig_cond_saved= false;
        }

        table->file->ha_index_or_rnd_end();
        if (tab->join->select_options & SELECT_DESCRIBE)
        {
          tab->ref.key= -1;
          tab->ref.key_parts= 0;
          if (select_limit < table->stat_records())
            tab->limit= select_limit;
          table->file->ha_end_keyread();
        }
      }
      else if (tab->type != JT_ALL || tab->select->quick)
      {
        /*
          We're about to use a quick access to the table.
          We need to change the access method so as the quick access
          method is actually used.
        */
        DBUG_ASSERT(tab->select->quick);
        tab->type=JT_ALL;
        tab->use_quick=1;
        tab->ref.key= -1;
        tab->ref.key_parts=0;		// Don't use ref key.
        tab->read_first_record= join_init_read_record;
        if (tab->is_using_loose_index_scan())
          tab->join->tmp_table_param.precomputed_group_by= TRUE;

        /*
          Restore the original condition as changes done by pushdown
          condition are not relevant anymore
        */
        if (tab->select && tab->select->pre_idx_push_select_cond)
	{
          tab->set_cond(tab->select->pre_idx_push_select_cond);
           tab->table->file->cancel_pushed_idx_cond();
        }
        /*
          TODO: update the number of records in join->best_positions[tablenr]
        */
      }
    } // best_key >= 0

    if (order_direction == -1)		// If ORDER BY ... DESC
    {
      if (select && select->quick)
      {
        /* ORDER BY range_key DESC */
        QUICK_SELECT_I *tmp= select->quick->make_reverse(used_key_parts);
        if (!tmp)
        {
          tab->limit= 0;
          goto use_filesort;           // Reverse sort failed -> filesort
        }
        /*
          Cancel Pushed Index Condition, as it doesn't work for reverse scans.
        */
        if (tab->select && tab->select->pre_idx_push_select_cond)
	{
          tab->set_cond(tab->select->pre_idx_push_select_cond);
           tab->table->file->cancel_pushed_idx_cond();
        }
        if (select->quick == save_quick)
          save_quick= 0;                // make_reverse() consumed it
        select->set_quick(tmp);
        /* Cancel "Range checked for each record" */
        if (tab->use_quick == 2)
        {
          tab->use_quick= 1;
          tab->read_first_record= join_init_read_record;
        }
      }
      else if (tab->type != JT_NEXT && tab->type != JT_REF_OR_NULL &&
               tab->ref.key >= 0 && tab->ref.key_parts <= used_key_parts)
      {
        /*
          SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC

          Use a traversal function that starts by reading the last row
          with key part (A) and then traverse the index backwards.
        */
        tab->read_first_record= join_read_last_key;
        tab->read_record.read_record_func= join_read_prev_same;
        /* Cancel "Range checked for each record" */
        if (tab->use_quick == 2)
        {
          tab->use_quick= 1;
          tab->read_first_record= join_init_read_record;
        }
        /*
          Cancel Pushed Index Condition, as it doesn't work for reverse scans.
        */
        if (tab->select && tab->select->pre_idx_push_select_cond)
	{
          tab->set_cond(tab->select->pre_idx_push_select_cond);
           tab->table->file->cancel_pushed_idx_cond();
        }
      }
    }
    else if (select && select->quick)
      select->quick->need_sorted_output();

    tab->read_record.unlock_row= (tab->type == JT_EQ_REF) ?
                                 join_read_key_unlock_row : rr_unlock_row;

  } // QEP has been modified

  /*
    Cleanup:
    We may have both a 'select->quick' and 'save_quick' (original)
    at this point. Delete the one that we wan't use.
  */

skipped_filesort:
  // Keep current (ordered) select->quick 
  if (select && save_quick != select->quick)
  {
    delete save_quick;
    save_quick= NULL;
  }
  if (orig_cond_saved && !changed_key)
    tab->set_cond(orig_cond);
  if (!no_changes && changed_key && table->file->pushed_idx_cond)
    table->file->cancel_pushed_idx_cond();

  DBUG_RETURN(1);

use_filesort:
  // Restore original save_quick
  if (select && select->quick != save_quick)
  {
    delete select->quick;
    select->quick= save_quick;
  }
  if (orig_cond_saved)
    tab->set_cond(orig_cond);

  DBUG_RETURN(0);
}

Project: server

end_sj_materialize(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
{
  int error;
  THD *thd= join->thd;
  SJ_MATERIALIZATION_INFO *sjm= join_tab[-1].emb_sj_nest->sj_mat_info;
  DBUG_ENTER("end_sj_materialize");
  if (!end_of_records)
  {
    TABLE *table= sjm->table;

    List_iterator<Item> it(sjm->sjm_table_cols);
    Item *item;
    while ((item= it++))
    {
      if (item->is_null())
        DBUG_RETURN(NESTED_LOOP_OK);
    }
    fill_record(thd, table, table->field, sjm->sjm_table_cols, TRUE, FALSE);
    if (unlikely(thd->is_error()))
      DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
    if (unlikely((error= table->file->ha_write_tmp_row(table->record[0]))))
    {
      /* create_myisam_from_heap will generate error if needed */
      if (table->file->is_fatal_error(error, HA_CHECK_DUP) &&
          create_internal_tmp_table_from_heap(thd, table,
                                              sjm->sjm_table_param.start_recinfo, 
                                              &sjm->sjm_table_param.recinfo, error, 1, NULL))
        DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
    }
  }
  DBUG_RETURN(NESTED_LOOP_OK);
}

Project: server

only_eq_ref_tables(JOIN *join,ORDER *order,table_map tables)
{
  tables&= ~PSEUDO_TABLE_BITS;
  for (JOIN_TAB **tab=join->map2table ; tables ; tab++, tables>>=1)
  {
    if (tables & 1 && !eq_ref_table(join, order, *tab))
      return 0;
  }
  return 1;
}

Project: server

static Item **get_sargable_cond(JOIN *join, TABLE *table)
{
  Item **retval;
  if (table->pos_in_table_list->on_expr)
  {
    /*
      This is an inner table from a single-table LEFT JOIN, "t1 LEFT JOIN
      t2 ON cond". Use the condition cond.
    */
    retval= &table->pos_in_table_list->on_expr;
  }
  else if (table->pos_in_table_list->embedding &&
           !table->pos_in_table_list->embedding->sj_on_expr)
  {
    /*
      This is the inner side of a multi-table outer join. Use the
      appropriate ON expression.
    */
    retval= &(table->pos_in_table_list->embedding->on_expr);
  }
  else
  {
    /* The table is not inner wrt some LEFT JOIN. Use the WHERE clause */
    retval= &join->conds;
  }
  return retval;
}

Project: server

void JOIN::cleanup(bool full)
{
  DBUG_ENTER("JOIN::cleanup");
  DBUG_PRINT("enter", ("full %u", (uint) full));
  
  if (full)
    have_query_plan= QEP_DELETED;

  if (original_join_tab)
  {
    /* Free the original optimized join created for the group_by_handler */
    join_tab= original_join_tab;
    original_join_tab= 0;
    table_count= original_table_count;
  }

  if (join_tab)
  {
    JOIN_TAB *tab;

    if (full)
    {
      /*
        Call cleanup() on join tabs used by the join optimization
        (join->join_tab may now be pointing to result of make_simple_join
         reading from the temporary table)

        We also need to check table_count to handle various degenerate joins
        w/o tables: they don't have some members initialized and
        WALK_OPTIMIZATION_TABS may not work correctly for them.
      */
      if (top_join_tab_count && tables_list)
      {
        for (tab= first_breadth_first_tab(); tab;
             tab= next_breadth_first_tab(first_breadth_first_tab(),
                                         top_join_tab_count, tab))
        {
          tab->cleanup();
          delete tab->filesort_result;
          tab->filesort_result= NULL;
        }
      }
      cleaned= true;
      //psergey2: added (Q: why not in the above loop?)
      {
        JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt();
        for (uint i= 0; i < aggr_tables; i++, curr_tab++)
        {
          if (curr_tab->aggr)
          {
            free_tmp_table(thd, curr_tab->table);
            delete curr_tab->tmp_table_param;
            curr_tab->tmp_table_param= NULL;
            curr_tab->aggr= NULL;

            delete curr_tab->filesort_result;
            curr_tab->filesort_result= NULL;
          }
        }
        aggr_tables= 0; // psergey3
      }
    }
    else
    {
      for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITH_CONST_TABLES); tab;
           tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
      {
        tab->partial_cleanup();
      }
    }
  }
  if (full)
  {
    cleanup_empty_jtbm_semi_joins(this, join_list);

    // Run Cached_item DTORs!
    group_fields.delete_elements();

    /*
      We can't call delete_elements() on copy_funcs as this will cause
      problems in free_elements() as some of the elements are then deleted.
    */
    tmp_table_param.copy_funcs.empty();
    /*
      If we have tmp_join and 'this' JOIN is not tmp_join and
      tmp_table_param.copy_field's  of them are equal then we have to remove
      pointer to  tmp_table_param.copy_field from tmp_join, because it will
      be removed in tmp_table_param.cleanup().
    */
    tmp_table_param.cleanup();

    delete pushdown_query;
    pushdown_query= 0;

    if (!join_tab)
    {
      List_iterator<TABLE_LIST> li(*join_list);
      TABLE_LIST *table_ref;
      while ((table_ref= li++))
      {
        if (table_ref->table &&
            table_ref->jtbm_subselect &&
            table_ref->jtbm_subselect->is_jtbm_const_tab)
        {
          free_tmp_table(thd, table_ref->table);
          table_ref->table= NULL;
        }
      }
    }
  }
  /* Restore ref array to original state */
  if (current_ref_ptrs != items0)
  {
    set_items_ref_array(items0);
    set_group_rpa= false;
  }
  DBUG_VOID_RETURN;
}

Project: server

static bool copy_blobs(Field **ptr)
{
  for (; *ptr ; ptr++)
  {
    if ((*ptr)->flags & BLOB_FLAG)
      if (((Field_blob *) (*ptr))->copy())
	return 1;				// Error
  }
  return 0;
}

Project: server

max_part_bit(key_part_map bits)
{
  uint found;
  for (found=0; bits & 1 ; found++,bits>>=1) ;
  return found;
}

Project: server

eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab)
{
  if (tab->cached_eq_ref_table)			// If cached
    return tab->eq_ref_table;
  tab->cached_eq_ref_table=1;
  /* We can skip const tables only if not an outer table */
  if (tab->type == JT_CONST && !tab->first_inner)
    return (tab->eq_ref_table=1);		/* purecov: inspected */
  if (tab->type != JT_EQ_REF || tab->table->maybe_null)
    return (tab->eq_ref_table=0);		// We must use this
  Item **ref_item=tab->ref.items;
  Item **end=ref_item+tab->ref.key_parts;
  uint found=0;
  table_map map=tab->table->map;

  for (; ref_item != end ; ref_item++)
  {
    if (! (*ref_item)->const_item())
    {						// Not a const ref
      ORDER *order;
      for (order=start_order ; order ; order=order->next)
      {
	if ((*ref_item)->eq(order->item[0],0))
	  break;
      }
      if (order)
      {
        if (!(order->used & map))
        {
          found++;
          order->used|= map;
        }
	continue;				// Used in ORDER BY
      }
      if (!only_eq_ref_tables(join,start_order, (*ref_item)->used_tables()))
	return (tab->eq_ref_table=0);
    }
  }
  /* Check that there was no reference to table before sort order */
  for (; found && start_order ; start_order=start_order->next)
  {
    if (start_order->used & map)
    {
      found--;
      continue;
    }
    if (start_order->depend_map & map)
      return (tab->eq_ref_table=0);
  }
  return tab->eq_ref_table=1;
}

Project: server

void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex)
{
  DBUG_ENTER("remove_redundant_subquery_clauses");
  Item_subselect *subq_predicate= subq_select_lex->master_unit()->item;
  /*
    The removal should happen for IN, ALL, ANY and EXISTS subqueries,
    which means all but single row subqueries. Example single row
    subqueries: 
       a) SELECT * FROM t1 WHERE t1.a = (<single row subquery>) 
       b) SELECT a, (<single row subquery) FROM t1
   */
  if (subq_predicate->substype() == Item_subselect::SINGLEROW_SUBS)
    DBUG_VOID_RETURN;

  /* A subquery that is not single row should be one of IN/ALL/ANY/EXISTS. */
  DBUG_ASSERT (subq_predicate->substype() == Item_subselect::EXISTS_SUBS ||
               subq_predicate->is_in_predicate());

  if (subq_select_lex->options & SELECT_DISTINCT)
  {
    subq_select_lex->join->select_distinct= false;
    subq_select_lex->options&= ~SELECT_DISTINCT;
    DBUG_PRINT("info", ("DISTINCT removed"));
  }

  /*
    Remove GROUP BY if there are no aggregate functions and no HAVING
    clause
  */
  if (subq_select_lex->group_list.elements &&
      !subq_select_lex->with_sum_func && !subq_select_lex->join->having)
  {
    for (ORDER *ord= subq_select_lex->group_list.first; ord; ord= ord->next)
    {
      /*
        Do not remove the item if it is used in select list and then referred
        from GROUP BY clause by its name or number. Example:

          select (select ... ) as SUBQ ...  group by SUBQ

        Here SUBQ cannot be removed.
      */
      if (!ord->in_field_list)
        (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL);
    }
    subq_select_lex->join->group_list= NULL;
    subq_select_lex->group_list.empty();
    DBUG_PRINT("info", ("GROUP BY removed"));
  }

  /*
    TODO: This would prevent processing quries with ORDER BY ... LIMIT
    therefore we disable this optimization for now.
    Remove GROUP BY if there are no aggregate functions and no HAVING
    clause
  if (subq_select_lex->group_list.elements &&
      !subq_select_lex->with_sum_func && !subq_select_lex->join->having)
  {
    subq_select_lex->join->group_list= NULL;
    subq_select_lex->group_list.empty();
  }
  */
  DBUG_VOID_RETURN;
}

Project: server

Item_func_ne::add_key_fields(JOIN *join, KEY_FIELD **key_fields,
                             uint *and_level, table_map usable_tables,
                             SARGABLE_PARAM **sargables)
{
  if (!(used_tables() & OUTER_REF_TABLE_BIT))
  {
    /*
      QQ: perhaps test for !is_local_field(args[1]) is not really needed here.
      Other comparison functions, e.g. Item_func_le, Item_func_gt, etc,
      do not have this test. See Item_bool_func2::add_key_fieldoptimize_op().
      Check with the optimizer team.
    */
    if (is_local_field(args[0]) && !is_local_field(args[1]))
      add_key_equal_fields(join, key_fields, *and_level, this,
                           (Item_field*) (args[0]->real_item()), false,
                           &args[1], 1, usable_tables, sargables);
    /*
      QQ: perhaps test for !is_local_field(args[0]) is not really needed here.
    */
    if (is_local_field(args[1]) && !is_local_field(args[0]))
      add_key_equal_fields(join, key_fields, *and_level, this,
                           (Item_field*) (args[1]->real_item()), false,
                           &args[0], 1, usable_tables, sargables);
  }
}

Project: server

join_read_next_same_or_null(READ_RECORD *info)
{
  int error;
  if (unlikely((error= join_read_next_same(info)) >= 0))
    return error;
  JOIN_TAB *tab= info->table->reginfo.join_tab;

  /* Test if we have already done a read after null key */
  if (*tab->ref.null_ref_key)
    return -1;					// All keys read
  *tab->ref.null_ref_key= 1;			// Set null byte
  return safe_index_read(tab);			// then read null keys
}

Project: server

static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
                                    KEYUSE *org_keyuse, table_map used_tables)
{
  KEY *keyinfo;
  KEY_PART_INFO *key_part_info;
  KEYUSE *keyuse= org_keyuse;
  uint key_parts= 0;
  THD  *thd= join->thd;
  TABLE *table= join_tab->table;
  bool first_keyuse= TRUE;
  DBUG_ENTER("create_hj_key_for_table");

  do
  {
    if (!(~used_tables & keyuse->used_tables) &&
        join_tab->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) &&
        are_tables_local(join_tab, keyuse->used_tables))    
    {
      if (first_keyuse)
      {
        key_parts++;
      }
      else
      {
        KEYUSE *curr= org_keyuse;
        for( ; curr < keyuse; curr++)
        {
          if (curr->keypart == keyuse->keypart &&
              !(~used_tables & curr->used_tables) &&
              join_tab->keyuse_is_valid_for_access_in_chosen_plan(join,
                                                                  curr) &&
              are_tables_local(join_tab, curr->used_tables))
            break;
        }
        if (curr == keyuse)
           key_parts++;
      }
    }
    first_keyuse= FALSE;
    keyuse++;
  } while (keyuse->table == table && keyuse->is_for_hash_join());
  if (!key_parts)
    DBUG_RETURN(TRUE);
  /* This memory is allocated only once for the joined table join_tab */
  if (!(keyinfo= (KEY *) thd->alloc(sizeof(KEY))) ||
      !(key_part_info = (KEY_PART_INFO *) thd->alloc(sizeof(KEY_PART_INFO)*
                                                     key_parts)))
    DBUG_RETURN(TRUE);
  keyinfo->usable_key_parts= keyinfo->user_defined_key_parts = key_parts;
  keyinfo->ext_key_parts= keyinfo->user_defined_key_parts;
  keyinfo->key_part= key_part_info;
  keyinfo->key_length=0;
  keyinfo->algorithm= HA_KEY_ALG_UNDEF;
  keyinfo->flags= HA_GENERATED_KEY;
  keyinfo->is_statistics_from_stat_tables= FALSE;
  keyinfo->name.str= "$hj";
  keyinfo->name.length= 3;
  keyinfo->rec_per_key= (ulong*) thd->calloc(sizeof(ulong)*key_parts);
  if (!keyinfo->rec_per_key)
    DBUG_RETURN(TRUE);
  keyinfo->key_part= key_part_info;

  first_keyuse= TRUE;
  keyuse= org_keyuse;
  do
  {
    if (!(~used_tables & keyuse->used_tables) &&
        join_tab->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) &&
        are_tables_local(join_tab, keyuse->used_tables))
    { 
      bool add_key_part= TRUE;
      if (!first_keyuse)
      {
        for(KEYUSE *curr= org_keyuse; curr < keyuse; curr++)
        {
          if (curr->keypart == keyuse->keypart &&
              !(~used_tables & curr->used_tables) &&
              join_tab->keyuse_is_valid_for_access_in_chosen_plan(join,
                                                                  curr) &&
              are_tables_local(join_tab, curr->used_tables))
	  {
            keyuse->keypart= NO_KEYPART;
            add_key_part= FALSE;
            break;
          }
        }
      }
      if (add_key_part)
      {
        Field *field= table->field[keyuse->keypart];
        uint fieldnr= keyuse->keypart+1;
        table->create_key_part_by_field(key_part_info, field, fieldnr);
        keyinfo->key_length += key_part_info->store_length;
        key_part_info++;
      }
    }
    first_keyuse= FALSE;
    keyuse++;
  } while (keyuse->table == table && keyuse->is_for_hash_join());

  keyinfo->ext_key_parts= keyinfo->user_defined_key_parts;
  keyinfo->ext_key_flags= keyinfo->flags;
  keyinfo->ext_key_part_map= 0;

  join_tab->hj_key= keyinfo;

  DBUG_RETURN(FALSE);
}

Project: server

change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
                         Item *and_father, Item *cond,
                         Item_bool_func2 *field_value_owner,
                         Item *field, Item *value)
{
  if (cond->type() == Item::COND_ITEM)
  {
    bool and_level= ((Item_cond*) cond)->functype() ==
      Item_func::COND_AND_FUNC;
    List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
    Item *item;
    while ((item=li++))
      change_cond_ref_to_const(thd, save_list,and_level ? cond : item, item,
			       field_value_owner, field, value);
    return;
  }
  if (cond->eq_cmp_result() == Item::COND_OK)
    return;					// Not a boolean function

  Item_bool_func2 *func=  (Item_bool_func2*) cond;
  Item **args= func->arguments();
  Item *left_item=  args[0];
  Item *right_item= args[1];
  Item_func::Functype functype=  func->functype();

  if (can_change_cond_ref_to_const(func, right_item, left_item,
                                   field_value_owner, field, value))
  {
    Item *tmp=value->clone_item(thd);
    if (tmp)
    {
      tmp->collation.set(right_item->collation);
      thd->change_item_tree(args + 1, tmp);
      func->update_used_tables();
      if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC)
	  && and_father != cond && !left_item->const_item())
      {
	cond->marker=1;
	COND_CMP *tmp2;
        /* Will work, even if malloc would fail */
        if ((tmp2= new (thd->mem_root) COND_CMP(and_father, func)))
	  save_list->push_back(tmp2);
      }
      /*
        LIKE can be optimized for BINARY/VARBINARY/BLOB columns, e.g.:

        from: WHERE CONCAT(c1)='const1' AND CONCAT(c1) LIKE 'const2'
          to: WHERE CONCAT(c1)='const1' AND 'const1' LIKE 'const2'

        So make sure to use set_cmp_func() only for non-LIKE operators.
      */
      if (functype != Item_func::LIKE_FUNC)
        ((Item_bool_rowready_func2*) func)->set_cmp_func();
    }
  }
  else if (can_change_cond_ref_to_const(func, left_item, right_item,
                                        field_value_owner, field, value))
  {
    Item *tmp= value->clone_item(thd);
    if (tmp)
    {
      tmp->collation.set(left_item->collation);
      thd->change_item_tree(args, tmp);
      value= tmp;
      func->update_used_tables();
      if ((functype == Item_func::EQ_FUNC || functype == Item_func::EQUAL_FUNC)
	  && and_father != cond && !right_item->const_item())
      {
        args[0]= args[1];                       // For easy check
        thd->change_item_tree(args + 1, value);
	cond->marker=1;
	COND_CMP *tmp2;
        /* Will work, even if malloc would fail */
        if ((tmp2=new (thd->mem_root) COND_CMP(and_father, func)))
	  save_list->push_back(tmp2);
      }
      if (functype != Item_func::LIKE_FUNC)
        ((Item_bool_rowready_func2*) func)->set_cmp_func();
    }
  }
}

Project: server

update_sum_func(Item_sum **func_ptr)
{
  Item_sum *func;
  for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
    if (func->aggregator_add())
      return 1;
  return 0;
}

Project: server

double table_multi_eq_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
                                       table_map rem_tables, uint keyparts,
                                       uint16 *ref_keyuse_steps)
{
  double sel= 1.0;
  COND_EQUAL *cond_equal= join->cond_equal;

  if (!cond_equal || !cond_equal->current_level.elements)
    return sel;

   if (!s->keyuse)
    return sel;

  Item_equal *item_equal;
  List_iterator_fast<Item_equal> it(cond_equal->current_level);
  TABLE *table= s->table;
  table_map table_bit= table->map;
  POSITION *pos= &join->positions[idx];
  
  while ((item_equal= it++))
  { 
    /* 
      Check whether we need to take into account the selectivity of
      multiple equality item_equal. If this is the case multiply
      the current value of sel by this selectivity
    */
    table_map used_tables= item_equal->used_tables();
    if (!(used_tables & table_bit))
      continue;
    if (item_equal->get_const())
      continue;

    bool adjust_sel= FALSE;
    Item_equal_fields_iterator fi(*item_equal);
    while((fi++) && !adjust_sel)
    {
      Field *fld= fi.get_curr_field();
      if (fld->table->map != table_bit)
        continue;
      if (pos->key == 0)
        adjust_sel= TRUE;
      else
      {
        uint i;
        KEYUSE *keyuse= pos->key;
        uint key= keyuse->key;
        for (i= 0; i < keyparts; i++)
	{
          if (i > 0)
            keyuse+= ref_keyuse_steps[i-1];
          uint fldno;
          if (is_hash_join_key_no(key))
	    fldno= keyuse->keypart;
          else
            fldno= table->key_info[key].key_part[i].fieldnr - 1;        
          if (fld->field_index == fldno)
            break;
        }
        keyuse= pos->key;

        if (i == keyparts)
	{
          /* 
            Field fld is included in multiple equality item_equal
            and is not a part of the ref key.
            The selectivity of the multiple equality must be taken
            into account unless one of the ref arguments is
            equal to fld.  
	  */
          adjust_sel= TRUE;
          for (uint j= 0; j < keyparts && adjust_sel; j++)
	  {
            if (j > 0)
              keyuse+= ref_keyuse_steps[j-1];  
            Item *ref_item= keyuse->val;
	    if (ref_item->real_item()->type() == Item::FIELD_ITEM)
	    {
              Item_field *field_item= (Item_field *) (ref_item->real_item());
              if (item_equal->contains(field_item->field))
                adjust_sel= FALSE;              
	    }
          }
        }          
      }
    }
    if (adjust_sel)
    {
      /* 
        If ref == 0 and there are no fields in the multiple equality
        item_equal that belong to the tables joined prior to s
        then the selectivity of multiple equality will be set to 1.0.
      */
      double eq_fld_sel= 1.0;
      fi.rewind();
      while ((fi++))
      {
        double curr_eq_fld_sel;
        Field *fld= fi.get_curr_field();
        if (!(fld->table->map & ~(table_bit | rem_tables)))
          continue;
        curr_eq_fld_sel= get_column_avg_frequency(fld) /
                         fld->table->stat_records();
        if (curr_eq_fld_sel < 1.0)
          set_if_bigger(eq_fld_sel, curr_eq_fld_sel);
      }
      sel*= eq_fld_sel;
    }
  } 
  return sel;
}

Project: server

int JOIN::init_join_caches()
{
  JOIN_TAB *tab;

  for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
       tab;
       tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
  {
    TABLE *table= tab->table;
    if (table->file->keyread_enabled())
    {
      if (!(table->file->index_flags(table->file->keyread, 0, 1) & HA_CLUSTERED_INDEX))
        table->mark_index_columns(table->file->keyread, table->read_set);
    }
    else if ((tab->read_first_record == join_read_first ||
              tab->read_first_record == join_read_last) &&
             !tab->filesort && table->covering_keys.is_set(tab->index) &&
             !table->no_keyread)
    {
      table->prepare_for_keyread(tab->index, table->read_set);
    }
    if (tab->cache && tab->cache->init(select_options & SELECT_DESCRIBE))
      revise_cache_usage(tab);
    else
      tab->remove_redundant_bnl_scan_conds();
  }
  return 0;
}

Project: server

Item_cond_and::add_key_fields(JOIN *join, KEY_FIELD **key_fields,
                              uint *and_level, table_map usable_tables,
                              SARGABLE_PARAM **sargables)
{
  List_iterator_fast<Item> li(*argument_list());
  KEY_FIELD *org_key_fields= *key_fields;

  Item *item;
  while ((item=li++))
    item->add_key_fields(join, key_fields, and_level, usable_tables,
                         sargables);
  for (; org_key_fields != *key_fields ; org_key_fields++)
    org_key_fields->level= *and_level;
}

Project: server

JOIN::optimize_distinct()
{
  for (JOIN_TAB *last_join_tab= join_tab + top_join_tab_count - 1; ;)
  {
    if (select_lex->select_list_tables & last_join_tab->table->map ||
        last_join_tab->use_join_cache)
      break;
    last_join_tab->shortcut_for_distinct= true;
    if (last_join_tab == join_tab)
      break;
    --last_join_tab;
  }

  /* Optimize "select distinct b from t1 order by key_part_1 limit #" */
  if (order && skip_sort_order)
  {
    /* Should already have been optimized away */
    DBUG_ASSERT(ordered_index_usage == ordered_index_order_by);
    if (ordered_index_usage == ordered_index_order_by)
    {
      order= NULL;
    }
  }
}

Project: server

static bool check_row_equality(THD *thd, const Arg_comparator *comparators,
                               Item *left_row, Item_row *right_row,
                               COND_EQUAL *cond_equal, List<Item>* eq_list)
{ 
  uint n= left_row->cols();
  for (uint i= 0 ; i < n; i++)
  {
    bool is_converted;
    Item *left_item= left_row->element_index(i);
    Item *right_item= right_row->element_index(i);
    if (left_item->type() == Item::ROW_ITEM &&
        right_item->type() == Item::ROW_ITEM)
    {
      /*
        Item_splocal for ROW SP variables return Item::ROW_ITEM.
        Here we know that left_item and right_item are not Item_splocal,
        because ROW SP variables with nested ROWs are not supported yet.
        It's safe to cast left_item and right_item to Item_row.
      */
      DBUG_ASSERT(!left_item->get_item_splocal());
      DBUG_ASSERT(!right_item->get_item_splocal());
      is_converted= check_row_equality(thd,
                                       comparators[i].subcomparators(),
                                       (Item_row *) left_item,
                                       (Item_row *) right_item,
			               cond_equal, eq_list);
    }
    else
    { 
      const Arg_comparator *tmp= &comparators[i];
      is_converted= check_simple_equality(thd,
                                          Item::Context(Item::ANY_SUBST,
                                                  tmp->compare_type_handler(),
                                                  tmp->compare_collation()),
                                          left_item, right_item,
                                          cond_equal);
    }  
 
    if (!is_converted)
    {
      Item_func_eq *eq_item;
      if (!(eq_item= new (thd->mem_root) Item_func_eq(thd, left_item, right_item)) ||
          eq_item->set_cmp_func())
        return FALSE;
      eq_item->quick_fix_field();
      eq_list->push_back(eq_item, thd->mem_root);
    }
  }
  return TRUE;
}

Project: server

bool open_tmp_table(TABLE *table)
{
  int error;
  if (unlikely((error= table->file->ha_open(table, table->s->path.str, O_RDWR,
                                            HA_OPEN_TMP_TABLE |
                                            HA_OPEN_INTERNAL_TABLE))))
  {
    table->file->print_error(error, MYF(0)); /* purecov: inspected */
    table->db_stat= 0;
    return 1;
  }
  table->db_stat= HA_OPEN_KEYFILE;
  (void) table->file->extra(HA_EXTRA_QUICK); /* Faster */
  if (!table->is_created())
  {
    table->set_created();
    table->in_use->inc_status_created_tmp_tables();
  }

  return 0;
}

Project: server

bool test_if_use_dynamic_range_scan(JOIN_TAB *join_tab)
{
    return (join_tab->use_quick == 2 && test_if_quick_select(join_tab) > 0);
}

Project: server

static bool get_range_limit_read_cost(const JOIN_TAB *tab, 
                                      const TABLE *table, 
                                      uint keynr, 
                                      ha_rows rows_limit,
                                      double *read_time)
{
  bool res= false;
  /* 
    We need to adjust the estimates if we had a quick select (or ref(const)) on
    index keynr.
  */
  if (table->quick_keys.is_set(keynr))
  {
    /*
      Start from quick select's rows and cost. These are always cheaper than
      full index scan/cost.
    */
    double best_rows= (double)table->quick_rows[keynr];
    double best_cost= (double)table->quick_costs[keynr];
    
    /*
      Check if ref(const) access was possible on this index. 
    */
    if (tab)
    {
      key_part_map map= 1;
      uint kp;
      /* Find how many key parts would be used by ref(const) */
      for (kp=0; kp < MAX_REF_PARTS; map=map << 1, kp++)
      {
        if (!(table->const_key_parts[keynr] & map))
          break;
      }
      
      if (kp > 0)
      {
        ha_rows ref_rows;
        /*
          Two possible cases:
          1. ref(const) uses the same #key parts as range access. 
          2. ref(const) uses fewer key parts, becasue there is a
            range_cond(key_part+1).
        */
        if (kp == table->quick_key_parts[keynr])
          ref_rows= table->quick_rows[keynr];
        else
          ref_rows= (ha_rows) table->key_info[keynr].actual_rec_per_key(kp-1);

        if (ref_rows > 0)
        {
          double tmp= (double)ref_rows;
          /* Reuse the cost formula from best_access_path: */
          set_if_smaller(tmp, (double) tab->join->thd->variables.max_seeks_for_key);
          if (table->covering_keys.is_set(keynr))
            tmp= table->file->keyread_time(keynr, 1, (ha_rows) tmp);
          else
            tmp= table->file->read_time(keynr, 1,
                                        (ha_rows) MY_MIN(tmp,tab->worst_seeks));
          if (tmp < best_cost)
          {
            best_cost= tmp;
            best_rows= (double)ref_rows;
          }
        }
      }
    }
 
    if (best_rows > rows_limit)
    {
      /*
        LIMIT clause specifies that we will need to read fewer records than
        quick select will return. Assume that quick select's cost is
        proportional to the number of records we need to return (e.g. if we 
        only need 1/3rd of records, it will cost us 1/3rd of quick select's
        read time)
      */
      best_cost *= rows_limit / best_rows;
    }
    *read_time= best_cost;
    res= true;
  }
  return res;
}

Project: server

Item *remove_pushed_top_conjuncts(THD *thd, Item *cond)
{
  if (cond->get_extraction_flag() == FULL_EXTRACTION_FL)
  {
    cond->clear_extraction_flag();
    return 0; 
  }
  if (cond->type() == Item::COND_ITEM)
  {
    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
    {
      List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
      Item *item;
      while ((item= li++))
      {
	if (item->get_extraction_flag() == FULL_EXTRACTION_FL)
	{
	  item->clear_extraction_flag();
	  li.remove();
	}
      }
      switch (((Item_cond*) cond)->argument_list()->elements) 
      {
      case 0:
	return 0;			
      case 1:
	return ((Item_cond*) cond)->argument_list()->head();
      default:
	return cond;
      }
    }
  }
  return cond;
}

Project: server

Item_func_null_predicate::add_key_fields(JOIN *join, KEY_FIELD **key_fields,
                                         uint *and_level,
                                         table_map usable_tables,
                                         SARGABLE_PARAM **sargables)
{
  /* column_name IS [NOT] NULL */
  if (is_local_field(args[0]) && !(used_tables() & OUTER_REF_TABLE_BIT))
  {
    Item *tmp= new (join->thd->mem_root) Item_null(join->thd);
    if (unlikely(!tmp))                       // Should never be true
      return;
    add_key_equal_fields(join, key_fields, *and_level, this,
                         (Item_field*) args[0]->real_item(),
                         functype() == Item_func::ISNULL_FUNC,
                         &tmp, 1, usable_tables, sargables);
  }
}

Project: server

bool JOIN::get_best_combination()
{
  uint tablenr;
  table_map used_tables;
  JOIN_TAB *j;
  KEYUSE *keyuse;
  DBUG_ENTER("get_best_combination");

   /*
    Additional plan nodes for postjoin tmp tables:
      1? + // For GROUP BY
      1? + // For DISTINCT
      1? + // For aggregation functions aggregated in outer query
           // when used with distinct
      1? + // For ORDER BY
      1?   // buffer result
    Up to 2 tmp tables are actually used, but it's hard to tell exact number
    at this stage.
  */ 
  uint aggr_tables= (group_list ? 1 : 0) +
                    (select_distinct ?
                     (tmp_table_param.using_outer_summary_function ? 2 : 1) : 0) +
                    (order ? 1 : 0) +
       (select_options & (SELECT_BIG_RESULT | OPTION_BUFFER_RESULT) ? 1 : 0) ;
  
  if (aggr_tables == 0)
    aggr_tables= 1; /* For group by pushdown */

  if (select_lex->window_specs.elements)
    aggr_tables++;

  if (aggr_tables > 2)
    aggr_tables= 2;
  if (!(join_tab= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)*
                                        (top_join_tab_count + aggr_tables))))
    DBUG_RETURN(TRUE);

  full_join=0;
  hash_join= FALSE;

  fix_semijoin_strategies_for_picked_join_order(this);
   
  JOIN_TAB_RANGE *root_range;
  if (!(root_range= new (thd->mem_root) JOIN_TAB_RANGE))
    DBUG_RETURN(TRUE);
   root_range->start= join_tab;
  /* root_range->end will be set later */
  join_tab_ranges.empty();

  if (join_tab_ranges.push_back(root_range, thd->mem_root))
    DBUG_RETURN(TRUE);

  JOIN_TAB *sjm_nest_end= NULL;
  JOIN_TAB *sjm_nest_root= NULL;

  for (j=join_tab, tablenr=0 ; tablenr < table_count ; tablenr++,j++)
  {
    TABLE *form;
    POSITION *cur_pos= &best_positions[tablenr];
    if (cur_pos->sj_strategy == SJ_OPT_MATERIALIZE || 
        cur_pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN)
    {
      /*
        Ok, we've entered an SJ-Materialization semi-join (note that this can't
        be done recursively, semi-joins are not allowed to be nested).
        1. Put into main join order a JOIN_TAB that represents a lookup or scan
           in the temptable.
      */
      bzero((void*)j, sizeof(JOIN_TAB));
      j->join= this;
      j->table= NULL; //temporary way to tell SJM tables from others.
      j->ref.key = -1;
      j->on_expr_ref= (Item**) &null_ptr;
      j->keys= key_map(1); /* The unique index is always in 'possible keys' in EXPLAIN */

      /*
        2. Proceed with processing SJM nest's join tabs, putting them into the
           sub-order
      */
      SJ_MATERIALIZATION_INFO *sjm= cur_pos->table->emb_sj_nest->sj_mat_info;
      j->records_read= (sjm->is_sj_scan? sjm->rows : 1);
      j->records= (ha_rows) j->records_read;
      j->cond_selectivity= 1.0;
      JOIN_TAB *jt;
      JOIN_TAB_RANGE *jt_range;
      if (!(jt= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)*sjm->tables)) ||
          !(jt_range= new JOIN_TAB_RANGE))
        DBUG_RETURN(TRUE);
      jt_range->start= jt;
      jt_range->end= jt + sjm->tables;
      join_tab_ranges.push_back(jt_range, thd->mem_root);
      j->bush_children= jt_range;
      sjm_nest_end= jt + sjm->tables;
      sjm_nest_root= j;

      j= jt;
    }
    
    *j= *best_positions[tablenr].table;

    j->bush_root_tab= sjm_nest_root;

    form= table[tablenr]= j->table;
    form->reginfo.join_tab=j;
    DBUG_PRINT("info",("type: %d", j->type));
    if (j->type == JT_CONST)
      goto loop_end;					// Handled in make_join_stat..

    j->loosescan_match_tab= NULL;  //non-nulls will be set later
    j->inside_loosescan_range= FALSE;
    j->ref.key = -1;
    j->ref.key_parts=0;

    if (j->type == JT_SYSTEM)
      goto loop_end;
    if ( !(keyuse= best_positions[tablenr].key))
    {
      j->type=JT_ALL;
      if (best_positions[tablenr].use_join_buffer &&
          tablenr != const_tables)
	full_join= 1;
    }

    /*if (best_positions[tablenr].sj_strategy == SJ_OPT_LOOSE_SCAN)
    {
      DBUG_ASSERT(!keyuse || keyuse->key ==
                             best_positions[tablenr].loosescan_picker.loosescan_key);
      j->index= best_positions[tablenr].loosescan_picker.loosescan_key;
    }*/

    if ((j->type == JT_REF || j->type == JT_EQ_REF) &&
        is_hash_join_key_no(j->ref.key))
      hash_join= TRUE; 

  loop_end:
    /* 
      Save records_read in JOIN_TAB so that select_describe()/etc don't have
      to access join->best_positions[]. 
    */
    j->records_read= best_positions[tablenr].records_read;
    j->cond_selectivity= best_positions[tablenr].cond_selectivity;
    map2table[j->table->tablenr]= j;

    /* If we've reached the end of sjm nest, switch back to main sequence */
    if (j + 1 == sjm_nest_end)
    {
      j->last_leaf_in_bush= TRUE;
      j= sjm_nest_root;
      sjm_nest_root= NULL;
      sjm_nest_end= NULL;
    }
  }
  root_range->end= j;

  used_tables= OUTER_REF_TABLE_BIT;		// Outer row is already read
  for (j=join_tab, tablenr=0 ; tablenr < table_count ; tablenr++,j++)
  {
    if (j->bush_children)
      j= j->bush_children->start;

    used_tables|= j->table->map;
    if (j->type != JT_CONST && j->type != JT_SYSTEM)
    {
      if ((keyuse= best_positions[tablenr].key) &&
          create_ref_for_key(this, j, keyuse, TRUE, used_tables))
        DBUG_RETURN(TRUE);              // Something went wrong
    }
    if (j->last_leaf_in_bush)
      j= j->bush_root_tab;
  }
 
  top_join_tab_count= (uint)(join_tab_ranges.head()->end - 
                      join_tab_ranges.head()->start);

  update_depend_map(this);
  DBUG_RETURN(0);
}

Project: server

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

  join->return_tab= 0;

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

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

  if (options & SELECT_NO_JOIN_CACHE)
    goto no_join_cache;

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

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

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

  /*
    Non-linked join buffers can't guarantee one match
  */
  if (tab->is_nested_inner())
  {
    if (force_unlinked_cache || cache_level == 1)
      goto no_join_cache;
    if (cache_level & 1)
      cache_level--;
  }
    
  /*
    Don't use BKA for materialized tables. We could actually have a
    meaningful use of BKA when linked join buffers are used.

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

  /*
    Don't use join buffering if we're dictated not to by no_jbuf_after
    (This is not meaningfully used currently)
  */
  if (table_index > no_jbuf_after)
    goto no_join_cache;
  
  /*
    TODO: BNL join buffer should be perfectly ok with tab->bush_children.
  */
  if (tab->loosescan_match_tab || tab->bush_children)
    goto no_join_cache;

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

  prev_cache= prev_tab->cache;

  switch (tab->type) {
  case JT_ALL:
    if (cache_level == 1)
      prev_cache= 0;
    if ((tab->cache= new (root) JOIN_CACHE_BNL(join, tab, prev_cache)))
    {
      tab->icp_other_tables_ok= FALSE;
      /* If make_join_select() hasn't called make_scan_filter(), do it now */
      if (!tab->cache_select && tab->make_scan_filter())
        goto no_join_cache;
      return (2 - MY_TEST(!prev_cache));
    }
    goto no_join_cache;
  case JT_SYSTEM:
  case JT_CONST:
  case JT_REF:
  case JT_EQ_REF:
    if (cache_level <=2 || (no_hashed_cache && no_bka_cache))
      goto no_join_cache;
    if (tab->ref.is_access_triggered())
      goto no_join_cache;

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

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

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

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

Project: server

bool JOIN::make_sum_func_list(List<Item> &field_list,
                              List<Item> &send_result_set_metadata,
			      bool before_group_by, bool recompute)
{
  List_iterator_fast<Item> it(field_list);
  Item_sum **func;
  Item *item;
  DBUG_ENTER("make_sum_func_list");

  if (*sum_funcs && !recompute)
    DBUG_RETURN(FALSE); /* We have already initialized sum_funcs. */

  func= sum_funcs;
  while ((item=it++))
  {
    if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item() &&
        (!((Item_sum*) item)->depended_from() ||
         ((Item_sum *)item)->depended_from() == select_lex))
      *func++= (Item_sum*) item;
  }
  if (before_group_by && rollup.state == ROLLUP::STATE_INITED)
  {
    rollup.state= ROLLUP::STATE_READY;
    if (rollup_make_fields(field_list, send_result_set_metadata, &func))
      DBUG_RETURN(TRUE);			// Should never happen
  }
  else if (rollup.state == ROLLUP::STATE_NONE)
  {
    for (uint i=0 ; i <= send_group_parts ;i++)
      sum_funcs_end[i]= func;
  }
  else if (rollup.state == ROLLUP::STATE_READY)
    DBUG_RETURN(FALSE);                         // Don't put end marker
  *func=0;					// End marker
  DBUG_RETURN(FALSE);
}

Project: server

COND *Item_equal::build_equal_items(THD *thd, COND_EQUAL *inherited,
                                    bool link_item_fields,
                                    COND_EQUAL **cond_equal_ref)
{
  COND *cond= Item_func::build_equal_items(thd, inherited, link_item_fields,
                                           cond_equal_ref);
  if (cond_equal_ref)
    *cond_equal_ref= new (thd->mem_root) COND_EQUAL(this, thd->mem_root);
  return cond;
}

Project: server

static void clear_tables(JOIN *join, table_map *cleared_tables)
{
  /* 
    must clear only the non-const tables as const tables are not re-calculated.
  */
  for (uint i= 0 ; i < join->table_count ; i++)
  {
    TABLE *table= join->table[i];

    if (table->null_row)
      continue;                                 // Nothing more to do
    if (!(table->map & join->const_table_map) || cleared_tables)
    {
      if (cleared_tables)
      {
        (*cleared_tables)|= (((table_map) 1) << i);
        if (table->s->null_bytes)
        {
          /*
            Remember null bits for the record so that we can restore the
            original const record in unclear_tables()
          */
          memcpy(table->record[1], table->null_flags, table->s->null_bytes);
        }
      }
      mark_as_null_row(table);                  // All fields are NULL
    }
  }
}

Project: server

int print_explain_message_line(select_result_sink *result, 
                               uint8 options, bool is_analyze,
                               uint select_number,
                               const char *select_type,
                               ha_rows *rows,
                               const char *message)
{
  THD *thd= result->thd;
  MEM_ROOT *mem_root= thd->mem_root;
  Item *item_null= new (mem_root) Item_null(thd);
  List<Item> item_list;

  item_list.push_back(new (mem_root) Item_int(thd, (int32) select_number),
                      mem_root);
  item_list.push_back(new (mem_root) Item_string_sys(thd, select_type),
                      mem_root);
  /* `table` */
  item_list.push_back(item_null, mem_root);
  
  /* `partitions` */
  if (options & DESCRIBE_PARTITIONS)
    item_list.push_back(item_null, mem_root);
  
  /* type, possible_keys, key, key_len, ref */
  for (uint i=0 ; i < 5; i++)
    item_list.push_back(item_null, mem_root);

  /* `rows` */
  if (rows)
  {
    item_list.push_back(new (mem_root) Item_int(thd, *rows,
                                     MY_INT64_NUM_DECIMAL_DIGITS),
                        mem_root);
  }
  else
    item_list.push_back(item_null, mem_root);

  /* `r_rows` */
  if (is_analyze)
    item_list.push_back(item_null, mem_root);

  /* `filtered` */
  if (is_analyze || options & DESCRIBE_EXTENDED)
    item_list.push_back(item_null, mem_root);
  
  /* `r_filtered` */
  if (is_analyze)
    item_list.push_back(item_null, mem_root);

  /* `Extra` */
  if (message)
    item_list.push_back(new (mem_root) Item_string_sys(thd, message),
                        mem_root);
  else
    item_list.push_back(item_null, mem_root);

  if (unlikely(thd->is_fatal_error) || unlikely(result->send_data(item_list)))
    return 1;
  return 0;
}

Project: server

Item_equal::add_key_fields(JOIN *join, KEY_FIELD **key_fields,
                           uint *and_level, table_map usable_tables,
                           SARGABLE_PARAM **sargables)
{
  Item *const_item2= get_const();
  Item_equal_fields_iterator it(*this);
  if (const_item2)
  {
    
    /*
      For each field field1 from item_equal consider the equality 
      field1=const_item as a condition allowing an index access of the table
      with field1 by the keys value of field1.
    */   
    while (it++)
    {
      Field *equal_field= it.get_curr_field();
      add_key_field(join, key_fields, *and_level, this, equal_field,
                    TRUE, &const_item2, 1, usable_tables, sargables);
    }
  }
  else 
  {
    /*
      Consider all pairs of different fields included into item_equal.
      For each of them (field1, field1) consider the equality 
      field1=field2 as a condition allowing an index access of the table
      with field1 by the keys value of field2.
    */   
    Item_equal_fields_iterator fi(*this);
    while (fi++)
    {
      Field *field= fi.get_curr_field();
      Item *item;
      while ((item= it++))
      {
        Field *equal_field= it.get_curr_field();
        if (!field->eq(equal_field))
        {
          add_key_field(join, key_fields, *and_level, this, field,
                        TRUE, &item, 1, usable_tables,
                        sargables);
        }
      }
      it.rewind();
    }
  }
}

Project: server

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

Project: server

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

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

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

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

Project: server

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

  /*
    Local SP variables may be int but are expressions, not positions.
    (And they can't be used before fix_fields is called for them).
  */
  if (order_item->type() == Item::INT_ITEM && order_item->basic_const_item() &&
      !from_window_spec)
  {						/* Order by position */
    uint count;
    if (order->counter_used)
      count= order->counter; // counter was once resolved
    else
      count= (uint) order_item->val_int();
    if (!count || count > fields.elements)
    {
      my_error(ER_BAD_FIELD_ERROR, MYF(0),
               order_item->full_name(), thd->where);
      return TRUE;
    }
    thd->change_item_tree((Item **)&order->item, (Item *)&ref_pointer_array[count - 1]);
    order->in_field_list= 1;
    order->counter= count;
    order->counter_used= 1;
    return FALSE;
  }
  /* Lookup the current GROUP/ORDER field in the SELECT clause. */
  select_item= find_item_in_list(order_item, fields, &counter,
                                 REPORT_EXCEPT_NOT_FOUND, &resolution);
  if (!select_item)
    return TRUE; /* The item is not unique, or some other error occurred. */


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

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

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

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

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

  if (!add_to_all_fields)
    return FALSE;

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

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

Project: server

bool Virtual_tmp_table::sp_set_all_fields_from_item_list(THD *thd,
                                                         List<Item> &items)
{
  DBUG_ASSERT(s->fields == items.elements);
  List_iterator<Item> it(items);
  Item *item;
  for (uint i= 0 ; (item= it++) ; i++)
  {
    if (field[i]->sp_prepare_and_store_item(thd, &item))
      return true;
  }
  return false;
}

Project: server

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

Project: server

static void free_blobs(Field **ptr)
{
  for (; *ptr ; ptr++)
  {
    if ((*ptr)->flags & BLOB_FLAG)
      ((Field_blob *) (*ptr))->free();
  }
}

Project: server

prev_record_reads(const POSITION *positions, uint idx, table_map found_ref)
{
  double found=1.0;
  const POSITION *pos_end= positions - 1;
  for (const POSITION *pos= positions + idx - 1; pos != pos_end; pos--)
  {
    if (pos->table->table->map & found_ref)
    {
      found_ref|= pos->ref_depend_map;
      /* 
        For the case of "t1 LEFT JOIN t2 ON ..." where t2 is a const table 
        with no matching row we will get position[t2].records_read==0. 
        Actually the size of output is one null-complemented row, therefore 
        we will use value of 1 whenever we get records_read==0.

        Note
        - the above case can't occur if inner part of outer join has more 
          than one table: table with no matches will not be marked as const.

        - Ideally we should add 1 to records_read for every possible null-
          complemented row. We're not doing it because: 1. it will require
          non-trivial code and add overhead. 2. The value of records_read
          is an inprecise estimate and adding 1 (or, in the worst case,
          #max_nested_outer_joins=64-1) will not make it any more precise.
      */
      if (pos->records_read)
      {
        found= COST_MULT(found, pos->records_read);
        found*= pos->cond_selectivity;
      }
     }
  }
  return found;
}

Project: server

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

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

    bzero(seg, sizeof(*seg) * keyinfo->user_defined_key_parts);
    /*
       Note that a similar check is performed during
       subquery_types_allow_materialization. See MDEV-7122 for more details as
       to why. Whenever this changes, it must be updated there as well, for
       all tmp_table engines.
    */
    if (keyinfo->key_length > table->file->max_key_length() ||
	keyinfo->user_defined_key_parts > table->file->max_key_parts() ||
	share->uniques)
    {
      if (!share->uniques && !(keyinfo->flags & HA_NOSAME))
      {
        my_error(ER_INTERNAL_ERROR, MYF(0),
                 "Using too big key for internal temp tables");
        DBUG_RETURN(1);
      }

      /* Can't create a key; Make a unique constraint instead of a key */
      share->keys=    0;
      share->uniques= 1;
      using_unique_constraint=1;
      bzero((char*) &uniquedef,sizeof(uniquedef));
      uniquedef.keysegs=keyinfo->user_defined_key_parts;
      uniquedef.seg=seg;
      uniquedef.null_are_equal=1;

      /* Create extra column for hash value */
      bzero((uchar*) *recinfo,sizeof(**recinfo));
      (*recinfo)->type=   FIELD_CHECK;
      (*recinfo)->length= MARIA_UNIQUE_HASH_LENGTH;
      (*recinfo)++;

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

  /*
    The logic for choosing the record format:
    The STATIC_RECORD format is the fastest one, because it's so simple,
    so we use this by default for short rows.
    BLOCK_RECORD caches both row and data, so this is generally faster than
    DYNAMIC_RECORD. The one exception is when we write to tmp table and
    want to use keys for duplicate elimination as with BLOCK RECORD
    we first write the row, then check for key conflicts and then we have to
    delete the row.  The cases when this can happen is when there is
    a group by and no sum functions or if distinct is used.
  */
  {
    enum data_file_type file_type= table->no_rows ? NO_RECORD :
        (share->reclength < 64 && !share->blob_fields ? STATIC_RECORD :
         table->used_for_duplicate_elimination ? DYNAMIC_RECORD : BLOCK_RECORD);
    uint create_flags= HA_CREATE_TMP_TABLE | HA_CREATE_INTERNAL_TABLE |
        (table->keep_row_order ? HA_PRESERVE_INSERT_ORDER : 0);

    if (file_type != NO_RECORD && encrypt_tmp_disk_tables)
    {
      /* encryption is only supported for BLOCK_RECORD */
      file_type= BLOCK_RECORD;
      if (table->used_for_duplicate_elimination)
      {
        /*
          sql-layer expect the last column to be stored/restored also
          when it's null.

          This is probably a bug (that sql-layer doesn't annotate
          the column as not-null) but both heap, aria-static, aria-dynamic and
          myisam has this property. aria-block_record does not since it
          does not store null-columns at all.
          Emulate behaviour by making column not-nullable when creating the
          table.
        */
        uint cols= (uint)(*recinfo-start_recinfo);
        start_recinfo[cols-1].null_bit= 0;
      }
    }

    if (unlikely((error= maria_create(share->path.str, file_type, share->keys,
                                      &keydef, (uint) (*recinfo-start_recinfo),
                                      start_recinfo, share->uniques, &uniquedef,
                                      &create_info, create_flags))))
    {
      table->file->print_error(error,MYF(0));	/* purecov: inspected */
      table->db_stat=0;
      goto err;
    }
  }

  table->in_use->inc_status_created_tmp_disk_tables();
  table->in_use->inc_status_created_tmp_tables();
  share->db_record_offset= 1;
  table->set_created();
  DBUG_RETURN(0);
 err:
  DBUG_RETURN(1);
}

Project: server

static bool compare_record(TABLE *table, Field **ptr)
{
  for (; *ptr ; ptr++)
  {
    Field *f= *ptr;
    if (f->is_null() != f->is_null(table->s->rec_buff_length) ||
        (!f->is_null() && f->cmp_offset(table->s->rec_buff_length)))
      return 1;
  }
  return 0;
}

Project: server

double JOIN::get_examined_rows()
{
  double examined_rows;
  double prev_fanout= 1;
  double records;
  JOIN_TAB *tab= first_breadth_first_tab();
  JOIN_TAB *prev_tab= tab;

  records= (double)tab->get_examined_rows();

  while ((tab= next_breadth_first_tab(first_breadth_first_tab(),
                                      top_join_tab_count, tab)))
  {
    prev_fanout= COST_MULT(prev_fanout, prev_tab->records_read);
    records=
      COST_ADD(records,
               COST_MULT((double) (tab->get_examined_rows()), prev_fanout));
    prev_tab= tab;
  }
  examined_rows= (double)
    (records > (double) HA_ROWS_MAX ? HA_ROWS_MAX : (ha_rows) records);
  return examined_rows;
}

Project: server

bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite,
                             bool need_tmp_table, bool need_order, 
                             bool distinct)
{
  /*
    If there is SELECT in this statement with the same number it must be the
    same SELECT
  */
  DBUG_SLOW_ASSERT(select_lex->select_number == UINT_MAX ||
              select_lex->select_number == INT_MAX ||
              !output ||
              !output->get_select(select_lex->select_number) ||
              output->get_select(select_lex->select_number)->select_lex ==
                select_lex);

  if (select_lex->select_number != UINT_MAX && 
      select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ && 
      have_query_plan != JOIN::QEP_NOT_PRESENT_YET && 
      have_query_plan != JOIN::QEP_DELETED &&  // this happens when there was 
                                               // no QEP ever, but then
                                               //cleanup() is called multiple times
      output && // for "SET" command in SPs.
      (can_overwrite? true: !output->get_select(select_lex->select_number)))
  {
    const char *message= NULL;
    if (!table_count || !tables_list || zero_result_cause)
    {
      /* It's a degenerate join */
      message= zero_result_cause ? zero_result_cause : "No tables used";
    }
    return save_explain_data_intern(thd->lex->explain, need_tmp_table, need_order,
                                    distinct, message);
  }
  
  /*
    Can have join_tab==NULL for degenerate cases (e.g. SELECT .. UNION ... SELECT LIMIT 0)
  */
  if (select_lex == select_lex->master_unit()->fake_select_lex && join_tab)
  {
    /* 
      This is fake_select_lex. It has no query plan, but we need to set up a
      tracker for ANALYZE 
    */
    uint nr= select_lex->master_unit()->first_select()->select_number;
    Explain_union *eu= output->get_union(nr);
    explain= &eu->fake_select_lex_explain;
    join_tab[0].tracker= eu->get_fake_select_lex_tracker();
    for (uint i=0 ; i < exec_join_tab_cnt() + aggr_tables; i++)
    {
      if (join_tab[i].filesort)
      {
        if (!(join_tab[i].filesort->tracker=
              new Filesort_tracker(thd->lex->analyze_stmt)))
          return 1;
      }
    }
  }
  return 0;
}

Project: server

test_if_equality_guarantees_uniqueness(Item *l, Item *r)
{
  return (r->const_item() || !(r->used_tables() & ~OUTER_REF_TABLE_BIT)) &&
    item_cmp_type(l, r) == l->cmp_type() &&
    (l->cmp_type() != STRING_RESULT ||
     l->collation.collation == r->collation.collation);
}

Project: server

update_tmptable_sum_func(Item_sum **func_ptr,
			 TABLE *tmp_table __attribute__((unused)))
{
  Item_sum *func;
  while ((func= *(func_ptr++)))
    func->update_field();
}

Project: server

join_read_always_key(JOIN_TAB *tab)
{
  int error;
  TABLE *table= tab->table;

  /* Initialize the index first */
  if (!table->file->inited)
  {
    if (unlikely((error= table->file->ha_index_init(tab->ref.key,
                                                    tab->sorted))))
    {
      (void) report_error(table, error);
      return 1;
    }
  }

  if (unlikely(cp_buffer_from_ref(tab->join->thd, table, &tab->ref)))
    return -1;
  if (unlikely((error=
                table->file->prepare_index_key_scan_map(tab->ref.key_buff,
                                                        make_prev_keypart_map(tab->ref.key_parts)))))
  {
    report_error(table,error);
    return -1;
  }
  if ((error= table->file->ha_index_read_map(table->record[0],
                                             tab->ref.key_buff,
                                             make_prev_keypart_map(tab->ref.key_parts),
                                             HA_READ_KEY_EXACT)))
  {
    if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
      return report_error(table, error);
    return -1; /* purecov: inspected */
  }
  return 0;
}

Project: server

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

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

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

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

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

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

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

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

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

Project: server

bool JOIN::rollup_init()
{
  uint i,j;
  Item **ref_array;

  tmp_table_param.quick_group= 0;	// Can't create groups in tmp table
  rollup.state= ROLLUP::STATE_INITED;

  /*
    Create pointers to the different sum function groups
    These are updated by rollup_make_fields()
  */
  tmp_table_param.group_parts= send_group_parts;

  Item_null_result **null_items=
    static_cast<Item_null_result**>(thd->alloc(sizeof(Item*)*send_group_parts));

  rollup.null_items= Item_null_array(null_items, send_group_parts);
  rollup.ref_pointer_arrays=
    static_cast<Ref_ptr_array*>
    (thd->alloc((sizeof(Ref_ptr_array) +
                 all_fields.elements * sizeof(Item*)) * send_group_parts));
  rollup.fields=
    static_cast<List<Item>*>(thd->alloc(sizeof(List<Item>) * send_group_parts));

  if (!null_items || !rollup.ref_pointer_arrays || !rollup.fields)
    return true;

  ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts);


  /*
    Prepare space for field list for the different levels
    These will be filled up in rollup_make_fields()
  */
  for (i= 0 ; i < send_group_parts ; i++)
  {
    if (!(rollup.null_items[i]= new (thd->mem_root) Item_null_result(thd)))
      return true;

    List<Item> *rollup_fields= &rollup.fields[i];
    rollup_fields->empty();
    rollup.ref_pointer_arrays[i]= Ref_ptr_array(ref_array, all_fields.elements);
    ref_array+= all_fields.elements;
  }
  for (i= 0 ; i < send_group_parts; i++)
  {
    for (j=0 ; j < fields_list.elements ; j++)
      rollup.fields[i].push_back(rollup.null_items[i], thd->mem_root);
  }
  List_iterator<Item> it(all_fields);
  Item *item;
  while ((item= it++))
  {
    ORDER *group_tmp;
    bool found_in_group= 0;

    for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next)
    {
      if (*group_tmp->item == item)
      {
        item->maybe_null= 1;
        item->in_rollup= 1;
        found_in_group= 1;
        break;
      }
    }
    if (item->type() == Item::FUNC_ITEM && !found_in_group)
    {
      bool changed= FALSE;
      if (change_group_ref(thd, (Item_func *) item, group_list, &changed))
        return 1;
      /*
        We have to prevent creation of a field in a temporary table for
        an expression that contains GROUP BY attributes.
        Marking the expression item as 'with_sum_func' will ensure this.
      */ 
      if (changed)
        item->with_sum_func= 1;
    }
  }
  return 0;
}

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

Project: server

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

Project: server

test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
	       const key_map *usable_keys)
{
  uint nr;
  uint min_length= (uint) ~0;
  uint best= MAX_KEY;
  KEY_PART_INFO *ref_key_part= table->key_info[ref].key_part;
  KEY_PART_INFO *ref_key_part_end= ref_key_part + ref_key_parts;
  
  /*
    Find the shortest key that
    - produces the required ordering
    - has key #ref (up to ref_key_parts) as its subkey.
  */
  for (nr= 0 ; nr < table->s->keys ; nr++)
  {
    if (usable_keys->is_set(nr) &&
	table->key_info[nr].key_length < min_length &&
	table->key_info[nr].user_defined_key_parts >= ref_key_parts &&
	is_subkey(table->key_info[nr].key_part, ref_key_part,
		  ref_key_part_end) &&
	test_if_order_by_key(NULL, order, table, nr))
    {
      min_length= table->key_info[nr].key_length;
      best= nr;
    }
  }
  return best;
}

Project: server

static void create_tmp_field_from_item_finalize(THD *thd,
                                                Field *new_field,
                                                Item *item,
                                                Item ***copy_func,
                                                bool modify_item)
{
  if (copy_func &&
      (item->is_result_field() ||
       (item->real_item()->is_result_field())))
    *((*copy_func)++) = item;			// Save for copy_funcs
  if (modify_item)
    item->set_result_field(new_field);
  if (item->type() == Item::NULL_ITEM)
    new_field->is_created_from_null_item= TRUE;
}

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;
    MEM_CHECK_DEFINED(table->record[0], table->s->reclength);
  }
  if (open_tmp_table(table))
    return TRUE;

  return FALSE;
}

Project: server

determine_search_depth(JOIN *join)
{
  uint table_count=  join->table_count - join->const_tables;
  uint search_depth;
  /* TODO: this value should be determined dynamically, based on statistics: */
  uint max_tables_for_exhaustive_opt= 7;

  if (table_count <= max_tables_for_exhaustive_opt)
    search_depth= table_count+1; // use exhaustive for small number of tables
  else
    /*
      TODO: this value could be determined by some mapping of the form:
      depth : table_count -> [max_tables_for_exhaustive_opt..MAX_EXHAUSTIVE]
    */
    search_depth= max_tables_for_exhaustive_opt; // use greedy search

  return search_depth;
}

Project: server

can_change_cond_ref_to_const(Item_bool_func2 *target,
                             Item *target_expr, Item *target_value,
                             Item_bool_func2 *source,
                             Item *source_expr, Item *source_const)
{
  return target_expr->eq(source_expr,0) &&
         target_value != source_const &&
         target->compare_type_handler()->
           can_change_cond_ref_to_const(target, target_expr, target_value,
                                        source, source_expr, source_const);
}

Project: server

add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
            JOIN_TAB *stat,COND *cond,table_map usable_tables)
{
  Item_func_match *cond_func=NULL;

  if (!cond)
    return FALSE;

  if (cond->type() == Item::FUNC_ITEM)
  {
    Item_func *func=(Item_func *)cond;
    Item_func::Functype functype=  func->functype();
    if (functype == Item_func::FT_FUNC)
      cond_func=(Item_func_match *)cond;
    else if (func->argument_count() == 2)
    {
      Item *arg0=(Item *)(func->arguments()[0]),
           *arg1=(Item *)(func->arguments()[1]);
      if (arg1->const_item() && arg1->cols() == 1 &&
           arg0->type() == Item::FUNC_ITEM &&
           ((Item_func *) arg0)->functype() == Item_func::FT_FUNC &&
          ((functype == Item_func::GE_FUNC && arg1->val_real() > 0) ||
           (functype == Item_func::GT_FUNC && arg1->val_real() >=0)))
        cond_func= (Item_func_match *) arg0;
      else if (arg0->const_item() && arg0->cols() == 1 &&
                arg1->type() == Item::FUNC_ITEM &&
                ((Item_func *) arg1)->functype() == Item_func::FT_FUNC &&
               ((functype == Item_func::LE_FUNC && arg0->val_real() > 0) ||
                (functype == Item_func::LT_FUNC && arg0->val_real() >=0)))
        cond_func= (Item_func_match *) arg1;
    }
  }
  else if (cond->type() == Item::COND_ITEM)
  {
    List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());

    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
    {
      Item *item;
      while ((item=li++))
      {
        if (add_ft_keys(keyuse_array,stat,item,usable_tables))
          return TRUE;
      }
    }
  }

  if (!cond_func || cond_func->key == NO_SUCH_KEY ||
      !(usable_tables & cond_func->table->map))
    return FALSE;

  KEYUSE keyuse;
  keyuse.table= cond_func->table;
  keyuse.val =  cond_func;
  keyuse.key =  cond_func->key;
  keyuse.keypart= FT_KEYPART;
  keyuse.used_tables=cond_func->key_item()->used_tables();
  keyuse.optimize= 0;
  keyuse.ref_table_rows= 0;
  keyuse.keypart_map= 0;
  keyuse.sj_pred_no= UINT_MAX;
  keyuse.validity_ref= 0;
  keyuse.null_rejecting= FALSE;
  return insert_dynamic(keyuse_array,(uchar*) &keyuse);
}

Project: server

  COND_CMP(Item *a,Item_bool_func2 *b) :and_level(a),cmp_func(b) {}

Project: server

join_read_last_key(JOIN_TAB *tab)
{
  int error;
  TABLE *table= tab->table;

  if (!table->file->inited &&
      unlikely((error= table->file->ha_index_init(tab->ref.key, tab->sorted))))
  {
    (void) report_error(table, error);
    return 1;
  }

  if (unlikely(cp_buffer_from_ref(tab->join->thd, table, &tab->ref)))
    return -1;
  if (unlikely((error=
                table->file->prepare_index_key_scan_map(tab->ref.key_buff,
                                                        make_prev_keypart_map(tab->ref.key_parts)))) )
  {
    report_error(table,error);
    return -1;
  }
  if (unlikely((error=
                table->file->ha_index_read_map(table->record[0],
                                               tab->ref.key_buff,
                                               make_prev_keypart_map(tab->ref.key_parts),
                                               HA_READ_PREFIX_LAST))))
  {
    if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
      return report_error(table, error);
    return -1; /* purecov: inspected */
  }
  return 0;
}

Project: server

sort_keyuse(KEYUSE *a,KEYUSE *b)
{
  int res;
  if (a->table->tablenr != b->table->tablenr)
    return (int) (a->table->tablenr - b->table->tablenr);
  if (a->key != b->key)
    return (int) (a->key - b->key);
  if (a->key == MAX_KEY && b->key == MAX_KEY && 
      a->used_tables != b->used_tables)
    return (int) ((ulong) a->used_tables - (ulong) b->used_tables);
  if (a->keypart != b->keypart)
    return (int) (a->keypart - b->keypart);
  // Place const values before other ones
  if ((res= MY_TEST((a->used_tables & ~OUTER_REF_TABLE_BIT)) -
       MY_TEST((b->used_tables & ~OUTER_REF_TABLE_BIT))))
    return res;
  /* Place rows that are not 'OPTIMIZE_REF_OR_NULL' first */
  return (int) ((a->optimize & KEY_OPTIMIZE_REF_OR_NULL) -
		(b->optimize & KEY_OPTIMIZE_REF_OR_NULL));
}

Project: server

Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length)
{
  const Type_handler *h= &type_handler_long;
  if (max_char_length() > convert_int_length)
    h= &type_handler_longlong;
  return h->make_and_init_table_field(&name, Record_addr(maybe_null),
                                      *this, table);
}

Project: server

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

  if (unlikely((error= table->file->ha_index_next_same(table->record[0],
                                                       tab->ref.key_buff,
                                                       tab->ref.key_length))))
  {
    if (error != HA_ERR_END_OF_FILE)
      return report_error(table, error);
    table->status= STATUS_GARBAGE;
    return -1;
  }
  return 0;
}

Project: server

static void update_const_equal_items(THD *thd, COND *cond, JOIN_TAB *tab,
                                     bool const_key)
{
  if (!(cond->used_tables() & tab->table->map))
    return;

  if (cond->type() == Item::COND_ITEM)
  {
    List<Item> *cond_list= ((Item_cond*) cond)->argument_list(); 
    List_iterator_fast<Item> li(*cond_list);
    Item *item;
    while ((item= li++))
      update_const_equal_items(thd, item, tab,
                               (((Item_cond*) cond)->top_level() &&
                                ((Item_cond*) cond)->functype() ==
                                Item_func::COND_AND_FUNC));
  }
  else if (cond->type() == Item::FUNC_ITEM && 
           ((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
  {
    Item_equal *item_equal= (Item_equal *) cond;
    bool contained_const= item_equal->get_const() != NULL;
    item_equal->update_const(thd);
    if (!contained_const && item_equal->get_const())
    {
      /* Update keys for range analysis */
      Item_equal_fields_iterator it(*item_equal);
      while (it++)
      {
        Field *field= it.get_curr_field();
        JOIN_TAB *stat= field->table->reginfo.join_tab;
        key_map possible_keys= field->key_start;
        possible_keys.intersect(field->table->keys_in_use_for_query);
        stat[0].const_keys.merge(possible_keys);

        /*
          For each field in the multiple equality (for which we know that it 
          is a constant) we have to find its corresponding key part, and set 
          that key part in const_key_parts.
        */  
        if (!possible_keys.is_clear_all())
        {
          TABLE *field_tab= field->table;
          KEYUSE *use;
          for (use= stat->keyuse; use && use->table == field_tab; use++)
            if (const_key &&
                !use->is_for_hash_join() && possible_keys.is_set(use->key) && 
                field_tab->key_info[use->key].key_part[use->keypart].field ==
                field)
              field_tab->const_key_parts[use->key]|= use->keypart_map;
        }
      }
    }
  }
}

Project: server

static int test_if_order_by_key(JOIN *join,
                                ORDER *order, TABLE *table, uint idx,
				uint *used_key_parts)
{
  KEY_PART_INFO *key_part,*key_part_end;
  key_part=table->key_info[idx].key_part;
  key_part_end=key_part + table->key_info[idx].ext_key_parts;
  key_part_map const_key_parts=table->const_key_parts[idx];
  uint user_defined_kp= table->key_info[idx].user_defined_key_parts;
  int reverse=0;
  uint key_parts;
  bool have_pk_suffix= false;
  uint pk= table->s->primary_key;
  DBUG_ENTER("test_if_order_by_key");
 
  if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && 
      table->key_info[idx].ext_key_part_map &&
      pk != MAX_KEY && pk != idx)
  {
    have_pk_suffix= true;
  }

  for (; order ; order=order->next, const_key_parts>>=1)
  {
    Item_field *item_field= ((Item_field*) (*order->item)->real_item());
    Field *field= item_field->field;
    int flag;

    /*
      Skip key parts that are constants in the WHERE clause.
      These are already skipped in the ORDER BY by const_expression_in_where()
    */
    for (; const_key_parts & 1 ; const_key_parts>>= 1)
      key_part++; 
    
    /*
      This check was in this function historically (although I think it's
      better to check it outside of this function):

      "Test if the primary key parts were all const (i.e. there's one row).
       The sorting doesn't matter"

       So, we're checking that 
       (1) this is an extended key
       (2) we've reached its end
    */
    key_parts= (uint)(key_part - table->key_info[idx].key_part);
    if (have_pk_suffix &&
        reverse == 0 && // all were =const so far
        key_parts == table->key_info[idx].ext_key_parts && 
        table->const_key_parts[pk] == PREV_BITS(uint, 
                                                table->key_info[pk].
                                                user_defined_key_parts))
    {
      key_parts= 0;
      reverse= 1;                           // Key is ok to use
      goto ok;
    }

    if (key_part == key_part_end)
    {
      /*
        There are some items left in ORDER BY that we don't
      */
      DBUG_RETURN(0);
    }

    if (key_part->field != field)
    {
      /*
        Check if there is a multiple equality that allows to infer that field
        and key_part->field are equal 
        (see also: compute_part_of_sort_key_for_equals)
      */
      if (item_field->item_equal && 
          item_field->item_equal->contains(key_part->field))
        field= key_part->field;
    }
    if (key_part->field != field || !field->part_of_sortkey.is_set(idx))
      DBUG_RETURN(0);

    const ORDER::enum_order keypart_order= 
      (key_part->key_part_flag & HA_REVERSE_SORT) ? 
      ORDER::ORDER_DESC : ORDER::ORDER_ASC;
    /* set flag to 1 if we can use read-next on key, else to -1 */
    flag= (order->direction == keypart_order) ? 1 : -1;
    if (reverse && flag != reverse)
      DBUG_RETURN(0);
    reverse=flag;				// Remember if reverse
    if (key_part < key_part_end)
      key_part++;
  }

  key_parts= (uint) (key_part - table->key_info[idx].key_part);

  if (reverse == -1 && 
      !(table->file->index_flags(idx, user_defined_kp-1, 1) & HA_READ_PREV))
    reverse= 0;                               // Index can't be used
  
  if (have_pk_suffix && reverse == -1)
  {
    uint pk_parts= table->key_info[pk].user_defined_key_parts;
    if (!(table->file->index_flags(pk, pk_parts, 1) & HA_READ_PREV))
      reverse= 0;                               // Index can't be used
  }

ok:
  if (used_key_parts != NULL)
    *used_key_parts= key_parts;
  DBUG_RETURN(reverse);
}

Project: server

static void print_table_array(THD *thd, 
                              table_map eliminated_tables,
                              String *str, TABLE_LIST **table, 
                              TABLE_LIST **end,
                              enum_query_type query_type)
{
  (*table)->print(thd, eliminated_tables, str, query_type);

  for (TABLE_LIST **tbl= table + 1; tbl < end; tbl++)
  {
    TABLE_LIST *curr= *tbl;
    
    /*
      The "eliminated_tables &&" check guards againist the case of 
      printing the query for CREATE VIEW. We do that without having run 
      JOIN::optimize() and so will have nested_join->used_tables==0.
    */
    if (eliminated_tables &&
        ((curr->table && (curr->table->map & eliminated_tables)) ||
         (curr->nested_join && !(curr->nested_join->used_tables &
                                ~eliminated_tables))))
    {
      /* as of 5.5, print_join doesnt put eliminated elements into array */
      DBUG_ASSERT(0); 
      continue;
    }

    /* JOIN_TYPE_OUTER is just a marker unrelated to real join */
    if (curr->outer_join & (JOIN_TYPE_LEFT|JOIN_TYPE_RIGHT))
    {
      /* MySQL converts right to left joins */
      str->append(STRING_WITH_LEN(" left join "));
    }
    else if (curr->straight)
      str->append(STRING_WITH_LEN(" straight_join "));
    else if (curr->sj_inner_tables)
      str->append(STRING_WITH_LEN(" semi join "));
    else
      str->append(STRING_WITH_LEN(" join "));
    
    curr->print(thd, eliminated_tables, str, query_type);
    if (curr->on_expr)
    {
      str->append(STRING_WITH_LEN(" on("));
      curr->on_expr->print(str, query_type);
      str->append(')');
    }
  }
}

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
        join->exec_const_cond=
	  make_cond_for_table(thd, cond,
                              join->const_table_map,
                              (table_map) 0, -1, FALSE, FALSE);
        /* Add conditions added by add_not_null_conds(). */
        for (uint i= 0 ; i < join->const_tables ; i++)
          add_cond_and_fix(thd, &join->exec_const_cond,
                           join->join_tab[i].select_cond);

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

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

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

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

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

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

      bool use_quick_range=0;
      COND *tmp;

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

      used_tables|=current_map;

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

      tmp= NULL;

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

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

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

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

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

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

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

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

            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->fixed)
	      sel->cond->quick_fix_field();

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

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

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

Project: server

end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
	       bool end_of_records)
{
  int idx= -1;
  enum_nested_loop_state ok_code= NESTED_LOOP_OK;
  List<Item> *fields= join_tab ? (join_tab-1)->fields : join->fields;
  DBUG_ENTER("end_send_group");

  if (!join->items3.is_null() && !join->set_group_rpa)
  {
    join->set_group_rpa= true;
    join->set_items_ref_array(join->items3);
  }

  if (!join->first_record || end_of_records ||
      (idx=test_if_group_changed(join->group_fields)) >= 0)
  {
    if (!join->group_sent &&
        (join->first_record ||
         (end_of_records && !join->group && !join->group_optimized_away)))
    {
      if (join->procedure)
	join->procedure->end_group();
      if (idx < (int) join->send_group_parts)
      {
	int error=0;
	if (join->procedure)
	{
	  if (join->having && join->having->val_int() == 0)
	    error= -1;				// Didn't satisfy having
 	  else
	  {
	    if (join->do_send_rows)
	      error=join->procedure->send_row(*fields) ? 1 : 0;
	    join->send_records++;
	  }
	  if (end_of_records && join->procedure->end_of_records())
	    error= 1;				// Fatal error
	}
	else
	{
	  if (!join->first_record)
	  {
            List_iterator_fast<Item> it(*join->fields);
            Item *item;
            /* No matching rows for group function */
            join->clear();

            while ((item= it++))
              item->no_rows_in_result();
	  }
	  if (join->having && join->having->val_int() == 0)
	    error= -1;				// Didn't satisfy having
	  else
	  {
	    if (join->do_send_rows)
            {
	      error=join->result->send_data(*fields);
              if (unlikely(error < 0))
              {
                /* Duplicate row, don't count */
                join->duplicate_rows++;
                error= 0;
              }
            }
	    join->send_records++;
            join->group_sent= true;
	  }
	  if (unlikely(join->rollup.state != ROLLUP::STATE_NONE && error <= 0))
	  {
	    if (join->rollup_send_data((uint) (idx+1)))
	      error= 1;
	  }
	}
	if (unlikely(error > 0))
          DBUG_RETURN(NESTED_LOOP_ERROR);        /* purecov: inspected */
	if (end_of_records)
	  DBUG_RETURN(NESTED_LOOP_OK);
	if (join->send_records >= join->unit->select_limit_cnt &&
	    join->do_send_rows)
	{
	  if (!(join->select_options & OPTION_FOUND_ROWS))
	    DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT); // Abort nicely
	  join->do_send_rows=0;
	  join->unit->select_limit_cnt = HA_POS_ERROR;
        }
        else if (join->send_records >= join->fetch_limit)
        {
          /*
            There is a server side cursor and all rows
            for this fetch request are sent.
          */
          /*
            Preventing code duplication. When finished with the group reset
            the group functions and copy_fields. We fall through. bug #11904
          */
          ok_code= NESTED_LOOP_CURSOR_LIMIT;
        }
      }
    }
    else
    {
      if (end_of_records)
	DBUG_RETURN(NESTED_LOOP_OK);
      join->first_record=1;
      (void) test_if_group_changed(join->group_fields);
    }
    if (idx < (int) join->send_group_parts)
    {
      /*
        This branch is executed also for cursors which have finished their
        fetch limit - the reason for ok_code.
      */
      copy_fields(&join->tmp_table_param);
      if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1]))
	DBUG_RETURN(NESTED_LOOP_ERROR);
      if (join->procedure)
	join->procedure->add();
      join->group_sent= false;
      DBUG_RETURN(ok_code);
    }
  }
  if (update_sum_func(join->sum_funcs))
    DBUG_RETURN(NESTED_LOOP_ERROR);
  if (join->procedure)
    join->procedure->add();
  DBUG_RETURN(NESTED_LOOP_OK);
}

Project: server

join_read_next(READ_RECORD *info)
{
  int error;
  if (unlikely((error= info->table->file->ha_index_next(info->record()))))
    return report_error(info->table, error);

  return 0;
}

Project: server

join_read_key(JOIN_TAB *tab)
{
  return join_read_key2(tab->join->thd, tab, tab->table, &tab->ref);
}

Project: server

static bool is_eliminated_table(table_map eliminated_tables, TABLE_LIST *tbl)
{
  return eliminated_tables &&
    ((tbl->table && (tbl->table->map & eliminated_tables)) ||
     (tbl->nested_join && !(tbl->nested_join->used_tables &
                            ~eliminated_tables)));
}

Project: server

bool JOIN_TAB::hash_join_is_possible()
{
  if (type != JT_REF && type != JT_EQ_REF)
    return FALSE;
  if (!is_ref_for_hash_join())
  {
    KEY *keyinfo= table->key_info + ref.key;
    return keyinfo->key_part[0].field->hash_join_is_possible();
  }
  return TRUE;
}

Project: server

JOIN_TAB *first_top_level_tab(JOIN *join, enum enum_with_const_tables const_tbls)
{
  JOIN_TAB *tab= join->join_tab;
  if (const_tbls == WITHOUT_CONST_TABLES)
  {
    if (join->const_tables == join->table_count || !tab)
      return NULL;
    tab += join->const_tables;
  }
  return tab;
}

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

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

Project: server

test_if_group_changed(List<Cached_item> &list)
{
  DBUG_ENTER("test_if_group_changed");
  List_iterator<Cached_item> li(list);
  int idx= -1,i;
  Cached_item *buff;

  for (i=(int) list.elements-1 ; (buff=li++) ; i--)
  {
    if (buff->cmp())
      idx=i;
  }
  DBUG_PRINT("info", ("idx: %d", idx));
  DBUG_RETURN(idx);
}

Project: server

static int compare_embedding_subqueries(JOIN_TAB *jt1, JOIN_TAB *jt2)
{
  /* Determine if the first table is originally from a subquery */
  TABLE_LIST *tbl1= jt1->table->pos_in_table_list;
  uint tbl1_select_no;
  if (tbl1->jtbm_subselect)
  {
    tbl1_select_no= 
      tbl1->jtbm_subselect->unit->first_select()->select_number;
  }
  else if (tbl1->embedding && tbl1->embedding->sj_subq_pred)
  {
    tbl1_select_no= 
      tbl1->embedding->sj_subq_pred->unit->first_select()->select_number;
  }
  else
    tbl1_select_no= 1; /* Top-level */

  /* Same for the second table */
  TABLE_LIST *tbl2= jt2->table->pos_in_table_list;
  uint tbl2_select_no;
  if (tbl2->jtbm_subselect)
  {
    tbl2_select_no= 
      tbl2->jtbm_subselect->unit->first_select()->select_number;
  }
  else if (tbl2->embedding && tbl2->embedding->sj_subq_pred)
  {
    tbl2_select_no= 
      tbl2->embedding->sj_subq_pred->unit->first_select()->select_number;
  }
  else
    tbl2_select_no= 1; /* Top-level */

  /* 
    Put top-level tables in front. Tables from within subqueries must follow,
    grouped by their owner subquery. We don't care about the order that
    subquery groups are in, because choose_initial_table_order() will re-order
    the groups.
  */
  if (tbl1_select_no != tbl2_select_no)
    return tbl1_select_no > tbl2_select_no ? 1 : -1;
  return 0;
}

Project: server

join_read_last(JOIN_TAB *tab)
{
  TABLE *table=tab->table;
  int error= 0;
  DBUG_ENTER("join_read_last");

  DBUG_ASSERT(table->no_keyread ||
              !table->covering_keys.is_set(tab->index) ||
              table->file->keyread == tab->index);
  tab->table->status=0;
  tab->read_record.read_record_func= join_read_prev;
  tab->read_record.table=table;
  if (!table->file->inited)
    error= table->file->ha_index_init(tab->index, 1);
  if (likely(!error))
    error= table->file->prepare_index_scan();
  if (unlikely(error) ||
      unlikely(error= tab->table->file->ha_index_last(tab->table->record[0])))
    DBUG_RETURN(report_error(table, error));

  DBUG_RETURN(0);
}

Project: server

JOIN::add_sorting_to_table(JOIN_TAB *tab, ORDER *order)
{
  tab->filesort= 
    new (thd->mem_root) Filesort(order, HA_POS_ERROR, tab->keep_current_rowid,
                                 tab->select);
  if (!tab->filesort)
    return true;
  /*
    Select was moved to filesort->select to force join_init_read_record to use
    sorted result instead of reading table through select.
  */
  if (tab->select)
  {
    tab->select= NULL;
    tab->set_select_cond(NULL, __LINE__);
  }
  tab->read_first_record= join_init_read_record;
  return false;
}

Project: server

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

Project: server

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

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

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

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

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

Project: server

JOIN_TAB *first_depth_first_tab(JOIN* join)
{
  JOIN_TAB* tab;
  /* This means we're starting the enumeration */
  if (join->const_tables == join->top_join_tab_count || !join->join_tab)
    return NULL;

  tab= join->join_tab + join->const_tables;

  return (tab->bush_children) ? tab->bush_children->start : tab;
}

Project: server

Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
                        Item ***copy_func, Field **from_field,
                        Field **default_field,
                        bool group, bool modify_item,
                        bool table_cant_handle_bit_fields,
                        bool make_copy_field)
{
  Field *result;
  Item::Type orig_type= type;
  Item *orig_item= 0;

  DBUG_ASSERT(thd == table->in_use);

  if (type != Item::FIELD_ITEM &&
      item->real_item()->type() == Item::FIELD_ITEM)
  {
    orig_item= item;
    item= item->real_item();
    type= Item::FIELD_ITEM;
  }

  switch (type) {
  case Item::TYPE_HOLDER:
  case Item::SUM_FUNC_ITEM:
  {
    result= item->create_tmp_field(group, table);
    if (!result)
      my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
    return result;
  }
  case Item::DEFAULT_VALUE_ITEM:
  {
    Field *field= ((Item_default_value*) item)->field;
    if (field->default_value && (field->flags & BLOB_FLAG))
    {
      /*
        We have to use a copy function when using a blob with default value
        as the we have to calcuate the default value before we can use it.
      */
      return create_tmp_field_from_item(thd, item, table,
                                        (make_copy_field ? 0 : copy_func),
                                        modify_item);
    }
  }
  /* Fall through */
  case Item::FIELD_ITEM:
  case Item::CONTEXTUALLY_TYPED_VALUE_ITEM:
  case Item::INSERT_VALUE_ITEM:
  case Item::TRIGGER_FIELD_ITEM:
  {
    Item_field *field= (Item_field*) item;
    bool orig_modify= modify_item;
    if (orig_type == Item::REF_ITEM)
      modify_item= 0;
    /*
      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 (((field->maybe_null && field->in_rollup) ||      
	(thd->create_tmp_table_for_derived  &&    /* for mat. view/dt */
	 orig_item && orig_item->maybe_null)) &&         
        !field->field->maybe_null())
    {
      bool save_maybe_null= FALSE;
      /*
        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.
      */
      if (orig_item)
      {
        save_maybe_null= item->maybe_null;
        item->maybe_null= orig_item->maybe_null;
      }
      result= create_tmp_field_from_item(thd, item, table, NULL,
                                         modify_item);
      *from_field= field->field;
      if (result && modify_item)
        field->result_field= result;
      if (orig_item)
      {
        item->maybe_null= save_maybe_null;
        result->field_name= orig_item->name;
      }
    }
    else if (table_cant_handle_bit_fields && field->field->type() ==
             MYSQL_TYPE_BIT)
    {
      const Type_handler *handler= item->type_handler_long_or_longlong();
      *from_field= field->field;
      if ((result=
             handler->make_and_init_table_field(&item->name,
                                                Record_addr(item->maybe_null),
                                                *item, table)))
        create_tmp_field_from_item_finalize(thd, result, item,
                                            copy_func, modify_item);
      if (result && modify_item)
        field->result_field= result;
    }
    else
    {
      LEX_CSTRING *tmp= orig_item ? &orig_item->name : &item->name;
      result= create_tmp_field_from_field(thd, (*from_field= field->field),
                                          tmp, table,
                                          modify_item ? field :
                                          NULL);
    }

    if (orig_type == Item::REF_ITEM && orig_modify)
      ((Item_ref*)orig_item)->set_result_field(result);
    /*
      Fields that are used as arguments to the DEFAULT() function already have
      their data pointers set to the default value during name resolution. See
      Item_default_value::fix_fields.
    */
    if (orig_type != Item::DEFAULT_VALUE_ITEM && field->field->eq_def(result))
      *default_field= field->field;
    return result;
  }
  /* Fall through */
  case Item::FUNC_ITEM:
    if (((Item_func *) item)->functype() == Item_func::FUNC_SP)
    {
      Item_func_sp *item_func_sp= (Item_func_sp *) item;
      Field *sp_result_field= item_func_sp->get_sp_result_field();

      if (make_copy_field)
      {
        DBUG_ASSERT(item_func_sp->result_field);
        *from_field= item_func_sp->result_field;
      }
      else
      {
        *((*copy_func)++)= item;
      }
      Field *result_field=
        create_tmp_field_from_field(thd,
                                    sp_result_field,
                                    &item_func_sp->name,
                                    table,
                                    NULL);

      if (modify_item)
        item->set_result_field(result_field);

      return result_field;
    }

    /* Fall through */
  case Item::COND_ITEM:
  case Item::SUBSELECT_ITEM:
  case Item::REF_ITEM:
  case Item::EXPR_CACHE_ITEM:
    if (make_copy_field)
    {
      DBUG_ASSERT(((Item_result_field*)item)->result_field);
      *from_field= ((Item_result_field*)item)->result_field;
    }
    /* Fall through */
  case Item::FIELD_AVG_ITEM:
  case Item::FIELD_STD_ITEM:
  case Item::PROC_ITEM:
  case Item::INT_ITEM:
  case Item::REAL_ITEM:
  case Item::DECIMAL_ITEM:
  case Item::STRING_ITEM:
  case Item::DATE_ITEM:
  case Item::NULL_ITEM:
  case Item::VARBIN_ITEM:
  case Item::CACHE_ITEM:
  case Item::WINDOW_FUNC_ITEM: // psergey-winfunc:
  case Item::PARAM_ITEM:
    return create_tmp_field_from_item(thd, item, table,
                                      (make_copy_field ? 0 : copy_func),
                                       modify_item);
  default:					// Dosen't have to be stored
    return 0;
  }
}

Project: server

list_contains_unique_index(TABLE *table,
                          bool (*find_func) (Field *, void *), void *data)
{
  for (uint keynr= 0; keynr < table->s->keys; keynr++)
  {
    if (keynr == table->s->primary_key ||
         (table->key_info[keynr].flags & HA_NOSAME))
    {
      KEY *keyinfo= table->key_info + keynr;
      KEY_PART_INFO *key_part, *key_part_end;

      for (key_part=keyinfo->key_part,
           key_part_end=key_part+ keyinfo->user_defined_key_parts;
           key_part < key_part_end;
           key_part++)
      {
        if (key_part->field->maybe_null() ||
            !find_func(key_part->field, data))
          break;
      }
      if (key_part == key_part_end)
        return 1;
    }
  }
  return 0;
}

Project: server

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

  if (end_of_records)
    DBUG_RETURN(NESTED_LOOP_OK);

  init_tmptable_sum_functions(join->sum_funcs);
  copy_fields(join_tab->tmp_table_param);		// Groups are copied twice.
  if (copy_funcs(join_tab->tmp_table_param->items_to_copy, join->thd))
    DBUG_RETURN(NESTED_LOOP_ERROR);           /* purecov: inspected */

  if (likely(!(error= table->file->ha_write_tmp_row(table->record[0]))))
    join_tab->send_records++;			// New group
  else
  {
    if (unlikely((int) table->file->get_dup_key(error) < 0))
    {
      table->file->print_error(error,MYF(0));	/* purecov: inspected */
      DBUG_RETURN(NESTED_LOOP_ERROR);            /* purecov: inspected */
    }
    /* Prepare table for random positioning */
    bool rnd_inited= (table->file->inited == handler::RND);
    if (!rnd_inited &&
        ((error= table->file->ha_index_end()) ||
         (error= table->file->ha_rnd_init(0))))
    {
      table->file->print_error(error, MYF(0));
      DBUG_RETURN(NESTED_LOOP_ERROR);
    }
    if (unlikely(table->file->ha_rnd_pos(table->record[1],table->file->dup_ref)))
    {
      table->file->print_error(error,MYF(0));	/* purecov: inspected */
      DBUG_RETURN(NESTED_LOOP_ERROR);            /* purecov: inspected */
    }
    restore_record(table,record[1]);
    update_tmptable_sum_func(join->sum_funcs,table);
    if (unlikely((error= table->file->ha_update_tmp_row(table->record[1],
                                                        table->record[0]))))
    {
      table->file->print_error(error,MYF(0));	/* purecov: inspected */
      DBUG_RETURN(NESTED_LOOP_ERROR);            /* purecov: inspected */
    }
    if (!rnd_inited &&
        ((error= table->file->ha_rnd_end()) ||
         (error= table->file->ha_index_init(0, 0))))
    {
      table->file->print_error(error, MYF(0));
      DBUG_RETURN(NESTED_LOOP_ERROR);
    }
  }
  if (unlikely(join->thd->check_killed()))
  {
    DBUG_RETURN(NESTED_LOOP_KILLED);             /* purecov: inspected */
  }
  DBUG_RETURN(NESTED_LOOP_OK);
}

Project: server

int JOIN::rollup_send_data(uint idx)
{
  uint i;
  for (i= send_group_parts ; i-- > idx ; )
  {
    int res= 0;
    /* Get reference pointers to sum functions in place */
    copy_ref_ptr_array(ref_ptrs, rollup.ref_pointer_arrays[i]);
    if ((!having || having->val_int()))
    {
      if (send_records < unit->select_limit_cnt && do_send_rows &&
	  (res= result->send_data(rollup.fields[i])) > 0)
	return 1;
      if (!res)
        send_records++;
    }
  }
  /* Restore ref_pointer_array */
  set_items_ref_array(current_ref_ptrs);
  return 0;
}

Project: server

AGGR_OP::put_record(bool end_of_records)
{
  // Lasy tmp table creation/initialization
  if (!join_tab->table->file->inited)
    if (prepare_tmp_table())
      return NESTED_LOOP_ERROR;
  enum_nested_loop_state rc= (*write_func)(join_tab->join, join_tab,
                                           end_of_records);
  return rc;
}

Project: server

void JOIN::get_partial_cost_and_fanout(int end_tab_idx,
                                       table_map filter_map,
                                       double *read_time_arg, 
                                       double *record_count_arg)
{
  double record_count= 1;
  double read_time= 0.0;
  double sj_inner_fanout= 1.0;
  JOIN_TAB *end_tab= NULL;
  JOIN_TAB *tab;
  int i;
  int last_sj_table= MAX_TABLES;

  /* 
    Handle a special case where the join is degenerate, and produces no
    records
  */
  if (table_count == const_tables)
  {
    *read_time_arg= 0.0;
    /*
      We return 1, because 
       - it is the pessimistic estimate (there might be grouping)
       - it's safer, as we're less likely to hit the edge cases in
         calculations.
    */
    *record_count_arg=1.0;
    return;
  }

  for (tab= first_depth_first_tab(this), i= const_tables;
       tab;
       tab= next_depth_first_tab(this, tab), i++)
  {
    end_tab= tab;
    if (i == end_tab_idx)
      break;
  }

  for (tab= first_depth_first_tab(this), i= const_tables;
       ;
       tab= next_depth_first_tab(this, tab), i++)
  {
    if (end_tab->bush_root_tab && end_tab->bush_root_tab == tab)
    {
      /* 
        We've entered the SJM nest that contains the end_tab. The caller is
        - interested in fanout inside the nest (because that's how many times 
          we'll invoke the attached WHERE conditions)
        - not interested in cost
      */
      record_count= 1.0;
      read_time= 0.0;
    }
    
    /* 
      Ignore fanout (but not cost) from sj-inner tables, as long as 
      the range that processes them finishes before the end_tab
    */
    if (tab->sj_strategy != SJ_OPT_NONE)
    {
      sj_inner_fanout= 1.0;
      last_sj_table= i + tab->n_sj_tables;
    }
    
    table_map cur_table_map;
    if (tab->table)
      cur_table_map= tab->table->map;
    else
    {
      /* This is a SJ-Materialization nest. Check all of its tables */
      TABLE *first_child= tab->bush_children->start->table;
      TABLE_LIST *sjm_nest= first_child->pos_in_table_list->embedding;
      cur_table_map= sjm_nest->nested_join->used_tables;
    }
    if (tab->records_read && (cur_table_map & filter_map))
    {
      record_count= COST_MULT(record_count, tab->records_read);
      read_time= COST_ADD(read_time,
                          COST_ADD(tab->read_time,
                                   record_count / (double) TIME_FOR_COMPARE));
      if (tab->emb_sj_nest)
        sj_inner_fanout= COST_MULT(sj_inner_fanout, tab->records_read);
				     }

    if (i == last_sj_table)
    {
      record_count /= sj_inner_fanout;
      sj_inner_fanout= 1.0;
      last_sj_table= MAX_TABLES;
    }

    if (tab == end_tab)
      break;
  }
  *read_time_arg= read_time;// + record_count / TIME_FOR_COMPARE;
  *record_count_arg= record_count;
}

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
    {
      param->func_count++;
      if (reset_with_sum_func)
	field->with_sum_func=0;
    }
  }
}

Project: server

setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps, uint field_count)
{
  uint bitmap_size= bitmap_buffer_size(field_count);

  DBUG_ASSERT(table->s->virtual_fields == 0 && table->def_vcol_set == 0);

  my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count,
              FALSE);
  bitmaps+= bitmap_size;
  my_bitmap_init(&table->tmp_set,
                 (my_bitmap_map*) bitmaps, field_count, FALSE);
  bitmaps+= bitmap_size;
  my_bitmap_init(&table->eq_join_set,
                 (my_bitmap_map*) bitmaps, field_count, FALSE);
  bitmaps+= bitmap_size;
  my_bitmap_init(&table->cond_set,
                 (my_bitmap_map*) bitmaps, field_count, FALSE);
  bitmaps+= bitmap_size;
  my_bitmap_init(&table->has_value_set,
                 (my_bitmap_map*) bitmaps, field_count, FALSE);
  /* write_set and all_set are copies of read_set */
  table->def_write_set= table->def_read_set;
  table->s->all_set= table->def_read_set;
  bitmap_set_all(&table->s->all_set);
  table->default_column_bitmaps();
}

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);
  return (rc != 0);
}

Project: server

static void unclear_tables(JOIN *join, table_map *cleared_tables)
{
  for (uint i= 0 ; i < join->table_count ; i++)
  {
    if ((*cleared_tables) & (((table_map) 1) << i))
    {
      TABLE *table= join->table[i];
      if (table->s->null_bytes)
        memcpy(table->null_flags, table->record[1], table->s->null_bytes);
      unmark_as_null_row(table);
    }
  }
}

Project: server

join_tab_cmp_embedded_first(const void *emb,  const void* ptr1, const void* ptr2)
{
  const TABLE_LIST *emb_nest= (TABLE_LIST*) emb;
  JOIN_TAB *jt1= *(JOIN_TAB**) ptr1;
  JOIN_TAB *jt2= *(JOIN_TAB**) ptr2;

  if (jt1->emb_sj_nest == emb_nest && jt2->emb_sj_nest != emb_nest)
    return -1;
  if (jt1->emb_sj_nest != emb_nest && jt2->emb_sj_nest == emb_nest)
    return 1;

  if (jt1->dependent & jt2->table->map)
    return 1;
  if (jt2->dependent & jt1->table->map)
    return -1;

  if (jt1->found_records > jt2->found_records)
    return 1;
  if (jt1->found_records < jt2->found_records)
    return -1; 
  
  return jt1 > jt2 ? 1 : (jt1 < jt2 ? -1 : 0);
}

Project: server

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

  cleanup(full);

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

  DBUG_VOID_RETURN;
}

Project: server

int JOIN_TAB::make_scan_filter()
{
  COND *tmp;
  DBUG_ENTER("make_scan_filter");

  Item *cond= is_inner_table_of_outer_join() ?
                *get_first_inner_table()->on_expr_ref : join->conds;
  
  if (cond &&
      (tmp= make_cond_for_table(join->thd, cond,
                               join->const_table_map | table->map,
			       table->map, -1, FALSE, TRUE)))
  {
     DBUG_EXECUTE("where",print_where(tmp,"cache", QT_ORDINARY););
     if (!(cache_select=
          (SQL_SELECT*) join->thd->memdup((uchar*) select, sizeof(SQL_SELECT))))
	DBUG_RETURN(1);
     cache_select->cond= tmp;
     cache_select->read_tables=join->const_table_map;
  }
  DBUG_RETURN(0);
}

Project: server

void JOIN::set_allowed_join_cache_types()
{
  allowed_join_cache_types= 0;
  if (optimizer_flag(thd, OPTIMIZER_SWITCH_JOIN_CACHE_INCREMENTAL))
    allowed_join_cache_types|= JOIN_CACHE_INCREMENTAL_BIT;
  if (optimizer_flag(thd, OPTIMIZER_SWITCH_JOIN_CACHE_HASHED))
    allowed_join_cache_types|= JOIN_CACHE_HASHED_BIT;
  if (optimizer_flag(thd, OPTIMIZER_SWITCH_JOIN_CACHE_BKA))
    allowed_join_cache_types|= JOIN_CACHE_BKA_BIT;
  allowed_semijoin_with_cache=
    optimizer_flag(thd, OPTIMIZER_SWITCH_SEMIJOIN_WITH_CACHE);
  allowed_outer_join_with_cache=
    optimizer_flag(thd, OPTIMIZER_SWITCH_OUTER_JOIN_WITH_CACHE);
  max_allowed_join_cache_level= thd->variables.join_cache_level;
}

Project: server

end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
		bool end_of_records)
{
  TABLE *table= join_tab->table;
  int	  idx= -1;
  DBUG_ENTER("end_write_group");

  if (!join->first_record || end_of_records ||
      (idx=test_if_group_changed(join->group_fields)) >= 0)
  {
    if (join->first_record || (end_of_records && !join->group))
    {
      if (join->procedure)
	join->procedure->end_group();
      int send_group_parts= join->send_group_parts;
      if (idx < send_group_parts)
      {
        if (!join->first_record)
        {
          /* No matching rows for group function */
          join->clear();
        }
        copy_sum_funcs(join->sum_funcs,
                       join->sum_funcs_end[send_group_parts]);
	if (!join_tab->having || join_tab->having->val_int())
	{
          int error= table->file->ha_write_tmp_row(table->record[0]);
          if (unlikely(error) &&
              create_internal_tmp_table_from_heap(join->thd, table,
                                          join_tab->tmp_table_param->start_recinfo,
                                          &join_tab->tmp_table_param->recinfo,
                                                   error, 0, NULL))
	    DBUG_RETURN(NESTED_LOOP_ERROR);
        }
        if (unlikely(join->rollup.state != ROLLUP::STATE_NONE))
	{
          if (unlikely(join->rollup_write_data((uint) (idx+1),
                                               join_tab->tmp_table_param,
                                               table)))
          {
	    DBUG_RETURN(NESTED_LOOP_ERROR);
          }
	}
	if (end_of_records)
	  goto end;
      }
    }
    else
    {
      if (end_of_records)
        goto end;
      join->first_record=1;
      (void) test_if_group_changed(join->group_fields);
    }
    if (idx < (int) join->send_group_parts)
    {
      copy_fields(join_tab->tmp_table_param);
      if (unlikely(copy_funcs(join_tab->tmp_table_param->items_to_copy,
                              join->thd)))
	DBUG_RETURN(NESTED_LOOP_ERROR);
      if (unlikely(init_sum_functions(join->sum_funcs,
                                      join->sum_funcs_end[idx+1])))
	DBUG_RETURN(NESTED_LOOP_ERROR);
      if (unlikely(join->procedure))
	join->procedure->add();
      goto end;
    }
  }
  if (unlikely(update_sum_func(join->sum_funcs)))
    DBUG_RETURN(NESTED_LOOP_ERROR);
  if (unlikely(join->procedure))
    join->procedure->add();
end:
  if (unlikely(join->thd->check_killed()))
  {
    DBUG_RETURN(NESTED_LOOP_KILLED);             /* purecov: inspected */
  }
  DBUG_RETURN(NESTED_LOOP_OK);
}

Project: server

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

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

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

Project: server

void JOIN_TAB::partial_cleanup()
{
  if (!table)
    return;

  if (table->is_created())
  {
    table->file->ha_index_or_rnd_end();
    DBUG_PRINT("info", ("close index: %s.%s  alias: %s",
               table->s->db.str,
               table->s->table_name.str,
               table->alias.c_ptr()));
    if (aggr)
    {
      int tmp= 0;
      if ((tmp= table->file->extra(HA_EXTRA_NO_CACHE)))
        table->file->print_error(tmp, MYF(0));
    }
  }
  delete filesort_result;
  filesort_result= NULL;
  free_cache(&read_record);
}

Project: server

static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list,
                             bool *changed)
{
  if (expr->argument_count())
  {
    Name_resolution_context *context= &thd->lex->current_select->context;
    Item **arg,**arg_end;
    bool arg_changed= FALSE;
    for (arg= expr->arguments(),
         arg_end= expr->arguments() + expr->argument_count();
         arg != arg_end; arg++)
    {
      Item *item= *arg;
      if (item->type() == Item::FIELD_ITEM || item->type() == Item::REF_ITEM)
      {
        ORDER *group_tmp;
        for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next)
        {
          if (item->eq(*group_tmp->item,0))
          {
            Item *new_item;
            if (!(new_item= new (thd->mem_root) Item_ref(thd, context,
                                                         group_tmp->item, 0,
                                                         &item->name)))
              return 1;                                 // fatal_error is set
            thd->change_item_tree(arg, new_item);
            arg_changed= TRUE;
          }
        }
      }
      else if (item->type() == Item::FUNC_ITEM)
      {
        if (change_group_ref(thd, (Item_func *) item, group_list, &arg_changed))
          return 1;
      }
    }
    if (arg_changed)
    {
      expr->maybe_null= 1;
      expr->in_rollup= 1;
      *changed= TRUE;
    }
  }
  return 0;
}

Project: server

join_read_always_key_or_null(JOIN_TAB *tab)
{
  int res;

  /* First read according to key which is NOT NULL */
  *tab->ref.null_ref_key= 0;			// Clear null byte
  if ((res= join_read_always_key(tab)) >= 0)
    return res;

  /* Then read key with null value */
  *tab->ref.null_ref_key= 1;			// Set null byte
  return safe_index_read(tab);
}

Project: server

get_sort_by_table(ORDER *a,ORDER *b, List<TABLE_LIST> &tables, 
                  table_map const_tables)
{
  TABLE_LIST *table;
  List_iterator<TABLE_LIST> ti(tables);
  table_map map= (table_map) 0;
  DBUG_ENTER("get_sort_by_table");

  if (!a)
    a=b;					// Only one need to be given
  else if (!b)
    b=a;

  for (; a && b; a=a->next,b=b->next)
  {
    /* Skip elements of a that are constant */
    while (!((*a->item)->used_tables() & ~const_tables))
    {
      if (!(a= a->next))
        break;
    }

    /* Skip elements of b that are constant */
    while (!((*b->item)->used_tables() & ~const_tables))
    {
      if (!(b= b->next))
        break;
    }

    if (!a || !b)
      break;

    if (!(*a->item)->eq(*b->item,1))
      DBUG_RETURN(0);
    map|=a->item[0]->used_tables();
  }
  if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT)))
    DBUG_RETURN(0);

  map&= ~const_tables;
  while ((table= ti++) && !(map & table->table->map)) ;
  if (map != table->table->map)
    DBUG_RETURN(0);				// More than one table
  DBUG_PRINT("exit",("sort by table: %d",table->table->tablenr));
  DBUG_RETURN(table->table);
}

Project: server

Field *create_tmp_field_from_field(THD *thd, Field *org_field,
                                   LEX_CSTRING *name, TABLE *table,
                                   Item_field *item)
{
  Field *new_field;

  new_field= org_field->make_new_field(thd->mem_root, table,
                                       table == org_field->table);
  if (new_field)
  {
    new_field->init(table);
    new_field->orig_table= org_field->orig_table;
    if (item)
      item->result_field= new_field;
    else
      new_field->field_name= *name;
    new_field->flags|= org_field->flags & NO_DEFAULT_VALUE_FLAG;
    if (org_field->maybe_null() || (item && item->maybe_null))
      new_field->flags&= ~NOT_NULL_FLAG;	// Because of outer join
    if (org_field->type() == MYSQL_TYPE_VAR_STRING ||
        org_field->type() == MYSQL_TYPE_VARCHAR)
      table->s->db_create_options|= HA_OPTION_PACK_RECORD;
    else if (org_field->type() == FIELD_TYPE_DOUBLE)
      ((Field_double *) new_field)->not_fixed= TRUE;
    new_field->vcol_info= 0;
    new_field->cond_selectivity= 1.0;
    new_field->next_equal_field= NULL;
    new_field->option_list= NULL;
    new_field->option_struct= NULL;
  }
  return new_field;
}

Project: server

Field *Item::create_field_for_schema(THD *thd, TABLE *table)
{
  if (field_type() == MYSQL_TYPE_VARCHAR)
  {
    Field *field;
    if (max_length > MAX_FIELD_VARCHARLENGTH)
      field= new Field_blob(max_length, maybe_null, &name,
                            collation.collation);
    else
      field= new Field_varstring(max_length, maybe_null, &name,
                                 table->s, collation.collation);
    if (field)
      field->init(table);
    return field;
  }
  return tmp_table_field_from_field_type(table);
}

Project: server

int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
{
  DBUG_ENTER("SELECT_LEX::vers_setup_cond");
#define newx new (thd->mem_root)

  const bool update_conds= !skip_setup_conds(thd);
  TABLE_LIST *table;

  if (!versioned_tables)
  {
    for (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= 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.type= SYSTEM_TIME_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;
    }

    const LEX_CSTRING *fstart=
        thd->make_clex_string(table->table->vers_start_field()->field_name);
    const LEX_CSTRING *fend=
        thd->make_clex_string(table->table->vers_end_field()->field_name);

    Item *row_start=
        newx Item_field(thd, &this->context, table->db.str, table->alias.str, fstart);
    Item *row_end=
        newx Item_field(thd, &this->context, table->db.str, table->alias.str, fend);

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

    Item *cond1= NULL, *cond2= NULL, *cond3= NULL, *curr= NULL;
    Item *point_in_time1= vers_conditions.start.item;
    Item *point_in_time2= vers_conditions.end.item;
    TABLE *t= table->table;
    if (t->versioned(VERS_TIMESTAMP))
    {
      MYSQL_TIME max_time;
      switch (vers_conditions.type)
      {
      case SYSTEM_TIME_UNSPECIFIED:
      case SYSTEM_TIME_HISTORY:
        thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE);
        max_time.second_part= TIME_MAX_SECOND_PART;
        curr= newx Item_datetime_literal(thd, &max_time, TIME_SECOND_PART_DIGITS);
        if (vers_conditions.type == SYSTEM_TIME_UNSPECIFIED)
          cond1= newx Item_func_eq(thd, row_end, curr);
        else
          cond1= newx Item_func_lt(thd, row_end, curr);
        break;
      case SYSTEM_TIME_AS_OF:
        cond1= newx Item_func_le(thd, row_start, point_in_time1);
        cond2= newx Item_func_gt(thd, row_end, point_in_time1);
        break;
      case SYSTEM_TIME_FROM_TO:
        cond1= newx Item_func_lt(thd, row_start, point_in_time2);
        cond2= newx Item_func_gt(thd, row_end, point_in_time1);
        cond3= newx Item_func_lt(thd, point_in_time1, point_in_time2);
        break;
      case SYSTEM_TIME_BETWEEN:
        cond1= newx Item_func_le(thd, row_start, point_in_time2);
        cond2= newx Item_func_gt(thd, row_end, point_in_time1);
        cond3= newx Item_func_le(thd, point_in_time1, point_in_time2);
        break;
      case SYSTEM_TIME_BEFORE:
        cond1= newx Item_func_history(thd, row_end);
        cond2= newx Item_func_lt(thd, row_end, point_in_time1);
        break;
      default:
        DBUG_ASSERT(0);
      }
    }
    else
    {
      DBUG_ASSERT(table->table->s && table->table->s->db_plugin);

      Item *trx_id0, *trx_id1;

      switch (vers_conditions.type)
      {
      case SYSTEM_TIME_UNSPECIFIED:
      case SYSTEM_TIME_HISTORY:
        curr= newx Item_int(thd, ULONGLONG_MAX);
        if (vers_conditions.type == SYSTEM_TIME_UNSPECIFIED)
          cond1= newx Item_func_eq(thd, row_end, curr);
        else
          cond1= newx Item_func_lt(thd, row_end, curr);
        break;
      case SYSTEM_TIME_AS_OF:
        trx_id0= vers_conditions.start.unit == VERS_TIMESTAMP
          ? newx Item_func_trt_id(thd, point_in_time1, TR_table::FLD_TRX_ID)
          : point_in_time1;
        cond1= newx Item_func_trt_trx_sees_eq(thd, trx_id0, row_start);
        cond2= newx Item_func_trt_trx_sees(thd, row_end, trx_id0);
        break;
      case SYSTEM_TIME_FROM_TO:
	cond3= newx Item_func_lt(thd, point_in_time1, point_in_time2);
        /* fall through */
      case SYSTEM_TIME_BETWEEN:
        trx_id0= vers_conditions.start.unit == VERS_TIMESTAMP
          ? newx Item_func_trt_id(thd, point_in_time1, TR_table::FLD_TRX_ID, true)
          : point_in_time1;
        trx_id1= vers_conditions.end.unit == VERS_TIMESTAMP
          ? newx Item_func_trt_id(thd, point_in_time2, TR_table::FLD_TRX_ID, false)
          : point_in_time2;
        cond1= vers_conditions.type == SYSTEM_TIME_FROM_TO
          ? newx Item_func_trt_trx_sees(thd, trx_id1, row_start)
          : newx Item_func_trt_trx_sees_eq(thd, trx_id1, row_start);
        cond2= newx Item_func_trt_trx_sees_eq(thd, row_end, trx_id0);
	if (!cond3)
	  cond3= newx Item_func_le(thd, point_in_time1, point_in_time2);
        break;
      case SYSTEM_TIME_BEFORE:
        trx_id0= vers_conditions.start.unit == VERS_TIMESTAMP
          ? newx Item_func_trt_id(thd, point_in_time1, TR_table::FLD_TRX_ID, true)
          : point_in_time1;
        cond1= newx Item_func_history(thd, row_end);
        cond2= newx Item_func_trt_trx_sees(thd, trx_id0, row_end);
        break;
      default:
        DBUG_ASSERT(0);
      }
    }

    if (cond1)
    {
      cond1= and_items(thd, cond2, cond1);
      cond1= and_items(thd, cond3, cond1);
      if (is_select)
        table->on_expr= and_items(thd, table->on_expr, cond1);
      else
      {
        if (join)
        {
          where= and_items(thd, join->conds, cond1);
          join->conds= where;
        }
        else
          where= and_items(thd, where, cond1);
        table->where= and_items(thd, table->where, cond1);
      }
    }

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

  DBUG_RETURN(0);
#undef newx
}

Project: server

join_read_const_table(THD *thd, JOIN_TAB *tab, POSITION *pos)
{
  int error;
  TABLE_LIST *tbl;
  DBUG_ENTER("join_read_const_table");
  TABLE *table=tab->table;
  table->const_table=1;
  table->null_row=0;
  table->status=STATUS_NO_RECORD;
  
  if (tab->table->pos_in_table_list->is_materialized_derived() &&
      !tab->table->pos_in_table_list->fill_me)
  {
    //TODO: don't get here at all
    /* Skip materialized derived tables/views. */
    DBUG_RETURN(0);
  }
  else if (tab->table->pos_in_table_list->jtbm_subselect && 
          tab->table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab)
  {
    /* Row will not be found */
    int res;
    if (tab->table->pos_in_table_list->jtbm_subselect->jtbm_const_row_found)
      res= 0;
    else
      res= -1;
    DBUG_RETURN(res);
  }
  else if (tab->type == JT_SYSTEM)
  {
    if (unlikely((error=join_read_system(tab))))
    {						// Info for DESCRIBE
      tab->info= ET_CONST_ROW_NOT_FOUND;
      /* Mark for EXPLAIN that the row was not found */
      pos->records_read=0.0;
      pos->ref_depend_map= 0;
      if (!table->pos_in_table_list->outer_join || error > 0)
	DBUG_RETURN(error);
    }
    /*
      The optimizer trust the engine that when stats.records is 0, there
      was no found rows
    */
    DBUG_ASSERT(table->file->stats.records > 0 || error);
  }
  else
  {
    if (/*!table->file->key_read && */
        table->covering_keys.is_set(tab->ref.key) && !table->no_keyread &&
        (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY)
    {
      table->file->ha_start_keyread(tab->ref.key);
      tab->index= tab->ref.key;
    }
    error=join_read_const(tab);
    table->file->ha_end_keyread();
    if (unlikely(error))
    {
      tab->info= ET_UNIQUE_ROW_NOT_FOUND;
      /* Mark for EXPLAIN that the row was not found */
      pos->records_read=0.0;
      pos->ref_depend_map= 0;
      if (!table->pos_in_table_list->outer_join || error > 0)
	DBUG_RETURN(error);
    }
  }
  /* 
     Evaluate an on-expression only if it is not considered expensive.
     This mainly prevents executing subqueries in optimization phase.
     This is necessary since proper setup for such execution has not been
     done at this stage.
  */
  if (*tab->on_expr_ref && !table->null_row && 
      !(*tab->on_expr_ref)->is_expensive())
  {
#if !defined(DBUG_OFF) && defined(NOT_USING_ITEM_EQUAL)
    /*
      This test could be very useful to find bugs in the optimizer
      where we would call this function with an expression that can't be
      evaluated yet. We can't have this enabled by default as long as
      have items like Item_equal, that doesn't report they are const but
      they can still be called even if they contain not const items.
    */
    (*tab->on_expr_ref)->update_used_tables();
    DBUG_ASSERT((*tab->on_expr_ref)->const_item());
#endif
    if ((table->null_row= MY_TEST((*tab->on_expr_ref)->val_int() == 0)))
      mark_as_null_row(table);  
  }
  if (!table->null_row && ! tab->join->mixed_implicit_grouping)
    table->maybe_null= 0;

  {
    JOIN *join= tab->join;
    List_iterator<TABLE_LIST> ti(join->select_lex->leaf_tables);
    /* Check appearance of new constant items in Item_equal objects */
    if (join->conds)
      update_const_equal_items(thd, join->conds, tab, TRUE);
    while ((tbl= ti++))
    {
      TABLE_LIST *embedded;
      TABLE_LIST *embedding= tbl;
      do
      {
        embedded= embedding;
        if (embedded->on_expr)
           update_const_equal_items(thd, embedded->on_expr, tab, TRUE);
        embedding= embedded->embedding;
      }
      while (embedding &&
             embedding->nested_join->join_list.head() == embedded);
    }
  }
  DBUG_RETURN(0);
}

Project: server

join_no_more_records(READ_RECORD *info __attribute__((unused)))
{
  return -1;
}

Project: server

static bool equal(Item *i1, Item *i2, Field *f2)
{
  DBUG_ASSERT((i2 == NULL) ^ (f2 == NULL));

  if (i2 != NULL)
    return i1->eq(i2, 1);
  else if (i1->type() == Item::FIELD_ITEM)
    return f2->eq(((Item_field *) i1)->field);
  else
    return FALSE;
}

Project: server

  static void operator delete(void *, MEM_ROOT*) {}

Project: server

bool Virtual_tmp_table::init(uint field_count)
{
  uint *blob_field;
  uchar *bitmaps;
  DBUG_ENTER("Virtual_tmp_table::init");
  if (!multi_alloc_root(in_use->mem_root,
                        &s, sizeof(*s),
                        &field, (field_count + 1) * sizeof(Field*),
                        &blob_field, (field_count + 1) * sizeof(uint),
                        &bitmaps, bitmap_buffer_size(field_count) * 6,
                        NullS))
    DBUG_RETURN(true);
  s->reset();
  s->blob_field= blob_field;
  setup_tmp_table_column_bitmaps(this, bitmaps, field_count);
  m_alloced_field_count= field_count;
  DBUG_RETURN(false);
};

Project: server

join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2)
{
  JOIN_TAB *jt1= *(JOIN_TAB**) ptr1;
  JOIN_TAB *jt2= *(JOIN_TAB**) ptr2;
  int cmp;

  if ((cmp= compare_embedding_subqueries(jt1, jt2)) != 0)
    return cmp;
  /*
    After that,
    take care about ordering imposed by LEFT JOIN constraints,
    possible [eq]ref accesses, and numbers of matching records in the table.
  */
  if (jt1->dependent & jt2->table->map)
    return 1;
  if (jt2->dependent & jt1->table->map)
    return -1;  
  if (jt1->found_records > jt2->found_records)
    return 1;
  if (jt1->found_records < jt2->found_records)
    return -1; 
  return jt1 > jt2 ? 1 : (jt1 < jt2 ? -1 : 0);
}

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

  join->join_free();

  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
  }
  DBUG_RETURN(0);
}

Project: server

void JOIN::save_query_plan(Join_plan_state *save_to)
{
  DYNAMIC_ARRAY tmp_keyuse;
  /* Swap the current and the backup keyuse internal arrays. */
  tmp_keyuse= keyuse;
  keyuse= save_to->keyuse; /* keyuse is reset to an empty array. */
  save_to->keyuse= tmp_keyuse;

  for (uint i= 0; i < table_count; i++)
  {
    save_to->join_tab_keyuse[i]= join_tab[i].keyuse;
    join_tab[i].keyuse= NULL;
    save_to->join_tab_checked_keys[i]= join_tab[i].checked_keys;
    join_tab[i].checked_keys.clear_all();
  }
  memcpy((uchar*) save_to->best_positions, (uchar*) best_positions,
         sizeof(POSITION) * (table_count + 1));
  memset((uchar*) best_positions, 0, sizeof(POSITION) * (table_count + 1));
  
  /* Save SJM nests */
  List_iterator<TABLE_LIST> it(select_lex->sj_nests);
  TABLE_LIST *tlist;
  SJ_MATERIALIZATION_INFO **p_info= save_to->sj_mat_info;
  while ((tlist= it++))
  {
    *(p_info++)= tlist->sj_mat_info;
  }
}

Project: server

bool generate_derived_keys_for_table(KEYUSE *keyuse, uint count, uint keys)
{
  TABLE *table= keyuse->table;
  if (table->alloc_keys(keys))
    return TRUE;
  uint key_count= 0;
  KEYUSE *first_keyuse= keyuse;
  uint prev_part= keyuse->keypart;
  uint parts= 0;
  uint i= 0;

  for ( ; i < count && key_count < keys; )
  {
    do
    {
      keyuse->key= table->s->keys;
      keyuse->keypart_map= (key_part_map) (1 << parts);     
      keyuse++;
      i++;
    } 
    while (i < count && keyuse->used_tables == first_keyuse->used_tables &&
           keyuse->keypart == prev_part);
    parts++;
    if (i < count && keyuse->used_tables == first_keyuse->used_tables)
    {
      prev_part= keyuse->keypart;
    }
    else
    {
      KEYUSE *save_first_keyuse= first_keyuse;
      if (table->check_tmp_key(table->s->keys, parts,
                               get_next_field_for_derived_key_simple,
                               (uchar *) &first_keyuse))

      {
        first_keyuse= save_first_keyuse;
        if (table->add_tmp_key(table->s->keys, parts, 
                               get_next_field_for_derived_key, 
                               (uchar *) &first_keyuse,
                               FALSE))
          return TRUE;
        table->reginfo.join_tab->keys.set_bit(table->s->keys);
      }
      else
      {
        /* Mark keyuses for this key to be excluded */
        for (KEYUSE *curr=save_first_keyuse; curr < keyuse; curr++)
	{
          curr->key= MAX_KEY;
        }
      }
      first_keyuse= keyuse;
      key_count++;
      parts= 0;
      prev_part= keyuse->keypart;
    }
  }             

  return FALSE;
}

Project: server

setup_new_fields(THD *thd, List<Item> &fields,
		 List<Item> &all_fields, ORDER *new_field)
{
  Item	  **item;
  uint counter;
  enum_resolution_type not_used;
  DBUG_ENTER("setup_new_fields");

  thd->column_usage= MARK_COLUMNS_READ;       // Not really needed, but...
  for (; new_field ; new_field= new_field->next)
  {
    if ((item= find_item_in_list(*new_field->item, fields, &counter,
				 IGNORE_ERRORS, &not_used)))
      new_field->item=item;			/* Change to shared Item */
    else
    {
      thd->where="procedure list";
      if ((*new_field->item)->fix_fields(thd, new_field->item))
	DBUG_RETURN(1); /* purecov: inspected */
      all_fields.push_front(*new_field->item, thd->mem_root);
      new_field->item=all_fields.head_ref();
    }
  }
  DBUG_RETURN(0);
}

Project: server

static TABLE_LIST* embedding_sjm(Item *item)
{
  Item_field *item_field= (Item_field *) (item->real_item());
  TABLE_LIST *nest= item_field->field->table->pos_in_table_list->embedding;
  if (nest && nest->sj_mat_info && nest->sj_mat_info->is_used)
    return nest;
  else
    return NULL;
}

Project: server

JOIN_TAB *next_explain_order_tab(JOIN* join, JOIN_TAB* tab)
{
  /* If we're inside SJM nest and have reached its end, get out */
  if (tab->last_leaf_in_bush)
    return tab->bush_root_tab;
  
  /* Move to next tab in the array we're traversing */
  tab++;
  
  if (tab == join->join_tab + join->top_join_tab_count)
    return NULL; /* Outside SJM nest and reached EOF */

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

  return tab;
}

Project: server

find_field_in_order_list (Field *field, void *data)
{
  ORDER *group= (ORDER *) data;
  bool part_found= 0;
  for (ORDER *tmp_group= group; tmp_group; tmp_group=tmp_group->next)
  {
    Item *item= (*tmp_group->item)->real_item();
    if (item->type() == Item::FIELD_ITEM &&
        ((Item_field*) item)->field->eq(field))
    {
      part_found= 1;
      break;
    }
  }
  return part_found;
}

Project: server

JOIN_TAB *first_linear_tab(JOIN *join,
                           enum enum_with_bush_roots include_bush_roots,
                           enum enum_with_const_tables const_tbls)
{
  JOIN_TAB *first= join->join_tab;

  if (!first)
    return NULL;

  if (const_tbls == WITHOUT_CONST_TABLES)
    first+= join->const_tables;

  if (first >= join->join_tab + join->top_join_tab_count)
    return NULL; /* All are const tables */

  if (first->bush_children && include_bush_roots == WITHOUT_BUSH_ROOTS)
  {
    /* This JOIN_TAB is a SJM nest; Start from first table in nest */
    return first->bush_children->start;
  }

  return first;
}