summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <monty@hundin.mysql.fi>2002-01-23 02:52:26 +0200
committerunknown <monty@hundin.mysql.fi>2002-01-23 02:52:26 +0200
commit7b72c14bbb857834ec81091eabc846774d35ab96 (patch)
treebe3a98f50b40e6cfe7dd9ac0bfb602ada79dcc02 /sql
parent879e892d661b0236850b0c5b0adf87a1bb3d507a (diff)
downloadmariadb-git-7b72c14bbb857834ec81091eabc846774d35ab96.tar.gz
Increase max package length to 512M for mysql and mysqldump.
Faster 'read_first_row' (Fixes slow 'preparing' state) Read constant tables earlier, which provides better optimzations when using tables with <=1 row. This also fixes a complicated bug involving const tables. Docs/manual.texi: Changelog client/mysql.cc: Increase max package length to 512M client/mysqldump.c: Increase max package length to 512M dbug/dbug.c: Fixed wrong printf() format string. mysql-test/t/innodb.test: Test for multi-table delete sql/handler.cc: Faster 'read_first_row' (Fixes slow 'preparing' state) sql/handler.h: Faster 'read_first_row' (Fixes slow 'preparing' state) sql/opt_range.cc: More debug info. sql/sql_select.cc: Read constant tables earlier, which provides better optimzations when using tables with <=1 row. This also fixes a complicated bug involving const tables. sql/sql_select.h: Read const tables earlier
Diffstat (limited to 'sql')
-rw-r--r--sql/handler.cc40
-rw-r--r--sql/handler.h2
-rw-r--r--sql/opt_range.cc3
-rw-r--r--sql/sql_select.cc461
-rw-r--r--sql/sql_select.h2
5 files changed, 285 insertions, 223 deletions
diff --git a/sql/handler.cc b/sql/handler.cc
index e56bdb916bf..58f8192cf22 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -472,17 +472,36 @@ int handler::analyze(THD* thd, HA_CHECK_OPT* check_opt)
return HA_ADMIN_NOT_IMPLEMENTED;
}
- /* Read first row from a table */
+/*
+ Read first row (only) from a table
+ This is never called for InnoDB or BDB tables, as these table types
+ has the HA_NOT_EXACT_COUNT set.
+*/
-int handler::rnd_first(byte * buf)
+int handler::read_first_row(byte * buf, uint primary_key)
{
register int error;
- DBUG_ENTER("handler::rnd_first");
+ DBUG_ENTER("handler::read_first_row");
statistic_increment(ha_read_first_count,&LOCK_status);
- (void) rnd_init();
- while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
- (void) rnd_end();
+
+ /*
+ If there is very few deleted rows in the table, find the first row by
+ scanning the table.
+ */
+ if (deleted < 10 || primary_key >= MAX_KEY)
+ {
+ (void) rnd_init();
+ while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
+ (void) rnd_end();
+ }
+ else
+ {
+ /* Find the first row through the primary key */
+ (void) index_init(primary_key);
+ error=index_first(buf);
+ (void) index_end();
+ }
DBUG_RETURN(error);
}
@@ -498,7 +517,7 @@ int handler::restart_rnd_next(byte *buf, byte *pos)
}
- /* Set a timestamp in record */
+/* Set a timestamp in record */
void handler::update_timestamp(byte *record)
{
@@ -514,9 +533,10 @@ void handler::update_timestamp(byte *record)
return;
}
- /* Updates field with field_type NEXT_NUMBER according to following:
- ** if field = 0 change field to the next free key in database.
- */
+/*
+ Updates field with field_type NEXT_NUMBER according to following:
+ if field = 0 change field to the next free key in database.
+*/
void handler::update_auto_increment()
{
diff --git a/sql/handler.h b/sql/handler.h
index aa809b333b4..0add543f12c 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -269,7 +269,7 @@ public:
virtual int rnd_end() { return 0; }
virtual int rnd_next(byte *buf)=0;
virtual int rnd_pos(byte * buf, byte *pos)=0;
- virtual int rnd_first(byte *buf);
+ virtual int read_first_row(byte *buf, uint primary_key);
virtual int restart_rnd_next(byte *buf, byte *pos);
virtual ha_rows records_in_range(int inx,
const byte *start_key,uint start_key_len,
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 4ac653e070c..c3f4c91b718 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -585,6 +585,9 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
uint idx;
double scan_time;
DBUG_ENTER("test_quick_select");
+ DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
+ (ulong) keys_to_use, (ulong) prev_tables,
+ (ulong) const_tables));
delete quick;
quick=0;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 31c349d199b..94018e0046a 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -41,6 +41,8 @@ static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
uint tables,COND *conds,table_map table_map);
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
static void set_position(JOIN *join,uint index,JOIN_TAB *table,KEYUSE *key);
+static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
+ table_map used_tables);
static void find_best_combination(JOIN *join,table_map rest_tables);
static void find_best(JOIN *join,table_map rest_tables,uint index,
double record_count,double read_time);
@@ -84,7 +86,7 @@ static int end_unique_update(JOIN *join,JOIN_TAB *join_tab,
static int end_write_group(JOIN *join, JOIN_TAB *join_tab,
bool end_of_records);
static int test_if_group_changed(List<Item_buff> &list);
-static int join_read_const_tables(JOIN *join);
+static int join_read_const_table(JOIN_TAB *tab, POSITION *pos);
static int join_read_system(JOIN_TAB *tab);
static int join_read_const(JOIN_TAB *tab);
static int join_read_key(JOIN_TAB *tab);
@@ -413,9 +415,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
goto err;
thd->proc_info="preparing";
result->initialize_tables(&join);
- if ((tmp=join_read_const_tables(&join)) > 0)
- goto err;
- if (tmp && !(select_options & SELECT_DESCRIBE))
+ if (join.const_table_map != join.found_const_table_map &&
+ !(select_options & SELECT_DESCRIBE))
{
error=return_zero_rows(result,tables,fields,
join.tmp_table_param.sum_func_count != 0 &&
@@ -903,7 +904,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
int error;
uint i,table_count,const_count,found_ref,refs,key,const_ref,eq_part;
- table_map const_table_map,all_table_map;
+ table_map const_table_map,found_const_table_map,all_table_map;
TABLE **table_vector;
JOIN_TAB *stat,*stat_end,*s,**stat_ref;
SQL_SELECT *select;
@@ -923,7 +924,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
join->best_ref=stat_vector;
stat_end=stat+table_count;
- const_table_map=all_table_map=0;
+ const_table_map=found_const_table_map=all_table_map=0;
const_count=0;
for (s=stat,i=0 ; tables ; s++,tables=tables->next,i++)
@@ -938,13 +939,13 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
bzero((char*) table->const_key_parts, sizeof(key_part_map)*table->keys);
all_table_map|= table->map;
s->join=join;
+ s->info=0; // For describe
if ((s->on_expr=tables->on_expr))
{
+ /* Left join */
if (!table->file->records)
{ // Empty table
- s->key_dependent=s->dependent=0;
- s->type=JT_SYSTEM;
- const_table_map|=table->map;
+ s->key_dependent=s->dependent=0; // Ignore LEFT JOIN depend.
set_position(join,const_count++,s,(KEYUSE*) 0);
continue;
}
@@ -965,8 +966,6 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
if ((table->system || table->file->records <= 1) && ! s->dependent &&
!(table->file->option_flag() & HA_NOT_EXACT_COUNT))
{
- s->type=JT_SYSTEM;
- const_table_map|=table->map;
set_position(join,const_count++,s,(KEYUSE*) 0);
}
}
@@ -974,10 +973,10 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
join->outer_join=outer_join;
/*
- ** If outer join: Re-arrange tables in stat_vector so that outer join
- ** tables are after all tables it is dependent of.
- ** For example: SELECT * from A LEFT JOIN B ON B.c=C.c, C WHERE A.C=C.C
- ** Will shift table B after table C.
+ If outer join: Re-arrange tables in stat_vector so that outer join
+ tables are after all tables it is dependent of.
+ For example: SELECT * from A LEFT JOIN B ON B.c=C.c, C WHERE A.C=C.C
+ Will shift table B after table C.
*/
if (outer_join)
{
@@ -1014,31 +1013,66 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
conds,~outer_join))
DBUG_RETURN(1);
+ /* Read tables with 0 or 1 rows (system tables) */
+ join->const_table_map=const_table_map;
+
+ for (POSITION *p_pos=join->positions, *p_end=p_pos+const_count;
+ p_pos < p_end ;
+ p_pos++)
+ {
+ int tmp;
+ s= p_pos->table;
+ s->type=JT_SYSTEM;
+ join->const_table_map|=s->table->map;
+ if ((tmp=join_read_const_table(s, p_pos)))
+ {
+ if (tmp > 0)
+ DBUG_RETURN(1); // Fatal error
+ }
+ else
+ found_const_table_map|= s->table->map;
+ }
+
/* loop until no more const tables are found */
int ref_changed;
do
{
ref_changed = 0;
found_ref=0;
- for (JOIN_TAB **pos=stat_vector+const_count; (s= *pos) ; pos++)
+
+ /*
+ We only have to loop from stat_vector + const_count as
+ set_position() will move all const_tables first in stat_vector
+ */
+
+ for (JOIN_TAB **pos=stat_vector+const_count ; (s= *pos) ; pos++)
{
+ TABLE *table=s->table;
if (s->dependent) // If dependent on some table
{
- if (s->dependent & ~(const_table_map)) // All dep. must be constants
+ // All dep. must be constants
+ if (s->dependent & ~(join->const_table_map))
continue;
- if (s->table->file->records <= 1L &&
- !(s->table->file->option_flag() & HA_NOT_EXACT_COUNT))
+ if (table->file->records <= 1L &&
+ !(table->file->option_flag() & HA_NOT_EXACT_COUNT))
{ // system table
+ int tmp;
s->type=JT_SYSTEM;
- const_table_map|=s->table->map;
+ join->const_table_map|=table->map;
set_position(join,const_count++,s,(KEYUSE*) 0);
+ if ((tmp=join_read_const_table(s,join->positions+const_count-1)))
+ {
+ if (tmp > 0)
+ DBUG_RETURN(1); // Fatal error
+ }
+ else
+ found_const_table_map|= table->map;
continue;
}
}
/* check if table can be read by key or table only uses const refs */
if ((keyuse=s->keyuse))
{
- TABLE *table=s->table;
s->type= JT_REF;
while (keyuse->table == table)
{
@@ -1051,7 +1085,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
if (keyuse->val->type() != Item::NULL_ITEM)
{
- if (!((~const_table_map) & keyuse->used_tables))
+ if (!((~join->const_table_map) & keyuse->used_tables))
const_ref|= (key_map) 1 << keyuse->keypart;
else
refs|=keyuse->used_tables;
@@ -1065,10 +1099,22 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
if (const_ref == eq_part)
{ // Found everything for ref.
+ int tmp;
+ ref_changed = 1;
s->type=JT_CONST;
- const_table_map|=table->map;
+ join->const_table_map|=table->map;
set_position(join,const_count++,s,start_keyuse);
- ref_changed = 1;
+ if (create_ref_for_key(join, s, start_keyuse,
+ join->const_table_map))
+ DBUG_RETURN(1);
+ if ((tmp=join_read_const_table(s,
+ join->positions+const_count-1)))
+ {
+ if (tmp > 0)
+ DBUG_RETURN(1); // Fatal error
+ }
+ else
+ found_const_table_map|= table->map;
break;
}
else
@@ -1077,7 +1123,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
}
}
}
- } while (const_table_map & found_ref && ref_changed);
+ } while (join->const_table_map & found_ref && ref_changed);
/* Calc how many (possible) matched records in each table */
@@ -1093,8 +1139,10 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
s->found_records=s->records=s->table->file->records;
s->read_time=(ha_rows) s->table->file->scan_time();
- /* Set a max range of how many seeks we can expect when using keys */
- /* This was (s->read_time*5), but this was too low with small rows */
+ /*
+ Set a max range of how many seeks we can expect when using keys
+ This was (s->read_time*5), but this was too low with small rows
+ */
s->worst_seeks= (double) s->found_records / 5;
if (s->worst_seeks < 2.0) // Fix for small tables
s->worst_seeks=2.0;
@@ -1105,15 +1153,14 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
ha_rows records;
if (!select)
- select=make_select(s->table,const_table_map,
- 0,
+ select=make_select(s->table, join->const_table_map,
+ join->const_table_map,
and_conds(conds,s->on_expr),&error);
records=get_quick_record_count(select,s->table, s->const_keys,
join->row_limit);
s->quick=select->quick;
s->needed_reg=select->needed_reg;
select->quick=0;
- select->read_tables=const_table_map;
if (records != HA_POS_ERROR)
{
s->found_records=records;
@@ -1128,10 +1175,10 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
join->map2table=stat_ref;
join->table= join->all_tables=table_vector;
join->const_tables=const_count;
- join->const_table_map=const_table_map;
+ join->found_const_table_map=found_const_table_map;
if (join->const_tables != join->tables)
- find_best_combination(join,all_table_map & ~const_table_map);
+ find_best_combination(join,all_table_map & ~join->const_table_map);
else
{
memcpy((gptr) join->best_positions,(gptr) join->positions,
@@ -2040,12 +2087,10 @@ prev_record_reads(JOIN *join,table_map found_ref)
static bool
get_best_combination(JOIN *join)
{
- uint i,key,tablenr;
+ uint i,tablenr;
table_map used_tables;
- TABLE *table;
JOIN_TAB *join_tab,*j;
KEYUSE *keyuse;
- KEY *keyinfo;
uint table_count;
THD *thd=join->thd;
@@ -2054,8 +2099,6 @@ get_best_combination(JOIN *join)
(JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)*table_count)))
return TRUE;
- join->const_tables=0; /* for checking */
- join->const_table_map=0;
join->full_join=0;
used_tables=0;
@@ -2064,169 +2107,165 @@ get_best_combination(JOIN *join)
TABLE *form;
*j= *join->best_positions[tablenr].table;
form=join->table[tablenr]=j->table;
- j->ref.key = -1;
- j->ref.key_parts=0;
- j->info=0; // For describe
used_tables|= form->map;
form->reginfo.join_tab=j;
if (!j->on_expr)
form->reginfo.not_exists_optimize=0; // Only with LEFT JOIN
+ if (j->type == JT_CONST)
+ continue; // Handled in make_join_stat..
+
+ j->ref.key = -1;
+ j->ref.key_parts=0;
if (j->type == JT_SYSTEM)
- {
- j->table->const_table=1;
- if (join->const_tables == tablenr)
- {
- join->const_tables++;
- join->const_table_map|=form->map;
- }
continue;
- }
if (!j->keys || !(keyuse= join->best_positions[tablenr].key))
{
j->type=JT_ALL;
if (tablenr != join->const_tables)
join->full_join=1;
}
- else
- {
- uint keyparts,length;
- bool ftkey=(keyuse->keypart == FT_KEYPART);
- /*
- ** Use best key from find_best
- */
- table=j->table;
- key=keyuse->key;
+ else if (create_ref_for_key(join, j, keyuse, used_tables))
+ return TRUE; // Something went wrong
+ }
- keyinfo=table->key_info+key;
- if (ftkey)
- {
- Item_func_match *ifm=(Item_func_match *)keyuse->val;
+ for (i=0 ; i < table_count ; i++)
+ join->map2table[join->join_tab[i].table->tablenr]=join->join_tab+i;
+ update_depend_map(join);
+ return 0;
+}
- length=0;
- keyparts=1;
- ifm->join_key=1;
- }
- else
- {
- keyparts=length=0;
- do
- {
- if (!((~used_tables) & keyuse->used_tables))
- {
- if (keyparts == keyuse->keypart)
- {
- keyparts++;
- length+=keyinfo->key_part[keyuse->keypart].store_length;
- }
- }
- keyuse++;
- } while (keyuse->table == table && keyuse->key == key);
- } /* not ftkey */
-
- /* set up fieldref */
- keyinfo=table->key_info+key;
- j->ref.key_parts=keyparts;
- j->ref.key_length=length;
- j->ref.key=(int) key;
- if (!(j->ref.key_buff= (byte*) thd->calloc(ALIGN_SIZE(length)*2)) ||
- !(j->ref.key_copy= (store_key**) thd->alloc((sizeof(store_key*) *
- (keyparts+1)))) ||
- !(j->ref.items= (Item**) thd->alloc(sizeof(Item*)*keyparts)))
- {
- return TRUE;
- }
- j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length);
- j->ref.key_err=1;
- keyuse=join->best_positions[tablenr].key;
- store_key **ref_key=j->ref.key_copy;
- byte *key_buff=j->ref.key_buff;
- if (ftkey)
- {
- j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
- if (keyuse->used_tables)
- return TRUE; // not supported yet. SerG
+static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
+ table_map used_tables)
+{
+ KEYUSE *keyuse=org_keyuse;
+ bool ftkey=(keyuse->keypart == FT_KEYPART);
+ THD *thd= join->thd;
+ uint keyparts,length,key;
+ TABLE *table;
+ KEY *keyinfo;
- j->type=JT_FT;
- }
- else
- {
- for (i=0 ; i < keyparts ; keyuse++,i++)
- {
- while (keyuse->keypart != i ||
- ((~used_tables) & keyuse->used_tables))
- keyuse++; /* Skip other parts */
-
- uint maybe_null= test(keyinfo->key_part[i].null_bit);
- j->ref.items[i]=keyuse->val; // Save for cond removal
- if (!keyuse->used_tables &&
- !(join->select_options & SELECT_DESCRIBE))
- { // Compare against constant
- store_key_item *tmp=new store_key_item(thd,
- keyinfo->key_part[i].field,
- (char*)key_buff +
- maybe_null,
- maybe_null ?
- (char*) key_buff : 0,
- keyinfo->key_part[i].length,
- keyuse->val);
- if (thd->fatal_error)
- {
- return TRUE;
- }
- tmp->copy();
- }
- else
- *ref_key++= get_store_key(join->thd,
- keyuse,join->const_table_map,
- &keyinfo->key_part[i],
- (char*) key_buff,maybe_null);
- key_buff+=keyinfo->key_part[i].store_length;
- }
- } /* not ftkey */
- *ref_key=0; // end_marker
- if (j->type == JT_FT) /* no-op */;
- else if (j->type == JT_CONST)
+ /*
+ ** Use best key from find_best
+ */
+ table=j->table;
+ key=keyuse->key;
+ keyinfo=table->key_info+key;
+
+ if (ftkey)
+ {
+ Item_func_match *ifm=(Item_func_match *)keyuse->val;
+
+ length=0;
+ keyparts=1;
+ ifm->join_key=1;
+ }
+ else
+ {
+ keyparts=length=0;
+ do
+ {
+ if (!((~used_tables) & keyuse->used_tables))
{
- j->table->const_table=1;
- if (join->const_tables == tablenr)
+ if (keyparts == keyuse->keypart)
{
- join->const_tables++;
- join->const_table_map|=form->map;
+ keyparts++;
+ length+=keyinfo->key_part[keyuse->keypart].store_length;
}
}
- else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) != HA_NOSAME) ||
- keyparts != keyinfo->key_parts)
- j->type=JT_REF; /* Must read with repeat */
- else if (ref_key == j->ref.key_copy)
- { /* Should never be reached */
- /*
- This happen if we are using a constant expression in the ON part
- of an LEFT JOIN.
- SELECT * FROM a LEFT JOIN b ON b.key=30
- Here we should not mark the table as a 'const' as a field may
- have a 'normal' value or a NULL value.
- */
- j->type=JT_CONST;
- if (join->const_tables == tablenr)
+ keyuse++;
+ } while (keyuse->table == table && keyuse->key == key);
+ } /* not ftkey */
+
+ /* set up fieldref */
+ keyinfo=table->key_info+key;
+ j->ref.key_parts=keyparts;
+ j->ref.key_length=length;
+ j->ref.key=(int) key;
+ if (!(j->ref.key_buff= (byte*) thd->calloc(ALIGN_SIZE(length)*2)) ||
+ !(j->ref.key_copy= (store_key**) thd->alloc((sizeof(store_key*) *
+ (keyparts+1)))) ||
+ !(j->ref.items= (Item**) thd->alloc(sizeof(Item*)*keyparts)))
+ {
+ return TRUE;
+ }
+ j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length);
+ j->ref.key_err=1;
+ keyuse=org_keyuse;
+
+ store_key **ref_key=j->ref.key_copy;
+ byte *key_buff=j->ref.key_buff;
+ if (ftkey)
+ {
+ j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
+ if (keyuse->used_tables)
+ return TRUE; // not supported yet. SerG
+
+ j->type=JT_FT;
+ }
+ else
+ {
+ uint i;
+ for (i=0 ; i < keyparts ; keyuse++,i++)
+ {
+ while (keyuse->keypart != i ||
+ ((~used_tables) & keyuse->used_tables))
+ keyuse++; /* Skip other parts */
+
+ uint maybe_null= test(keyinfo->key_part[i].null_bit);
+ j->ref.items[i]=keyuse->val; // Save for cond removal
+ if (!keyuse->used_tables &&
+ !(join->select_options & SELECT_DESCRIBE))
+ { // Compare against constant
+ store_key_item *tmp=new store_key_item(thd,
+ keyinfo->key_part[i].field,
+ (char*)key_buff +
+ maybe_null,
+ maybe_null ?
+ (char*) key_buff : 0,
+ keyinfo->key_part[i].length,
+ keyuse->val);
+ if (thd->fatal_error)
{
- join->const_tables++;
- join->const_table_map|=form->map;
+ return TRUE;
}
+ tmp->copy();
}
else
- j->type=JT_EQ_REF;
- }
+ *ref_key++= get_store_key(thd,
+ keyuse,join->const_table_map,
+ &keyinfo->key_part[i],
+ (char*) key_buff,maybe_null);
+ key_buff+=keyinfo->key_part[i].store_length;
+ }
+ } /* not ftkey */
+ *ref_key=0; // end_marker
+ if (j->type == JT_FT) /* no-op */;
+ else if (j->type == JT_CONST)
+ j->table->const_table=1;
+ else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY))
+ != HA_NOSAME) ||
+ keyparts != keyinfo->key_parts)
+ j->type=JT_REF; /* Must read with repeat */
+ else if (ref_key == j->ref.key_copy)
+ { /* Should never be reached */
+ /*
+ This happen if we are using a constant expression in the ON part
+ of an LEFT JOIN.
+ SELECT * FROM a LEFT JOIN b ON b.key=30
+ Here we should not mark the table as a 'const' as a field may
+ have a 'normal' value or a NULL value.
+ */
+ j->type=JT_CONST;
}
-
- for (i=0 ; i < table_count ; i++)
- join->map2table[join->join_tab[i].table->tablenr]=join->join_tab+i;
- update_depend_map(join);
+ else
+ j->type=JT_EQ_REF;
return 0;
}
+
static store_key *
get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
KEY_PART_INFO *key_part, char *key_buff, uint maybe_null)
@@ -3163,13 +3202,13 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
{
/*
- ** Handles this special case for some ODBC applications:
- ** The are requesting the row that was just updated with a auto_increment
- ** value with this construct:
- **
- ** SELECT * from table_name where auto_increment_column IS NULL
- ** This will be changed to:
- ** SELECT * from table_name where auto_increment_column = LAST_INSERT_ID
+ Handles this special case for some ODBC applications:
+ The are requesting the row that was just updated with a auto_increment
+ value with this construct:
+
+ SELECT * from table_name where auto_increment_column IS NULL
+ This will be changed to:
+ SELECT * from table_name where auto_increment_column = LAST_INSERT_ID
*/
Item_func_isnull *func=(Item_func_isnull*) cond;
@@ -4365,45 +4404,44 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last)
*****************************************************************************/
static int
-join_read_const_tables(JOIN *join)
+join_read_const_table(JOIN_TAB *tab, POSITION *pos)
{
- uint i;
int error;
- DBUG_ENTER("join_read_const_tables");
- for (i=0 ; i < join->const_tables ; i++)
- {
- TABLE *form=join->table[i];
- form->null_row=0;
- form->status=STATUS_NO_RECORD;
-
- if (join->join_tab[i].type == JT_SYSTEM)
- {
- if ((error=join_read_system(join->join_tab+i)))
- { // Info for DESCRIBE
- join->join_tab[i].info="const row not found";
- join->best_positions[i].records_read=0.0;
- if (!form->outer_join || error > 0)
- DBUG_RETURN(error);
- }
- }
- else
- {
- if ((error=join_read_const(join->join_tab+i)))
- {
- join->join_tab[i].info="unique row not found";
- join->best_positions[i].records_read=0.0;
- if (!form->outer_join || error > 0)
- DBUG_RETURN(error);
- }
+ DBUG_ENTER("join_read_const_table");
+ TABLE *table=tab->table;
+ table->const_table=1;
+ table->null_row=0;
+ table->status=STATUS_NO_RECORD;
+
+ if (tab->type == JT_SYSTEM)
+ {
+ if ((error=join_read_system(tab)))
+ { // Info for DESCRIBE
+ tab->info="const row not found";
+ /* Mark for EXPLAIN that the row was not found */
+ pos->records_read=0.0;
+ if (!table->outer_join || error > 0)
+ DBUG_RETURN(error);
}
- if (join->join_tab[i].on_expr && !form->null_row)
+ }
+ else
+ {
+ if ((error=join_read_const(tab)))
{
- if ((form->null_row= test(join->join_tab[i].on_expr->val_int() == 0)))
- empty_record(form);
+ tab->info="unique row not found";
+ /* Mark for EXPLAIN that the row was not found */
+ pos->records_read=0.0;
+ if (!table->outer_join || error > 0)
+ DBUG_RETURN(error);
}
- if (!form->null_row)
- form->maybe_null=0;
}
+ if (tab->on_expr && !table->null_row)
+ {
+ if ((table->null_row= test(tab->on_expr->val_int() == 0)))
+ empty_record(table);
+ }
+ if (!table->null_row)
+ table->maybe_null=0;
DBUG_RETURN(0);
}
@@ -4415,7 +4453,8 @@ join_read_system(JOIN_TAB *tab)
int error;
if (table->status & STATUS_GARBAGE) // If first read
{
- if ((error=table->file->rnd_first(table->record[0])))
+ if ((error=table->file->read_first_row(table->record[0],
+ table->primary_key)))
{
if (error != HA_ERR_END_OF_FILE)
{
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 9eb287c8845..befa1efde53 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -158,7 +158,7 @@ class JOIN {
uint send_group_parts;
bool sort_and_group,first_record,full_join,group, no_field_update;
bool do_send_rows;
- table_map const_table_map,outer_join;
+ table_map const_table_map,found_const_table_map,outer_join;
ha_rows send_records,found_records,examined_rows,row_limit;
POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1];
double best_read;