[MDEV-9221] Derive Item from Type_handler virtually Created: 2015-12-01  Updated: 2017-04-09  Resolved: 2016-11-26

Status: Closed
Project: MariaDB Server
Component/s: OTHER
Fix Version/s: 10.3.0

Type: Task Priority: Major
Reporter: Alexander Barkov Assignee: Alexander Barkov
Resolution: Won't Do Votes: 0
Labels: refactoring

Issue Links:
Blocks
blocks MDEV-4912 Data type plugin API version 1 Closed

 Description   

This task was canceled. See a comment below.

There is some code duplication in Item implementation.

class Item_str_func
{
  double val_real()
  {
    int err_not_used;
    char *end_not_used;
    String *res;
    res= val_str(&str_value);
    return res ? my_strntod(res->charset(),(char*) res->ptr(),
                            res->length(), &end_not_used, &err_not_used) : 0.0;
  }
};

class Item_func_group_concat
{
  double val_real()
  {
    int error;
    const char *end;
    String *res;
    if (!(res= val_str(&str_value)))
      return 0.0;
    end= res->ptr() + res->length();
    return (my_strtod(res->ptr(), (char**) &end, &error));
  }
};

class Item_func_udf_str
{
  double val_real()
  {
    int err_not_used;
    char *end_not_used;
    String *res;
    res= val_str(&str_value);
     return res ? my_strntod(res->charset(),(char*) res->ptr(),
                            res->length(), &end_not_used, &err_not_used) : 0.0;
  }
};

The same type of duplications happens with all other val_xxx() methods.

The same duplication happens in deriving Item_xxx from Type_handler_xxx:

class Item_sum_sum :public Item_sum_num,
                    public Type_handler_hybrid_field_type
{
...
  enum_field_types field_type() const   
  { return Type_handler_hybrid_field_type::field_type(); }
  enum Item_result result_type () const
  { return Type_handler_hybrid_field_type::result_type(); }
  enum Item_result cmp_type () const
  { return Type_handler_hybrid_field_type::cmp_type(); }
...
};

class Item_sum_hybrid :public Item_sum, public Type_handler_hybrid_field_type
{
...
  enum Item_result result_type () const
  { return Type_handler_hybrid_field_type::result_type(); }
  enum Item_result cmp_type () const
  { return Type_handler_hybrid_field_type::cmp_type(); }
  enum enum_field_types field_type() const
  { return Type_handler_hybrid_field_type::field_type(); }
...
};

class Item_hybrid_func: public Item_func,
                        public Type_handler_hybrid_field_type
{
...
  enum_field_types field_type() const
  { return Type_handler_hybrid_field_type::field_type(); }
  enum Item_result result_type () const
  { return Type_handler_hybrid_field_type::result_type(); }
  enum Item_result cmp_type () const
  { return Type_handler_hybrid_field_type::cmp_type(); }
...
};

Duplicate code can be avoided by using diamond-style inheritance, deriving Item from Type_handler virtually, so these methods are automatically assigned by just the class declaration.

Diamond style inheritance:

         Top
       /      \
   Left        Right
       \      /
        Bottom

Deriving from Top to Left and from Top to Right is done virtually. This is important to have only one copy of "Top" in "Bottom".

In our case:

  • Top is Type_handler
  • Left is the data type: Type_handler_str, Type_handler_longlong, Type_handler_double, etc.
  • Right is the Item type: Item_func, Item_sum, Item_cache, etc.
  • Bottom is the Item type with the data type: Item_func_str, Item_sum_int, Item_cache_real, etc.

                          Type_handler
                         /             \
    Type_handler_longlong               Item_func
                         \             /
                          Item_int_func
    

First, we inherit two different branches of Type_handler virtually (notice "public virtual"):

// The data type branch (string, double, int, decimal, date, time,datetime)
class Type_handler_str: public virtual Type_handler
{
  // This class implements field_type(), cmp_type(), result_type()
  // as well as conversion methods val_int(), val_decimal(), val_real(), get_date().
  // Notice, it does not implement the native method val_str(). It's pure virtual here.
};
 
// The Item type branch (Item_basic_constant, Item_cache, Item_func, Item_sum, Item_field, all the rest)
class Item: public Value_source,
            public Type_std_attributes,
            public virtual Type_handler
{
  // This class implements the code that returns the native value.
  // It does NOT implement field_type(), cmp_type(), return_type(), they are pure virtual. here.
  // It does NOT implement non-native val_xxx(), get_date(). They are pure virtual here.
};

Now we join the two branches into a single object:

class Item_func_udf_str: public Item_udf_func, public Type_handler_str
{
  // No needs to declare field_type(), result_type(), cmp_type().
  // No needs to declare val_real(), val_int(), val_decimal(), get_date().
  // They are derived automatically from Type_handler_str.
  // This class leaves only one pure virtual method val_str(),
  // and its children are responsible to implement it.
};
class Item_func_str: public Item_func, public Type_handler_str
{
  // Same here.
};
class Item_func_group_concat: public Item_sum, public Type_handler_str
{
  // Same here, but it does not have children and implements val_str() itself.
};

A similar example with Type_handler_hybrid_field_type

class Item_sum_sum :public Item_sum_num,
                    public Type_handler_hybrid_field_type
{
 // No needs to declare field_type(), result_type(), cmp_type()
 // They are automatically assigned from Type_handler_hybrid_field_type
}



 Comments   
Comment by Alexander Barkov [ 2016-11-26 ]

After discussions, it was decided not to use diamond inheritance.
Canceling this task.

Generated at Thu Feb 08 07:33:03 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.