summaryrefslogtreecommitdiff
path: root/sql/sql_class.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_class.h')
-rw-r--r--sql/sql_class.h151
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