home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 January
/
Chip_2001-01_cd1.bin
/
tema
/
mysql
/
mysql-3.23.28g-win-source.exe
/
sql
/
sql_analyse.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2000-08-31
|
27KB
|
988 lines
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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; either version 2 of the License, or
(at your option) any later version.
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 */
/* Analyse database */
/* TODO: - Check if any character fields can be of any date type
** (date, datetime, year, time, timestamp, newdate)
** - Check if any number field should be a timestamp
** - type set is out of optimization yet
*/
#ifdef __GNUC__
#pragma implementation // gcc: Class implementation
#endif
#include "mysql_priv.h"
#include "procedure.h"
#include "sql_analyse.h"
#include <m_ctype.h>
#define MAX_TREEMEM 8192
#define MAX_TREE_ELEMENTS 256
#define UINT_MAX16 0xffff
#define UINT_MAX24 0xffffff
#define UINT_MAX32 0xffffffff
Procedure *
proc_analyse_init(THD *thd, ORDER *param, select_result *result,
List<Item> &field_list)
{
char *proc_name = (*param->item)->name;
analyse *pc = new analyse(result);
field_info **f_info;
DBUG_ENTER("proc_analyse_init");
if (!(param = param->next))
{
pc->max_tree_elements = MAX_TREE_ELEMENTS;
pc->max_treemem = MAX_TREEMEM;
}
else if (param->next)
{
// first parameter
if ((*param->item)->type() != Item::INT_ITEM ||
(*param->item)->val() < 0)
{
net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
return 0;
}
pc->max_tree_elements = (uint) (*param->item)->val_int();
param = param->next;
if (param->next) // no third parameter possible
{
net_printf(&thd->net, ER_WRONG_PARAMCOUNT_TO_PROCEDURE, proc_name);
return 0;
}
// second parameter
if ((*param->item)->type() != Item::INT_ITEM ||
(*param->item)->val() < 0)
{
net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
return 0;
}
pc->max_treemem = (uint) (*param->item)->val_int();
}
else if ((*param->item)->type() != Item::INT_ITEM ||
(*param->item)->val() < 0)
{
net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
return 0;
}
// if only one parameter was given, it will be the value of max_tree_elements
else
{
pc->max_tree_elements = (uint) (*param->item)->val_int();
pc->max_treemem = MAX_TREEMEM;
}
if (!pc || !(pc->f_info = (field_info**)
sql_alloc(sizeof(field_info*)*field_list.elements)))
DBUG_RETURN(0);
pc->f_end = pc->f_info + field_list.elements;
pc->fields = field_list;
List_iterator<Item> it(pc->fields);
f_info = pc->f_info;
Item *item;
while ((item = it++))
{
if (item->result_type() == INT_RESULT)
{
// Check if fieldtype is ulonglong
if (item->type() == Item::FIELD_ITEM &&
((Item_field*) item)->field->type() == FIELD_TYPE_LONGLONG &&
((Field_longlong*) ((Item_field*) item)->field)->unsigned_flag)
*f_info++ = new field_ulonglong(item, pc);
else
*f_info++ = new field_longlong(item, pc);
}
if (item->result_type() == REAL_RESULT)
*f_info++ = new field_real(item, pc);
if (item->result_type() == STRING_RESULT)
*f_info++ = new field_str(item, pc);
}
return pc;
} // proc_analyse_init
// return 1 if number, else return 0
// store info about found number in info
// NOTE:It is expected, that elements of 'info' are all zero!
bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
{
const char *begin, *end = str + str_len;
DBUG_ENTER("test_if_number");
// MySQL removes any endspaces of a string, so we must take care only of
// spaces in front of a string
for (; str != end && isspace(*str); str++) ;
if (str == end)
return 0;
if (*str == '-')
{
info->negative = 1;
if (++str == end || *str == '0') // converting -0 to a number
return 0; // might lose information
}
else
info->negative = 0;
begin = str;
for (; str != end && isdigit(*str); str++)
{
if (!info->integers && *str == '0' && (str + 1) != end &&
isdigit(*(str + 1)))
info->zerofill = 1; // could be a postnumber for example
info->integers++;
}
if (str == end && info->integers)
{
info->ullval = (ulonglong) strtoull(begin ,NULL, 10);
if (info->integers == 1)
return 0; // a single number can't be zerofill
info->maybe_zerofill = 1;
return 1; // a zerofill number, or an integer
}
if (*str == '.' || *str == 'e' || *str == 'E')
{
if (info->zerofill) // can't be zerofill anymore
return 0;
if ((str + 1) == end) // number was something like '123[.eE]'
{
info->ullval = (ulonglong) strtoull(begin, NULL, 10);
return 1;
}
if (*str == 'e' || *str == 'E') // number may be something like '1e+50'
{
str++;
if (*str != '-' && *str != '+')
return 0;
for (str++; str != end && isdigit(*str); str++) ;
if (str == end)
{
info->is_float = 1; // we can't use variable decimals here
return 1;
}
else
return 0;
}
for (str++; *(end - 1) == '0'; end--); // jump over zeros at the end
if (str == end) // number was something like '123.000'
{
info->ullval = (ulonglong) strtoull(begin, NULL, 10);
return 1;
}
for (; str != end && isdigit(*str); str++)
info->decimals++;
if (str == end)
{
info->dval = atod(begin);
return 1;
}
else
return 0;
}
else
return 0;
} //test_if_number
// Stores the biggest and the smallest value from current 'info'
// to ev_num_info
// If info contains an ulonglong number, which is bigger than
// biggest positive number able to be stored in a longlong variable
// and is marked as negative, function will return 0, else 1.
bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num)
{
if (info->negative)
{
if (((longlong) info->ullval) < 0)
return 0; // Impossible to store as a negative number
ev_info->llval = -(longlong) max((ulonglong) -ev_info->llval,
info->ullval);
ev_info->min_dval = (double) -max(-ev_info->min_dval, info->dval);
}
else // ulonglong is as big as bigint in MySQL
{
if ((check_ulonglong(num, info->integers) == REAL_NUM))
return 0;
ev_info->ullval = (ulonglong) max(ev_info->ullval, info->ullval);
ev_info->max_dval = (double) max(ev_info->max_dval, info->dval);
}
return 1;
} // get_ev_num_info
void free_string(String *s)
{
s->free();
}
void field_str::add()
{
char buff[MAX_FIELD_WIDTH], *ptr;
String s(buff, sizeof(buff)), *res;
ulong length;
if (!(res = item->val_str(&s)))
{
nulls++;
return;
}
if (!(length = res->length()))
empty++;
else
{
ptr = (char*) res->ptr();
if (*(ptr + (length - 1)) == ' ')
must_be_blob = 1;
}
if (can_be_still_num)
{
bzero((char*) &num_info, sizeof(num_info));
if (!test_if_number(&num_info, res->ptr(), (uint) length))
can_be_still_num = 0;
if (!found)
{
bzero((char*) &ev_num_info, sizeof(ev_num_info));
was_zero_fill = num_info.zerofill;
}
else if (num_info.zerofill != was_zero_fill && !was_maybe_zerofill)
can_be_still_num = 0; // one more check needed, when length is counted
if (can_be_still_num)
can_be_still_num = get_ev_num_info(&ev_num_info, &num_info, res->ptr());
was_maybe_zerofill = num_info.maybe_zerofill;
}
if (room_in_tree)
{
if (res != &s)
s.copy(*res);
if (!tree_search(&tree, (void*) &s)) // If not in tree
{
s.copy(); // slow, when SAFE_MALLOC is in use
if (!tree_insert(&tree, (void*) &s, 0))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree);
}
else
{
bzero((char*) &s, sizeof(s)); // Let tree handle free of this
if ((treemem += length) > pc->max_treemem)
{
room_in_tree = 0; // Remove tree, too big tree
delete_tree(&tree);
}
}
}
}
if (!found)
{
found = 1;
min_arg.copy(*res);
max_arg.copy(*res);
min_length = max_length = length; sum=length;
}
else if (length)
{
sum += length;
if (length < min_length)
min_length = length;
if (length > max_length)
max_length = length;
if (item->binary)
{
if (stringcmp(res, &min_arg) < 0)
min_arg.copy(*res);
if (stringcmp(res, &max_arg) > 0)
max_arg.copy(*res);
}
else
{
if (sortcmp(res, &min_arg) < 0)
min_arg.copy(*res);
if (sortcmp(res, &max_arg) > 0)
max_arg.copy(*res);
}
}
if ((num_info.zerofill && (max_length != min_length)) ||
(was_zero_fill && (max_length != min_length)))
can_be_still_num = 0; // zerofilled numbers must be of same length
} // field_str::add
void field_real::add()
{
char buff[MAX_FIELD_WIDTH], *ptr, *end;
double num = item->val();
uint length, zero_count, decs;
TREE_ELEMENT *element;
if (item->null_value)
{
nulls++;
return;
}
if (num == 0.0)
empty++;
if ((decs = decimals()) == NOT_FIXED_DEC)
{
sprintf(buff, "%g", num);
length = (uint) strlen(buff);
if (rint(num) != num)
max_notzero_dec_len = 1;
}
else
{
#ifdef HAVE_SNPRINTF
buff[sizeof(buff)-1]=0; // Safety
snprintf(buff, sizeof(buff)-1, "%-.*f", (int) decs, num);
#else
sprintf(buff, "%-.*f", (int) decs, num);
#endif
length = (uint) strlen(buff);
// We never need to check further than this
end = buff + length - 1 - decs + max_notzero_dec_len;
zero_count = 0;
for (ptr = buff + length - 1; ptr > end && *ptr == '0'; ptr--)
zero_count++;
if ((decs - zero_count > max_notzero_dec_len))
max_notzero_dec_len = decs - zero_count;
}
if (room_in_tree)
{
if (!(element = tree_insert(&tree, (void*) &num, 0)))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree);
}
// if element->count == 1, this element can be found only once from tree
// if element->count == 2, or more, this element is already in tree
else if (element->count == 1 && (tree_elements++) > pc->max_tree_elements)
{
room_in_tree = 0; // Remove tree, too many elements
delete_tree(&tree);
}
}
if (!found)
{
found = 1;
min_arg = max_arg = sum = num;
sum_sqr = num * num;
min_length = max_length = length;
}
else if (num != 0.0)
{
sum += num;
sum_sqr += num * num;
if (length < min_length)
min_length = length;
if (length > max_length)
max_length = length;
if (compare_double(&num, &min_arg) < 0)
min_arg = num;
if (compare_double(&num, &max_arg) > 0)
max_arg = num;
}
} // field_real::add
void field_longlong::add()
{
char buff[MAX_FIELD_WIDTH];
longlong num = item->val_int();
uint length = (uint) (longlong10_to_str(num, buff, -10) - buff);
TREE_ELEMENT *element;
if (item->null_value)
{
nulls++;
return;
}
if (num == 0)
empty++;
if (room_in_tree)
{
if (!(element = tree_insert(&tree, (void*) &num, 0)))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree);
}
// if element->count == 1, this element can be found only once from tree
// if element->count == 2, or more, this element is already in tree
else if (element->count == 1 && (tree_elements++) > pc->max_tree_elements)
{
room_in_tree = 0; // Remove tree, too many elements
delete_tree(&tree);
}
}
if (!found)
{
found = 1;
min_arg = max_arg = sum = num;
sum_sqr = num * num;
min_length = max_length = length;
}
else if (num != 0)
{
sum += num;
sum_sqr += num * num;
if (length < min_length)
min_length = length;
if (length > max_length)
max_length = length;
if (compare_longlong(&num, &min_arg) < 0)
min_arg = num;
if (compare_longlong(&num, &max_arg) > 0)
max_arg = num;
}
} // field_longlong::add
void field_ulonglong::add()
{
char buff[MAX_FIELD_WIDTH];
longlong num = item->val_int();
uint length = (uint) (longlong10_to_str(num, buff, 10) - buff);
TREE_ELEMENT *element;
if (item->null_value)
{
nulls++;
return;
}
if (num == 0)
empty++;
if (room_in_tree)
{
if (!(element = tree_insert(&tree, (void*) &num, 0)))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree);
}
// if element->count == 1, this element can be found only once from tree
// if element->count == 2, or more, this element is already in tree
else if (element->count == 1 && (tree_elements++) > pc->max_tree_elements)
{
room_in_tree = 0; // Remove tree, too many elements
delete_tree(&tree);
}
}
if (!found)
{
found = 1;
min_arg = max_arg = sum = num;
sum_sqr = num * num;
min_length = max_length = length;
}
else if (num != 0)
{
sum += num;
sum_sqr += num * num;
if (length < min_length)
min_length = length;
if (length > max_length)
max_length = length;
if (compare_ulonglong((ulonglong*) &num, &min_arg) < 0)
min_arg = num;
if (compare_ulonglong((ulonglong*) &num, &max_arg) > 0)
max_arg = num;
}
} // field_ulonglong::add
int analyse::send_row(List<Item> &field_list __attribute__((unused)))
{
field_info **f = f_info;
rows++;
for (;f != f_end; f++)
{
(*f)->add();
}
return 0;
} // analyse::send_row
bool analyse::end_of_records()
{
field_info **f = f_info;
char buff[MAX_FIELD_WIDTH];
String *res, s_min(buff, sizeof(buff)), s_max(buff, sizeof(buff)),
ans(buff, sizeof(buff));
for (; f != f_end; f++)
{
func_items[0]->set((*f)->item->full_name());
if (!(*f)->found)
{
func_items[1]->null_value = 1;
func_items[2]->null_value = 1;
}
else
{
func_items[1]->null_value = 0;
res = (*f)->get_min_arg(&s_min);
func_items[1]->set(res->ptr(), res->length());
func_items[2]->null_value = 0;
res = (*f)->get_max_arg(&s_max);
func_items[2]->set(res->ptr(), res->length());
}
func_items[3]->set((longlong) (*f)->min_length);
func_items[4]->set((longlong) (*f)->max_length);
func_items[5]->set((longlong) (*f)->empty);
func_items[6]->set((longlong) (*f)->nulls);
res = (*f)->avg(&s_max, rows);
func_items[7]->set(res->ptr(), res->length());
func_items[8]->null_value = 0;
res = (*f)->std(&s_max, rows);
if (!res)
func_items[8]->null_value = 1;
else
func_items[8]->set(res->ptr(), res->length());
// count the dots, quotas, etc. in (ENUM("a","b","c"...))
// if tree has been removed, don't suggest ENUM.
// treemem is used to measure the size of tree for strings,
// tree_elements is used to count the elements in tree in case of numbers.
// max_treemem tells how long the string starting from ENUM("... and
// ending to ..") shall at maximum be. If case is about numbers,
// max_tree_elements will tell the length of the above, now
// every number is considered as length 1
if (((*f)->treemem || (*f)->tree_elements) &&
(*f)->tree.elements_in_tree &&
(((*f)->treemem ? max_treemem : max_tree_elements) >
(((*f)->treemem ? (*f)->treemem : (*f)->tree_elements) +
((*f)->tree.elements_in_tree * 3 - 1 + 6))))
{
char tmp[331]; //331, because one double prec. num. can be this long
String tmp_str(tmp, sizeof(tmp));
TREE_INFO tree_info;
tree_info.str = &tmp_str;
tree_info.found = 0;
tree_info.item = (*f)->item;
tmp_str.set("ENUM(", 5);
tree_walk(&(*f)->tree, (*f)->collect_enum(), (char*) &tree_info,
left_root_right);
tmp_str.append(')');
if (!(*f)->nulls)
tmp_str.append(" NOT NULL");
output_str_length = tmp_str.length();
func_items[9]->set(tmp_str.ptr(), tmp_str.length());
if (result->send_data(result_fields))
return -1;
continue;
}
ans.length(0);
if (!(*f)->treemem && !(*f)->tree_elements)
ans.append("CHAR(0)", 7);
else if ((*f)->item->type() == Item::FIELD_ITEM)
{
switch (((Item_field*) (*f)->item)->field->real_type())
{
case FIELD_TYPE_TIMESTAMP:
ans.append("TIMESTAMP", 9);
break;
case FIELD_TYPE_DATETIME:
ans.append("DATETIME", 8);
break;
case FIELD_TYPE_DATE:
ans.append("DATE", 4);
break;
case FIELD_TYPE_SET:
ans.append("SET", 3);
break;
case FIELD_TYPE_YEAR:
ans.append("YEAR", 4);
break;
case FIELD_TYPE_TIME:
ans.append("TIME", 4);
break;
case FIELD_TYPE_NEWDATE:
ans.append("NEWDATE", 7);
break;
case FIELD_TYPE_DECIMAL:
ans.append("DECIMAL", 7);
// if item is FIELD_ITEM, it _must_be_ Field_num in this case
if (((Field_num*) (*f)->item)->zerofill)
ans.append(" ZEROFILL");
break;
default:
(*f)->get_opt_type(&ans, rows);
break;
}
}
if (!(*f)->nulls)
ans.append(" NOT NULL");
func_items[9]->set(ans.ptr(), ans.length());
if (result->send_data(result_fields))
return -1;
}
return 0;
} // analyse::end_of_records
void field_str::get_opt_type(String *answer, ha_rows total_rows)
{
char buff[MAX_FIELD_WIDTH];
if (can_be_still_num)
{
if (num_info.is_float)
sprintf(buff, "DOUBLE"); // number was like 1e+50... TODO:
else if (num_info.decimals) // DOUBLE(%d,%d) sometime
{
if (num_info.dval > -FLT_MAX && num_info.dval < FLT_MAX)
sprintf(buff, "FLOAT(%d,%d)", num_info.integers, num_info.decimals);
else
sprintf(buff, "DOUBLE(%d,%d)", num_info.integers, num_info.decimals);
}
else if (ev_num_info.llval >= -128 &&
ev_num_info.ullval <=
(ulonglong) (ev_num_info.llval >= 0 ? 255 : 127))
sprintf(buff, "TINYINT(%d)", num_info.integers);
else if (ev_num_info.llval >= INT_MIN16 &&
ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ?
UINT_MAX16 : INT_MAX16))
sprintf(buff, "SMALLINT(%d)", num_info.integers);
else if (ev_num_info.llval >= INT_MIN24 &&
ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ?
UINT_MAX24 : INT_MAX24))
sprintf(buff, "MEDIUMINT(%d)", num_info.integers);
else if (ev_num_info.llval >= INT_MIN32 &&
ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ?
UINT_MAX32 : INT_MAX32))
sprintf(buff, "INT(%d)", num_info.integers);
else
sprintf(buff, "BIGINT(%d)", num_info.integers);
answer->append(buff, (uint) strlen(buff));
if (ev_num_info.llval >= 0 && ev_num_info.min_dval >= 0)
answer->append(" UNSIGNED");
if (num_info.zerofill)
answer->append(" ZEROFILL");
}
else if (max_length < 256)
{
if (must_be_blob)
{
if (item->binary)
answer->append("TINYBLOB", 8);
else
answer->append("TINYTEXT", 8);
}
else if ((max_length * (total_rows - nulls)) < (sum + total_rows))
{
sprintf(buff, "CHAR(%d)", (int) max_length);
answer->append(buff, (uint) strlen(buff));
}
else
{
sprintf(buff, "VARCHAR(%d)", (int) max_length);
answer->append(buff, (uint) strlen(buff));
}
}
else if (max_length < (1L << 16))
{
if (item->binary)
answer->append("BLOB", 4);
else
answer->append("TEXT", 4);
}
else if (max_length < (1L << 24))
{
if (item->binary)
answer->append("MEDIUMBLOB", 10);
else
answer->append("MEDIUMTEXT", 10);
}
else
{
if (item->binary)
answer->append("LONGBLOB", 8);
else
answer->append("LONGTEXT", 8);
}
} // field_str::get_opt_type
void field_real::get_opt_type(String *answer,
ha_rows total_rows __attribute__((unused)))
{
char buff[MAX_FIELD_WIDTH];
if (!max_notzero_dec_len)
{
if (min_arg >= -128 && max_arg <= (min_arg >= 0 ? 255 : 127))
sprintf(buff, "TINYINT(%d)", (int) max_length - (item->decimals + 1));
else if (min_arg >= INT_MIN16 && max_arg <= (min_arg >= 0 ?
UINT_MAX16 : INT_MAX16))
sprintf(buff, "SMALLINT(%d)", (int) max_length - (item->decimals + 1));
else if (min_arg >= INT_MIN24 && max_arg <= (min_arg >= 0 ?
UINT_MAX24 : INT_MAX24))
sprintf(buff, "MEDIUMINT(%d)", (int) max_length - (item->decimals + 1));
else if (min_arg >= INT_MIN32 && max_arg <= (min_arg >= 0 ?
UINT_MAX32 : INT_MAX32))
sprintf(buff, "INT(%d)", (int) max_length - (item->decimals + 1));
else
sprintf(buff, "BIGINT(%d)", (int) max_length - (item->decimals + 1));
answer->append(buff, (uint) strlen(buff));
if (min_arg >= 0)
answer->append(" UNSIGNED");
}
else
{
if (min_arg >= -FLT_MAX && max_arg <= FLT_MAX)
sprintf(buff, "FLOAT(%d,%d)", (int) max_length - (item->decimals + 1),
max_notzero_dec_len);
else
sprintf(buff, "DOUBLE(%d,%d)", (int) max_length - (item->decimals + 1),
max_notzero_dec_len);
answer->append(buff, (uint) strlen(buff));
}
// if item is FIELD_ITEM, it _must_be_ Field_num in this class
if (item->type() == Item::FIELD_ITEM &&
// a single number shouldn't be zerofill
(max_length - (item->decimals + 1)) != 1 &&
((Field_num*) ((Item_field*) item)->field)->zerofill)
answer->append(" ZEROFILL");
} // field_real::get_opt_type
void field_longlong::get_opt_type(String *answer,
ha_rows total_rows __attribute__((unused)))
{
char buff[MAX_FIELD_WIDTH];
if (min_arg >= -128 && max_arg <= (min_arg >= 0 ? 255 : 127))
sprintf(buff, "TINYINT(%d)", (int) max_length);
else if (min_arg >= INT_MIN16 && max_arg <= (min_arg >= 0 ?
UINT_MAX16 : INT_MAX16))
sprintf(buff, "SMALLINT(%d)", (int) max_length);
else if (min_arg >= INT_MIN24 && max_arg <= (min_arg >= 0 ?
UINT_MAX24 : INT_MAX24))
sprintf(buff, "MEDIUMINT(%d)", (int) max_length);
else if (min_arg >= INT_MIN32 && max_arg <= (min_arg >= 0 ?
UINT_MAX32 : INT_MAX32))
sprintf(buff, "INT(%d)", (int) max_length);
else
sprintf(buff, "BIGINT(%d)", (int) max_length);
answer->append(buff, (uint) strlen(buff));
if (min_arg >= 0)
answer->append(" UNSIGNED");
// if item is FIELD_ITEM, it _must_be_ Field_num in this class
if ((item->type() == Item::FIELD_ITEM) &&
// a single number shouldn't be zerofill
max_length != 1 &&
((Field_num*) ((Item_field*) item)->field)->zerofill)
answer->append(" ZEROFILL");
} // field_longlong::get_opt_type
void field_ulonglong::get_opt_type(String *answer,
ha_rows total_rows __attribute__((unused)))
{
char buff[MAX_FIELD_WIDTH];
if (max_arg < 256)
sprintf(buff, "TINYINT(%d) UNSIGNED", (int) max_length);
else if (max_arg <= ((2 * INT_MAX16) + 1))
sprintf(buff, "SMALLINT(%d) UNSIGNED", (int) max_length);
else if (max_arg <= ((2 * INT_MAX24) + 1))
sprintf(buff, "MEDIUMINT(%d) UNSIGNED", (int) max_length);
else if (max_arg < (((ulonglong) 1) << 32))
sprintf(buff, "INT(%d) UNSIGNED", (int) max_length);
else
sprintf(buff, "BIGINT(%d) UNSIGNED", (int) max_length);
// if item is FIELD_ITEM, it _must_be_ Field_num in this class
answer->append(buff, (uint) strlen(buff));
if (item->type() == Item::FIELD_ITEM &&
// a single number shouldn't be zerofill
max_length != 1 &&
((Field_num*) ((Item_field*) item)->field)->zerofill)
answer->append(" ZEROFILL");
} //field_ulonglong::get_opt_type
int collect_string(String *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
{
if (info->found)
info->str->append(',');
else
info->found = 1;
info->str->append('\'');
info->str->append(*element);
info->str->append('\'');
return 0;
} // collect_string
int collect_real(double *element, element_count count __attribute__((unused)),
TREE_INFO *info)
{
char buff[255];
String s(buff, sizeof(buff));
if (info->found)
info->str->append(',');
else
info->found = 1;
info->str->append('\'');
s.set(*element, info->item->decimals);
info->str->append(s);
info->str->append('\'');
return 0;
} // collect_real
int collect_longlong(longlong *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
{
char buff[255];
String s(buff, sizeof(buff));
if (info->found)
info->str->append(',');
else
info->found = 1;
info->str->append('\'');
s.set(*element);
info->str->append(s);
info->str->append('\'');
return 0;
} // collect_longlong
int collect_ulonglong(ulonglong *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
{
char buff[255];
String s(buff, sizeof(buff));
if (info->found)
info->str->append(',');
else
info->found = 1;
info->str->append('\'');
s.set(*element);
info->str->append(s);
info->str->append('\'');
return 0;
} // collect_ulonglong
bool analyse::change_columns(List<Item> &field_list)
{
field_list.empty();
func_items[0] = new Item_proc_string("Field_name", 255);
func_items[1] = new Item_proc_string("Min_value", 255);
func_items[1]->maybe_null = 1;
func_items[2] = new Item_proc_string("Max_value", 255);
func_items[2]->maybe_null = 1;
func_items[3] = new Item_proc_int("Min_length");
func_items[4] = new Item_proc_int("Max_length");
func_items[5] = new Item_proc_int("Empties_or_zeros");
func_items[6] = new Item_proc_int("Nulls");
func_items[7] = new Item_proc_string("Avg_value_or_avg_length", 255);
func_items[8] = new Item_proc_string("Std", 255);
func_items[8]->maybe_null = 1;
func_items[9] = new Item_proc_string("Optimal_fieldtype",
max(64, output_str_length));
for (uint i = 0; i < array_elements(func_items); i++)
field_list.push_back(func_items[i]);
result_fields = field_list;
return 0;
} // analyse::change_columns
int compare_double(const double *s, const double *t)
{
return ((*s < *t) ? -1 : *s > *t ? 1 : 0);
} /* compare_double */
int compare_longlong(const longlong *s, const longlong *t)
{
return ((*s < *t) ? -1 : *s > *t ? 1 : 0);
} /* compare_longlong */
int compare_ulonglong(const ulonglong *s, const ulonglong *t)
{
return ((*s < *t) ? -1 : *s > *t ? 1 : 0);
} /* compare_ulonglong */
uint check_ulonglong(const char *str, uint length)
{
const char *long_str = "2147483647", *ulonglong_str = "18446744073709551615";
const uint long_len = 10, ulonglong_len = 20;
while (*str == '0' && length)
{
str++; length--;
}
if (length < long_len)
return NUM;
uint smaller, bigger;
const char *cmp;
if (length == long_len)
{
cmp = long_str;
smaller = NUM;
bigger = LONG_NUM;
}
else if (length > ulonglong_len)
return REAL_NUM;
else
{
cmp = ulonglong_str;
smaller = LONG_NUM;
bigger = REAL_NUM;
}
while (*cmp && *cmp++ == *str++) ;
return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
} /* check_ulonlong */