summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Nozdrin <alik@sun.com>2009-11-06 19:13:33 +0300
committerAlexander Nozdrin <alik@sun.com>2009-11-06 19:13:33 +0300
commit6b1d61ecb072aab0f04a4dbaa380309a92ee2b10 (patch)
tree1856f6f3743fb840ae45d1166df3bffe566031e4 /sql
parentae71ffc1c88f2e37320dee98824e6d437a083604 (diff)
parentcb0cca865587da1da071a67e0932dcfaa54a4b0c (diff)
downloadmariadb-git-6b1d61ecb072aab0f04a4dbaa380309a92ee2b10.tar.gz
Manual merge from mysql-trunk-merge.
Diffstat (limited to 'sql')
-rw-r--r--sql/item_subselect.cc1
-rw-r--r--sql/records.cc2
-rw-r--r--sql/records.h4
-rw-r--r--sql/sql_select.cc60
-rw-r--r--sql/sql_select.h7
5 files changed, 72 insertions, 2 deletions
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 335b9f79e78..0ce9c555fea 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1956,6 +1956,7 @@ int subselect_single_select_engine::exec()
tab->read_record.record= tab->table->record[0];
tab->read_record.thd= join->thd;
tab->read_record.ref_length= tab->table->file->ref_length;
+ tab->read_record.unlock_row= rr_unlock_row;
*(last_changed_tab++)= tab;
break;
}
diff --git a/sql/records.cc b/sql/records.cc
index 93b19aefbaf..8fd63d104a4 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -67,6 +67,7 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
info->file= table->file;
info->record= table->record[0];
info->print_error= print_error;
+ info->unlock_row= rr_unlock_row;
table->status=0; /* And it's always found */
if (!table->file->inited)
@@ -192,6 +193,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
}
info->select=select;
info->print_error=print_error;
+ info->unlock_row= rr_unlock_row;
info->ignore_not_found_rows= 0;
table->status=0; /* And it's always found */
diff --git a/sql/records.h b/sql/records.h
index 9207a05f826..ae81a31ee1a 100644
--- a/sql/records.h
+++ b/sql/records.h
@@ -43,11 +43,13 @@ class SQL_SELECT;
struct READ_RECORD
{
typedef int (*Read_func)(READ_RECORD*);
+ typedef void (*Unlock_row_func)(st_join_table *);
typedef int (*Setup_func)(struct st_join_table*);
TABLE *table; /* Head-form */
handler *file;
TABLE **forms; /* head and ref forms */
+ Unlock_row_func unlock_row;
Read_func read_record;
THD *thd;
SQL_SELECT *select;
@@ -72,4 +74,6 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
bool print_error, uint idx);
void end_read_record(READ_RECORD *info);
+void rr_unlock_row(st_join_table *tab);
+
#endif /* SQL_RECORDS_H */
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 310f26cd192..6b67a216341 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -150,6 +150,7 @@ 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);
+static void join_read_key_unlock_row(st_join_table *tab);
static int join_read_always_key(JOIN_TAB *tab);
static int join_read_last_key(JOIN_TAB *tab);
static int join_no_more_records(READ_RECORD *info);
@@ -5736,7 +5737,9 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
}
j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length);
j->ref.key_err=1;
+ j->ref.has_record= FALSE;
j->ref.null_rejecting= 0;
+ j->ref.use_count= 0;
keyuse=org_keyuse;
store_key **ref_key= j->ref.key_copy;
@@ -6569,6 +6572,20 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
DBUG_RETURN(0);
}
+
+/**
+ The default implementation of unlock-row method of READ_RECORD,
+ used in all access methods.
+*/
+
+void rr_unlock_row(st_join_table *tab)
+{
+ READ_RECORD *info= &tab->read_record;
+ info->file->unlock_row();
+}
+
+
+
static void
make_join_readinfo(JOIN *join, ulonglong options)
{
@@ -6584,6 +6601,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
TABLE *table=tab->table;
tab->read_record.table= table;
tab->read_record.file=table->file;
+ tab->read_record.unlock_row= rr_unlock_row;
tab->next_select=sub_select; /* normal select */
/*
@@ -6629,6 +6647,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
delete tab->quick;
tab->quick=0;
tab->read_first_record= join_read_key;
+ tab->read_record.unlock_row= join_read_key_unlock_row;
tab->read_record.read_record= join_no_more_records;
if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread)
@@ -11472,7 +11491,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
else
{
join->thd->warning_info->inc_current_row_for_warning();
- join_tab->read_record.file->unlock_row();
+ join_tab->read_record.unlock_row(join_tab);
}
}
else
@@ -11483,7 +11502,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
*/
join->examined_rows++;
join->thd->warning_info->inc_current_row_for_warning();
- join_tab->read_record.file->unlock_row();
+ join_tab->read_record.unlock_row(join_tab);
}
return NESTED_LOOP_OK;
}
@@ -11843,18 +11862,55 @@ join_read_key(JOIN_TAB *tab)
table->status=STATUS_NOT_FOUND;
return -1;
}
+ /*
+ Moving away from the current record. Unlock the row
+ in the handler if it did not match the partial WHERE.
+ */
+ if (tab->ref.has_record && tab->ref.use_count == 0)
+ {
+ tab->read_record.file->unlock_row();
+ tab->ref.has_record= FALSE;
+ }
error=table->file->index_read_map(table->record[0],
tab->ref.key_buff,
make_prev_keypart_map(tab->ref.key_parts),
HA_READ_KEY_EXACT);
if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
return report_error(table, error);
+
+ if (! error)
+ {
+ tab->ref.has_record= TRUE;
+ tab->ref.use_count= 1;
+ }
+ }
+ else if (table->status == 0)
+ {
+ DBUG_ASSERT(tab->ref.has_record);
+ tab->ref.use_count++;
}
table->null_row=0;
return table->status ? -1 : 0;
}
+/**
+ Since join_read_key may buffer a record, do not unlock
+ it if it was not used in this invocation of join_read_key().
+ Only count locks, thus remembering if the record was left unused,
+ and unlock already when pruning the current value of
+ TABLE_REF buffer.
+ @sa join_read_key()
+*/
+
+static void
+join_read_key_unlock_row(st_join_table *tab)
+{
+ DBUG_ASSERT(tab->ref.use_count);
+ if (tab->ref.use_count)
+ tab->ref.use_count--;
+}
+
/*
ref access method implementation: "read_first" function
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 76b3d1717f4..e049e4ed765 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -61,6 +61,8 @@ class store_key;
typedef struct st_table_ref
{
bool key_err;
+ /** True if something was read into buffer in join_read_key. */
+ bool has_record;
uint key_parts; ///< num of ...
uint key_length; ///< length of key_buff
int key; ///< key no
@@ -88,6 +90,11 @@ typedef struct st_table_ref
table_map depend_map; ///< Table depends on these tables.
/* null byte position in the key_buf. Used for REF_OR_NULL optimization */
uchar *null_ref_key;
+ /*
+ The number of times the record associated with this key was used
+ in the join.
+ */
+ ha_rows use_count;
} TABLE_REF;