diff --git a/sql/field.cc b/sql/field.cc
index a5d5da5eaca601fe1466145a634b44d2721ecca5..20ac47d49f5d2ec759c047b05d7212c1f3bb3985 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -10347,6 +10347,7 @@ bool Column_definition::fix_attributes_temporal_with_time(uint int_part_length)
              MAX_DATETIME_PRECISION);
     return true;
   }
+  decimals= length;
   length+= int_part_length + (length ? 1 : 0);
   return false;
 }
@@ -10552,6 +10553,7 @@ bool Field_vers_trx_id::test_if_equality_guarantees_uniqueness(const Item* item)
 
 Column_definition_attributes::Column_definition_attributes(const Field *field)
  :length(field->character_octet_length() / field->charset()->mbmaxlen),
+  decimals(field->decimals()),
   unireg_check(field->unireg_check),
   interval(NULL),
   charset(field->charset()), // May be NULL ptr
@@ -10572,7 +10574,6 @@ Column_definition::Column_definition(THD *thd, Field *old_field,
   pack_length=old_field->pack_length();
   set_handler(old_field->type_handler());
   comment=    old_field->comment;
-  decimals=   old_field->decimals();
   vcol_info=  old_field->vcol_info;
   option_list= old_field->option_list;
   compression_method_ptr= 0;
diff --git a/sql/field.h b/sql/field.h
index 981f0fa3be4d3e3498d04484f34f3b2b73295979..27a4f18fa7177046585a96dddd8c6b66d5d5ed37 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -4790,6 +4790,7 @@ class Column_definition_attributes
     max number of characters.
   */
   ulonglong length;
+  uint decimals;
   Field::utype unireg_check;
   const TYPELIB *interval;            // Which interval to use
   CHARSET_INFO *charset;
@@ -4797,6 +4798,7 @@ class Column_definition_attributes
   uint pack_flag;
   Column_definition_attributes()
    :length(0),
+    decimals(0),
     unireg_check(Field::NONE),
     interval(NULL),
     charset(&my_charset_bin),
@@ -4816,8 +4818,12 @@ class Column_definition_attributes
   uint pack_flag_to_pack_length() const;
   void frm_pack_basic(uchar *buff) const;
   void frm_pack_charset(uchar *buff) const;
+  void frm_pack_numeric_with_dec(uchar *buff) const;
   void frm_unpack_basic(const uchar *buff);
   bool frm_unpack_charset(TABLE_SHARE *share, const uchar *buff);
+  bool frm_unpack_numeric_with_dec(TABLE_SHARE *share, const uchar *buff);
+  bool frm_unpack_temporal_with_dec(TABLE_SHARE *share, uint intlen,
+                                    const uchar *buff);
 };
 
 
@@ -4887,7 +4893,7 @@ class Column_definition: public Sql_alloc,
     for most of the types, or of bytes for BLOBs or numeric types.
   */
   uint32 char_length;
-  uint  decimals, flags, pack_length;
+  uint  flags, pack_length;
   List<String> interval_list;
   engine_option_value *option_list;
 
@@ -4910,7 +4916,7 @@ class Column_definition: public Sql_alloc,
    :Type_handler_hybrid_field_type(&type_handler_null),
     compression_method_ptr(0),
     comment(null_clex_str),
-    on_update(NULL), invisible(VISIBLE), char_length(0), decimals(0),
+    on_update(NULL), invisible(VISIBLE), char_length(0),
     flags(0), pack_length(0),
     option_list(NULL),
     vcol_info(0), default_value(0), check_constraint(0),
@@ -5009,7 +5015,7 @@ class Column_definition: public Sql_alloc,
   bool prepare_stage2_varchar(ulonglong table_flags);
   bool prepare_stage2_typelib(const char *type_name, uint field_flags,
                               uint *dup_val_count);
-  uint pack_flag_numeric(uint dec) const;
+  uint pack_flag_numeric() const;
   uint sign_length() const { return flags & UNSIGNED_FLAG ? 0 : 1; }
   bool check_length(uint mysql_errno, uint max_allowed_length) const;
   bool fix_attributes_real(uint default_length);
@@ -5471,6 +5477,8 @@ bool check_expression(Virtual_column_info *vcol, const LEX_CSTRING *name,
 #define FIELDFLAG_DEC_SHIFT		8
 #define FIELDFLAG_MAX_DEC               63U
 
+#define FIELDFLAG_DEC_MASK              0x3F00U
+
 #define MTYP_TYPENR(type) ((type) & 127U) // Remove bits from type
 
 #define f_is_dec(x)		((x) & FIELDFLAG_DECIMAL)
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 69672eebd524252f278298f901dd2f8e788dcd96..b8f8aae57fb18746423609fa1531f29933f1f678 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2920,12 +2920,11 @@ bool Column_definition::prepare_stage2_typelib(const char *type_name,
 }
 
 
-uint Column_definition::pack_flag_numeric(uint dec) const
+uint Column_definition::pack_flag_numeric() const
 {
   return (FIELDFLAG_NUMBER |
           (flags & UNSIGNED_FLAG ? 0 : FIELDFLAG_DECIMAL)  |
-          (flags & ZEROFILL_FLAG ? FIELDFLAG_ZEROFILL : 0) |
-          (dec << FIELDFLAG_DEC_SHIFT));
+          (flags & ZEROFILL_FLAG ? FIELDFLAG_ZEROFILL : 0));
 }
 
 
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 2289b900460b8877cf5a5d03b2a585fa02f30e20..c8a5ada46c982ef417a78efab26cdcc81b9d832f 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -3145,8 +3145,7 @@ bool Type_handler::
        Column_definition_prepare_stage2_legacy_num(Column_definition *def,
                                                    enum_field_types type) const
 {
-  def->pack_flag= def->pack_flag_numeric(def->decimals) |
-                  f_settype((uint) type);
+  def->pack_flag= def->pack_flag_numeric() | f_settype((uint) type);
   return false;
 }
 
@@ -3162,7 +3161,8 @@ bool Type_handler::
   */
   if (dec >= FLOATING_POINT_DECIMALS)
     dec= FLOATING_POINT_DECIMALS;
-  def->pack_flag= def->pack_flag_numeric(dec) | f_settype((uint) type);
+  def->decimals= dec;
+  def->pack_flag= def->pack_flag_numeric() | f_settype((uint) type);
   return false;
 }
 
@@ -3171,7 +3171,7 @@ bool Type_handler_newdecimal::
                                         handler *file,
                                         ulonglong table_flags) const
 {
-  def->pack_flag= def->pack_flag_numeric(def->decimals);
+  def->pack_flag= def->pack_flag_numeric();
   return false;
 }
 
@@ -7790,11 +7790,12 @@ Field *Type_handler_olddecimal::
                             const Column_definition_attributes *attr,
                             uint32 flags) const
 {
+  DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
   return new (mem_root)
     Field_decimal(rec.ptr(), (uint32) attr->length,
                   rec.null_ptr(), rec.null_bit(),
                   attr->unireg_check, name,
-                  f_decimals(attr->pack_flag),
+                  (uint8) attr->decimals,
                   f_is_zerofill(attr->pack_flag) != 0,
                   f_is_dec(attr->pack_flag) == 0);
 }
@@ -7807,11 +7808,12 @@ Field *Type_handler_newdecimal::
                             const Column_definition_attributes *attr,
                             uint32 flags) const
 {
+  DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
   return new (mem_root)
     Field_new_decimal(rec.ptr(), (uint32) attr->length,
                       rec.null_ptr(), rec.null_bit(),
                       attr->unireg_check, name,
-                      f_decimals(attr->pack_flag),
+                      (uint8) attr->decimals,
                       f_is_zerofill(attr->pack_flag) != 0,
                       f_is_dec(attr->pack_flag) == 0);
 }
