diff options
Diffstat (limited to 'sql/unireg.cc')
-rw-r--r-- | sql/unireg.cc | 141 |
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) { |