Commit 5d0122bd authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-7113 difference between check_vcol_func_processor and check_partition_func_processor

MDEV-6789 segfault in Item_func_from_unixtime::get_date on updating table with virtual columns

* prohibit VALUES in partitioning expression
* prohibit user and system variables in virtual column expressions
* fix Item_func_date_format to cache locale (for %M/%W to return the same as MONTHNAME/DAYNAME)
* fix Item_func_from_unixtime to cache time_zone directly, not THD (and not to crash)
* added tests for other incorrectly allowed (in vcols) functions to see that they don't crash
parent 84f25c25
...@@ -1754,3 +1754,8 @@ PARTITION pmax VALUES LESS THAN MAXVALUE); ...@@ -1754,3 +1754,8 @@ PARTITION pmax VALUES LESS THAN MAXVALUE);
ERROR HY000: Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed ERROR HY000: Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed
DROP TABLE t1; DROP TABLE t1;
End of 5.1 tests End of 5.1 tests
create table t1 (a int) partition by list (values(a) div 1) (partition p0 values in (0), partition p1 values in (1));
ERROR HY000: This partition function is not allowed
create table t1 (a int) partition by list (uuid_short()) (partition p0 values in (0), partition p1 values in (1));
ERROR 42000: Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed near ') (partition p0 values in (0), partition p1 values in (1))' at line 1
End of 5.5 tests
set lc_time_names = 'es_MX';
set time_zone='+10:00';
set div_precision_increment=20;
create table t1 (a int, b int, v decimal(20,19) as (a/3));
create table t2 (a int, b int, v int as (a+@a));
ERROR HY000: Function or expression is not allowed for column 'v'
create table t3 (a int, b int, v int as (a+@@error_count));
ERROR HY000: Function or expression is not allowed for column 'v'
create table t4 (a int, b int, v int as (@a:=a));
ERROR HY000: Function or expression is not allowed for column 'v'
create table t5 (a int, b int, v varchar(100) as (monthname(a)));
create table t6 (a int, b int, v varchar(100) as (dayname(a)));
create table t7 (a int, b int, v varchar(100) as (date_format(a, '%W %a %M %b')));
create table t8 (a int, b int, v varchar(100) as (from_unixtime(a)));
insert t1 (a,b) values (1,2);
insert t5 (a,b) values (20141010,2);
insert t6 (a,b) values (20141010,2);
insert t7 (a,b) values (20141010,2);
insert t8 (a,b) values (1234567890,2);
select * from t1;
a b v
1 2 0.3333333333333333333
select * from t5;
a b v
20141010 2 octubre
select * from t6;
a b v
20141010 2 viernes
select * from t7;
a b v
20141010 2 viernes vie octubre oct
select * from t8;
a b v
1234567890 2 2009-02-14 09:31:30
set time_zone='+1:00';
select * from t1;
a b v
1 2 0.3333333333333333333
select * from t5;
a b v
20141010 2 octubre
select * from t6;
a b v
20141010 2 viernes
select * from t7;
a b v
20141010 2 viernes vie octubre oct
select * from t8;
a b v
1234567890 2 2009-02-14 09:31:30
flush tables;
select * from t1;
a b v
1 2 0.3333333330000000000
select * from t5;
a b v
20141010 2 October
select * from t6;
a b v
20141010 2 Friday
select * from t7;
a b v
20141010 2 Friday Fri October Oct
select * from t8;
a b v
1234567890 2 2009-02-14 00:31:30
drop table t1, t5, t6, t7, t8;
#
# MDEV-7113 difference between check_vcol_func_processor and check_partition_func_processor
#
# the following functions must not be supported in virtual columns.
# but for compatibility reasons it won't be done in a GA version,
# we'll only fix most critical issues (inconsistent results, crashes)
connect (con1, localhost, root);
set lc_time_names = 'es_MX';
set time_zone='+10:00';
set div_precision_increment=20;
create table t1 (a int, b int, v decimal(20,19) as (a/3));
--error ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED
create table t2 (a int, b int, v int as (a+@a));
--error ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED
create table t3 (a int, b int, v int as (a+@@error_count));
--error ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED
create table t4 (a int, b int, v int as (@a:=a));
create table t5 (a int, b int, v varchar(100) as (monthname(a)));
create table t6 (a int, b int, v varchar(100) as (dayname(a)));
create table t7 (a int, b int, v varchar(100) as (date_format(a, '%W %a %M %b')));
create table t8 (a int, b int, v varchar(100) as (from_unixtime(a)));
insert t1 (a,b) values (1,2);
insert t5 (a,b) values (20141010,2);
insert t6 (a,b) values (20141010,2);
insert t7 (a,b) values (20141010,2);
insert t8 (a,b) values (1234567890,2);
select * from t1;
select * from t5;
select * from t6;
select * from t7;
select * from t8;
disconnect con1;
connection default;
set time_zone='+1:00';
select * from t1;
select * from t5;
select * from t6;
select * from t7;
select * from t8;
flush tables;
select * from t1;
select * from t5;
select * from t6;
select * from t7;
select * from t8;
drop table t1, t5, t6, t7, t8;
...@@ -2005,3 +2005,14 @@ PARTITION pmax VALUES LESS THAN MAXVALUE); ...@@ -2005,3 +2005,14 @@ PARTITION pmax VALUES LESS THAN MAXVALUE);
DROP TABLE t1; DROP TABLE t1;
--echo End of 5.1 tests --echo End of 5.1 tests
#
# MDEV-7113 difference between check_vcol_func_processor and check_partition_func_processor
#
--error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
create table t1 (a int) partition by list (values(a) div 1) (partition p0 values in (0), partition p1 values in (1));
--error ER_PARSE_ERROR
create table t1 (a int) partition by list (uuid_short()) (partition p0 values in (0), partition p1 values in (1));
--echo End of 5.5 tests
...@@ -3939,6 +3939,7 @@ class Item_insert_value : public Item_field ...@@ -3939,6 +3939,7 @@ class Item_insert_value : public Item_field
return arg->walk(processor, walk_subquery, args) || return arg->walk(processor, walk_subquery, args) ||
(this->*processor)(args); (this->*processor)(args);
} }
bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
bool check_vcol_func_processor(uchar *arg) bool check_vcol_func_processor(uchar *arg)
{ {
return trace_unsupported_by_check_vcol_func_processor("values"); return trace_unsupported_by_check_vcol_func_processor("values");
......
...@@ -1696,6 +1696,7 @@ class Item_func_set_user_var :public Item_func ...@@ -1696,6 +1696,7 @@ class Item_func_set_user_var :public Item_func
bool register_field_in_bitmap(uchar *arg); bool register_field_in_bitmap(uchar *arg);
bool set_entry(THD *thd, bool create_if_not_exists); bool set_entry(THD *thd, bool create_if_not_exists);
void cleanup(); void cleanup();
bool check_vcol_func_processor(uchar *int_arg) {return TRUE;}
}; };
...@@ -1735,6 +1736,7 @@ class Item_func_get_user_var :public Item_func, ...@@ -1735,6 +1736,7 @@ class Item_func_get_user_var :public Item_func,
{ {
return this; return this;
} }
bool check_vcol_func_processor(uchar *int_arg) { return TRUE;}
}; };
...@@ -1817,6 +1819,7 @@ class Item_func_get_system_var :public Item_func ...@@ -1817,6 +1819,7 @@ class Item_func_get_system_var :public Item_func
bool eq(const Item *item, bool binary_cmp) const; bool eq(const Item *item, bool binary_cmp) const;
void cleanup(); void cleanup();
bool check_vcol_func_processor(uchar *int_arg) { return TRUE;}
}; };
...@@ -2090,7 +2093,6 @@ class Item_func_uuid_short :public Item_int_func ...@@ -2090,7 +2093,6 @@ class Item_func_uuid_short :public Item_int_func
longlong val_int(); longlong val_int();
void fix_length_and_dec() void fix_length_and_dec()
{ max_length= 21; unsigned_flag=1; } { max_length= 21; unsigned_flag=1; }
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
bool check_vcol_func_processor(uchar *int_arg) bool check_vcol_func_processor(uchar *int_arg)
{ {
return trace_unsupported_by_check_vcol_func_processor(func_name()); return trace_unsupported_by_check_vcol_func_processor(func_name());
......
...@@ -450,16 +450,14 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, ...@@ -450,16 +450,14 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
Create a formated date/time value in a string. Create a formated date/time value in a string.
*/ */
bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time, static bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
timestamp_type type, String *str) timestamp_type type, MY_LOCALE *locale, String *str)
{ {
char intbuff[15]; char intbuff[15];
uint hours_i; uint hours_i;
uint weekday; uint weekday;
ulong length; ulong length;
const char *ptr, *end; const char *ptr, *end;
THD *thd= current_thd;
MY_LOCALE *locale= thd->variables.lc_time_names;
str->length(0); str->length(0);
...@@ -1726,6 +1724,8 @@ bool Item_func_sec_to_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) ...@@ -1726,6 +1724,8 @@ bool Item_func_sec_to_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
void Item_func_date_format::fix_length_and_dec() void Item_func_date_format::fix_length_and_dec()
{ {
THD* thd= current_thd; THD* thd= current_thd;
locale= thd->variables.lc_time_names;
/* /*
Must use this_item() in case it's a local SP variable Must use this_item() in case it's a local SP variable
(for ->max_length and ->str_value) (for ->max_length and ->str_value)
...@@ -1889,7 +1889,7 @@ String *Item_func_date_format::val_str(String *str) ...@@ -1889,7 +1889,7 @@ String *Item_func_date_format::val_str(String *str)
if (!make_date_time(&date_time_format, &l_time, if (!make_date_time(&date_time_format, &l_time,
is_time_format ? MYSQL_TIMESTAMP_TIME : is_time_format ? MYSQL_TIMESTAMP_TIME :
MYSQL_TIMESTAMP_DATE, MYSQL_TIMESTAMP_DATE,
str)) locale, str))
return str; return str;
null_date: null_date:
...@@ -1900,8 +1900,9 @@ String *Item_func_date_format::val_str(String *str) ...@@ -1900,8 +1900,9 @@ String *Item_func_date_format::val_str(String *str)
void Item_func_from_unixtime::fix_length_and_dec() void Item_func_from_unixtime::fix_length_and_dec()
{ {
thd= current_thd; THD *thd= current_thd;
thd->time_zone_used= 1; thd->time_zone_used= 1;
tz= thd->variables.time_zone;
decimals= args[0]->decimals; decimals= args[0]->decimals;
Item_temporal_func::fix_length_and_dec(); Item_temporal_func::fix_length_and_dec();
} }
...@@ -1922,7 +1923,7 @@ bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime, ...@@ -1922,7 +1923,7 @@ bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
if (args[0]->null_value || sign || sec > TIMESTAMP_MAX_VALUE) if (args[0]->null_value || sign || sec > TIMESTAMP_MAX_VALUE)
return (null_value= 1); return (null_value= 1);
thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)sec); tz->gmt_sec_to_TIME(ltime, (my_time_t)sec);
ltime->second_part= sec_part; ltime->second_part= sec_part;
......
...@@ -688,6 +688,7 @@ class Item_func_from_days :public Item_datefunc ...@@ -688,6 +688,7 @@ class Item_func_from_days :public Item_datefunc
class Item_func_date_format :public Item_str_func class Item_func_date_format :public Item_str_func
{ {
MY_LOCALE *locale;
int fixed_length; int fixed_length;
const bool is_time_format; const bool is_time_format;
String value; String value;
...@@ -705,7 +706,7 @@ class Item_func_date_format :public Item_str_func ...@@ -705,7 +706,7 @@ class Item_func_date_format :public Item_str_func
class Item_func_from_unixtime :public Item_temporal_func class Item_func_from_unixtime :public Item_temporal_func
{ {
THD *thd; Time_zone *tz;
public: public:
Item_func_from_unixtime(Item *a) :Item_temporal_func(a) {} Item_func_from_unixtime(Item *a) :Item_temporal_func(a) {}
const char *func_name() const { return "from_unixtime"; } const char *func_name() const { return "from_unixtime"; }
...@@ -1046,10 +1047,4 @@ class Item_func_last_day :public Item_datefunc ...@@ -1046,10 +1047,4 @@ class Item_func_last_day :public Item_datefunc
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
}; };
/* Function prototypes */
bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
timestamp_type type, String *str);
#endif /* ITEM_TIMEFUNC_INCLUDED */ #endif /* ITEM_TIMEFUNC_INCLUDED */
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