mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 12:32:27 +01:00
BUG#21354: (COUNT(*) = 1) not working in SELECT inside prepared
statement. The problem was that during statement re-execution if the result was empty the old result could be returned for group functions. The solution is to implement proper cleanup() method in group functions.
This commit is contained in:
parent
a55d18e746
commit
fbf6507cf7
5 changed files with 219 additions and 3 deletions
|
@ -889,3 +889,100 @@ create temporary table if not exists t1 (a1 int);
|
|||
execute stmt;
|
||||
drop temporary table t1;
|
||||
deallocate prepare stmt;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1 (i INT, INDEX(i));
|
||||
INSERT INTO t1 VALUES (1);
|
||||
PREPARE stmt FROM "SELECT (COUNT(i) = 1), COUNT(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(COUNT(i) = 1) COUNT(i)
|
||||
0 0
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(COUNT(i) = 1) COUNT(i)
|
||||
1 1
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(COUNT(i) = 1) COUNT(i)
|
||||
0 0
|
||||
PREPARE stmt FROM "SELECT (AVG(i) = 1), AVG(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(AVG(i) = 1) AVG(i)
|
||||
NULL NULL
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(AVG(i) = 1) AVG(i)
|
||||
1 1.0000
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(AVG(i) = 1) AVG(i)
|
||||
NULL NULL
|
||||
PREPARE stmt FROM "SELECT (VARIANCE(i) = 1), VARIANCE(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(VARIANCE(i) = 1) VARIANCE(i)
|
||||
NULL NULL
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(VARIANCE(i) = 1) VARIANCE(i)
|
||||
0 0.0000
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(VARIANCE(i) = 1) VARIANCE(i)
|
||||
NULL NULL
|
||||
PREPARE stmt FROM "SELECT (STDDEV(i) = 1), STDDEV(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(STDDEV(i) = 1) STDDEV(i)
|
||||
NULL NULL
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(STDDEV(i) = 1) STDDEV(i)
|
||||
0 0.0000
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(STDDEV(i) = 1) STDDEV(i)
|
||||
NULL NULL
|
||||
PREPARE stmt FROM "SELECT (BIT_OR(i) = 1), BIT_OR(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_OR(i) = 1) BIT_OR(i)
|
||||
0 0
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_OR(i) = 1) BIT_OR(i)
|
||||
1 1
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_OR(i) = 1) BIT_OR(i)
|
||||
0 0
|
||||
PREPARE stmt FROM "SELECT (BIT_AND(i) = 1), BIT_AND(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_AND(i) = 1) BIT_AND(i)
|
||||
0 18446744073709551615
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_AND(i) = 1) BIT_AND(i)
|
||||
1 1
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_AND(i) = 1) BIT_AND(i)
|
||||
0 18446744073709551615
|
||||
PREPARE stmt FROM "SELECT (BIT_XOR(i) = 1), BIT_XOR(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_XOR(i) = 1) BIT_XOR(i)
|
||||
0 0
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_XOR(i) = 1) BIT_XOR(i)
|
||||
1 1
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_XOR(i) = 1) BIT_XOR(i)
|
||||
0 0
|
||||
DEALLOCATE PREPARE stmt;
|
||||
DROP TABLE t1;
|
||||
End of 4.1 tests.
|
||||
|
|
|
@ -99,7 +99,7 @@ select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'withou
|
|||
select distinct ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'with distinct: cutoff at length of shortname' from t1;
|
||||
drop table t1;
|
||||
|
||||
# check zero rows
|
||||
# check zero rows (bug#836)
|
||||
create table t1(id int);
|
||||
create table t2(id int);
|
||||
insert into t1 values(0),(1);
|
||||
|
|
|
@ -951,4 +951,76 @@ execute stmt;
|
|||
drop temporary table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
||||
#
|
||||
# BUG#21354: (COUNT(*) = 1) not working in SELECT inside prepared
|
||||
# statement
|
||||
#
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (i INT, INDEX(i));
|
||||
INSERT INTO t1 VALUES (1);
|
||||
|
||||
PREPARE stmt FROM "SELECT (COUNT(i) = 1), COUNT(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
PREPARE stmt FROM "SELECT (AVG(i) = 1), AVG(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
PREPARE stmt FROM "SELECT (VARIANCE(i) = 1), VARIANCE(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
PREPARE stmt FROM "SELECT (STDDEV(i) = 1), STDDEV(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
PREPARE stmt FROM "SELECT (BIT_OR(i) = 1), BIT_OR(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
PREPARE stmt FROM "SELECT (BIT_AND(i) = 1), BIT_AND(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
PREPARE stmt FROM "SELECT (BIT_XOR(i) = 1), BIT_XOR(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
DEALLOCATE PREPARE stmt;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo End of 4.1 tests.
|
||||
|
|
|
@ -312,6 +312,7 @@ longlong Item_sum_count::val_int()
|
|||
void Item_sum_count::cleanup()
|
||||
{
|
||||
DBUG_ENTER("Item_sum_count::cleanup");
|
||||
clear();
|
||||
Item_sum_int::cleanup();
|
||||
used_table_cache= ~(table_map) 0;
|
||||
DBUG_VOID_RETURN;
|
||||
|
|
|
@ -58,9 +58,30 @@ public:
|
|||
Item_sum(THD *thd, Item_sum *item);
|
||||
enum Type type() const { return SUM_FUNC_ITEM; }
|
||||
virtual enum Sumfunctype sum_func () const=0;
|
||||
|
||||
/*
|
||||
This method is similar to add(), but it is called when the current
|
||||
aggregation group changes. Thus it performs a combination of
|
||||
clear() and add().
|
||||
*/
|
||||
inline bool reset() { clear(); return add(); };
|
||||
|
||||
/*
|
||||
Prepare this item for evaluation of an aggregate value. This is
|
||||
called by reset() when a group changes, or, for correlated
|
||||
subqueries, between subquery executions. E.g. for COUNT(), this
|
||||
method should set count= 0;
|
||||
*/
|
||||
virtual void clear()= 0;
|
||||
|
||||
/*
|
||||
This method is called for the next row in the same group. Its
|
||||
purpose is to aggregate the new value to the previous values in
|
||||
the group (i.e. since clear() was called last time). For example,
|
||||
for COUNT(), do count++.
|
||||
*/
|
||||
virtual bool add()=0;
|
||||
|
||||
/*
|
||||
Called when new group is started and results are being saved in
|
||||
a temporary table. Similar to reset(), but must also store value in
|
||||
|
@ -86,7 +107,17 @@ public:
|
|||
void make_field(Send_field *field);
|
||||
void print(String *str);
|
||||
void fix_num_length_and_dec();
|
||||
void no_rows_in_result() { reset(); }
|
||||
|
||||
/*
|
||||
This function is called by the execution engine to assign 'NO ROWS
|
||||
FOUND' value to an aggregate item, when the underlying result set
|
||||
has no rows. Such value, in a general case, may be different from
|
||||
the default value of the item after 'clear()': e.g. a numeric item
|
||||
may be initialized to 0 by clear() and to NULL by
|
||||
no_rows_in_result().
|
||||
*/
|
||||
void no_rows_in_result() { clear(); }
|
||||
|
||||
virtual bool setup(THD *thd) {return 0;}
|
||||
virtual void make_unique() {}
|
||||
Item *get_tmp_table_item(THD *thd);
|
||||
|
@ -304,6 +335,11 @@ class Item_sum_avg :public Item_sum_num
|
|||
void no_rows_in_result() {}
|
||||
const char *func_name() const { return "avg"; }
|
||||
Item *copy_or_same(THD* thd);
|
||||
void cleanup()
|
||||
{
|
||||
clear();
|
||||
Item_sum_num::cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
class Item_sum_variance;
|
||||
|
@ -361,6 +397,11 @@ class Item_sum_variance : public Item_sum_num
|
|||
void no_rows_in_result() {}
|
||||
const char *func_name() const { return "variance"; }
|
||||
Item *copy_or_same(THD* thd);
|
||||
void cleanup()
|
||||
{
|
||||
clear();
|
||||
Item_sum_num::cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
class Item_sum_std;
|
||||
|
@ -485,6 +526,11 @@ public:
|
|||
void update_field();
|
||||
void fix_length_and_dec()
|
||||
{ decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; }
|
||||
void cleanup()
|
||||
{
|
||||
clear();
|
||||
Item_sum_int::cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue