commit 73f69b23465d2a1d4f4e9bc73b3efcae78c66cdc
Author: Alexander Barkov <bar@mariadb.org>
Date:   Wed Nov 16 13:24:28 2016 +0400

    MDEV-11294 Move definitions of Derivation, DTCollation, Type_std_attributes from field.h and item.h to sql_type.h
    
    Note, this patchs revealed a bug in Item_func_sp::fix_length_and_dec().
    See MDEV-11292 for details. This patch does not fix MDEV-11292.

diff --git a/sql/field.h b/sql/field.h
index cc8f758..db8eedd 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -31,6 +31,7 @@
 #include "my_decimal.h"                         /* my_decimal */
 #include "sql_error.h"                          /* Sql_condition */
 #include "compat56.h"
+#include "sql_type.h"                           /* Type_std_attributes */
 
 class Send_field;
 class Copy_field;
@@ -403,25 +404,10 @@ class Value_source
 };
 
 
-enum Derivation
-{
-  DERIVATION_IGNORABLE= 6,
-  DERIVATION_NUMERIC= 5,
-  DERIVATION_COERCIBLE= 4,
-  DERIVATION_SYSCONST= 3,
-  DERIVATION_IMPLICIT= 2,
-  DERIVATION_NONE= 1,
-  DERIVATION_EXPLICIT= 0
-};
-
-
 #define STORAGE_TYPE_MASK 7
 #define COLUMN_FORMAT_MASK 7
 #define COLUMN_FORMAT_SHIFT 3
 
-#define my_charset_numeric      my_charset_latin1
-#define MY_REPERTOIRE_NUMERIC   MY_REPERTOIRE_ASCII
-
 /* The length of the header part for each virtual column in the .frm file */
 #define FRM_VCOL_OLD_HEADER_SIZE(b) (3 + MY_TEST(b))
 #define FRM_VCOL_NEW_BASE_SIZE 16
@@ -778,6 +764,18 @@ class Field: public Value_source
         uchar null_bit_arg, utype unireg_check_arg,
         const char *field_name_arg);
   virtual ~Field() {}
+
+  DTCollation dtcollation() const
+  {
+    return DTCollation(charset(), derivation(), repertoire());
+  }
+  Type_std_attributes type_std_attributes() const
+  {
+    return Type_std_attributes(field_length, decimals(),
+                               MY_TEST(flags & UNSIGNED_FLAG),
+                               dtcollation());
+  }
+
   /**
     Convenience definition of a copy function returned by
     Field::get_copy_func()
diff --git a/sql/item.h b/sql/item.h
index 6c9307f..0fe850b 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -88,124 +88,11 @@ bool mark_unsupported_function(const char *w1, const char *w2,
 #define SPLIT_SUM_SKIP_REGISTERED 1     /* Skip registered funcs */
 #define SPLIT_SUM_SELECT 2		/* SELECT item; Split all parts */
 
-/*
-   "Declared Type Collation"
-   A combination of collation and its derivation.
-
-  Flags for collation aggregation modes:
-  MY_COLL_ALLOW_SUPERSET_CONV  - allow conversion to a superset
-  MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value
-                                 (i.e. constant).
-  MY_COLL_ALLOW_CONV           - allow any kind of conversion
-                                 (combination of the above two)
-  MY_COLL_ALLOW_NUMERIC_CONV   - if all items were numbers, convert to
-                                 @@character_set_connection
-  MY_COLL_DISALLOW_NONE        - don't allow return DERIVATION_NONE
-                                 (e.g. when aggregating for comparison)
-  MY_COLL_CMP_CONV             - combination of MY_COLL_ALLOW_CONV
-                                 and MY_COLL_DISALLOW_NONE
-*/
-
-#define MY_COLL_ALLOW_SUPERSET_CONV   1
-#define MY_COLL_ALLOW_COERCIBLE_CONV  2
-#define MY_COLL_DISALLOW_NONE         4
-#define MY_COLL_ALLOW_NUMERIC_CONV    8
-
-#define MY_COLL_ALLOW_CONV (MY_COLL_ALLOW_SUPERSET_CONV | MY_COLL_ALLOW_COERCIBLE_CONV)
-#define MY_COLL_CMP_CONV   (MY_COLL_ALLOW_CONV | MY_COLL_DISALLOW_NONE)
 
 #define NO_EXTRACTION_FL              (1 << 6)
 #define FULL_EXTRACTION_FL            (1 << 7)
 #define EXTRACTION_MASK               (NO_EXTRACTION_FL | FULL_EXTRACTION_FL)
 
