udf_handler::fix_fields(THD *thd, Item_func_or_sum *func,
			uint arg_count, Item **arguments)
{
  uchar buff[STACK_BUFF_ALLOC];			// Max argument in function
  DBUG_ENTER("Item_udf_func::fix_fields");

  if (check_stack_overrun(thd, STACK_MIN_SIZE, buff))
    DBUG_RETURN(TRUE);				// Fatal error flag is set!

  udf_func *tmp_udf=find_udf(u_d->name.str,(uint) u_d->name.length,1);

  if (!tmp_udf)
  {
    my_error(ER_CANT_FIND_UDF, MYF(0), u_d->name.str);
    DBUG_RETURN(TRUE);
  }
  u_d=tmp_udf;
  args=arguments;

  /* Fix all arguments */
  func->maybe_null=0;
  func->used_tables_and_const_cache_init();

  if ((f_args.arg_count=arg_count))
  {
    if (!(f_args.arg_type= (Item_result*)
	  thd->alloc(f_args.arg_count*sizeof(Item_result))))

    {
    err_exit:
      free_udf(u_d);
      DBUG_RETURN(TRUE);
    }
    uint i;
    Item **arg,**arg_end;
    for (i=0, arg=arguments, arg_end=arguments+arg_count;
	 arg != arg_end ;
	 arg++,i++)
    {
      if (!(*arg)->fixed &&
          (*arg)->fix_fields(thd, arg))
	DBUG_RETURN(1);
      // we can't assign 'item' before, because fix_fields() can change arg
      Item *item= *arg;
      if (item->check_cols(1))
	DBUG_RETURN(TRUE);
      /*
	TODO: We should think about this. It is not always
	right way just to set an UDF result to return my_charset_bin
	if one argument has binary sorting order.
	The result collation should be calculated according to arguments
	derivations in some cases and should not in other cases.
	Moreover, some arguments can represent a numeric input
	which doesn't effect the result character set and collation.
	There is no a general rule for UDF. Everything depends on
        the particular user defined function.
      */
      if (item->collation.collation->state & MY_CS_BINSORT)
	func->collation.set(&my_charset_bin);
      if (item->maybe_null)
	func->maybe_null=1;
      func->with_sum_func= func->with_sum_func || item->with_sum_func;
      func->with_window_func= func->with_window_func ||
                              item->with_window_func;
      func->with_field= func->with_field || item->with_field;
      func->with_param= func->with_param || item->with_param;
      func->with_subselect|= item->with_subselect;
      func->used_tables_and_const_cache_join(item);
      f_args.arg_type[i]=item->result_type();
    }
    //TODO: why all following memory is not allocated with 1 thd->alloc() call?
    buffers= new String[arg_count];
    if (!buffers ||
	!(f_args.args= (char**) thd->alloc(arg_count * sizeof(char *))) ||
	!(f_args.lengths= (ulong*) thd->alloc(arg_count * sizeof(long))) ||
	!(f_args.maybe_null= (char*) thd->alloc(arg_count * sizeof(char))) ||
	!(num_buffer= (char*) thd->alloc(arg_count *
					ALIGN_SIZE(sizeof(double)))) ||
	!(f_args.attributes= (char**) thd->alloc(arg_count *
                                                 sizeof(char *))) ||
	!(f_args.attribute_lengths= (ulong*) thd->alloc(arg_count *
						       sizeof(long))))
      goto err_exit;
  }
  if (func->fix_length_and_dec())
    DBUG_RETURN(TRUE);
  initid.max_length=func->max_length;
  initid.maybe_null=func->maybe_null;
  initid.const_item=func->const_item_cache;
  initid.decimals=func->decimals;
  initid.ptr=0;

  if (u_d->func_init)
  {
    char init_msg_buff[MYSQL_ERRMSG_SIZE];
    char *to=num_buffer;
    for (uint i=0; i < arg_count; i++)
    {
      /*
       For a constant argument i, args->args[i] points to the argument value. 
       For non-constant, args->args[i] is NULL.
      */
      f_args.args[i]= NULL;         /* Non-const unless updated below. */

      f_args.lengths[i]= arguments[i]->max_length;
      f_args.maybe_null[i]= (char) arguments[i]->maybe_null;
      f_args.attributes[i]= arguments[i]->name;
      f_args.attribute_lengths[i]= arguments[i]->name_length;

      if (arguments[i]->const_item())
      {
        switch (arguments[i]->result_type()) {
        case STRING_RESULT:
        case DECIMAL_RESULT:
        {
          String *res= arguments[i]->val_str(&buffers[i]);
          if (arguments[i]->null_value)
            continue;
          f_args.args[i]= (char*) res->c_ptr_safe();
          f_args.lengths[i]= res->length();
          break;
        }
        case INT_RESULT:
          *((longlong*) to)= arguments[i]->val_int();
          if (arguments[i]->null_value)
            continue;
          f_args.args[i]= to;
          to+= ALIGN_SIZE(sizeof(longlong));
          break;
        case REAL_RESULT:
          *((double*) to)= arguments[i]->val_real();
          if (arguments[i]->null_value)
            continue;
          f_args.args[i]= to;
          to+= ALIGN_SIZE(sizeof(double));
          break;
        case ROW_RESULT:
        case TIME_RESULT:
          DBUG_ASSERT(0);          // This case should never be chosen
          break;
        }
      }
    }
    Udf_func_init init= u_d->func_init;
    if ((error=(uchar) init(&initid, &f_args, init_msg_buff)))
    {
      my_error(ER_CANT_INITIALIZE_UDF, MYF(0),
               u_d->name.str, init_msg_buff);
      goto err_exit;
    }
    func->max_length=MY_MIN(initid.max_length,MAX_BLOB_WIDTH);
    func->maybe_null=initid.maybe_null;
    /*
      The above call for init() can reset initid.const_item to "false",
      e.g. when the UDF function wants to be non-deterministic.
      See sequence_init() in udf_example.cc.
    */
    func->const_item_cache= initid.const_item;
    func->decimals=MY_MIN(initid.decimals,NOT_FIXED_DEC);
  }
  initialized=1;
  if (error)
  {
    my_error(ER_CANT_INITIALIZE_UDF, MYF(0),
             u_d->name.str, ER_THD(thd, ER_UNKNOWN_ERROR));
    DBUG_RETURN(TRUE);
  }
  DBUG_RETURN(FALSE);
}