summaryrefslogtreecommitdiff
path: root/sql/sql_table.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r--sql/sql_table.cc147
1 files changed, 22 insertions, 125 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index f8a61b641c0..fa99605bd6d 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2822,40 +2822,6 @@ bool check_duplicates_in_interval(const char *set_or_name,
/*
- Check TYPELIB (set or enum) max and total lengths
-
- SYNOPSIS
- calculate_interval_lengths()
- cs charset+collation pair of the interval
- typelib list of values for the column
- max_length length of the longest item
- tot_length sum of the item lengths
-
- DESCRIPTION
- After this function call:
- - ENUM uses max_length
- - SET uses tot_length.
-
- RETURN VALUES
- void
-*/
-void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
- uint32 *max_length, uint32 *tot_length)
-{
- const char **pos;
- uint *len;
- *max_length= *tot_length= 0;
- for (pos= interval->type_names, len= interval->type_lengths;
- *pos ; pos++, len++)
- {
- size_t length= cs->cset->numchars(cs, *pos, *pos + *len);
- *tot_length+= length;
- set_if_bigger(*max_length, (uint32)length);
- }
-}
-
-
-/*
Prepare a create_table instance for packing
SYNOPSIS
@@ -3251,79 +3217,16 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (sql_field->sql_type == MYSQL_TYPE_SET ||
sql_field->sql_type == MYSQL_TYPE_ENUM)
{
- uint32 dummy;
- CHARSET_INFO *cs= sql_field->charset;
- TYPELIB *interval= sql_field->interval;
-
/*
- Create typelib from interval_list, and if necessary
- convert strings from client character set to the
- column character set.
+ Create the typelib in runtime memory - we will free the
+ occupied memory at the same time when we free this
+ sql_field -- at the end of execution.
+ Pass "true" as the last argument to reuse "interval_list"
+ values in "interval" in cases when no character conversion is needed,
+ to avoid extra copying.
*/
- if (!interval)
- {
- /*
- Create the typelib in runtime memory - we will free the
- occupied memory at the same time when we free this
- sql_field -- at the end of execution.
- */
- interval= sql_field->interval= typelib(thd->mem_root,
- sql_field->interval_list);
- List_iterator<String> int_it(sql_field->interval_list);
- String conv, *tmp;
- char comma_buf[5]; /* 5 bytes for 'filename' charset */
- DBUG_ASSERT(sizeof(comma_buf) >= cs->mbmaxlen);
- int comma_length= cs->cset->wc_mb(cs, ',', (uchar*) comma_buf,
- (uchar*) comma_buf +
- sizeof(comma_buf));
- DBUG_ASSERT(comma_length > 0);
- for (uint i= 0; (tmp= int_it++); i++)
- {
- size_t lengthsp;
- if (String::needs_conversion(tmp->length(), tmp->charset(),
- cs, &dummy))
- {
- uint cnv_errs;
- conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
- interval->type_names[i]= strmake_root(thd->mem_root, conv.ptr(),
- conv.length());
- interval->type_lengths[i]= conv.length();
- }
-
- // Strip trailing spaces.
- lengthsp= cs->cset->lengthsp(cs, interval->type_names[i],
- interval->type_lengths[i]);
- interval->type_lengths[i]= lengthsp;
- ((uchar *)interval->type_names[i])[lengthsp]= '\0';
- if (sql_field->sql_type == MYSQL_TYPE_SET)
- {
- if (cs->coll->instr(cs, interval->type_names[i],
- interval->type_lengths[i],
- comma_buf, comma_length, NULL, 0))
- {
- ErrConvString err(tmp->ptr(), tmp->length(), cs);
- my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", err.ptr());
- DBUG_RETURN(TRUE);
- }
- }
- }
- sql_field->interval_list.empty(); // Don't need interval_list anymore
- }
-
- if (sql_field->sql_type == MYSQL_TYPE_SET)
- {
- uint32 field_length;
- calculate_interval_lengths(cs, interval, &dummy, &field_length);
- sql_field->length= field_length + (interval->count - 1);
- }
- else /* MYSQL_TYPE_ENUM */
- {
- uint32 field_length;
- DBUG_ASSERT(sql_field->sql_type == MYSQL_TYPE_ENUM);
- calculate_interval_lengths(cs, interval, &field_length, &dummy);
- sql_field->length= field_length;
- }
- set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
+ if (sql_field->prepare_interval_field(thd->mem_root, true))
+ DBUG_RETURN(true); // E.g. wrong values with commas: SET('a,b')
}
if (sql_field->sql_type == MYSQL_TYPE_BIT)
@@ -4349,28 +4252,18 @@ static bool prepare_blob_field(THD *thd, Column_definition *sql_field)
*/
-void sp_prepare_create_field(THD *thd, Column_definition *sql_field)
+bool sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root,
+ Column_definition *sql_field)
{
if (sql_field->sql_type == MYSQL_TYPE_SET ||
sql_field->sql_type == MYSQL_TYPE_ENUM)
{
- uint32 field_length, dummy;
- if (sql_field->sql_type == MYSQL_TYPE_SET)
- {
- calculate_interval_lengths(sql_field->charset,
- sql_field->interval, &dummy,
- &field_length);
- sql_field->length= field_length +
- (sql_field->interval->count - 1);
- }
- else /* MYSQL_TYPE_ENUM */
- {
- calculate_interval_lengths(sql_field->charset,
- sql_field->interval,
- &field_length, &dummy);
- sql_field->length= field_length;
- }
- set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
+ /*
+ Pass "false" as the last argument to allocate TYPELIB values on mem_root,
+ even if no character set conversion is needed.
+ */
+ if (sql_field->prepare_interval_field(mem_root, false))
+ return true; // E.g. wrong values with commas: SET('a,b')
}
if (sql_field->sql_type == MYSQL_TYPE_BIT)
@@ -4380,8 +4273,12 @@ void sp_prepare_create_field(THD *thd, Column_definition *sql_field)
}
sql_field->create_length_to_internal_length();
DBUG_ASSERT(sql_field->default_value == 0);
- /* Can't go wrong as sql_field->def is not defined */
- (void) prepare_blob_field(thd, sql_field);
+ /*
+ prepare_blob_field() can return an error on attempt to create a too long
+ VARCHAR/VARBINARY field when the current sql_mode does not allow automatic
+ conversion to TEXT/BLOB.
+ */
+ return prepare_blob_field(thd, sql_field);
}