@@ -7824,7 +7826,8 @@ Field *Type_handler_float::
                             const Column_definition_attributes *attr,
                             uint32 flags) const
 {
-  int decimals= f_decimals(attr->pack_flag);
+  DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
+  uint decimals= attr->decimals;
   if (decimals == FLOATING_POINT_DECIMALS)
     decimals= NOT_FIXED_DEC;
   return new (mem_root)
@@ -7843,7 +7846,8 @@ Field *Type_handler_double::
                             const Column_definition_attributes *attr,
                             uint32 flags) const
 {
-  int decimals= f_decimals(attr->pack_flag);
+  DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
+  uint decimals= attr->decimals;
   if (decimals == FLOATING_POINT_DECIMALS)
     decimals= NOT_FIXED_DEC;
   return new (mem_root)
@@ -7947,6 +7951,7 @@ Field *Type_handler_timestamp::
                             const Column_definition_attributes *attr,
                             uint32 flags) const
 {
+  DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
   return new_Field_timestamp(mem_root,
                              rec.ptr(), rec.null_ptr(), rec.null_bit(),
                              attr->unireg_check, name, share,
@@ -7961,6 +7966,7 @@ Field *Type_handler_timestamp2::
                             const Column_definition_attributes *attr,
                             uint32 flags) const
 {
+  DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
   return new (mem_root)
     Field_timestampf(rec.ptr(), rec.null_ptr(), rec.null_bit(),
                      attr->unireg_check,
@@ -8014,6 +8020,7 @@ Field *Type_handler_time::
                             const Column_definition_attributes *attr,
                             uint32 flags) const
 {
+  DBUG_ASSERT(attr->decimals == attr->temporal_dec(MIN_TIME_WIDTH));
   return new_Field_time(mem_root, rec.ptr(), rec.null_ptr(), rec.null_bit(),
                         attr->unireg_check, name,
                         attr->temporal_dec(MIN_TIME_WIDTH));
@@ -8027,6 +8034,7 @@ Field *Type_handler_time2::
                             const Column_definition_attributes *attr,
                             uint32 flags) const
 {
+  DBUG_ASSERT(attr->decimals == attr->temporal_dec(MIN_TIME_WIDTH));
   return new (mem_root)
     Field_timef(rec.ptr(), rec.null_ptr(), rec.null_bit(),
                 attr->unireg_check, name,
@@ -8041,6 +8049,7 @@ Field *Type_handler_datetime::
                             const Column_definition_attributes *attr,
                             uint32 flags) const
 {
+  DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
   return new_Field_datetime(mem_root, rec.ptr(), rec.null_ptr(), rec.null_bit(),
                             attr->unireg_check, name,
                             attr->temporal_dec(MAX_DATETIME_WIDTH));
@@ -8054,6 +8063,7 @@ Field *Type_handler_datetime2::
                             const Column_definition_attributes *attr,
                             uint32 flags) const
 {
+  DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
   return new (mem_root)
     Field_datetimef(rec.ptr(), rec.null_ptr(), rec.null_bit(),
                     attr->unireg_check, name,
@@ -8188,6 +8198,110 @@ void Type_handler::
 }
 
 
+void Type_handler_real_result::
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+                                        uchar *buff) const
+{
+  def->frm_pack_numeric_with_dec(buff);
+}
+
+
+void Type_handler_decimal_result::
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+                                        uchar *buff) const
+{
+  def->frm_pack_numeric_with_dec(buff);
+}
+
+
+void Type_handler_int_result::
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+                                        uchar *buff) const
+{
+  DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+  DBUG_ASSERT(def->decimals == 0);
+  Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_date_common::
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+                                        uchar *buff) const
+{
+  DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+  DBUG_ASSERT(def->decimals == 0);
+  Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_bit::
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+                                        uchar *buff) const
+{
+  DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_TREAT_BIT_AS_CHAR) == 0);
+  DBUG_ASSERT(def->decimals == 0);
+  Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_blob_common::
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+                                        uchar *buff) const
+{
+  DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_BLOB) == 0);
+  DBUG_ASSERT(def->decimals == 0 ||
+              def->decimals == NOT_FIXED_DEC);
+  Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_null::
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+                                        uchar *buff) const
+{
+  DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+  DBUG_ASSERT(def->decimals == NOT_FIXED_DEC);
+  Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_string_result::
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+                                        uchar *buff) const
+{
+  DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+  DBUG_ASSERT(def->decimals == 0 || def->decimals == NOT_FIXED_DEC);
+  Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_enum::
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+                                        uchar *buff) const
+{
+  DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_INTERVAL) == 0);
+  DBUG_ASSERT(def->decimals == 0);
+  Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_set::
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+                                        uchar *buff) const
+{
+  DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_BITFIELD) == 0);
+  DBUG_ASSERT(def->decimals == 0);
+  Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_temporal_result::
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+                                        uchar *buff) const
+{
+  DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+  Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
 
 
 /***************************************************************************/
@@ -8204,6 +8318,61 @@ bool Type_handler::
 }
 
 
