summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorsergefp@mysql.com <>2004-11-21 11:51:19 +0300
committersergefp@mysql.com <>2004-11-21 11:51:19 +0300
commite6a7386c120f80a7ee9c6d61fcf964c508c5b218 (patch)
tree4405a89b7616b6761af8778b22aaa0801ee5bcad /sql
parent162587878858b8c960d40956aae6258b84522607 (diff)
downloadmariadb-git-e6a7386c120f80a7ee9c6d61fcf964c508c5b218.tar.gz
Fix for BUG#4177:
* Make index merge quick selects code allow perform several scans. * Delay additional handler objects creation till row retrieval is started.
Diffstat (limited to 'sql')
-rw-r--r--sql/opt_range.cc114
-rw-r--r--sql/opt_range.h18
2 files changed, 89 insertions, 43 deletions
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index f036cbc799b..ec7434d215b 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -777,8 +777,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param,
TABLE *table)
- :cur_quick_it(quick_selects),pk_quick_select(NULL),unique(NULL),
- thd(thd_param)
+ :pk_quick_select(NULL), thd(thd_param)
{
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT");
index= MAX_KEY;
@@ -790,17 +789,14 @@ QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param,
int QUICK_INDEX_MERGE_SELECT::init()
{
- cur_quick_it.rewind();
- cur_quick_select= cur_quick_it++;
- return 0;
+ DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::init");
+ DBUG_RETURN(0);
}
int QUICK_INDEX_MERGE_SELECT::reset()
{
- int result;
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::reset");
- result= cur_quick_select->reset() || prepare_unique();
- DBUG_RETURN(result);
+ DBUG_RETURN(read_keys_and_merge());
}
bool
@@ -820,8 +816,12 @@ QUICK_INDEX_MERGE_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick_sel_range)
QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT()
{
+ List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects);
+ QUICK_RANGE_SELECT* quick;
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT");
- delete unique;
+ quick_it.rewind();
+ while ((quick= quick_it++))
+ quick->file= NULL;
quick_selects.delete_elements();
delete pk_quick_select;
free_root(&alloc,MYF(0));
@@ -833,7 +833,8 @@ QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param,
TABLE *table,
bool retrieve_full_rows,
MEM_ROOT *parent_alloc)
- : cpk_quick(NULL), thd(thd_param), need_to_fetch_row(retrieve_full_rows)
+ : cpk_quick(NULL), thd(thd_param), need_to_fetch_row(retrieve_full_rows),
+ scans_inited(false)
{
index= MAX_KEY;
head= table;
@@ -859,8 +860,9 @@ QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param,
int QUICK_ROR_INTERSECT_SELECT::init()
{
- /* Check if last_rowid was successfully allocated in ctor */
- return !last_rowid;
+ DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::init");
+ /* Check if last_rowid was successfully allocated in ctor */
+ DBUG_RETURN(!last_rowid);
}
@@ -953,7 +955,7 @@ int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler)
DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan");
/* Initialize all merged "children" quick selects */
- DBUG_ASSERT(!(need_to_fetch_row && !reuse_handler));
+ DBUG_ASSERT(!need_to_fetch_row || reuse_handler);
if (!need_to_fetch_row && reuse_handler)
{
quick= quick_it++;
@@ -995,7 +997,14 @@ int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler)
int QUICK_ROR_INTERSECT_SELECT::reset()
{
DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::reset");
- DBUG_RETURN(init_ror_merged_scan(TRUE));
+ if (!scans_inited && init_ror_merged_scan(TRUE))
+ DBUG_RETURN(1);
+ scans_inited= true;
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ QUICK_RANGE_SELECT *quick;
+ while ((quick= it++))
+ quick->reset();
+ DBUG_RETURN(0);
}
@@ -1034,7 +1043,7 @@ QUICK_ROR_INTERSECT_SELECT::~QUICK_ROR_INTERSECT_SELECT()
QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param,
TABLE *table)
- :thd(thd_param)
+ : thd(thd_param), scans_inited(false)
{
index= MAX_KEY;
head= table;
@@ -1057,18 +1066,19 @@ QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param,
int QUICK_ROR_UNION_SELECT::init()
{
+ DBUG_ENTER("QUICK_ROR_UNION_SELECT::init");
if (init_queue(&queue, quick_selects.elements, 0,
FALSE , QUICK_ROR_UNION_SELECT::queue_cmp,
(void*) this))
{
bzero(&queue, sizeof(QUEUE));
- return 1;
+ DBUG_RETURN(1);
}
if (!(cur_rowid= (byte*)alloc_root(&alloc, 2*head->file->ref_length)))
- return 1;
+ DBUG_RETURN(1);
prev_rowid= cur_rowid + head->file->ref_length;
- return 0;
+ DBUG_RETURN(0);
}
@@ -1106,6 +1116,18 @@ int QUICK_ROR_UNION_SELECT::reset()
int error;
DBUG_ENTER("QUICK_ROR_UNION_SELECT::reset");
have_prev_rowid= FALSE;
+ if (!scans_inited)
+ {
+ QUICK_SELECT_I *quick;
+ List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
+ while ((quick= it++))
+ {
+ if (quick->init_ror_merged_scan(FALSE))
+ DBUG_RETURN(1);
+ }
+ scans_inited= true;
+ }
+ queue_remove_all(&queue);
/*
Initialize scans for merged quick selects and put all merged quick
selects into the queue.
@@ -1113,7 +1135,7 @@ int QUICK_ROR_UNION_SELECT::reset()
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
while ((quick= it++))
{
- if (quick->init_ror_merged_scan(FALSE))
+ if (quick->reset())
DBUG_RETURN(1);
if ((error= quick->get_next()))
{
@@ -1591,7 +1613,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
keys_to_use.to_ulonglong(), (ulong) prev_tables,
(ulong) const_tables));
-
delete quick;
quick=0;
needed_reg.clear_all();
@@ -5545,22 +5566,29 @@ err:
/*
- Fetch all row ids into unique.
-
+ Perform key scans for all used indexes (except CPK), get rowids and merge
+ them into an ordered non-recurrent sequence of rowids.
+
+ The merge/duplicate removal is performed using Unique class. We put all
+ rowids into Unique, get the sorted sequence and destroy the Unique.
+
If table has a clustered primary key that covers all rows (TRUE for bdb
and innodb currently) and one of the index_merge scans is a scan on PK,
then
- primary key scan rowids are not put into Unique and also
- rows that will be retrieved by PK scan are not put into Unique
+ rows that will be retrieved by PK scan are not put into Unique and
+ primary key scan is not performed here, it is performed later separately.
RETURN
0 OK
other error
*/
-int QUICK_INDEX_MERGE_SELECT::prepare_unique()
+int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
{
+ List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it(quick_selects);
+ QUICK_RANGE_SELECT* cur_quick;
int result;
+ Unique *unique;
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::prepare_unique");
/* We're going to just read rowids. */
@@ -5575,7 +5603,17 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique()
*/
head->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- cur_quick_select->init();
+ cur_quick_it.rewind();
+ cur_quick= cur_quick_it++;
+ DBUG_ASSERT(cur_quick);
+
+ /*
+ We reuse the same instance of handler so we need to call both init and
+ reset here.
+ */
+ if (cur_quick->init())
+ DBUG_RETURN(1);
+ cur_quick->reset();
unique= new Unique(refpos_order_cmp, (void *)head->file,
head->file->ref_length,
@@ -5584,24 +5622,28 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique()
DBUG_RETURN(1);
for (;;)
{
- while ((result= cur_quick_select->get_next()) == HA_ERR_END_OF_FILE)
+ while ((result= cur_quick->get_next()) == HA_ERR_END_OF_FILE)
{
- cur_quick_select->range_end();
- cur_quick_select= cur_quick_it++;
- if (!cur_quick_select)
+ cur_quick->range_end();
+ cur_quick= cur_quick_it++;
+ if (!cur_quick)
break;
- if (cur_quick_select->init())
+ if (cur_quick->file->inited != handler::NONE)
+ cur_quick->file->ha_index_end();
+ if (cur_quick->init())
DBUG_RETURN(1);
-
/* QUICK_RANGE_SELECT::reset never fails */
- cur_quick_select->reset();
+ cur_quick->reset();
}
if (result)
{
if (result != HA_ERR_END_OF_FILE)
+ {
+ cur_quick->range_end();
DBUG_RETURN(result);
+ }
break;
}
@@ -5612,8 +5654,8 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique()
if (pk_quick_select && pk_quick_select->row_in_ranges())
continue;
- cur_quick_select->file->position(cur_quick_select->record);
- result= unique->unique_add((char*)cur_quick_select->file->ref);
+ cur_quick->file->position(cur_quick->record);
+ result= unique->unique_add((char*)cur_quick->file->ref);
if (result)
DBUG_RETURN(1);
@@ -5621,6 +5663,7 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique()
/* ok, all row ids are in Unique */
result= unique->get(head);
+ delete unique;
doing_pk_scan= FALSE;
/* start table scan */
init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1, 1);
@@ -5660,6 +5703,7 @@ int QUICK_INDEX_MERGE_SELECT::get_next()
doing_pk_scan= TRUE;
if ((result= pk_quick_select->init()))
DBUG_RETURN(result);
+ pk_quick_select->reset();
DBUG_RETURN(pk_quick_select->get_next());
}
}
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 19234f61ea2..74d388128c8 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -127,7 +127,8 @@ public:
reset() should be called when it is certain that row retrieval will be
necessary. This call may do heavyweight initialization like buffering first
N records etc. If reset() call fails get_next() must not be called.
-
+ Note that reset() may be called several times if this quick select
+ executes in a subselect.
RETURN
0 OK
other Error code
@@ -274,6 +275,10 @@ public:
next=0;
range= NULL;
cur_range= NULL;
+ /*
+ Note: in opt_range.cc there are places where it is assumed that this
+ function always succeeds
+ */
return 0;
}
int init();
@@ -388,21 +393,15 @@ public:
/* range quick selects this index_merge read consists of */
List<QUICK_RANGE_SELECT> quick_selects;
- /* quick select which is currently used for rows retrieval */
- List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it;
- QUICK_RANGE_SELECT* cur_quick_select;
-
/* quick select that uses clustered primary key (NULL if none) */
QUICK_RANGE_SELECT* pk_quick_select;
/* true if this select is currently doing a clustered PK scan */
bool doing_pk_scan;
- Unique *unique;
MEM_ROOT alloc;
-
THD *thd;
- int prepare_unique();
+ int read_keys_and_merge();
/* used to get rows collected in Unique */
READ_RECORD read_record;
@@ -465,6 +464,8 @@ public:
MEM_ROOT alloc; /* Memory pool for this and merged quick selects data. */
THD *thd; /* current thread */
bool need_to_fetch_row; /* if true, do retrieve full table records. */
+ /* in top-level quick select, true if merged scans where initialized */
+ bool scans_inited;
};
@@ -514,6 +515,7 @@ public:
uint rowid_length; /* table rowid length */
private:
static int queue_cmp(void *arg, byte *val1, byte *val2);
+ bool scans_inited;
};