-class DTCollation {
-public:
-  CHARSET_INFO     *collation;
-  enum Derivation derivation;
-  uint repertoire;
-  
-  void set_repertoire_from_charset(CHARSET_INFO *cs)
-  {
-    repertoire= cs->state & MY_CS_PUREASCII ?
-                MY_REPERTOIRE_ASCII : MY_REPERTOIRE_UNICODE30;
-  }
-  DTCollation()
-  {
-    collation= &my_charset_bin;
-    derivation= DERIVATION_NONE;
-    repertoire= MY_REPERTOIRE_UNICODE30;
-  }
-  DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg)
-  {
-    collation= collation_arg;
-    derivation= derivation_arg;
-    set_repertoire_from_charset(collation_arg);
-  }
-  DTCollation(CHARSET_INFO *collation_arg,
-              Derivation derivation_arg,
-              uint repertoire_arg)
-   :collation(collation_arg),
-    derivation(derivation_arg),
-    repertoire(repertoire_arg)
-  { }
-  void set(const DTCollation &dt)
-  { 
-    collation= dt.collation;
-    derivation= dt.derivation;
-    repertoire= dt.repertoire;
-  }
-  void set(CHARSET_INFO *collation_arg, Derivation derivation_arg)
-  {
-    collation= collation_arg;
-    derivation= derivation_arg;
-    set_repertoire_from_charset(collation_arg);
-  }
-  void set(CHARSET_INFO *collation_arg,
-           Derivation derivation_arg,
-           uint repertoire_arg)
-  {
-    collation= collation_arg;
-    derivation= derivation_arg;
-    repertoire= repertoire_arg;
-  }
-  void set_numeric()
-  {
-    collation= &my_charset_numeric;
-    derivation= DERIVATION_NUMERIC;
-    repertoire= MY_REPERTOIRE_NUMERIC;
-  }
-  void set(CHARSET_INFO *collation_arg)
-  {
-    collation= collation_arg;
-    set_repertoire_from_charset(collation_arg);
-  }
-  void set(Derivation derivation_arg)
-  { derivation= derivation_arg; }
-  bool aggregate(const DTCollation &dt, uint flags= 0);
-  bool set(DTCollation &dt1, DTCollation &dt2, uint flags= 0)
-  { set(dt1); return aggregate(dt2, flags); }
-  const char *derivation_name() const
-  {
-    switch(derivation)
-    {
-      case DERIVATION_NUMERIC:   return "NUMERIC";
-      case DERIVATION_IGNORABLE: return "IGNORABLE";
-      case DERIVATION_COERCIBLE: return "COERCIBLE";
-      case DERIVATION_IMPLICIT:  return "IMPLICIT";
-      case DERIVATION_SYSCONST:  return "SYSCONST";
-      case DERIVATION_EXPLICIT:  return "EXPLICIT";
-      case DERIVATION_NONE:      return "NONE";
-      default: return "UNKNOWN";
-    }
-  }
-  int sortcmp(const String *s, const String *t) const
-  {
-    return collation->coll->strnncollsp(collation,
-                                        (uchar *) s->ptr(), s->length(),
-                                        (uchar *) t->ptr(), t->length());
-  }
-};
-
 
 void dummy_error_processor(THD *thd, void *data);
 
@@ -576,46 +463,6 @@ class String_copier_for_item: public String_copier
 };
 
 