+bool Type_handler_real_result::
+  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+                                          TABLE_SHARE *share,
+                                          const uchar *buffer,
+                                          LEX_CUSTRING *gis_options)
+                                          const
+{
+  return attr->frm_unpack_numeric_with_dec(share, buffer);
+}
+
+
+bool Type_handler_decimal_result::
+  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+                                          TABLE_SHARE *share,
+                                          const uchar *buffer,
+                                          LEX_CUSTRING *gis_options)
+                                          const
+{
+  return attr->frm_unpack_numeric_with_dec(share, buffer);
+}
+
+
+bool Type_handler_time_common::
+  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+                                          TABLE_SHARE *share,
+                                          const uchar *buffer,
+                                          LEX_CUSTRING *gis_options)
+                                          const
+{
+  return attr->frm_unpack_temporal_with_dec(share, MIN_TIME_WIDTH, buffer);
+}
+
+
+bool Type_handler_datetime_common::
+  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+                                          TABLE_SHARE *share,
+                                          const uchar *buffer,
+                                          LEX_CUSTRING *gis_options)
+                                          const
+{
+  return attr->frm_unpack_temporal_with_dec(share, MAX_DATETIME_WIDTH, buffer);
+}
+
+
+bool Type_handler_timestamp_common::
+  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+                                          TABLE_SHARE *share,
+                                          const uchar *buffer,
+                                          LEX_CUSTRING *gis_options)
+                                          const
+{
+  return attr->frm_unpack_temporal_with_dec(share, MAX_DATETIME_WIDTH, buffer);
+}
+
+
 bool Type_handler_null::Item_const_eq(const Item_const *a,
                                       const Item_const *b,
                                       bool binary_cmp) const
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 778159106ea1587007876483f0151d8a259cb181..a39b2d837c29235ee1fe21785f7a6398c1cca0d2 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -4395,6 +4395,15 @@ class Type_handler_real_result: public Type_handler_numeric
                                               Column_definition *c,
                                               const Field *field)
                                               const override;
+  void
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+                                        uchar *buff) const override;
+  bool
+  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+                                          TABLE_SHARE *share,
+                                          const uchar *buffer,
+                                          LEX_CUSTRING *gis_options)
+                                          const override;
   int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
                                const override;
   bool subquery_type_allows_materialization(const Item *inner,
@@ -4507,6 +4516,15 @@ class Type_handler_decimal_result: public Type_handler_numeric
   Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const;
   void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
                      Sort_param *param) const;
+  void
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+                                        uchar *buff) const override;
+  bool
+  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+                                          TABLE_SHARE *share,
+                                          const uchar *buffer,
+                                          LEX_CUSTRING *gis_options)
+                                          const override;
   void sortlength(THD *thd,
                   const Type_std_attributes *item,
                   SORT_FIELD_ATTR *attr) const;
@@ -4735,6 +4753,9 @@ class Type_handler_int_result: public Type_handler_numeric
   Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override;
   void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
                      Sort_param *param) const override;
