1
0
Files
2022-09-29 17:59:04 +03:00

658 lines
12 KiB
C++

/* Copyright (C) 1979-1996 TcX AB & Monty Program KB & Detron HB
This software is distributed with NO WARRANTY OF ANY KIND. No author or
distributor accepts any responsibility for the consequences of using it, or
for whether it serves any particular purpose or works at all, unless he or
she says so in writing. Refer to the Free Public License (the "License")
for full details.
Every copy of this file must include a copy of the License, normally in a
plain ASCII text file named PUBLIC. The License grants you the right to
copy, modify and redistribute this file, but only under certain conditions
described in the License. Among other things, the License requires that
the copyright notice and this notice be preserved on all copies. */
/* Sum functions (COUNT, MIN...) */
#ifdef __GNUC__
#pragma implementation // gcc: Class implementation
#endif
#include "mysql_priv.h"
void Item_sum::make_field(Send_field *tmp_field)
{
if (item->type() == Item::FIELD_ITEM && keep_field_type())
((Item_field*) item)->field->make_field(tmp_field);
else
{
tmp_field->flags=0;
if (!maybe_null)
tmp_field->flags|= NOT_NULL_FLAG;
tmp_field->length=max_length;
tmp_field->decimals=decimals;
tmp_field->type=(result_type() == INT_RESULT ? FIELD_TYPE_LONG :
result_type() == REAL_RESULT ? FIELD_TYPE_DOUBLE :
FIELD_TYPE_VAR_STRING);
}
tmp_field->table_name="";
tmp_field->col_name=name;
}
void Item_sum::print(String *str)
{
str->append(func_name());
str->append('(');
item->print(str);
str->append(')');
}
String *
Item_sum_num::str(String *str)
{
double nr=val();
if (null_value)
return 0;
str->set(nr,decimals);
return str;
}
String *
Item_sum_int::str(String *str)
{
longlong nr=val_int();
if (null_value)
return 0;
char buff[21];
uint length= (uint) (longlong2str(nr,buff,-10)-buff);
str->copy(buff,length);
return str;
}
bool
Item_sum_num::fix_fields(THD *thd,TABLE_LIST *tables)
{
if (!thd->allow_sum_func)
{
my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
return 1;
}
thd->allow_sum_func=0; // No included group funcs
if (item->fix_fields(thd,tables))
return 1;
decimals=item->decimals;
result_field=0;
max_length=float_length(decimals);
maybe_null=item->maybe_null;
null_value=1;
fix_length_and_dec();
thd->allow_sum_func=1; // Allow group functions
return 0;
}
bool
Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables)
{
if (!thd->allow_sum_func)
{
my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
return 1;
}
thd->allow_sum_func=0; // No included group funcs
if (item->fix_fields(thd,tables))
return 1;
hybrid_type=item->result_type();
if (hybrid_type == INT_RESULT)
max_length=21;
else if (hybrid_type == REAL_RESULT)
max_length=float_length(decimals);
else
max_length=item->max_length;
decimals=item->decimals;
maybe_null=item->maybe_null;
binary=item->binary;
result_field=0;
null_value=1;
fix_length_and_dec();
thd->allow_sum_func=1; // Allow group functions
return 0;
}
/***********************************************************************
** reset and add of sum_func
***********************************************************************/
void Item_sum_sum::reset()
{
null_value=0; sum=item->val();
}
void Item_sum_sum::add()
{
sum+=item->val();
}
double Item_sum_sum::val()
{
return sum;
}
void Item_sum_count::reset()
{
count=0; null_value=0; add();
}
void Item_sum_count::add()
{
if (!item->maybe_null)
count++;
else
{
(void) item->val_int();
if (!item->null_value)
count++;
}
}
longlong Item_sum_count::val_int()
{
return (longlong) count;
}
/*
** Avgerage
*/
void Item_sum_avg::reset()
{
sum=0.0; count=0; Item_sum_avg::add();
}
void Item_sum_avg::add()
{
double nr=item->val();
if (!item->null_value)
{
sum+=nr;
count++;
}
}
double Item_sum_avg::val()
{
if (!count)
{
null_value=1;
return 0.0;
}
null_value=0;
return sum/ulonglong2double(count);
}
/*
** Standard deviation
*/
void Item_sum_std::reset()
{
sum=sum_sqr=0.0; count=0; Item_sum_std::add();
}
void Item_sum_std::add()
{
double nr=item->val();
if (!item->null_value)
{
sum+=nr;
sum_sqr+=nr*nr;
count++;
}
}
double Item_sum_std::val()
{
if (!count)
{
null_value=1;
return 0.0;
}
null_value=0;
double tmp=ulonglong2double(count);
return sqrt((sum_sqr - sum*sum/tmp)/tmp);
}
void Item_sum_std::reset_field()
{
double nr=item->val();
char *res=result_field->ptr;
if (item->null_value)
bzero(res,sizeof(double)*2+sizeof(long));
else
{
doublestore(res,nr);
nr*=nr;
doublestore(res+sizeof(double),nr);
longstore(res+sizeof(double)*2,1);
}
}
void Item_sum_std::update_field(int offset)
{
double nr,old_nr,old_sqr;
longlong field_count;
char *res=result_field->ptr;
doubleget(old_nr,res+offset);
doubleget(old_sqr,res+offset+sizeof(double));
longlongget(field_count,res+offset+sizeof(double)*2);
nr=item->val();
if (!item->null_value)
{
old_nr+=nr;
old_sqr+=nr*nr;
field_count++;
}
doublestore(res,old_nr);
doublestore(res+sizeof(double),old_sqr);
longlongstore(res+sizeof(double)*2,field_count);
}
/* min & max */
double Item_sum_hybrid::val()
{
if (null_value)
return 0.0;
if (hybrid_type == STRING_RESULT)
{
String *res; res=str(&str_value);
return res ? atof(res->c_ptr()) : 0.0;
}
return sum;
}
String *
Item_sum_hybrid::str(String *str)
{
if (null_value)
return 0;
if (hybrid_type == STRING_RESULT)
return &value;
str->set(sum,decimals);
return str;
}
void Item_sum_min::add()
{
if (hybrid_type != STRING_RESULT)
{
double nr=item->val();
if (!item->null_value && (null_value || nr < sum))
{
sum=nr;
null_value=0;
}
}
else
{
String *result=item->str(&tmp_value);
if (!item->null_value &&
(null_value ||
(binary ? stringcmp(&value,result) : sortcmp(&value,result)) > 0))
{
value.copy(*result);
null_value=0;
}
}
}
void Item_sum_max::add()
{
if (hybrid_type != STRING_RESULT)
{
double nr=item->val();
if (!item->null_value && (null_value || nr > sum))
{
sum=nr;
null_value=0;
}
}
else
{
String *result=item->str(&tmp_value);
if (!item->null_value &&
(null_value ||
(binary ? stringcmp(&value,result) : sortcmp(&value,result)) < 0))
{
value.copy(*result);
null_value=0;
}
}
}
/* bit_or and bit_and */
longlong Item_sum_bit::val_int()
{
return (longlong) bits;
}
void Item_sum_bit::reset()
{
bits=reset_bits; add();
}
void Item_sum_or::add()
{
ulonglong value= (ulonglong) item->val_int();
if (!item->null_value)
bits|=value;
}
void Item_sum_and::add()
{
ulonglong value= (ulonglong) item->val_int();
if (!item->null_value)
bits&=value;
}
/************************************************************************
** reset result of a Item_sum with is saved in a tmp_table
*************************************************************************/
void Item_sum_num::reset_field()
{
double nr=item->val();
char *res=result_field->ptr;
if (maybe_null)
{
if (item->null_value)
{
nr=0.0;
result_field->set_null();
}
else
result_field->set_notnull();
}
memcpy(res,(char*) &nr,sizeof(double));
}
void Item_sum_hybrid::reset_field()
{
if (hybrid_type == STRING_RESULT)
{
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff)),*res;
res=item->str(&tmp);
if (item->null_value)
{
result_field->set_null();
result_field->reset();
}
else
{
result_field->set_notnull();
result_field->store(res->ptr(),res->length());
}
}
else if (hybrid_type == INT_RESULT)
{
longlong nr=item->val_int();
if (maybe_null)
{
if (item->null_value)
{
nr=0;
result_field->set_null();
}
else
result_field->set_notnull();
}
result_field->store(nr);
}
else // REAL_RESULT
{
double nr=item->val();
if (maybe_null)
{
if (item->null_value)
{
nr=0.0;
result_field->set_null();
}
else
result_field->set_notnull();
}
result_field->store(nr);
}
}
void Item_sum_sum::reset_field()
{
double nr=item->val(); // Nulls also return 0
memcpy(result_field->ptr,(char*) &nr,sizeof(double));
}
void Item_sum_count::reset_field()
{
char *res=result_field->ptr;
longlong nr=0;
if (!item->maybe_null)
nr=1;
else
{
(void) item->val_int();
if (!item->null_value)
nr=1;
}
longlongstore(res,nr);
}
void Item_sum_avg::reset_field()
{
double nr=item->val();
char *res=result_field->ptr;
if (item->null_value)
bzero(res,sizeof(double)+sizeof(longlong));
else
{
doublestore(res,nr);
res+=sizeof(double);
longlong tmp=1;
longlongstore(res,tmp);
}
}
void Item_sum_bit::reset_field()
{
char *res=result_field->ptr;
ulonglong nr=(ulonglong) item->val_int();
longlongstore(res,nr);
}
/*
** calc next value and merge it with field_value
*/
void Item_sum_sum::update_field(int offset)
{
double old_nr,nr;
char *res=result_field->ptr;
doubleget(old_nr,res+offset);
nr=item->val();
if (!item->null_value)
old_nr+=nr;
doublestore(res,old_nr);
}
void Item_sum_count::update_field(int offset)
{
longlong nr;
char *res=result_field->ptr;
longlongget(nr,res+offset);
if (!item->maybe_null)
nr++;
else
{
(void) item->val_int();
if (!item->null_value)
nr++;
}
longlongstore(res,nr);
}
void Item_sum_avg::update_field(int offset)
{
double nr,old_nr;
longlong field_count;
char *res=result_field->ptr;
doubleget(old_nr,res+offset);
longlongget(field_count,res+offset+sizeof(double));
nr=item->val();
if (!item->null_value)
{
old_nr+=nr;
field_count++;
}
doublestore(res,old_nr);
res+=sizeof(double);
longlongstore(res,field_count);
}
void Item_sum_hybrid::update_field(int offset)
{
if (hybrid_type == STRING_RESULT)
min_max_update_str_field(offset);
else if (hybrid_type == INT_RESULT)
min_max_update_int_field(offset);
else
min_max_update_real_field(offset);
}
void
Item_sum_hybrid::min_max_update_str_field(int offset)
{
String *res_str=item->str(&value);
if (item->null_value)
result_field->copy_from_tmp(offset); // Use old value
else
{
res_str->strip_sp();
result_field->ptr+=offset; // Get old max/min
result_field->val_str(&tmp_value,&tmp_value);
result_field->ptr-=offset;
if (result_field->is_null() ||
(cmp_sign * (binary ? stringcmp(res_str,&tmp_value) :
sortcmp(res_str,&tmp_value)) < 0))
result_field->store(res_str->ptr(),res_str->length());
else
{ // Use old value
char *res=result_field->ptr;
memcpy(res,res+offset,result_field->pack_length());
}
result_field->set_notnull();
}
}
void
Item_sum_hybrid::min_max_update_real_field(int offset)
{
double nr,old_nr;
result_field->ptr+=offset;
old_nr=result_field->val_real();
nr=item->val();
if (!item->null_value)
{
if (result_field->is_null(offset) ||
(cmp_sign > 0 ? old_nr > nr : old_nr < nr))
old_nr=nr;
result_field->set_notnull();
}
else if (result_field->is_null(offset))
result_field->set_null();
result_field->ptr-=offset;
result_field->store(old_nr);
}
void
Item_sum_hybrid::min_max_update_int_field(int offset)
{
longlong nr,old_nr;
result_field->ptr+=offset;
old_nr=result_field->val_int();
nr=item->val_int();
if (!item->null_value)
{
if (result_field->is_null(offset) ||
(cmp_sign > 0 ? old_nr > nr : old_nr < nr))
old_nr=nr;
result_field->set_notnull();
}
else if (result_field->is_null(offset))
result_field->set_null();
result_field->ptr-=offset;
result_field->store(old_nr);
}
void Item_sum_or::update_field(int offset)
{
ulonglong nr;
char *res=result_field->ptr;
ulongget(nr,res+offset);
nr|= (ulonglong) item->val_int();
longlongstore(res,nr);
}
void Item_sum_and::update_field(int offset)
{
ulonglong nr;
char *res=result_field->ptr;
ulongget(nr,res+offset);
nr&= (ulonglong) item->val_int();
longlongstore(res,nr);
}