mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-20042 Implement EXTRA2_FIELD_DATA_TYPE_INFO in FRM
This commit is contained in:
21
mysql-test/main/frm-debug.result
Normal file
21
mysql-test/main/frm-debug.result
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#
|
||||||
|
# MDEV-20042 Implement EXTRA2_FIELD_DATA_TYPE_INFO in FRM
|
||||||
|
#
|
||||||
|
SET SESSION debug_dbug="+d,frm_data_type_info";
|
||||||
|
CREATE TABLE t1 (c01 INT, c02 CHAR(20), c03 TEXT, c04 DOUBLE);
|
||||||
|
Warnings:
|
||||||
|
Note 1105 build_frm_image: Field data type info length: 0
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET SESSION debug_dbug="-d,frm_data_type_info";
|
||||||
|
SET SESSION debug_dbug="+d,frm_data_type_info";
|
||||||
|
SET SESSION debug_dbug="+d,frm_data_type_info_emulate";
|
||||||
|
CREATE TABLE t1 (c01 INT, c02 CHAR(20), c03 TEXT, c04 DOUBLE);
|
||||||
|
Warnings:
|
||||||
|
Note 1105 build_frm_image: Field data type info length: 12
|
||||||
|
Note 1105 DBUG: [0] name='c01' type_info=''
|
||||||
|
Note 1105 DBUG: [1] name='c02' type_info='char'
|
||||||
|
Note 1105 DBUG: [2] name='c03' type_info='blob'
|
||||||
|
Note 1105 DBUG: [3] name='c04' type_info=''
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET SESSION debug_dbug="-d,frm_data_type_info_emulate";
|
||||||
|
SET SESSION debug_dbug="-d,frm_data_type_info";
|
19
mysql-test/main/frm-debug.test
Normal file
19
mysql-test/main/frm-debug.test
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
--source include/have_debug.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-20042 Implement EXTRA2_FIELD_DATA_TYPE_INFO in FRM
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
# This should have empty EXTRA2_FIELD_DATA_TYPE_INFO
|
||||||
|
SET SESSION debug_dbug="+d,frm_data_type_info";
|
||||||
|
CREATE TABLE t1 (c01 INT, c02 CHAR(20), c03 TEXT, c04 DOUBLE);
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET SESSION debug_dbug="-d,frm_data_type_info";
|
||||||
|
|
||||||
|
# This should have non-empty EXTRA2_FIELD_DATA_TYPE_INFO
|
||||||
|
SET SESSION debug_dbug="+d,frm_data_type_info";
|
||||||
|
SET SESSION debug_dbug="+d,frm_data_type_info_emulate";
|
||||||
|
CREATE TABLE t1 (c01 INT, c02 CHAR(20), c03 TEXT, c04 DOUBLE);
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET SESSION debug_dbug="-d,frm_data_type_info_emulate";
|
||||||
|
SET SESSION debug_dbug="-d,frm_data_type_info";
|
@ -528,6 +528,10 @@ public:
|
|||||||
q_append(s, size);
|
q_append(s, size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool append(const LEX_CSTRING &s)
|
||||||
|
{
|
||||||
|
return append(s.str, s.length);
|
||||||
|
}
|
||||||
bool append(const Binary_string &s)
|
bool append(const Binary_string &s)
|
||||||
{
|
{
|
||||||
return append(s.ptr(), s.length());
|
return append(s.ptr(), s.length());
|
||||||
@ -1001,6 +1005,15 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<size_t buff_sz>
|
||||||
|
class BinaryStringBuffer : public Binary_string
|
||||||
|
{
|
||||||
|
char buff[buff_sz];
|
||||||
|
public:
|
||||||
|
BinaryStringBuffer() : Binary_string(buff, buff_sz) { length(0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class String_space: public String
|
class String_space: public String
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -8365,6 +8365,20 @@ const Name & Type_handler_timestamp_common::default_value() const
|
|||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************************/
|
||||||
|
|
||||||
|
bool Type_handler::Column_definition_data_type_info_image(Binary_string *to,
|
||||||
|
const Column_definition &def)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
// Have *some* columns write type info (let's use string fields as an example)
|
||||||
|
DBUG_EXECUTE_IF("frm_data_type_info_emulate",
|
||||||
|
if (cmp_type() == STRING_RESULT)
|
||||||
|
return to->append(name().lex_cstring()););
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
LEX_CSTRING Charset::collation_specific_name() const
|
LEX_CSTRING Charset::collation_specific_name() const
|
||||||
|
@ -3076,6 +3076,7 @@ public:
|
|||||||
}
|
}
|
||||||
const char *ptr() const { return LEX_CSTRING::str; }
|
const char *ptr() const { return LEX_CSTRING::str; }
|
||||||
uint length() const { return (uint) LEX_CSTRING::length; }
|
uint length() const { return (uint) LEX_CSTRING::length; }
|
||||||
|
const LEX_CSTRING &lex_cstring() const { return *this; }
|
||||||
bool eq(const LEX_CSTRING &other) const
|
bool eq(const LEX_CSTRING &other) const
|
||||||
{
|
{
|
||||||
return !my_strnncoll(system_charset_info,
|
return !my_strnncoll(system_charset_info,
|
||||||
@ -3490,6 +3491,9 @@ public:
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
virtual bool Column_definition_data_type_info_image(Binary_string *to,
|
||||||
|
const Column_definition &def)
|
||||||
|
const;
|
||||||
// Check if the implicit default value is Ok in the current sql_mode
|
// Check if the implicit default value is Ok in the current sql_mode
|
||||||
virtual bool validate_implicit_default_value(THD *thd,
|
virtual bool validate_implicit_default_value(THD *thd,
|
||||||
const Column_definition &def)
|
const Column_definition &def)
|
||||||
|
103
sql/table.cc
103
sql/table.cc
@ -59,6 +59,7 @@ struct extra2_fields
|
|||||||
LEX_CUSTRING field_flags;
|
LEX_CUSTRING field_flags;
|
||||||
LEX_CUSTRING system_period;
|
LEX_CUSTRING system_period;
|
||||||
LEX_CUSTRING application_period;
|
LEX_CUSTRING application_period;
|
||||||
|
LEX_CUSTRING field_data_type_info;
|
||||||
void reset()
|
void reset()
|
||||||
{ bzero((void*)this, sizeof(*this)); }
|
{ bzero((void*)this, sizeof(*this)); }
|
||||||
};
|
};
|
||||||
@ -1508,6 +1509,12 @@ bool read_extra2(const uchar *frm_image, size_t len, extra2_fields *fields)
|
|||||||
fields->application_period.str= extra2;
|
fields->application_period.str= extra2;
|
||||||
fields->application_period.length= length;
|
fields->application_period.length= length;
|
||||||
break;
|
break;
|
||||||
|
case EXTRA2_FIELD_DATA_TYPE_INFO:
|
||||||
|
if (fields->field_data_type_info.str)
|
||||||
|
DBUG_RETURN(true);
|
||||||
|
fields->field_data_type_info.str= extra2;
|
||||||
|
fields->field_data_type_info.length= length;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* abort frm parsing if it's an unknown but important extra2 value */
|
/* abort frm parsing if it's an unknown but important extra2 value */
|
||||||
if (type >= EXTRA2_ENGINE_IMPORTANT)
|
if (type >= EXTRA2_ENGINE_IMPORTANT)
|
||||||
@ -1522,6 +1529,86 @@ bool read_extra2(const uchar *frm_image, size_t len, extra2_fields *fields)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Field_data_type_info_array
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class Elem
|
||||||
|
{
|
||||||
|
LEX_CSTRING m_type_info;
|
||||||
|
public:
|
||||||
|
void set(const LEX_CSTRING &type_info)
|
||||||
|
{
|
||||||
|
m_type_info= type_info;
|
||||||
|
}
|
||||||
|
const LEX_CSTRING &type_info() const
|
||||||
|
{
|
||||||
|
return m_type_info;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
Elem *m_array;
|
||||||
|
uint m_count;
|
||||||
|
bool alloc(MEM_ROOT *root, uint count)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(!m_array);
|
||||||
|
DBUG_ASSERT(!m_count);
|
||||||
|
size_t nbytes= sizeof(Elem) * count;
|
||||||
|
if (!(m_array= (Elem*) alloc_root(root, nbytes)))
|
||||||
|
return true;
|
||||||
|
m_count= count;
|
||||||
|
bzero((void*) m_array, nbytes);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static uint32 read_length(uchar **pos, const uchar *end)
|
||||||
|
{
|
||||||
|
ulonglong num= safe_net_field_length_ll(pos, end - *pos);
|
||||||
|
if (num > UINT_MAX32)
|
||||||
|
return 0;
|
||||||
|
return (uint32) num;
|
||||||
|
}
|
||||||
|
static bool read_string(LEX_CSTRING *to, uchar **pos, const uchar *end)
|
||||||
|
{
|
||||||
|
to->length= read_length(pos, end);
|
||||||
|
if (*pos + to->length > end)
|
||||||
|
return true; // Not enough data
|
||||||
|
to->str= (const char *) *pos;
|
||||||
|
*pos+= to->length;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
Field_data_type_info_array()
|
||||||
|
:m_array(NULL), m_count(0)
|
||||||
|
{ }
|
||||||
|
uint count() const
|
||||||
|
{
|
||||||
|
return m_count;
|
||||||
|
}
|
||||||
|
const Elem element(uint i) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(i < m_count);
|
||||||
|
return m_array[i];
|
||||||
|
}
|
||||||
|
bool parse(MEM_ROOT *root, uint count, LEX_CUSTRING &image)
|
||||||
|
{
|
||||||
|
const uchar *pos= image.str;
|
||||||
|
const uchar *end= pos + image.length;
|
||||||
|
if (alloc(root, count))
|
||||||
|
return true;
|
||||||
|
for (uint i= 0; i < count && pos < end; i++)
|
||||||
|
{
|
||||||
|
LEX_CSTRING type_info;
|
||||||
|
uint fieldnr= read_length((uchar**) &pos, end);
|
||||||
|
if ((fieldnr == 0 && i > 0) || fieldnr >= count)
|
||||||
|
return true; // Bad data
|
||||||
|
if (read_string(&type_info, (uchar**) &pos, end) || type_info.length == 0)
|
||||||
|
return true; // Bad data
|
||||||
|
m_array[fieldnr].set(type_info);
|
||||||
|
}
|
||||||
|
return pos < end; // Error if some data is still left
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Read data from a binary .frm file image into a TABLE_SHARE
|
Read data from a binary .frm file image into a TABLE_SHARE
|
||||||
|
|
||||||
@ -1572,6 +1659,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
|
|||||||
uint ext_key_parts= 0;
|
uint ext_key_parts= 0;
|
||||||
plugin_ref se_plugin= 0;
|
plugin_ref se_plugin= 0;
|
||||||
bool vers_can_native= false;
|
bool vers_can_native= false;
|
||||||
|
Field_data_type_info_array field_data_type_info_array;
|
||||||
|
|
||||||
MEM_ROOT *old_root= thd->mem_root;
|
MEM_ROOT *old_root= thd->mem_root;
|
||||||
Virtual_column_info **table_check_constraints;
|
Virtual_column_info **table_check_constraints;
|
||||||
@ -2111,6 +2199,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
|
|||||||
status_var_increment(thd->status_var.feature_application_time_periods);
|
status_var_increment(thd->status_var.feature_application_time_periods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extra2.field_data_type_info.length &&
|
||||||
|
field_data_type_info_array.parse(old_root, share->fields,
|
||||||
|
extra2.field_data_type_info))
|
||||||
|
goto err;
|
||||||
|
|
||||||
for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++)
|
for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++)
|
||||||
{
|
{
|
||||||
uint interval_nr= 0, recpos;
|
uint interval_nr= 0, recpos;
|
||||||
@ -2195,6 +2288,16 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
|
|||||||
strpos,
|
strpos,
|
||||||
&extra2.gis))
|
&extra2.gis))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
if (field_data_type_info_array.count())
|
||||||
|
{
|
||||||
|
DBUG_EXECUTE_IF("frm_data_type_info",
|
||||||
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
|
||||||
|
ER_UNKNOWN_ERROR, "DBUG: [%u] name='%s' type_info='%.*s'",
|
||||||
|
i, share->fieldnames.type_names[i],
|
||||||
|
(uint) field_data_type_info_array.element(i).type_info().length,
|
||||||
|
field_data_type_info_array.element(i).type_info().str););
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((uint) strpos[10]) & MYSQL57_GENERATED_FIELD)
|
if (((uint) strpos[10]) & MYSQL57_GENERATED_FIELD)
|
||||||
|
@ -171,6 +171,61 @@ static uint gis_field_options_image(uchar *buff,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Field_data_type_info_image: public BinaryStringBuffer<512>
|
||||||
|
{
|
||||||
|
static uchar *store_length(uchar *pos, ulonglong length)
|
||||||
|
{
|
||||||
|
return net_store_length(pos, length);
|
||||||
|
}
|
||||||
|
static uchar *store_string(uchar *pos, const LEX_CSTRING &str)
|
||||||
|
{
|
||||||
|
pos= store_length(pos, str.length);
|
||||||
|
memcpy(pos, str.str, str.length);
|
||||||
|
return pos + str.length;
|
||||||
|
}
|
||||||
|
static uint store_length_required_length(ulonglong length)
|
||||||
|
{
|
||||||
|
return net_length_size(length);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
Field_data_type_info_image() { }
|
||||||
|
bool append(uint fieldnr, const Column_definition &def)
|
||||||
|
{
|
||||||
|
BinaryStringBuffer<64> type_info;
|
||||||
|
if (def.type_handler()->
|
||||||
|
Column_definition_data_type_info_image(&type_info, def) ||
|
||||||
|
type_info.length() > 0xFFFF/*Some reasonable limit*/)
|
||||||
|
return true; // Error
|
||||||
|
if (!type_info.length())
|
||||||
|
return false;
|
||||||
|
size_t need_length= store_length_required_length(fieldnr) +
|
||||||
|
store_length_required_length(type_info.length()) +
|
||||||
|
type_info.length();
|
||||||
|
if (reserve(need_length))
|
||||||
|
return true; // Error
|
||||||
|
uchar *pos= (uchar *) end();
|
||||||
|
pos= store_length(pos, fieldnr);
|
||||||
|
pos= store_string(pos, type_info.lex_cstring());
|
||||||
|
size_t new_length= (const char *) pos - ptr();
|
||||||
|
DBUG_ASSERT(new_length < alloced_length());
|
||||||
|
length((uint32) new_length);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool append(List<Create_field> &fields)
|
||||||
|
{
|
||||||
|
uint fieldnr= 0;
|
||||||
|
Create_field *field;
|
||||||
|
List_iterator<Create_field> it(fields);
|
||||||
|
for (field= it++; field; field= it++, fieldnr++)
|
||||||
|
{
|
||||||
|
if (append(fieldnr, *field))
|
||||||
|
return true; // Error
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create a frm (table definition) file
|
Create a frm (table definition) file
|
||||||
|
|
||||||
@ -210,6 +265,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
|
|||||||
uchar *frm_ptr, *pos;
|
uchar *frm_ptr, *pos;
|
||||||
LEX_CUSTRING frm= {0,0};
|
LEX_CUSTRING frm= {0,0};
|
||||||
StringBuffer<MAX_FIELD_WIDTH> vcols;
|
StringBuffer<MAX_FIELD_WIDTH> vcols;
|
||||||
|
Field_data_type_info_image field_data_type_info_image;
|
||||||
DBUG_ENTER("build_frm_image");
|
DBUG_ENTER("build_frm_image");
|
||||||
|
|
||||||
/* If fixed row records, we need one bit to check for deleted rows */
|
/* If fixed row records, we need one bit to check for deleted rows */
|
||||||
@ -263,6 +319,22 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
|
|||||||
gis_extra2_len= gis_field_options_image(NULL, create_fields);
|
gis_extra2_len= gis_field_options_image(NULL, create_fields);
|
||||||
DBUG_PRINT("info", ("Options length: %u", options_len));
|
DBUG_PRINT("info", ("Options length: %u", options_len));
|
||||||
|
|
||||||
|
if (field_data_type_info_image.append(create_fields))
|
||||||
|
{
|
||||||
|
my_printf_error(ER_CANT_CREATE_TABLE,
|
||||||
|
"Cannot create table %`s: "
|
||||||
|
"Building the field data type info image failed.",
|
||||||
|
MYF(0), table.str);
|
||||||
|
DBUG_RETURN(frm);
|
||||||
|
}
|
||||||
|
DBUG_PRINT("info", ("Field data type info length: %u",
|
||||||
|
(uint) field_data_type_info_image.length()));
|
||||||
|
DBUG_EXECUTE_IF("frm_data_type_info",
|
||||||
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
|
||||||
|
ER_UNKNOWN_ERROR,
|
||||||
|
"build_frm_image: Field data type info length: %u",
|
||||||
|
(uint) field_data_type_info_image.length()););
|
||||||
|
|
||||||
if (validate_comment_length(thd, &create_info->comment, TABLE_COMMENT_MAXLEN,
|
if (validate_comment_length(thd, &create_info->comment, TABLE_COMMENT_MAXLEN,
|
||||||
ER_TOO_LONG_TABLE_COMMENT, table.str))
|
ER_TOO_LONG_TABLE_COMMENT, table.str))
|
||||||
DBUG_RETURN(frm);
|
DBUG_RETURN(frm);
|
||||||
@ -308,6 +380,9 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
|
|||||||
if (gis_extra2_len)
|
if (gis_extra2_len)
|
||||||
extra2_size+= 1 + extra2_str_size(gis_extra2_len);
|
extra2_size+= 1 + extra2_str_size(gis_extra2_len);
|
||||||
|
|
||||||
|
if (field_data_type_info_image.length())
|
||||||
|
extra2_size+= 1 + extra2_str_size(field_data_type_info_image.length());
|
||||||
|
|
||||||
if (create_info->versioned())
|
if (create_info->versioned())
|
||||||
{
|
{
|
||||||
extra2_size+= 1 + extra2_str_size(2 * frm_fieldno_size);
|
extra2_size+= 1 + extra2_str_size(2 * frm_fieldno_size);
|
||||||
@ -380,6 +455,22 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
|
|||||||
pos+= gis_field_options_image(pos, create_fields);
|
pos+= gis_field_options_image(pos, create_fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (field_data_type_info_image.length())
|
||||||
|
{
|
||||||
|
if (field_data_type_info_image.length() > 0xFFFF)
|
||||||
|
{
|
||||||
|
my_printf_error(ER_CANT_CREATE_TABLE,
|
||||||
|
"Cannot create table %`s: "
|
||||||
|
"field data type info image is too large. "
|
||||||
|
"Decrease the number of columns with "
|
||||||
|
"extended data types.",
|
||||||
|
MYF(0), table.str);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
*pos= EXTRA2_FIELD_DATA_TYPE_INFO;
|
||||||
|
pos= extra2_write_str(pos + 1, field_data_type_info_image.lex_cstring());
|
||||||
|
}
|
||||||
|
|
||||||
// PERIOD
|
// PERIOD
|
||||||
if (create_info->period_info.is_set())
|
if (create_info->period_info.is_set())
|
||||||
{
|
{
|
||||||
|
@ -176,7 +176,8 @@ enum extra2_frm_value_type {
|
|||||||
#define EXTRA2_ENGINE_IMPORTANT 128
|
#define EXTRA2_ENGINE_IMPORTANT 128
|
||||||
|
|
||||||
EXTRA2_ENGINE_TABLEOPTS=128,
|
EXTRA2_ENGINE_TABLEOPTS=128,
|
||||||
EXTRA2_FIELD_FLAGS=129
|
EXTRA2_FIELD_FLAGS=129,
|
||||||
|
EXTRA2_FIELD_DATA_TYPE_INFO=130
|
||||||
};
|
};
|
||||||
|
|
||||||
enum extra2_field_flags {
|
enum extra2_field_flags {
|
||||||
|
Reference in New Issue
Block a user