Skip to content

Commit

Permalink
Moving LEX::set_last_field_type() to Column_definition::set_attributes()
Browse files Browse the repository at this point in the history
This is an extraction from the patch for MDEV-10577, which is not
directly related to %TYPE implementation. This patch does the following:
- Moves LEX::set_last_field_type() to Column_definition::set_attributes()
- Adds initialization of Column_definition members length, decimals,
  charset, on_update into the constructor.
- Column_definition::set_attributes() now does not set length and decimal
  to 0 any more, as they are not initialized in the constructor.
- Move Column_definition::prepare_interval_field() from field.h to field.cc,
  as it's too huge.
  • Loading branch information
Alexander Barkov committed Dec 16, 2016
1 parent 6be6786 commit 1c1d8fe
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 55 deletions.
79 changes: 79 additions & 0 deletions sql/field.cc
Expand Up @@ -9801,6 +9801,84 @@ bool Column_definition::create_interval_from_interval_list(MEM_ROOT *mem_root,
}


bool Column_definition::prepare_interval_field(MEM_ROOT *mem_root,
bool reuse_interval_list_values)
{
DBUG_ENTER("Column_definition::prepare_interval_field");
DBUG_ASSERT(sql_type == MYSQL_TYPE_ENUM || sql_type == MYSQL_TYPE_SET);
/*
Interval values are either in "interval" or in "interval_list",
but not in both at the same time, and are not empty at the same time.
- Values are in "interval_list" when we're coming from the parser
in CREATE TABLE or in CREATE {FUNCTION|PROCEDURE}.
- Values are in "interval" when we're in ALTER TABLE.
In a corner case with an empty set like SET(''):
- after the parser we have interval_list.elements==1
- in ALTER TABLE we have a non-NULL interval with interval->count==1,
with interval->type_names[0]=="" and interval->type_lengths[0]==0.
So the assert is still valid for this corner case.
ENUM and SET with no values at all (e.g. ENUM(), SET()) are not possible,
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.
*/
DBUG_ASSERT((interval == NULL) == (interval_list.elements > 0));

/*
Create typelib from interval_list, and if necessary
convert strings from client character set to the
column character set.
*/
if (interval_list.elements &&
create_interval_from_interval_list(mem_root,
reuse_interval_list_values))
DBUG_RETURN(true);

if (!reuse_interval_list_values)
{
/*
We're initializing from an existing table or view Field_enum
(e.g. for a %TYPE variable) rather than from the parser.
The constructor Column_definition(THD*,Field*,Field*) has already
copied the TYPELIB pointer from the original Field_enum.
Now we need to make a permanent copy of that TYPELIB,
as the original field can be freed before the end of the life
cycle of "this".
*/
DBUG_ASSERT(interval);
if (!(interval= copy_typelib(mem_root, interval)))
DBUG_RETURN(true);
}
prepare_interval_field_calc_length();
DBUG_RETURN(false);
}


void Column_definition::set_attributes(const Lex_field_type_st &type,
CHARSET_INFO *cs)
{
DBUG_ASSERT(sql_type == MYSQL_TYPE_NULL);
DBUG_ASSERT(charset == &my_charset_bin || charset == NULL);
DBUG_ASSERT(length == 0);
DBUG_ASSERT(decimals == 0);

sql_type= type.field_type();
charset= cs;

if (type.length())
{
int err;
length= my_strtoll10(type.length(), NULL, &err);
if (err)
length= ~0ULL; // safety
}

if (type.dec())
decimals= (uint) atoi(type.dec());
}


