Commit 7977a0c8 authored by igor@rurik.mysql.com's avatar igor@rurik.mysql.com
Browse files

Fixed bug #14927.

A query with a group by and having clauses could return a wrong
result set if the having condition contained a constant conjunct 
evaluated to FALSE.
It happened because the pushdown condition for table with
grouping columns lost its constant conjuncts.
Pushdown conditions are always built by the function make_cond_for_table
that ignores constant conjuncts. This is apparently not correct when
constant false conjuncts are present.
parent ceef1105
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -141,3 +141,20 @@ SUM(a)
6
4
DROP TABLE t1;
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (1), (2), (1), (3), (2), (1);
SELECT a FROM t1 GROUP BY a HAVING a > 1;
a
2
3
SELECT a FROM t1 GROUP BY a HAVING 1 != 1 AND a > 1;
a
SELECT 0 AS x, a FROM t1 GROUP BY x,a HAVING x=1 AND a > 1;
x	a
EXPLAIN SELECT a FROM t1 GROUP BY a HAVING 1 != 1 AND a > 1;
id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible HAVING
EXPLAIN SELECT 0 AS x, a FROM t1 GROUP BY x,a HAVING x=1 AND a > 1;
id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible HAVING
DROP table t1;
+16 −0
Original line number Diff line number Diff line
@@ -135,4 +135,20 @@ SELECT SUM(a) FROM t1 GROUP BY a HAVING SUM(a);

DROP TABLE t1;

#
# Bug #14927: HAVING clause containing constant false conjunct
#

CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (1), (2), (1), (3), (2), (1);

SELECT a FROM t1 GROUP BY a HAVING a > 1;
SELECT a FROM t1 GROUP BY a HAVING 1 != 1 AND a > 1;
SELECT 0 AS x, a FROM t1 GROUP BY x,a HAVING x=1 AND a > 1;

EXPLAIN SELECT a FROM t1 GROUP BY a HAVING 1 != 1 AND a > 1;
EXPLAIN SELECT 0 AS x, a FROM t1 GROUP BY x,a HAVING x=1 AND a > 1;

DROP table t1;  

# End of 4.1 tests
+2 −0
Original line number Diff line number Diff line
@@ -1074,6 +1074,7 @@ void st_select_lex::init_query()
  item_list.empty();
  join= 0;
  where= 0;
  having= 0;
  olap= UNSPECIFIED_OLAP_TYPE;
  having_fix_field= 0;
  resolve_mode= NOMATTER_MODE;
@@ -1081,6 +1082,7 @@ void st_select_lex::init_query()
  ref_pointer_array= 0;
  select_n_having_items= 0;
  prep_where= 0;
  prep_having= 0;
  subquery_in_having= explicit_limit= 0;
  parsing_place= NO_MATTER;
  is_item_list_lookup= 0;
+1 −0
Original line number Diff line number Diff line
@@ -422,6 +422,7 @@ class st_select_lex: public st_select_lex_node
  char *db, *db1, *table1, *db2, *table2;      	/* For outer join using .. */
  Item *where, *having;                         /* WHERE & HAVING clauses */
  Item *prep_where; /* saved WHERE clause for prepared statement processing */
  Item *prep_having;/* saved HAVING clause for prepared statement processing */
  enum olap_type olap;
  SQL_LIST	      table_list, group_list;   /* FROM & GROUP BY clauses */
  List<Item>          item_list; /* list of fields & expressions */
+8 −2
Original line number Diff line number Diff line
@@ -1667,10 +1667,11 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
    for (; sl; sl= sl->next_select_in_list())
    {
      /*
        Save WHERE clause pointers, because they may be changed
        Save WHERE, HAVING clause pointers, because they may be changed
        during query optimisation.
      */
      sl->prep_where= sl->where;
      sl->prep_having= sl->having;
      /*
        Switch off a temporary flag that prevents evaluation of
        subqueries in statement prepare.
@@ -1696,13 +1697,18 @@ static void reset_stmt_for_execute(Prepared_statement *stmt)
    /* remove option which was put by mysql_explain_union() */
    sl->options&= ~SELECT_DESCRIBE;
    /*
      Copy WHERE clause pointers to avoid damaging they by optimisation
      Copy WHERE, HAVING clause pointers to avoid damaging they by optimisation
    */
    if (sl->prep_where)
    {
      sl->where= sl->prep_where->copy_andor_structure(thd);
      sl->where->cleanup();
    }
    if (sl->prep_having)
    {
      sl->having= sl->prep_having->copy_andor_structure(thd);
      sl->having->cleanup();
    }
    DBUG_ASSERT(sl->join == 0);
    ORDER *order;
    /* Fix GROUP list */
Loading