diff options
author | unknown <timour@askmonty.org> | 2011-02-10 16:16:06 +0200 |
---|---|---|
committer | unknown <timour@askmonty.org> | 2011-02-10 16:16:06 +0200 |
commit | ca37339585cd73363cb0d11cea73561cf78ee79f (patch) | |
tree | 6303cd62b5d49c95870a7ca6262a3514b63cf0f5 | |
parent | 648e604615dfe852abbd467dbd8e6c3c9476dd07 (diff) | |
download | mariadb-git-ca37339585cd73363cb0d11cea73561cf78ee79f.tar.gz |
MWL#89
Fixed a memory leak found by valgrind. The memory leak was
a result of JOINs corresponding to subselects in a global
ORDER BY of a UNION not being cleaned up because the
fake_select of the UNION didn't point down to the subquery
select.
-rw-r--r-- | sql/item_subselect.cc | 20 | ||||
-rw-r--r-- | sql/sql_lex.cc | 25 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 |
3 files changed, 34 insertions, 13 deletions
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index b30cf450d6d..bb99d20b305 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -326,23 +326,19 @@ bool Item_subselect::set_fake_select_as_master_processor(uchar *arg) /* Move the st_select_lex_unit of a subquery from a global ORDER BY clause to become a direct child of the fake_select of a UNION. In this way the - ORDER BY is applied to the temporary table that contains the result of the - whole UNION, and all columns in the subquery are resolved against this table. - - Apply the transformation only for immediate child subqueries of a - UNION query. + ORDER BY that is applied to the temporary table that contains the result of + the whole UNION, and all columns in the subquery are resolved against this + table. The transformation is applied only for immediate child subqueries of + a UNION query. */ if (unit->outer_select()->master_unit()->fake_select_lex == fake_select) { /* - Set the master of the subquery to be the fake select (i.e. the whole UNION), - instead of the last query in the UNION. - TODO: - This is a hack, instead we should call: unit->include_down(fake_select); - However, this call results in an infinite loop where - some_select_lex->master == some_select_lex. + Set the master of the subquery to be the fake select (i.e. the whole + UNION), instead of the last query in the UNION. */ - unit->set_master(fake_select); + fake_select->add_slave(unit); + DBUG_ASSERT(unit->outer_select() == fake_select); /* Adjust the name resolution context hierarchy accordingly. */ for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) sl->context.outer_context= &(fake_select->context); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index e8a724cea82..f7e2f1835ad 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1684,6 +1684,31 @@ void st_select_lex_node::include_down(st_select_lex_node *upper) slave= 0; } + +void st_select_lex_node::add_slave(st_select_lex_node *slave_arg) +{ + for (; slave; slave= slave->next) + if (slave == slave_arg) + return; + + if (slave) + { + st_select_lex_node *slave_arg_slave= slave_arg->slave; + /* Insert in the front of list of slaves if any. */ + slave_arg->include_neighbour(slave); + /* include_neighbour() sets slave_arg->slave=0, restore it. */ + slave_arg->slave= slave_arg_slave; + /* Count on include_neighbour() setting the master. */ + DBUG_ASSERT(slave_arg->master == this); + } + else + { + slave= slave_arg; + slave_arg->master= this; + } +} + + /* include on level down (but do not link) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 525d7c5cf46..eb5a7acbbd2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -439,10 +439,10 @@ public: st_select_lex_node(): linkage(UNSPECIFIED_TYPE) {} virtual ~st_select_lex_node() {} inline st_select_lex_node* get_master() { return master; } - inline void set_master(st_select_lex_node* master_arg) { master= master_arg; } virtual void init_query(); virtual void init_select(); void include_down(st_select_lex_node *upper); + void add_slave(st_select_lex_node *slave_arg); void include_neighbour(st_select_lex_node *before); void include_standalone(st_select_lex_node *sel, st_select_lex_node **ref); void include_global(st_select_lex_node **plink); |