Bug #21809: Error 1356 while selecting from view with grouping though underlying

            select OK.
The SQL parser was using Item::name to transfer user defined function attributes
to the user defined function (udf). It was not distinguishing between user defined 
function call arguments and stored procedure call arguments. Setting Item::name 
was causing Item_ref::print() method to print the argument as quoted identifiers 
and caused views that reference aggregate functions as udf call arguments (and 
rely on Item::print() for the text of the view to store) to throw an undefined 
identifier error.
Overloaded Item_ref::print to print aggregate functions as such when printing
the references to aggregate functions taken out of context by split_sum_func2()
Fixed the parser to properly detect using AS clause in stored procedure arguments
as an error.
Fixed printing the arguments of udf call to print properly the udf attribute.
parent a5899ea8
...@@ -105,6 +105,85 @@ explain select myfunc_int(f1) from t1 order by 1; ...@@ -105,6 +105,85 @@ explain select myfunc_int(f1) from t1 order by 1;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
drop table t1; drop table t1;
CREATE TABLE t1(a INT, b INT);
INSERT INTO t1 values (1,1),(2,2);
CREATE FUNCTION fn(a int) RETURNS int DETERMINISTIC
BEGIN
RETURN a;
END
||
CREATE VIEW v1 AS SELECT a, fn(MIN(b)) as c FROM t1 GROUP BY a;
SELECT myfunc_int(a AS attr_name) FROM t1;
myfunc_int(a AS attr_name)
1
2
EXPLAIN EXTENDED SELECT myfunc_int(a AS attr_name) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2
Warnings:
Note 1003 select myfunc_int(`test`.`t1`.`a` AS `attr_name`) AS `myfunc_int(a AS attr_name)` from `test`.`t1`
EXPLAIN EXTENDED SELECT myfunc_int(a) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2
Warnings:
Note 1003 select myfunc_int(`test`.`t1`.`a` AS `a`) AS `myfunc_int(a)` from `test`.`t1`
SELECT a,c FROM v1;
a c
1 1
2 2
SELECT a, fn(MIN(b) xx) as c FROM t1 GROUP BY a;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xx) as c FROM t1 GROUP BY a' at line 1
SELECT myfunc_int(fn(MIN(b) xx)) as c FROM t1 GROUP BY a;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xx)) as c FROM t1 GROUP BY a' at line 1
SELECT myfunc_int(test.fn(MIN(b) xx)) as c FROM t1 GROUP BY a;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xx)) as c FROM t1 GROUP BY a' at line 1
SELECT myfunc_int(fn(MIN(b)) xx) as c FROM t1 GROUP BY a;
c
1
2
SELECT myfunc_int(test.fn(MIN(b)) xx) as c FROM t1 GROUP BY a;
c
1
2
EXPLAIN EXTENDED SELECT myfunc_int(MIN(b) xx) as c FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
Warnings:
Note 1003 select myfunc_int(min(`test`.`t1`.`b`) AS `xx`) AS `c` from `test`.`t1` group by `test`.`t1`.`a`
EXPLAIN EXTENDED SELECT test.fn(MIN(b)) as c FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
Warnings:
Note 1003 select `test`.`fn`(min(`test`.`t1`.`b`)) AS `c` from `test`.`t1` group by `test`.`t1`.`a`
EXPLAIN EXTENDED SELECT myfunc_int(fn(MIN(b))) as c FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
Warnings:
Note 1003 select myfunc_int(`test`.`fn`(min(`test`.`t1`.`b`)) AS `fn(MIN(b))`) AS `c` from `test`.`t1` group by `test`.`t1`.`a`
EXPLAIN EXTENDED SELECT myfunc_int(test.fn(MIN(b))) as c FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
Warnings:
Note 1003 select myfunc_int(`test`.`fn`(min(`test`.`t1`.`b`)) AS `test.fn(MIN(b))`) AS `c` from `test`.`t1` group by `test`.`t1`.`a`
SELECT myfunc_int(MIN(b) xx) as c FROM t1 GROUP BY a;
c
1
2
SELECT test.fn(MIN(b)) as c FROM t1 GROUP BY a;
c
1
2
SELECT myfunc_int(fn(MIN(b))) as c FROM t1 GROUP BY a;
c
1
2
SELECT myfunc_int(test.fn(MIN(b))) as c FROM t1 GROUP BY a;
c
1
2
DROP VIEW v1;
DROP TABLE t1;
DROP FUNCTION fn;
End of 5.0 tests. End of 5.0 tests.
DROP FUNCTION metaphon; DROP FUNCTION metaphon;
DROP FUNCTION myfunc_double; DROP FUNCTION myfunc_double;
......
...@@ -127,6 +127,50 @@ create table t1(f1 int); ...@@ -127,6 +127,50 @@ create table t1(f1 int);
insert into t1 values(1),(2); insert into t1 values(1),(2);
explain select myfunc_int(f1) from t1 order by 1; explain select myfunc_int(f1) from t1 order by 1;
drop table t1; drop table t1;
#
# Bug #21809: Error 1356 while selecting from view with grouping though
# underlying select OK.
#
CREATE TABLE t1(a INT, b INT); INSERT INTO t1 values (1,1),(2,2);
DELIMITER ||;
CREATE FUNCTION fn(a int) RETURNS int DETERMINISTIC
BEGIN
RETURN a;
END
||
DELIMITER ;||
CREATE VIEW v1 AS SELECT a, fn(MIN(b)) as c FROM t1 GROUP BY a;
SELECT myfunc_int(a AS attr_name) FROM t1;
EXPLAIN EXTENDED SELECT myfunc_int(a AS attr_name) FROM t1;
EXPLAIN EXTENDED SELECT myfunc_int(a) FROM t1;
SELECT a,c FROM v1;
--error ER_PARSE_ERROR
SELECT a, fn(MIN(b) xx) as c FROM t1 GROUP BY a;
--error ER_PARSE_ERROR
SELECT myfunc_int(fn(MIN(b) xx)) as c FROM t1 GROUP BY a;
--error ER_PARSE_ERROR
SELECT myfunc_int(test.fn(MIN(b) xx)) as c FROM t1 GROUP BY a;
SELECT myfunc_int(fn(MIN(b)) xx) as c FROM t1 GROUP BY a;
SELECT myfunc_int(test.fn(MIN(b)) xx) as c FROM t1 GROUP BY a;
EXPLAIN EXTENDED SELECT myfunc_int(MIN(b) xx) as c FROM t1 GROUP BY a;
EXPLAIN EXTENDED SELECT test.fn(MIN(b)) as c FROM t1 GROUP BY a;
EXPLAIN EXTENDED SELECT myfunc_int(fn(MIN(b))) as c FROM t1 GROUP BY a;
EXPLAIN EXTENDED SELECT myfunc_int(test.fn(MIN(b))) as c FROM t1 GROUP BY a;
SELECT myfunc_int(MIN(b) xx) as c FROM t1 GROUP BY a;
SELECT test.fn(MIN(b)) as c FROM t1 GROUP BY a;
SELECT myfunc_int(fn(MIN(b))) as c FROM t1 GROUP BY a;
SELECT myfunc_int(test.fn(MIN(b))) as c FROM t1 GROUP BY a;
DROP VIEW v1;
DROP TABLE t1;
DROP FUNCTION fn;
--echo End of 5.0 tests. --echo End of 5.0 tests.
# #
......
...@@ -1147,6 +1147,28 @@ void Item_name_const::print(String *str) ...@@ -1147,6 +1147,28 @@ void Item_name_const::print(String *str)
} }
/*
need a special class to adjust printing : references to aggregate functions
must not be printed as refs because the aggregate functions that are added to
the front of select list are not printed as well.
*/
class Item_aggregate_ref : public Item_ref
{
public:
Item_aggregate_ref(Name_resolution_context *context_arg, Item **item,
const char *table_name_arg, const char *field_name_arg)
:Item_ref(context_arg, item, table_name_arg, field_name_arg) {}
void print (String *str)
{
if (ref)
(*ref)->print(str);
else
Item_ident::print(str);
}
};
/* /*
Move SUM items out from item tree and replace with reference Move SUM items out from item tree and replace with reference
...@@ -1200,8 +1222,8 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, ...@@ -1200,8 +1222,8 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
Item *new_item, *real_itm= real_item(); Item *new_item, *real_itm= real_item();
ref_pointer_array[el]= real_itm; ref_pointer_array[el]= real_itm;
if (!(new_item= new Item_ref(&thd->lex->current_select->context, if (!(new_item= new Item_aggregate_ref(&thd->lex->current_select->context,
ref_pointer_array + el, 0, name))) ref_pointer_array + el, 0, name)))
return; // fatal_error is set return; // fatal_error is set
fields.push_front(real_itm); fields.push_front(real_itm);
thd->change_item_tree(ref, new_item); thd->change_item_tree(ref, new_item);
......
...@@ -2869,6 +2869,20 @@ void Item_udf_func::cleanup() ...@@ -2869,6 +2869,20 @@ void Item_udf_func::cleanup()
} }
void Item_udf_func::print(String *str)
{
str->append(func_name());
str->append('(');
for (uint i=0 ; i < arg_count ; i++)
{
if (i != 0)
str->append(',');
args[i]->print_item_w_name(str);
}
str->append(')');
}
double Item_func_udf_float::val_real() double Item_func_udf_float::val_real()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
......
...@@ -951,6 +951,7 @@ class Item_udf_func :public Item_func ...@@ -951,6 +951,7 @@ class Item_udf_func :public Item_func
Item_result result_type () const { return udf.result_type(); } Item_result result_type () const { return udf.result_type(); }
table_map not_null_tables() const { return 0; } table_map not_null_tables() const { return 0; }
bool is_expensive() { return 1; } bool is_expensive() { return 1; }
void print(String *str);
}; };
......
...@@ -163,6 +163,7 @@ void lex_start(THD *thd, uchar *buf,uint length) ...@@ -163,6 +163,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc; lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc;
lex->select_lex.group_list.empty(); lex->select_lex.group_list.empty();
lex->select_lex.order_list.empty(); lex->select_lex.order_list.empty();
lex->select_lex.udf_list.empty();
lex->current_select= &lex->select_lex; lex->current_select= &lex->select_lex;
lex->yacc_yyss=lex->yacc_yyvs=0; lex->yacc_yyss=lex->yacc_yyvs=0;
lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE); lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE);
...@@ -1166,6 +1167,7 @@ void st_select_lex::init_select() ...@@ -1166,6 +1167,7 @@ void st_select_lex::init_select()
braces= 0; braces= 0;
when_list.empty(); when_list.empty();
expr_list.empty(); expr_list.empty();
udf_list.empty();
interval_list.empty(); interval_list.empty();
use_index.empty(); use_index.empty();
ftfunc_list_alloc.empty(); ftfunc_list_alloc.empty();
......
...@@ -580,6 +580,8 @@ class st_select_lex: public st_select_lex_node ...@@ -580,6 +580,8 @@ class st_select_lex: public st_select_lex_node
/* exclude this select from check of unique_table() */ /* exclude this select from check of unique_table() */
bool exclude_from_table_unique_test; bool exclude_from_table_unique_test;
List<udf_func> udf_list; /* udf function calls stack */
void init_query(); void init_query();
void init_select(); void init_select();
st_select_lex_unit* master_unit(); st_select_lex_unit* master_unit();
......
...@@ -650,11 +650,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -650,11 +650,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token UNIX_TIMESTAMP %token UNIX_TIMESTAMP
%token UNKNOWN_SYM %token UNKNOWN_SYM
%token UNLOCK_SYM %token UNLOCK_SYM
%token UNLOCK_SYM
%token UNSIGNED %token UNSIGNED
%token UNTIL_SYM %token UNTIL_SYM
%token UNTIL_SYM
%token UPDATE_SYM
%token UPDATE_SYM %token UPDATE_SYM
%token UPGRADE_SYM %token UPGRADE_SYM
%token USAGE %token USAGE
...@@ -764,7 +761,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -764,7 +761,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <item_list> %type <item_list>
expr_list udf_expr_list udf_expr_list2 when_list expr_list udf_expr_list udf_expr_list2 when_list
ident_list ident_list_arg ident_list ident_list_arg opt_expr_list
%type <var_type> %type <var_type>
option_type opt_var_type opt_var_ident_type option_type opt_var_type opt_var_ident_type
...@@ -4724,7 +4721,7 @@ simple_expr: ...@@ -4724,7 +4721,7 @@ simple_expr:
{ $$= new Item_func_trim($5,$3); } { $$= new Item_func_trim($5,$3); }
| TRUNCATE_SYM '(' expr ',' expr ')' | TRUNCATE_SYM '(' expr ',' expr ')'
{ $$= new Item_func_round($3,$5,1); } { $$= new Item_func_round($3,$5,1); }
| ident '.' ident '(' udf_expr_list ')' | ident '.' ident '(' opt_expr_list ')'
{ {
LEX *lex= Lex; LEX *lex= Lex;
sp_name *name= new sp_name($1, $3); sp_name *name= new sp_name($1, $3);
...@@ -4741,27 +4738,27 @@ simple_expr: ...@@ -4741,27 +4738,27 @@ simple_expr:
{ {
#ifdef HAVE_DLOPEN #ifdef HAVE_DLOPEN
udf_func *udf= 0; udf_func *udf= 0;
LEX *lex= Lex;
if (using_udf_functions && if (using_udf_functions &&
(udf= find_udf($1.str, $1.length)) && (udf= find_udf($1.str, $1.length)) &&
udf->type == UDFTYPE_AGGREGATE) udf->type == UDFTYPE_AGGREGATE)
{ {
LEX *lex= Lex;
if (lex->current_select->inc_in_sum_expr()) if (lex->current_select->inc_in_sum_expr())
{ {
yyerror(ER(ER_SYNTAX_ERROR)); yyerror(ER(ER_SYNTAX_ERROR));
YYABORT; YYABORT;
} }
} }
$<udf>$= udf; lex->current_select->udf_list.push_front(udf);
#endif #endif
} }
udf_expr_list ')' udf_expr_list ')'
{ {
#ifdef HAVE_DLOPEN #ifdef HAVE_DLOPEN
udf_func *udf= $<udf>3; udf_func *udf;
SELECT_LEX *sel= Select; LEX *lex= Lex;
if (udf) if (NULL != (udf= lex->current_select->udf_list.pop()))
{ {
if (udf->type == UDFTYPE_AGGREGATE) if (udf->type == UDFTYPE_AGGREGATE)
Select->in_sum_expr--; Select->in_sum_expr--;
...@@ -4988,12 +4985,29 @@ udf_expr_list3: ...@@ -4988,12 +4985,29 @@ udf_expr_list3:
udf_expr: udf_expr:
remember_name expr remember_end select_alias remember_name expr remember_end select_alias
{ {
udf_func *udf= Select->udf_list.head();
/*
Use Item::name as a storage for the attribute value of user
defined function argument. It is safe to use Item::name
because the syntax will not allow having an explicit name here.
See WL#1017 re. udf attributes.
*/
if ($4.str) if ($4.str)
{ {
if (!udf)
{
/*
Disallow using AS to specify explicit names for the arguments
of stored routine calls
*/
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
$2->is_autogenerated_name= FALSE; $2->is_autogenerated_name= FALSE;
$2->set_name($4.str, $4.length, system_charset_info); $2->set_name($4.str, $4.length, system_charset_info);
} }
else else if (udf)
$2->set_name($1, (uint) ($3 - $1), YYTHD->charset()); $2->set_name($1, (uint) ($3 - $1), YYTHD->charset());
$$= $2; $$= $2;
} }
...@@ -5114,6 +5128,11 @@ cast_type: ...@@ -5114,6 +5128,11 @@ cast_type:
| DECIMAL_SYM float_options { $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; } | DECIMAL_SYM float_options { $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; }
; ;
opt_expr_list:
/* empty */ { $$= NULL; }
| expr_list { $$= $1;}
;
expr_list: expr_list:
{ Select->expr_list.push_front(new List<Item>); } { Select->expr_list.push_front(new List<Item>); }
expr_list2 expr_list2
......
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