summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Petrunya <psergey@askmonty.org>2013-09-17 15:01:34 +0400
committerSergey Petrunya <psergey@askmonty.org>2013-09-17 15:01:34 +0400
commitabf4a910f29b230efbb42eda1199533fb5b93173 (patch)
tree1b5e923e1fa6eeb5d66670b2c91bfd2c65337e2e
parent69c386d9a69aa73418160fae3626762213f649cc (diff)
downloadmariadb-git-abf4a910f29b230efbb42eda1199533fb5b93173.tar.gz
[SHOW] EXPLAIN UPDATE/DELETE
- Make QPF structures store data members, not strings. This is not fully possible, because table names (and hence key names, etc) can be deleted, and we have to store strings.
-rw-r--r--sql/opt_qpf.cc201
-rw-r--r--sql/opt_qpf.h95
-rw-r--r--sql/opt_range.cc100
-rw-r--r--sql/opt_range.h22
-rw-r--r--sql/sql_select.cc108
5 files changed, 379 insertions, 147 deletions
diff --git a/sql/opt_qpf.cc b/sql/opt_qpf.cc
index 8155f28acb7..d3fd88ce9bd 100644
--- a/sql/opt_qpf.cc
+++ b/sql/opt_qpf.cc
@@ -1,6 +1,18 @@
/*
- TODO MP AB copyright
-*/
+ Copyright (c) 2013 Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
@@ -309,6 +321,11 @@ int QPF_table_access::print_explain(select_result_sink *output, uint8 explain_fl
uint select_id, const char *select_type,
bool using_temporary, bool using_filesort)
{
+ const CHARSET_INFO *cs= system_charset_info;
+ const char *hash_key_prefix= "#hash#";
+ bool is_hj= (type == JT_HASH || type == JT_HASH_NEXT ||
+ type == JT_HASH_RANGE || type == JT_HASH_INDEX_MERGE);
+
List<Item> item_list;
Item *item_null= new Item_null();
//const CHARSET_INFO *cs= system_charset_info;
@@ -349,14 +366,62 @@ int QPF_table_access::print_explain(select_result_sink *output, uint8 explain_fl
item_list.push_back(item_null);
/* `key` */
- if (key_set)
- push_string(&item_list, &key);
+ StringBuffer<64> key_str;
+ if (key.key_name)
+ {
+ if (is_hj)
+ key_str.append(hash_key_prefix, strlen(hash_key_prefix), cs);
+
+ key_str.append(key.key_name);
+
+ if (is_hj && type != JT_HASH)
+ key_str.append(':');
+ }
+
+ if (quick_info)
+ {
+ StringBuffer<64> buf2;
+ quick_info->print_key(&buf2);
+ key_str.append(buf2);
+ }
+ if (type == JT_HASH_NEXT)
+ key_str.append(hash_next_key.key_name);
+
+ if (key_str.length() > 0)
+ push_string(&item_list, &key_str);
else
item_list.push_back(item_null);
/* `key_len` */
- if (key_len_set)
- push_string(&item_list, &key_len);
+ StringBuffer<64> key_len_str;
+
+ if (key.key_len != (uint)-1)
+ {
+ char buf[64];
+ size_t length;
+ length= longlong10_to_str(key.key_len, buf, 10) - buf;
+ key_len_str.append(buf, length);
+ if (is_hj && type != JT_HASH)
+ key_len_str.append(':');
+ }
+
+ if (quick_info)
+ {
+ StringBuffer<64> buf2;
+ quick_info->print_key_len(&buf2);
+ key_len_str.append(buf2);
+ }
+
+ if (type == JT_HASH_NEXT)
+ {
+ char buf[64];
+ size_t length;
+ length= longlong10_to_str(hash_next_key.key_len, buf, 10) - buf;
+ key_len_str.append(buf, length);
+ }
+
+ if (key_len_str.length() > 0)
+ push_string(&item_list, &key_len_str);
else
item_list.push_back(item_null);
@@ -416,7 +481,6 @@ int QPF_table_access::print_explain(select_result_sink *output, uint8 explain_fl
extra_buf.append(STRING_WITH_LEN("Using filesort"));
}
- const CHARSET_INFO *cs= system_charset_info;
item_list.push_back(new Item_string(extra_buf.ptr(), extra_buf.length(), cs));
if (output->send_data(item_list))
@@ -476,7 +540,7 @@ void QPF_table_access::append_tag_name(String *str, enum Extra_tag tag)
{
// quick select
str->append(STRING_WITH_LEN("Using "));
- str->append(quick_info);
+ quick_info->print_extra(str);
break;
}
case ET_RANGE_CHECKED_FOR_EACH_RECORD:
@@ -535,6 +599,127 @@ void QPF_table_access::append_tag_name(String *str, enum Extra_tag tag)
}
+/*
+ This is called for top-level QPF_quick_select only. The point of this
+ function is:
+ - index_merge should print $index_merge_type (child, ...)
+ - 'range' should not print anything.
+*/
+
+void QPF_quick_select::print_extra(String *str)
+{
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
+ {
+ /* print nothing */
+ }
+ else
+ print_extra_recursive(str);
+}
+
+
+void QPF_quick_select::print_extra_recursive(String *str)
+{
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC)
+ {
+ str->append(range.key_name);
+ }
+ else
+ {
+ str->append(get_name_by_type());
+ str->append('(');
+ List_iterator_fast<QPF_quick_select> it (children);
+ QPF_quick_select* child;
+ bool first= true;
+ while ((child = it++))
+ {
+ if (first)
+ first= false;
+ else
+ str->append(',');
+
+ child->print_extra_recursive(str);
+ }
+ str->append(')');
+ }
+}
+
+
+const char * QPF_quick_select::get_name_by_type()
+{
+ switch (quick_type) {
+ case QUICK_SELECT_I::QS_TYPE_INDEX_MERGE:
+ return "sort_union";
+ case QUICK_SELECT_I::QS_TYPE_ROR_UNION:
+ return "union";
+ case QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT:
+ return "intersect";
+ case QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT:
+ return "sort_intersect";
+ default:
+ DBUG_ASSERT(0);
+ return "Oops";
+ }
+}
+
+
+/*
+ This prints a comma-separated list of used indexes, ignoring nesting
+*/
+
+void QPF_quick_select::print_key(String *str)
+{
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
+ {
+ if (str->length() > 0)
+ str->append(',');
+ str->append(range.key_name);
+ }
+ else
+ {
+ List_iterator_fast<QPF_quick_select> it (children);
+ QPF_quick_select* child;
+ while ((child = it++))
+ {
+ child->print_key(str);
+ }
+ }
+}
+
+
+/*
+ This prints a comma-separated list of used key_lengths, ignoring nesting
+*/
+
+void QPF_quick_select::print_key_len(String *str)
+{
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
+ {
+ char buf[64];
+ size_t length;
+ length= longlong10_to_str(range.key_len, buf, 10) - buf;
+ if (str->length() > 0)
+ str->append(',');
+ str->append(buf, length);
+ }
+ else
+ {
+ List_iterator_fast<QPF_quick_select> it (children);
+ QPF_quick_select* child;
+ while ((child = it++))
+ {
+ child->print_key_len(str);
+ }
+ }
+}
+
+
int QPF_delete::print_explain(QPF_query *query, select_result_sink *output,
uint8 explain_flags)
{
diff --git a/sql/opt_qpf.h b/sql/opt_qpf.h
index f8f0004c669..2ab32967c8b 100644
--- a/sql/opt_qpf.h
+++ b/sql/opt_qpf.h
@@ -1,3 +1,20 @@
+/*
+ Copyright (c) 2013 Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
/**************************************************************************************
Query Plan Footprint (QPF) structures
@@ -286,6 +303,41 @@ typedef struct st_qpf_bka_type
/*
+ Data about how an index is used by some access method
+*/
+class QPF_index_use : public Sql_alloc
+{
+public:
+ const char *key_name;
+ uint key_len;
+ /* will add #keyparts here if we implement EXPLAIN FORMAT=JSON */
+};
+
+
+/*
+ QPF for quick range selects, as well as index_merge select
+*/
+class QPF_quick_select : public Sql_alloc
+{
+public:
+ int quick_type;
+
+ /* This is used when quick_type == QUICK_SELECT_I::QS_TYPE_RANGE */
+ QPF_index_use range;
+
+ /* Used in all other cases */
+ List<QPF_quick_select> children;
+
+ void print_extra(String *str);
+ void print_key(String *str);
+ void print_key_len(String *str);
+private:
+ void print_extra_recursive(String *str);
+ const char *get_name_by_type();
+};
+
+
+/*
Query Plan Footprint for a JOIN_TAB.
*/
class QPF_table_access : public Sql_alloc
@@ -302,29 +354,33 @@ public:
int sjm_nest_select_id;
/* id and 'select_type' are cared-of by the parent QPF_select */
- TABLE *table;
- StringBuffer<64> table_name;
+ StringBuffer<32> table_name;
enum join_type type;
- StringBuffer<64> used_partitions;
+ StringBuffer<32> used_partitions;
bool used_partitions_set;
-
- key_map possible_keys;
- StringBuffer<64> possible_keys_str;
- /* Not used? */
- uint key_no;
- uint key_length;
-
- bool key_set; /* not set means 'NULL' should be printed */
- StringBuffer<64> key;
-
- bool key_len_set; /* not set means 'NULL' should be printed */
- StringBuffer<64> key_len;
+ /* Empty strings means "NULL" will be printed */
+ StringBuffer<32> possible_keys_str;
+
+ /*
+ Index use: key name and length.
+ Note: that when one is accessing I_S tables, those may show use of
+ non-existant indexes.
+ key.key_name == NULL means 'NULL' will be shown in tabular output.
+ key.key_len == (uint)-1 means 'NULL' will be shown in tabular output.
+ */
+ QPF_index_use key;
+
+ /*
+ when type==JT_HASH_NEXT, this stores the real index.
+ */
+ QPF_index_use hash_next_key;
+
bool ref_set; /* not set means 'NULL' should be printed */
- StringBuffer<64> ref;
+ StringBuffer<32> ref;
bool rows_set; /* not set means 'NULL' should be printed */
ha_rows rows;
@@ -339,7 +395,7 @@ public:
Dynamic_array<enum Extra_tag> extra_tags;
// Valid if ET_USING tag is present
- StringBuffer<64> quick_info;
+ QPF_quick_select *quick_info;
// Valid if ET_USING_INDEX_FOR_GROUP_BY is present
bool loose_scan_is_scanning;
@@ -348,13 +404,12 @@ public:
key_map range_checked_map;
// valid with ET_USING_MRR
- StringBuffer<64> mrr_type;
+ StringBuffer<32> mrr_type;
// valid with ET_USING_JOIN_BUFFER
QPF_BKA_TYPE bka_type;
- //TABLE *firstmatch_table;
- StringBuffer<64> firstmatch_table_name;
+ StringBuffer<32> firstmatch_table_name;
int print_explain(select_result_sink *output, uint8 explain_flags,
uint select_id, const char *select_type,
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 27913f0aa8e..c216a035794 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -11940,78 +11940,106 @@ void QUICK_SELECT_I::add_key_name(String *str, bool *first)
}
-void QUICK_RANGE_SELECT::add_info_string(String *str)
+void QUICK_RANGE_SELECT::save_info(QPF_quick_select *qpf)
{
- bool first= TRUE;
-
- add_key_name(str, &first);
+ qpf->quick_type= QS_TYPE_RANGE;
+ qpf->range.key_name= head->key_info[index].name;
+ qpf->range.key_len= max_used_key_length;
+}
+
+
+void QUICK_GROUP_MIN_MAX_SELECT::save_info(QPF_quick_select *qpf)
+{
+ qpf->quick_type= QS_TYPE_GROUP_MIN_MAX;
+ qpf->range.key_name= head->key_info[index].name;
+ qpf->range.key_len= max_used_key_length;
}
-void QUICK_INDEX_MERGE_SELECT::add_info_string(String *str)
+
+void QUICK_INDEX_SORT_SELECT::save_info(QPF_quick_select *qpf)
{
+ qpf->quick_type= get_type();
+
QUICK_RANGE_SELECT *quick;
- bool first= TRUE;
+ QPF_quick_select *child_qpf;
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
-
- str->append(STRING_WITH_LEN("sort_union("));
while ((quick= it++))
{
- quick->add_key_name(str, &first);
+ child_qpf= new QPF_quick_select;
+ qpf->children.push_back(child_qpf);
+ quick->save_info(child_qpf);
}
+
if (pk_quick_select)
- pk_quick_select->add_key_name(str, &first);
- str->append(')');
+ {
+ child_qpf= new QPF_quick_select;
+ qpf->children.push_back(child_qpf);
+ pk_quick_select->save_info(child_qpf);
+ }
}
-void QUICK_INDEX_INTERSECT_SELECT::add_info_string(String *str)
+/*
+ Same as QUICK_INDEX_SORT_SELECT::save_info(), but primary key is printed
+ first
+*/
+void QUICK_INDEX_INTERSECT_SELECT::save_info(QPF_quick_select *qpf)
{
- QUICK_RANGE_SELECT *quick;
- bool first= TRUE;
- List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ qpf->quick_type= get_type();
+ QPF_quick_select *child_qpf;
- str->append(STRING_WITH_LEN("sort_intersect("));
if (pk_quick_select)
- pk_quick_select->add_key_name(str, &first);
+ {
+ child_qpf= new QPF_quick_select;
+ qpf->children.push_back(child_qpf);
+ pk_quick_select->save_info(child_qpf);
+ }
+
+ QUICK_RANGE_SELECT *quick;
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
while ((quick= it++))
{
- quick->add_key_name(str, &first);
+ child_qpf= new QPF_quick_select;
+ qpf->children.push_back(child_qpf);
+ quick->save_info(child_qpf);
}
- str->append(')');
+
}
-void QUICK_ROR_INTERSECT_SELECT::add_info_string(String *str)
+
+void QUICK_ROR_INTERSECT_SELECT::save_info(QPF_quick_select *qpf)
{
- bool first= TRUE;
+ qpf->quick_type= get_type();
+
QUICK_SELECT_WITH_RECORD *qr;
List_iterator_fast<QUICK_SELECT_WITH_RECORD> it(quick_selects);
-
- str->append(STRING_WITH_LEN("intersect("));
while ((qr= it++))
{
- qr->quick->add_key_name(str, &first);
+ QPF_quick_select *child_qpf= new QPF_quick_select;
+ qpf->children.push_back(child_qpf);
+ qr->quick->save_info(child_qpf);
}
+
if (cpk_quick)
- cpk_quick->add_key_name(str, &first);
- str->append(')');
+ {
+ QPF_quick_select *child_qpf= new QPF_quick_select;
+ qpf->children.push_back(child_qpf);
+ cpk_quick->save_info(child_qpf);
+ }
}
-void QUICK_ROR_UNION_SELECT::add_info_string(String *str)
+void QUICK_ROR_UNION_SELECT::save_info(QPF_quick_select *qpf)
{
+ qpf->quick_type= get_type();
+
QUICK_SELECT_I *quick;
- bool first= TRUE;
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
-
- str->append(STRING_WITH_LEN("union("));
while ((quick= it++))
{
- if (first)
- first= FALSE;
- else
- str->append(',');
- quick->add_info_string(str);
+ QPF_quick_select *child_qpf= new QPF_quick_select;
+ qpf->children.push_back(child_qpf);
+ quick->save_info(child_qpf);
}
- str->append(')');
}
diff --git a/sql/opt_range.h b/sql/opt_range.h
index d701c7f9201..eeb4e4b77ad 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -52,7 +52,7 @@ typedef struct st_key_part {
Field::imagetype image_type;
} KEY_PART;
-
+class QPF_quick_select;
/*
A "MIN_TUPLE < tbl.key_tuple < MAX_TUPLE" interval.
@@ -345,13 +345,8 @@ public:
void add_key_name(String *str, bool *first);
- /*
- Append text representation of quick select structure (what and how is
- merged) to str. The result is added to "Extra" field in EXPLAIN output.
- This function is implemented only by quick selects that merge other quick
- selects output and/or can produce output suitable for merging.
- */
- virtual void add_info_string(String *str) {}
+ /* Save information about quick select's query plan */
+ virtual void save_info(QPF_quick_select *qpf)= 0;
/*
Return 1 if any index used by this quick select
@@ -478,7 +473,7 @@ public:
{ file->position(record); }
int get_type() { return QS_TYPE_RANGE; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
- void add_info_string(String *str);
+ void save_info(QPF_quick_select *qpf);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
@@ -615,6 +610,7 @@ public:
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
+ void save_info(QPF_quick_select *qpf);
bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);
@@ -663,7 +659,6 @@ public:
int get_next();
int get_type() { return QS_TYPE_INDEX_MERGE; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
- void add_info_string(String *str);
};
class QUICK_INDEX_INTERSECT_SELECT : public QUICK_INDEX_SORT_SELECT
@@ -679,7 +674,7 @@ public:
int get_next();
int get_type() { return QS_TYPE_INDEX_INTERSECT; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
- void add_info_string(String *str);
+ void save_info(QPF_quick_select *qpf);
};
@@ -717,7 +712,7 @@ public:
bool unique_key_range() { return false; }
int get_type() { return QS_TYPE_ROR_INTERSECT; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
- void add_info_string(String *str);
+ void save_info(QPF_quick_select *qpf);
bool is_keys_used(const MY_BITMAP *fields);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
@@ -796,7 +791,7 @@ public:
bool unique_key_range() { return false; }
int get_type() { return QS_TYPE_ROR_UNION; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
- void add_info_string(String *str);
+ void save_info(QPF_quick_select *qpf);
bool is_keys_used(const MY_BITMAP *fields);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
@@ -945,6 +940,7 @@ public:
#endif
bool is_agg_distinct() { return have_agg_distinct; }
bool loose_scan_is_scanning() { return is_index_scan; }
+ void save_info(QPF_quick_select *qpf);
};
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 97f59d80ae2..236ddbe8ed3 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -11172,7 +11172,8 @@ void JOIN::cleanup(bool full)
if (full)
{
/* Save it again */
-#if 0 psergey-todo: remove?
+#if 0
+ psergey-todo: remove?
if (select_lex->select_number != UINT_MAX &&
select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ &&
have_query_plan != QEP_NOT_PRESENT_YET &&
@@ -22576,20 +22577,12 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
TABLE *table=tab->table;
TABLE_LIST *table_list= tab->table->pos_in_table_list;
- char buff2[512], buff3[512], buff4[512];
- char keylen_str_buf[64];
+ char buff4[512];
my_bool key_read;
char table_name_buffer[SAFE_NAME_LEN];
- String tmp2(buff2,sizeof(buff2),cs);
- String tmp3(buff3,sizeof(buff3),cs);
String tmp4(buff4,sizeof(buff4),cs);
- char hash_key_prefix[]= "#hash#";
KEY *key_info= 0;
uint key_len= 0;
- bool is_hj= tab->type == JT_HASH || tab->type ==JT_HASH_NEXT;
-
- tmp2.length(0);
- tmp3.length(0);
tmp4.length(0);
quick_type= -1;
QUICK_SELECT_I *quick= NULL;
@@ -22611,6 +22604,9 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
QPF_table_access *qpt= new (output->mem_root) QPF_table_access;
qp_sel->add_table(qpt);
+ qpt->key.key_name= NULL;
+ qpt->key.key_len= (uint)-1;
+ qpt->quick_info= NULL;
/* id */
if (tab->bush_root_tab)
@@ -22685,13 +22681,10 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
qpt->type= tab_type;
/* Build "possible_keys" value */
- qpt->possible_keys= tab->keys;
append_possible_keys(&qpt->possible_keys_str, table, tab->keys);
/* Build "key", "key_len", and "ref" */
- // tmp2 holds key_name
- // tmp3 holds key_length
// tmp4 holds ref
if (tab_type == JT_NEXT)
{
@@ -22703,16 +22696,22 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
key_info= tab->get_keyinfo_by_key_no(tab->ref.key);
key_len= tab->ref.key_length;
}
+
+ /*
+ In STRAIGHT_JOIN queries, there can be join tabs with JT_CONST type
+ that still have quick selects.
+ */
+ if (tab->select && tab->select->quick && tab_type != JT_CONST)
+ {
+ qpt->quick_info= new QPF_quick_select;
+ tab->select->quick->save_info(qpt->quick_info);
+ }
- if (key_info)
+ if (key_info) /* 'index' or 'ref' access */
{
- register uint length;
- if (is_hj)
- tmp2.append(hash_key_prefix, strlen(hash_key_prefix), cs);
- tmp2.append(key_info->name, strlen(key_info->name), cs);
- length= (longlong10_to_str(key_len, keylen_str_buf, 10) -
- keylen_str_buf);
- tmp3.append(keylen_str_buf, length, cs);
+ qpt->key.key_name= key_info->name;
+ qpt->key.key_len= key_len;
+
if (tab->ref.key_parts && tab_type != JT_FT)
{
store_key **ref=tab->ref.key_copy;
@@ -22731,45 +22730,15 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
}
}
}
-
- if (is_hj && tab_type != JT_HASH)
- {
- tmp2.append(':');
- tmp3.append(':');
- }
-
- if (tab_type == JT_HASH_NEXT)
+
+ if (tab_type == JT_HASH_NEXT) /* full index scan + hash join */
{
- register uint length;
- key_info= table->key_info+tab->index;
- key_len= key_info->key_length;
- tmp2.append(key_info->name, strlen(key_info->name), cs);
- length= (longlong10_to_str(key_len, keylen_str_buf, 10) -
- keylen_str_buf);
- tmp3.append(keylen_str_buf, length, cs);
+ qpt->hash_next_key.key_name= table->key_info[tab->index].name;
+ qpt->hash_next_key.key_len= table->key_info[tab->index].key_length;
}
- if (tab->type != JT_CONST && tab->select && quick)
- tab->select->quick->add_keys_and_lengths(&tmp2, &tmp3);
-
- if (key_info || (tab->select && quick))
+ if (key_info)
{
- if (tmp2.length())
- {
- qpt->key.copy(tmp2);
- qpt->key_set= true;
- }
- else
- qpt->key_set= false;
-
- if (tmp3.length())
- {
- qpt->key_len.copy(tmp3);
- qpt->key_len_set= true;
- }
- else
- qpt->key_len_set= false;
-
if (key_info && tab_type != JT_NEXT)
{
qpt->ref.copy(tmp4);
@@ -22786,37 +22755,37 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
{
const char *tmp_buff;
int f_idx;
+ StringBuffer<64> key_name_buf;
if (table_list->has_db_lookup_value)
{
+ /* The "key" has the name of the column referring to the database */
f_idx= table_list->schema_table->idx_field1;
tmp_buff= table_list->schema_table->fields_info[f_idx].field_name;
- tmp2.append(tmp_buff, strlen(tmp_buff), cs);
+ key_name_buf.append(tmp_buff, strlen(tmp_buff), cs);
}
if (table_list->has_table_lookup_value)
{
if (table_list->has_db_lookup_value)
- tmp2.append(',');
+ key_name_buf.append(',');
+
f_idx= table_list->schema_table->idx_field2;
tmp_buff= table_list->schema_table->fields_info[f_idx].field_name;
- tmp2.append(tmp_buff, strlen(tmp_buff), cs);
+ key_name_buf.append(tmp_buff, strlen(tmp_buff), cs);
}
- if (tmp2.length())
+
+ size_t len;
+ if ((len= key_name_buf.length()))
{
- qpt->key.copy(tmp2);
- qpt->key_set= true;
+ char *ptr= (char*)thd->alloc(len+1);
+ memcpy(ptr, key_name_buf.c_ptr_safe(), len+1);
+ qpt->key.key_name= ptr;
+ qpt->key.key_len= -1;
}
- else
- qpt->key_set= false;
}
- else
- qpt->key_set= false;
-
- qpt->key_len_set= false;
qpt->ref_set= false;
}
/* "rows" */
-
if (table_list /* SJM bushes don't have table_list */ &&
table_list->schema_table)
{
@@ -22888,7 +22857,6 @@ int JOIN::save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
{
qpt->push_extra(ET_USING);
- tab->select->quick->add_info_string(&qpt->quick_info);
}
if (tab->select)
{