summaryrefslogtreecommitdiff
path: root/sql/item_sum.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_sum.cc')
-rw-r--r--sql/item_sum.cc183
1 files changed, 171 insertions, 12 deletions
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 0c85cf53e18..f774ee5a561 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1243,7 +1243,8 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table)
Item_sum_sum::Item_sum_sum(THD *thd, Item_sum_sum *item)
:Item_sum_num(thd, item),
Type_handler_hybrid_field_type(item),
- curr_dec_buff(item->curr_dec_buff)
+ curr_dec_buff(item->curr_dec_buff),
+ count(item->count)
{
/* TODO: check if the following assignments are really needed */
if (Item_sum_sum::result_type() == DECIMAL_RESULT)
@@ -1265,6 +1266,7 @@ void Item_sum_sum::clear()
{
DBUG_ENTER("Item_sum_sum::clear");
null_value=1;
+ count= 0;
if (Item_sum_sum::result_type() == DECIMAL_RESULT)
{
curr_dec_buff= 0;
@@ -1318,25 +1320,57 @@ void Item_sum_sum::fix_length_and_dec()
bool Item_sum_sum::add()
{
DBUG_ENTER("Item_sum_sum::add");
+ add_helper(false);
+ DBUG_RETURN(0);
+}
+
+void Item_sum_sum::add_helper(bool perform_removal)
+{
+ DBUG_ENTER("Item_sum_sum::add_helper");
+
if (Item_sum_sum::result_type() == DECIMAL_RESULT)
{
my_decimal value;
const my_decimal *val= aggr->arg_val_decimal(&value);
if (!aggr->arg_is_null(true))
{
- my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1),
- val, dec_buffs + curr_dec_buff);
+ if (perform_removal)
+ {
+ DBUG_ASSERT(count > 0);
+ my_decimal_sub(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff ^ 1),
+ dec_buffs + curr_dec_buff, val);
+ count--;
+ }
+ else
+ {
+ count++;
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff ^ 1),
+ val, dec_buffs + curr_dec_buff);
+ }
curr_dec_buff^= 1;
- null_value= 0;
+ null_value= (count > 0) ? 0 : 1;
}
}
else
{
- sum+= aggr->arg_val_real();
+ if (perform_removal)
+ sum-= aggr->arg_val_real();
+ else
+ sum+= aggr->arg_val_real();
if (!aggr->arg_is_null(true))
- null_value= 0;
+ {
+ if (perform_removal)
+ {
+ DBUG_ASSERT(count > 0);
+ count--;
+ }
+ else
+ count++;
+
+ null_value= (count > 0) ? 0 : 1;
+ }
}
- DBUG_RETURN(0);
+ DBUG_VOID_RETURN;
}
@@ -1386,6 +1420,13 @@ my_decimal *Item_sum_sum::val_decimal(my_decimal *val)
return val_decimal_from_real(val);
}
+void Item_sum_sum::remove()
+{
+ DBUG_ENTER("Item_sum_sum::remove");
+ add_helper(true);
+ DBUG_VOID_RETURN;
+}
+
/**
Aggregate a distinct row from the distinct hash table.
@@ -1531,6 +1572,19 @@ bool Item_sum_count::add()
return 0;
}
+
+/*
+ Remove a row. This is used by window functions.
+*/
+
+void Item_sum_count::remove()
+{
+ DBUG_ASSERT(aggr->Aggrtype() == Aggregator::SIMPLE_AGGREGATOR);
+ if (aggr->arg_is_null(false))
+ return;
+ count--;
+}
+
longlong Item_sum_count::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -1626,6 +1680,16 @@ bool Item_sum_avg::add()
return FALSE;
}
+void Item_sum_avg::remove()
+{
+ Item_sum_sum::remove();
+ if (!aggr->arg_is_null(true))
+ {
+ DBUG_ASSERT(count > 0);
+ count--;
+ }
+}
+
double Item_sum_avg::val_real()
{
DBUG_ASSERT(fixed == 1);
@@ -2086,6 +2150,8 @@ longlong Item_sum_bit::val_int()
void Item_sum_bit::clear()
{
bits= reset_bits;
+ if (as_window_function)
+ clear_as_window();
}
Item *Item_sum_or::copy_or_same(THD* thd)
@@ -2093,15 +2159,79 @@ Item *Item_sum_or::copy_or_same(THD* thd)
return new (thd->mem_root) Item_sum_or(thd, this);
}
+bool Item_sum_bit::clear_as_window()
+{
+ memset(bit_counters, 0, sizeof(bit_counters));
+ num_values_added= 0;
+ set_bits_from_counters();
+ return 0;
+}
+
+bool Item_sum_bit::remove_as_window(ulonglong value)
+{
+ DBUG_ASSERT(as_window_function);
+ for (int i= 0; i < NUM_BIT_COUNTERS; i++)
+ {
+ if (!bit_counters[i])
+ {
+ // Don't attempt to remove values that were never added.
+ DBUG_ASSERT((value & (1 << i)) == 0);
+ continue;
+ }
+ bit_counters[i]-= (value & (1 << i)) ? 1 : 0;
+ }
+ DBUG_ASSERT(num_values_added > 0);
+ // Prevent overflow;
+ num_values_added = std::min(num_values_added, num_values_added - 1);
+ set_bits_from_counters();
+ return 0;
+}
+
+bool Item_sum_bit::add_as_window(ulonglong value)
+{
+ DBUG_ASSERT(as_window_function);
+ for (int i= 0; i < NUM_BIT_COUNTERS; i++)
+ {
+ bit_counters[i]+= (value & (1 << i)) ? 1 : 0;
+ }
+ // Prevent overflow;
+ num_values_added = std::max(num_values_added, num_values_added + 1);
+ set_bits_from_counters();
+ return 0;
+}
+
+void Item_sum_or::set_bits_from_counters()
+{
+ ulonglong value= 0;
+ for (int i= 0; i < NUM_BIT_COUNTERS; i++)
+ {
+ value|= bit_counters[i] > 0 ? (1 << i) : 0;
+ }
+ bits= value | reset_bits;
+}
bool Item_sum_or::add()
{
ulonglong value= (ulonglong) args[0]->val_int();
if (!args[0]->null_value)
+ {
+ if (as_window_function)
+ return add_as_window(value);
bits|=value;
+ }
return 0;
}
+void Item_sum_xor::set_bits_from_counters()
+{
+ ulonglong value= 0;
+ for (int i= 0; i < NUM_BIT_COUNTERS; i++)
+ {
+ value|= (bit_counters[i] % 2) ? (1 << i) : 0;
+ }
+ bits= value ^ reset_bits;
+}
+
Item *Item_sum_xor::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_xor(thd, this);
@@ -2112,10 +2242,31 @@ bool Item_sum_xor::add()
{
ulonglong value= (ulonglong) args[0]->val_int();
if (!args[0]->null_value)
+ {
+ if (as_window_function)
+ return add_as_window(value);
bits^=value;
+ }
return 0;
}
+void Item_sum_and::set_bits_from_counters()
+{
+ ulonglong value= 0;
+ if (!num_values_added)
+ {
+ bits= reset_bits;
+ return;
+ }
+
+ for (int i= 0; i < NUM_BIT_COUNTERS; i++)
+ {
+ // We've only added values of 1 for this bit.
+ if (bit_counters[i] == num_values_added)
+ value|= (1 << i);
+ }
+ bits= value & reset_bits;
+}
Item *Item_sum_and::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_and(thd, this);
@@ -2126,7 +2277,11 @@ bool Item_sum_and::add()
{
ulonglong value= (ulonglong) args[0]->val_int();
if (!args[0]->null_value)
+ {
+ if (as_window_function)
+ return add_as_window(value);
bits&=value;
+ }
return 0;
}
@@ -2314,6 +2469,10 @@ void Item_sum_bit::reset_field()
void Item_sum_bit::update_field()
{
+ // We never call update_field when computing the function as a window
+ // function. Setting bits to a random value invalidates the bits counters and
+ // the result of the bit function becomes erroneous.
+ DBUG_ASSERT(!as_window_function);
uchar *res=result_field->ptr;
bits= uint8korr(res);
add();
@@ -2896,7 +3055,7 @@ int group_concat_key_cmp_with_order(void* arg, const void* key1,
field->table->s->null_bytes);
int res= field->cmp((uchar*)key1 + offset, (uchar*)key2 + offset);
if (res)
- return (*order_item)->asc ? res : -res;
+ return ((*order_item)->direction == ORDER::ORDER_ASC) ? res : -res;
}
/*
We can't return 0 because in that case the tree class would remove this
@@ -3372,8 +3531,8 @@ bool Item_func_group_concat::setup(THD *thd)
if (!ref_pointer_array)
DBUG_RETURN(TRUE);
memcpy(ref_pointer_array, args, arg_count * sizeof(Item*));
- if (setup_order(thd, ref_pointer_array, context->table_list, list,
- all_fields, *order))
+ if (setup_order(thd, Ref_ptr_array(ref_pointer_array, n_elems),
+ context->table_list, list, all_fields, *order))
DBUG_RETURN(TRUE);
}
@@ -3507,9 +3666,9 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type)
if (i)
str->append(',');
orig_args[i + arg_count_field]->print(str, query_type);
- if (order[i]->asc)
+ if (order[i]->direction == ORDER::ORDER_ASC)
str->append(STRING_WITH_LEN(" ASC"));
- else
+ else
str->append(STRING_WITH_LEN(" DESC"));
}
}