MDEV-12668 SRID is not preserved in UNION, VIEW, MIN, MAX

Fixing the problem that an operation involving a mix of
two or more GEOMETRY operands did not preserve their SRIDs.
Now SRIDs are preserved by hybrid functions, subqueries, TVCs, UNIONs, VIEWs.

Incompatible change:
  An attempt to mix two different SRIDs now raises an error.

Details:

- Adding a new class Type_extra_attributes. It's a generic
  container which can store very specific data type attributes.
  For now it can store one uint32 and one const pointer attribute
  (for GEOMETRY's SRID and for ENUM/SET TYPELIB respectively).
  In the future it can grow as needed.

  Type_extra_attributes will also be reused soon to store "const Type_zone*"
  pointers for the TIMESTAMP's "WITH TIME ZONE 'tz'" attribute
  (a timestamp data type with a fixed time zone independent from @@time_zone).
  The time zone attribute will be stored in exactly the same way like
  a TYPELIB pointer is stored by ENUM/SET.

- Removing Column_definition_attributes members "interval" and "srid".
  Deriving Column_definition_attributes from the generic attribute container
  Type_extra_attributes instead.

- Adding a new class Type_typelib_attributes, to store
  the TYPELIB of the ENUM and SET data types. Deriving Field_enum from it.
  Removing the member Field_enum::typelib.

- Adding a new class Type_geom_attributes, to store
  the GEOMETRY related attributes. Deriving Field_geom from it.
  Removing the member Field_geom::srid.

- Removing virtual methods:
    Field::get_typelib()
    Type_all_attributes::get_typelib() and
    Type_all_attributes::set_typelib()
  They were very specific to TYPELIB.
  Adding more generic virtual methods instead:
  * Field::type_extra_attributes() - to get extra attributes
  * Type_all_attributes::type_extra_attributes() - to get extra attributes
  * Type_all_attributes::type_extra_attributes_addr() - to set extra attributes

- Removing Item_type_holder::enum_set_typelib. Deriving Item_type_holder
  from the generic attribute container Type_extra_attributes instead.
  This makes it possible for UNION to preserve SRID
  (in addition to preserving TYPELIB).

- Deriving Item_hybrid_func from Type_extra_attributes.
  This makes it possible for hybrid functions (e.g. CASE, COALESCE,
  LEAST, GREATEST etc) to preserve SRID.

- Deriving Item_singlerow_subselect from Type_extra_attributes and
  overriding methods:
  * Item_cache::type_extra_attributes()
  * subselect_single_select_engine::fix_length_and_dec()
  * Item_singlerow_subselect::type_extra_attributes()
  * Item_singlerow_subselect::type_extra_attributes_addr()
  This is needed to preserve SRID in subqueries and TVCs

- Cleanup: fixing the data type of members
  * Binlog_type_info::m_enum_typelib
  * Binlog_type_info::m_set_typelib
  from "TYPELIB *" to "const TYPELIB *"
This commit is contained in:
Alexander Barkov 2024-04-23 12:57:36 +04:00
parent 486d42d812
commit 001f93df2b
21 changed files with 502 additions and 153 deletions

View File

@ -5437,3 +5437,69 @@ DROP TABLE t1;
# #
# End of 10.5 tests # End of 10.5 tests
# #
#
# Start of 11.5 tests
#
#
# MDEV-12668 SRID is not preserved in UNION, VIEW, MIN, MAX
#
CREATE TABLE t1 (a POINT REF_SYSTEM_ID=0, b POINT REF_SYSTEM_ID=102);
SELECT a FROM t1 UNION SELECT b FROM t1;
ERROR HY000: Illegal parameter data types `point ref_system_id=0` and `point ref_system_id=102` for operation 'UNION'
DROP TABLE t1;
CREATE TABLE t1 (a POINT REF_SYSTEM_ID=101, b POINT REF_SYSTEM_ID=102);
SELECT a FROM t1 UNION SELECT b FROM t1;
ERROR HY000: Illegal parameter data types `point ref_system_id=101` and `point ref_system_id=102` for operation 'UNION'
DROP TABLE t1;
CREATE TABLE t1 (a POINT REF_SYSTEM_ID=101, b POINT REF_SYSTEM_ID=101);
CREATE TABLE t2 AS SELECT a, b FROM t1;
CREATE VIEW v2 AS SELECT a, b FROM t1;
CREATE TABLE t3 AS SELECT a FROM t1 UNION SELECT b FROM t1;
CREATE VIEW v3 AS SELECT a FROM t1 UNION SELECT b FROM t1;
CREATE TABLE t4 AS SELECT COALESCE(a,b) AS a FROM t1;
CREATE VIEW v4 AS SELECT COALESCE(a,b) AS a FROM t1;
CREATE TABLE t5 AS SELECT LEAST(a,b) AS a FROM t1;
CREATE VIEW v5 AS SELECT LEAST(a,b) AS a FROM t1;
CREATE TABLE t6 AS SELECT MIN(a) AS a FROM t1;
CREATE VIEW v6 AS SELECT MIN(a) AS a FROM t1;
CREATE TABLE t7 AS SELECT MIN(a) AS a FROM t1 UNION SELECT b FROM v2;
CREATE VIEW v7 AS SELECT MIN(a) AS a FROM t1 UNION SELECT b FROM v2;
CREATE TABLE t8 AS SELECT (SELECT a FROM t1) AS a;
CREATE VIEW v8 AS SELECT (SELECT a FROM t1) AS a;
CREATE TABLE t9 AS VALUES ((SELECT MAX(a) FROM t1)),(((SELECT MIN(b) FROM t1)));
CREATE VIEW v9 AS VALUES ((SELECT MAX(a) FROM t1)),(((SELECT MIN(b) FROM t1)));
SELECT
G_TABLE_NAME, G_GEOMETRY_COLUMN, SRID
FROM
INFORMATION_SCHEMA.GEOMETRY_COLUMNS
WHERE
F_TABLE_SCHEMA='test'
ORDER
BY G_TABLE_NAME, G_GEOMETRY_COLUMN;
G_TABLE_NAME G_GEOMETRY_COLUMN SRID
t1 a 101
t1 b 101
t2 a 101
t2 b 101
t3 a 101
t4 a 101
t5 a 101
t6 a 101
t7 a 101
t8 a 101
t9 (SELECT MAX(a) FROM t1) 101
v2 a 101
v2 b 101
v3 a 101
v4 a 101
v5 a 101
v6 a 101
v7 a 101
v8 a 101
v9 (select max(`test`.`t1`.`a`) from `test`.`t1`) 101
DROP TABLE t2,t3,t4,t5,t6,t7,t8,t9;
DROP VIEW v2,v3,v4,v5,v6,v7,v8,v9;
DROP TABLE t1;
#
# End of 11.5 tests
#

View File

@ -3441,3 +3441,64 @@ DROP TABLE t1;
--echo # --echo #
--echo # End of 10.5 tests --echo # End of 10.5 tests
--echo # --echo #
--echo #
--echo # Start of 11.5 tests
--echo #
--echo #
--echo # MDEV-12668 SRID is not preserved in UNION, VIEW, MIN, MAX
--echo #
CREATE TABLE t1 (a POINT REF_SYSTEM_ID=0, b POINT REF_SYSTEM_ID=102);
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT a FROM t1 UNION SELECT b FROM t1;
DROP TABLE t1;
CREATE TABLE t1 (a POINT REF_SYSTEM_ID=101, b POINT REF_SYSTEM_ID=102);
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT a FROM t1 UNION SELECT b FROM t1;
DROP TABLE t1;
CREATE TABLE t1 (a POINT REF_SYSTEM_ID=101, b POINT REF_SYSTEM_ID=101);
CREATE TABLE t2 AS SELECT a, b FROM t1;
CREATE VIEW v2 AS SELECT a, b FROM t1;
CREATE TABLE t3 AS SELECT a FROM t1 UNION SELECT b FROM t1;
CREATE VIEW v3 AS SELECT a FROM t1 UNION SELECT b FROM t1;
CREATE TABLE t4 AS SELECT COALESCE(a,b) AS a FROM t1;
CREATE VIEW v4 AS SELECT COALESCE(a,b) AS a FROM t1;
CREATE TABLE t5 AS SELECT LEAST(a,b) AS a FROM t1;
CREATE VIEW v5 AS SELECT LEAST(a,b) AS a FROM t1;
CREATE TABLE t6 AS SELECT MIN(a) AS a FROM t1;
CREATE VIEW v6 AS SELECT MIN(a) AS a FROM t1;
CREATE TABLE t7 AS SELECT MIN(a) AS a FROM t1 UNION SELECT b FROM v2;
CREATE VIEW v7 AS SELECT MIN(a) AS a FROM t1 UNION SELECT b FROM v2;
CREATE TABLE t8 AS SELECT (SELECT a FROM t1) AS a;
CREATE VIEW v8 AS SELECT (SELECT a FROM t1) AS a;
CREATE TABLE t9 AS VALUES ((SELECT MAX(a) FROM t1)),(((SELECT MIN(b) FROM t1)));
CREATE VIEW v9 AS VALUES ((SELECT MAX(a) FROM t1)),(((SELECT MIN(b) FROM t1)));
SELECT
G_TABLE_NAME, G_GEOMETRY_COLUMN, SRID
FROM
INFORMATION_SCHEMA.GEOMETRY_COLUMNS
WHERE
F_TABLE_SCHEMA='test'
ORDER
BY G_TABLE_NAME, G_GEOMETRY_COLUMN;
DROP TABLE t2,t3,t4,t5,t6,t7,t8,t9;
DROP VIEW v2,v3,v4,v5,v6,v7,v8,v9;
DROP TABLE t1;
--echo #
--echo # End of 11.5 tests
--echo #

View File

@ -9341,7 +9341,7 @@ int Field_enum::store(const char *from,size_t length,CHARSET_INFO *cs)
/* Remove end space */ /* Remove end space */
length= (uint) field_charset()->lengthsp(from, length); length= (uint) field_charset()->lengthsp(from, length);
uint tmp=find_type2(typelib, from, length, field_charset()); uint tmp=find_type2(m_typelib, from, length, field_charset());
if (!tmp) if (!tmp)
{ {
if (length < 6) // Can't be more than 99999 enums if (length < 6) // Can't be more than 99999 enums
@ -9349,7 +9349,7 @@ int Field_enum::store(const char *from,size_t length,CHARSET_INFO *cs)
/* This is for reading numbers with LOAD DATA INFILE */ /* This is for reading numbers with LOAD DATA INFILE */
char *end; char *end;
tmp=(uint) cs->strntoul(from,length,10,&end,&err); tmp=(uint) cs->strntoul(from,length,10,&end,&err);
if (err || end != from+length || tmp > typelib->count) if (err || end != from + length || tmp > m_typelib->count)
{ {
tmp=0; tmp=0;
set_warning(WARN_DATA_TRUNCATED, 1); set_warning(WARN_DATA_TRUNCATED, 1);
@ -9379,7 +9379,7 @@ int Field_enum::store(longlong nr, bool unsigned_val)
{ {
DBUG_ASSERT(marked_for_write_or_computed()); DBUG_ASSERT(marked_for_write_or_computed());
int error= 0; int error= 0;
if ((ulonglong) nr > typelib->count || nr == 0) if ((ulonglong) nr > m_typelib->count || nr == 0)
{ {
set_warning(WARN_DATA_TRUNCATED, 1); set_warning(WARN_DATA_TRUNCATED, 1);
if (nr != 0 || get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION) if (nr != 0 || get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION)
@ -9425,7 +9425,7 @@ Binlog_type_info Field_enum::binlog_type_info() const
{ {
DBUG_ASSERT(Field_enum::type() == binlog_type()); DBUG_ASSERT(Field_enum::type() == binlog_type());
return Binlog_type_info(Field_enum::type(), real_type() + (pack_length() << 8), return Binlog_type_info(Field_enum::type(), real_type() + (pack_length() << 8),
2, charset(), (TYPELIB *)get_typelib(), NULL); 2, charset(), m_typelib, NULL);
} }
@ -9433,12 +9433,12 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr) String *val_ptr)
{ {
uint tmp=(uint) Field_enum::val_int(); uint tmp=(uint) Field_enum::val_int();
if (!tmp || tmp > typelib->count) if (!tmp || tmp > m_typelib->count)
val_ptr->set("", 0, field_charset()); val_ptr->set("", 0, field_charset());
else else
val_ptr->set((const char*) typelib->type_names[tmp-1], val_ptr->set((const char*) m_typelib->type_names[tmp - 1],
typelib->type_lengths[tmp-1], m_typelib->type_lengths[tmp - 1],
field_charset()); field_charset());
return val_ptr; return val_ptr;
} }
@ -9470,8 +9470,8 @@ void Field_enum::sql_type(String &res) const
res.append(STRING_WITH_LEN("enum(")); res.append(STRING_WITH_LEN("enum("));
bool flag=0; bool flag=0;
uint *len= typelib->type_lengths; uint *len= m_typelib->type_lengths;
for (const char **pos= typelib->type_names; *pos; pos++, len++) for (const char **pos= m_typelib->type_names; *pos; pos++, len++)
{ {
uint dummy_errors; uint dummy_errors;
if (flag) if (flag)
@ -9491,7 +9491,7 @@ Field *Field_enum::make_new_field(MEM_ROOT *root, TABLE *new_table,
Field_enum *res= (Field_enum*) Field::make_new_field(root, new_table, Field_enum *res= (Field_enum*) Field::make_new_field(root, new_table,
keep_type); keep_type);
if (res) if (res)
res->typelib= copy_typelib(root, typelib); res->m_typelib= copy_typelib(root, m_typelib);
return res; return res;
} }
@ -9524,7 +9524,7 @@ int Field_set::store(const char *from,size_t length,CHARSET_INFO *cs)
from= tmpstr.ptr(); from= tmpstr.ptr();
length= tmpstr.length(); length= tmpstr.length();
} }
ulonglong tmp= find_set(typelib, from, length, field_charset(), ulonglong tmp= find_set(m_typelib, from, length, field_charset(),
&not_used, &not_used2, &got_warning); &not_used, &not_used2, &got_warning);
if (!tmp && length && length < 22) if (!tmp && length && length < 22)
{ {
@ -9552,10 +9552,10 @@ int Field_set::store(longlong nr, bool unsigned_val)
int error= 0; int error= 0;
ulonglong max_nr; ulonglong max_nr;
if (sizeof(ulonglong)*8 <= typelib->count) if (sizeof(ulonglong) * 8 <= m_typelib->count)
max_nr= ULONGLONG_MAX; max_nr= ULONGLONG_MAX;
else else
max_nr= (1ULL << typelib->count) - 1; max_nr= (1ULL << m_typelib->count) - 1;
if ((ulonglong) nr > max_nr) if ((ulonglong) nr > max_nr)
{ {
@ -9577,13 +9577,13 @@ String *Field_set::val_str(String *val_buffer,
val_buffer->set_charset(field_charset()); val_buffer->set_charset(field_charset());
val_buffer->length(0); val_buffer->length(0);
while (tmp && bitnr < (uint) typelib->count) while (tmp && bitnr < (uint) m_typelib->count)
{ {
if (tmp & 1) if (tmp & 1)
{ {
if (val_buffer->length()) if (val_buffer->length())
val_buffer->append(&field_separator, 1, &my_charset_latin1); val_buffer->append(&field_separator, 1, &my_charset_latin1);
String str(typelib->type_names[bitnr], typelib->type_lengths[bitnr], String str(m_typelib->type_names[bitnr], m_typelib->type_lengths[bitnr],
field_charset()); field_charset());
val_buffer->append(str); val_buffer->append(str);
} }
@ -9603,8 +9603,8 @@ void Field_set::sql_type(String &res) const
res.append(STRING_WITH_LEN("set(")); res.append(STRING_WITH_LEN("set("));
bool flag=0; bool flag=0;
uint *len= typelib->type_lengths; uint *len= m_typelib->type_lengths;
for (const char **pos= typelib->type_names; *pos; pos++, len++) for (const char **pos= m_typelib->type_names; *pos; pos++, len++)
{ {
uint dummy_errors; uint dummy_errors;
if (flag) if (flag)
@ -9621,7 +9621,7 @@ Binlog_type_info Field_set::binlog_type_info() const
{ {
DBUG_ASSERT(Field_set::type() == binlog_type()); DBUG_ASSERT(Field_set::type() == binlog_type());
return Binlog_type_info(Field_set::type(), real_type() return Binlog_type_info(Field_set::type(), real_type()
+ (pack_length() << 8), 2, charset(), NULL, (TYPELIB *)get_typelib()); + (pack_length() << 8), 2, charset(), NULL, m_typelib);
} }
/** /**
@ -9668,13 +9668,13 @@ bool Field_enum::eq_def(const Field *field) const
if (!Field::eq_def(field)) if (!Field::eq_def(field))
return FALSE; return FALSE;
values= ((Field_enum*) field)->typelib; values= ((Field_enum*) field)->m_typelib;
/* Definition must be strictly equal. */ /* Definition must be strictly equal. */
if (typelib->count != values->count) if (m_typelib->count != values->count)
return FALSE; return FALSE;
return compare_type_names(field_charset(), typelib, values); return compare_type_names(field_charset(), m_typelib, values);
} }
@ -9689,8 +9689,6 @@ bool Field_enum::eq_def(const Field *field) const
bool Field_enum::is_equal(const Column_definition &new_field) const bool Field_enum::is_equal(const Column_definition &new_field) const
{ {
const TYPELIB *values= new_field.interval;
/* /*
The fields are compatible if they have the same flags, The fields are compatible if they have the same flags,
type, charset and have the same underlying length. type, charset and have the same underlying length.
@ -9705,11 +9703,11 @@ bool Field_enum::is_equal(const Column_definition &new_field) const
enumeration or set members to the end of the list of valid member enumeration or set members to the end of the list of valid member
values only alters table metadata and not table data. values only alters table metadata and not table data.
*/ */
if (typelib->count > values->count) if (m_typelib->count > new_field.typelib()->count)
return false; return false;
/* Check whether there are modification before the end. */ /* Check whether there are modification before the end. */
if (! compare_type_names(field_charset(), typelib, new_field.interval)) if (! compare_type_names(field_charset(), m_typelib, new_field.typelib()))
return false; return false;
return true; return true;
@ -10405,9 +10403,10 @@ bool Column_definition::create_interval_from_interval_list(MEM_ROOT *mem_root,
bool reuse_interval_list_values) bool reuse_interval_list_values)
{ {
DBUG_ENTER("Column_definition::create_interval_from_interval_list"); DBUG_ENTER("Column_definition::create_interval_from_interval_list");
DBUG_ASSERT(!interval); DBUG_ASSERT(!typelib());
TYPELIB *tmpint; TYPELIB *tmpint;
if (!(interval= tmpint= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB)))) if (!set_typelib(tmpint= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB))).
typelib())
DBUG_RETURN(true); // EOM DBUG_RETURN(true); // EOM
List_iterator<String> it(interval_list); List_iterator<String> it(interval_list);
@ -10476,7 +10475,8 @@ bool Column_definition::create_interval_from_interval_list(MEM_ROOT *mem_root,
interval_list.empty(); // Don't need interval_list anymore interval_list.empty(); // Don't need interval_list anymore
DBUG_RETURN(false); DBUG_RETURN(false);
err: err:
interval= NULL; // Avoid having both non-empty interval_list and interval // Avoid having both non-empty interval_list and the typelib attribute
set_typelib(NULL);
DBUG_RETURN(true); DBUG_RETURN(true);
} }
@ -10504,7 +10504,7 @@ bool Column_definition::prepare_interval_field(MEM_ROOT *mem_root,
as the parser requires at least one element, so for a ENUM or SET field it as the parser requires at least one element, so for a ENUM or SET field it
should never happen that both internal_list.elements and interval are 0. should never happen that both internal_list.elements and interval are 0.
*/ */
DBUG_ASSERT((interval == NULL) == (interval_list.elements > 0)); DBUG_ASSERT((typelib() == NULL) == (interval_list.elements > 0));
/* /*
Create typelib from interval_list, and if necessary Create typelib from interval_list, and if necessary
@ -10527,8 +10527,8 @@ bool Column_definition::prepare_interval_field(MEM_ROOT *mem_root,
as the original field can be freed before the end of the life as the original field can be freed before the end of the life
cycle of "this". cycle of "this".
*/ */
DBUG_ASSERT(interval); DBUG_ASSERT(typelib());
if (!(interval= copy_typelib(mem_root, interval))) if (!set_typelib(copy_typelib(mem_root, typelib())).typelib())
DBUG_RETURN(true); DBUG_RETURN(true);
} }
prepare_interval_field_calc_length(); prepare_interval_field_calc_length();
@ -10886,7 +10886,7 @@ Field *Column_definition_attributes::make_field(TABLE_SHARE *share,
{ {
DBUG_ASSERT(length <= UINT_MAX32); DBUG_ASSERT(length <= UINT_MAX32);
DBUG_PRINT("debug", ("field_type: %s, field_length: %u, interval: %p, pack_flag: %s%s%s%s%s", DBUG_PRINT("debug", ("field_type: %s, field_length: %u, interval: %p, pack_flag: %s%s%s%s%s",
handler->name().ptr(), (uint) length, interval, handler->name().ptr(), (uint) length, typelib(),
FLAGSTR(pack_flag, FIELDFLAG_BINARY), FLAGSTR(pack_flag, FIELDFLAG_BINARY),
FLAGSTR(pack_flag, FIELDFLAG_INTERVAL), FLAGSTR(pack_flag, FIELDFLAG_INTERVAL),
FLAGSTR(pack_flag, FIELDFLAG_NUMBER), FLAGSTR(pack_flag, FIELDFLAG_NUMBER),
@ -10915,9 +10915,7 @@ bool Field_vers_trx_id::test_if_equality_guarantees_uniqueness(const Item* item)
Column_definition_attributes::Column_definition_attributes(const Field *field) Column_definition_attributes::Column_definition_attributes(const Field *field)
:length(field->character_octet_length() / field->charset()->mbmaxlen), :length(field->character_octet_length() / field->charset()->mbmaxlen),
interval(NULL),
charset(field->charset()), // May be NULL ptr charset(field->charset()), // May be NULL ptr
srid(0),
pack_flag(0), pack_flag(0),
decimals(field->decimals()), decimals(field->decimals()),
unireg_check(field->unireg_check) unireg_check(field->unireg_check)
@ -10926,10 +10924,9 @@ Column_definition_attributes::Column_definition_attributes(const Field *field)
Column_definition_attributes:: Column_definition_attributes::
Column_definition_attributes(const Type_all_attributes &attr) Column_definition_attributes(const Type_all_attributes &attr)
:length(attr.max_length), :Type_extra_attributes(attr.type_extra_attributes()),
interval(attr.get_typelib()), length(attr.max_length),
charset(attr.collation.collation), charset(attr.collation.collation),
srid(0),
pack_flag(attr.unsigned_flag ? 0 : FIELDFLAG_DECIMAL), pack_flag(attr.unsigned_flag ? 0 : FIELDFLAG_DECIMAL),
decimals(attr.decimals), decimals(attr.decimals),
unireg_check(Field::NONE) unireg_check(Field::NONE)
@ -10942,7 +10939,6 @@ Column_definition::Column_definition(THD *thd, Field *old_field,
Field *orig_field) Field *orig_field)
:Column_definition_attributes(old_field) :Column_definition_attributes(old_field)
{ {
srid= 0;
on_update= NULL; on_update= NULL;
field_name= old_field->field_name; field_name= old_field->field_name;
flags= old_field->flags; flags= old_field->flags;
@ -11034,6 +11030,7 @@ Column_definition::redefine_stage1_common(const Column_definition *dup_field,
const handler *file) const handler *file)
{ {
set_handler(dup_field->type_handler()); set_handler(dup_field->type_handler());
Type_extra_attributes::operator=(*dup_field);
default_value= dup_field->default_value; default_value= dup_field->default_value;
DBUG_ASSERT(dup_field->charset); // Set by prepare_stage1() DBUG_ASSERT(dup_field->charset); // Set by prepare_stage1()
charset= dup_field->charset; charset= dup_field->charset;
@ -11042,7 +11039,6 @@ Column_definition::redefine_stage1_common(const Column_definition *dup_field,
decimals= dup_field->decimals; decimals= dup_field->decimals;
unireg_check= dup_field->unireg_check; unireg_check= dup_field->unireg_check;
flags= dup_field->flags; flags= dup_field->flags;
interval= dup_field->interval;
vcol_info= dup_field->vcol_info; vcol_info= dup_field->vcol_info;
invisible= dup_field->invisible; invisible= dup_field->invisible;
check_constraint= dup_field->check_constraint; check_constraint= dup_field->check_constraint;

View File

@ -662,8 +662,8 @@ public:
Retrieve the field metadata for fields. Retrieve the field metadata for fields.
*/ */
CHARSET_INFO *m_cs; // NULL if not relevant CHARSET_INFO *m_cs; // NULL if not relevant
TYPELIB *m_enum_typelib; // NULL if not relevant const TYPELIB *m_enum_typelib; // NULL if not relevant
TYPELIB *m_set_typelib; // NULL if not relevant const TYPELIB *m_set_typelib; // NULL if not relevant
binlog_sign_t m_signedness; binlog_sign_t m_signedness;
uint16 m_metadata; uint16 m_metadata;
uint8 m_metadata_size; uint8 m_metadata_size;
@ -708,7 +708,7 @@ public:
Binlog_type_info(uchar type_code, uint16 metadata, Binlog_type_info(uchar type_code, uint16 metadata,
uint8 metadata_size, uint8 metadata_size,
CHARSET_INFO *cs, CHARSET_INFO *cs,
TYPELIB *t_enum, TYPELIB *t_set) const TYPELIB *t_enum, const TYPELIB *t_set)
:m_cs(cs), :m_cs(cs),
m_enum_typelib(t_enum), m_enum_typelib(t_enum),
m_set_typelib(t_set), m_set_typelib(t_set),
@ -1661,7 +1661,10 @@ public:
virtual bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate); virtual bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
virtual longlong val_datetime_packed(THD *thd); virtual longlong val_datetime_packed(THD *thd);
virtual longlong val_time_packed(THD *thd); virtual longlong val_time_packed(THD *thd);
virtual const TYPELIB *get_typelib() const { return NULL; } virtual const Type_extra_attributes type_extra_attributes() const
{
return Type_extra_attributes();
}
virtual CHARSET_INFO *charset() const= 0; virtual CHARSET_INFO *charset() const= 0;
/* returns TRUE if the new charset differs. */ /* returns TRUE if the new charset differs. */
virtual void change_charset(const DTCollation &new_cs) {} virtual void change_charset(const DTCollation &new_cs) {}
@ -4778,7 +4781,9 @@ private:
}; };
class Field_enum :public Field_str { class Field_enum :public Field_str,
public Type_typelib_attributes
{
static void do_field_enum(const Copy_field *copy_field); static void do_field_enum(const Copy_field *copy_field);
longlong val_int(const uchar *) const; longlong val_int(const uchar *) const;
Data_type_compatibility can_optimize_range_or_keypart_ref( Data_type_compatibility can_optimize_range_or_keypart_ref(
@ -4787,7 +4792,6 @@ class Field_enum :public Field_str {
protected: protected:
uint packlength; uint packlength;
public: public:
const TYPELIB *typelib;
Field_enum(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, Field_enum(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
@ -4796,7 +4800,8 @@ public:
const DTCollation &collation) const DTCollation &collation)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, collation), unireg_check_arg, field_name_arg, collation),
packlength(packlength_arg),typelib(typelib_arg) Type_typelib_attributes(typelib_arg),
packlength(packlength_arg)
{ {
flags|=ENUM_FLAG; flags|=ENUM_FLAG;
} }
@ -4869,8 +4874,10 @@ public:
/* enum and set are sorted as integers */ /* enum and set are sorted as integers */
CHARSET_INFO *sort_charset() const override { return &my_charset_bin; } CHARSET_INFO *sort_charset() const override { return &my_charset_bin; }
decimal_digits_t decimals() const override { return 0; } decimal_digits_t decimals() const override { return 0; }
const TYPELIB *get_typelib() const override { return typelib; } const Type_extra_attributes type_extra_attributes() const override
{
return Type_extra_attributes(m_typelib);
}
uchar *pack(uchar *to, const uchar *from, uint max_length) override; uchar *pack(uchar *to, const uchar *from, uint max_length) override;
const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end, const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
uint param_data) override; uint param_data) override;
@ -5198,7 +5205,7 @@ public:
extern const LEX_CSTRING null_clex_str; extern const LEX_CSTRING null_clex_str;
class Column_definition_attributes class Column_definition_attributes: public Type_extra_attributes
{ {
public: public:
/* /*
@ -5206,17 +5213,13 @@ public:
max number of characters. max number of characters.
*/ */
ulonglong length; ulonglong length;
const TYPELIB *interval;
CHARSET_INFO *charset; CHARSET_INFO *charset;
uint32 srid;
uint32 pack_flag; uint32 pack_flag;
decimal_digits_t decimals; decimal_digits_t decimals;
Field::utype unireg_check; Field::utype unireg_check;
Column_definition_attributes() Column_definition_attributes()
:length(0), :length(0),
interval(NULL),
charset(&my_charset_bin), charset(&my_charset_bin),
srid(0),
pack_flag(0), pack_flag(0),
decimals(0), decimals(0),
unireg_check(Field::NONE) unireg_check(Field::NONE)
@ -5287,7 +5290,7 @@ class Column_definition: public Sql_alloc,
const char **pos; const char **pos;
uint *len; uint *len;
*max_length= *tot_length= 0; *max_length= *tot_length= 0;
for (pos= interval->type_names, len= interval->type_lengths; for (pos= typelib()->type_names, len= typelib()->type_lengths;
*pos ; pos++, len++) *pos ; pos++, len++)
{ {
size_t length= charset->numchars(*pos, *pos + *len); size_t length= charset->numchars(*pos, *pos + *len);
@ -5412,7 +5415,7 @@ public:
if (real_field_type() == MYSQL_TYPE_SET) if (real_field_type() == MYSQL_TYPE_SET)
{ {
calculate_interval_lengths(&dummy, &field_length); calculate_interval_lengths(&dummy, &field_length);
length= field_length + (interval->count - 1); length= field_length + (typelib()->count - 1);
} }
else /* MYSQL_TYPE_ENUM */ else /* MYSQL_TYPE_ENUM */
{ {
@ -5516,15 +5519,14 @@ public:
void set_type(const Column_definition &other) void set_type(const Column_definition &other)
{ {
set_handler(other.type_handler()); set_handler(other.type_handler());
Type_extra_attributes::operator=(other);
length= other.length; length= other.length;
char_length= other.char_length; char_length= other.char_length;
decimals= other.decimals; decimals= other.decimals;
flags= other.flags; flags= other.flags;
pack_length= other.pack_length; pack_length= other.pack_length;
unireg_check= other.unireg_check; unireg_check= other.unireg_check;
interval= other.interval;
charset= other.charset; charset= other.charset;
srid= other.srid;
pack_flag= other.pack_flag; pack_flag= other.pack_flag;
} }

View File

@ -1328,7 +1328,14 @@ public:
{ {
return type_handler()->max_display_length(this); return type_handler()->max_display_length(this);
} }
const TYPELIB *get_typelib() const override { return NULL; } const Type_extra_attributes type_extra_attributes() const override
{
return Type_extra_attributes();
}
Type_extra_attributes *type_extra_attributes_addr() override
{
return nullptr;
}
/* optimized setting of maybe_null without jumps. Minimizes code size */ /* optimized setting of maybe_null without jumps. Minimizes code size */
inline void set_maybe_null(bool maybe_null_arg) inline void set_maybe_null(bool maybe_null_arg)
{ {
@ -1366,11 +1373,6 @@ public:
bool is_top_level_item() const bool is_top_level_item() const
{ return (bool) (base_flags & item_base_t::AT_TOP_LEVEL); } { return (bool) (base_flags & item_base_t::AT_TOP_LEVEL); }
void set_typelib(const TYPELIB *typelib) override
{
// Non-field Items (e.g. hybrid functions) never have ENUM/SET types yet.
DBUG_ASSERT(0);
}
Item_cache* get_cache(THD *thd) const Item_cache* get_cache(THD *thd) const
{ {
return type_handler()->Item_get_cache(thd, this); return type_handler()->Item_get_cache(thd, this);
@ -3696,7 +3698,10 @@ public:
Field *create_tmp_field_ex(MEM_ROOT *root, Field *create_tmp_field_ex(MEM_ROOT *root,
TABLE *table, Tmp_field_src *src, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param) override; const Tmp_field_param *param) override;
const TYPELIB *get_typelib() const override { return field->get_typelib(); } const Type_extra_attributes type_extra_attributes() const override
{
return field->type_extra_attributes();
}
enum_monotonicity_info get_monotonicity_info() const override enum_monotonicity_info get_monotonicity_info() const override
{ {
return MONOTONIC_STRICT_INCREASING; return MONOTONIC_STRICT_INCREASING;
@ -5731,9 +5736,9 @@ public:
{ {
return ref ? (*ref)->real_item() : this; return ref ? (*ref)->real_item() : this;
} }
const TYPELIB *get_typelib() const override const Type_extra_attributes type_extra_attributes() const override
{ {
return ref ? (*ref)->get_typelib() : NULL; return ref ? (*ref)->type_extra_attributes() : Type_extra_attributes();
} }
bool walk(Item_processor processor, bool walk_subquery, void *arg) override bool walk(Item_processor processor, bool walk_subquery, void *arg) override
@ -7154,6 +7159,12 @@ public:
const Type_handler *type_handler() const override const Type_handler *type_handler() const override
{ return Type_handler_hybrid_field_type::type_handler(); } { return Type_handler_hybrid_field_type::type_handler(); }
const Type_extra_attributes type_extra_attributes() const override
{
DBUG_ASSERT(fixed());
return example ? example->type_extra_attributes() :
Type_extra_attributes();
}
Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param) override const Tmp_field_param *param) override
{ {
@ -7677,15 +7688,17 @@ public:
Item_type_holder do not need cleanup() because its time of live limited by Item_type_holder do not need cleanup() because its time of live limited by
single SP/PS execution. single SP/PS execution.
*/ */
class Item_type_holder: public Item, public Type_handler_hybrid_field_type class Item_type_holder: public Item,
public Type_handler_hybrid_field_type,
public Type_extra_attributes
{ {
protected:
const TYPELIB *enum_set_typelib;
public: public:
Item_type_holder(THD *thd, Item *item, const Type_handler *handler, Item_type_holder(THD *thd, Item *item, const Type_handler *handler,
const Type_all_attributes *attr, bool maybe_null_arg) const Type_all_attributes *attr,
:Item(thd), Type_handler_hybrid_field_type(handler), bool maybe_null_arg)
enum_set_typelib(attr->get_typelib()) :Item(thd),
Type_handler_hybrid_field_type(handler),
Type_extra_attributes(attr->type_extra_attributes())
{ {
name= item->name; name= item->name;
Type_std_attributes::set(*attr); Type_std_attributes::set(*attr);
@ -7705,7 +7718,14 @@ public:
} }
Type type() const override { return TYPE_HOLDER; } Type type() const override { return TYPE_HOLDER; }
const TYPELIB *get_typelib() const override { return enum_set_typelib; } Type_extra_attributes *type_extra_attributes_addr() override
{
return this;
}
const Type_extra_attributes type_extra_attributes() const override
{
return *this;
}
/* /*
When handling a query like this: When handling a query like this:
VALUES ('') UNION VALUES( _utf16 0x0020 COLLATE utf16_bin); VALUES ('') UNION VALUES( _utf16 0x0020 COLLATE utf16_bin);

View File

@ -3295,8 +3295,8 @@ bool Item_func_find_in_set::fix_length_and_dec(THD *thd)
{ {
// find is not NULL pointer so args[0] is not a null-value // find is not NULL pointer so args[0] is not a null-value
DBUG_ASSERT(!args[0]->null_value); DBUG_ASSERT(!args[0]->null_value);
enum_value= find_type(((Field_enum*) field)->typelib,find->ptr(), enum_value= find_type(((Field_enum*) field)->typelib(), find->ptr(),
find->length(), 0); find->length(), 0);
enum_bit=0; enum_bit=0;
if (enum_value) if (enum_value)
enum_bit= 1ULL << (enum_value-1); enum_bit= 1ULL << (enum_value-1);

View File

@ -497,7 +497,8 @@ public:
Functions whose returned field type is determined at fix_fields() time. Functions whose returned field type is determined at fix_fields() time.
*/ */
class Item_hybrid_func: public Item_func, class Item_hybrid_func: public Item_func,
public Type_handler_hybrid_field_type public Type_handler_hybrid_field_type,
public Type_extra_attributes
{ {
protected: protected:
bool fix_attributes(Item **item, uint nitems); bool fix_attributes(Item **item, uint nitems);
@ -512,6 +513,14 @@ public:
:Item_func(thd, item), Type_handler_hybrid_field_type(item) { } :Item_func(thd, item), Type_handler_hybrid_field_type(item) { }
const Type_handler *type_handler() const override const Type_handler *type_handler() const override
{ return Type_handler_hybrid_field_type::type_handler(); } { return Type_handler_hybrid_field_type::type_handler(); }
Type_extra_attributes *type_extra_attributes_addr() override
{
return this;
}
const Type_extra_attributes type_extra_attributes() const override
{
return *this;
}
void fix_length_and_dec_long_or_longlong(uint char_length, bool unsigned_arg) void fix_length_and_dec_long_or_longlong(uint char_length, bool unsigned_arg)
{ {
collation= DTCollation_numeric(); collation= DTCollation_numeric();

View File

@ -4037,6 +4037,8 @@ bool subselect_single_select_engine::fix_length_and_dec(Item_cache **row)
if (set_row(select_lex->item_list, row)) if (set_row(select_lex->item_list, row))
return TRUE; return TRUE;
item->collation.set(row[0]->collation); item->collation.set(row[0]->collation);
if (Type_extra_attributes *eattr= item->type_extra_attributes_addr())
eattr[0]= row[0]->type_extra_attributes();
if (cols() != 1) if (cols() != 1)
maybe_null= 0; maybe_null= 0;
return FALSE; return FALSE;

View File

@ -294,7 +294,8 @@ public:
/* single value subselect */ /* single value subselect */
class Item_cache; class Item_cache;
class Item_singlerow_subselect :public Item_subselect class Item_singlerow_subselect :public Item_subselect,
public Type_extra_attributes
{ {
protected: protected:
Item_cache *value, **row; Item_cache *value, **row;
@ -319,6 +320,14 @@ public:
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override;
const Type_handler *type_handler() const override; const Type_handler *type_handler() const override;
bool fix_length_and_dec() override; bool fix_length_and_dec() override;
Type_extra_attributes *type_extra_attributes_addr() override
{
return this;
}
const Type_extra_attributes type_extra_attributes() const override
{
return *this;
}
uint cols() const override; uint cols() const override;
Item* element_index(uint i) override Item* element_index(uint i) override

View File

@ -1172,7 +1172,10 @@ public:
{ {
return get_arg(0)->real_type_handler(); return get_arg(0)->real_type_handler();
} }
const TYPELIB *get_typelib() const override { return args[0]->get_typelib(); } const Type_extra_attributes type_extra_attributes() const override
{
return args[0]->type_extra_attributes();
}
void update_field() override; void update_field() override;
void min_max_update_str_field(); void min_max_update_str_field();
void min_max_update_real_field(); void min_max_update_real_field();

View File

@ -6248,7 +6248,7 @@ bool Table_map_log_event::init_column_name_field()
bool Table_map_log_event::init_set_str_value_field() bool Table_map_log_event::init_set_str_value_field()
{ {
StringBuffer<1024> buf; StringBuffer<1024> buf;
TYPELIB *typelib; const TYPELIB *typelib;
/* /*
SET string values are stored in the same format: SET string values are stored in the same format:
@ -6278,7 +6278,7 @@ bool Table_map_log_event::init_set_str_value_field()
bool Table_map_log_event::init_enum_str_value_field() bool Table_map_log_event::init_enum_str_value_field()
{ {
StringBuffer<1024> buf; StringBuffer<1024> buf;
TYPELIB *typelib; const TYPELIB *typelib;
/* ENUM is same to SET columns, see comment in init_set_str_value_field */ /* ENUM is same to SET columns, see comment in init_set_str_value_field */
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i) for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)

View File

@ -863,7 +863,7 @@ class Grant_table_base
{ {
Field *field= m_table->field[end_priv_columns]; Field *field= m_table->field[end_priv_columns];
if (field->real_type() == MYSQL_TYPE_ENUM && if (field->real_type() == MYSQL_TYPE_ENUM &&
static_cast<Field_enum*>(field)->typelib->count == 2) static_cast<Field_enum*>(field)->typelib()->count == 2)
{ {
if (!start_priv_columns) if (!start_priv_columns)
start_priv_columns= end_priv_columns; start_priv_columns= end_priv_columns;
@ -3052,7 +3052,7 @@ static privilege_t get_access(TABLE *form, uint fieldnr, uint *next_field)
for (pos=form->field+fieldnr, bit=1; for (pos=form->field+fieldnr, bit=1;
*pos && (*pos)->real_type() == MYSQL_TYPE_ENUM && *pos && (*pos)->real_type() == MYSQL_TYPE_ENUM &&
((Field_enum*) (*pos))->typelib->count == 2 ; ((Field_enum*) (*pos))->typelib()->count == 2 ;
pos++, fieldnr++, bit<<=1) pos++, fieldnr++, bit<<=1)
{ {
if (get_YN_as_bool(*pos)) if (get_YN_as_bool(*pos))

View File

@ -8197,20 +8197,22 @@ public:
class Type_holder: public Sql_alloc, class Type_holder: public Sql_alloc,
public Item_args, public Item_args,
public Type_handler_hybrid_field_type, public Type_handler_hybrid_field_type,
public Type_all_attributes public Type_all_attributes,
public Type_extra_attributes
{ {
const TYPELIB *m_typelib;
bool m_maybe_null; bool m_maybe_null;
public: public:
Type_holder() Type_holder()
:m_typelib(NULL), :m_maybe_null(false)
m_maybe_null(false)
{ } { }
void set_type_maybe_null(bool maybe_null_arg) { m_maybe_null= maybe_null_arg; } void set_type_maybe_null(bool maybe_null_arg) override
{
m_maybe_null= maybe_null_arg;
}
bool get_maybe_null() const { return m_maybe_null; } bool get_maybe_null() const { return m_maybe_null; }
decimal_digits_t decimal_precision() const decimal_digits_t decimal_precision() const override
{ {
/* /*
Type_holder is not used directly to create fields, so Type_holder is not used directly to create fields, so
@ -8222,13 +8224,13 @@ public:
DBUG_ASSERT(0); DBUG_ASSERT(0);
return 0; return 0;
} }
void set_typelib(const TYPELIB *typelib) Type_extra_attributes *type_extra_attributes_addr() override
{ {
m_typelib= typelib; return this;
} }
const TYPELIB *get_typelib() const const Type_extra_attributes type_extra_attributes() const override
{ {
return m_typelib; return *this;
} }
bool aggregate_attributes(THD *thd) bool aggregate_attributes(THD *thd)

View File

@ -2269,7 +2269,7 @@ bool Column_definition::prepare_stage2_typelib(const char *type_name,
pack_flag= pack_length_to_packflag(pack_length) | field_flags; pack_flag= pack_length_to_packflag(pack_length) | field_flags;
if (charset->state & MY_CS_BINSORT) if (charset->state & MY_CS_BINSORT)
pack_flag|= FIELDFLAG_BINARY; pack_flag|= FIELDFLAG_BINARY;
return check_duplicates_in_interval(type_name, field_name.str, interval, return check_duplicates_in_interval(type_name, field_name.str, typelib(),
charset, dup_val_count); charset, dup_val_count);
} }
@ -2537,13 +2537,13 @@ bool Column_definition::prepare_stage1_check_typelib_default()
{ {
char *not_used; char *not_used;
uint not_used2; uint not_used2;
find_set(interval, def->ptr(), def->length(), find_set(typelib(), def->ptr(), def->length(),
charset, &not_used, &not_used2, &not_found); charset, &not_used, &not_used2, &not_found);
} }
else /* MYSQL_TYPE_ENUM */ else /* MYSQL_TYPE_ENUM */
{ {
def->length(charset->lengthsp(def->ptr(), def->length())); def->length(charset->lengthsp(def->ptr(), def->length()));
not_found= !find_type2(interval, def->ptr(), def->length(), charset); not_found= !find_type2(typelib(), def->ptr(), def->length(), charset);
} }
} }
if (not_found) if (not_found)

View File

@ -2666,7 +2666,7 @@ Field *Type_handler_enum::make_conversion_table_field(MEM_ROOT *root,
Field_enum(NULL, target->field_length, Field_enum(NULL, target->field_length,
(uchar *) "", 1, Field::NONE, &empty_clex_str, (uchar *) "", 1, Field::NONE, &empty_clex_str,
metadata & 0x00ff/*pack_length()*/, metadata & 0x00ff/*pack_length()*/,
((const Field_enum*) target)->typelib, target->charset()); ((const Field_enum*) target)->typelib(), target->charset());
} }
@ -2682,7 +2682,7 @@ Field *Type_handler_set::make_conversion_table_field(MEM_ROOT *root,
Field_set(NULL, target->field_length, Field_set(NULL, target->field_length,
(uchar *) "", 1, Field::NONE, &empty_clex_str, (uchar *) "", 1, Field::NONE, &empty_clex_str,
metadata & 0x00ff/*pack_length()*/, metadata & 0x00ff/*pack_length()*/,
((const Field_enum*) target)->typelib, target->charset()); ((const Field_enum*) target)->typelib(), target->charset());
} }
@ -2977,7 +2977,8 @@ void Type_handler_typelib::
const Field *field) const const Field *field) const
{ {
DBUG_ASSERT(def->flags & (ENUM_FLAG | SET_FLAG)); DBUG_ASSERT(def->flags & (ENUM_FLAG | SET_FLAG));
def->interval= field->get_typelib(); const Field_enum *field_enum= static_cast<const Field_enum*>(field);
field_enum->Type_typelib_attributes::store(def);
} }
@ -3336,7 +3337,7 @@ bool Type_handler_set::
if (def->prepare_stage2_typelib("SET", FIELDFLAG_BITFIELD, &dup_count)) if (def->prepare_stage2_typelib("SET", FIELDFLAG_BITFIELD, &dup_count))
return true; return true;
/* Check that count of unique members is not more then 64 */ /* Check that count of unique members is not more then 64 */
if (def->interval->count - dup_count > sizeof(longlong)*8) if (def->typelib()->count - dup_count > sizeof(longlong)*8)
{ {
my_error(ER_TOO_BIG_SET, MYF(0), def->field_name.str); my_error(ER_TOO_BIG_SET, MYF(0), def->field_name.str);
return true; return true;
@ -3549,14 +3550,14 @@ Type_handler_string_result::calc_key_length(const Column_definition &def) const
uint Type_handler_enum::calc_key_length(const Column_definition &def) const uint Type_handler_enum::calc_key_length(const Column_definition &def) const
{ {
DBUG_ASSERT(def.interval); DBUG_ASSERT(def.typelib());
return get_enum_pack_length(def.interval->count); return get_enum_pack_length(def.typelib()->count);
} }
uint Type_handler_set::calc_key_length(const Column_definition &def) const uint Type_handler_set::calc_key_length(const Column_definition &def) const
{ {
DBUG_ASSERT(def.interval); DBUG_ASSERT(def.typelib());
return get_set_pack_length(def.interval->count); return get_set_pack_length(def.typelib()->count);
} }
uint Type_handler_blob_common::calc_key_length(const Column_definition &def) const uint Type_handler_blob_common::calc_key_length(const Column_definition &def) const
@ -3931,13 +3932,14 @@ Field *Type_handler_enum::make_table_field(MEM_ROOT *root,
const Type_all_attributes &attr, const Type_all_attributes &attr,
TABLE_SHARE *share) const TABLE_SHARE *share) const
{ {
const TYPELIB *typelib= attr.get_typelib(); const Type_typelib_attributes typelib_attr(attr.type_extra_attributes());
DBUG_ASSERT(typelib); DBUG_ASSERT(typelib_attr.typelib());
return new (root) return new (root)
Field_enum(addr.ptr(), attr.max_length, Field_enum(addr.ptr(), attr.max_length,
addr.null_ptr(), addr.null_bit(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, Field::NONE, name,
get_enum_pack_length(typelib->count), typelib, get_enum_pack_length(typelib_attr.typelib()->count),
typelib_attr.typelib(),
attr.collation); attr.collation);
} }
@ -3949,13 +3951,14 @@ Field *Type_handler_set::make_table_field(MEM_ROOT *root,
TABLE_SHARE *share) const TABLE_SHARE *share) const
{ {
const TYPELIB *typelib= attr.get_typelib(); const Type_typelib_attributes typelib_attr(attr.type_extra_attributes());
DBUG_ASSERT(typelib); DBUG_ASSERT(typelib_attr.typelib());
return new (root) return new (root)
Field_set(addr.ptr(), attr.max_length, Field_set(addr.ptr(), attr.max_length,
addr.null_ptr(), addr.null_bit(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, Field::NONE, name,
get_enum_pack_length(typelib->count), typelib, get_enum_pack_length(typelib_attr.typelib()->count),
typelib_attr.typelib(),
attr.collation); attr.collation);
} }
@ -4694,8 +4697,8 @@ bool Type_handler_typelib::
const TYPELIB *typelib= NULL; const TYPELIB *typelib= NULL;
for (uint i= 0; i < nitems; i++) for (uint i= 0; i < nitems; i++)
{ {
const TYPELIB *typelib2; const Type_extra_attributes eattr2= items[i]->type_extra_attributes();
if ((typelib2= items[i]->get_typelib())) if (eattr2.typelib())
{ {
if (typelib) if (typelib)
{ {
@ -4707,11 +4710,13 @@ bool Type_handler_typelib::
handler->set_handler(&type_handler_varchar); handler->set_handler(&type_handler_varchar);
return func->aggregate_attributes_string(func_name, items, nitems); return func->aggregate_attributes_string(func_name, items, nitems);
} }
typelib= typelib2; typelib= eattr2.typelib();
} }
} }
DBUG_ASSERT(typelib); // There must be at least one typelib DBUG_ASSERT(typelib); // There must be at least one typelib
func->set_typelib(typelib); Type_extra_attributes *eattr_addr= func->type_extra_attributes_addr();
if (eattr_addr)
eattr_addr->set_typelib(typelib);
return func->aggregate_attributes_string(func_name, items, nitems); return func->aggregate_attributes_string(func_name, items, nitems);
} }
@ -8536,7 +8541,7 @@ Field *Type_handler_enum::
return new (mem_root) return new (mem_root)
Field_enum(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(), Field_enum(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
attr->unireg_check, name, attr->pack_flag_to_pack_length(), attr->unireg_check, name, attr->pack_flag_to_pack_length(),
attr->interval, attr->charset); attr->typelib(), attr->charset);
} }
@ -8550,7 +8555,7 @@ Field *Type_handler_set::
return new (mem_root) return new (mem_root)
Field_set(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(), Field_set(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
attr->unireg_check, name, attr->pack_flag_to_pack_length(), attr->unireg_check, name, attr->pack_flag_to_pack_length(),
attr->interval, attr->charset); attr->typelib(), attr->charset);
} }

View File

@ -3402,6 +3402,98 @@ public:
}; };
/*
A container for very specific data type attributes.
For now it prodives space for:
- one const pointer attributes
- one unt32 attribute
*/
class Type_extra_attributes
{
const void *m_attr_const_void_ptr[1];
uint32 m_attr_uint32[1];
public:
Type_extra_attributes()
:m_attr_const_void_ptr{0},
m_attr_uint32{0}
{ }
Type_extra_attributes(const void *const_void_ptr)
:m_attr_const_void_ptr{const_void_ptr},
m_attr_uint32{0}
{ }
/*
Generic const pointer attributes.
The ENUM and SET data types store TYPELIB information here.
*/
Type_extra_attributes & set_attr_const_void_ptr(uint i, const void *value)
{
m_attr_const_void_ptr[i]= value;
return *this;
}
const void *get_attr_const_void_ptr(uint i) const
{
return m_attr_const_void_ptr[i];
}
/*
Generic uint32 attributes.
The GEOMETRY data type stores SRID here.
*/
Type_extra_attributes & set_attr_uint32(uint i, uint32 value)
{
m_attr_uint32[i]= value;
return *this;
}
uint32 get_attr_uint32(uint i) const
{
return m_attr_uint32[i];
}
/*
Helper methods for TYPELIB attributes.
They are mostly needed to simplify the code
in Column_definition_attributes and Column_definition methods.
Eventually we should move this code into Type_typelib_attributes
and remove these methods.
*/
Type_extra_attributes & set_typelib(const TYPELIB *typelib)
{
return set_attr_const_void_ptr(0, typelib);
}
const TYPELIB *typelib() const
{
return (const TYPELIB*) get_attr_const_void_ptr(0);
}
};
class Type_typelib_attributes
{
protected:
const TYPELIB *m_typelib;
public:
Type_typelib_attributes()
:m_typelib(nullptr)
{ }
Type_typelib_attributes(const TYPELIB *typelib)
:m_typelib(typelib)
{ }
Type_typelib_attributes(const Type_extra_attributes &eattr)
:m_typelib((const TYPELIB *) eattr.get_attr_const_void_ptr(0))
{ }
void store(Type_extra_attributes *to) const
{
to->set_attr_const_void_ptr(0, m_typelib);
}
const TYPELIB *typelib() const
{
return m_typelib;
}
void set_typelib(const TYPELIB *typelib)
{
m_typelib= typelib;
}
};
class Type_all_attributes: public Type_std_attributes class Type_all_attributes: public Type_std_attributes
{ {
public: public:
@ -3411,8 +3503,8 @@ public:
virtual void set_type_maybe_null(bool maybe_null_arg)= 0; virtual void set_type_maybe_null(bool maybe_null_arg)= 0;
// Returns total number of decimal digits // Returns total number of decimal digits
virtual decimal_digits_t decimal_precision() const= 0; virtual decimal_digits_t decimal_precision() const= 0;
virtual const TYPELIB *get_typelib() const= 0; virtual Type_extra_attributes *type_extra_attributes_addr() = 0;
virtual void set_typelib(const TYPELIB *typelib)= 0; virtual const Type_extra_attributes type_extra_attributes() const= 0;
}; };

View File

@ -22,6 +22,24 @@
#include "sql_type_geom.h" #include "sql_type_geom.h"
#include "item_geofunc.h" #include "item_geofunc.h"
class GeomTypeStr: public BinaryStringBuffer<64>
{
public:
GeomTypeStr(const Type_handler &th, const Type_geom_attributes &gattr)
{
append_char('`');
append(th.name().lex_cstring());
append_char(' ');
append(STRING_WITH_LEN("ref_system_id="));
append_ulonglong(gattr.get_srid());
append_char('`');
DBUG_ASSERT(str_length < Alloced_length);
Ptr[str_length]= '\0';
}
};
Named_type_handler<Type_handler_geometry> type_handler_geometry("geometry"); Named_type_handler<Type_handler_geometry> type_handler_geometry("geometry");
Named_type_handler<Type_handler_point> type_handler_point("point"); Named_type_handler<Type_handler_point> type_handler_point("point");
Named_type_handler<Type_handler_linestring> type_handler_linestring("linestring"); Named_type_handler<Type_handler_linestring> type_handler_linestring("linestring");
@ -256,7 +274,7 @@ Field *Type_handler_geometry::make_conversion_table_field(MEM_ROOT *root,
const Field_geom *fg= static_cast<const Field_geom*>(target); const Field_geom *fg= static_cast<const Field_geom*>(target);
return new (root) return new (root)
Field_geom(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str, Field_geom(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str,
table->s, 4, fg->type_handler_geom(), fg->srid); table->s, 4, fg->type_handler_geom(), *fg);
} }
@ -272,7 +290,8 @@ void Type_handler_geometry::
Column_definition *def, Column_definition *def,
const Field *field) const const Field *field) const
{ {
def->srid= ((Field_geom*) field)->srid; DBUG_ASSERT(dynamic_cast<const Field_geom*>(field));
static_cast<const Field_geom*>(field)->Type_geom_attributes::store(def);
} }
@ -486,13 +505,14 @@ Field *Type_handler_geometry::make_table_field(MEM_ROOT *root,
{ {
return new (root) return new (root)
Field_geom(addr.ptr(), addr.null_ptr(), addr.null_bit(), Field_geom(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, share, 4, this, 0); Field::NONE, name, share, 4, this,
Type_geom_attributes(attr.type_extra_attributes()));
} }
bool Type_handler_geometry:: bool Type_handler_geometry::
Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func_fix_attributes(THD *thd,
const LEX_CSTRING &func_name, const LEX_CSTRING &op_name,
Type_handler_hybrid_field_type *handler, Type_handler_hybrid_field_type *handler,
Type_all_attributes *func, Type_all_attributes *func,
Item **items, uint nitems) const Item **items, uint nitems) const
@ -503,6 +523,24 @@ bool Type_handler_geometry::
func->decimals= 0; func->decimals= 0;
func->max_length= (uint32) UINT_MAX32; func->max_length= (uint32) UINT_MAX32;
func->set_type_maybe_null(true); func->set_type_maybe_null(true);
Type_extra_attributes *func_eattr= func->type_extra_attributes_addr();
if (func_eattr && nitems > 0)
{
Type_geom_attributes gattr(items[0]->type_extra_attributes());
for (uint32 i= 1; i < nitems; i++)
{
const Type_geom_attributes gattr1(items[i]->type_extra_attributes());
if (gattr.join(gattr1))
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
GeomTypeStr(*items[i-1]->type_handler(), gattr).ptr(),
GeomTypeStr(*items[i]->type_handler(), gattr1).ptr(),
op_name.str);
return true;
}
}
gattr.store(func_eattr);
}
return false; return false;
} }
@ -660,7 +698,8 @@ Field *Type_handler_geometry::
return new (root) return new (root)
Field_geom(rec.ptr(), rec.null_ptr(), rec.null_bit(), Field_geom(rec.ptr(), rec.null_ptr(), rec.null_bit(),
attr->unireg_check, name, share, attr->unireg_check, name, share,
attr->pack_flag_to_pack_length(), this, attr->srid); attr->pack_flag_to_pack_length(), this,
Type_geom_attributes(*attr));
} }
@ -708,7 +747,7 @@ Type_handler_geometry::
cbuf[5]= (uchar) def.decimals; cbuf[5]= (uchar) def.decimals;
cbuf[6]= FIELDGEOM_SRID; cbuf[6]= FIELDGEOM_SRID;
int4store(cbuf + 7, ((uint32) def.srid)); int4store(cbuf + 7, Type_geom_attributes(def).get_srid());
cbuf[11]= FIELDGEOM_END; cbuf[11]= FIELDGEOM_END;
} }
@ -775,11 +814,13 @@ bool Type_handler_geometry::
{ {
uint gis_opt_read, gis_length, gis_decimals; uint gis_opt_read, gis_length, gis_decimals;
Field_geom::storage_type st_type; Field_geom::storage_type st_type;
uint32 srid= 0;
attr->frm_unpack_basic(buffer); attr->frm_unpack_basic(buffer);
gis_opt_read= gis_field_options_read(gis_options->str, gis_opt_read= gis_field_options_read(gis_options->str,
gis_options->length, gis_options->length,
&st_type, &gis_length, &st_type, &gis_length,
&gis_decimals, &attr->srid); &gis_decimals, &srid);
Type_geom_attributes(srid).store(attr);
gis_options->str+= gis_opt_read; gis_options->str+= gis_opt_read;
gis_options->length-= gis_opt_read; gis_options->length-= gis_opt_read;
return false; return false;

View File

@ -24,6 +24,40 @@
#include "mariadb.h" #include "mariadb.h"
#include "sql_type.h" #include "sql_type.h"
class Type_geom_attributes
{
protected:
uint32 m_srid;
public:
Type_geom_attributes()
:m_srid(0)
{ }
explicit Type_geom_attributes(const Type_extra_attributes &eattr)
:m_srid(eattr.get_attr_uint32(0))
{ }
explicit Type_geom_attributes(uint32 srid)
:m_srid(srid)
{ }
void store(Type_extra_attributes *to) const
{
to->set_attr_uint32(0, m_srid);
}
void set_srid(uint32 srid)
{
m_srid= srid;
}
uint32 get_srid() const
{
return m_srid;
}
bool join(const Type_geom_attributes &rhs)
{
return m_srid != rhs.m_srid;
}
};
#ifdef HAVE_SPATIAL #ifdef HAVE_SPATIAL
class Type_handler_geometry: public Type_handler_string_result class Type_handler_geometry: public Type_handler_string_result
{ {
@ -326,11 +360,11 @@ Type_collection_geometry_handler_by_name(const LEX_CSTRING &name);
#include "field.h" #include "field.h"
class Field_geom :public Field_blob class Field_geom :public Field_blob,
public Type_geom_attributes
{ {
const Type_handler_geometry *m_type_handler; const Type_handler_geometry *m_type_handler;
public: public:
uint srid;
uint precision; uint precision;
enum storage_type { GEOM_STORAGE_WKB= 0, GEOM_STORAGE_BINARY= 1}; enum storage_type { GEOM_STORAGE_WKB= 0, GEOM_STORAGE_BINARY= 1};
enum storage_type storage; enum storage_type storage;
@ -339,11 +373,12 @@ public:
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
TABLE_SHARE *share, uint blob_pack_length, TABLE_SHARE *share, uint blob_pack_length,
const Type_handler_geometry *gth, const Type_handler_geometry *gth,
uint field_srid) const Type_geom_attributes &geom_attr)
:Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
field_name_arg, share, blob_pack_length, &my_charset_bin), field_name_arg, share, blob_pack_length, &my_charset_bin),
Type_geom_attributes(geom_attr),
m_type_handler(gth) m_type_handler(gth)
{ srid= field_srid; } { }
enum_conv_type rpl_conv_type_from(const Conv_source &source, enum_conv_type rpl_conv_type_from(const Conv_source &source,
const Relay_log_info *rli, const Relay_log_info *rli,
const Conv_param &param) const override; const Conv_param &param) const override;
@ -363,6 +398,12 @@ public:
{ {
m_type_handler= th; m_type_handler= th;
} }
const Type_extra_attributes type_extra_attributes() const override
{
Type_extra_attributes eattr;
Type_geom_attributes::store(&eattr);
return eattr;
}
enum_field_types type() const override enum_field_types type() const override
{ {
return MYSQL_TYPE_GEOMETRY; return MYSQL_TYPE_GEOMETRY;
@ -428,7 +469,6 @@ public:
bool load_data_set_null(THD *thd) override; bool load_data_set_null(THD *thd) override;
bool load_data_set_no_data(THD *thd, bool fixed_format) override; bool load_data_set_no_data(THD *thd, bool fixed_format) override;
uint get_srid() const { return srid; }
void print_key_value(String *out, uint32 length) override void print_key_value(String *out, uint32 length) override
{ {
out->append(STRING_WITH_LEN("unprintable_geometry_value")); out->append(STRING_WITH_LEN("unprintable_geometry_value"));

View File

@ -6494,11 +6494,11 @@ real_type:
srid_option: srid_option:
/* empty */ /* empty */
{ Lex->last_field->srid= 0; } { Lex->last_field->set_attr_uint32(0, 0); }
| |
REF_SYSTEM_ID_SYM '=' NUM REF_SYSTEM_ID_SYM '=' NUM
{ {
Lex->last_field->srid=atoi($3.str); Lex->last_field->set_attr_uint32(0, (uint32) atoi($3.str));
} }
; ;

View File

@ -2734,7 +2734,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
/* Convert pre-10.2.2 timestamps to use Field::default_value */ /* Convert pre-10.2.2 timestamps to use Field::default_value */
name.str= fieldnames.type_names[i]; name.str= fieldnames.type_names[i];
name.length= strlen(name.str); name.length= strlen(name.str);
attr.interval= interval_nr ? share->intervals + interval_nr - 1 : NULL; attr.set_typelib(interval_nr ? share->intervals + interval_nr - 1 : NULL);
Record_addr addr(record + recpos, null_pos, null_bit_pos); Record_addr addr(record + recpos, null_pos, null_bit_pos);
*field_ptr= reg_field= *field_ptr= reg_field=
attr.make_field(share, &share->mem_root, &addr, handler, &name, flags); attr.make_field(share, &share->mem_root, &addr, handler, &name, flags);
@ -10573,7 +10573,7 @@ bool TR_table::check(bool error)
} }
Field_enum *iso_level= static_cast<Field_enum *>(table->field[FLD_ISO_LEVEL]); Field_enum *iso_level= static_cast<Field_enum *>(table->field[FLD_ISO_LEVEL]);
const st_typelib *typelib= iso_level->typelib; const st_typelib *typelib= iso_level->typelib();
if (typelib->count != 4) if (typelib->count != 4)
goto wrong_enum; goto wrong_enum;

View File

@ -644,7 +644,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
{ {
if (field->save_interval) if (field->save_interval)
{ {
field->interval= field->save_interval; field->set_typelib(field->save_interval);
field->save_interval= 0; field->save_interval= 0;
} }
} }
@ -887,7 +887,7 @@ static bool pack_header(THD *thd, uchar *forminfo,
n_length+= field->field_name.length + 1; n_length+= field->field_name.length + 1;
field->interval_id=0; field->interval_id=0;
field->save_interval= 0; field->save_interval= 0;
if (field->interval) if (field->typelib())
{ {
uint old_int_count=int_count; uint old_int_count=int_count;
@ -902,9 +902,9 @@ static bool pack_header(THD *thd, uchar *forminfo,
filled with default values it is saved in save_interval filled with default values it is saved in save_interval
The HEX representation is created from this copy. The HEX representation is created from this copy.
*/ */
uint count= field->interval->count; uint count= field->typelib()->count;
field->save_interval= field->interval; field->save_interval= field->typelib();
field->interval= tmpint= (TYPELIB*) thd->alloc(sizeof(TYPELIB)); field->set_typelib(tmpint= (TYPELIB*) thd->alloc(sizeof(TYPELIB)));
*tmpint= *field->save_interval; *tmpint= *field->save_interval;
tmpint->type_names= tmpint->type_names=
(const char **) thd->alloc(sizeof(char*) * (const char **) thd->alloc(sizeof(char*) *
@ -913,7 +913,7 @@ static bool pack_header(THD *thd, uchar *forminfo,
tmpint->type_names[count]= 0; tmpint->type_names[count]= 0;
tmpint->type_lengths[count]= 0; tmpint->type_lengths[count]= 0;
for (uint pos= 0; pos < field->interval->count; pos++) for (uint pos= 0; pos < field->typelib()->count; pos++)
{ {
char *dst; char *dst;
const char *src= field->save_interval->type_names[pos]; const char *src= field->save_interval->type_names[pos];
@ -929,8 +929,8 @@ static bool pack_header(THD *thd, uchar *forminfo,
field->interval_id=get_interval_id(&int_count,create_fields,field); field->interval_id=get_interval_id(&int_count,create_fields,field);
if (old_int_count != int_count) if (old_int_count != int_count)
{ {
int_length+= typelib_values_packed_length(field->interval); int_length+= typelib_values_packed_length(field->typelib());
int_parts+= field->interval->count + 1; int_parts+= field->typelib()->count + 1;
} }
} }
if (f_maybe_null(field->pack_flag)) if (f_maybe_null(field->pack_flag))
@ -984,7 +984,7 @@ static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
{ {
List_iterator<Create_field> it(create_fields); List_iterator<Create_field> it(create_fields);
Create_field *field; Create_field *field;
const TYPELIB *interval= last_field->interval; const TYPELIB *interval= last_field->typelib();
while ((field=it++) != last_field) while ((field=it++) != last_field)
{ {
@ -996,11 +996,11 @@ static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
- mbminlen>1 are written to FRM in hex-encoded format - mbminlen>1 are written to FRM in hex-encoded format
*/ */
if (field->interval_id && if (field->interval_id &&
field->interval->count == interval->count && field->typelib()->count == interval->count &&
field->charset->mbminlen == last_field->charset->mbminlen) field->charset->mbminlen == last_field->charset->mbminlen)
{ {
const char **a,**b; const char **a,**b;
for (a=field->interval->type_names, b=interval->type_names ; for (a= field->typelib()->type_names, b= interval->type_names ;
*a && !strcmp(*a,*b); *a && !strcmp(*a,*b);
a++,b++) ; a++,b++) ;
@ -1028,7 +1028,7 @@ static size_t packed_fields_length(List<Create_field> &create_fields)
{ {
int_count= field->interval_id; int_count= field->interval_id;
length++; length++;
length+= typelib_values_packed_length(field->interval); length+= typelib_values_packed_length(field->typelib());
length++; length++;
} }
@ -1096,8 +1096,8 @@ static bool pack_fields(uchar **buff_arg, List<Create_field> &create_fields,
bzero(occ, sizeof(occ)); bzero(occ, sizeof(occ));
for (i=0; (val= (unsigned char*) field->interval->type_names[i]); i++) for (i=0; (val= (unsigned char*) field->typelib()->type_names[i]); i++)
for (uint j = 0; j < field->interval->type_lengths[i]; j++) for (uint j = 0; j < field->typelib()->type_lengths[i]; j++)
occ[(unsigned int) (val[j])]= 1; occ[(unsigned int) (val[j])]= 1;
if (!occ[(unsigned char)NAMES_SEP_CHAR]) if (!occ[(unsigned char)NAMES_SEP_CHAR])
@ -1127,10 +1127,11 @@ static bool pack_fields(uchar **buff_arg, List<Create_field> &create_fields,
int_count= field->interval_id; int_count= field->interval_id;
*buff++= sep; *buff++= sep;
for (int i=0; field->interval->type_names[i]; i++) for (int i=0; field->typelib()->type_names[i]; i++)
{ {
memcpy(buff, field->interval->type_names[i], field->interval->type_lengths[i]); memcpy(buff, field->typelib()->type_names[i],
buff+= field->interval->type_lengths[i]; field->typelib()->type_lengths[i]);
buff+= field->typelib()->type_lengths[i];
*buff++= sep; *buff++= sep;
} }
*buff++= 0; *buff++= 0;
@ -1214,8 +1215,8 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
Record_addr addr(buff + field->offset + data_offset, Record_addr addr(buff + field->offset + data_offset,
null_pos + null_count / 8, null_count & 7); null_pos + null_count / 8, null_count & 7);
Column_definition_attributes tmp(*field); Column_definition_attributes tmp(*field);
tmp.interval= field->save_interval ? tmp.set_typelib(field->save_interval ?
field->save_interval : field->interval; field->save_interval : field->typelib());
/* regfield don't have to be deleted as it's allocated on THD::mem_root */ /* regfield don't have to be deleted as it's allocated on THD::mem_root */
Field *regfield= tmp.make_field(&share, thd->mem_root, &addr, Field *regfield= tmp.make_field(&share, thd->mem_root, &addr,
field->type_handler(), field->type_handler(),