+  void
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+                                        uchar *buff) const override;
   void sortlength(THD *thd,
                   const Type_std_attributes *item,
                   SORT_FIELD_ATTR *attr) const override;
@@ -4823,6 +4844,9 @@ class Type_handler_temporal_result: public Type_handler
   Item_result result_type() const override { return STRING_RESULT; }
   Item_result cmp_type() const override { return TIME_RESULT; }
   virtual ~Type_handler_temporal_result() {}
+  void
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+                                        uchar *buff) const override;
   void make_sort_key(uchar *to, Item *item,  const SORT_FIELD_ATTR *sort_field,
                      Sort_param *param) const override;
   void sortlength(THD *thd,
@@ -4928,6 +4952,9 @@ class Type_handler_string_result: public Type_handler
                                          const handler *file,
                                          const Schema_specification_st *schema)
                                          const override;
+  void
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+                                        uchar *buff) const override;
   uint32 max_display_length(const Item *item) const override;
   bool Item_const_eq(const Item_const *a, const Item_const *b,
                      bool binary_cmp) const override;
@@ -5454,6 +5481,9 @@ class Type_handler_bit: public Type_handler_int_result
   uint32 max_display_length_for_field(const Conv_source &src) const override;
   uint32 calc_pack_length(uint32 length) const override { return length / 8; }
   uint calc_key_length(const Column_definition &def) const override;
+  void
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+                                        uchar *buff) const override;
   bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
   {
     return Item_send_str(item, protocol, buf);
@@ -5662,6 +5692,12 @@ class Type_handler_time_common: public Type_handler_temporal_result
                                const override;
   void Column_definition_implicit_upgrade(Column_definition *c) const override;
   bool Column_definition_fix_attributes(Column_definition *c) const override;
+  bool
+  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+                                          TABLE_SHARE *share,
+                                          const uchar *buffer,
+                                          LEX_CUSTRING *gis_options)
+                                          const override;
   bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
   bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
   {
@@ -5850,6 +5886,9 @@ class Type_handler_date_common: public Type_handler_temporal_with_date
                                        const Column_definition &def)
                                        const override;
   bool Column_definition_fix_attributes(Column_definition *c) const override;
+  void
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+                                        uchar *buff) const override;
   uint Item_decimal_precision(const Item *item) const override;
   String *print_item_value(THD *thd, Item *item, String *str) const override;
   Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
@@ -5965,6 +6004,12 @@ class Type_handler_datetime_common: public Type_handler_temporal_with_date
                                        const override;
   void Column_definition_implicit_upgrade(Column_definition *c) const override;
   bool Column_definition_fix_attributes(Column_definition *c) const override;
+  bool
+  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+                                          TABLE_SHARE *share,
+                                          const uchar *buffer,
+                                          LEX_CUSTRING *gis_options)
+                                          const override;
   uint Item_decimal_scale(const Item *item) const override
   {
     return Item_decimal_scale_with_seconds(item);
@@ -6096,6 +6141,12 @@ class Type_handler_timestamp_common: public Type_handler_temporal_with_date
     return true;
   }
   void Column_definition_implicit_upgrade(Column_definition *c) const override;
+  bool
+  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+                                          TABLE_SHARE *share,
+                                          const uchar *buffer,
+                                          LEX_CUSTRING *gis_options)
+                                          const override;
   bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
                      Item *a, Item *b) const override;
   bool Item_val_native_with_conversion(THD *thd, Item *, Native *to)
@@ -6342,6 +6393,9 @@ class Type_handler_null: public Type_handler_general_purpose_string
                                         handler *file,
                                         ulonglong table_flags) const override
   { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_NULL); }
