diff options
Diffstat (limited to 'sql/sql_class.h')
-rw-r--r-- | sql/sql_class.h | 151 |
1 files changed, 148 insertions, 3 deletions
diff --git a/sql/sql_class.h b/sql/sql_class.h index 152bf0617cd..f59afe52601 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5708,17 +5708,18 @@ public: class select_unit :public select_result_interceptor { +public: uint curr_step, prev_step, curr_sel; enum sub_select_type step; public: - Item_int *intersect_mark; TMP_TABLE_PARAM tmp_table_param; + /* Number of additional (hidden) field of the used temporary table */ + int addon_cnt; int write_err; /* Error code from the last send_data->ha_write_row call. */ TABLE *table; select_unit(THD *thd_arg): - select_result_interceptor(thd_arg), - intersect_mark(0), table(0) + select_result_interceptor(thd_arg), addon_cnt(0), table(0) { init(); tmp_table_param.init(); @@ -5735,6 +5736,9 @@ public: virtual bool postponed_prepare(List<Item> &types) { return false; } int send_data(List<Item> &items); + int write_record(); + int update_counter(Field *counter, longlong value); + int delete_record(); bool send_eof(); virtual bool flush(); void cleanup(); @@ -5753,7 +5757,148 @@ public: step= UNION_TYPE; write_err= 0; } + virtual void change_select(); + virtual bool force_enable_index_if_needed() { return false; } +}; + + +/** + @class select_unit_ext + + The class used when processing rows produced by operands of query expressions + containing INTERSECT ALL and/or EXCEPT all operations. One or two extra fields + of the temporary to store the rows of the partial and final result can be employed. + Both of them contain counters. The second additional field is used only when + the processed query expression contains INTERSECT ALL. + + Consider how these extra fields are used. + + Let + table t1 (f char(8)) + table t2 (f char(8)) + table t3 (f char(8)) + contain the following sets: + ("b"),("a"),("d"),("c"),("b"),("a"),("c"),("a") + ("c"),("b"),("c"),("c"),("a"),("b"),("g") + ("c"),("a"),("b"),("d"),("b"),("e") + + - Let's demonstrate how the the set operation INTERSECT ALL is proceesed + for the query + SELECT f FROM t1 INTERSECT ALL SELECT f FROM t2 + + When send_data() is called for the rows of the first operand we put + the processed record into the temporary table if there was no such record + setting dup_cnt field to 1 and add_cnt field to 0 and increment the + counter in the dup_cnt field by one otherwise. We get + + |add_cnt|dup_cnt| f | + |0 |2 |b | + |0 |3 |a | + |0 |1 |d | + |0 |2 |c | + + The call of send_eof() for the first operand swaps the values stored in + dup_cnt and add_cnt. After this, we'll see the following rows in the + temporary table + + |add_cnt|dup_cnt| f | + |2 |0 |b | + |3 |0 |a | + |1 |0 |d | + |2 |0 |c | + + When send_data() is called for the rows of the second operand we increment + the counter in dup_cnt if the processed row is found in the table and do + nothing otherwise. As a result we get + + |add_cnt|dup_cnt| f | + |2 |2 |b | + |3 |1 |a | + |1 |0 |d | + |2 |3 |c | + + At the call of send_eof() for the second operand first we disable index. + Then for each record, the minimum of counters from dup_cnt and add_cnt m is + taken. If m == 0 then the record is deleted. Otherwise record is replaced + with m copies of it. Yet the counter in this copies are set to 1 for + dup_cnt and to 0 for add_cnt + + |add_cnt|dup_cnt| f | + |0 |1 |b | + |0 |1 |b | + |0 |1 |a | + |0 |1 |c | + |0 |1 |c | + + - Let's demonstrate how the the set operation EXCEPT ALL is proceesed + for the query + SELECT f FROM t1 EXCEPT ALL SELECT f FROM t3 + + Only one additional counter field dup_cnt is used for EXCEPT ALL. + After the first operand has been processed we have in the temporary table + + |dup_cnt| f | + |2 |b | + |3 |a | + |1 |d | + |2 |c | + + When send_data() is called for the rows of the second operand we decrement + the counter in dup_cnt if the processed row is found in the table and do + nothing otherwise. If the counter becomes 0 we delete the record + + |dup_cnt| f | + |2 |a | + |1 |c | + + Finally at the call of send_eof() for the second operand we disable index + unfold rows adding duplicates + + |dup_cnt| f | + |1 |a | + |1 |a | + |1 |c | + */ + +class select_unit_ext :public select_unit +{ +public: + select_unit_ext(THD *thd_arg): + select_unit(thd_arg), increment(0), is_index_enabled(TRUE), + curr_op_type(UNSPECIFIED) + { + }; + int send_data(List<Item> &items); void change_select(); + int unfold_record(int cnt); + bool send_eof(); + bool force_enable_index_if_needed() + { + is_index_enabled= true; + return true; + } + bool disable_index_if_needed(SELECT_LEX *curr_sl); + + /* + How to change increment/decrement the counter in duplicate_cnt field + when processing a record produced by the current operand in send_data(). + The value can be 1 or -1 + */ + int increment; + /* TRUE <=> the index of the result temporary table is enabled */ + bool is_index_enabled; + /* The type of the set operation currently executed */ + enum set_op_type curr_op_type; + /* + Points to the extra field of the temporary table where + duplicate counters are stored + */ + Field *duplicate_cnt; + /* + Points to the extra field of the temporary table where additional + counters used only for INTERSECT ALL operations are stored + */ + Field *additional_cnt; }; class select_union_recursive :public select_unit |