-/**
-  A class to store type attributes for the standard data types.
-  Does not include attributes for the extended data types
-  such as ENUM, SET, GEOMETRY.
-*/
-class Type_std_attributes
-{
-public:
-  DTCollation collation;
-  uint decimals;
-  /*
-    The maximum value length in characters multiplied by collation->mbmaxlen.
-    Almost always it's the maximum value length in bytes.
-  */
-  uint32 max_length;
-  bool unsigned_flag;
-  Type_std_attributes()
-   :collation(&my_charset_bin, DERIVATION_COERCIBLE),
-    decimals(0), max_length(0), unsigned_flag(false)
-  { }
-  Type_std_attributes(const Type_std_attributes *other)
-   :collation(other->collation),
-    decimals(other->decimals),
-    max_length(other->max_length),
-    unsigned_flag(other->unsigned_flag)
-  { }
-  void set(const Type_std_attributes *other)
-  {
-    *this= *other;
-  }
-  void set(const Field *field)
-  {
-    decimals= field->decimals();
-    max_length= field->field_length;
-    collation.set(field->charset());
-    unsigned_flag= MY_TEST(field->flags & UNSIGNED_FLAG);
-  }
-};
-
-
 class Item: public Value_source,
             public Type_std_attributes
 {
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 3b98dd0..cbd272f 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -6601,7 +6601,9 @@ void Item_func_sp::fix_length_and_dec()
   DBUG_ENTER("Item_func_sp::fix_length_and_dec");
 
   DBUG_ASSERT(sp_result_field);
-  Type_std_attributes::set(sp_result_field);
+  Type_std_attributes::set(sp_result_field->type_std_attributes());
+  // There is a bug in the line below. See MDEV-11292 for details.
+  collation.derivation= DERIVATION_COERCIBLE;
   maybe_null= 1;
 
   DBUG_VOID_RETURN;
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 4b05a46..de5c31a 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -30,6 +30,186 @@ class Sort_param;
 struct TABLE;
 struct SORT_FIELD_ATTR;
 
+
+/*
+  Flags for collation aggregation modes, used in TDCollation::agg():
+
+  MY_COLL_ALLOW_SUPERSET_CONV  - allow conversion to a superset
+  MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value
+                                 (i.e. constant).
+  MY_COLL_ALLOW_CONV           - allow any kind of conversion
+                                 (combination of the above two)
+  MY_COLL_ALLOW_NUMERIC_CONV   - if all items were numbers, convert to
+                                 @@character_set_connection
+  MY_COLL_DISALLOW_NONE        - don't allow return DERIVATION_NONE
+                                 (e.g. when aggregating for comparison)
+  MY_COLL_CMP_CONV             - combination of MY_COLL_ALLOW_CONV
+                                 and MY_COLL_DISALLOW_NONE
+*/
+
+#define MY_COLL_ALLOW_SUPERSET_CONV   1
+#define MY_COLL_ALLOW_COERCIBLE_CONV  2
+#define MY_COLL_DISALLOW_NONE         4
+#define MY_COLL_ALLOW_NUMERIC_CONV    8
+
+#define MY_COLL_ALLOW_CONV (MY_COLL_ALLOW_SUPERSET_CONV | MY_COLL_ALLOW_COERCIBLE_CONV)
+#define MY_COLL_CMP_CONV   (MY_COLL_ALLOW_CONV | MY_COLL_DISALLOW_NONE)
+
+
+#define my_charset_numeric      my_charset_latin1
+#define MY_REPERTOIRE_NUMERIC   MY_REPERTOIRE_ASCII
+
+
+enum Derivation
+{
+  DERIVATION_IGNORABLE= 6,
+  DERIVATION_NUMERIC= 5,
+  DERIVATION_COERCIBLE= 4,
+  DERIVATION_SYSCONST= 3,
+  DERIVATION_IMPLICIT= 2,
+  DERIVATION_NONE= 1,
+  DERIVATION_EXPLICIT= 0
+};
+
+
+/**
+   "Declared Type Collation"
+   A combination of collation and its derivation.
+*/
+
+class DTCollation {
+public:
+  CHARSET_INFO     *collation;
+  enum Derivation derivation;
+  uint repertoire;
+
+  void set_repertoire_from_charset(CHARSET_INFO *cs)
+  {
+    repertoire= cs->state & MY_CS_PUREASCII ?
+                MY_REPERTOIRE_ASCII : MY_REPERTOIRE_UNICODE30;
+  }
+  DTCollation()
+  {
+    collation= &my_charset_bin;
+    derivation= DERIVATION_NONE;
+    repertoire= MY_REPERTOIRE_UNICODE30;
+  }
+  DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg)
+  {
+    collation= collation_arg;
+    derivation= derivation_arg;
+    set_repertoire_from_charset(collation_arg);
+  }
+  DTCollation(CHARSET_INFO *collation_arg,
+              Derivation derivation_arg,
+              uint repertoire_arg)
+   :collation(collation_arg),
+    derivation(derivation_arg),
+    repertoire(repertoire_arg)
+  { }
+  void set(const DTCollation &dt)
+  {
+    collation= dt.collation;
+    derivation= dt.derivation;
+    repertoire= dt.repertoire;
+  }
+  void set(CHARSET_INFO *collation_arg, Derivation derivation_arg)
+  {
+    collation= collation_arg;
+    derivation= derivation_arg;
+    set_repertoire_from_charset(collation_arg);
+  }
+  void set(CHARSET_INFO *collation_arg,
+           Derivation derivation_arg,
+           uint repertoire_arg)
+  {
+    collation= collation_arg;
+    derivation= derivation_arg;
+    repertoire= repertoire_arg;
+  }
+  void set_numeric()
+  {
+    collation= &my_charset_numeric;
+    derivation= DERIVATION_NUMERIC;
+    repertoire= MY_REPERTOIRE_NUMERIC;
+  }
+  void set(CHARSET_INFO *collation_arg)
+  {
+    collation= collation_arg;
+    set_repertoire_from_charset(collation_arg);
+  }
+  void set(Derivation derivation_arg)
+  { derivation= derivation_arg; }
+  bool aggregate(const DTCollation &dt, uint flags= 0);
+  bool set(DTCollation &dt1, DTCollation &dt2, uint flags= 0)
+  { set(dt1); return aggregate(dt2, flags); }
+  const char *derivation_name() const
+  {
+    switch(derivation)
+    {
+      case DERIVATION_NUMERIC:   return "NUMERIC";
+      case DERIVATION_IGNORABLE: return "IGNORABLE";
+      case DERIVATION_COERCIBLE: return "COERCIBLE";
+      case DERIVATION_IMPLICIT:  return "IMPLICIT";
+      case DERIVATION_SYSCONST:  return "SYSCONST";
+      case DERIVATION_EXPLICIT:  return "EXPLICIT";
+      case DERIVATION_NONE:      return "NONE";
+      default: return "UNKNOWN";
+    }
+  }
+  int sortcmp(const String *s, const String *t) const
+  {
+    return collation->coll->strnncollsp(collation,
+                                        (uchar *) s->ptr(), s->length(),
+                                        (uchar *) t->ptr(), t->length());
+  }
+};
+
+
+/**
+  A class to store type attributes for the standard data types.
+  Does not include attributes for the extended data types
+  such as ENUM, SET, GEOMETRY.
+*/
+class Type_std_attributes
+{
+public:
+  DTCollation collation;
+  uint decimals;
+  /*
+    The maximum value length in characters multiplied by collation->mbmaxlen.
+    Almost always it's the maximum value length in bytes.
+  */
+  uint32 max_length;
+  bool unsigned_flag;
+  Type_std_attributes()
+   :collation(&my_charset_bin, DERIVATION_COERCIBLE),
+    decimals(0), max_length(0), unsigned_flag(false)
+  { }
+  Type_std_attributes(const Type_std_attributes *other)
+   :collation(other->collation),
+    decimals(other->decimals),
+    max_length(other->max_length),
+    unsigned_flag(other->unsigned_flag)
+  { }
+  Type_std_attributes(uint32 max_length_arg, uint decimals_arg,
+                      bool unsigned_flag_arg, const DTCollation &dtc)
+    :collation(dtc),
+     decimals(decimals_arg),
+     max_length(max_length_arg),
+     unsigned_flag(unsigned_flag_arg)
+  { }
+  void set(const Type_std_attributes *other)
+  {
+    *this= *other;
+  }
+  void set(const Type_std_attributes &other)
+  {
+    *this= other;
+  }
+};
+
+
 class Type_handler
 {
 protected:
