Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-9221

Derive Item from Type_handler virtually

    Details

      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
      }
      

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                bar Alexander Barkov
                Reporter:
                bar Alexander Barkov
              • Votes:
                0 Vote for this issue
                Watchers:
                2 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: