static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
                                 bool is_sub_part, bool is_create_table_ind)
{
  partition_info *part_info= table->part_info;
  bool result= TRUE;
  int error;
  LEX *old_lex= thd->lex;
  LEX lex;
  DBUG_ENTER("fix_fields_part_func");

  if (init_lex_with_single_table(thd, table, &lex))
    goto end;
  table->get_fields_in_item_tree= true;

  func_expr->walk(&Item::change_context_processor, 0, &lex.select_lex.context);
  thd->where= "partition function";
  /*
    In execution we must avoid the use of thd->change_item_tree since
    we might release memory before statement is completed. We do this
    by temporarily setting the stmt_arena->mem_root to be the mem_root
    of the table object, this also ensures that any memory allocated
    during fix_fields will not be released at end of execution of this
    statement. Thus the item tree will remain valid also in subsequent
    executions of this table object. We do however not at the moment
    support allocations during execution of val_int so any item class
    that does this during val_int must be disallowed as partition
    function.
    SEE Bug #21658

    This is a tricky call to prepare for since it can have a large number
    of interesting side effects, both desirable and undesirable.
  */
  {
    const bool save_agg_field= thd->lex->current_select->non_agg_field_used();
    const bool save_agg_func=  thd->lex->current_select->agg_func_used();
    const nesting_map saved_allow_sum_func= thd->lex->allow_sum_func;
    thd->lex->allow_sum_func.clear_all();

    if (likely(!(error= func_expr->fix_fields_if_needed(thd, (Item**)&func_expr))))
      func_expr->walk(&Item::post_fix_fields_part_expr_processor, 0, NULL);

    /*
      Restore agg_field/agg_func  and allow_sum_func,
      fix_fields should not affect mysql_select later, see Bug#46923.
    */
    thd->lex->current_select->set_non_agg_field_used(save_agg_field);
    thd->lex->current_select->set_agg_func_used(save_agg_func);
    thd->lex->allow_sum_func= saved_allow_sum_func;
  }
  if (unlikely(error))
  {
    DBUG_PRINT("info", ("Field in partition function not part of table"));
    clear_field_flag(table);
    goto end;
  }
  if (unlikely(func_expr->const_item()))
  {
    my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
    clear_field_flag(table);
    goto end;
  }

  /*
    We don't allow creating partitions with expressions with non matching
    arguments as a (sub)partitioning function,
    but we want to allow such expressions when opening existing tables for
    easier maintenance. This exception should be deprecated at some point
    in future so that we always throw an error.
  */
  if (func_expr->walk(&Item::check_valid_arguments_processor, 0, NULL))
  {
    if (is_create_table_ind)
    {
      my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
      goto end;
    }
    else
      push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
                   ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR,
                   ER_THD(thd, ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
  }

  if (unlikely((!is_sub_part) && (error= check_signed_flag(part_info))))
    goto end;
  result= set_up_field_array(thd, table, is_sub_part);
end:
  end_lex_with_single_table(thd, table, old_lex);
  func_expr->walk(&Item::change_context_processor, 0, 0);
  DBUG_RETURN(result);
}