diff options
author | tomas@poseidon.ndb.mysql.com <> | 2005-10-06 10:54:07 +0200 |
---|---|---|
committer | tomas@poseidon.ndb.mysql.com <> | 2005-10-06 10:54:07 +0200 |
commit | 620b7bafb0182949463e706fc91c0144328d0d34 (patch) | |
tree | cbe58ba165511396b212afaa1654a226d8ae88a4 /sql/opt_sum.cc | |
parent | 418808ba9ab51a5e0dec3ed7f00b1a8e1689ebca (diff) | |
parent | 3af12c477662114f4e118bba6806af65f64b9793 (diff) | |
download | mariadb-git-620b7bafb0182949463e706fc91c0144328d0d34.tar.gz |
Merge
Diffstat (limited to 'sql/opt_sum.cc')
-rw-r--r-- | sql/opt_sum.cc | 74 |
1 files changed, 64 insertions, 10 deletions
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 9802bbddde6..2e87f9cf0db 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -80,6 +80,8 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) List_iterator_fast<Item> it(all_fields); int const_result= 1; bool recalc_const_item= 0; + longlong count= 1; + bool is_exact_count= TRUE; table_map removed_tables= 0, outer_tables= 0, used_tables= 0; table_map where_tables= 0; Item *item; @@ -88,9 +90,13 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) if (conds) where_tables= conds->used_tables(); - /* Don't replace expression on a table that is part of an outer join */ + /* + Analyze outer join dependencies, and, if possible, compute the number + of returned rows. + */ for (TABLE_LIST *tl= tables; tl; tl= tl->next_leaf) { + /* Don't replace expression on a table that is part of an outer join */ if (tl->on_expr) { outer_tables|= tl->table->map; @@ -106,11 +112,27 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } else used_tables|= tl->table->map; + + /* + If the storage manager of 'tl' gives exact row count, compute the total + number of rows. If there are no outer table dependencies, this count + may be used as the real count. + */ + if (tl->table->file->table_flags() & HA_NOT_EXACT_COUNT) + { + is_exact_count= FALSE; + count= 1; // ensure count != 0 + } + else + { + tl->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); + count*= tl->table->file->records; + } } /* - Iterate through item is select part and replace COUNT(), MIN() and MAX() - with constants (if possible) + Iterate through all items in the SELECT clause and replace + COUNT(), MIN() and MAX() with constants (if possible). */ while ((item= it++)) @@ -122,9 +144,11 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) case Item_sum::COUNT_FUNC: /* If the expr in count(expr) can never be null we can change this - to the number of rows in the tables + to the number of rows in the tables if this number is exact and + there are no outer joins. */ - if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null) + if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null && + !outer_tables && is_exact_count) { longlong count= 1; TABLE_LIST *table; @@ -210,12 +234,27 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } removed_tables|= table->map; } - else if (!expr->const_item()) // This is VERY seldom false + else if (!expr->const_item() || !is_exact_count) { + /* + The optimization is not applicable in both cases: + (a) 'expr' is a non-constant expression. Then we can't + replace 'expr' by a constant. + (b) 'expr' is a costant. According to ANSI, MIN/MAX must return + NULL if the query does not return any rows. Thus, if we are not + able to determine if the query returns any rows, we can't apply + the optimization and replace MIN/MAX with a constant. + */ const_result= 0; break; } - ((Item_sum_min*) item_sum)->reset(); + if (!count) + { + /* If count == 0, then we know that is_exact_count == TRUE. */ + ((Item_sum_min*) item_sum)->clear(); /* Set to NULL. */ + } + else + ((Item_sum_min*) item_sum)->reset(); /* Set to the constant value. */ ((Item_sum_min*) item_sum)->make_const(); recalc_const_item= 1; break; @@ -282,13 +321,28 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } removed_tables|= table->map; } - else if (!expr->const_item()) // This is VERY seldom false + else if (!expr->const_item() || !is_exact_count) { + /* + The optimization is not applicable in both cases: + (a) 'expr' is a non-constant expression. Then we can't + replace 'expr' by a constant. + (b) 'expr' is a costant. According to ANSI, MIN/MAX must return + NULL if the query does not return any rows. Thus, if we are not + able to determine if the query returns any rows, we can't apply + the optimization and replace MIN/MAX with a constant. + */ const_result= 0; break; } - ((Item_sum_min*) item_sum)->reset(); - ((Item_sum_min*) item_sum)->make_const(); + if (!count) + { + /* If count != 1, then we know that is_exact_count == TRUE. */ + ((Item_sum_max*) item_sum)->clear(); /* Set to NULL. */ + } + else + ((Item_sum_max*) item_sum)->reset(); /* Set to the constant value. */ + ((Item_sum_max*) item_sum)->make_const(); recalc_const_item= 1; break; } |