drizzle
Profile
Search
 
Powered by SoftLayer
ConvertStructs

Goals of This Blueprint

Currently, there are numerous structures in the code base which should actually be classes since we aim for Drizzle to be developed in C++ (not C+). We can enumerate the goals of this task:


To help get started with this blueprint, we give 2 short examples to demonstrate what we are discussing.

Example of the Process

As an example, the following structure is declared in the drizzled/session.h file:

typedef struct drizzled_lock_st
{
  Table **table;
  uint32_t table_count;
  uint32_t lock_count;
  THR_LOCK_DATA **locks;
} DRIZZLE_LOCK;

A good first step would simply be to change this structure into a class and provide a default constructor. We would also move the new class we create into the drizzled/lock.h header file. Another goal of this blueprint is to add as many Doxygen comments as possible to the new classes that are created. Thus, the above structure might look as follows after this simple first step:

/**
 * @class
 *   DrizzleLock
 * @brief
 *   Brief description of what this class is for
 *
 * Can optionally provide a longer in-depth description of the class
 * here. While this is optional for a developer, it is highly encouraged
 * as it makes things a lot easier to understand.
 */
class DrizzleLock
{
public:
 
  DrizzleLock(Table **in_table,
                    uint32_t in_table_count,
                    uint32_t in_lock_count,
                    THR_LOCK_DATA **in_locks)
    :
      table(in_table),
      table_count(in_table_count),
      lock_count(in_lock_count),
      locks(in_locks)
  {}
 
  DrizzleLock()
    :
      table(NULL),
      table_count(0),
      lock_count(0),
      locks(NULL)
  {}
 
  /**
   * Descriptive comment on this member
   */
  Table **table;
 
  /**
   * Descriptive comment on this member
   */
  uint32_t table_count;
 
  /**
   * Descriptive comment on this member
   */
  uint32_t lock_count;
 
  /**
   * Descriptive comment on this member
   */
  THR_LOCK_DATA **locks;
};

Obviously, any client code which uses the DRIZZLE_LOCK structure will need to be modified to now use the DrizzleLock class instead. This would be a good time to make a commit, test that Drizzle still compiles, and that all tests still pass.

Now, the next step would be to go one further. Since we are programming in C++ and our aim is develop in an object-orientated manner, we would aim to encapsulate as much of the data in the DrizzleLock class as possible. Thus, we might modify DrizzleLock to have all data members private as follows:

/**
 * @class
 *   DrizzleLock
 * @brief
 *   Brief description of what this class is for
 *
 * Can optionally provide a longer in-depth description of the class
 * here. While this is optional for a developer, it is highly encouraged
 * as it makes things a lot easier to understand.
 */
class DrizzleLock
{
public:
 
  DrizzleLock(Table **in_table,
                    uint32_t in_table_count,
                    uint32_t in_lock_count,
                    THR_LOCK_DATA **in_locks)
    :
      table(in_table),
      table_count(in_table_count),
      lock_count(in_lock_count),
      locks(in_locks)
  {}
 
  DrizzleLock()
    :
      table(NULL),
      table_count(0),
      lock_count(0),
      locks(NULL)
  {}
 
  /**
    * @return comment describing what the return is here
    */
  uint32_t getTableCount() const
  {
    return table_count;
  }
 
  /**
    * @return comment describing what the return is here
    */
  uint32_t getLockCount() const
  {
    return lock_count;
  }
 
private:
 
  /**
    * Descriptive comment on this member
    */
  Table **table;
 
  /**
    * Descriptive comment on this member
    */
  uint32_t table_count;
 
  /**
    * Descriptive comment on this member
    */
  uint32_t lock_count;
 
  /**
    * Descriptive comment on this member
    */
  THR_LOCK_DATA **locks;
};

We would continue on in the manner outlined above adding getters/setters when necessary to access the encapsulated data in the DrizzleLock class. We would also need to modify client code that uses DrizzleLock classes to now call the accessors we develop instead of directly accessing DrizzleLock's data members.

After we have done this, another direction to proceed in may be to search for functions which operate on DrizzleLock objects and see if any of these functions can be made member functions of the DrizzleLock class. For example, a number of functions in drizzled/lock.cc might be good candidates to become member functions in DrizzleLock. One example is mysql_lock_tables().

Another Example

An example of a structure that I recently did this with is the st_field_info structure which used to look as follows in the drizzle/table.h header file:

typedef struct st_field_info
{
  /**
      This is used as column name.
  */
  const char* field_name;
  /**
     For string-type columns, this is the maximum number of
     characters. Otherwise, it is the 'display-length' for the column.
  */
  uint32_t field_length;
  /**
     This denotes data type for the column. For the most part, there seems to
     be one entry in the enum for each SQL data type, although there seem to
     be a number of additional entries in the enum.
  */
  enum enum_field_types field_type;
  int value;
  /**
     This is used to set column attributes. By default, columns are @c NOT
     @c NULL and @c SIGNED, and you can deviate from the default
     by setting the appopriate flags. You can use either one of the flags
     @c MY_I_S_MAYBE_NULL and @cMY_I_S_UNSIGNED or
     combine them using the bitwise or operator @c |. Both flags are
     defined in table.h.
   */
  uint32_t field_flags;        // Field atributes(maybe_null, signed, unsigned etc.)
  const char* old_name;
  /**
     This should be one of @c SKIP_OPEN_TABLE,
     @c OPEN_FRM_ONLY or @c OPEN_FULL_TABLE.
  */
  uint32_t open_method;
} ST_FIELD_INFO;

I created a new header file where this struct would live (drizzled/info_schema.h) and modified it to be a class with encapsulation as outlined in the previous example. The class that I replaced the structure with looks as follows:

/**
  * @class 
  *   ColumnInfo
  * @brief
  *   Represents a field (column) in an I_S table.
  */
class ColumnInfo
{
public:
  ColumnInfo(const char *in_name,
             uint32_t in_length,
             enum enum_field_types in_type,
             int32_t in_value,
             uint32_t in_flags,
             const char *in_old_name,
             uint32_t in_open_method)
    :
      name(in_name),
      length(in_length),
      type(in_type),
      value(in_value),
      flags(in_flags),
      old_name(in_old_name),
      open_method(in_open_method)
  {}
 
  ColumnInfo()
    :
      name(NULL),
      length(0),
      type(DRIZZLE_TYPE_VARCHAR),
      flags(0),
      old_name(NULL),
      open_method(SKIP_OPEN_TABLE)
  {}
 
  /**
    * @return the name of this column.
    */
  const char *getName() const
  {
    return name;
  }
 
  /**
    * This method is only ever called from the
    * InfoSchemaMethods::oldFormat() methods. It is mostly
    * for old SHOW compatability. It is used when a list
    * of fields need to be generated for SHOW. The names
    * for those fields (or columns) are found by calling
    * this method on each column in the I_S table.
    *
    * @return the old name of this column.
    */
  const char *getOldName() const
  {
    return old_name;
  }
 
  /**
    * @return the open method for this column.
    */
  uint32_t getOpenMethod() const
  {
    return open_method;
  }
 
  /**
    * @return the flags for this column.
    */
  uint32_t getFlags() const
  {
    return flags;
  }
 
  /**
    * @return the length of this column.
    */
  uint32_t getLength() const
  {
    return length;
  }
 
  /**
    * @return the value of this column.
    */
  int32_t getValue() const
  {
    return value;
  }
 
  /**
    * @return this column's type.
    */
  enum enum_field_types getType() const
  {
    return type;
  }
 
private:
 
  /**
    * This is used as column name.
    */
  const char *name;
 
  /**
    * For string-type columns, this is the maximum number of
    * characters. Otherwise, it is the 'display-length' for the column.
    */
  uint32_t length;
 
  /**
    * This denotes data type for the column. For the most part, there seems to
    * be one entry in the enum for each SQL data type, although there seem to
    * be a number of additional entries in the enum.
    */
  enum enum_field_types type;
 
  int32_t value;
 
  /**
    * This is used to set column attributes. By default, columns are @c NOT
    * @c NULL and @c SIGNED, and you can deviate from the default
    * by setting the appopriate flags. You can use either one of the flags
    * @c MY_I_S_MAYBE_NULL and @cMY_I_S_UNSIGNED or
    * combine them using the bitwise or operator @c |. Both flags are
    * defined in table.h.
    */
  uint32_t flags;
 
  /**
    * The name of this column which is used for old SHOW
    * compatability.
    */
  const char *old_name;
 
  /**
    * This should be one of @c SKIP_OPEN_TABLE,
    * @c OPEN_FRM_ONLY or @c OPEN_FULL_TABLE.
    */
  uint32_t open_method;
 
};

As you can see, we made all data members private, provided accessors for those data members when appropriate, followed all coding standards, and added copious Doxygen comments to the class.

Site generously hosted by SoftLayer Technologies