Commit 1c1d8fe9 authored by Alexander Barkov's avatar Alexander Barkov

Moving LEX::set_last_field_type() to Column_definition::set_attributes()

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.
parent 6be67860
......@@ -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.
*/
......@@ -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;
......
......@@ -3800,9 +3800,10 @@ 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)
{
......@@ -3810,7 +3811,9 @@ class Column_definition: public Sql_alloc
}
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".
......@@ -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)
{
......@@ -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);
......
......@@ -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);
......
......@@ -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)
{
......@@ -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;
......@@ -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);
}
;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment