maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #07893
Review: [MDEV-7062] parser refactoring: don't store field properties in LEX
Hi Sergei,
> Sergei Golubchik edited comment on MDEV-7062 at 11/10/14 11:40 AM:
> -------------------------------------------------------------------
>
> http://lists.askmonty.org/pipermail/commits/2014-November/006908.html
>
> {noformat}
> From: serg@xxxxxxxxxxx
> To: commits@xxxxxxxxxxx
> Subject: [Commits] 2c904b9: parser cleanup: don't store field properties
> in LEX, use Create_field directly
> Date: Mon, 10 Nov 2014 10:26:48 +0100
> {noformat}
>
Please find my comments below:
[Commits] 2c904b9: parser cleanup: don't store field properties in LEX, use Create_field directly
serg at mariadb.org serg at mariadb.org
Mon Nov 10 11:26:48 EET 2014
Previous message: [Commits] Rev 4344: MDEV-6179: dynamic columns functions/cast()/convert() doesn't play nice with CREATE/ALTER TABLE in lp:~maria-captains/maria/5.5
Next message: [Commits] Rev 4345: MDEV-6862 "#error <my_config.h>" and third-party libraries in lp:~maria-captains/maria/5.5
Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
revision-id: 2c904b937b5ef7fbec60ebb9cb514a501c5bd8e4
parent(s): f59588b9112965849986c45fcd150d9abed74063
committer: Sergei Golubchik
branch nick: maria
timestamp: 2014-11-09 22:33:17 +0100
message:
parser cleanup: don't store field properties in LEX, use Create_field directly
length/dec/charset are still in LEX, because they're also used
for CAST and dynamic columns.
also
1. fix "MDEV-7041 COLLATION(CAST('a' AS CHAR BINARY)) returns a wrong result"
2. allow BINARY modifier in stored function RETURN clause
3. allow "COLLATION without CHARSET" in SP/SF (parameters, RETURN, DECLARE)
4. print correct variable name in error messages for stored routine parameters
A very nice clean up.
I only found it a little bit not easy to track that
all Lex and Create_field attributes get initialized and copied to each
other properly.
I suggest to go a little bit further and get rid from Lex->dec,
Lex->length and Lex->charset at all, and write the attributes directly
to the destination as soon as they get parsed. See a proposed addon
patch attached.
diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result
index c81af13..8ad4568 100644
--- a/mysql-test/r/cast.result
+++ b/mysql-test/r/cast.result
@@ -796,3 +796,32 @@ DATE("foo")
NULL
Warnings:
Warning 1292 Incorrect datetime value: 'foo'
+create table t1 (a int, b char(5) as (cast("a" as char(10) binary) + a) );
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(5) AS (cast("a" as char(10) binary) + a) VIRTUAL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+select collation(cast("a" as char(10) binary));
+collation(cast("a" as char(10) binary))
+latin1_bin
+select collation(cast("a" as char(10) charset utf8 binary));
+collation(cast("a" as char(10) charset utf8 binary))
+utf8_bin
+select collation(cast("a" as char(10) ascii binary));
+collation(cast("a" as char(10) ascii binary))
+latin1_bin
+select collation(cast("a" as char(10) unicode binary));
+collation(cast("a" as char(10) unicode binary))
> +ucs2_bin
UNICODE is an alias for UCS2, which is not always compiled.
Please move ucs2 related tests to ctype_ucs.test.
<skip>
diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test
index b6c37ca..aa43ee6 100644
--- a/mysql-test/t/cast.test
+++ b/mysql-test/t/cast.test
@@ -456,3 +456,21 @@ SELECT CAST(TIME('10:20:30') AS DATE) + INTERVAL 1 DAY;
SET SQL_MODE=ALLOW_INVALID_DATES;
SELECT DATE("foo");
+#
+# CAST and field definition using same fields in LEX
+#
+create table t1 (a int, b char(5) as (cast("a" as char(10) binary) + a) );
+show create table t1;
+drop table t1;
+
+#
+# CAST (... BINARY)
+#
+select collation(cast("a" as char(10) binary));
+select collation(cast("a" as char(10) charset utf8 binary));
+select collation(cast("a" as char(10) ascii binary));
+select collation(cast("a" as char(10) unicode binary));
+select collation(cast("a" as char(10) binary charset utf8));
+select collation(cast("a" as char(10) binary ascii));
+select collation(cast("a" as char(10) binary unicode));
More UCS2.
You removed this code in field.cc:
- if (fld_length != NULL)
- {
- errno= 0;
- length= strtoul(fld_length, NULL, 10);
- if ((errno != 0) || (length > MAX_FIELD_BLOBLENGTH))
- {
- my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), fld_name, MAX_FIELD_BLOBLENGTH);
- DBUG_RETURN(TRUE);
- }
-
- if (length == 0)
- fld_length= NULL; /* purecov: inspected */
- }
and added this in sql_yacc.yy:
+ if (length)
+ {
+ int err;
+ last_field->length= (ulong)my_strtoll10(length, NULL, &err);
+ if (err)
+ last_field->length= ~0UL; // safety
+ }
+ else
+ last_field->length= 0;
I have a feeling that on a 32bit platforms it will stop sending errors
on attempt to create a blob larger that 4Gb.
last_field->length is ulong, which is 32bit is a 32 bit platform,
and it gets assigned to a 64 bit value.
diff --git a/sql/field.cc b/sql/field.cc
index a7d9106..801e191 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -9169,6 +9169,24 @@ static inline bool is_item_func(Item* x)
}
+bool Create_type_attributes_st::check(const char *field_name) const
+{
+ if (length > MAX_FIELD_BLOBLENGTH)
+ {
+ my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name, MAX_FIELD_BLOBLENGTH);
+ return true;
+ }
+
+ if (decimals >= NOT_FIXED_DEC)
+ {
+ my_error(ER_TOO_BIG_SCALE, MYF(0), decimals, field_name,
+ static_cast<ulong>(NOT_FIXED_DEC - 1));
+ return true;
+ }
+ return false;
+}
+
+
bool Create_field::check(THD *thd)
{
const uint conditional_type_modifiers= AUTO_INCREMENT_FLAG;
@@ -9182,19 +9200,8 @@ bool Create_field::check(THD *thd)
sql_type= (enum enum_field_types)MYSQL_TYPE_VIRTUAL;
}
- if (length > MAX_FIELD_BLOBLENGTH)
- {
- my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name, MAX_FIELD_BLOBLENGTH);
- DBUG_RETURN(1);
- }
-
- if (decimals >= NOT_FIXED_DEC)
- {
- my_error(ER_TOO_BIG_SCALE, MYF(0), decimals, field_name,
- static_cast<ulong>(NOT_FIXED_DEC - 1));
- DBUG_RETURN(TRUE);
- }
-
+ if (Create_type_attributes_st::check(field_name))
+ DBUG_RETURN(true);
if (def)
{
/*
@@ -9802,18 +9809,16 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length,
/** Create a field suitable for create of table. */
Create_field::Create_field(Field *old_field,Field *orig_field)
+ :Create_type_attributes(old_field)
{
field= old_field;
field_name=change=old_field->field_name;
- length= old_field->field_length;
flags= old_field->flags;
unireg_check=old_field->unireg_check;
pack_length=old_field->pack_length();
key_length= old_field->key_length();
sql_type= old_field->real_type();
- charset= old_field->charset(); // May be NULL ptr
comment= old_field->comment;
- decimals= old_field->decimals();
vcol_info= old_field->vcol_info;
create_if_not_exists= FALSE;
stored_in_db= old_field->stored_in_db;
diff --git a/sql/field.h b/sql/field.h
index fdc00ed..55998e2 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -2833,11 +2833,25 @@ class Field_bit_as_char: public Field_bit {
};
+class Create_type_attributes: public Sql_alloc,
+ public Create_type_attributes_st
+{
+public:
+ Create_type_attributes() { init(); }
+ Create_type_attributes(const char *len, const char *dec, CHARSET_INFO *cs)
+ { set(len, dec, cs); }
+ Create_type_attributes(const Field *field)
+ { set(field->field_length, field->decimals(), field->charset()); }
+ Create_type_attributes(const Create_type_attributes_st &attr)
+ { set(attr.length, attr.decimals, attr.charset); }
+};
+
+
/*
Create field class for CREATE TABLE
*/
-class Create_field :public Sql_alloc
+class Create_field :public Create_type_attributes
{
public:
const char *field_name;
@@ -2847,22 +2861,16 @@ class Create_field :public Sql_alloc
Item *def, *on_update; // Default value
enum enum_field_types sql_type;
/*
- At various stages in execution this can be length of field in bytes or
- max number of characters.
- */
- ulong length;
- /*
The value of `length' as set by parser: is the number of characters
for most of the types, or of bytes for BLOBs or numeric types.
*/
uint32 char_length;
- uint decimals, flags, pack_length, key_length;
+ uint flags, pack_length, key_length;
Field::utype unireg_check;
TYPELIB *interval; // Which interval to use
TYPELIB *save_interval; // Temporary copy for the above
// Used only for UCS2 intervals
List<String> interval_list;
- CHARSET_INFO *charset;
Field::geometry_type geom_type;
Field *field; // For alter table
engine_option_value *option_list;
diff --git a/sql/item.h b/sql/item.h
index ff0c786..7e8039f 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -593,16 +593,22 @@ class Copy_query_with_rewrite
{ return copy_up_to(src_len); }
};
-struct st_dyncall_create_def
+class DYNCALL_CREATE_DEF: public Create_type_attributes
{
+public:
+ DYNCALL_CREATE_DEF(const char *len, const char *dec, CHARSET_INFO *cs)
+ :Create_type_attributes(len, dec, cs)
+ { }
+ DYNCALL_CREATE_DEF(const Create_type_attributes_st &attr)
+ :Create_type_attributes(attr)
+ { }
+ DYNCALL_CREATE_DEF()
+ :Create_type_attributes()
+ { }
Item *key, *value;
- CHARSET_INFO *cs;
- uint len, frac;
DYNAMIC_COLUMN_TYPE type;
};
-typedef struct st_dyncall_create_def DYNCALL_CREATE_DEF;
-
typedef bool (Item::*Item_processor) (uchar *arg);
/*
diff --git a/sql/item_create.cc b/sql/item_create.cc
index fa8249c..6175bd6 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -6017,22 +6017,10 @@ void item_create_cleanup()
Item *
create_func_cast(THD *thd, Item *a, Cast_target cast_type,
- const char *c_len, const char *c_dec,
- CHARSET_INFO *cs)
+ const Create_type_attributes &attr)
{
Item *UNINIT_VAR(res);
- ulonglong length= 0, decimals= 0;
- int error;
- /*
- We don't have to check for error here as sql_yacc.yy has guaranteed
- that the values are in range of ulonglong
- */
- if (c_len)
- length= (ulonglong) my_strtoll10(c_len, NULL, &error);
- if (c_dec)
- decimals= (ulonglong) my_strtoll10(c_dec, NULL, &error);
-
switch (cast_type) {
case ITEM_CAST_BINARY:
res= new (thd->mem_root) Item_func_binary(a);
@@ -6047,28 +6035,28 @@ void item_create_cleanup()
res= new (thd->mem_root) Item_date_typecast(a);
break;
case ITEM_CAST_TIME:
- if (decimals > MAX_DATETIME_PRECISION)
+ if (attr.decimals > MAX_DATETIME_PRECISION)
{
- wrong_precision_error(ER_TOO_BIG_PRECISION, a, decimals,
+ wrong_precision_error(ER_TOO_BIG_PRECISION, a, attr.decimals,
MAX_DATETIME_PRECISION);
return 0;
}
- res= new (thd->mem_root) Item_time_typecast(a, (uint) decimals);
+ res= new (thd->mem_root) Item_time_typecast(a, (uint) attr.decimals);
break;
case ITEM_CAST_DATETIME:
- if (decimals > MAX_DATETIME_PRECISION)
+ if (attr.decimals > MAX_DATETIME_PRECISION)
{
- wrong_precision_error(ER_TOO_BIG_PRECISION, a, decimals,
+ wrong_precision_error(ER_TOO_BIG_PRECISION, a, attr.decimals,
MAX_DATETIME_PRECISION);
return 0;
}
- res= new (thd->mem_root) Item_datetime_typecast(a, (uint) decimals);
+ res= new (thd->mem_root) Item_datetime_typecast(a, (uint) attr.decimals);
break;
case ITEM_CAST_DECIMAL:
{
ulong len;
uint dec;
- if (get_length_and_scale(length, decimals, &len, &dec,
+ if (get_length_and_scale(attr.length, attr.decimals, &len, &dec,
DECIMAL_MAX_PRECISION, DECIMAL_MAX_SCALE,
a))
return NULL;
@@ -6079,8 +6067,10 @@ void item_create_cleanup()
{
ulong len;
uint dec;
+ ulonglong length= attr.length;
+ ulonglong decimals= attr.decimals;
- if (!c_len)
+ if (!attr.length && !attr.decimals)
{
length= DBL_DIG+7;
decimals= NOT_FIXED_DEC;
@@ -6096,10 +6086,11 @@ void item_create_cleanup()
case ITEM_CAST_CHAR:
{
int len= -1;
- CHARSET_INFO *real_cs= (cs ? cs : thd->variables.collation_connection);
- if (c_len)
+ CHARSET_INFO *real_cs= attr.charset ? attr.charset :
+ thd->variables.collation_connection;
+ if (attr.length_was_set_explicitly())
{
- if (length > MAX_FIELD_BLOBLENGTH)
+ if (attr.length > MAX_FIELD_BLOBLENGTH)
{
char buff[1024];
String buf(buff, sizeof(buff), system_charset_info);
@@ -6107,7 +6098,7 @@ void item_create_cleanup()
MAX_FIELD_BLOBLENGTH);
return NULL;
}
- len= (int) length;
+ len= (int) attr.length;
}
res= new (thd->mem_root) Item_char_typecast(a, len, real_cs);
break;
@@ -6281,12 +6272,11 @@ Item *create_func_dyncol_delete(THD *thd, Item *str, List<Item> &nums)
Item *create_func_dyncol_get(THD *thd, Item *str, Item *num,
Cast_target cast_type,
- const char *c_len, const char *c_dec,
- CHARSET_INFO *cs)
+ const Create_type_attributes &attr)
{
Item *res;
if (!(res= new (thd->mem_root) Item_dyncol_get(str, num)))
return res; // Return NULL
- return create_func_cast(thd, res, cast_type, c_len, c_dec, cs);
+ return create_func_cast(thd, res, cast_type, attr);
}
diff --git a/sql/item_create.h b/sql/item_create.h
index 05fe48f..efee18e 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -165,8 +165,7 @@ class Create_udf_func : public Create_func
*/
Item *
create_func_cast(THD *thd, Item *a, Cast_target cast_type,
- const char *len, const char *dec,
- CHARSET_INFO *cs);
+ const Create_type_attributes &attr);
Item *create_temporal_literal(THD *thd,
const char *str, uint length,
@@ -192,8 +191,7 @@ Item *create_func_dyncol_add(THD *thd, Item *str,
Item *create_func_dyncol_delete(THD *thd, Item *str, List<Item> &nums);
Item *create_func_dyncol_get(THD *thd, Item *num, Item *str,
Cast_target cast_type,
- const char *c_len, const char *c_dec,
- CHARSET_INFO *cs);
+ const Create_type_attributes &attr);
Item *create_func_dyncol_json(THD *thd, Item *str);
#endif
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 9a3c758..72e3c99 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -4562,10 +4562,10 @@ void Item_func_dyncol_create::print_arguments(String *str,
case DYN_COL_DYNCOL:
case DYN_COL_STRING:
str->append(STRING_WITH_LEN(" AS char"));
- if (defs[i].cs)
+ if (defs[i].charset)
{
str->append(STRING_WITH_LEN(" charset "));
- str->append(defs[i].cs->csname);
+ str->append(defs[i].charset->csname);
str->append(' ');
}
break;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 7eb38b1..62a5510 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -491,7 +491,6 @@ void lex_start(THD *thd)
lex->parsing_options.reset();
lex->empty_field_list_on_rset= 0;
lex->select_lex.select_number= 1;
- lex->length=0;
lex->part_info= 0;
lex->select_lex.in_sum_expr=0;
lex->select_lex.ftfunc_list_alloc.empty();
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 409358d..fcbda9c 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -2355,8 +2355,34 @@ struct LEX: public Query_tables_list
Explain_query *explain;
// type information
- char *length,*dec;
- CHARSET_INFO *charset;
+ Create_type_attributes *last_attr;
+ CHARSET_INFO *charset() const { return last_attr->charset; }
+ ulong length() const { return last_attr->length; }
+ uint dec() const { return last_attr->decimals; }
+ bool length_was_set_explicitly() const
+ { return last_attr->length_was_set_explicitly(); }
+
+ void init_last_attributes(CHARSET_INFO *cs= NULL) { last_attr->init(cs); }
+ void set_length(ulong length) { last_attr->set_length(length); }
+ CHARSET_INFO *set_charset(CHARSET_INFO *cs)
+ { return last_attr->charset= cs; }
+ void set_explicit_length(const char *length)
+ { last_attr->set_explicit_length(length); }
+ void set_length_and_dec(const char *length, const char *decimals)
+ {
+ last_attr->set_length(length);
+ last_attr->set_decimals(decimals);
+ }
+ void set_length_and_dec(ulong length, uint decimals)
+ {
+ last_attr->set_length(length);
+ last_attr->set_decimals(decimals);
+ }
+ void set_charset_and_dec(CHARSET_INFO *cs, const char *decimals)
+ {
+ last_attr->set_charset(cs);
+ last_attr->set_decimals(decimals);
+ }
LEX_STRING name;
char *help_arg;
@@ -2782,8 +2808,7 @@ struct LEX: public Query_tables_list
int print_explain(select_result_sink *output, uint8 explain_flags,
bool is_analyze, bool *printed_anything);
-
- void init_last_field(Create_field *field, const char *name, CHARSET_INFO *cs);
+ void init_last_field(Create_field *field, const char *name);
void set_last_field_type(enum enum_field_types type);
bool set_bincmp(CHARSET_INFO *cs, bool bin);
};
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 7b36d39..ff75b63 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -871,9 +871,10 @@ static void add_key_to_list(LEX *lex, LEX_STRING *field_name,
lex->col_list.empty();
}
-void LEX::init_last_field(Create_field *field, const char *name, CHARSET_INFO *cs)
+void LEX::init_last_field(Create_field *field, const char *name)
{
last_field= field;
+ last_attr= field;
field->field_name= name;
field->flags= 0;
@@ -885,30 +886,12 @@ void LEX::init_last_field(Create_field *field, const char *name, CHARSET_INFO *c
field->comment= null_lex_str;
field->vcol_info= 0;
field->interval_list.empty();
-
- /* reset LEX fields that are used in Create_field::set_and_check() */
- length= 0;
- dec= 0;
- charset= cs;
}
void LEX::set_last_field_type(enum enum_field_types type)
{
last_field->sql_type= type;
last_field->create_if_not_exists= check_exists;
- last_field->charset= charset;
-
- if (length)
- {
- int err;
- last_field->length= (ulong)my_strtoll10(length, NULL, &err);
- if (err)
- last_field->length= ~0UL; // safety
- }
- else
- last_field->length= 0;
-
- last_field->decimals= dec ? (uint)atoi(dec) : 0;
}
bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin)
@@ -919,16 +902,16 @@ bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin)
field charset is determined in get_sql_field_charset() much later.
so we only set a flag here.
*/
- if (!charset)
+ if (!charset())
{
- charset= cs;
+ set_charset(cs);
last_field->flags|= bin ? BINCMP_FLAG : 0;
return false;
}
- charset= bin ? find_bin_collation(cs ? cs : charset)
- : cs ? cs : charset;
- return charset == NULL;
+ set_charset(bin ? find_bin_collation(cs ? cs : charset())
+ : cs ? cs : charset());
+ return charset() == NULL;
}
#define bincmp_collation(X,Y) \
@@ -1836,7 +1819,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <ha_rkey_mode> handler_rkey_mode
-%type <cast_type> cast_type
+%type <cast_type> cast_type create_new_cast_type
%type <symbol> keyword keyword_sp
@@ -2904,9 +2887,8 @@ sp_param_name_and_type:
}
sp_variable *spvar= spc->add_variable(thd, $1);
-
- lex->init_last_field(&spvar->field_def, $1.str,
- thd->variables.collation_database);
+ lex->init_last_field(&spvar->field_def, $1.str);
+ lex->init_last_attributes(thd->variables.collation_database);
$<spvar>$= spvar;
}
type_with_opt_collate
@@ -3002,8 +2984,8 @@ sp_decl:
lex->sphead->reset_lex(thd);
pctx->declare_var_boundary($2);
- thd->lex->init_last_field(&spvar->field_def, spvar->name.str,
- thd->variables.collation_database);
+ thd->lex->init_last_field(&spvar->field_def, spvar->name.str);
+ thd->lex->init_last_attributes(thd->variables.collation_database);
}
type_with_opt_collate
sp_opt_default
@@ -6071,7 +6053,7 @@ field_spec:
if (!f)
MYSQL_YYABORT;
- lex->init_last_field(f, $1.str, NULL);
+ lex->init_last_field(f, $1.str);
}
field_type { Lex->set_last_field_type($3); }
field_def
@@ -6183,24 +6165,22 @@ field_type:
| FLOAT_SYM float_options field_options
{
$$=MYSQL_TYPE_FLOAT;
- if (Lex->length && !Lex->dec)
+ if (Lex->length_was_set_explicitly() && !Lex->dec())
{
- int err;
- ulonglong tmp_length= my_strtoll10(Lex->length, NULL, &err);
- if (err || tmp_length > PRECISION_FOR_DOUBLE)
+ if (Lex->length() > PRECISION_FOR_DOUBLE)
{
my_error(ER_WRONG_FIELD_SPEC, MYF(0),
Lex->last_field->field_name);
MYSQL_YYABORT;
}
- else if (tmp_length > PRECISION_FOR_FLOAT)
+ else if (Lex->length() > PRECISION_FOR_FLOAT)
$$= MYSQL_TYPE_DOUBLE;
- Lex->length= 0;
+ Lex->set_length(0);
}
}
| BIT_SYM
{
- Lex->length= (char*) "1";
+ Lex->set_length(1);
$$=MYSQL_TYPE_BIT;
}
| BIT_SYM field_length
@@ -6209,12 +6189,12 @@ field_type:
}
| BOOL_SYM
{
- Lex->length= (char*) "1";
+ Lex->set_length(1);
$$=MYSQL_TYPE_TINY;
}
| BOOLEAN_SYM
{
- Lex->length= (char*) "1";
+ Lex->set_length(1);
$$=MYSQL_TYPE_TINY;
}
| char field_length opt_binary
@@ -6223,7 +6203,7 @@ field_type:
}
| char opt_binary
{
- Lex->length= (char*) "1";
+ Lex->set_length(1);
$$=MYSQL_TYPE_STRING;
}
| nchar field_length opt_bin_mod
@@ -6233,19 +6213,19 @@ field_type:
}
| nchar opt_bin_mod
{
- Lex->length= (char*) "1";
+ Lex->set_length(1);
$$=MYSQL_TYPE_STRING;
bincmp_collation(national_charset_info, $2);
}
| BINARY field_length
{
- Lex->charset=&my_charset_bin;
+ Lex->set_charset(&my_charset_bin);
$$=MYSQL_TYPE_STRING;
}
| BINARY
{
- Lex->length= (char*) "1";
- Lex->charset=&my_charset_bin;
+ Lex->set_length(1);
+ Lex->set_charset(&my_charset_bin);
$$=MYSQL_TYPE_STRING;
}
| varchar field_length opt_binary
@@ -6259,19 +6239,17 @@ field_type:
}
| VARBINARY field_length
{
- Lex->charset=&my_charset_bin;
+ Lex->set_charset(&my_charset_bin);
$$= MYSQL_TYPE_VARCHAR;
}
| YEAR_SYM opt_field_length field_options
{
- if (Lex->length)
+ if (Lex->length_was_set_explicitly())
{
- errno= 0;
- ulong length= strtoul(Lex->length, NULL, 10);
- if (errno == 0 && length <= MAX_FIELD_BLOBLENGTH && length != 4)
+ if (Lex->length() <= MAX_FIELD_BLOBLENGTH && Lex->length() != 4)
{
char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1];
- my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length);
+ my_snprintf(buff, sizeof(buff), "YEAR(%lu)", Lex->length());
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_WARN_DEPRECATED_SYNTAX,
ER(ER_WARN_DEPRECATED_SYNTAX),
@@ -6305,18 +6283,18 @@ field_type:
MYSQL_TYPE_DATETIME2 : MYSQL_TYPE_DATETIME; }
| TINYBLOB
{
- Lex->charset=&my_charset_bin;
+ Lex->set_charset(&my_charset_bin);
$$=MYSQL_TYPE_TINY_BLOB;
}
| BLOB_SYM opt_field_length
{
- Lex->charset=&my_charset_bin;
+ Lex->set_charset(&my_charset_bin);
$$=MYSQL_TYPE_BLOB;
}
| spatial_type
{
#ifdef HAVE_SPATIAL
- Lex->charset=&my_charset_bin;
+ Lex->set_charset(&my_charset_bin);
Lex->last_field->geom_type= $1;
$$=MYSQL_TYPE_GEOMETRY;
#else
@@ -6327,17 +6305,17 @@ field_type:
}
| MEDIUMBLOB
{
- Lex->charset=&my_charset_bin;
+ Lex->set_charset(&my_charset_bin);
$$=MYSQL_TYPE_MEDIUM_BLOB;
}
| LONGBLOB
{
- Lex->charset=&my_charset_bin;
+ Lex->set_charset(&my_charset_bin);
$$=MYSQL_TYPE_LONG_BLOB;
}
| LONG_SYM VARBINARY
{
- Lex->charset=&my_charset_bin;
+ Lex->set_charset(&my_charset_bin);
$$=MYSQL_TYPE_MEDIUM_BLOB;
}
| LONG_SYM varchar opt_binary
@@ -6375,8 +6353,7 @@ spatial_type:
| GEOMETRYCOLLECTION { $$= Field::GEOM_GEOMETRYCOLLECTION; }
| POINT_SYM
{
- Lex->length= const_cast<char*>(STRINGIFY_ARG
- (MAX_LEN_GEOM_POINT_FIELD));
+ Lex->set_length(MAX_LEN_GEOM_POINT_FIELD);
$$= Field::GEOM_POINT;
}
| MULTIPOINT { $$= Field::GEOM_MULTIPOINT; }
@@ -6430,9 +6407,9 @@ real_type:
float_options:
/* empty */
- { Lex->dec=Lex->length= (char*)0; }
+ { }
| field_length
- { Lex->dec= (char*)0; }
+ { }
| precision
{}
;
@@ -6440,9 +6417,7 @@ float_options:
precision:
'(' NUM ',' NUM ')'
{
- LEX *lex=Lex;
- lex->length=$2.str;
- lex->dec=$4.str;
+ Lex->set_length_and_dec($2.str, $4.str);
}
;
@@ -6463,13 +6438,13 @@ field_option:
;
field_length:
- '(' LONG_NUM ')' { Lex->length= $2.str; }
- | '(' ULONGLONG_NUM ')' { Lex->length= $2.str; }
- | '(' DECIMAL_NUM ')' { Lex->length= $2.str; }
- | '(' NUM ')' { Lex->length= $2.str; };
+ '(' LONG_NUM ')' { Lex->set_explicit_length($2.str); }
+ | '(' ULONGLONG_NUM ')' { Lex->set_explicit_length($2.str); }
+ | '(' DECIMAL_NUM ')' { Lex->set_explicit_length($2.str); }
+ | '(' NUM ')' { Lex->set_explicit_length($2.str); };
opt_field_length:
- /* empty */ { Lex->length=(char*) 0; /* use default length */ }
+ /* empty */ { /* use default length */ }
| field_length { }
;
@@ -6527,10 +6502,10 @@ attribute:
| COMMENT_SYM TEXT_STRING_sys { Lex->last_field->comment= $2; }
| COLLATE_SYM collation_name
{
- if (Lex->charset && !my_charset_same(Lex->charset,$2))
+ if (Lex->charset() && !my_charset_same(Lex->charset(), $2))
{
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
- $2->name,Lex->charset->csname);
+ $2->name, Lex->charset()->csname);
MYSQL_YYABORT;
}
else
@@ -6571,7 +6546,7 @@ type_with_opt_collate:
if ($2)
{
- if (!(Lex->charset= merge_charset_and_collation(Lex->charset, $2)))
+ if (!(Lex->set_charset(merge_charset_and_collation(Lex->charset(), $2))))
MYSQL_YYABORT;
}
Lex->set_last_field_type($1);
@@ -9006,117 +8981,54 @@ all_or_any:
;
opt_dyncol_type:
- /* empty */
- {
- LEX *lex= Lex;
- $$= DYN_COL_NULL; /* automatic type */
- lex->charset= NULL;
- lex->length= lex->dec= 0;
- }
+ /* empty */ { $$= DYN_COL_NULL; } /* automatic type */
| AS dyncol_type { $$= $2; }
;
dyncol_type:
- INT_SYM
- {
- LEX *lex= Lex;
- $$= DYN_COL_INT;
- lex->charset= NULL;
- lex->length= lex->dec= 0;
- }
- | UNSIGNED INT_SYM
- {
- LEX *lex= Lex;
- $$= DYN_COL_UINT;
- lex->charset= NULL;
- lex->length= lex->dec= 0;
- }
- | DOUBLE_SYM
- {
- LEX *lex= Lex;
- $$= DYN_COL_DOUBLE;
- lex->charset= NULL;
- lex->length= lex->dec= 0;
- }
- | REAL
- {
- LEX *lex= Lex;
- $$= DYN_COL_DOUBLE;
- lex->charset= NULL;
- lex->length= lex->dec= 0;
- }
- | FLOAT_SYM
- {
- LEX *lex= Lex;
- $$= DYN_COL_DOUBLE;
- lex->charset= NULL;
- lex->length= lex->dec= 0;
- }
- | DECIMAL_SYM float_options
- {
- $$= DYN_COL_DECIMAL;
- Lex->charset= NULL;
- }
+ INT_SYM { $$= DYN_COL_INT; }
+ | UNSIGNED INT_SYM { $$= DYN_COL_UINT; }
+ | DOUBLE_SYM { $$= DYN_COL_DOUBLE; }
+ | REAL { $$= DYN_COL_DOUBLE; }
+ | FLOAT_SYM { $$= DYN_COL_DOUBLE; }
+ | DECIMAL_SYM float_options { $$= DYN_COL_DECIMAL; }
+ | DATE_SYM { $$= DYN_COL_DATE; }
| char
- { Lex->charset= thd->variables.collation_connection; }
+ { Lex->set_charset(thd->variables.collation_connection); }
opt_binary
{
- LEX *lex= Lex;
$$= DYN_COL_STRING;
- lex->length= lex->dec= 0;
}
| nchar
{
- LEX *lex= Lex;
$$= DYN_COL_STRING;
- lex->charset= national_charset_info;
- lex->length= lex->dec= 0;
- }
- | DATE_SYM
- {
- LEX *lex= Lex;
- $$= DYN_COL_DATE;
- lex->charset= NULL;
- lex->length= lex->dec= 0;
+ Lex->set_charset(national_charset_info);
}
| TIME_SYM opt_field_length
{
- LEX *lex= Lex;
$$= DYN_COL_TIME;
- lex->charset= NULL;
- lex->dec= lex->length;
- lex->length= 0;
+ Lex->set_length_and_dec(0, Lex->length()); // Move length to dec
}
| DATETIME opt_field_length
{
- LEX *lex= Lex;
$$= DYN_COL_DATETIME;
- lex->charset= NULL;
- lex->dec= lex->length;
- lex->length= 0;
+ Lex->set_length_and_dec(0, Lex->length()); // Move length to dec
}
;
dyncall_create_element:
- expr ',' expr opt_dyncol_type
+ expr ',' expr
{
- LEX *lex= Lex;
- $$= (DYNCALL_CREATE_DEF *)
- alloc_root(thd->mem_root, sizeof(DYNCALL_CREATE_DEF));
- if ($$ == NULL)
+ if (!(Lex->last_attr= new DYNCALL_CREATE_DEF()))
MYSQL_YYABORT;
+ }
+ opt_dyncol_type
+ {
+ LEX *lex= Lex;
+ $$= (DYNCALL_CREATE_DEF*) lex->last_attr;
$$->key= $1;
$$->value= $3;
- $$->type= (DYNAMIC_COLUMN_TYPE)$4;
- $$->cs= lex->charset;
- if (lex->length)
- $$->len= strtoul(lex->length, NULL, 10);
- else
- $$->len= 0;
- if (lex->dec)
- $$->frac= strtoul(lex->dec, NULL, 10);
- else
- $$->len= 0;
+ $$->type= (DYNAMIC_COLUMN_TYPE)$5;
}
dyncall_create_list:
@@ -9246,16 +9158,15 @@ simple_expr:
}
| BINARY simple_expr %prec NEG
{
- $$= create_func_cast(thd, $2, ITEM_CAST_CHAR, NULL, NULL,
- &my_charset_bin);
+ $$= create_func_cast(thd, $2, ITEM_CAST_CHAR,
+ Create_type_attributes(NULL, NULL, &my_charset_bin));
if ($$ == NULL)
MYSQL_YYABORT;
}
- | CAST_SYM '(' expr AS cast_type ')'
+ | CAST_SYM '(' expr AS create_new_cast_type ')'
{
LEX *lex= Lex;
- $$= create_func_cast(thd, $3, $5, lex->length, lex->dec,
- lex->charset);
+ $$= create_func_cast(thd, $3, $5, lex->last_attr[0]);
if ($$ == NULL)
MYSQL_YYABORT;
}
@@ -9265,10 +9176,9 @@ simple_expr:
if ($$ == NULL)
MYSQL_YYABORT;
}
- | CONVERT_SYM '(' expr ',' cast_type ')'
+ | CONVERT_SYM '(' expr ',' create_new_cast_type ')'
{
- $$= create_func_cast(thd, $3, $5, Lex->length, Lex->dec,
- Lex->charset);
+ $$= create_func_cast(thd, $3, $5, Lex->last_attr[0]);
if ($$ == NULL)
MYSQL_YYABORT;
}
@@ -9700,12 +9610,10 @@ function_call_nonkeyword:
MYSQL_YYABORT;
}
|
- COLUMN_GET_SYM '(' expr ',' expr AS cast_type ')'
+ COLUMN_GET_SYM '(' expr ',' expr AS create_new_cast_type ')'
{
LEX *lex= Lex;
- $$= create_func_dyncol_get(thd, $3, $5, $7,
- lex->length, lex->dec,
- lex->charset);
+ $$= create_func_dyncol_get(thd, $3, $5, $7, lex->last_attr[0]);
if ($$ == NULL)
MYSQL_YYABORT;
}
@@ -10374,45 +10282,39 @@ in_sum_expr:
}
;
+create_new_cast_type:
+ /* Empty*/ { Lex->last_attr= new Create_type_attributes(); }
+ cast_type { $$= $2; }
+ ;
+
cast_type:
BINARY opt_field_length
- { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; Lex->dec= 0; }
+ { $$=ITEM_CAST_CHAR; Lex->set_charset(&my_charset_bin); }
| CHAR_SYM opt_field_length
- { Lex->charset= thd->variables.collation_connection; }
- opt_binary
- { $$=ITEM_CAST_CHAR; Lex->dec= 0; }
+ { Lex->set_charset(thd->variables.collation_connection); }
+ opt_binary { $$=ITEM_CAST_CHAR; }
| NCHAR_SYM opt_field_length
- { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; }
- | INT_SYM
- { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
- | SIGNED_SYM
- { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
- | SIGNED_SYM INT_SYM
- { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
- | UNSIGNED
- { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
- | UNSIGNED INT_SYM
- { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
- | DATE_SYM
- { $$=ITEM_CAST_DATE; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ { $$=ITEM_CAST_CHAR; Lex->set_charset_and_dec(national_charset_info, 0); }
+ | INT_SYM { $$=ITEM_CAST_SIGNED_INT; }
+ | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; }
+ | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; }
+ | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; }
+ | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; }
+ | DATE_SYM { $$=ITEM_CAST_DATE; }
| TIME_SYM opt_field_length
{
$$=ITEM_CAST_TIME;
LEX *lex= Lex;
- lex->charset= NULL; lex->dec= lex->length; lex->length= (char*)0;
+ lex->set_length_and_dec(0, lex->length());
}
| DATETIME opt_field_length
{
$$=ITEM_CAST_DATETIME;
LEX *lex= Lex;
- lex->charset= NULL; lex->dec= lex->length; lex->length= (char*)0;
+ lex->set_length_and_dec(0, lex->length()); // Swap dec and length
}
- | DECIMAL_SYM float_options
- { $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; }
- | DOUBLE_SYM
- { Lex->charset= NULL; Lex->length= Lex->dec= 0;}
- opt_precision
- { $$=ITEM_CAST_DOUBLE; }
+ | DECIMAL_SYM float_options { $$=ITEM_CAST_DECIMAL; }
+ | DOUBLE_SYM opt_precision { $$=ITEM_CAST_DOUBLE; }
opt_expr_list:
/* empty */ { $$= NULL; }
@@ -16184,8 +16086,8 @@ sf_tail:
RETURNS_SYM /* $9 */
{ /* $10 */
LEX *lex= Lex;
- lex->init_last_field(&lex->sphead->m_return_field_def, NULL,
- thd->variables.collation_database);
+ lex->init_last_field(&lex->sphead->m_return_field_def, NULL);
+ lex->init_last_attributes(thd->variables.collation_database);
}
type_with_opt_collate /* $11 */
{ /* $12 */
diff --git a/sql/structs.h b/sql/structs.h
index 99561c5..20af8e0 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -471,4 +471,72 @@ class Discrete_intervals_list {
Discrete_interval* get_current() const { return current; };
};
+
+struct Create_type_attributes_st
+{
+ bool m_length_was_set_explicitly;
+public:
+ /*
+ When in Create_field:
+ At various stages in execution this can be length of field in bytes or
+ max number of characters.
+ */
+ ulong length;
+ uint decimals;
+ CHARSET_INFO *charset;
+
+ bool length_was_set_explicitly() const
+ { return m_length_was_set_explicitly; }
+
+ void init(CHARSET_INFO *cs= NULL)
+ {
+ charset= cs;
+ length= 0;
+ decimals= 0;
+ m_length_was_set_explicitly= false;
+ }
+ bool check(const char *field_name) const;
+ void set_charset(CHARSET_INFO *cs) { charset= cs; }
+ void set_decimals(uint dec) { decimals= dec; }
+ void set_decimals(const char *dec) { decimals= dec ? (uint) atoi(dec) : 0; }
+ void set_length(const char *length_arg)
+ {
+ if (length_arg)
+ {
+ int err;
+ length= (ulong)my_strtoll10(length_arg, NULL, &err);
+ if (err)
+ length= ~0UL; // safety
+ }
+ else
+ length= 0;
+ m_length_was_set_explicitly= false;
+ }
+ void set(const char *length_arg, const char *dec_arg, CHARSET_INFO *cs)
+ {
+ charset= cs;
+ set_length(length_arg);
+ set_decimals(dec_arg);
+ m_length_was_set_explicitly= length_arg != NULL;
+ }
+ void set(ulong length_arg, uint dec_arg, CHARSET_INFO *cs)
+ {
+ charset= cs;
+ set_length(length_arg);
+ set_decimals(dec_arg);
+ m_length_was_set_explicitly= false;
+ }
+ void set_explicit_length(const char *length)
+ {
+ set_length(length);
+ m_length_was_set_explicitly= true;
+ }
+ void set_length(ulong length_arg)
+ {
+ length= length_arg;
+ m_length_was_set_explicitly= false;
+ }
+};
+
+
#endif /* STRUCTS_INCLUDED */
Follow ups