Commit f6899b07 authored by konstantin@mysql.com's avatar konstantin@mysql.com

Merge bk-internal.mysql.com:/home/bk/mysql-5.0

into  mysql.com:/opt/local/work/mysql-5.0-12736
parents 93d8c03d b2ff3820
......@@ -152,3 +152,23 @@ EXECUTE my_stmt;
b count(*)
deallocate prepare my_stmt;
drop table t1,t2;
CREATE TABLE t1 (
school_name varchar(45) NOT NULL,
country varchar(45) NOT NULL,
funds_requested float NOT NULL,
schooltype varchar(45) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into t1 values ("the school", "USA", 1200, "Human");
select count(country) as countrycount, sum(funds_requested) as smcnt,
country, (select sum(funds_requested) from t1) as total_funds
from t1
group by country;
countrycount smcnt country total_funds
1 1200 USA 1200
select count(country) as countrycount, sum(funds_requested) as smcnt,
country, (select sum(funds_requested) from t1) as total_funds
from t1
group by country;
countrycount smcnt country total_funds
1 1200 USA 1200
drop table t1;
......@@ -161,3 +161,25 @@ deallocate prepare my_stmt;
drop table t1,t2;
# End of 4.1 tests
CREATE TABLE t1 (
school_name varchar(45) NOT NULL,
country varchar(45) NOT NULL,
funds_requested float NOT NULL,
schooltype varchar(45) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into t1 values ("the school", "USA", 1200, "Human");
select count(country) as countrycount, sum(funds_requested) as smcnt,
country, (select sum(funds_requested) from t1) as total_funds
from t1
group by country;
select count(country) as countrycount, sum(funds_requested) as smcnt,
country, (select sum(funds_requested) from t1) as total_funds
from t1
group by country;
drop table t1;
......@@ -1413,6 +1413,12 @@ void subselect_union_engine::cleanup()
}
bool subselect_union_engine::is_executed() const
{
return unit->executed;
}
void subselect_uniquesubquery_engine::cleanup()
{
DBUG_ENTER("subselect_uniquesubquery_engine::cleanup");
......
......@@ -109,6 +109,12 @@ public:
engine_changed= 1;
return eng == 0;
}
/*
True if this subquery has been already evaluated. Implemented only for
single select and union subqueries only.
*/
bool is_evaluated() const;
/*
Used by max/min subquery to initialize value presence registration
mechanism. Engine call this method before rexecution query.
......@@ -317,6 +323,7 @@ public:
virtual void print(String *str)= 0;
virtual bool change_result(Item_subselect *si, select_subselect *result)= 0;
virtual bool no_tables()= 0;
virtual bool is_executed() const { return FALSE; }
};
......@@ -342,6 +349,7 @@ public:
void print (String *str);
bool change_result(Item_subselect *si, select_subselect *result);
bool no_tables();
bool is_executed() const { return executed; }
};
......@@ -363,6 +371,7 @@ public:
void print (String *str);
bool change_result(Item_subselect *si, select_subselect *result);
bool no_tables();
bool is_executed() const;
};
......@@ -411,3 +420,10 @@ public:
int exec();
void print (String *str);
};
inline bool Item_subselect::is_evaluated() const
{
return engine->is_executed();
}
......@@ -386,12 +386,12 @@ protected:
select_result *result;
ulong found_rows_for_union;
bool res;
public:
bool prepared, // prepare phase already performed for UNION (unit)
optimized, // optimize phase already performed for UNION (unit)
executed, // already executed
cleaned;
public:
// list of fields which points to temporary table for union
List<Item> item_list;
/*
......@@ -638,6 +638,11 @@ public:
SELECT_LEX and all nested SELECT_LEXes and SELECT_LEX_UNITs).
*/
bool cleanup();
/*
Recursively cleanup the join of this select lex and of all nested
select lexes.
*/
void cleanup_all_joins(bool full);
};
typedef class st_select_lex SELECT_LEX;
......
......@@ -1377,7 +1377,7 @@ JOIN::exec()
DBUG_PRINT("info",("Creating group table"));
/* Free first data from old join */
curr_join->join_free(0);
curr_join->join_free();
if (make_simple_join(curr_join, curr_tmp_table))
DBUG_VOID_RETURN;
calc_group_buffer(curr_join, group_list);
......@@ -1475,7 +1475,7 @@ JOIN::exec()
if (curr_tmp_table->distinct)
curr_join->select_distinct=0; /* Each row is unique */
curr_join->join_free(0); /* Free quick selects */
curr_join->join_free(); /* Free quick selects */
if (curr_join->select_distinct && ! curr_join->group_list)
{
thd->proc_info="Removing duplicates";
......@@ -5718,34 +5718,88 @@ void JOIN_TAB::cleanup()
end_read_record(&read_record);
}
/*
Partially cleanup JOIN after it has executed: close index or rnd read
(table cursors), free quick selects.
DESCRIPTION
This function is called in the end of execution of a JOIN, before the used
tables are unlocked and closed.
For a join that is resolved using a temporary table, the first sweep is
performed against actual tables and an intermediate result is inserted
into the temprorary table.
The last sweep is performed against the temporary table. Therefore,
the base tables and associated buffers used to fill the temporary table
are no longer needed, and this function is called to free them.
void JOIN::join_free(bool full)
For a join that is performed without a temporary table, this function
is called after all rows are sent, but before EOF packet is sent.
For a simple SELECT with no subqueries this function performs a full
cleanup of the JOIN and calls mysql_unlock_read_tables to free used base
tables.
If a JOIN is executed for a subquery or if it has a subquery, we can't
do the full cleanup and need to do a partial cleanup only.
o If a JOIN is not the top level join, we must not unlock the tables
because the outer select may not have been evaluated yet, and we
can't unlock only selected tables of a query.
o Additionally, if this JOIN corresponds to a correlated subquery, we
should not free quick selects and join buffers because they will be
needed for the next execution of the correlated subquery.
o However, if this is a JOIN for a [sub]select, which is not
a correlated subquery itself, but has subqueries, we can free it
fully and also free JOINs of all its subqueries. The exception
is a subquery in SELECT list, e.g:
SELECT a, (select max(b) from t1) group by c
This subquery will not be evaluated at first sweep and its value will
not be inserted into the temporary table. Instead, it's evaluated
when selecting from the temporary table. Therefore, it can't be freed
here even though it's not correlated.
*/
void JOIN::join_free()
{
SELECT_LEX_UNIT *unit;
SELECT_LEX *sl;
DBUG_ENTER("JOIN::join_free");
/*
Optimization: if not EXPLAIN and we are done with the JOIN,
free all tables.
*/
full= full || (!select_lex->uncacheable && !thd->lex->describe);
bool full= (!select_lex->uncacheable && !thd->lex->describe);
bool can_unlock= full;
DBUG_ENTER("JOIN::join_free");
cleanup(full);
for (unit= select_lex->first_inner_unit(); unit; unit= unit->next_unit())
for (sl= unit->first_select(); sl; sl= sl->next_select())
{
JOIN *join= sl->join;
if (join)
join->join_free(full);
Item_subselect *subselect= sl->master_unit()->item;
bool full_local= full && (!subselect || subselect->is_evaluated());
/*
If this join is evaluated, we can fully clean it up and clean up all
its underlying joins even if they are correlated -- they will not be
used any more anyway.
If this join is not yet evaluated, we still must clean it up to
close its table cursors -- it may never get evaluated, as in case of
... HAVING FALSE OR a IN (SELECT ...))
but all table cursors must be closed before the unlock.
*/
sl->cleanup_all_joins(full_local);
/* Can't unlock if at least one JOIN is still needed */
can_unlock= can_unlock && full_local;
}
/*
We are not using tables anymore
Unlock all tables. We may be in an INSERT .... SELECT statement.
*/
if (full && lock && thd->lock && !(select_options & SELECT_NO_UNLOCK) &&
if (can_unlock && lock && thd->lock &&
!(select_options & SELECT_NO_UNLOCK) &&
!select_lex->subquery_in_having &&
(select_lex == (thd->lex->unit.fake_select_lex ?
thd->lex->unit.fake_select_lex : &thd->lex->select_lex)))
......@@ -6059,7 +6113,7 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
DBUG_RETURN(0);
}
join->join_free(0);
join->join_free();
if (send_row)
{
......@@ -9019,7 +9073,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
The following will unlock all cursors if the command wasn't an
update command
*/
join->join_free(0); // Unlock all cursors
join->join_free(); // Unlock all cursors
if (join->result->send_eof())
rc= 1; // Don't send error
}
......
......@@ -358,7 +358,7 @@ class JOIN :public Sql_alloc
the end of execution in order to increase concurrency and reduce
memory consumption.
*/
void join_free(bool full);
void join_free();
/* Cleanup this JOIN, possibly for reuse */
void cleanup(bool full);
void clear();
......
......@@ -720,3 +720,17 @@ bool st_select_lex::cleanup()
DBUG_RETURN(error);
}
void st_select_lex::cleanup_all_joins(bool full)
{
SELECT_LEX_UNIT *unit;
SELECT_LEX *sl;
if (join)
join->cleanup(full);
for (unit= first_inner_unit(); unit; unit= unit->next_unit())
for (sl= unit->first_select(); sl; sl= sl->next_select())
sl->cleanup_all_joins(full);
}
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