Commit dcaa684c authored by unknown's avatar unknown

Merge abotchkov@bk-internal.mysql.com:/home/bk/mysql-5.0-opt

into  mysql.com:/usersnfs/abotchkov/mysql-5.0-opt1

parents 1533e884 37a823b7
...@@ -1029,3 +1029,29 @@ t1 CREATE TABLE `t1` ( ...@@ -1029,3 +1029,29 @@ t1 CREATE TABLE `t1` (
`stddev(0)` double(8,4) default NULL `stddev(0)` double(8,4) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
CREATE TABLE t1 (a INT, b INT);
INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8);
INSERT INTO t1 SELECT a, b+8 FROM t1;
INSERT INTO t1 SELECT a, b+16 FROM t1;
INSERT INTO t1 SELECT a, b+32 FROM t1;
INSERT INTO t1 SELECT a, b+64 FROM t1;
INSERT INTO t1 SELECT a, b+128 FROM t1;
INSERT INTO t1 SELECT a, b+256 FROM t1;
INSERT INTO t1 SELECT a, b+512 FROM t1;
INSERT INTO t1 SELECT a, b+1024 FROM t1;
INSERT INTO t1 SELECT a, b+2048 FROM t1;
INSERT INTO t1 SELECT a, b+4096 FROM t1;
INSERT INTO t1 SELECT a, b+8192 FROM t1;
INSERT INTO t1 SELECT a, b+16384 FROM t1;
INSERT INTO t1 SELECT a, b+32768 FROM t1;
SELECT a,COUNT(DISTINCT b) AS cnt FROM t1 GROUP BY a HAVING cnt > 50;
a cnt
1 65536
SELECT a,SUM(DISTINCT b) AS sumation FROM t1 GROUP BY a HAVING sumation > 50;
a sumation
1 2147516416
SELECT a,AVG(DISTINCT b) AS average FROM t1 GROUP BY a HAVING average > 50;
a average
1 32768.5000
DROP TABLE t1;
End of 5.0 tests
...@@ -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;
......
...@@ -700,3 +700,28 @@ create table t1 select stddev(0); ...@@ -700,3 +700,28 @@ create table t1 select stddev(0);
show create table t1; show create table t1;
drop table t1; drop table t1;
#
# Bug #23184: SELECT causes server crash
#
CREATE TABLE t1 (a INT, b INT);
INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8);
INSERT INTO t1 SELECT a, b+8 FROM t1;
INSERT INTO t1 SELECT a, b+16 FROM t1;
INSERT INTO t1 SELECT a, b+32 FROM t1;
INSERT INTO t1 SELECT a, b+64 FROM t1;
INSERT INTO t1 SELECT a, b+128 FROM t1;
INSERT INTO t1 SELECT a, b+256 FROM t1;
INSERT INTO t1 SELECT a, b+512 FROM t1;
INSERT INTO t1 SELECT a, b+1024 FROM t1;
INSERT INTO t1 SELECT a, b+2048 FROM t1;
INSERT INTO t1 SELECT a, b+4096 FROM t1;
INSERT INTO t1 SELECT a, b+8192 FROM t1;
INSERT INTO t1 SELECT a, b+16384 FROM t1;
INSERT INTO t1 SELECT a, b+32768 FROM t1;
SELECT a,COUNT(DISTINCT b) AS cnt FROM t1 GROUP BY a HAVING cnt > 50;
SELECT a,SUM(DISTINCT b) AS sumation FROM t1 GROUP BY a HAVING sumation > 50;
SELECT a,AVG(DISTINCT b) AS average FROM t1 GROUP BY a HAVING average > 50;
DROP TABLE t1;
--echo End of 5.0 tests
...@@ -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);
......
...@@ -952,6 +952,7 @@ public: ...@@ -952,6 +952,7 @@ public:
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);
}; };
......
...@@ -893,6 +893,7 @@ bool Item_sum_distinct::setup(THD *thd) ...@@ -893,6 +893,7 @@ bool Item_sum_distinct::setup(THD *thd)
tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length, tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length,
thd->variables.max_heap_table_size); thd->variables.max_heap_table_size);
is_evaluated= FALSE;
DBUG_RETURN(tree == 0); DBUG_RETURN(tree == 0);
} }
...@@ -900,6 +901,7 @@ bool Item_sum_distinct::setup(THD *thd) ...@@ -900,6 +901,7 @@ bool Item_sum_distinct::setup(THD *thd)
bool Item_sum_distinct::add() bool Item_sum_distinct::add()
{ {
args[0]->save_in_field(table->field[0], FALSE); args[0]->save_in_field(table->field[0], FALSE);
is_evaluated= FALSE;
if (!table->field[0]->is_null()) if (!table->field[0]->is_null())
{ {
DBUG_ASSERT(tree); DBUG_ASSERT(tree);
...@@ -929,6 +931,7 @@ void Item_sum_distinct::clear() ...@@ -929,6 +931,7 @@ void Item_sum_distinct::clear()
DBUG_ASSERT(tree != 0); /* we always have a tree */ DBUG_ASSERT(tree != 0); /* we always have a tree */
null_value= 1; null_value= 1;
tree->reset(); tree->reset();
is_evaluated= FALSE;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -938,6 +941,7 @@ void Item_sum_distinct::cleanup() ...@@ -938,6 +941,7 @@ void Item_sum_distinct::cleanup()
delete tree; delete tree;
tree= 0; tree= 0;
table= 0; table= 0;
is_evaluated= FALSE;
} }
Item_sum_distinct::~Item_sum_distinct() Item_sum_distinct::~Item_sum_distinct()
...@@ -949,16 +953,20 @@ Item_sum_distinct::~Item_sum_distinct() ...@@ -949,16 +953,20 @@ Item_sum_distinct::~Item_sum_distinct()
void Item_sum_distinct::calculate_val_and_count() void Item_sum_distinct::calculate_val_and_count()
{ {
count= 0; if (!is_evaluated)
val.traits->set_zero(&val);
/*
We don't have a tree only if 'setup()' hasn't been called;
this is the case of sql_select.cc:return_zero_rows.
*/
if (tree)
{ {
table->field[0]->set_notnull(); count= 0;
tree->walk(item_sum_distinct_walk, (void*) this); val.traits->set_zero(&val);
/*
We don't have a tree only if 'setup()' hasn't been called;
this is the case of sql_select.cc:return_zero_rows.
*/
if (tree)
{
table->field[0]->set_notnull();
tree->walk(item_sum_distinct_walk, (void*) this);
}
is_evaluated= TRUE;
} }
} }
...@@ -1014,9 +1022,13 @@ Item_sum_avg_distinct::fix_length_and_dec() ...@@ -1014,9 +1022,13 @@ Item_sum_avg_distinct::fix_length_and_dec()
void void
Item_sum_avg_distinct::calculate_val_and_count() Item_sum_avg_distinct::calculate_val_and_count()
{ {
Item_sum_distinct::calculate_val_and_count(); if (!is_evaluated)
if (count) {
val.traits->div(&val, count); Item_sum_distinct::calculate_val_and_count();
if (count)
val.traits->div(&val, count);
is_evaluated= TRUE;
}
} }
...@@ -2477,6 +2489,7 @@ void Item_sum_count_distinct::cleanup() ...@@ -2477,6 +2489,7 @@ void Item_sum_count_distinct::cleanup()
*/ */
delete tree; delete tree;
tree= 0; tree= 0;
is_evaluated= FALSE;
if (table) if (table)
{ {
free_tmp_table(table->in_use, table); free_tmp_table(table->in_use, table);
...@@ -2498,6 +2511,7 @@ void Item_sum_count_distinct::make_unique() ...@@ -2498,6 +2511,7 @@ void Item_sum_count_distinct::make_unique()
original= 0; original= 0;
force_copy_fields= 1; force_copy_fields= 1;
tree= 0; tree= 0;
is_evaluated= FALSE;
tmp_table_param= 0; tmp_table_param= 0;
always_null= FALSE; always_null= FALSE;
} }
...@@ -2617,6 +2631,7 @@ bool Item_sum_count_distinct::setup(THD *thd) ...@@ -2617,6 +2631,7 @@ bool Item_sum_count_distinct::setup(THD *thd)
but this has to be handled - otherwise someone can crash but this has to be handled - otherwise someone can crash
the server with a DoS attack the server with a DoS attack
*/ */
is_evaluated= FALSE;
if (! tree) if (! tree)
return TRUE; return TRUE;
} }
...@@ -2633,8 +2648,11 @@ Item *Item_sum_count_distinct::copy_or_same(THD* thd) ...@@ -2633,8 +2648,11 @@ Item *Item_sum_count_distinct::copy_or_same(THD* thd)
void Item_sum_count_distinct::clear() void Item_sum_count_distinct::clear()
{ {
/* tree and table can be both null only if always_null */ /* tree and table can be both null only if always_null */
is_evaluated= FALSE;
if (tree) if (tree)
{
tree->reset(); tree->reset();
}
else if (table) else if (table)
{ {
table->file->extra(HA_EXTRA_NO_CACHE); table->file->extra(HA_EXTRA_NO_CACHE);
...@@ -2655,6 +2673,7 @@ bool Item_sum_count_distinct::add() ...@@ -2655,6 +2673,7 @@ bool Item_sum_count_distinct::add()
if ((*field)->is_real_null(0)) if ((*field)->is_real_null(0))
return 0; // Don't count NULL return 0; // Don't count NULL
is_evaluated= FALSE;
if (tree) if (tree)
{ {
/* /*
...@@ -2680,12 +2699,14 @@ longlong Item_sum_count_distinct::val_int() ...@@ -2680,12 +2699,14 @@ longlong Item_sum_count_distinct::val_int()
return LL(0); return LL(0);
if (tree) if (tree)
{ {
ulonglong count; if (is_evaluated)
return count;
if (tree->elements == 0) if (tree->elements == 0)
return (longlong) tree->elements_in_tree(); // everything fits in memory return (longlong) tree->elements_in_tree(); // everything fits in memory
count= 0; count= 0;
tree->walk(count_distinct_walk, (void*) &count); tree->walk(count_distinct_walk, (void*) &count);
is_evaluated= TRUE;
return (longlong) count; return (longlong) count;
} }
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
......
...@@ -321,12 +321,23 @@ public: ...@@ -321,12 +321,23 @@ public:
class Item_sum_num :public Item_sum class Item_sum_num :public Item_sum
{ {
protected:
/*
val_xxx() functions may be called several times during the execution of a
query. Derived classes that require extensive calculation in val_xxx()
maintain cache of aggregate value. This variable governs the validity of
that cache.
*/
bool is_evaluated;
public: public:
Item_sum_num() :Item_sum() {} Item_sum_num() :Item_sum(),is_evaluated(FALSE) {}
Item_sum_num(Item *item_par) :Item_sum(item_par) {} Item_sum_num(Item *item_par)
Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {} :Item_sum(item_par), is_evaluated(FALSE) {}
Item_sum_num(List<Item> &list) :Item_sum(list) {} Item_sum_num(Item *a, Item* b) :Item_sum(a,b),is_evaluated(FALSE) {}
Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item) {} Item_sum_num(List<Item> &list)
:Item_sum(list), is_evaluated(FALSE) {}
Item_sum_num(THD *thd, Item_sum_num *item)
:Item_sum(thd, item),is_evaluated(item->is_evaluated) {}
bool fix_fields(THD *, Item **); bool fix_fields(THD *, Item **);
longlong val_int() longlong val_int()
{ {
...@@ -508,6 +519,12 @@ class Item_sum_count_distinct :public Item_sum_int ...@@ -508,6 +519,12 @@ class Item_sum_count_distinct :public Item_sum_int
to help get things set up, but we insert nothing in it to help get things set up, but we insert nothing in it
*/ */
Unique *tree; Unique *tree;
/*
Storage for the value of count between calls to val_int() so val_int()
will not recalculate on each call. Validitiy of the value is stored in
is_evaluated.
*/
longlong count;
/* /*
Following is 0 normal object and pointer to original one for copy Following is 0 normal object and pointer to original one for copy
(to correctly free resources) (to correctly free resources)
...@@ -525,14 +542,15 @@ class Item_sum_count_distinct :public Item_sum_int ...@@ -525,14 +542,15 @@ class Item_sum_count_distinct :public Item_sum_int
public: public:
Item_sum_count_distinct(List<Item> &list) Item_sum_count_distinct(List<Item> &list)
:Item_sum_int(list), table(0), field_lengths(0), tmp_table_param(0), :Item_sum_int(list), table(0), field_lengths(0), tmp_table_param(0),
force_copy_fields(0), tree(0), original(0), always_null(FALSE) force_copy_fields(0), tree(0), count(0),
original(0), always_null(FALSE)
{ quick_group= 0; } { quick_group= 0; }
Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item) Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item)
:Item_sum_int(thd, item), table(item->table), :Item_sum_int(thd, item), table(item->table),
field_lengths(item->field_lengths), field_lengths(item->field_lengths),
tmp_table_param(item->tmp_table_param), tmp_table_param(item->tmp_table_param),
force_copy_fields(0), tree(item->tree), original(item), force_copy_fields(0), tree(item->tree), count(item->count),
tree_key_length(item->tree_key_length), original(item), tree_key_length(item->tree_key_length),
always_null(item->always_null) always_null(item->always_null)
{} {}
~Item_sum_count_distinct(); ~Item_sum_count_distinct();
......
...@@ -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();
......
...@@ -581,6 +581,8 @@ public: ...@@ -581,6 +581,8 @@ public:
/* 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