/**
Convert create_field::length from number of characters to number of bytes.
*/
Expand Down Expand Up @@ -10540,6 +10618,7 @@ Field *make_field(TABLE_SHARE *share,
Column_definition::Column_definition(THD *thd, Field *old_field,
Field *orig_field)
{
on_update= NULL;
field_name= old_field->field_name;
length= old_field->field_length;
flags= old_field->flags;
Expand Down
43 changes: 8 additions & 35 deletions sql/field.h
Expand Up @@ -3800,17 +3800,20 @@ class Column_definition: public Sql_alloc

Column_definition():
comment(null_lex_str),
on_update(0), sql_type(MYSQL_TYPE_NULL),
on_update(NULL), sql_type(MYSQL_TYPE_NULL), length(0), decimals(0),
flags(0), pack_length(0), key_length(0), unireg_check(Field::NONE),
interval(0), srid(0), geom_type(Field::GEOM_GEOMETRY),
interval(0), charset(&my_charset_bin),
srid(0), geom_type(Field::GEOM_GEOMETRY),
option_list(NULL),
vcol_info(0), default_value(0), check_constraint(0)
{
interval_list.empty();
}

Column_definition(THD *thd, Field *field, Field *orig_field);
void set_attributes(const Lex_field_type_st &type, CHARSET_INFO *cs);
void create_length_to_internal_length(void);

/**
Prepare a SET/ENUM field.
Create "interval" from "interval_list" if needed, and adjust "length".
Expand All @@ -3823,39 +3826,10 @@ class Column_definition: public Sql_alloc
is not needed
*/
bool prepare_interval_field(MEM_ROOT *mem_root,
bool reuse_interval_list_values)
{
DBUG_ENTER("Column_definition::prepare_interval_field");
DBUG_ASSERT(sql_type == MYSQL_TYPE_ENUM || sql_type == MYSQL_TYPE_SET);
/*
Interval values are either in "interval" or in "interval_list",
but not in both at the same time, and are not empty at the same time.
- Values are in "interval_list" when we're coming from the parser
in CREATE TABLE or in CREATE {FUNCTION|PROCEDURE}.
- Values are in "interval" when we're in ALTER TABLE.
In a corner case with an empty set like SET(''):
- after the parser we have interval_list.elements==1
- in ALTER TABLE we have a non-NULL interval with interval->count==1,
with interval->type_names[0]=="" and interval->type_lengths[0]==0.
So the assert is still valid for this corner case.
ENUM and SET with no values at all (e.g. ENUM(), SET()) are not possible,
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.
*/
DBUG_ASSERT((interval == NULL) == (interval_list.elements > 0));

/*
Create typelib from interval_list, and if necessary
convert strings from client character set to the
column character set.
*/
if (interval_list.elements &&
create_interval_from_interval_list(mem_root,
reuse_interval_list_values))
DBUG_RETURN(true);
bool reuse_interval_list_values);

void prepare_interval_field_calc_length()
{
uint32 field_length, dummy;
if (sql_type == MYSQL_TYPE_SET)
{
Expand All @@ -3868,7 +3842,6 @@ class Column_definition: public Sql_alloc
length= field_length;
}
set_if_smaller(length, MAX_FIELD_WIDTH - 1);
DBUG_RETURN(false);
}

bool prepare_blob_field(THD *thd);
Expand Down
1 change: 0 additions & 1 deletion sql/sql_lex.h
Expand Up @@ -2995,7 +2995,6 @@ struct LEX: public Query_tables_list
void restore_set_statement_var();

void init_last_field(Column_definition *field, const char *name, CHARSET_INFO *cs);
void set_last_field_type(const Lex_field_type_st &type);
bool set_bincmp(CHARSET_INFO *cs, bool bin);

bool get_dynamic_sql_string(LEX_CSTRING *dst, String *buffer);
Expand Down
21 changes: 2 additions & 19 deletions sql/sql_yacc.yy
Expand Up @@ -833,23 +833,6 @@ void LEX::init_last_field(Column_definition *field, const char *field_name,
charset= cs;
}

void LEX::set_last_field_type(const Lex_field_type_st &type)
{
last_field->sql_type= type.field_type();
last_field->charset= charset;

if (type.length())
{
int err;
last_field->length= my_strtoll10(type.length(), NULL, &err);
if (err)
last_field->length= ~0ULL; // safety
}
else
last_field->length= 0;

last_field->decimals= type.dec() ? (uint)atoi(type.dec()) : 0;
}

bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin)
{
Expand Down Expand Up @@ -6109,7 +6092,7 @@ field_spec:
lex->init_last_field(f, $1.str, NULL);
$<create_field>$= f;
}
field_type { Lex->set_last_field_type($3); }
field_type { Lex->last_field->set_attributes($3, Lex->charset); }
field_def
{
LEX *lex=Lex;
Expand Down Expand Up @@ -6615,7 +6598,7 @@ type_with_opt_collate:
if (!(Lex->charset= merge_charset_and_collation(Lex->charset, $2)))
MYSQL_YYABORT;
}
Lex->set_last_field_type($1);
Lex->last_field->set_attributes($1, Lex->charset);
}
;

Expand Down

0 comments on commit 1c1d8fe

Please sign in to comment.