+  void
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+                                        uchar *buff) const override;
   Field *make_table_field(MEM_ROOT *root,
                           const LEX_CSTRING *name,
                           const Record_addr &addr,
@@ -6553,6 +6607,9 @@ class Type_handler_blob_common: public Type_handler_longstr
   bool Column_definition_prepare_stage2(Column_definition *c,
                                         handler *file,
                                         ulonglong table_flags) const override;
+  void
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+                                        uchar *buff) const override;
   bool Key_part_spec_init_ft(Key_part_spec *part,
                              const Column_definition &def) const override;
   bool Key_part_spec_init_primary(Key_part_spec *part,
@@ -6735,6 +6792,9 @@ class Type_handler_enum: public Type_handler_typelib
   }
   uint32 calc_pack_length(uint32 length) const override;
   uint calc_key_length(const Column_definition &def) const override;
+  void
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+                                        uchar *buff) const override;
   Field *make_conversion_table_field(MEM_ROOT *root,
                                      TABLE *table, uint metadata,
                                      const Field *target)
@@ -6775,6 +6835,9 @@ class Type_handler_set: public Type_handler_typelib
   }
   uint32 calc_pack_length(uint32 length) const override;
   uint calc_key_length(const Column_definition &def) const override;
+  void
+  Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+                                        uchar *buff) const override;
   Field *make_conversion_table_field(MEM_ROOT *root,
                                      TABLE *table, uint metadata,
                                      const Field *target)
diff --git a/sql/sql_type_geom.cc b/sql/sql_type_geom.cc
index 49b0848cf5ee0ce0a4554f781467090743057a8b..5d6e5184b35eb74e7342033209ed972b51fefb87 100644
--- a/sql/sql_type_geom.cc
+++ b/sql/sql_type_geom.cc
@@ -659,6 +659,7 @@ void Type_handler_geometry::
   Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                         uchar *buff) const
 {
+  DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_GEOM) == 0);
   def->frm_pack_basic(buff);
   buff[11]= 0;
   buff[14]= (uchar) geometry_type();
diff --git a/sql/table.cc b/sql/table.cc
index 6e5e86468da8330cbb22b2133ffbcd1338ab3e2c..6c4d01852f5b5181fcca73fa14e08e424eb4dc09 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -967,6 +967,38 @@ void Column_definition_attributes::frm_unpack_basic(const uchar *buff)
 }
 
 
+void Column_definition_attributes::frm_pack_numeric_with_dec(uchar *buff) const
+{
+  DBUG_ASSERT(f_decimals(pack_flag) == 0);
+  uint tmp_pack_flag= pack_flag | (decimals << FIELDFLAG_DEC_SHIFT);
+  int2store(buff + 3, length);
+  int2store(buff + 8, tmp_pack_flag);
+  buff[10]= (uchar) unireg_check;
+}
+
+
+bool
+Column_definition_attributes::frm_unpack_numeric_with_dec(TABLE_SHARE *share,
+                                                          const uchar *buff)
+{
+  frm_unpack_basic(buff);
+  decimals= f_decimals(pack_flag);
+  pack_flag&= ~FIELDFLAG_DEC_MASK;
+  return frm_unpack_charset(share, buff);
+}
+
+
+bool
+Column_definition_attributes::frm_unpack_temporal_with_dec(TABLE_SHARE *share,
+                                                           uint intlen,
+                                                           const uchar *buff)
+{
+  frm_unpack_basic(buff);
+  decimals= temporal_dec(intlen);
+  return frm_unpack_charset(share, buff);
+}
+
+
 void Column_definition_attributes::frm_pack_charset(uchar *buff) const
 {
   buff[11]= (uchar) (charset->number >> 8);
@@ -2346,6 +2378,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
       attr.length= (uint) strpos[3];
       recpos=	    uint2korr(strpos+4),
       attr.pack_flag=    uint2korr(strpos+6);
+      if (f_is_num(attr.pack_flag))
+      {
+        attr.decimals= f_decimals(attr.pack_flag);
+        attr.pack_flag&= ~FIELDFLAG_DEC_MASK;
+      }
       attr.pack_flag&=   ~FIELDFLAG_NO_DEFAULT;     // Safety for old files
       attr.unireg_check=  (Field::utype) MTYP_TYPENR((uint) strpos[8]);
       interval_nr=  (uint) strpos[10];