Adding a New Data Type to MariaDB with Type_handler – Part 4

This is part 4 of a series related to extending MariaDB with a custom data type using the Type_handler framework.

You can find the previous articles below:

Overriding Existing Types

In the previous examples, our MONEY data type inherits from DOUBLE and then we override some methods.

But all the methods of every type cannot be overridden. For example, if we would like to change how the money column is sorted, we would have to override the Field_double::sort_string() method. But this method is defined as final in sql/field.h:

void sort_string(uchar *buff, uint length) override final;

This means that we need to switch to Field_real for example. But Field_real is abstract and requires that we implement methods that Field_double provided for free.

Therefore, Field_money will have to provide its own numeric field operations (store, val_real, val_str, cmp, …).

This is a table derived directly from the source code that lists all field types:

Field typeStatusMain limitation
Field_numAbstract baseNumeric helper layer only; not instantiable
Field_strAbstract baseString helper layer only; not instantiable
Field_longstrAbstract baseRequires max_data_length and packed_col_length implementation
Field_realAbstract baseFloating/real helper only; key numeric operations must be implemented by child
Field_decimalConcrete finalFixed behavior; cannot subclass
Field_new_decimalConcrete finalFixed behavior; cannot subclass
Field_intAbstract baseRequires type_limits_int implementation
Field_tinyConcreteExtendable, but still tied to integer semantics
Field_shortConcreteExtendable, integer semantics
Field_mediumConcrete finalCannot subclass
Field_longConcrete finalCannot subclass
Field_longlongConcreteExtendable, integer semantics
Field_vers_trx_idConcreteSpecialized versioned transaction-id semantics
Field_floatConcrete finalCannot subclass
Field_doubleConcrete (many methods final)Critical methods are locked; notably cmp is final in this class
Field_nullConcreteRepresents NULL-like behavior; many operations fixed
Field_temporalAbstract baseTemporal helper layer only
Field_temporal_with_dateAbstract baseRequires store_TIME and get_TIME
Field_timestampAbstract baseRequires store_TIMEVAL
Field_timestamp0ConcreteTimestamp(0)-style storage semantics
Field_timestamp_with_decAbstract baseFractional timestamp base
Field_timestamp_hiresConcreteSpecialized hires timestamp behavior
Field_timestampfConcreteMySQL56 timestamp(0..6) variant
Field_yearConcrete finalCannot subclass
Field_date_commonAbstract baseShared date logic; concrete date classes implement storage details
Field_dateConcrete finalCannot subclass
Field_newdateConcrete finalCannot subclass
Field_timeAbstract baseRequires store_TIME
Field_time0Concrete finalCannot subclass
Field_time_with_decAbstract baseFractional time base
Field_time_hiresConcrete finalCannot subclass
Field_timefConcrete finalCannot subclass
Field_datetimeAbstract baseRequires date-time low-level methods from child
Field_datetime0Concrete finalCannot subclass
Field_datetime_with_decAbstract baseFractional datetime base
Field_datetime_hiresConcrete finalCannot subclass
Field_datetimefConcrete finalCannot subclass
Field_stringConcrete finalFixed CHAR behavior
Field_varstringConcreteExtendable VARCHAR behavior
Field_varstring_compressedConcrete finalCannot subclass; key/index behavior intentionally restricted
Field_blobConcreteComplex pointer/length semantics; engine-sensitive behavior
Field_blob_compressedConcrete finalCannot subclass; key/index operations restricted
Field_enumConcreteENUM semantics; some optimizer paths intentionally restricted
Field_setConcrete finalCannot subclass
Field_bitConcreteBit storage has special key/compare constraints
Field_bit_as_charConcrete finalCannot subclass
Field_rowConcrete finalSpecial virtual row type; many normal field operations are not applicable

Abstract” means you cannot instantiate it directly; you must derive and implement missing behavior.
Concrete” means instantiable.
Final” means concrete and cannot be subclassed.

Deriving from Field_real

So, as we need to derive from Field_real to be able to modify the sorting, we need to implement these in our class to be concrete and useful:

  1. type_handler
  2. key_type
  3. store from string
  4. store from double
  5. store from longlong
  6. reset
  7. val_real
  8. val_int
  9. val_str
  10. send
  11. cmp
  12. sort_string
  13. pack_length
  14. row_pack_length
  15. get_max_int_value
  16. binlog_type_info

This is exactly what we did, and we modified even more the sort_string() method to sort the content of our MONEY column in reverse order:

void Field_money::sort_string(uchar *buff, uint length __attribute__((unused)))
{
  double nr;
  float8get(nr,ptr);
  change_double_for_sort(nr, buff);

  // Invert key bytes so lexicographic ascending comparison
  // yields descending order.
  for (uint i= 0; i < sizeof(double); i++)
    buff[i]^= 0xFF;
}

This is a stupid sort, but it’s there only as an example.

Let’s test it:

MariaDB [test]> install soname 'type_money';
Query OK, 0 rows affected (0.012 sec)

MariaDB [test]> create table t1 (id int auto_increment primary key, amount money(10,2)) engine=innodb;
Query OK, 0 rows affected (0.008 sec)

MariaDB [test]> insert into t1 (amount) values (15678.309);
Query OK, 1 row affected (0.016 sec)

MariaDB [test]> insert into t1 (amount) values (24.4);
Query OK, 1 row affected (0.003 sec)

MariaDB [test]> insert into t1 (amount) values (41578.4);
Query OK, 1 row affected (0.003 sec)

MariaDB [test]> select * from t1 order by amount;
+----+-----------+
| id | amount    |
+----+-----------+
|  3 | $41578.40 |
|  1 | $15678.31 |
|  2 | $24.40    |
+----+-----------+
3 rows in set (0.002 sec)

We can see that the order is reversed.

The code is available in the part4 branch of the GitHub repo.

Happy compiling and happy coding.

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Leave a Reply

Your email address will not be published. Required fields are marked *