summaryrefslogtreecommitdiff
path: root/sql/unireg.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/unireg.cc')
-rw-r--r--sql/unireg.cc141
1 files changed, 124 insertions, 17 deletions
diff --git a/sql/unireg.cc b/sql/unireg.cc
index a1605dac2e6..e4a43d3ace5 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -152,6 +152,80 @@ static size_t extra2_str_size(size_t len)
return (len > 255 ? 3 : 1) + len;
}
+
+static uint gis_field_options_image(uchar *buff,
+ List<Create_field> &create_fields)
+{
+ uint image_size= 0;
+ List_iterator<Create_field> it(create_fields);
+ Create_field *field;
+ while ((field= it++))
+ {
+ if (field->real_field_type() != MYSQL_TYPE_GEOMETRY)
+ continue;
+ uchar *cbuf= buff ? buff + image_size : NULL;
+ image_size+= field->type_handler()->
+ Column_definition_gis_options_image(cbuf, *field);
+ }
+ return image_size;
+}
+
+
+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
@@ -191,6 +265,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
uchar *frm_ptr, *pos;
LEX_CUSTRING frm= {0,0};
StringBuffer<MAX_FIELD_WIDTH> vcols;
+ Field_data_type_info_image field_data_type_info_image;
DBUG_ENTER("build_frm_image");
/* If fixed row records, we need one bit to check for deleted rows */
@@ -241,11 +316,25 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
options_len= engine_table_options_frm_length(create_info->option_list,
create_fields,
keys, key_info);
-#ifdef HAVE_SPATIAL
gis_extra2_len= gis_field_options_image(NULL, create_fields);
-#endif /*HAVE_SPATIAL*/
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,
ER_TOO_LONG_TABLE_COMMENT, table.str))
DBUG_RETURN(frm);
@@ -291,6 +380,9 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
if (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())
{
extra2_size+= 1 + extra2_str_size(2 * frm_fieldno_size);
@@ -356,14 +448,28 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
create_fields, keys, key_info);
}
-#ifdef HAVE_SPATIAL
if (gis_extra2_len)
{
*pos= EXTRA2_GIS;
pos= extra2_write_len(pos+1, gis_extra2_len);
pos+= gis_field_options_image(pos, create_fields);
}
-#endif /*HAVE_SPATIAL*/
+
+ 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
if (create_info->period_info.is_set())
@@ -723,6 +829,7 @@ static bool pack_header(THD *thd, uchar *forminfo,
if (field->charset->mbminlen > 1)
{
+ TYPELIB *tmpint;
/*
Escape UCS2 intervals using HEX notation to avoid
problems with delimiters between enum elements.
@@ -731,16 +838,17 @@ static bool pack_header(THD *thd, uchar *forminfo,
filled with default values it is saved in save_interval
The HEX representation is created from this copy.
*/
+ uint count= field->interval->count;
field->save_interval= field->interval;
- field->interval= (TYPELIB*) thd->alloc(sizeof(TYPELIB));
- *field->interval= *field->save_interval;
- field->interval->type_names=
- (const char **) thd->alloc(sizeof(char*) *
- (field->interval->count+1));
- field->interval->type_names[field->interval->count]= 0;
- field->interval->type_lengths=
- (uint *) thd->alloc(sizeof(uint) * field->interval->count);
-
+ field->interval= tmpint= (TYPELIB*) thd->alloc(sizeof(TYPELIB));
+ *tmpint= *field->save_interval;
+ tmpint->type_names=
+ (const char **) thd->alloc(sizeof(char*) *
+ (count + 1));
+ tmpint->type_lengths= (uint *) thd->alloc(sizeof(uint) * (count + 1));
+ tmpint->type_names[count]= 0;
+ tmpint->type_lengths[count]= 0;
+
for (uint pos= 0; pos < field->interval->count; pos++)
{
char *dst;
@@ -748,9 +856,8 @@ static bool pack_header(THD *thd, uchar *forminfo,
size_t hex_length;
length= field->save_interval->type_lengths[pos];
hex_length= length * 2;
- field->interval->type_lengths[pos]= (uint)hex_length;
- field->interval->type_names[pos]= dst=
- (char*) thd->alloc(hex_length + 1);
+ tmpint->type_lengths[pos]= (uint) hex_length;
+ tmpint->type_names[pos]= dst= (char*) thd->alloc(hex_length + 1);
octet2hex(dst, src, length);
}
}
@@ -814,7 +921,7 @@ static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
{
List_iterator<Create_field> it(create_fields);
Create_field *field;
- TYPELIB *interval=last_field->interval;
+ const TYPELIB *interval= last_field->interval;
while ((field=it++) != last_field)
{