Item *st_select_lex::pushdown_from_having_into_where(THD *thd, Item *having)
{
  if (!having || !group_list.first)
    return having;
  if (!cond_pushdown_is_allowed())
    return having;

  st_select_lex *save_curr_select= thd->lex->current_select;
  thd->lex->current_select= this;

  /*
    1. Collect fields used in the GROUP BY grouping fields of this SELECT
    2. Collect fields equal to grouping_fields from the WHERE clause
       of this SELECT and add them to the grouping fields list.
  */
  if (collect_grouping_fields(thd) ||
      collect_fields_equal_to_grouping(thd))
    return having;

  /*
    3. Extract the most restrictive condition from the HAVING clause of this
       select that depends only on the grouping fields (directly or indirectly
       through equality).
       If the extracted condition is an AND condition it is transformed into a
       list of all its conjuncts saved in attach_to_conds. Otherwise,
       the condition is put into attach_to_conds as the only its element.
  */
  List_iterator_fast<Item> it(attach_to_conds);
  Item *item;
  check_cond_extraction_for_grouping_fields(thd, having);
  if (build_pushable_cond_for_having_pushdown(thd, having))
  {
    attach_to_conds.empty();
    goto exit;
  }
  if (!attach_to_conds.elements)
    goto exit;

  /*
    4. Remove conditions from HAVING clause that can be entirely pushed
       into WHERE.
       Multiple equalities are not removed but marked with DELETION_FL flag.
       They will be deleted later in substitite_for_best_equal_field() called
       for the HAVING condition.
  */
  having= remove_pushed_top_conjuncts_for_having(thd, having);

  /*
    Change join->cond_equal which points to the multiple equalities of
    the top level of HAVING.
    Removal of AND conditions may leave only one conjunct in HAVING.

    Example 1:
    SELECT *
    FROM t1
    GROUP BY t1.a
    (t1.a < 2) AND (t1.b = 2)

    (t1.a < 2) is pushed into WHERE.
    join->cond_equal should point on (t1.b = 2) multiple equality now.

    Example 2:
    SELECT *
    FROM t1
    GROUP BY t1.a
    (t1.a = 2) AND (t1.b < 2)

    (t1.a = 2) is pushed into WHERE.
    join->cond_equal should be NULL now.
  */
  if (having &&
      having->type() == Item::FUNC_ITEM &&
      ((Item_func*) having)->functype() == Item_func::MULT_EQUAL_FUNC)
    join->having_equal= new (thd->mem_root) COND_EQUAL((Item_equal *)having,
                                                       thd->mem_root);
  else if (!having ||
           having->type() != Item::COND_ITEM ||
           ((Item_cond *)having)->functype() != Item_cond::COND_AND_FUNC)
    join->having_equal= 0;

  /*
    5. Unwrap fields wrapped in Item_ref wrappers contained in the condition
       of attach_to_conds so the condition could be pushed into WHERE.
  */
  it.rewind();
  while ((item=it++))
  {
    item= item->transform(thd,
                          &Item::field_transformer_for_having_pushdown,
                          (uchar *)this);

    if (item->walk(&Item::cleanup_excluding_immutables_processor, 0, STOP_PTR)
        || item->fix_fields(thd, NULL))
    {
      attach_to_conds.empty();
      goto exit;
    }
  }
exit:
  thd->lex->current_select= save_curr_select;
  return having;
}