1
0
Files
irix-657m-src/eoe/cmd/sss/ssdb/ssdbserver/sql/field.cc
2022-09-29 17:59:04 +03:00

3371 lines
73 KiB
C++

/* Copyright (C) 1979-1997 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. */
/*
NOTES:
Some of the number class uses the system functions strtol(), strtoll()...
To avoid patching the end \0 or copying the buffer unnecessary, all calls
to system functions are wrapped to a String object that adds the end null
if it only if it isn't there.
This adds some overhead when assigning numbers from strings but makes
everything simpler.
*/
/*****************************************************************************
** This file implements classes defined in field.h
*****************************************************************************/
#ifdef __GNUC__
#pragma implementation // gcc: Class implementation
#endif
#include "mysql_priv.h"
#include "sql_select.h"
#include <m_ctype.h>
#include <errno.h>
#ifdef HAVE_FCONVERT
#include <floatingpoint.h>
#endif
/*****************************************************************************
** Instansiate templates and static variables
*****************************************************************************/
#ifdef __GNUC__
template class List<create_field>;
template class List_iterator<create_field>;
#endif
struct decstr {
uint nr_length,nr_dec,sign,extra;
char sign_char;
};
uchar Field_null::null[1]={1};
const char field_separator=',';
/*****************************************************************************
** Static help functions
*****************************************************************************/
/*
** Calculate length of number and it's parts
** Increment cuted_fields if wrong number
*/
static bool
number_dec(struct decstr *sdec, const char *str, const char *end)
{
sdec->sign=sdec->extra=0;
if (str == end)
{
current_thd->cuted_fields++;
sdec->nr_length=sdec->nr_dec=sdec->sign=0;
sdec->extra=1; // We must put one 0 before .
return 1;
}
if (*str == '-' || *str == '+') /* sign */
{
sdec->sign_char= *str;
sdec->sign=1;
str++;
}
const char *start=str;
while (str != end && isdigit(*str))
str++;
if (!(sdec->nr_length=(uint) (str-start)))
sdec->extra=1; // We must put one 0 before .
start=str;
if (str != end && *str == '.')
{
str++;
start=str;
while (str != end && isdigit(*str))
str++;
}
sdec->nr_dec=(uint) (str-start);
if (current_thd->count_cuted_fields)
{
while (str != end && isspace(*str))
str++; /* purecov: inspected */
if (str != end)
{
current_thd->cuted_fields++;
return 1;
}
}
return 0;
}
void Field_num::prepend_zeros(String *value)
{
int diff;
if ((diff= (int) (field_length - value->length())) > 0)
{
bmove_upp((char*) value->ptr()+field_length,value->ptr()+value->length(),
value->length());
bfill((char*) value->ptr(),diff,'0');
value->length(field_length);
(void) value->c_ptr_quick(); // Avoid warnings in purify
}
}
/*
** Test if given number is a int (or a fixed format float with .000)
** This is only used to give warnings in ALTER TABLE or LOAD DATA...
*/
static bool test_if_int(const char *str,int length)
{
const char *end=str+length;
while (str != end && isspace(*str)) // Allow start space
str++; /* purecov: inspected */
if (str != end && (*str == '-' || *str == '+'))
str++;
if (str == end)
return 0; // Error: Empty string
for ( ; str != end ; str++)
{
if (!isdigit(*str))
{
if (*str == '.')
{ // Allow '.0000'
for (str++ ; str != end && *str == '0'; str++) ;
if (str == end)
return 1;
}
if (!isspace(*str))
return 0;
for (str++ ; str != end ; str++)
if (!isspace(*str))
return 0;
return 1;
}
}
return 1;
}
static bool test_if_real(const char *str,int length)
{
while (length && isspace(*str))
{ // Allow start space
length--; str++;
}
if (!length)
return 0;
if (*str == '+' || *str == '-')
{
length--; str++;
if (!length || !(isdigit(*str) || *str == '.'))
return 0;
}
while (length && isdigit(*str))
{
length--; str++;
}
if (!length)
return 1;
if (*str == '.')
{
length--; str++;
while (length && isdigit(*str))
{
length--; str++;
}
}
if (!length)
return 1;
if (*str == 'E' || *str == 'e')
{
if (length < 3 || (str[1] != '+' && str[1] != '-') || !isdigit(str[2]))
return 0;
length-=3;
str+=3;
while (length && isdigit(*str))
{
length--; str++;
}
}
for ( ; length ; length--, str++)
{ // Allow end space
if (!isspace(*str))
return 0;
}
return 1;
}
/****************************************************************************
** Functions for the base classes
** This is a unpacked number.
****************************************************************************/
Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
uint null_bit_arg,
utype unireg_check_arg,char *field_name_arg,
struct st_table *table_arg)
:ptr(ptr_arg),null_ptr(null_ptr_arg),null_bit(null_bit_arg),
table(table_arg),query_id(0),key_start(0),part_of_key(0),
table_name(table_arg ? table_arg->table_name : 0),
field_name(field_name_arg), unireg_check(unireg_check_arg),
field_length(length_arg)
{
flags=null_ptr ? 0: NOT_NULL_FLAG;
}
uint Field::offset()
{
return (uint) (ptr - (char*) table->record[0]);
}
void Field::copy_from_tmp(int offset)
{
memcpy(ptr,ptr+offset,pack_length());
if (null_ptr)
{
*null_ptr= ((null_ptr[0] & (uchar) ~(uint) null_bit) |
null_ptr[offset] & (uchar) null_bit);
}
}
bool Field::send(String *packet)
{
if (is_null())
return net_store_null(packet);
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff));
val_str(&tmp,&tmp);
CONVERT *convert;
if ((convert=current_thd->convert_set))
return convert->store(packet,tmp.ptr(),tmp.length());
return net_store_data(packet,tmp.ptr(),tmp.length());
}
void Field_num::add_zerofill_and_unsigned(String &res) const
{
res.length(strlen(res.ptr())); // Fix length
if (unsigned_flag)
res.append(" unsigned");
if (zerofill)
res.append(" zerofill");
}
void Field_num::make_field(Send_field *field)
{
field->table_name=table_name;
field->col_name=field_name;
field->length=field_length;
field->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
field->decimals=decimals;
}
void Field_str::make_field(Send_field *field)
{
field->table_name=table_name;
field->col_name=field_name;
field->length=field_length;
field->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
field->decimals=0;
}
uint Field::fill_cache_field(CACHE_FIELD *copy)
{
copy->str=ptr;
copy->length=pack_length();
copy->blob_field=0;
if (flags & BLOB_FLAG)
{
copy->blob_field=(Field_blob*) this;
copy->strip=0;
copy->length-=sizeof(char*);
return copy->length;
}
else if (!zero_pack() && (type() == FIELD_TYPE_STRING && copy->length > 4 ||
type() == FIELD_TYPE_VAR_STRING))
copy->strip=1; /* Remove end space */
else
copy->strip=0;
return copy->length+(int) copy->strip;
}
/****************************************************************************
** Functions for the Field_decimal class
** This is a unpacked number.
****************************************************************************/
void
Field_decimal::reset(void)
{
Field_decimal::store("0",1);
}
void Field_decimal::overflow(bool negative)
{
uint len=field_length;
char *to=ptr;
if (negative && !unsigned_flag)
{
*to++ = '-';
len--;
}
bfill(to,len,negative && unsigned_flag ? '0' : '9');
if (decimals)
ptr[field_length-decimals-1]='.';
return;
}
void Field_decimal::store(const char *from,uint len)
{
reg3 int i;
uint dec;
char fyllchar;
const char *end=from+len;
struct decstr index;
bool error;
if ((dec= decimals))
dec++; // Calculate pos of '.'
while (from != end && isspace(*from))
from++;
if (zerofill)
{
fyllchar = '0';
if (from != end)
while (*from == '0' && from != end-1) // Skipp prezero
from++;
}
else
fyllchar=' ';
error=number_dec(&index,from,end);
if (index.sign)
{
from++;
if (unsigned_flag) // No sign with zerofill
{
if (!error)
current_thd->cuted_fields++;
Field_decimal::overflow(1);
return;
}
}
/*
** Remove pre-zeros if too big number
*/
for (i= (int) (index.nr_length+index.extra -(field_length-dec)+index.sign) ;
i > 0 ;
i--)
{
if (*from == '0')
{
from++;
index.nr_length--;
continue;
}
if (index.sign && index.sign_char == '+' && i == 1)
{ // Remove pre '+'
index.sign=0;
break;
}
current_thd->cuted_fields++;
// too big number, change to max or min number
Field_decimal::overflow(index.sign && index.sign_char == '-');
return;
}
char *to=ptr;
for (i=(int) (field_length-dec-index.nr_length-index.extra - index.sign) ;
i-- > 0 ;)
*to++ = fyllchar;
if (index.sign)
*to++= index.sign_char;
if (index.extra)
*to++ = '0';
for (i=(int) index.nr_length ; i-- > 0 ; )
*to++ = *from++;
if (dec--)
{
*to++ ='.';
if (index.nr_dec) from++; // Skipp '.'
for (i=(int) min(index.nr_dec,dec) ; i-- > 0 ; ) *to++ = *from++;
for (i=(int) (dec-min(index.nr_dec,dec)) ; i-- > 0 ; ) *to++ = '0';
}
/*
** Check for incorrect string if in batch mode (ALTER TABLE/LOAD DATA...)
*/
if (!error && current_thd->count_cuted_fields && from != end)
{ // Check if number was cuted
for (; from != end ; from++)
{
if (*from != '0')
{
if (!isspace(*from)) // Space is ok
current_thd->cuted_fields++;
break;
}
}
}
}
void Field_decimal::store(double nr)
{
if (unsigned_flag && nr < 0)
{
overflow(1);
current_thd->cuted_fields++;
return;
}
reg4 uint i,length;
char fyllchar,*to;
char buff[320];
fyllchar = zerofill ? (char) '0' : (char) ' ';
sprintf(buff,"%.*f",decimals,nr);
length=strlen(buff);
if (length > field_length)
{
overflow(nr < 0.0);
current_thd->cuted_fields++;
}
else
{
to=ptr;
for (i=field_length-length ; i-- > 0 ;)
*to++ = fyllchar;
memcpy(to,buff,length);
}
}
void Field_decimal::store(longlong nr)
{
if (unsigned_flag && nr < 0)
{
overflow(1);
current_thd->cuted_fields++;
return;
}
char buff[22];
uint length=(uint) (longlong2str(nr,buff,-10)-buff);
uint int_part=field_length- (decimals ? decimals+1 : 0);
if (length > int_part)
{
overflow(test(nr < 0L)); /* purecov: inspected */
current_thd->cuted_fields++; /* purecov: inspected */
}
else
{
char fyllchar = zerofill ? (char) '0' : (char) ' ';
char *to=ptr;
for (uint i=int_part-length ; i-- > 0 ;)
*to++ = fyllchar;
memcpy(to,buff,length);
if (decimals)
{
to[length]='.';
bfill(to+length+1,decimals,'0');
}
}
}
double Field_decimal::val_real(void)
{
char temp= *(ptr+field_length); *(ptr+field_length) = '\0';
double nr=atod(ptr);
*(ptr+field_length)=temp;
return(nr);
}
longlong Field_decimal::val_int(void)
{
char temp= *(ptr+field_length); *(ptr+field_length) = '\0';
longlong nr;
if (unsigned_flag)
nr=(longlong) strtoull(ptr,NULL,10);
else
nr=strtoll(ptr,NULL,10);
*(ptr+field_length)=temp;
return(nr);
}
String *Field_decimal::val_str(String *val_buffer,String *val_ptr)
{
char *str;
for (str=ptr ; *str == ' ' ; str++) ;
uint tmp_length=(uint) (str-ptr);
if (field_length < tmp_length) // Error in data
val_ptr->length(0);
else
val_ptr->set((const char*) str,field_length-tmp_length);
return val_ptr;
}
/*
** Should be able to handle at least the following fixed decimal formats:
** 5.00 , -1.0, 05, -05, +5 with optional pre/end space
*/
int Field_decimal::cmp(const char *a_ptr,const char *b_ptr)
{
const char *end;
/* First remove prefixes '0', ' ', and '-' */
for (end=a_ptr+field_length;
a_ptr != end &&
(*a_ptr == *b_ptr ||
((isspace(*a_ptr) || *a_ptr == '+' || *a_ptr == '0') &&
(isspace(*b_ptr) || *b_ptr == '+' || *b_ptr == '0')));
a_ptr++,b_ptr++) ;
if (a_ptr == end)
return 0;
int swap=0;
if (*a_ptr == '-')
{
if (*b_ptr != '-')
return -1;
swap= -1 ^ 1; // Swap result
a_ptr++, b_ptr++;
} else if (*b_ptr == '-')
return 1;
while (a_ptr != end)
{
if (*a_ptr++ != *b_ptr++)
return swap ^ (a_ptr[-1] < b_ptr[-1] ? -1 : 1); // compare digits
}
return 0;
}
void Field_decimal::sort_string(char *to,uint length)
{
char *str,*end;
for (str=ptr,end=ptr+length;
str != end &&
((isspace(*str) || *str == '+' || *str == '0')) ;
str++)
*to++=' ';
if (str == end)
return; /* purecov: inspected */
if (*str == '-')
{
*to++=1; // Smaller than any number
str++;
while (str != end)
if (isdigit(*str))
*to++= (char) ('9' - *str++);
else
*to++= *str++;
}
else memcpy(to,str,(uint) (end-str));
}
void Field_decimal::sql_type(String &res) const
{
sprintf((char*) res.ptr(),"decimal(%d,%d)",field_length,decimals);
add_zerofill_and_unsigned(res);
}
/****************************************************************************
** tiny int
****************************************************************************/
void Field_tiny::store(const char *from,uint len)
{
String tmp_str(from,len);
long tmp= strtol(tmp_str.c_ptr(),NULL,10);
if (unsigned_flag)
{
if (tmp < 0)
{
tmp=0; /* purecov: inspected */
current_thd->cuted_fields++; /* purecov: inspected */
}
else if (tmp > 255)
{
tmp= 255;
current_thd->cuted_fields++;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
current_thd->cuted_fields++;
}
else
{
if (tmp < -128)
{
tmp= -128;
current_thd->cuted_fields++;
}
else if (tmp >= 128)
{
tmp= 127;
current_thd->cuted_fields++;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
current_thd->cuted_fields++;
}
ptr[0]= (char) tmp;
}
void Field_tiny::store(double nr)
{
nr=rint(nr);
if (unsigned_flag)
{
if (nr < 0.0)
{
*ptr=0;
current_thd->cuted_fields++;
}
else if (nr > 255.0)
{
*ptr=(char) 255;
current_thd->cuted_fields++;
}
else
*ptr=(char) nr;
}
else
{
if (nr < -128.0)
{
*ptr= (char) -128;
current_thd->cuted_fields++;
}
else if (nr > 127.0)
{
*ptr=127;
current_thd->cuted_fields++;
}
else
*ptr=(char) nr;
}
}
void Field_tiny::store(longlong nr)
{
if (unsigned_flag)
{
if (nr < 0L)
{
*ptr=0;
current_thd->cuted_fields++;
}
else if (nr > 255L)
{
*ptr= (char) 255;
current_thd->cuted_fields++;
}
else
*ptr=(char) nr;
}
else
{
if (nr < -128L)
{
*ptr= (char) -128;
current_thd->cuted_fields++;
}
else if (nr > 127L)
{
*ptr=127;
current_thd->cuted_fields++;
}
else
*ptr=(char) nr;
}
}
double Field_tiny::val_real(void)
{
int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
(int) ((signed char*) ptr)[0];
return (double) tmp;
}
longlong Field_tiny::val_int(void)
{
int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
(int) ((signed char*) ptr)[0];
return (longlong) tmp;
}
String *Field_tiny::val_str(String *val_buffer,String *val_ptr)
{
uint length;
val_buffer->alloc(max(field_length+1,5));
char *to=(char*) val_buffer->ptr();
if (unsigned_flag)
length= (uint) (int2str((long) *((uchar*) ptr),to,10)-to);
else
length=(int2str((long) *((signed char*) ptr),to,-10)-to);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
return val_buffer;
}
int Field_tiny::cmp(const char *a_ptr, const char *b_ptr)
{
signed char a,b;
a=(signed char) a_ptr[0]; b= (signed char) b_ptr[0];
if (unsigned_flag)
return ((uchar) a < (uchar) b) ? -1 : ((uchar) a > (uchar) b) ? 1 : 0;
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
void Field_tiny::sort_string(char *to,uint length)
{
if (unsigned_flag)
*to= *ptr;
else
to[0] = (char) ((uchar) ptr[0] ^ (uchar) 128); /* Revers signbit */
}
void Field_tiny::sql_type(String &res) const
{
sprintf((char*) res.ptr(),"tinyint(%d)",field_length);
add_zerofill_and_unsigned(res);
}
/****************************************************************************
** short int
****************************************************************************/
// Note: Sometimes this should be fixed to use one strtol() to use
// len and check for garbage after number.
void Field_short::store(const char *from,uint len)
{
String tmp_str(from,len);
long tmp= strtol(tmp_str.c_ptr(),NULL,10);
if (unsigned_flag)
{
if (tmp < 0)
{
tmp=0;
current_thd->cuted_fields++;
}
else if (tmp > (uint16) ~0)
{
tmp=(uint16) ~0;
current_thd->cuted_fields++;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
current_thd->cuted_fields++;
}
else
{
if (tmp < INT_MIN16)
{
tmp= INT_MIN16;
current_thd->cuted_fields++;
}
else if (tmp > INT_MAX16)
{
tmp=INT_MAX16;
current_thd->cuted_fields++;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
current_thd->cuted_fields++;
}
shortstore(ptr,(short) tmp);
}
void Field_short::store(double nr)
{
nr=rint(nr);
if (unsigned_flag)
{
if (nr < 0)
{
shortstore(ptr,0);
current_thd->cuted_fields++;
}
else if (nr > (double) (uint16) ~0)
{
shortstore(ptr,(uint16) ~0);
current_thd->cuted_fields++;
}
else
shortstore(ptr,(uint16) nr);
}
else
{
if (nr < (double) INT_MIN16)
{
shortstore(ptr,INT_MIN16);
current_thd->cuted_fields++;
}
else if (nr > (double) INT_MAX16)
{
shortstore(ptr,INT_MAX16);
current_thd->cuted_fields++;
}
else
shortstore(ptr,(int16) nr);
}
}
void Field_short::store(longlong nr)
{
if (unsigned_flag)
{
if (nr < 0L)
{
shortstore(ptr,0);
current_thd->cuted_fields++;
}
else if (nr > (longlong) (uint16) ~0)
{
shortstore(ptr,(uint16) ~0);
current_thd->cuted_fields++;
}
else
shortstore(ptr,(uint16) nr);
}
else
{
if (nr < INT_MIN16)
{
shortstore(ptr,INT_MIN16);
current_thd->cuted_fields++;
}
else if (nr > INT_MAX16)
{
shortstore(ptr,INT_MAX16);
current_thd->cuted_fields++;
}
else
shortstore(ptr,(int16) nr);
}
}
double Field_short::val_real(void)
{
short j;
shortget(j,ptr)
return unsigned_flag ? (double) (unsigned short) j : (double) j;
}
longlong Field_short::val_int(void)
{
short j;
shortget(j,ptr)
return unsigned_flag ? (longlong) (unsigned short) j : (longlong) j;
}
String *Field_short::val_str(String *val_buffer,String *val_ptr)
{
uint length;
val_buffer->alloc(max(field_length+1,7));
char *to=(char*) val_buffer->ptr();
short j; shortget(j,ptr);
if (unsigned_flag)
length=(uint) (int2str((long) (uint16) j,to,10)-to);
else
length=(uint) (int2str((long) j,to,-10)-to);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
return val_buffer;
}
int Field_short::cmp(const char *a_ptr, const char *b_ptr)
{
short a,b;
shortget(a,a_ptr);
shortget(b,b_ptr);
if (unsigned_flag)
return ((unsigned short) a < (unsigned short) b) ? -1 :
((unsigned short) a > (unsigned short) b) ? 1 : 0;
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
void Field_short::sort_string(char *to,uint length)
{
#ifdef WORDS_BIGENDIAN
if (unsigned_flag)
to[0] = ptr[0];
else
to[0] = ptr[0] ^ 128; /* Revers signbit */
to[1] = ptr[1];
#else
if (unsigned_flag)
to[0] = ptr[1];
else
to[0] = ptr[1] ^ 128; /* Revers signbit */
to[1] = ptr[0];
#endif
}
void Field_short::sql_type(String &res) const
{
sprintf((char*) res.ptr(),"smallint(%d)",field_length);
add_zerofill_and_unsigned(res);
}
/****************************************************************************
** medium int
****************************************************************************/
// Note: Sometimes this should be fixed to use one strtol() to use
// len and check for garbage after number.
void Field_medium::store(const char *from,uint len)
{
String tmp_str(from,len);
long tmp= strtol(tmp_str.c_ptr(),NULL,10);
if (unsigned_flag)
{
if (tmp < 0)
{
tmp=0;
current_thd->cuted_fields++;
}
else if (tmp >= (long) (1L << 24))
{
tmp=(long) (1L << 24)-1L;
current_thd->cuted_fields++;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
current_thd->cuted_fields++;
}
else
{
if (tmp < INT_MIN24)
{
tmp= INT_MIN24;
current_thd->cuted_fields++;
}
else if (tmp > INT_MAX24)
{
tmp=INT_MAX24;
current_thd->cuted_fields++;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
current_thd->cuted_fields++;
}
int3store(ptr,tmp);
}
void Field_medium::store(double nr)
{
nr=rint(nr);
if (unsigned_flag)
{
if (nr < 0)
{
int3store(ptr,0);
current_thd->cuted_fields++;
}
else if (nr >= (double) (long) (1L << 24))
{
ulong tmp=(ulong) (1L << 24)-1L;
int3store(ptr,tmp);
current_thd->cuted_fields++;
}
else
int3store(ptr,(ulong) nr);
}
else
{
if (nr < (double) INT_MIN24)
{
long tmp=(long) INT_MIN24;
int3store(ptr,tmp);
current_thd->cuted_fields++;
}
else if (nr > (double) INT_MAX24)
{
long tmp=(long) INT_MAX24;
int3store(ptr,tmp);
current_thd->cuted_fields++;
}
else
int3store(ptr,(long) nr);
}
}
void Field_medium::store(longlong nr)
{
if (unsigned_flag)
{
if (nr < 0L)
{
int3store(ptr,0);
current_thd->cuted_fields++;
}
else if (nr >= (longlong) (long) (1L << 24))
{
long tmp=(long) (1L << 24)-1L;;
int3store(ptr,tmp);
current_thd->cuted_fields++;
}
else
int3store(ptr,(ulong) nr);
}
else
{
if (nr < (longlong) INT_MIN24)
{
long tmp=(long) INT_MIN24;
int3store(ptr,tmp);
current_thd->cuted_fields++;
}
else if (nr > (longlong) INT_MAX24)
{
long tmp=(long) INT_MAX24;
int3store(ptr,tmp);
current_thd->cuted_fields++;
}
else
int3store(ptr,(long) nr);
}
}
double Field_medium::val_real(void)
{
long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
return (double) j;
}
longlong Field_medium::val_int(void)
{
long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
return (longlong) j;
}
String *Field_medium::val_str(String *val_buffer,String *val_ptr)
{
uint length;
val_buffer->alloc(max(field_length+1,10));
char *to=(char*) val_buffer->ptr();
long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
length=(uint) (int2str(j,to,-10)-to);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer); /* purecov: inspected */
return val_buffer;
}
int Field_medium::cmp(const char *a_ptr, const char *b_ptr)
{
long a,b;
if (unsigned_flag)
{
a=uint3korr(a_ptr);
b=uint3korr(b_ptr);
}
else
{
a=sint3korr(a_ptr);
b=sint3korr(b_ptr);
}
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
void Field_medium::sort_string(char *to,uint length)
{
if (unsigned_flag)
to[0] = ptr[2];
else
to[0] = (uchar) (ptr[2] ^ 128); /* Revers signbit */
to[1] = ptr[1];
to[2] = ptr[0];
}
void Field_medium::sql_type(String &res) const
{
sprintf((char*) res.ptr(),"mediumint(%d)",field_length);
add_zerofill_and_unsigned(res);
}
/****************************************************************************
** long int
****************************************************************************/
// Note: Sometimes this should be fixed to use one strtol() to use
// len and check for garbage after number.
void Field_long::store(const char *from,uint len)
{
while (len && isspace(*from))
{
len--; from++;
}
long tmp;
String tmp_str(from,len);
errno=0;
if (unsigned_flag)
{
if (!len || *from == '-')
{
tmp=0; // Set negative to 0
errno=ERANGE;
}
else
tmp=(long) strtoul(tmp_str.c_ptr(),NULL,10);
}
else
tmp=strtol(tmp_str.c_ptr(),NULL,10);
if (errno || current_thd->count_cuted_fields && !test_if_int(from,len))
current_thd->cuted_fields++;
longstore(ptr,tmp);
}
void Field_long::store(double nr)
{
nr=rint(nr);
if (unsigned_flag)
{
if (nr < 0)
{
longstore(ptr,0);
current_thd->cuted_fields++;
}
else if (nr > (double) (ulong) ~0L)
{
ulong tmp=(ulong) ~0L;
longstore(ptr,tmp);
current_thd->cuted_fields++;
}
else
longstore(ptr,(ulong) nr);
}
else
{
if (nr < (double) INT_MIN32)
{
long tmp=(long) INT_MIN32;
longstore(ptr,tmp);
current_thd->cuted_fields++;
}
else if (nr > (double) INT_MAX32)
{
long tmp=(long) INT_MAX32;
longstore(ptr,tmp);
current_thd->cuted_fields++;
}
else
longstore(ptr,(long) nr);
}
}
void Field_long::store(longlong nr)
{
if (unsigned_flag)
{
if (nr < 0)
{
longstore(ptr,0);
current_thd->cuted_fields++;
}
else if (nr > (longlong) (uint32) ~0L)
{
uint32 tmp=(uint32) ~0L;
longstore(ptr,tmp);
current_thd->cuted_fields++;
}
else
longstore(ptr,(uint32) nr);
}
else
{
if (nr < (longlong) INT_MIN32)
{
int32 tmp=(int32) INT_MIN32;
longstore(ptr,tmp);
current_thd->cuted_fields++;
}
else if (nr > (longlong) INT_MAX32)
{
int32 tmp=(int32) INT_MAX32;
longstore(ptr,tmp);
current_thd->cuted_fields++;
}
else
longstore(ptr,(int32) nr);
}
}
double Field_long::val_real(void)
{
int32 j;
longget(j,ptr);
return unsigned_flag ? (double) (uint32) j : (double) j;
}
longlong Field_long::val_int(void)
{
int32 j;
longget(j,ptr)
return unsigned_flag ? (longlong) (uint32) j : (longlong) j;
}
String *Field_long::val_str(String *val_buffer,String *val_ptr)
{
uint length;
val_buffer->alloc(max(field_length+1,12));
char *to=(char*) val_buffer->ptr();
int32 j; longget(j,ptr);
length=(uint) (int2str((unsigned_flag ? (long) (uint32) j : (long) j),
to,
unsigned_flag ? 10 : -10)-to);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
return val_buffer;
}
int Field_long::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
longget(a,a_ptr);
longget(b,b_ptr);
if (unsigned_flag)
return ((ulong) a < (ulong) b) ? -1 : ((ulong) a > (ulong) b) ? 1 : 0;
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
void Field_long::sort_string(char *to,uint length)
{
#ifdef WORDS_BIGENDIAN
if (unsigned_flag)
to[0] = ptr[0];
else
to[0] = ptr[0] ^ 128; /* Revers signbit */
to[1] = ptr[1];
to[2] = ptr[2];
to[3] = ptr[3];
#else
if (unsigned_flag)
to[0] = ptr[3];
else
to[0] = ptr[3] ^ 128; /* Revers signbit */
to[1] = ptr[2];
to[2] = ptr[1];
to[3] = ptr[0];
#endif
}
void Field_long::sql_type(String &res) const
{
sprintf((char*) res.ptr(),"int(%d)",field_length);
add_zerofill_and_unsigned(res);
}
/****************************************************************************
** longlong int
****************************************************************************/
void Field_longlong::store(const char *from,uint len)
{
while (len && isspace(*from))
{ // For easy error check
len--; from++;
}
longlong tmp;
String tmp_str(from,len);
errno=0;
if (unsigned_flag)
{
if (!len || *from == '-')
{
tmp=0; // Set negative to 0
errno=ERANGE;
}
else
tmp=(longlong) strtoull(tmp_str.c_ptr(),NULL,10);
}
else
tmp=strtoll(tmp_str.c_ptr(),NULL,10);
if (errno || current_thd->count_cuted_fields && !test_if_int(from,len))
current_thd->cuted_fields++;
longlongstore(ptr,tmp);
}
void Field_longlong::store(double nr)
{
nr=rint(nr);
if (unsigned_flag)
{
if (nr < 0)
{
bzero(ptr,pack_length());
current_thd->cuted_fields++;
}
else if (nr > (double) ~ (ulonglong) 0)
{
bfill(ptr,pack_length(),(char) 255);
current_thd->cuted_fields++;
}
else
{
ulonglong tmp=(ulonglong) nr;
longlongstore(ptr,tmp);
}
}
else
{
if (nr <= (double) LONGLONG_MIN)
{
longlong tmp=(longlong) LONGLONG_MIN;
longlongstore(ptr,tmp);
current_thd->cuted_fields++;
}
else if (nr >= (double) LONGLONG_MAX)
{
longlong tmp=(longlong) LONGLONG_MAX;
longlongstore(ptr,tmp);
current_thd->cuted_fields++;
}
else
{
longlong tmp=(longlong) nr;
longlongstore(ptr,tmp);
}
}
}
void Field_longlong::store(longlong nr)
{
longlongstore(ptr,nr);
}
double Field_longlong::val_real(void)
{
longlong j;
longlongget(j,ptr);
return unsigned_flag ? ulonglong2double(j) : (double) j;
}
longlong Field_longlong::val_int(void)
{
longlong j;
longlongget(j,ptr);
return j;
}
String *Field_longlong::val_str(String *val_buffer,String *val_ptr)
{
uint length;
val_buffer->alloc(max(field_length+1,22));
char *to=(char*) val_buffer->ptr();
longlong j; longlongget(j,ptr);
length=(uint) (longlong2str(j,to,unsigned_flag ? 10 : -10)-to);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
return val_buffer;
}
int Field_longlong::cmp(const char *a_ptr, const char *b_ptr)
{
longlong a,b;
longlongget(a,a_ptr);
longlongget(b,b_ptr);
if (unsigned_flag)
return ((ulonglong) a < (ulonglong) b) ? -1 :
((ulonglong) a > (ulonglong) b) ? 1 : 0;
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
void Field_longlong::sort_string(char *to,uint length)
{
#ifdef WORDS_BIGENDIAN
if (unsigned_flag)
to[0] = ptr[0];
else
to[0] = ptr[0] ^ 128; /* Revers signbit */
to[1] = ptr[1];
to[2] = ptr[2];
to[3] = ptr[3];
to[4] = ptr[4];
to[5] = ptr[5];
to[6] = ptr[6];
to[7] = ptr[7];
#else
if (unsigned_flag)
to[0] = ptr[7];
else
to[0] = ptr[7] ^ 128; /* Revers signbit */
to[1] = ptr[6];
to[2] = ptr[5];
to[3] = ptr[4];
to[4] = ptr[3];
to[5] = ptr[2];
to[6] = ptr[1];
to[7] = ptr[0];
#endif
}
void Field_longlong::sql_type(String &res) const
{
sprintf((char*) res.ptr(),"bigint(%d)",field_length);
add_zerofill_and_unsigned(res);
}
/****************************************************************************
** single precision float
****************************************************************************/
void Field_float::store(const char *from,uint len)
{
String tmp_str(from,len);
errno=0;
Field_float::store(atof(tmp_str.c_ptr()));
if (errno || current_thd->count_cuted_fields && !test_if_real(from,len))
current_thd->cuted_fields++;
}
void Field_float::store(double nr)
{
if (decimals != 31)
nr=floor(nr*log_10[decimals]+0.5)/log_10[decimals]; // To fixed point
float j;
if (nr < -FLT_MAX)
{
j= -FLT_MAX;
current_thd->cuted_fields++;
}
else if (nr > FLT_MAX)
{
j=FLT_MAX;
current_thd->cuted_fields++;
}
else
j= (float) nr;
memcpy(ptr,(byte*) &j,sizeof(j));
}
void Field_float::store(longlong nr)
{
float j= (float) nr;
memcpy(ptr,(byte*) &j,sizeof(j));
}
double Field_float::val_real(void)
{
float j; memcpy((byte*) &j,ptr,sizeof(j));
return ((double) j);
}
longlong Field_float::val_int(void)
{
float j; memcpy((byte*) &j,ptr,sizeof(j));
return ((longlong) j);
}
String *Field_float::val_str(String *val_buffer,String *val_ptr)
{
float j;
memcpy((byte*) &j,(char*) ptr,sizeof(j));
val_buffer->alloc(max(field_length,70));
char *to=(char*) val_buffer->ptr();
#ifdef HAVE_FCONVERT
char buff[70],*pos=buff;
int decpt,sign,dec=decimals;
VOID(sfconvert(&j,dec,&decpt,&sign,buff));
if (sign)
{
*to++='-';
}
if (decpt < 0)
{ /* val_buffer is < 0 */
*to++='0';
if (!dec)
goto end;
*to++='.';
if (-decpt > dec)
decpt= - (int) dec;
dec=(uint) ((int) dec+decpt);
while (decpt++ < 0)
*to++='0';
}
else if (decpt == 0)
{
*to++= '0';
if (!dec)
goto end;
*to++='.';
}
else
{
while (decpt-- > 0)
*to++= *pos++;
if (!dec)
goto end;
*to++='.';
}
while (dec--)
*to++= *pos++;
end:
#else
sprintf(to,"%.*lf",decimals,j);
to=strend(to);
#endif
val_buffer->length((uint) (to-val_buffer->ptr()));
if (zerofill)
prepend_zeros(val_buffer);
return val_buffer;
}
int Field_float::cmp(const char *a_ptr, const char *b_ptr)
{
float a,b;
memcpy(&a,a_ptr,sizeof(float));
memcpy(&b,b_ptr,sizeof(float));
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
#define FLT_EXP_DIG (sizeof(float)*8-FLT_MANT_DIG)
void Field_float::sort_string(char *to,uint length)
{
float nr;
memcpy(&nr,ptr,sizeof(nr));
uchar *tmp= (uchar*) to;
if (nr == (float) 0.0)
{ /* Change to zero string */
tmp[0]=(uchar) 128;
bzero((char*) tmp+1,sizeof(nr)-1);
}
else
{
#ifdef WORDS_BIGENDIAN
memcpy(tmp,&nr,sizeof(nr));
#else
tmp[0]= ptr[3]; tmp[1]=ptr[2]; tmp[2]= ptr[1]; tmp[3]=ptr[0];
#endif
if (tmp[0] & 128) /* Negative */
{ /* make complement */
uint i;
for (i=0 ; i < sizeof(nr); i++)
tmp[i]=tmp[i] ^ (uchar) 255;
}
else
{
ushort exp=((ushort) tmp[0] << 8) | (ushort) tmp[1] | (ushort) 32768;
exp+= (ushort) 1 << (16-1-FLT_EXP_DIG);
tmp[0]= (uchar) (exp >> 8);
tmp[1]= (uchar) exp;
}
}
}
void Field_float::sql_type(String &res) const
{
sprintf((char*) res.ptr(),"float(%d,%d)",field_length,decimals);
add_zerofill_and_unsigned(res);
}
/****************************************************************************
** double precision floating point numbers
****************************************************************************/
void Field_double::store(const char *from,uint len)
{
String tmp_str(from,len);
errno=0;
double j= atof(tmp_str.c_ptr());
if (errno || current_thd->count_cuted_fields && !test_if_real(from,len))
current_thd->cuted_fields++;
doublestore(ptr,j);
}
void Field_double::store(double nr)
{
if (decimals != 31)
nr=floor(nr*log_10[decimals]+0.5)/log_10[decimals]; // To fixed point
doublestore(ptr,nr);
}
void Field_double::store(longlong nr)
{
double j= (double) nr;
doublestore(ptr,j);
}
double Field_double::val_real(void)
{
double j; doubleget(j,ptr);
return j;
}
longlong Field_double::val_int(void)
{
double j; doubleget(j,ptr);
return ((longlong) j);
}
String *Field_double::val_str(String *val_buffer,String *val_ptr)
{
double j;
doubleget(j,ptr);
val_buffer->alloc(max(field_length,320));
char *to=(char*) val_buffer->ptr();
#ifdef HAVE_FCONVERT
char buff[320],*pos=buff;
int decpt,sign,dec=decimals;
VOID(fconvert(j,dec,&decpt,&sign,buff));
if (sign)
{
*to++='-';
}
if (decpt < 0)
{ /* val_buffer is < 0 */
*to++='0';
if (!dec)
goto end;
*to++='.';
if (-decpt > dec)
decpt= - (int) dec;
dec=(uint) ((int) dec+decpt);
while (decpt++ < 0)
*to++='0';
}
else if (decpt == 0)
{
*to++= '0';
if (!dec)
goto end;
*to++='.';
}
else
{
while (decpt-- > 0)
*to++= *pos++;
if (!dec)
goto end;
*to++='.';
}
while (dec--)
*to++= *pos++;
end:
#else
sprintf(to,"%.*lf",decimals,j);
to=strend(to);
#endif
val_buffer->length((uint) (to-val_buffer->ptr()));
if (zerofill)
prepend_zeros(val_buffer);
return val_buffer;
}
int Field_double::cmp(const char *a_ptr, const char *b_ptr)
{
double a,b;
memcpy(&a,a_ptr,sizeof(double));
memcpy(&b,b_ptr,sizeof(double));
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
#define DBL_EXP_DIG (sizeof(double)*8-DBL_MANT_DIG)
/* The following should work for IEEE */
void Field_double::sort_string(char *to,uint length)
{
double nr;
memcpy(&nr,ptr,sizeof(nr));
change_double_for_sort(nr, (byte*) to);
}
void Field_double::sql_type(String &res) const
{
sprintf((char*) res.ptr(),"double(%d,%d)",field_length,decimals);
add_zerofill_and_unsigned(res);
}
/****************************************************************************
** timestamp
** The first timestamp in the table is automaticly updated
** by handler.cc. The form->timestamp points at the automatic timestamp.
****************************************************************************/
Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
enum utype unireg_check_arg,
char *field_name_arg,
struct st_table *table_arg)
:Field_num(ptr_arg, len_arg, (uchar*) 0,0,
unireg_check_arg, field_name_arg, table_arg,
0, 1, 1)
{
if (table && !table->timestamp_field)
{
table->timestamp_field= this; // Automatic timestamp
table->time_stamp=(uint) (ptr_arg - (char*) table->record[0])+1;
flags|=TIMESTAMP_FLAG;
}
}
void Field_timestamp::store(const char *from,uint len)
{
long tmp=(long) str_to_timestamp(from,len);
longstore(ptr,tmp);
}
void Field_timestamp::fill_and_store(char *from,uint len)
{
uint res_length;
if (len <= field_length)
res_length=field_length;
else if (len <= 12)
res_length=12; /* purecov: inspected */
else if (len <= 14)
res_length=14; /* purecov: inspected */
else
res_length=(len+1)/2*2; // must be even
if (res_length != len)
{
bmove_upp(from+res_length,from+len,len);
bfill(from,res_length-len,'0');
len=res_length;
}
long skr=(long) str_to_timestamp(from,len);
longstore(ptr,skr);
}
void Field_timestamp::store(double nr)
{
if (nr < 0 || nr > 99991231235959.0)
{
nr=0; // Avoid overflow on buff
current_thd->cuted_fields++;
}
Field_timestamp::store((longlong) rint(nr));
}
/*
** Convert a datetime of formats YYMMDD, YYYYMMDD or YYMMDDHHMSS to
** YYYYMMDDHHMMSS. The high date '99991231235959' is checked before this
** function.
*/
static longlong fix_datetime(longlong nr)
{
if (nr == LL(0) || nr >= LL(10000101000000))
return nr; // Normal datetime >= Year 1000
if (nr < 101)
goto err;
if (nr <= 691231L)
return (nr+20000000L)*1000000L; // YYMMDD, year: 2000-2069
if (nr < 700101L)
goto err;
if (nr <= 991231L)
return (nr+19000000L)*1000000L; // YYMMDD, year: 1970-1999
if (nr < 10000101L)
goto err;
if (nr <= 99991231L)
return nr*1000000L;
if (nr < 101000000L)
goto err;
if (nr <= LL(691231235959))
return nr+LL(20000000000000); // YYMMDDHHMMSS, 2000-2069
if (nr < LL(700101000000))
goto err;
if (nr <= LL(991231235959))
return nr+LL(19000000000000); // YYMMDDHHMMSS, 1970-1999
err:
current_thd->cuted_fields++;
return LL(0);
}
void Field_timestamp::store(longlong nr)
{
char buff[22];
fill_and_store(buff,longlong2str(fix_datetime(nr),buff,10)-buff);
}
double Field_timestamp::val_real(void)
{
return (double) Field_timestamp::val_int();
}
longlong Field_timestamp::val_int(void)
{
uint len,pos;
int part_time;
uint32 temp;
time_t time_arg;
struct tm *l_time;
longlong res;
struct tm tm_tmp;
longget(temp,ptr);
if (temp == 0L) // No time
return(0); /* purecov: inspected */
time_arg=(time_t) temp;
localtime_r(&time_arg,&tm_tmp);
l_time=&tm_tmp;
res=(longlong) 0;
for (pos=len=0; len+1 < (uint) field_length ; len+=2,pos++)
{
bool year_flag=0;
switch (dayord.pos[pos]) {
case 0: part_time=l_time->tm_year % 100; year_flag=1 ; break;
case 1: part_time=l_time->tm_mon+1; break;
case 2: part_time=l_time->tm_mday; break;
case 3: part_time=l_time->tm_hour; break;
case 4: part_time=l_time->tm_min; break;
case 5: part_time=l_time->tm_sec; break;
default: part_time=0; break; /* purecov: deadcode */
}
if (year_flag && (field_length == 8 || field_length == 14))
{
res=res*(longlong) 10000+(part_time+((part_time < 70) ? 2000 : 1900));
len+=2;
}
else
res=res*(longlong) 100+part_time;
}
return (longlong) res;
}
String *Field_timestamp::val_str(String *val_buffer,String *val_ptr)
{
uint pos;
int part_time;
uint32 temp;
time_t time_arg;
struct tm *l_time;
struct tm tm_tmp;
val_buffer->alloc(field_length+1);
char *to=(char*) val_buffer->ptr(),*end=to+field_length;
longget(temp,ptr);
if (temp == 0L)
{ /* Zero time is "000000" */
VOID(strfill(to,field_length,'0'));
val_buffer->length(field_length);
return val_buffer;
}
time_arg=(time_t) temp;
localtime_r(&time_arg,&tm_tmp);
l_time=&tm_tmp;
for (pos=0; to < end ; pos++)
{
bool year_flag=0;
switch (dayord.pos[pos]) {
case 0: part_time=l_time->tm_year % 100; year_flag=1; break;
case 1: part_time=l_time->tm_mon+1; break;
case 2: part_time=l_time->tm_mday; break;
case 3: part_time=l_time->tm_hour; break;
case 4: part_time=l_time->tm_min; break;
case 5: part_time=l_time->tm_sec; break;
default: part_time=0; break; /* purecov: deadcode */
}
if (year_flag && (field_length == 8 || field_length == 14))
{
if (part_time < 70)
{
*to++='2'; *to++='0'; /* purecov: inspected */
}
else
{
*to++='1'; *to++='9';
}
}
*to++=(char) ('0'+((uint) part_time/10));
*to++=(char) ('0'+((uint) part_time % 10));
}
*to=0; // Safeguard
val_buffer->length((uint) (to-val_buffer->ptr()));
return val_buffer;
}
int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
longget(a,a_ptr);
longget(b,b_ptr);
return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
}
void Field_timestamp::sort_string(char *to,uint length)
{
#ifdef WORDS_BIGENDIAN
to[0] = ptr[0];
to[1] = ptr[1];
to[2] = ptr[2];
to[3] = ptr[3];
#else
to[0] = ptr[3];
to[1] = ptr[2];
to[2] = ptr[1];
to[3] = ptr[0];
#endif
}
void Field_timestamp::sql_type(String &res) const
{
sprintf((char*) res.ptr(),"timestamp(%d)",field_length);
res.length(strlen(res.ptr()));
}
void Field_timestamp::set_time()
{
long skr= current_thd->query_start();
longstore(ptr,skr);
}
/****************************************************************************
** time type
** In string context: HH:MM:SS
** In number context: HHMMSS
** Stored as a 3 byte unsigned int
****************************************************************************/
void Field_time::store(const char *from,uint len)
{
TIME ltime;
long tmp;
if (str_to_time(from,len,&ltime))
tmp=0L;
else
{
tmp=(ltime.day*24L+ltime.hour*10000L)+(ltime.minute*100+ltime.second);
if (tmp > 8385959)
{
tmp=8385959;
current_thd->cuted_fields++;
}
}
if (ltime.neg)
tmp= -tmp;
Field_time::store((longlong) tmp);
}
void Field_time::store(double nr)
{
long tmp;
if (nr > 8385959.0)
{
tmp=8385959L;
current_thd->cuted_fields++;
}
else if (nr < -8385959.0)
{
tmp= -8385959L;
current_thd->cuted_fields++;
}
else
{
tmp=(long) rint(nr);
if (tmp % 100 > 59 || tmp/100 % 100 > 59)
{
tmp=0;
current_thd->cuted_fields++;
}
}
int3store(ptr,tmp);
}
void Field_time::store(longlong nr)
{
long tmp;
if (nr > (longlong) 8385959L)
{
tmp=8385959L;
current_thd->cuted_fields++;
}
else if (nr < (longlong) -8385959L)
{
tmp= -8385959L;
current_thd->cuted_fields++;
}
else
{
tmp=(long) nr;
if (tmp % 100 > 59 || tmp/100 % 100 > 59)
{
tmp=0;
current_thd->cuted_fields++;
}
}
int3store(ptr,tmp);
}
double Field_time::val_real(void)
{
ulong j= (ulong) uint3korr(ptr);
return (double) j;
}
longlong Field_time::val_int(void)
{
return (longlong) sint3korr(ptr);
}
String *Field_time::val_str(String *val_buffer,String *val_ptr)
{
val_buffer->alloc(16);
long tmp=(long) sint3korr(ptr);
char *sign="";
if (tmp < 0)
{
tmp= -tmp;
sign= "-";
}
sprintf((char*) val_buffer->ptr(),"%s%02d:%02d:%02d",
sign,(int) tmp/10000, (int) (tmp/100 % 100),
(int) (tmp % 100));
val_buffer->length(strlen(val_buffer->ptr()));
return val_buffer;
}
int Field_time::cmp(const char *a_ptr, const char *b_ptr)
{
long a,b;
a=(long) sint3korr(a_ptr);
b=(long) sint3korr(b_ptr);
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
void Field_time::sort_string(char *to,uint length)
{
to[0] = (uchar) (ptr[2] ^ 128);
to[1] = ptr[1];
to[2] = ptr[0];
}
void Field_time::sql_type(String &res) const
{
res.set("time",4);
}
/****************************************************************************
** year type
** Save in a byte the year 0, 1901->2155
** Can handle 2 byte or 4 byte years!
****************************************************************************/
void Field_year::store(const char *from, uint len)
{
String tmp_str(from,len);
long nr= strtol(tmp_str.c_ptr(),NULL,10);
if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
{
*ptr=0;
current_thd->cuted_fields++;
return;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
current_thd->cuted_fields++;
if (nr != 0 || len != 4)
{
if (nr < 70)
nr+=100; // 2000 - 2069
else if (nr > 1900)
nr-= 1900;
}
*ptr= (char) (unsigned char) nr;
}
void Field_year::store(double nr)
{
if (nr < 0.0 || nr >= 2155.0)
Field_year::store((longlong) -1);
else
Field_year::store((longlong) nr);
}
void Field_year::store(longlong nr)
{
if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
{
*ptr=0;
current_thd->cuted_fields++;
return;
}
if (nr != 0 || field_length != 4) // 0000 -> 0; 00 -> 2000
{
if (nr < 70)
nr+=100; // 2000 - 2069
else if (nr > 1900)
nr-= 1900;
}
*ptr= (char) (unsigned char) nr;
}
double Field_year::val_real(void)
{
return (double) Field_year::val_int();
}
longlong Field_year::val_int(void)
{
int tmp= (int) ((uchar*) ptr)[0];
if (field_length != 4)
tmp%=100; // Return last 2 char
else if (tmp)
tmp+=1900;
return (longlong) tmp;
}
String *Field_year::val_str(String *val_buffer,String *val_ptr)
{
val_buffer->alloc(5);
val_buffer->length(field_length);
char *to=(char*) val_buffer->ptr();
sprintf(to,field_length == 2 ? "%02d" : "%04d",(int) Field_year::val_int());
return val_buffer;
}
void Field_year::sql_type(String &res) const
{
sprintf((char*) res.ptr(),"year(%d)",field_length);
res.length(strlen(res.ptr()));
}
/****************************************************************************
** date type
** In string context: YYYY-MM-DD
** In number context: YYYYMMDD
** Stored as a 4 byte unsigned int
****************************************************************************/
void Field_date::store(const char *from,uint len)
{
TIME l_time;
ulong tmp;
if (str_to_TIME(from,len,&l_time) == TIMESTAMP_NONE)
tmp=0;
else
tmp=(ulong) l_time.year*10000L + (ulong) (l_time.month*100+l_time.day);
longstore(ptr,tmp);
}
void Field_date::store(double nr)
{
long tmp;
if (nr > 19000000000000.0 && nr <= 99991231235959.0)
nr=floor(nr/1000000.0); // Timestamp to date
if (nr < 0.0 || nr > 99991231.0)
{
tmp=0L;
current_thd->cuted_fields++;
}
else
tmp=(long) rint(nr);
longstore(ptr,tmp);
}
void Field_date::store(longlong nr)
{
long tmp;
if (nr > LL(19000000000000) && nr < LL(99991231235959))
nr=nr/LL(1000000); // Timestamp to date
if (nr < 0 || nr > LL(99991231))
{
tmp=0L;
current_thd->cuted_fields++;
}
else
tmp=(long) nr;
longstore(ptr,tmp);
}
double Field_date::val_real(void)
{
int32 j;
longget(j,ptr);
return (double) (uint32) j;
}
longlong Field_date::val_int(void)
{
int32 j;
longget(j,ptr);
return (longlong) (uint32) j;
}
String *Field_date::val_str(String *val_buffer,String *val_ptr)
{
val_buffer->alloc(field_length);
val_buffer->length(field_length);
int32 tmp;
longget(tmp,ptr);
sprintf((char*) val_buffer->ptr(),"%04d-%02d-%02d",
(int) ((uint32) tmp/10000L % 10000), (int) ((uint32) tmp/100 % 100),
(int) ((uint32) tmp % 100));
return val_buffer;
}
int Field_date::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
longget(a,a_ptr);
longget(b,b_ptr);
return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
}
void Field_date::sort_string(char *to,uint length)
{
#ifdef WORDS_BIGENDIAN
to[0] = ptr[0];
to[1] = ptr[1];
to[2] = ptr[2];
to[3] = ptr[3];
#else
to[0] = ptr[3];
to[1] = ptr[2];
to[2] = ptr[1];
to[3] = ptr[0];
#endif
}
void Field_date::sql_type(String &res) const
{
res.set("date",4);
}
/****************************************************************************
** The new date type
** This is identical to the old date type, but stored on 3 bytes instead of 4
** In number context: YYYYMMDD
****************************************************************************/
void Field_newdate::store(const char *from,uint len)
{
TIME l_time;
long tmp;
if (str_to_TIME(from,len,&l_time) == TIMESTAMP_NONE)
tmp=0L;
else
tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
int3store(ptr,tmp);
}
void Field_newdate::store(double nr)
{
if (nr < 0.0 || nr > 99991231235959.0)
Field_newdate::store((longlong) -1);
else
Field_newdate::store((longlong) rint(nr));
}
void Field_newdate::store(longlong nr)
{
long tmp;
if (nr >= LL(100000000) && nr <= LL(99991231235959))
nr=nr/LL(1000000); // Timestamp to date
if (nr < 0L || nr > 99991231L)
{
tmp=0;
current_thd->cuted_fields++;
}
else
{
tmp=(long) nr;
if (tmp)
{
if (tmp < 700000) // Fix short dates
tmp+=20000000;
else if (tmp < 999999)
tmp+=19000000;
}
uint month=((tmp/100) % 100);
uint day= tmp%100;
if (month > 12 || day > 31)
{
tmp=0L; // Don't allow date to change
current_thd->cuted_fields++;
}
else
tmp= day + month*32 + (tmp/10000)*16*32;
}
int3store(ptr,tmp);
}
double Field_newdate::val_real(void)
{
return (double) Field_newdate::val_int();
}
longlong Field_newdate::val_int(void)
{
ulong j=uint3korr(ptr);
j= (j % 32L)+(j / 32L % 16L)*100L + (j/(16L*32L))*10000L;
return (longlong) j;
}
String *Field_newdate::val_str(String *val_buffer,String *val_ptr)
{
val_buffer->alloc(field_length);
val_buffer->length(field_length);
ulong tmp=(ulong) uint3korr(ptr);
sprintf((char*) val_buffer->ptr(),"%04d-%02d-%02d",
(int) (tmp/(32*16L) % 10000), (int) (tmp/32 % 16),
(int) (tmp % 32));
return val_buffer;
}
int Field_newdate::cmp(const char *a_ptr, const char *b_ptr)
{
ulong a,b;
a=(ulong) uint3korr(a_ptr);
b=(ulong) uint3korr(b_ptr);
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
void Field_newdate::sort_string(char *to,uint length)
{
to[0] = ptr[2];
to[1] = ptr[1];
to[2] = ptr[0];
}
void Field_newdate::sql_type(String &res) const
{
res.set("date",4);
}
/****************************************************************************
** datetime type
** In string context: YYYY-MM-DD HH:MM:DD
** In number context: YYYYMMDDHHMMDD
** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int.
****************************************************************************/
void Field_datetime::store(const char *from,uint len)
{
longlong tmp=str_to_datetime(from,len);
longlongstore(ptr,tmp);
}
void Field_datetime::store(double nr)
{
if (nr < 0.0 || nr > 99991231235959.0)
{
nr=0.0;
current_thd->cuted_fields++;
}
Field_datetime::store((longlong) rint(nr));
}
void Field_datetime::store(longlong nr)
{
if (nr < 0 || nr > LL(99991231235959))
{
nr=0;
current_thd->cuted_fields++;
}
else
nr=fix_datetime(nr);
longlongstore(ptr,nr);
}
double Field_datetime::val_real(void)
{
return (double) Field_datetime::val_int();
}
longlong Field_datetime::val_int(void)
{
longlong j;
longlongget(j,ptr);
return j;
}
String *Field_datetime::val_str(String *val_buffer,String *val_ptr)
{
val_buffer->alloc(field_length);
val_buffer->length(field_length);
ulonglong tmp;
longlongget(tmp,ptr);
// We divide the year with 10000L to catch overflow errors
sprintf((char*) val_buffer->ptr(),
"%04d-%02d-%02d %02d:%02d:%02d",
(int) ((ulong) (tmp/LL(10000000000) % 10000L)),
(int) ((tmp/LL(100000000)) % 100),
(int) ((tmp/LL(1000000)) % 100),
(int) ((tmp/LL(10000)) % 100),
(int) ((tmp/LL(100)) % 100),
(int) (tmp % LL(100)));
return val_buffer;
}
int Field_datetime::cmp(const char *a_ptr, const char *b_ptr)
{
longlong a,b;
longlongget(a,a_ptr);
longlongget(b,b_ptr);
return ((ulonglong) a < (ulonglong) b) ? -1 :
((ulonglong) a > (ulonglong) b) ? 1 : 0;
}
void Field_datetime::sort_string(char *to,uint length)
{
#ifdef WORDS_BIGENDIAN
to[0] = ptr[0];
to[1] = ptr[1];
to[2] = ptr[2];
to[3] = ptr[3];
to[4] = ptr[4];
to[5] = ptr[5];
to[6] = ptr[6];
to[7] = ptr[7];
#else
to[0] = ptr[7];
to[1] = ptr[6];
to[2] = ptr[5];
to[3] = ptr[4];
to[4] = ptr[3];
to[5] = ptr[2];
to[6] = ptr[1];
to[7] = ptr[0];
#endif
}
void Field_datetime::sql_type(String &res) const
{
res.set("datetime",8);
}
/****************************************************************************
** string type
** A string may be varchar or binary
****************************************************************************/
/* Copy a string and fill with space */
void Field_string::store(const char *from,uint length)
{
#ifdef USE_TIS620
if(!binary_flag) {
ThNormalize((uchar *)ptr, field_length, (uchar *)from, length);
if(length < field_length) {
bfill(ptr + length, field_length - length, ' ');
}
}
#else
if (length <= field_length)
{
memcpy(ptr,from,length);
if (length < field_length)
bfill(ptr+length,field_length-length,' ');
}
else
{
memcpy(ptr,from,field_length);
if (current_thd->count_cuted_fields)
{ // Check if we loosed some info
const char *end=from+length;
for (from+=field_length ; from != end ; from++)
{
if (!isspace(*from))
{
current_thd->cuted_fields++;
break;
}
}
}
}
#endif /* USE_TIS620 */
}
void Field_string::store(double nr)
{
char buff[MAX_FIELD_WIDTH];
int width=min(field_length,DBL_DIG+5);
sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
Field_string::store(buff,strlen(buff));
}
void Field_string::store(longlong nr)
{
char buff[22];
char *end=longlong2str(nr,buff,-10);
Field_string::store(buff,end-buff);
}
double Field_string::val_real(void)
{
double value;
char save=ptr[field_length]; // Ok to patch record
ptr[field_length]=0;
value=atof(ptr);
ptr[field_length]=save;
return value;
}
longlong Field_string::val_int(void)
{
longlong value;
char save=ptr[field_length]; // Ok to patch record
ptr[field_length]=0;
value=strtoll(ptr,NULL,10);
ptr[field_length]=save;
return value;
}
String *Field_string::val_str(String *val_buffer,String *val_ptr)
{
char *end=ptr+field_length;
while (end > ptr && end[-1] == ' ')
end--;
val_ptr->set((const char*) ptr,(uint) (end - ptr));
return val_ptr;
}
int Field_string::cmp(const char *a_ptr, const char *b_ptr)
{
if (binary_flag)
return memcmp(a_ptr,b_ptr,field_length);
else
return my_sortcmp(a_ptr,b_ptr,field_length);
}
void Field_string::sort_string(char *to,uint length)
{
if (binary_flag)
memcpy((byte*) to,(byte*) ptr,(size_t) field_length);
else
#ifndef USE_STRCOLL
{
for (char *from=ptr,*end=ptr+field_length ; from != end ;)
*to++=(char) my_sort_order[(uint) (uchar) *from++];
}
#else
{
uint tmp=my_strnxfrm((unsigned char *)to,(unsigned char *)ptr,length,field_length);
if (tmp < length)
bzero(to+tmp,length-tmp);
}
#endif
}
void Field_string::sql_type(String &res) const
{
sprintf((char*) res.ptr(),"%s(%d)",
field_length > 3 &&
(table->db_create_options & HA_OPTION_PACK_RECORD) ?
"varchar" : "char",
field_length);
res.length(strlen(res.ptr()));
if (binary_flag)
res.append(" binary");
}
/****************************************************************************
** blob type
** A blob is saved as a length and a pointer. The length is stored in the
** packlength slot and may be from 1-4.
****************************************************************************/
Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
enum utype unireg_check_arg, char *field_name_arg,
struct st_table *table_arg,uint blob_pack_length,
bool binary_arg)
:Field_str(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L,
null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
table_arg),
packlength(blob_pack_length),binary_flag(binary_arg)
{
flags|= BLOB_FLAG;
if (binary_arg)
flags|=BINARY_FLAG;
if (table)
table->blob_fields++;
}
void Field_blob::store_length(ulong number)
{
switch (packlength) {
case 1:
if (number > 255)
{
number=255;
current_thd->cuted_fields++;
}
ptr[0]= (uchar) number;
break;
case 2:
if (number > (uint16) ~0)
{
number= (uint16) ~0;
current_thd->cuted_fields++;
}
shortstore(ptr,(unsigned short) number);
break;
case 3:
if (number > (ulong) (1L << 24))
{
number= (ulong) (1L << 24)-1L;
current_thd->cuted_fields++;
}
int3store(ptr,number);
break;
case 4:
longstore(ptr,number);
}
}
ulong Field_blob::get_length(void)
{
switch (packlength) {
case 1:
return (ulong) (uchar) ptr[0];
case 2:
{
uint16 tmp; shortget(tmp,ptr);
return (ulong) tmp;
}
case 3:
return (ulong) uint3korr(ptr);
case 4:
{
uint32 tmp; longget(tmp,ptr);
return (ulong) tmp;
}
}
return 0; // Impossible
}
void Field_blob::store(const char *from,uint len)
{
if (!len)
{
bzero(ptr,Field_blob::pack_length());
}
else
{
#ifdef USE_TIS620
char *th_ptr=0;
#endif
Field_blob::store_length(len);
if (table->copy_blobs)
{ // Must make a copy
#ifdef USE_TIS620
if(!binary_flag)
{
/* If there isn't enough memory, use original string */
if ((th_ptr=(char * ) my_malloc(sizeof(char) * len,MYF(0))))
{
ThNormalize((uchar *) th_ptr, len, (uchar *) from, len);
from= (const char*) th_ptr;
}
}
#endif /* USE_TIS620 */
value.set(from,len);
value.copy();
from=value.ptr();
}
bmove(ptr+packlength,(char*) &from,sizeof(char*));
#ifdef USE_TIS620
my_free(th_ptr,MYF(MY_ALLOW_ZERO_PTR));
#endif
}
}
void Field_blob::store(double nr)
{
value.set(nr);
Field_blob::store(value.ptr(),value.length());
}
void Field_blob::store(longlong nr)
{
value.set(nr);
Field_blob::store(value.ptr(),value.length());
}
double Field_blob::val_real(void)
{
char *blob;
memcpy(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0.0;
ulong length=get_length();
char save=blob[length]; // Ok to patch blob in NISAM
blob[length]=0;
double nr=atof(blob);
blob[length]=save;
return nr;
}
longlong Field_blob::val_int(void)
{
char *blob;
memcpy(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0;
ulong length=get_length();
char save=blob[length]; // Ok to patch blob in NISAM
blob[length]=0;
longlong nr=strtoll(blob,NULL,10);
blob[length]=save;
return nr;
}
String *Field_blob::val_str(String *val_buffer,String *val_ptr)
{
char *blob;
memcpy(&blob,ptr+packlength,sizeof(char*));
if (!blob)
val_ptr->length(0);
else
val_ptr->set((const char*) blob,get_length());
return val_ptr;
}
int Field_blob::cmp(const char *a_ptr, const char *b_ptr)
{
return 0; // Never used
}
void Field_blob::sort_string(char *to,uint length)
{
char *blob;
uint blob_length=get_length();
#ifdef USE_STRCOLL
uint blob_org_length=blob_length;
#endif
if (!blob_length)
bzero(to,length);
else
{
if (blob_length > length)
blob_length=length;
memcpy(&blob,ptr+packlength,sizeof(char*));
if (binary_flag)
{
memcpy(to,blob,blob_length);
to+=blob_length;
}
else
#ifndef USE_STRCOLL
{
for (char *end=blob+blob_length ; blob != end ;)
*to++=(char) my_sort_order[(uint) (uchar) *blob++];
}
#else
{
blob_length=my_strnxfrm((unsigned char *)to,(unsigned char *)blob,length,blob_org_length);
if (blob_length >= length)
return;
to+=blob_length;
}
#endif
bzero(to,length-blob_length);
}
}
void Field_blob::sql_type(String &res) const
{
char *str;
switch (packlength) {
default: str="tiny"; break;
case 2: str=""; break;
case 3: str="medium"; break;
case 4: str="long"; break;
}
res.set(str,strlen(str));
res.append(binary_flag ? "blob" : "text");
}
/****************************************************************************
** enum type.
** This is a string which only can have a selection of different values.
** If one uses this string in a number context one gets the type number.
****************************************************************************/
enum ha_base_keytype Field_enum::key_type() const
{
switch (packlength) {
default: return HA_KEYTYPE_BINARY;
case 2: return HA_KEYTYPE_USHORT_INT;
case 3: return HA_KEYTYPE_UINT24;
case 4: return HA_KEYTYPE_ULONG_INT;
case 8: return HA_KEYTYPE_ULONGLONG;
}
}
void Field_enum::store_type(ulonglong value)
{
switch (packlength) {
case 1: ptr[0]= (uchar) value; break;
case 2: shortstore(ptr,(unsigned short) value); break;
case 3: int3store(ptr,(long) value); break;
case 4: longstore(ptr,(long) value); break;
case 8: longlongstore(ptr,value); break;
}
}
uint find_enum(TYPELIB *typelib,const char *x, uint length)
{
const char *end=x+length;
while (end > x && isspace(end[-1]))
end--;
const char *i;
const char *j;
for (uint pos=0 ; (j=typelib->type_names[pos]) ; pos++)
{
for (i=x ; i != end && toupper(*i) == toupper(*j) ; i++, j++) ;
if (i == end && ! *j)
return(pos+1);
}
return(0);
}
/*
** Note. Storing a empty string in a enum field gives a warning
** (if there isn't a empty value in the enum)
*/
void Field_enum::store(const char *from,uint length)
{
uint tmp=find_enum(typelib,from,length);
{
if (!tmp)
{
current_thd->cuted_fields++;
Field_enum::store_type((longlong) 0);
}
else
store_type((ulonglong) tmp);
}
}
void Field_enum::store(double nr)
{
Field_enum::store((longlong) nr);
}
void Field_enum::store(longlong nr)
{
if ((uint) nr > typelib->count || nr == 0)
{
current_thd->cuted_fields++;
nr=0;
}
store_type((ulonglong) (uint) nr);
}
double Field_enum::val_real(void)
{
return (double) Field_enum::val_int();
}
longlong Field_enum::val_int(void)
{
switch (packlength) {
case 1:
return (longlong) (uchar) ptr[0];
case 2:
{
uint16 tmp; shortget(tmp,ptr);
return (longlong) tmp;
}
case 3:
return (longlong) uint3korr(ptr);
case 4:
{
uint32 tmp; longget(tmp,ptr);
return (longlong) tmp;
}
case 8:
{
longlong tmp; longlongget(tmp,ptr);
return tmp;
}
}
return 0; // impossible
}
String *Field_enum::val_str(String *val_buffer,String *val_ptr)
{
uint tmp=(uint) Field_enum::val_int();
if (!tmp)
val_ptr->length(0);
else
val_ptr->set((const char*) typelib->type_names[tmp-1],
strlen(typelib->type_names[tmp-1]));
return val_ptr;
}
int Field_enum::cmp(const char *a_ptr, const char *b_ptr)
{
char *old=ptr;
ptr=(char*) a_ptr;
ulonglong a=Field_enum::val_int();
ptr=(char*) b_ptr;
ulonglong b=Field_enum::val_int();
ptr=old;
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
void Field_enum::sort_string(char *to,uint length)
{
ulonglong value=Field_enum::val_int();
to+=packlength-1;
for (uint i=0 ; i < packlength ; i++)
{
*to-- = (uchar) (value & 255);
value>>=8;
}
}
void Field_enum::sql_type(String &res) const
{
res.length(0);
res.append("enum(");
bool flag=0;
for (char **pos=typelib->type_names; *pos ; pos++)
{
if (flag)
res.append(',');
res.append('\'');
append_unescaped(&res,*pos);
res.append('\'');
flag=1;
}
res.append(')');
}
/****************************************************************************
** set type.
** This is a string which can have a collection of different values.
** Each string value is separated with a ','.
** For example "One,two,five"
** If one uses this string in a number context one gets the bits as a longlong
** number.
****************************************************************************/
ulonglong find_set(TYPELIB *typelib,const char *x,uint length)
{
const char *end=x+length;
while (end > x && isspace(end[-1]))
end--;
ulonglong found=0;
if (x != end)
{
const char *start=x;
bool error=0;
for (;;)
{
const char *pos=start;
for ( ; pos != end && *pos != field_separator ; pos++) ;
uint find=find_enum(typelib,start,(uint) (pos-start));
if (!find)
error=1;
else
found|= ((longlong) 1 << (find-1));
if (pos == end)
break;
start=pos+1;
}
if (error)
current_thd->cuted_fields++;
}
return found;
}
void Field_set::store(const char *from,uint length)
{
store_type(find_set(typelib,from,length));
}
void Field_set::store(longlong nr)
{
if ((ulonglong) nr > (ulonglong) (((longlong) 1 << typelib->count) -
(longlong) 1))
{
nr&= (longlong) (((longlong) 1 << typelib->count) - (longlong) 1);
current_thd->cuted_fields++;
}
store_type((ulonglong) nr);
}
String *Field_set::val_str(String *val_buffer,String *val_ptr)
{
ulonglong tmp=(ulonglong) Field_enum::val_int();
uint bitnr=0;
val_buffer->length(0);
while (tmp && bitnr < (uint) typelib->count)
{
if (tmp & 1)
{
if (val_buffer->length())
val_buffer->append(field_separator);
String str(typelib->type_names[bitnr],
strlen(typelib->type_names[bitnr]));
val_buffer->append(str);
}
tmp>>=1;
bitnr++;
}
return val_buffer;
}
void Field_set::sql_type(String &res) const
{
res.length(0);
res.append("set(");
bool flag=0;
for (char **pos=typelib->type_names; *pos ; pos++)
{
if (flag)
res.append(',');
res.append('\'');
append_unescaped(&res,*pos);
res.append('\'');
flag=1;
}
res.append(')');
}
/*****************************************************************************
** Handling of field and create_field
*****************************************************************************/
/*
** Make a field from the .frm file info
*/
uint32 calc_pack_length(enum_field_types type,uint32 length)
{
switch (type) {
case FIELD_TYPE_STRING:
case FIELD_TYPE_VAR_STRING:
case FIELD_TYPE_DECIMAL: return (length);
case FIELD_TYPE_YEAR:
case FIELD_TYPE_TINY : return 1;
case FIELD_TYPE_SHORT : return 2;
case FIELD_TYPE_INT24:
case FIELD_TYPE_NEWDATE:
case FIELD_TYPE_TIME: return 3;
case FIELD_TYPE_TIMESTAMP:
case FIELD_TYPE_DATE:
case FIELD_TYPE_LONG : return 4;
case FIELD_TYPE_FLOAT : return sizeof(float);
case FIELD_TYPE_DOUBLE: return sizeof(double);
case FIELD_TYPE_DATETIME:
case FIELD_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */
case FIELD_TYPE_NULL : return 0;
case FIELD_TYPE_TINY_BLOB: return 1+sizeof(char*);
case FIELD_TYPE_BLOB: return 2+sizeof(char*);
case FIELD_TYPE_MEDIUM_BLOB: return 3+sizeof(char*);
case FIELD_TYPE_LONG_BLOB: return 4+sizeof(char*);
case FIELD_TYPE_SET:
case FIELD_TYPE_ENUM: abort(); return 0; // This shouldn't happen
}
return 0; // This shouldn't happen
}
uint pack_length_to_packflag(uint type)
{
switch (type) {
case 1: return f_settype((uint) FIELD_TYPE_TINY);
case 2: return f_settype((uint) FIELD_TYPE_SHORT);
case 3: return f_settype((uint) FIELD_TYPE_INT24);
case 4: return f_settype((uint) FIELD_TYPE_LONG);
case 8: return f_settype((uint) FIELD_TYPE_LONGLONG);
}
return 0; // This shouldn't happen
}
Field *make_field(char *ptr, uint32 field_length,
uchar *null_pos, uint null_bit,
uint pack_flag,
Field::utype unireg_check,
TYPELIB *interval,
char *field_name,
struct st_table *table)
{
if (!f_maybe_null(pack_flag))
{
null_pos=0;
null_bit=0;
}
if (f_is_alpha(pack_flag))
{
if (!f_is_packed(pack_flag))
return new Field_string(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
f_is_binary(pack_flag) != 0);
uint pack_length=calc_pack_length((enum_field_types)
f_packtype(pack_flag),
field_length);
if (f_is_blob(pack_flag))
return new Field_blob(ptr,null_pos,null_bit,
unireg_check, field_name, table,
pack_length,f_is_binary(pack_flag) != 0);
if (interval)
{
if (f_is_enum(pack_flag))
return new Field_enum(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
pack_length, interval);
else
return new Field_set(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
pack_length, interval);
}
}
switch ((enum enum_field_types) f_packtype(pack_flag)) {
case FIELD_TYPE_DECIMAL:
return new Field_decimal(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
case FIELD_TYPE_FLOAT:
return new Field_float(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag)== 0);
case FIELD_TYPE_DOUBLE:
return new Field_double(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag)== 0);
case FIELD_TYPE_TINY:
return new Field_tiny(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
case FIELD_TYPE_SHORT:
return new Field_short(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
case FIELD_TYPE_INT24:
return new Field_medium(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
case FIELD_TYPE_LONG:
return new Field_long(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
case FIELD_TYPE_LONGLONG:
return new Field_longlong(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
case FIELD_TYPE_TIMESTAMP:
return new Field_timestamp(ptr,field_length,
unireg_check, field_name, table);
case FIELD_TYPE_YEAR:
return new Field_year(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table);
case FIELD_TYPE_DATE:
return new Field_date(ptr,null_pos,null_bit,
unireg_check, field_name, table);
case FIELD_TYPE_NEWDATE:
return new Field_newdate(ptr,null_pos,null_bit,
unireg_check, field_name, table);
case FIELD_TYPE_TIME:
return new Field_time(ptr,null_pos,null_bit,
unireg_check, field_name, table);
case FIELD_TYPE_DATETIME:
return new Field_datetime(ptr,null_pos,null_bit,
unireg_check, field_name, table);
case FIELD_TYPE_NULL:
default: // Impossible (Wrong version)
return new Field_null(ptr,field_length,unireg_check,field_name,table);
}
return 0; // Impossible (Wrong version)
}
/* Create a field suitable for create of table */
create_field::create_field(Field *old_field)
{
field= old_field;
field_name=change=old_field->field_name;
length= old_field->field_length;
flags= old_field->flags;
unireg_check=old_field->unireg_check;
pack_length=old_field->pack_length();
sql_type= old_field->real_type();
if (sql_type == FIELD_TYPE_STRING)
sql_type=old_field->type();
if (old_field->result_type() == REAL_RESULT)
decimals= ((Field_num*) old_field)->decimals;
else
decimals=0;
if (flags & ENUM_FLAG)
interval= ((Field_enum*) old_field)->typelib;
else
interval=0;
if (!old_field->is_null() && ! (flags & BLOB_FLAG) &&
old_field->type() != FIELD_TYPE_TIMESTAMP)
{
char buff[MAX_FIELD_WIDTH],*pos;
String tmp(buff,sizeof(buff));
field->val_str(&tmp,&tmp);
pos=sql_memdup(tmp.ptr(),tmp.length()+1);
pos[tmp.length()]=0;
def=new Item_string(pos,tmp.length());
}
else
def=0;
}