summaryrefslogtreecommitdiff
path: root/sql/field.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/field.cc')
-rw-r--r--sql/field.cc2148
1 files changed, 1284 insertions, 864 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 43481ca0963..efdf1762c0b 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -15,16 +15,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*
- 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
*****************************************************************************/
@@ -44,8 +34,6 @@
// Maximum allowed exponent value for converting string to decimal
#define MAX_EXPONENT 1024
-
-
/*****************************************************************************
Instansiate templates and static variables
*****************************************************************************/
@@ -77,44 +65,54 @@ void Field_num::prepend_zeros(String *value)
/*
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...
+
+ SYNOPSIS
+ test_if_int()
+ str String to test
+ end Pointer to char after last used digit
+ cs Character set
+
+ NOTES
+ This is called after one has called my_strntol() or similar function.
+ This is only used to give warnings in ALTER TABLE or LOAD DATA...
+
+ TODO
+ Make this multi-byte-character safe
+
+ RETURN
+ 0 ok
+ 1 error
*/
-bool test_if_int(const char *str,int length)
+bool test_if_int(const char *str, int length, const char *int_end,
+ CHARSET_INFO *cs)
{
+ if (str == int_end)
+ return 0; // Empty string
const char *end=str+length;
+ if ((str= int_end) == end)
+ return 1; // All digits was used
- 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++)
+ /* Allow end .0000 */
+ if (*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;
- }
+ for (str++ ; str != end && *str == '0'; str++) ;
+ }
+ /* Allow end space */
+ for (str++ ; str != end ; str++)
+ {
+ if (!my_isspace(cs,*str))
+ return 0;
}
return 1;
}
-static bool test_if_real(const char *str,int length)
+static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
{
- while (length && isspace(*str))
+ cs= system_charset_info; // QQ move test_if_real into CHARSET_INFO struct
+
+ while (length && my_isspace(cs,*str))
{ // Allow start space
length--; str++;
}
@@ -123,10 +121,10 @@ static bool test_if_real(const char *str,int length)
if (*str == '+' || *str == '-')
{
length--; str++;
- if (!length || !(isdigit(*str) || *str == '.'))
+ if (!length || !(my_isdigit(cs,*str) || *str == '.'))
return 0;
}
- while (length && isdigit(*str))
+ while (length && my_isdigit(cs,*str))
{
length--; str++;
}
@@ -135,7 +133,7 @@ static bool test_if_real(const char *str,int length)
if (*str == '.')
{
length--; str++;
- while (length && isdigit(*str))
+ while (length && my_isdigit(cs,*str))
{
length--; str++;
}
@@ -144,18 +142,19 @@ static bool test_if_real(const char *str,int length)
return 1;
if (*str == 'E' || *str == 'e')
{
- if (length < 3 || (str[1] != '+' && str[1] != '-') || !isdigit(str[2]))
+ if (length < 3 || (str[1] != '+' && str[1] != '-') ||
+ !my_isdigit(cs,str[2]))
return 0;
length-=3;
str+=3;
- while (length && isdigit(*str))
+ while (length && my_isdigit(cs,*str))
{
length--; str++;
}
}
for (; length ; length--, str++)
{ // Allow end space
- if (!isspace(*str))
+ if (!my_isspace(cs,*str))
return 0;
}
return 1;
@@ -184,9 +183,11 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
field_name(field_name_arg),
query_id(0),key_start(0),part_of_key(0),part_of_sortkey(0),
unireg_check(unireg_check_arg),
- field_length(length_arg),null_bit(null_bit_arg)
+ field_length(length_arg),null_bit(null_bit_arg),abs_offset(0)
{
flags=null_ptr ? 0: NOT_NULL_FLAG;
+ comment.str= (char*) "";
+ comment.length=0;
}
uint Field::offset()
@@ -206,23 +207,17 @@ void Field::copy_from_tmp(int row_offset)
}
-bool Field::send(THD *thd, String *packet)
+bool Field::send_binary(Protocol *protocol)
{
- if (is_null())
- return net_store_null(packet);
char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff));
+ String tmp(buff,sizeof(buff),charset());
val_str(&tmp,&tmp);
- CONVERT *convert;
- if ((convert=thd->variables.convert_set))
- return convert->store(packet,tmp.ptr(),tmp.length());
- return net_store_data(packet,tmp.ptr(),tmp.length());
+ return protocol->store(tmp.ptr(), tmp.length(), tmp.charset());
}
void Field_num::add_zerofill_and_unsigned(String &res) const
{
- res.length((uint) strlen(res.ptr())); // Fix length
if (unsigned_flag)
res.append(" unsigned");
if (zerofill)
@@ -231,8 +226,12 @@ void Field_num::add_zerofill_and_unsigned(String &res) const
void Field_num::make_field(Send_field *field)
{
+ /* table_cache_key is not set for temp tables */
+ field->db_name=table->table_cache_key ? table->table_cache_key : "";
+ field->org_table_name=table->real_name;
field->table_name=table_name;
- field->col_name=field_name;
+ field->col_name=field->org_col_name=field_name;
+ field->charsetnr= charset()->number;
field->length=field_length;
field->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
@@ -242,8 +241,12 @@ void Field_num::make_field(Send_field *field)
void Field_str::make_field(Send_field *field)
{
+ /* table_cache_key is not set for temp tables */
+ field->db_name=table->table_cache_key ? table->table_cache_key : "";
+ field->org_table_name=table->real_name;
field->table_name=table_name;
- field->col_name=field_name;
+ field->col_name=field->org_col_name=field_name;
+ field->charsetnr= charset()->number;
field->length=field_length;
field->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
@@ -274,7 +277,7 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
bool Field::get_date(TIME *ltime,bool fuzzydate)
{
char buff[40];
- String tmp(buff,sizeof(buff)),tmp2,*res;
+ String tmp(buff,sizeof(buff),&my_charset_bin),tmp2,*res;
if (!(res=val_str(&tmp,&tmp2)) ||
str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE)
return 1;
@@ -284,7 +287,7 @@ bool Field::get_date(TIME *ltime,bool fuzzydate)
bool Field::get_time(TIME *ltime)
{
char buff[40];
- String tmp(buff,sizeof(buff)),tmp2,*res;
+ String tmp(buff,sizeof(buff),&my_charset_bin),tmp2,*res;
if (!(res=val_str(&tmp,&tmp2)) ||
str_to_time(res->ptr(),res->length(),ltime))
return 1;
@@ -298,24 +301,26 @@ void Field::store_time(TIME *ltime,timestamp_type type)
char buff[25];
switch (type) {
case TIMESTAMP_NONE:
- store("",0); // Probably an error
+ store("",0,&my_charset_bin); // Probably an error
break;
case TIMESTAMP_DATE:
sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day);
- store(buff,10);
+ store(buff,10,&my_charset_bin);
break;
case TIMESTAMP_FULL:
sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d",
ltime->year,ltime->month,ltime->day,
ltime->hour,ltime->minute,ltime->second);
- store(buff,19);
+ store(buff,19,&my_charset_bin);
break;
case TIMESTAMP_TIME:
- sprintf(buff, "%02d:%02d:%02d",
- ltime->hour,ltime->minute,ltime->second);
- store(buff,(uint) strlen(buff));
+ {
+ ulong length= my_sprintf(buff, (buff, "%02d:%02d:%02d",
+ ltime->hour,ltime->minute,ltime->second));
+ store(buff,(uint) length, &my_charset_bin);
break;
}
+ }
}
@@ -325,6 +330,16 @@ bool Field::optimize_range(uint idx)
}
/****************************************************************************
+ Field_null, a field that always return NULL
+****************************************************************************/
+
+void Field_null::sql_type(String &res) const
+{
+ res.set_ascii("null", 4);
+}
+
+
+/****************************************************************************
Functions for the Field_decimal class
This is an number stored as a pre-space (or pre-zero) string
****************************************************************************/
@@ -332,7 +347,7 @@ bool Field::optimize_range(uint idx)
void
Field_decimal::reset(void)
{
- Field_decimal::store("0",1);
+ Field_decimal::store("0",1,&my_charset_bin);
}
void Field_decimal::overflow(bool negative)
@@ -340,7 +355,7 @@ void Field_decimal::overflow(bool negative)
uint len=field_length;
char *to=ptr, filler= '9';
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
if (negative)
{
if (!unsigned_flag)
@@ -374,8 +389,19 @@ void Field_decimal::overflow(bool negative)
}
-void Field_decimal::store(const char *from,uint len)
+int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
{
+ char buff[80];
+ String tmp(buff,sizeof(buff), &my_charset_bin);
+
+ /* Convert character set if the old one is multi byte */
+ if (cs->mbmaxlen > 1)
+ {
+ tmp.copy(from, len, cs, &my_charset_bin);
+ from= tmp.ptr();
+ len= tmp.length();
+ }
+
const char *end= from+len;
/* The pointer where the field value starts (i.e., "where to write") */
char *to=ptr;
@@ -385,13 +411,13 @@ void Field_decimal::store(const char *from,uint len)
specified), '+' or '-'
*/
char sign_char=0;
- /* The pointers where prezeros start and stop */
+ /* The pointers where prezeros start and stop */
const char *pre_zeros_from, *pre_zeros_end;
- /* The pointers where digits at the left of '.' start and stop */
+ /* The pointers where digits at the left of '.' start and stop */
const char *int_digits_from, *int_digits_end;
- /* The pointers where digits at the right of '.' start and stop */
+ /* The pointers where digits at the right of '.' start and stop */
const char *frac_digits_from, *frac_digits_end;
- /* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */
+ /* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */
char expo_sign_char=0;
uint exponent=0; // value of the exponent
/*
@@ -401,21 +427,21 @@ void Field_decimal::store(const char *from,uint len)
const char *int_digits_tail_from;
/* Number of 0 that need to be added at the left of the '.' (1E3: 3 zeros) */
uint int_digits_added_zeros;
- /*
- Pointer used when digits move from the right of the '.' to the left
- of the '.'
- */
+ /*
+ Pointer used when digits move from the right of the '.' to the left
+ of the '.'
+ */
const char *frac_digits_head_end;
- /* Number of 0 that need to be added at the right of the '.' (for 1E-3) */
+ /* Number of 0 that need to be added at the right of the '.' (for 1E-3) */
uint frac_digits_added_zeros;
char *pos,*tmp_left_pos,*tmp_right_pos;
/* Pointers that are used as limits (begin and end of the field buffer) */
char *left_wall,*right_wall;
char tmp_char;
- /*
- To remember if current_thd->cuted_fields has already been incremented,
- to do that only once
- */
+ /*
+ To remember if current_thd->cuted_fields has already been incremented,
+ to do that only once
+ */
bool is_cuted_fields_incr=0;
LINT_INIT(int_digits_tail_from);
@@ -425,19 +451,21 @@ void Field_decimal::store(const char *from,uint len)
/*
There are three steps in this function :
- - parse the input string
- - modify the position of digits around the decimal dot '.'
- according to the exponent value (if specified)
- - write the formatted number
+ - parse the input string
+ - modify the position of digits around the decimal dot '.'
+ according to the exponent value (if specified)
+ - write the formatted number
*/
if ((tmp_dec=dec))
tmp_dec++;
- for (; from !=end && isspace(*from); from++) ; // Read spaces
+ /* skip pre-space */
+ while (from != end && my_isspace(&my_charset_bin,*from))
+ from++;
if (from == end)
{
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
is_cuted_fields_incr=1;
}
else if (*from == '+' || *from == '-') // Found some sign ?
@@ -453,11 +481,11 @@ void Field_decimal::store(const char *from,uint len)
if (sign_char=='-')
{
Field_decimal::overflow(1);
- return;
+ return 1;
}
/*
- Defining this will not store "+" for unsigned decimal type even if
- it is passed in numeric string. This will make some tests to fail
+ Defining this will not store "+" for unsigned decimal type even if
+ it is passed in numeric string. This will make some tests to fail
*/
#ifdef DONT_ALLOW_UNSIGNED_PLUS
else
@@ -470,13 +498,13 @@ void Field_decimal::store(const char *from,uint len)
for (; from!=end && *from == '0'; from++) ; // Read prezeros
pre_zeros_end=int_digits_from=from;
/* Read non zero digits at the left of '.'*/
- for (; from!=end && isdigit(*from);from++) ;
+ for (; from != end && my_isdigit(&my_charset_bin, *from) ; from++) ;
int_digits_end=from;
if (from!=end && *from == '.') // Some '.' ?
from++;
frac_digits_from= from;
/* Read digits at the right of '.' */
- for (;from!=end && isdigit(*from); from++) ;
+ for (;from!=end && my_isdigit(&my_charset_bin, *from); from++) ;
frac_digits_end=from;
// Some exponentiation symbol ?
if (from != end && (*from == 'e' || *from == 'E'))
@@ -492,7 +520,7 @@ void Field_decimal::store(const char *from,uint len)
exponents will become small (e.g. 1e4294967296 will become 1e0, and the
field will finally contain 1 instead of its max possible value).
*/
- for (;from!=end && isdigit(*from); from++)
+ for (;from!=end && my_isdigit(&my_charset_bin, *from); from++)
{
exponent=10*exponent+(*from-'0');
if (exponent>MAX_EXPONENT)
@@ -509,10 +537,11 @@ void Field_decimal::store(const char *from,uint len)
if (current_thd->count_cuted_fields)
{
- for (;from != end && isspace(*from); from++) ; // Read end spaces
+ // Skip end spaces
+ for (;from != end && my_isspace(&my_charset_bin, *from); from++) ;
if (from != end) // If still something left, warn
{
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
is_cuted_fields_incr=1;
}
}
@@ -521,21 +550,21 @@ void Field_decimal::store(const char *from,uint len)
Now "move" digits around the decimal dot according to the exponent value,
and add necessary zeros.
Examples :
- - 1E+3 : needs 3 more zeros at the left of '.' (int_digits_added_zeros=3)
- - 1E-3 : '1' moves at the right of '.', and 2 more zeros are needed
- between '.' and '1'
+ - 1E+3 : needs 3 more zeros at the left of '.' (int_digits_added_zeros=3)
+ - 1E-3 : '1' moves at the right of '.', and 2 more zeros are needed
+ between '.' and '1'
- 1234.5E-3 : '234' moves at the right of '.'
- These moves are implemented with pointers which point at the begin
- and end of each moved segment. Examples :
+ These moves are implemented with pointers which point at the begin
+ and end of each moved segment. Examples :
- 1234.5E-3 : before the code below is executed, the int_digits part is
- from '1' to '4' and the frac_digits part from '5' to '5'. After the code
- below, the int_digits part is from '1' to '1', the frac_digits_head
- part is from '2' to '4', and the frac_digits part from '5' to '5'.
+ from '1' to '4' and the frac_digits part from '5' to '5'. After the code
+ below, the int_digits part is from '1' to '1', the frac_digits_head
+ part is from '2' to '4', and the frac_digits part from '5' to '5'.
- 1234.5E3 : before the code below is executed, the int_digits part is
- from '1' to '4' and the frac_digits part from '5' to '5'. After the code
- below, the int_digits part is from '1' to '4', the int_digits_tail
- part is from '5' to '5', the frac_digits part is empty, and
- int_digits_added_zeros=2 (to make 1234500).
+ from '1' to '4' and the frac_digits part from '5' to '5'. After the code
+ below, the int_digits part is from '1' to '4', the int_digits_tail
+ part is from '5' to '5', the frac_digits part is empty, and
+ int_digits_added_zeros=2 (to make 1234500).
*/
/*
@@ -597,7 +626,7 @@ void Field_decimal::store(const char *from,uint len)
{
// too big number, change to max or min number
Field_decimal::overflow(sign_char == '-');
- return;
+ return 1;
}
/*
@@ -678,7 +707,7 @@ void Field_decimal::store(const char *from,uint len)
{
if (current_thd->count_cuted_fields && !is_cuted_fields_incr)
break; // Go on below to see if we lose non zero digits
- return;
+ return 0;
}
*pos++='0';
}
@@ -690,8 +719,8 @@ void Field_decimal::store(const char *from,uint len)
if (tmp_char != '0') // Losing a non zero digit ?
{
if (!is_cuted_fields_incr)
- current_thd->cuted_fields++;
- return;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ return 0;
}
continue;
}
@@ -707,8 +736,8 @@ void Field_decimal::store(const char *from,uint len)
if (tmp_char != '0') // Losing a non zero digit ?
{
if (!is_cuted_fields_incr)
- current_thd->cuted_fields++;
- return;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ return 0;
}
continue;
}
@@ -717,26 +746,26 @@ void Field_decimal::store(const char *from,uint len)
while (pos != right_wall)
*pos++='0'; // Fill with zeros at right of '.'
-
+ return 0;
}
-void Field_decimal::store(double nr)
+int Field_decimal::store(double nr)
{
if (unsigned_flag && nr < 0)
{
overflow(1);
- return;
+ return 1;
}
#ifdef HAVE_FINITE
if (!finite(nr)) // Handle infinity as special case
{
overflow(nr < 0.0);
- return;
+ return 1;
}
#endif
-
+
reg4 uint i,length;
char fyllchar,*to;
char buff[320];
@@ -745,36 +774,43 @@ void Field_decimal::store(double nr)
#ifdef HAVE_SNPRINTF
buff[sizeof(buff)-1]=0; // Safety
snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr);
+ length=(uint) strlen(buff);
#else
- sprintf(buff,"%.*f",dec,nr);
+ length=(uint) my_sprintf(buff,(buff,"%.*f",dec,nr));
#endif
- length=(uint) strlen(buff);
if (length > field_length)
+ {
overflow(nr < 0.0);
+ return 1;
+ }
else
{
to=ptr;
for (i=field_length-length ; i-- > 0 ;)
*to++ = fyllchar;
memcpy(to,buff,length);
+ return 0;
}
}
-void Field_decimal::store(longlong nr)
+int Field_decimal::store(longlong nr)
{
if (unsigned_flag && nr < 0)
{
overflow(1);
- return;
+ return 1;
}
char buff[22];
uint length=(uint) (longlong10_to_str(nr,buff,-10)-buff);
uint int_part=field_length- (dec ? dec+1 : 0);
if (length > int_part)
+ {
overflow(test(nr < 0L)); /* purecov: inspected */
+ return 1;
+ }
else
{
char fyllchar = zerofill ? (char) '0' : (char) ' ';
@@ -787,40 +823,40 @@ void Field_decimal::store(longlong nr)
to[length]='.';
bfill(to+length+1,dec,'0');
}
+ return 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);
+ int not_used;
+ return my_strntod(&my_charset_bin, ptr, field_length, NULL, &not_used);
}
longlong Field_decimal::val_int(void)
{
- char temp= *(ptr+field_length); *(ptr+field_length) = '\0';
- longlong nr;
+ int not_used;
if (unsigned_flag)
- nr=(longlong) strtoull(ptr,NULL,10);
+ return my_strntoull(&my_charset_bin, ptr, field_length, 10, NULL,
+ &not_used);
else
- nr=strtoll(ptr,NULL,10);
- *(ptr+field_length)=temp;
- return(nr);
+ return my_strntoll(&my_charset_bin, ptr, field_length, 10, NULL,
+ &not_used);
}
+
String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
char *str;
for (str=ptr ; *str == ' ' ; str++) ;
uint tmp_length=(uint) (str-ptr);
+ val_ptr->set_charset(&my_charset_bin);
if (field_length < tmp_length) // Error in data
val_ptr->length(0);
else
- val_ptr->set((const char*) str,field_length-tmp_length);
+ val_ptr->set_ascii((const char*) str, field_length-tmp_length);
return val_ptr;
}
@@ -837,8 +873,10 @@ int Field_decimal::cmp(const char *a_ptr,const char *b_ptr)
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')));
+ ((my_isspace(&my_charset_bin,*a_ptr) || *a_ptr == '+' ||
+ *a_ptr == '0') &&
+ (my_isspace(&my_charset_bin,*b_ptr) || *b_ptr == '+' ||
+ *b_ptr == '0')));
a_ptr++,b_ptr++)
{
if (*a_ptr == '-') // If both numbers are negative
@@ -865,8 +903,8 @@ 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')) ;
-
+ ((my_isspace(&my_charset_bin,*str) || *str == '+' ||
+ *str == '0')) ;
str++)
*to++=' ';
if (str == end)
@@ -877,7 +915,7 @@ void Field_decimal::sort_string(char *to,uint length)
*to++=1; // Smaller than any number
str++;
while (str != end)
- if (isdigit(*str))
+ if (my_isdigit(&my_charset_bin,*str))
*to++= (char) ('9' - *str++);
else
*to++= *str++;
@@ -885,14 +923,17 @@ void Field_decimal::sort_string(char *to,uint length)
else memcpy(to,str,(uint) (end-str));
}
+
void Field_decimal::sql_type(String &res) const
{
+ CHARSET_INFO *cs=res.charset();
uint tmp=field_length;
if (!unsigned_flag)
tmp--;
if (dec)
tmp--;
- sprintf((char*) res.ptr(),"decimal(%d,%d)",tmp,dec);
+ res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "decimal(%d,%d)",tmp,dec));
add_zerofill_and_unsigned(res);
}
@@ -901,59 +942,75 @@ void Field_decimal::sql_type(String &res) const
** tiny int
****************************************************************************/
-void Field_tiny::store(const char *from,uint len)
+int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len);
- long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ int not_used; // We can ignore result from str2int
+ char *end;
+ long tmp= my_strntol(cs, from, len, 10, &end, &not_used);
+ int error= 0;
if (unsigned_flag)
{
if (tmp < 0)
{
tmp=0; /* purecov: inspected */
- current_thd->cuted_fields++; /* purecov: inspected */
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (tmp > 255)
{
tmp= 255;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ error= 1;
}
- 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++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (tmp >= 128)
{
tmp= 127;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ error= 1;
}
- else if (current_thd->count_cuted_fields && !test_if_int(from,len))
- current_thd->cuted_fields++;
}
ptr[0]= (char) tmp;
+ return error;
}
-void Field_tiny::store(double nr)
+int Field_tiny::store(double nr)
{
+ int error= 0;
nr=rint(nr);
if (unsigned_flag)
{
if (nr < 0.0)
{
*ptr=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > 255.0)
{
*ptr=(char) 255;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
*ptr=(char) nr;
@@ -963,31 +1020,37 @@ void Field_tiny::store(double nr)
if (nr < -128.0)
{
*ptr= (char) -128;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > 127.0)
{
*ptr=127;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
*ptr=(char) nr;
}
+ return error;
}
-void Field_tiny::store(longlong nr)
+int Field_tiny::store(longlong nr)
{
+ int error= 0;
if (unsigned_flag)
{
if (nr < 0L)
{
*ptr=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > 255L)
{
*ptr= (char) 255;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
*ptr=(char) nr;
@@ -997,16 +1060,19 @@ void Field_tiny::store(longlong nr)
if (nr < -128L)
{
*ptr= (char) -128;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > 127L)
{
*ptr=127;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
*ptr=(char) nr;
}
+ return error;
}
@@ -1027,19 +1093,29 @@ longlong Field_tiny::val_int(void)
String *Field_tiny::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs= &my_charset_bin;
uint length;
- val_buffer->alloc(max(field_length+1,5));
+ uint mlength=max(field_length+1,5*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
+
if (unsigned_flag)
- length= (uint) (int10_to_str((long) *((uchar*) ptr),to,10)-to);
+ length= (uint) cs->cset->long10_to_str(cs,to,mlength, 10,
+ (long) *((uchar*) ptr));
else
- length= (uint) (int10_to_str((long) *((signed char*) ptr),to,-10)-to);
+ length= (uint) cs->cset->long10_to_str(cs,to,mlength,-10,
+ (long) *((signed char*) ptr));
+
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
return val_buffer;
}
+bool Field_tiny::send_binary(Protocol *protocol)
+{
+ return protocol->store_tiny((longlong) (int8) ptr[0]);
+}
int Field_tiny::cmp(const char *a_ptr, const char *b_ptr)
{
@@ -1060,51 +1136,62 @@ void Field_tiny::sort_string(char *to,uint length __attribute__((unused)))
void Field_tiny::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"tinyint(%d)",(int) field_length);
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "tinyint(%d)",(int) field_length));
add_zerofill_and_unsigned(res);
}
/****************************************************************************
-** short int
+ Field type short int (2 byte)
****************************************************************************/
-
-// 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)
+int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len);
- long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ int not_used; // We can ignore result from str2int
+ char *end;
+ long tmp= my_strntol(cs, from, len, 10, &end, &not_used);
+ int error= 0;
+
if (unsigned_flag)
{
if (tmp < 0)
{
tmp=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (tmp > (uint16) ~0)
{
tmp=(uint16) ~0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ error= 1;
}
- 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++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (tmp > INT_MAX16)
{
tmp=INT_MAX16;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ error= 1;
}
- else if (current_thd->count_cuted_fields && !test_if_int(from,len))
- current_thd->cuted_fields++;
}
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -1114,11 +1201,13 @@ void Field_short::store(const char *from,uint len)
else
#endif
shortstore(ptr,(short) tmp);
+ return error;
}
-void Field_short::store(double nr)
+int Field_short::store(double nr)
{
+ int error= 0;
int16 res;
nr=rint(nr);
if (unsigned_flag)
@@ -1126,12 +1215,14 @@ void Field_short::store(double nr)
if (nr < 0)
{
res=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > (double) (uint16) ~0)
{
res=(int16) (uint16) ~0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
res=(int16) (uint16) nr;
@@ -1141,12 +1232,14 @@ void Field_short::store(double nr)
if (nr < (double) INT_MIN16)
{
res=INT_MIN16;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > (double) INT_MAX16)
{
res=INT_MAX16;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
res=(int16) nr;
@@ -1159,22 +1252,26 @@ void Field_short::store(double nr)
else
#endif
shortstore(ptr,res);
+ return error;
}
-void Field_short::store(longlong nr)
+int Field_short::store(longlong nr)
{
+ int error= 0;
int16 res;
if (unsigned_flag)
{
if (nr < 0L)
{
res=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > (longlong) (uint16) ~0)
{
res=(int16) (uint16) ~0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
res=(int16) (uint16) nr;
@@ -1184,12 +1281,14 @@ void Field_short::store(longlong nr)
if (nr < INT_MIN16)
{
res=INT_MIN16;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > INT_MAX16)
{
res=INT_MAX16;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
res=(int16) nr;
@@ -1202,6 +1301,7 @@ void Field_short::store(longlong nr)
else
#endif
shortstore(ptr,res);
+ return error;
}
@@ -1229,11 +1329,14 @@ longlong Field_short::val_int(void)
return unsigned_flag ? (longlong) (unsigned short) j : (longlong) j;
}
+
String *Field_short::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs= &my_charset_bin;
uint length;
- val_buffer->alloc(max(field_length+1,7));
+ uint mlength=max(field_length+1,7*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
short j;
#ifdef WORDS_BIGENDIAN
@@ -1244,9 +1347,10 @@ String *Field_short::val_str(String *val_buffer,
shortget(j,ptr);
if (unsigned_flag)
- length=(uint) (int10_to_str((long) (uint16) j,to,10)-to);
+ length=(uint) cs->cset->long10_to_str(cs, to, mlength, 10,
+ (long) (uint16) j);
else
- length=(uint) (int10_to_str((long) j,to,-10)-to);
+ length=(uint) cs->cset->long10_to_str(cs, to, mlength,-10, (long) j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
@@ -1254,6 +1358,12 @@ String *Field_short::val_str(String *val_buffer,
}
+bool Field_short::send_binary(Protocol *protocol)
+{
+ return protocol->store_short(Field_short::val_int());
+}
+
+
int Field_short::cmp(const char *a_ptr, const char *b_ptr)
{
short a,b;
@@ -1300,73 +1410,88 @@ void Field_short::sort_string(char *to,uint length __attribute__((unused)))
void Field_short::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"smallint(%d)",(int) field_length);
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "smallint(%d)",(int) field_length));
add_zerofill_and_unsigned(res);
}
/****************************************************************************
-** medium int
+ Field type medium int (3 byte)
****************************************************************************/
-// 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)
+int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len);
- long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ int not_used; // We can ignore result from str2int
+ char *end;
+ long tmp= my_strntol(cs, from, len, 10, &end, &not_used);
+ int error= 0;
if (unsigned_flag)
{
if (tmp < 0)
{
tmp=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (tmp >= (long) (1L << 24))
{
tmp=(long) (1L << 24)-1L;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ error= 1;
}
- 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++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (tmp > INT_MAX24)
{
tmp=INT_MAX24;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
+ }
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ error= 1;
}
- else if (current_thd->count_cuted_fields && !test_if_int(from,len))
- current_thd->cuted_fields++;
}
int3store(ptr,tmp);
+ return error;
}
-void Field_medium::store(double nr)
+int Field_medium::store(double nr)
{
+ int error= 0;
nr=rint(nr);
if (unsigned_flag)
{
if (nr < 0)
{
int3store(ptr,0);
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr >= (double) (long) (1L << 24))
{
uint32 tmp=(uint32) (1L << 24)-1L;
int3store(ptr,tmp);
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
int3store(ptr,(uint32) nr);
@@ -1377,33 +1502,39 @@ void Field_medium::store(double nr)
{
long tmp=(long) INT_MIN24;
int3store(ptr,tmp);
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > (double) INT_MAX24)
{
long tmp=(long) INT_MAX24;
int3store(ptr,tmp);
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
int3store(ptr,(long) nr);
}
+ return error;
}
-void Field_medium::store(longlong nr)
+int Field_medium::store(longlong nr)
{
+ int error= 0;
if (unsigned_flag)
{
if (nr < 0L)
{
int3store(ptr,0);
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr >= (longlong) (long) (1L << 24))
{
long tmp=(long) (1L << 24)-1L;;
int3store(ptr,tmp);
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
int3store(ptr,(uint32) nr);
@@ -1414,17 +1545,20 @@ void Field_medium::store(longlong nr)
{
long tmp=(long) INT_MIN24;
int3store(ptr,tmp);
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > (longlong) INT_MAX24)
{
long tmp=(long) INT_MAX24;
int3store(ptr,tmp);
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
int3store(ptr,(long) nr);
}
+ return error;
}
@@ -1434,21 +1568,25 @@ double Field_medium::val_real(void)
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 __attribute__((unused)))
{
+ CHARSET_INFO *cs= &my_charset_bin;
uint length;
- val_buffer->alloc(max(field_length+1,10));
+ uint mlength=max(field_length+1,10*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
- length=(uint) (int10_to_str(j,to,-10)-to);
+ length=(uint) cs->cset->long10_to_str(cs,to,mlength,-10,j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer); /* purecov: inspected */
@@ -1456,6 +1594,12 @@ String *Field_medium::val_str(String *val_buffer,
}
+bool Field_medium::send_binary(Protocol *protocol)
+{
+ return protocol->store_long(Field_medium::val_int());
+}
+
+
int Field_medium::cmp(const char *a_ptr, const char *b_ptr)
{
long a,b;
@@ -1485,7 +1629,9 @@ void Field_medium::sort_string(char *to,uint length __attribute__((unused)))
void Field_medium::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"mediumint(%d)",(int) field_length);
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "mediumint(%d)",(int) field_length));
add_zerofill_and_unsigned(res);
}
@@ -1494,36 +1640,36 @@ void Field_medium::sql_type(String &res) const
****************************************************************************/
-// 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)
+int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
{
- char *end;
- while (len && isspace(*from))
- {
- len--; from++;
- }
long tmp;
- String tmp_str(from,len);
- from= tmp_str.c_ptr(); // Add end null if needed
- errno=0;
+ int error= 0;
+ char *end;
+
+ tmp= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES);
+ len-= tmp;
+ from+= tmp;
+ my_errno=0;
if (unsigned_flag)
{
if (!len || *from == '-')
{
tmp=0; // Set negative to 0
- errno=ERANGE;
+ my_errno=ERANGE;
+ error= 1;
}
else
- tmp=(long) strtoul(from, &end, 10);
+ tmp=(long) my_strntoul(cs,from,len,10,&end,&error);
}
else
- tmp=strtol(from, &end, 10);
- if (errno ||
+ tmp=my_strntol(cs,from,len,10,&end,&error);
+ if (error ||
(from+len != end && current_thd->count_cuted_fields &&
- !test_if_int(from,len)))
- current_thd->cuted_fields++;
+ !test_if_int(from,len,end,cs)))
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ error= 1;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -1532,11 +1678,13 @@ void Field_long::store(const char *from,uint len)
else
#endif
longstore(ptr,tmp);
+ return error;
}
-void Field_long::store(double nr)
+int Field_long::store(double nr)
{
+ int error= 0;
int32 res;
nr=rint(nr);
if (unsigned_flag)
@@ -1544,12 +1692,14 @@ void Field_long::store(double nr)
if (nr < 0)
{
res=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > (double) (ulong) ~0L)
{
res=(int32) (uint32) ~0L;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
res=(int32) (ulong) nr;
@@ -1559,12 +1709,14 @@ void Field_long::store(double nr)
if (nr < (double) INT_MIN32)
{
res=(int32) INT_MIN32;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > (double) INT_MAX32)
{
res=(int32) INT_MAX32;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
res=(int32) nr;
@@ -1577,23 +1729,27 @@ void Field_long::store(double nr)
else
#endif
longstore(ptr,res);
+ return error;
}
-void Field_long::store(longlong nr)
+int Field_long::store(longlong nr)
{
+ int error= 0;
int32 res;
if (unsigned_flag)
{
if (nr < 0)
{
res=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr >= (LL(1) << 32))
{
res=(int32) (uint32) ~0L;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
res=(int32) (uint32) nr;
@@ -1603,12 +1759,14 @@ void Field_long::store(longlong nr)
if (nr < (longlong) INT_MIN32)
{
res=(int32) INT_MIN32;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > (longlong) INT_MAX32)
{
res=(int32) INT_MAX32;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
res=(int32) nr;
@@ -1621,6 +1779,7 @@ void Field_long::store(longlong nr)
else
#endif
longstore(ptr,res);
+ return error;
}
@@ -1651,8 +1810,10 @@ longlong Field_long::val_int(void)
String *Field_long::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs= &my_charset_bin;
uint length;
- val_buffer->alloc(max(field_length+1,12));
+ uint mlength=max(field_length+1,12*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
int32 j;
#ifdef WORDS_BIGENDIAN
@@ -1662,9 +1823,10 @@ String *Field_long::val_str(String *val_buffer,
#endif
longget(j,ptr);
- length=(uint) (int10_to_str((unsigned_flag ? (long) (uint32) j : (long) j),
- to,
- unsigned_flag ? 10 : -10)-to);
+ if (unsigned_flag)
+ length=cs->cset->long10_to_str(cs,to,mlength, 10,(long) (uint32)j);
+ else
+ length=cs->cset->long10_to_str(cs,to,mlength,-10,(long) j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
@@ -1672,6 +1834,11 @@ String *Field_long::val_str(String *val_buffer,
}
+bool Field_long::send_binary(Protocol *protocol)
+{
+ return protocol->store_long(Field_long::val_int());
+}
+
int Field_long::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
@@ -1721,41 +1888,46 @@ void Field_long::sort_string(char *to,uint length __attribute__((unused)))
void Field_long::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"int(%d)",(int) field_length);
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "int(%d)",(int) field_length));
add_zerofill_and_unsigned(res);
}
/****************************************************************************
-** longlong int
+ Field type longlong int (8 bytes)
****************************************************************************/
-void Field_longlong::store(const char *from,uint len)
+int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
{
- char *end;
- while (len && isspace(*from))
- { // For easy error check
- len--; from++;
- }
longlong tmp;
- String tmp_str(from,len);
- from= tmp_str.c_ptr(); // Add end null if needed
- errno=0;
+ int error= 0;
+ char *end;
+
+ tmp= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES);
+ len-= (uint)tmp;
+ from+= tmp;
+ my_errno=0;
if (unsigned_flag)
{
if (!len || *from == '-')
{
tmp=0; // Set negative to 0
- errno=ERANGE;
+ my_errno= ERANGE;
+ error= 1;
}
else
- tmp=(longlong) strtoull(from, &end, 10);
+ tmp=(longlong) my_strntoull(cs,from,len,10,&end,&error);
}
else
- tmp=strtoll(from, &end, 10);
- if (errno ||
+ tmp=my_strntoll(cs,from,len,10,&end,&error);
+ if (error ||
(from+len != end && current_thd->count_cuted_fields &&
- !test_if_int(from,len)))
- current_thd->cuted_fields++;
+ !test_if_int(from,len,end,cs)))
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ error= 1;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -1764,11 +1936,13 @@ void Field_longlong::store(const char *from,uint len)
else
#endif
longlongstore(ptr,tmp);
+ return error;
}
-void Field_longlong::store(double nr)
+int Field_longlong::store(double nr)
{
+ int error= 0;
longlong res;
nr=rint(nr);
if (unsigned_flag)
@@ -1776,12 +1950,14 @@ void Field_longlong::store(double nr)
if (nr < 0)
{
res=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr >= (double) ~ (ulonglong) 0)
{
res= ~(longlong) 0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
res=(longlong) (ulonglong) nr;
@@ -1791,12 +1967,14 @@ void Field_longlong::store(double nr)
if (nr <= (double) LONGLONG_MIN)
{
res=(longlong) LONGLONG_MIN;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr >= (double) LONGLONG_MAX)
{
res=(longlong) LONGLONG_MAX;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
res=(longlong) nr;
@@ -1809,10 +1987,11 @@ void Field_longlong::store(double nr)
else
#endif
longlongstore(ptr,res);
+ return error;
}
-void Field_longlong::store(longlong nr)
+int Field_longlong::store(longlong nr)
{
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -1822,6 +2001,7 @@ void Field_longlong::store(longlong nr)
else
#endif
longlongstore(ptr,nr);
+ return 0;
}
@@ -1862,8 +2042,10 @@ longlong Field_longlong::val_int(void)
String *Field_longlong::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs= &my_charset_bin;
uint length;
- val_buffer->alloc(max(field_length+1,22));
+ uint mlength=max(field_length+1,22*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
longlong j;
#ifdef WORDS_BIGENDIAN
@@ -1873,7 +2055,8 @@ String *Field_longlong::val_str(String *val_buffer,
#endif
longlongget(j,ptr);
- length=(uint) (longlong10_to_str(j,to,unsigned_flag ? 10 : -10)-to);
+ length=(uint) (cs->cset->longlong10_to_str)(cs,to,mlength,
+ unsigned_flag ? 10 : -10, j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
@@ -1881,6 +2064,12 @@ String *Field_longlong::val_str(String *val_buffer,
}
+bool Field_longlong::send_binary(Protocol *protocol)
+{
+ return protocol->store_longlong(Field_longlong::val_int(), unsigned_flag);
+}
+
+
int Field_longlong::cmp(const char *a_ptr, const char *b_ptr)
{
longlong a,b;
@@ -1939,7 +2128,9 @@ void Field_longlong::sort_string(char *to,uint length __attribute__((unused)))
void Field_longlong::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"bigint(%d)",(int) field_length);
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "bigint(%d)",(int) field_length));
add_zerofill_and_unsigned(res);
}
@@ -1947,35 +2138,42 @@ void Field_longlong::sql_type(String &res) const
** single precision float
****************************************************************************/
-void Field_float::store(const char *from,uint len)
+int Field_float::store(const char *from,uint len,CHARSET_INFO *cs)
{
- 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++;
+ int err;
+ Field_float::store(my_strntod(cs,(char*) from,len,(char**)NULL,&err));
+ if (err || current_thd->count_cuted_fields && !test_if_real(from,len,cs))
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ return 1;
+ }
+ return (err) ? 1 : 0;
}
-void Field_float::store(double nr)
+int Field_float::store(double nr)
{
float j;
+ int error= 0;
if (dec < NOT_FIXED_DEC)
nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point
if (unsigned_flag && nr < 0)
{
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
nr=0;
+ error= 1;
}
if (nr < -FLT_MAX)
{
j= -FLT_MAX;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr > FLT_MAX)
{
j=FLT_MAX;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
j= (float) nr;
@@ -1987,16 +2185,19 @@ void Field_float::store(double nr)
else
#endif
memcpy_fixed(ptr,(byte*) &j,sizeof(j));
+ return error;
}
-void Field_float::store(longlong nr)
+int Field_float::store(longlong nr)
{
+ int error= 0;
float j= (float) nr;
if (unsigned_flag && j < 0)
{
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
j=0;
+ error= 1;
}
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -2006,6 +2207,7 @@ void Field_float::store(longlong nr)
else
#endif
memcpy_fixed(ptr,(byte*) &j,sizeof(j));
+ return error;
}
@@ -2105,10 +2307,10 @@ String *Field_float::val_str(String *val_buffer,
#ifdef HAVE_SNPRINTF
to[to_length-1]=0; // Safety
snprintf(to,to_length-1,"%.*f",dec,nr);
+ to=strend(to);
#else
- sprintf(to,"%.*f",dec,nr);
+ to+= my_sprintf(to,(to,"%.*f",dec,nr));
#endif
- to=strend(to);
#endif
}
#ifdef HAVE_FCONVERT
@@ -2184,12 +2386,24 @@ void Field_float::sort_string(char *to,uint length __attribute__((unused)))
}
+bool Field_float::send_binary(Protocol *protocol)
+{
+ return protocol->store((float) Field_float::val_real(), dec, (String*) 0);
+}
+
+
void Field_float::sql_type(String &res) const
{
if (dec == NOT_FIXED_DEC)
- strmov((char*) res.ptr(),"float");
+ {
+ res.set_ascii("float", 5);
+ }
else
- sprintf((char*) res.ptr(),"float(%d,%d)",(int) field_length,dec);
+ {
+ CHARSET_INFO *cs= res.charset();
+ res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "float(%d,%d)",(int) field_length,dec));
+ }
add_zerofill_and_unsigned(res);
}
@@ -2197,17 +2411,20 @@ void Field_float::sql_type(String &res) const
** double precision floating point numbers
****************************************************************************/
-void Field_double::store(const char *from,uint len)
+int Field_double::store(const char *from,uint len,CHARSET_INFO *cs)
{
- 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++;
+ int err;
+ double j= my_strntod(cs,(char*) from,len,(char**)0,&err);
+ if (err || current_thd->count_cuted_fields && !test_if_real(from,len,cs))
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ err= 1;
+ }
if (unsigned_flag && j < 0)
{
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
j=0;
+ err= 1;
}
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -2217,17 +2434,20 @@ void Field_double::store(const char *from,uint len)
else
#endif
doublestore(ptr,j);
+ return err;
}
-void Field_double::store(double nr)
+int Field_double::store(double nr)
{
+ int error= 0;
if (dec < NOT_FIXED_DEC)
nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point
if (unsigned_flag && nr < 0)
{
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
nr=0;
+ error= 1;
}
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -2237,15 +2457,18 @@ void Field_double::store(double nr)
else
#endif
doublestore(ptr,nr);
+ return error;
}
-void Field_double::store(longlong nr)
+int Field_double::store(longlong nr)
{
double j= (double) nr;
+ int error= 0;
if (unsigned_flag && j < 0)
{
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
j=0;
}
#ifdef WORDS_BIGENDIAN
@@ -2256,6 +2479,7 @@ void Field_double::store(longlong nr)
else
#endif
doublestore(ptr,j);
+ return error;
}
@@ -2354,10 +2578,10 @@ String *Field_double::val_str(String *val_buffer,
#ifdef HAVE_SNPRINTF
to[to_length-1]=0; // Safety
snprintf(to,to_length-1,"%.*f",dec,nr);
+ to=strend(to);
#else
- sprintf(to,"%.*f",dec,nr);
+ to+= my_sprintf(to,(to,"%.*f",dec,nr));
#endif
- to=strend(to);
#endif
}
#ifdef HAVE_FCONVERT
@@ -2370,6 +2594,11 @@ String *Field_double::val_str(String *val_buffer,
return val_buffer;
}
+bool Field_double::send_binary(Protocol *protocol)
+{
+ return protocol->store((double) Field_double::val_real(), dec, (String*) 0);
+}
+
int Field_double::cmp(const char *a_ptr, const char *b_ptr)
{
@@ -2422,10 +2651,16 @@ void Field_double::sort_string(char *to,uint length __attribute__((unused)))
void Field_double::sql_type(String &res) const
{
+ CHARSET_INFO *cs=res.charset();
if (dec == NOT_FIXED_DEC)
- strmov((char*) res.ptr(),"double");
+ {
+ res.set_ascii("double",6);
+ }
else
- sprintf((char*) res.ptr(),"double(%d,%d)",(int) field_length,dec);
+ {
+ res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "double(%d,%d)",(int) field_length,dec));
+ }
add_zerofill_and_unsigned(res);
}
@@ -2436,22 +2671,15 @@ void Field_double::sql_type(String &res) const
** by handler.cc. The form->timestamp points at the automatic timestamp.
****************************************************************************/
-enum Item_result Field_timestamp::result_type() const
-{
- return (!current_thd->variables.new_mode &&
- (field_length == 8 || field_length == 14) ? INT_RESULT :
- STRING_RESULT);
-}
-
-
Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
enum utype unireg_check_arg,
const 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)
+ struct st_table *table_arg,
+ CHARSET_INFO *cs)
+ :Field_str(ptr_arg, 19, (uchar*) 0,0,
+ unireg_check_arg, field_name_arg, table_arg, cs)
{
+ flags|=ZEROFILL_FLAG; /* 4.0 MYD compatibility */
if (table && !table->timestamp_field)
{
table->timestamp_field= this; // Automatic timestamp
@@ -2461,7 +2689,7 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
}
-void Field_timestamp::store(const char *from,uint len)
+int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
{
long tmp=(long) str_to_timestamp(from,len);
#ifdef WORDS_BIGENDIAN
@@ -2472,56 +2700,32 @@ void Field_timestamp::store(const char *from,uint len)
else
#endif
longstore(ptr,tmp);
+ return 0;
}
-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 tmp=(long) str_to_timestamp(from,len);
-#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int4store(ptr,tmp);
- }
- else
-#endif
- longstore(ptr,tmp);
-}
-
-
-void Field_timestamp::store(double nr)
+int Field_timestamp::store(double nr)
{
+ int error= 0;
if (nr < 0 || nr > 99991231235959.0)
{
- nr=0; // Avoid overflow on buff
- current_thd->cuted_fields++;
+ nr= 0; // Avoid overflow on buff
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
- Field_timestamp::store((longlong) rint(nr));
+ error|= Field_timestamp::store((longlong) rint(nr));
+ return error;
}
/*
-** Convert a datetime of formats YYMMDD, YYYYMMDD or YYMMDDHHMSS to
-** YYYYMMDDHHMMSS. The high date '99991231235959' is checked before this
-** function.
+ 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)
{
+ current_thd->last_cuted_field= 0;
if (nr == LL(0) || nr >= LL(10000101000000))
return nr; // Normal datetime >= Year 1000
if (nr < 101)
@@ -2546,12 +2750,12 @@ static longlong fix_datetime(longlong nr)
return nr+LL(19000000000000); // YYMMDDHHMMSS, 1970-1999
err:
- current_thd->cuted_fields++;
+ current_thd->last_cuted_field= 1;
return LL(0);
}
-void Field_timestamp::store(longlong nr)
+int Field_timestamp::store(longlong nr)
{
TIME l_time;
time_t timestamp;
@@ -2580,6 +2784,9 @@ void Field_timestamp::store(longlong nr)
else
#endif
longstore(ptr,(uint32) timestamp);
+ if (current_thd->last_cuted_field)
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ return 0;
}
@@ -2590,7 +2797,6 @@ double Field_timestamp::val_real(void)
longlong Field_timestamp::val_int(void)
{
- uint len,pos;
int part_time;
uint32 temp;
time_t time_arg;
@@ -2610,44 +2816,34 @@ longlong Field_timestamp::val_int(void)
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 < YY_PART_YEAR) ? 2000 : 1900));
- len+=2;
- }
- else
- res=res*(longlong) 100+part_time;
- }
- return (longlong) res;
+
+ part_time= l_time->tm_year % 100;
+ res= ((longlong) (part_time+ ((part_time < YY_PART_YEAR) ? 2000 : 1900))*
+ LL(10000000000));
+ part_time= l_time->tm_mon+1;
+ res+= (longlong) part_time * LL(100000000);
+ part_time=l_time->tm_mday;
+ res+= (longlong) ((long) part_time * 1000000L);
+ part_time=l_time->tm_hour;
+ res+= (longlong) (part_time * 10000L);
+ part_time=l_time->tm_min;
+ res+= (longlong) (part_time * 100);
+ part_time=l_time->tm_sec;
+ return res+part_time;
}
String *Field_timestamp::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
- uint pos;
- int part_time;
- uint32 temp;
+ uint32 temp, temp2;
time_t time_arg;
struct tm *l_time;
struct tm tm_tmp;
- my_bool new_format= (current_thd->variables.new_mode),
- full_year=(field_length == 8 || field_length == 14 || new_format);
- int real_field_length= new_format ? 19 : field_length;
+
+ val_buffer->alloc(field_length+1);
+ char *to=(char*) val_buffer->ptr(),*end=to+field_length;
+ val_buffer->length(field_length);
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -2658,57 +2854,58 @@ String *Field_timestamp::val_str(String *val_buffer,
if (temp == 0L)
{ /* Zero time is "000000" */
- if (new_format)
- val_buffer->copy("0000-00-00 00:00:00", real_field_length);
- else
- val_buffer->copy("00000000000000", real_field_length);
- return val_buffer;
+ val_ptr->set("0000-00-00 00:00:00", 19, &my_charset_bin);
+ return val_ptr;
}
+ val_buffer->set_charset(&my_charset_bin); // Safety
time_arg=(time_t) temp;
localtime_r(&time_arg,&tm_tmp);
l_time=&tm_tmp;
- val_buffer->alloc(real_field_length+1);
- char *to=(char*) val_buffer->ptr(),*end=to+real_field_length;
-
- for (pos=0; to < end ; pos++)
- {
- bool year_flag=0;
- switch (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 && full_year)
- {
- if (part_time < YY_PART_YEAR)
- {
- *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));
- if (new_format)
- {
- static const char delim[6]="-- ::";
- *to++=delim[pos];
- }
- }
- if (new_format)
- to--;
- *to=0; // Safeguard
- val_buffer->length((uint) (to-val_buffer->ptr()));
+ temp= l_time->tm_year % 100;
+ if (temp < YY_PART_YEAR)
+ {
+ *to++= '2';
+ *to++= '0';
+ }
+ else
+ {
+ *to++= '1';
+ *to++= '9';
+ }
+ temp2=temp/10; temp=temp-temp2*10;
+ *to++= (char) ('0'+(char) (temp2));
+ *to++= (char) ('0'+(char) (temp));
+ *to++= '-';
+ temp=l_time->tm_mon+1;
+ temp2=temp/10; temp=temp-temp2*10;
+ *to++= (char) ('0'+(char) (temp2));
+ *to++= (char) ('0'+(char) (temp));
+ *to++= '-';
+ temp=l_time->tm_mday;
+ temp2=temp/10; temp=temp-temp2*10;
+ *to++= (char) ('0'+(char) (temp2));
+ *to++= (char) ('0'+(char) (temp));
+ *to++= ' ';
+ temp=l_time->tm_hour;
+ temp2=temp/10; temp=temp-temp2*10;
+ *to++= (char) ('0'+(char) (temp2));
+ *to++= (char) ('0'+(char) (temp));
+ *to++= ':';
+ temp=l_time->tm_min;
+ temp2=temp/10; temp=temp-temp2*10;
+ *to++= (char) ('0'+(char) (temp2));
+ *to++= (char) ('0'+(char) (temp));
+ *to++= ':';
+ temp=l_time->tm_sec;
+ temp2=temp/10; temp=temp-temp2*10;
+ *to++= (char) ('0'+(char) (temp2));
+ *to++= (char) ('0'+(char) (temp));
+ *to= 0;
return val_buffer;
}
+
bool Field_timestamp::get_date(TIME *ltime, bool fuzzydate)
{
long temp;
@@ -2748,6 +2945,15 @@ bool Field_timestamp::get_time(TIME *ltime)
return Field_timestamp::get_date(ltime,0);
}
+
+bool Field_timestamp::send_binary(Protocol *protocol)
+{
+ TIME tm;
+ Field_timestamp::get_date(&tm, 1);
+ return protocol->store(&tm);
+}
+
+
int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
@@ -2766,6 +2972,7 @@ int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
}
+
void Field_timestamp::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
@@ -2789,8 +2996,7 @@ void Field_timestamp::sort_string(char *to,uint length __attribute__((unused)))
void Field_timestamp::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"timestamp(%d)",(int) field_length);
- res.length((uint) strlen(res.ptr()));
+ res.set_ascii("timestamp", 9);
}
@@ -2807,23 +3013,6 @@ void Field_timestamp::set_time()
longstore(ptr,tmp);
}
-/*
- This is an exact copy of Field_num except that 'length' is depending
- on --new mode
-*/
-
-void Field_timestamp::make_field(Send_field *field)
-{
- field->table_name=table_name;
- field->col_name=field_name;
- /* If --new, then we are using "YYYY-MM-DD HH:MM:SS" format */
- field->length= current_thd->variables.new_mode ? 19 : field_length;
- field->type=type();
- field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
- field->decimals=dec;
-}
-
-
/****************************************************************************
** time type
** In string context: HH:MM:SS
@@ -2831,12 +3020,17 @@ void Field_timestamp::make_field(Send_field *field)
** Stored as a 3 byte unsigned int
****************************************************************************/
-void Field_time::store(const char *from,uint len)
+int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
{
TIME ltime;
long tmp;
+ int error= 0;
if (str_to_time(from,len,&ltime))
+ {
tmp=0L;
+ error= 1;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ }
else
{
if (ltime.month)
@@ -2845,27 +3039,32 @@ void Field_time::store(const char *from,uint len)
if (tmp > 8385959)
{
tmp=8385959;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
}
if (ltime.neg)
tmp= -tmp;
- Field_time::store((longlong) tmp);
+ error |= Field_time::store((longlong) tmp);
+ return error;
}
-void Field_time::store(double nr)
+int Field_time::store(double nr)
{
long tmp;
+ int error= 0;
if (nr > 8385959.0)
{
tmp=8385959L;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr < -8385959.0)
{
tmp= -8385959L;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
{
@@ -2875,25 +3074,30 @@ void Field_time::store(double nr)
if (tmp % 100 > 59 || tmp/100 % 100 > 59)
{
tmp=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
}
int3store(ptr,tmp);
+ return error;
}
-void Field_time::store(longlong nr)
+int Field_time::store(longlong nr)
{
long tmp;
+ int error= 0;
if (nr > (longlong) 8385959L)
{
tmp=8385959L;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else if (nr < (longlong) -8385959L)
{
tmp= -8385959L;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
{
@@ -2901,10 +3105,12 @@ void Field_time::store(longlong nr)
if (tmp % 100 > 59 || tmp/100 % 100 > 59)
{
tmp=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
}
int3store(ptr,tmp);
+ return error;
}
@@ -2919,6 +3125,12 @@ longlong Field_time::val_int(void)
return (longlong) sint3korr(ptr);
}
+
+/*
+ This function is multi-byte safe as the result string is always of type
+ my_charset_bin
+*/
+
String *Field_time::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
@@ -2930,10 +3142,11 @@ String *Field_time::val_str(String *val_buffer,
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((uint) strlen(val_buffer->ptr()));
+ long length= my_sprintf((char*) val_buffer->ptr(),
+ ((char*) val_buffer->ptr(),"%s%02d:%02d:%02d",
+ sign,(int) (tmp/10000), (int) (tmp/100 % 100),
+ (int) (tmp % 100)));
+ val_buffer->length(length);
return val_buffer;
}
@@ -2946,14 +3159,27 @@ bool Field_time::get_time(TIME *ltime)
ltime->neg= 1;
tmp=-tmp;
}
+ ltime->day= 0;
ltime->hour= (int) (tmp/10000);
tmp-=ltime->hour*10000;
ltime->minute= (int) tmp/100;
ltime->second= (int) tmp % 100;
ltime->second_part=0;
+ ltime->time_type= TIMESTAMP_TIME;
return 0;
}
+
+bool Field_time::send_binary(Protocol *protocol)
+{
+ TIME tm;
+ Field_time::get_time(&tm);
+ tm.day= tm.hour/3600; // Move hours to days
+ tm.hour-= tm.day*3600;
+ return protocol->store_time(&tm);
+}
+
+
int Field_time::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
@@ -2971,7 +3197,7 @@ void Field_time::sort_string(char *to,uint length __attribute__((unused)))
void Field_time::sql_type(String &res) const
{
- res.set("time",4);
+ res.set_ascii("time", 4);
}
/****************************************************************************
@@ -2980,19 +3206,20 @@ void Field_time::sql_type(String &res) const
** Can handle 2 byte or 4 byte years!
****************************************************************************/
-void Field_year::store(const char *from, uint len)
+int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len);
- long nr= strtol(tmp_str.c_ptr(),NULL,10);
+ int not_used; // We can ignore result from str2int
+ char *end;
+ long nr= my_strntol(cs, from, len, 10, &end, &not_used);
if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
{
*ptr=0;
- current_thd->cuted_fields++;
- return;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ return 1;
}
- else if (current_thd->count_cuted_fields && !test_if_int(from,len))
- current_thd->cuted_fields++;
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
if (nr != 0 || len != 4)
{
if (nr < YY_PART_YEAR)
@@ -3001,23 +3228,27 @@ void Field_year::store(const char *from, uint len)
nr-= 1900;
}
*ptr= (char) (unsigned char) nr;
+ return 0;
}
-void Field_year::store(double nr)
+int Field_year::store(double nr)
{
if (nr < 0.0 || nr >= 2155.0)
- Field_year::store((longlong) -1);
+ {
+ (void) Field_year::store((longlong) -1);
+ return 1;
+ }
else
- Field_year::store((longlong) nr);
+ return Field_year::store((longlong) nr);
}
-void Field_year::store(longlong nr)
+int Field_year::store(longlong nr)
{
if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
{
*ptr=0;
- current_thd->cuted_fields++;
- return;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ return 1;
}
if (nr != 0 || field_length != 4) // 0000 -> 0; 00 -> 2000
{
@@ -3027,8 +3258,14 @@ void Field_year::store(longlong nr)
nr-= 1900;
}
*ptr= (char) (unsigned char) nr;
+ return 0;
}
+bool Field_year::send_binary(Protocol *protocol)
+{
+ ulonglong tmp= Field_year::val_int();
+ return protocol->store_short(tmp);
+}
double Field_year::val_real(void)
{
@@ -3057,8 +3294,9 @@ String *Field_year::val_str(String *val_buffer,
void Field_year::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"year(%d)",(int) field_length);
- res.length((uint) strlen(res.ptr()));
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->cset->snprintf(cs,(char*)res.ptr(),res.alloced_length(),
+ "year(%d)",(int) field_length));
}
@@ -3069,12 +3307,17 @@ void Field_year::sql_type(String &res) const
** Stored as a 4 byte unsigned int
****************************************************************************/
-void Field_date::store(const char *from, uint len)
+int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
{
TIME l_time;
uint32 tmp;
+ int error= 0;
if (str_to_TIME(from,len,&l_time,1) == TIMESTAMP_NONE)
+ {
tmp=0;
+ error= 1;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ }
else
tmp=(uint32) l_time.year*10000L + (uint32) (l_time.month*100+l_time.day);
#ifdef WORDS_BIGENDIAN
@@ -3085,18 +3328,21 @@ void Field_date::store(const char *from, uint len)
else
#endif
longstore(ptr,tmp);
+ return error;
}
-void Field_date::store(double nr)
+int Field_date::store(double nr)
{
long tmp;
+ int error= 0;
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++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
tmp=(long) rint(nr);
@@ -3108,18 +3354,21 @@ void Field_date::store(double nr)
else
#endif
longstore(ptr,tmp);
+ return error;
}
-void Field_date::store(longlong nr)
+int Field_date::store(longlong nr)
{
long tmp;
+ int error= 0;
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++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
tmp=(long) nr;
@@ -3131,6 +3380,18 @@ void Field_date::store(longlong nr)
else
#endif
longstore(ptr,tmp);
+ return error;
+}
+
+
+bool Field_date::send_binary(Protocol *protocol)
+{
+ longlong tmp= Field_date::val_int();
+ TIME tm;
+ tm.year= (uint32) tmp/10000L % 10000;
+ tm.month= (uint32) tmp/100 % 100;
+ tm.day= (uint32) tmp % 100;
+ return protocol->store_date(&tm);
}
@@ -3217,7 +3478,7 @@ void Field_date::sort_string(char *to,uint length __attribute__((unused)))
void Field_date::sql_type(String &res) const
{
- res.set("date",4);
+ res.set_ascii("date", 4);
}
/****************************************************************************
@@ -3226,35 +3487,47 @@ void Field_date::sql_type(String &res) const
** In number context: YYYYMMDD
****************************************************************************/
-void Field_newdate::store(const char *from,uint len)
+int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
{
TIME l_time;
long tmp;
+ int error= 0;
if (str_to_TIME(from,len,&l_time,1) == TIMESTAMP_NONE)
+ {
tmp=0L;
+ error= 1;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ }
else
tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
int3store(ptr,tmp);
+ return error;
}
-void Field_newdate::store(double nr)
+int Field_newdate::store(double nr)
{
if (nr < 0.0 || nr > 99991231235959.0)
- Field_newdate::store((longlong) -1);
+ {
+ (void) Field_newdate::store((longlong) -1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ return 1;
+ }
else
- Field_newdate::store((longlong) rint(nr));
+ return Field_newdate::store((longlong) rint(nr));
}
-void Field_newdate::store(longlong nr)
+int Field_newdate::store(longlong nr)
{
int32 tmp;
+ int error= 0;
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++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
{
@@ -3271,12 +3544,14 @@ void Field_newdate::store(longlong nr)
if (month > 12 || day > 31)
{
tmp=0L; // Don't allow date to change
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
tmp= day + month*32 + (tmp/10000)*16*32;
}
int3store(ptr,(int32) tmp);
+ return error;
}
void Field_newdate::store_time(TIME *ltime,timestamp_type type)
@@ -3287,12 +3562,17 @@ void Field_newdate::store_time(TIME *ltime,timestamp_type type)
else
{
tmp=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
}
int3store(ptr,tmp);
}
-
+bool Field_newdate::send_binary(Protocol *protocol)
+{
+ TIME tm;
+ Field_newdate::get_date(&tm,0);
+ return protocol->store_date(&tm);
+}
double Field_newdate::val_real(void)
{
@@ -3368,7 +3648,7 @@ void Field_newdate::sort_string(char *to,uint length __attribute__((unused)))
void Field_newdate::sql_type(String &res) const
{
- res.set("date",4);
+ res.set_ascii("date", 4);
}
@@ -3379,7 +3659,7 @@ void Field_newdate::sql_type(String &res) const
** 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)
+int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
{
longlong tmp=str_to_datetime(from,len,1);
#ifdef WORDS_BIGENDIAN
@@ -3390,26 +3670,32 @@ void Field_datetime::store(const char *from,uint len)
else
#endif
longlongstore(ptr,tmp);
+ return 0;
}
-void Field_datetime::store(double nr)
+int Field_datetime::store(double nr)
{
+ int error= 0;
if (nr < 0.0 || nr > 99991231235959.0)
{
nr=0.0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
- Field_datetime::store((longlong) rint(nr));
+ error |= Field_datetime::store((longlong) rint(nr));
+ return error;
}
-void Field_datetime::store(longlong nr)
+int Field_datetime::store(longlong nr)
{
+ int error= 0;
if (nr < 0 || nr > LL(99991231235959))
{
nr=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
+ error= 1;
}
else
nr=fix_datetime(nr);
@@ -3421,6 +3707,9 @@ void Field_datetime::store(longlong nr)
else
#endif
longlongstore(ptr,nr);
+ if (current_thd->last_cuted_field)
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ return error;
}
void Field_datetime::store_time(TIME *ltime,timestamp_type type)
@@ -3432,7 +3721,7 @@ void Field_datetime::store_time(TIME *ltime,timestamp_type type)
else
{
tmp=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
}
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -3444,6 +3733,13 @@ void Field_datetime::store_time(TIME *ltime,timestamp_type type)
longlongstore(ptr,tmp);
}
+bool Field_datetime::send_binary(Protocol *protocol)
+{
+ TIME tm;
+ Field_datetime::get_date(&tm, 1);
+ return protocol->store(&tm);
+}
+
double Field_datetime::val_real(void)
{
@@ -3585,7 +3881,7 @@ void Field_datetime::sort_string(char *to,uint length __attribute__((unused)))
void Field_datetime::sql_type(String &res) const
{
- res.set("datetime",8);
+ res.set_ascii("datetime", 8);
}
/****************************************************************************
@@ -3595,21 +3891,29 @@ void Field_datetime::sql_type(String &res) const
/* Copy a string and fill with space */
-void Field_string::store(const char *from,uint length)
+static bool use_conversion(CHARSET_INFO *cs1, CHARSET_INFO *cs2)
{
-#ifdef USE_TIS620
- if (!binary_flag) {
- ThNormalize((uchar *)ptr, field_length, (uchar *)from, length);
- if (length < field_length) {
- bfill(ptr + length, field_length - length, ' ');
- }
+ return (cs1 != &my_charset_bin) && (cs2 != &my_charset_bin) && (cs1!=cs2);
+}
+
+int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
+{
+ int error= 0;
+ char buff[80];
+ String tmpstr(buff,sizeof(buff), &my_charset_bin);
+ /* Convert character set if nesessary */
+ if (use_conversion(cs, field_charset))
+ {
+ tmpstr.copy(from, length, cs, field_charset);
+ from= tmpstr.ptr();
+ length= tmpstr.length();
}
-#else
if (length <= field_length)
{
memcpy(ptr,from,length);
if (length < field_length)
- bfill(ptr+length,field_length-length,' ');
+ field_charset->cset->fill(field_charset,ptr+length,field_length-length,
+ ' ');
}
else
{
@@ -3617,57 +3921,53 @@ void Field_string::store(const char *from,uint 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++)
+ from+= field_length;
+ from+= field_charset->cset->scan(field_charset, from, end,
+ MY_SEQ_SPACES);
+ if (from != end)
{
- if (!isspace(*from))
- {
- current_thd->cuted_fields++;
- break;
- }
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ error=1;
}
}
}
-#endif /* USE_TIS620 */
+ return error;
}
-void Field_string::store(double nr)
+int Field_string::store(double nr)
{
char buff[MAX_FIELD_WIDTH],*end;
int width=min(field_length,DBL_DIG+5);
sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
end=strcend(buff,' ');
- Field_string::store(buff,(uint) (end - buff));
+ return Field_string::store(buff,(uint) (end - buff), &my_charset_bin);
}
-void Field_string::store(longlong nr)
+int Field_string::store(longlong nr)
{
- char buff[22];
- char *end=longlong10_to_str(nr,buff,-10);
- Field_string::store(buff,(uint) (end-buff));
+ char buff[64];
+ int l;
+ CHARSET_INFO *cs=charset();
+ l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr);
+ return Field_string::store(buff,(uint)l,cs);
}
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;
+ int not_used;
+ CHARSET_INFO *cs=charset();
+ return my_strntod(cs,ptr,field_length,(char**)0,&not_used);
}
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;
+ int not_used;
+ CHARSET_INFO *cs=charset();
+ return my_strntoll(cs,ptr,field_length,10,NULL,&not_used);
}
@@ -3680,64 +3980,49 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)),
#endif
while (end > ptr && end[-1] == ' ')
end--;
- val_ptr->set((const char*) ptr,(uint) (end - ptr));
+ val_ptr->set((const char*) ptr,(uint) (end - ptr),field_charset);
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);
-#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
+ if (field_charset->strxfrm_multiply > 1)
{
/*
We have to remove end space to be able to compare multi-byte-characters
like in latin_de 'ae' and 0xe4
*/
- uint a_length= field_length_without_space(a_ptr, field_length);
- uint b_length= field_length_without_space(b_ptr, field_length);
- return my_strnncoll(default_charset_info,
- (const uchar*) a_ptr, a_length,
- (const uchar*) b_ptr, b_length);
+ return field_charset->coll->strnncollsp(field_charset,
+ (const uchar*) a_ptr, field_length,
+ (const uchar*) b_ptr, field_length);
}
-#endif
- return my_sortcmp(a_ptr,b_ptr,field_length);
+ return field_charset->coll->strnncoll(field_charset,
+ (const uchar*) a_ptr, field_length,
+ (const uchar*) b_ptr, field_length);
}
void Field_string::sort_string(char *to,uint length)
{
- if (binary_flag)
- memcpy((byte*) to,(byte*) ptr,(size_t) length);
- else
- {
-#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info)) {
- uint tmp=my_strnxfrm(default_charset_info,
- (unsigned char *)to, (unsigned char *) ptr,
- length, field_length);
- if (tmp < length)
- bzero(to + tmp, length - tmp);
- }
- else
-#endif
- for (char *from=ptr,*end=ptr+length ; from != end ;)
- *to++=(char) my_sort_order[(uint) (uchar) *from++];
- }
+ uint tmp=my_strnxfrm(field_charset,
+ (unsigned char *)to, length,
+ (unsigned char *) ptr, field_length);
+ if (tmp < length)
+ bzero(to + tmp, length - tmp);
}
void Field_string::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"%s(%d)",
- field_length > 3 &&
- (table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
- "varchar" : "char",
- (int) field_length);
- res.length((uint) strlen(res.ptr()));
- if (binary_flag)
- res.append(" binary");
+ CHARSET_INFO *cs=res.charset();
+ ulong length= cs->cset->snprintf(cs,(char*) res.ptr(),
+ res.alloced_length(), "%s(%d)",
+ (field_length > 3 &&
+ (table->db_options_in_use &
+ HA_OPTION_PACK_RECORD) ?
+ "varchar" : "char"),
+ (int) field_length / charset()->mbmaxlen);
+ res.length(length);
}
@@ -3766,13 +4051,9 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length)
{
uint a_length= (uint) (uchar) *a++;
uint b_length= (uint) (uchar) *b++;
-
- if (binary_flag)
- {
- int cmp= memcmp(a,b,min(a_length,b_length));
- return cmp ? cmp : (int) (a_length - b_length);
- }
- return my_sortncmp(a,a_length, b,b_length);
+ return my_strnncoll(field_charset,
+ (const uchar*)a,a_length,
+ (const uchar*)b,b_length);
}
@@ -3783,13 +4064,9 @@ int Field_string::pack_cmp(const char *b, uint length)
while (end > ptr && end[-1] == ' ')
end--;
uint a_length = (uint) (end - ptr);
-
- if (binary_flag)
- {
- int cmp= memcmp(ptr,b,min(a_length,b_length));
- return cmp ? cmp : (int) (a_length - b_length);
- }
- return my_sortncmp(ptr,a_length, b, b_length);
+ return my_strnncoll(field_charset,
+ (const uchar*)ptr,a_length,
+ (const uchar*)b, b_length);
}
@@ -3812,68 +4089,65 @@ uint Field_string::max_packed_col_length(uint max_length)
****************************************************************************/
-void Field_varstring::store(const char *from,uint length)
+int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
{
-#ifdef USE_TIS620
- if (!binary_flag)
- {
- ThNormalize((uchar *) ptr+2, field_length, (uchar *) from, length);
- }
-#else
- if (length <= field_length)
- {
- memcpy(ptr+2,from,length);
+ int error= 0;
+ char buff[80];
+ String tmpstr(buff,sizeof(buff), &my_charset_bin);
+ /* Convert character set if nesessary */
+ if (use_conversion(cs, field_charset))
+ {
+ tmpstr.copy(from, length, cs, field_charset);
+ from= tmpstr.ptr();
+ length= tmpstr.length();
}
- else
+ if (length > field_length)
{
length=field_length;
- memcpy(ptr+2,from,field_length);
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ error= 1;
}
-#endif /* USE_TIS620 */
- int2store(ptr,length);
+ memcpy(ptr+2,from,length);
+ int2store(ptr, length);
+ return error;
}
-void Field_varstring::store(double nr)
+int Field_varstring::store(double nr)
{
char buff[MAX_FIELD_WIDTH],*end;
int width=min(field_length,DBL_DIG+5);
sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
end=strcend(buff,' ');
- Field_varstring::store(buff,(uint) (end - buff));
+ return Field_varstring::store(buff,(uint) (end - buff), &my_charset_bin);
}
-void Field_varstring::store(longlong nr)
+int Field_varstring::store(longlong nr)
{
- char buff[22];
- char *end=longlong10_to_str(nr,buff,-10);
- Field_varstring::store(buff,(uint) (end-buff));
+ char buff[64];
+ int l;
+ CHARSET_INFO *cs=charset();
+ l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr);
+ return Field_varstring::store(buff,(uint)l,cs);
}
double Field_varstring::val_real(void)
{
- double value;
+ int not_used;
uint length=uint2korr(ptr)+2;
- char save=ptr[length]; // Ok to patch record
- ptr[length]=0;
- value=atof(ptr+2);
- ptr[length]=save;
- return value;
+ CHARSET_INFO *cs=charset();
+ return my_strntod(cs,ptr+2,length,(char**)0, &not_used);
}
longlong Field_varstring::val_int(void)
{
- longlong value;
+ int not_used;
uint length=uint2korr(ptr)+2;
- char save=ptr[length]; // Ok to patch record
- ptr[length]=0;
- value=strtoll(ptr+2,NULL,10);
- ptr[length]=save;
- return value;
+ CHARSET_INFO *cs=charset();
+ return my_strntoll(cs,ptr+2,length,10,NULL, &not_used);
}
@@ -3881,7 +4155,7 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
uint length=uint2korr(ptr);
- val_ptr->set((const char*) ptr+2,length);
+ val_ptr->set((const char*) ptr+2,length,field_charset);
return val_ptr;
}
@@ -3891,37 +4165,18 @@ int Field_varstring::cmp(const char *a_ptr, const char *b_ptr)
uint a_length=uint2korr(a_ptr);
uint b_length=uint2korr(b_ptr);
int diff;
- if (binary_flag)
- diff=memcmp(a_ptr+2,b_ptr+2,min(a_length,b_length));
- else
- diff=my_sortcmp(a_ptr+2,b_ptr+2,min(a_length,b_length));
+ diff=my_strnncoll(field_charset,
+ (const uchar*)a_ptr+2,min(a_length,b_length),
+ (const uchar*)b_ptr+2,min(a_length,b_length));
return diff ? diff : (int) (a_length - b_length);
}
void Field_varstring::sort_string(char *to,uint length)
{
uint tot_length=uint2korr(ptr);
- if (binary_flag)
- memcpy((byte*) to,(byte*) ptr+2,(size_t) tot_length);
- else
- {
-#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
- tot_length=my_strnxfrm(default_charset_info,
- (unsigned char *) to, (unsigned char *)ptr+2,
- length, tot_length);
- else
- {
-#endif
- char *tmp=to;
- if (tot_length > length)
- tot_length=length;
- for (char *from=ptr+2,*end=from+tot_length ; from != end ;)
- *tmp++=(char) my_sort_order[(uint) (uchar) *from++];
-#ifdef USE_STRCOLL
- }
-#endif
- }
+ tot_length=my_strnxfrm(field_charset,
+ (unsigned char *) to, length,
+ (unsigned char *)ptr+2, tot_length);
if (tot_length < length)
bzero(to+tot_length,length-tot_length);
}
@@ -3929,10 +4184,11 @@ void Field_varstring::sort_string(char *to,uint length)
void Field_varstring::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"varchar(%d)",(int) field_length);
- res.length((uint) strlen(res.ptr()));
- if (binary_flag)
- res.append(" binary");
+ CHARSET_INFO *cs=res.charset();
+ ulong length= cs->cset->snprintf(cs,(char*) res.ptr(),
+ res.alloced_length(),"varchar(%u)",
+ field_length / charset()->mbmaxlen);
+ res.length(length);
}
char *Field_varstring::pack(char *to, const char *from, uint max_length)
@@ -3983,12 +4239,9 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
a_length= (uint) (uchar) *a++;
b_length= (uint) (uchar) *b++;
}
- if (binary_flag)
- {
- int cmp= memcmp(a,b,min(a_length,b_length));
- return cmp ? cmp : (int) (a_length - b_length);
- }
- return my_sortncmp(a,a_length, b,b_length);
+ return my_strnncoll(field_charset,
+ (const uchar *)a,a_length,
+ (const uchar *)b,b_length);
}
int Field_varstring::pack_cmp(const char *b, uint key_length)
@@ -4004,12 +4257,9 @@ int Field_varstring::pack_cmp(const char *b, uint key_length)
{
b_length= (uint) (uchar) *b++;
}
- if (binary_flag)
- {
- int cmp= memcmp(a,b,min(a_length,b_length));
- return cmp ? cmp : (int) (a_length - b_length);
- }
- return my_sortncmp(a,a_length, b,b_length);
+ return my_strnncoll(field_charset,
+ (const uchar *)a,a_length,
+ (const uchar *)b,b_length);
}
uint Field_varstring::packed_col_length(const char *data_ptr, uint length)
@@ -4025,6 +4275,29 @@ uint Field_varstring::max_packed_col_length(uint max_length)
return (max_length > 255 ? 2 : 1)+max_length;
}
+void Field_varstring::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
+ imagetype type)
+{
+ length-= HA_KEY_BLOB_LENGTH;
+ uint f_length=uint2korr(ptr);
+ if (f_length > length)
+ f_length= length;
+ int2store(buff,length);
+ memcpy(buff+2,ptr+2,length);
+#ifdef HAVE_purify
+ if (f_length < length)
+ bzero(buff+2+f_length, (length-f_length));
+#endif
+}
+
+void Field_varstring::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
+{
+ length=uint2korr(buff); // Real length is here
+ (void) Field_varstring::store(buff+2, length, cs);
+}
+
+
+
/****************************************************************************
** blob type
** A blob is saved as a length and a pointer. The length is stored in the
@@ -4034,15 +4307,13 @@ uint Field_varstring::max_packed_col_length(uint max_length)
Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint blob_pack_length,
- bool binary_arg)
+ CHARSET_INFO *cs)
: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)
+ table_arg, cs),
+ geom_flag(true), packlength(blob_pack_length)
{
flags|= BLOB_FLAG;
- if (binary_arg)
- flags|=BINARY_FLAG;
if (table)
table->blob_fields++;
}
@@ -4055,7 +4326,7 @@ void Field_blob::store_length(uint32 number)
if (number > 255)
{
number=255;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
}
ptr[0]= (uchar) number;
break;
@@ -4063,7 +4334,7 @@ void Field_blob::store_length(uint32 number)
if (number > (uint16) ~0)
{
number= (uint16) ~0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
}
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -4078,7 +4349,7 @@ void Field_blob::store_length(uint32 number)
if (number > (uint32) (1L << 24))
{
number= (uint32) (1L << 24)-1L;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
}
int3store(ptr,number);
break;
@@ -4129,89 +4400,76 @@ uint32 Field_blob::get_length(const char *pos)
}
-void Field_blob::store(const char *from,uint len)
+int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
{
- if (!len)
+ if (!length)
{
bzero(ptr,Field_blob::pack_length());
}
else
{
-#ifdef USE_TIS620
- char *th_ptr=0;
-#endif
- Field_blob::store_length(len);
- if (table->copy_blobs || len <= MAX_FIELD_WIDTH)
+ char buff[80];
+ String tmpstr(buff,sizeof(buff), &my_charset_bin);
+ /* Convert character set if nesessary */
+ if (use_conversion(cs, field_charset))
+ {
+ tmpstr.copy(from, length, cs, field_charset);
+ from= tmpstr.ptr();
+ length= tmpstr.length();
+ }
+ Field_blob::store_length(length);
+ if (table->copy_blobs || length <= MAX_FIELD_WIDTH)
{ // 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 */
if (from != value.ptr()) // For valgrind
{
- value.copy(from, len);
- from= value.ptr();
+ value.copy(from,length,charset());
+ from=value.ptr();
}
-#ifdef USE_TIS620
- my_free(th_ptr,MYF(MY_ALLOW_ZERO_PTR));
-#endif
}
bmove(ptr+packlength,(char*) &from,sizeof(char*));
}
+ return 0;
}
-void Field_blob::store(double nr)
+int Field_blob::store(double nr)
{
- value.set(nr);
- Field_blob::store(value.ptr(),(uint) value.length());
+ CHARSET_INFO *cs=charset();
+ value.set(nr, 2, cs);
+ return Field_blob::store(value.ptr(),(uint) value.length(), cs);
}
-void Field_blob::store(longlong nr)
+int Field_blob::store(longlong nr)
{
- value.set(nr);
- Field_blob::store(value.ptr(), (uint) value.length());
+ CHARSET_INFO *cs=charset();
+ value.set(nr, cs);
+ return Field_blob::store(value.ptr(), (uint) value.length(), cs);
}
double Field_blob::val_real(void)
{
+ int not_used;
char *blob;
-
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0.0;
uint32 length=get_length(ptr);
-
- char save=blob[length]; // Ok to patch blob in NISAM
- blob[length]=0;
- double nr=atof(blob);
- blob[length]=save;
- return nr;
+ CHARSET_INFO *cs=charset();
+ return my_strntod(cs,blob,length,(char**)0, &not_used);
}
longlong Field_blob::val_int(void)
{
+ int not_used;
char *blob;
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0;
uint32 length=get_length(ptr);
-
- char save=blob[length]; // Ok to patch blob in NISAM
- blob[length]=0;
- longlong nr=strtoll(blob,NULL,10);
- blob[length]=save;
- return nr;
+ return my_strntoll(charset(),blob,length,10,NULL,&not_used);
}
@@ -4221,9 +4479,9 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
char *blob;
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
- val_ptr->set("",0); // A bit safer than ->length(0)
+ val_ptr->set("",0,charset()); // A bit safer than ->length(0)
else
- val_ptr->set((const char*) blob,get_length(ptr));
+ val_ptr->set((const char*) blob,get_length(ptr),charset());
return val_ptr;
}
@@ -4231,11 +4489,9 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
int Field_blob::cmp(const char *a,uint32 a_length, const char *b,
uint32 b_length)
{
- int diff;
- if (binary_flag)
- diff=memcmp(a,b,min(a_length,b_length));
- else
- diff=my_sortcmp(a,b,min(a_length,b_length));
+ int diff=my_strnncoll(field_charset,
+ (const uchar*)a,min(a_length,b_length),
+ (const uchar*)b,min(a_length,b_length));
return diff ? diff : (int) (a_length - b_length);
}
@@ -4283,11 +4539,30 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
/* The following is used only when comparing a key */
-void Field_blob::get_key_image(char *buff,uint length)
+void Field_blob::get_key_image(char *buff,uint length,
+ CHARSET_INFO *cs, imagetype type)
{
- length-=HA_KEY_BLOB_LENGTH;
- uint32 blob_length=get_length(ptr);
+ length-= HA_KEY_BLOB_LENGTH;
+ uint32 blob_length= get_length(ptr);
char *blob;
+
+ if (type == itMBR)
+ {
+ if (!blob_length)
+ return;
+ get_ptr(&blob);
+
+ MBR mbr;
+ Geometry gobj;
+ gobj.create_from_wkb(blob + SRID_SIZE, blob_length - SRID_SIZE);
+ gobj.get_mbr(&mbr);
+ float8store(buff, mbr.xmin);
+ float8store(buff+8, mbr.xmax);
+ float8store(buff+16, mbr.ymin);
+ float8store(buff+24, mbr.ymax);
+ return;
+ }
+
if ((uint32) length > blob_length)
{
/*
@@ -4302,12 +4577,13 @@ void Field_blob::get_key_image(char *buff,uint length)
memcpy(buff+2,blob,length);
}
-void Field_blob::set_key_image(char *buff,uint length)
+void Field_blob::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
{
length=uint2korr(buff);
- Field_blob::store(buff+2,length);
+ (void) Field_blob::store(buff+2,length,cs);
}
+
int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
{
char *blob1;
@@ -4329,39 +4605,18 @@ 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_fixed(&blob,ptr+packlength,sizeof(char*));
- if (binary_flag)
- {
- memcpy(to,blob,blob_length);
- to+=blob_length;
- }
- else
- {
-#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
- {
- blob_length=my_strnxfrm(default_charset_info,
- (unsigned char *)to,(unsigned char *)blob,
- length,blob_org_length);
- if (blob_length >= length)
- return;
- to+=blob_length;
- }
- else
-#endif
- for (char *end=blob+blob_length ; blob != end ;)
- *to++=(char) my_sort_order[(uint) (uchar) *blob++];
- }
- bzero(to,length-blob_length);
+
+ blob_length=my_strnxfrm(field_charset,
+ (unsigned char *)to, length,
+ (unsigned char *)blob, blob_length);
+ if (blob_length < length)
+ bzero(to+blob_length, length-blob_length);
}
}
@@ -4369,14 +4624,20 @@ void Field_blob::sort_string(char *to,uint length)
void Field_blob::sql_type(String &res) const
{
const char *str;
+ uint length;
switch (packlength) {
- default: str="tiny"; break;
- case 2: str=""; break;
- case 3: str="medium"; break;
- case 4: str="long"; break;
+ default: str="tiny"; length=4; break;
+ case 2: str=""; length=0; break;
+ case 3: str="medium"; length= 6; break;
+ case 4: str="long"; length=4; break;
+ }
+ res.set_ascii(str,length);
+ if (charset() == &my_charset_bin)
+ res.append("blob");
+ else
+ {
+ res.append("text");
}
- res.set(str,(uint) strlen(str));
- res.append(binary_flag ? "blob" : "text");
}
@@ -4432,12 +4693,9 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
a_length= (uint) (uchar) *a++;
b_length= (uint) (uchar) *b++;
}
- if (binary_flag)
- {
- int cmp= memcmp(a,b,min(a_length,b_length));
- return cmp ? cmp : (int) (a_length - b_length);
- }
- return my_sortncmp(a,a_length, b,b_length);
+ return my_strnncoll(field_charset,
+ (const uchar *)a,a_length,
+ (const uchar *)b,b_length);
}
@@ -4458,12 +4716,9 @@ int Field_blob::pack_cmp(const char *b, uint key_length)
{
b_length= (uint) (uchar) *b++;
}
- if (binary_flag)
- {
- int cmp= memcmp(a,b,min(a_length,b_length));
- return cmp ? cmp : (int) (a_length - b_length);
- }
- return my_sortncmp(a,a_length, b,b_length);
+ return my_strnncoll(field_charset,
+ (const uchar *)a,a_length,
+ (const uchar *)b,b_length);
}
/* Create a packed key that will be used for storage from a MySQL row */
@@ -4516,6 +4771,90 @@ uint Field_blob::max_packed_col_length(uint max_length)
return (max_length > 255 ? 2 : 1)+max_length;
}
+
+void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
+ imagetype type)
+{
+ length-= HA_KEY_BLOB_LENGTH;
+ ulong blob_length= get_length(ptr);
+ char *blob;
+ get_ptr(&blob);
+
+ MBR mbr;
+ Geometry gobj;
+ gobj.create_from_wkb(blob + SRID_SIZE, blob_length - SRID_SIZE);
+ gobj.get_mbr(&mbr);
+ float8store(buff, mbr.xmin);
+ float8store(buff + 8, mbr.xmax);
+ float8store(buff + 16, mbr.ymin);
+ float8store(buff + 24, mbr.ymax);
+ return;
+}
+
+
+void Field_geom::set_key_image(char *buff, uint length, CHARSET_INFO *cs)
+{
+ Field_blob::set_key_image(buff, length, cs);
+}
+
+void Field_geom::sql_type(String &res) const
+{
+ CHARSET_INFO *cs= &my_charset_latin1;
+ switch (geom_type)
+ {
+ case GEOM_POINT:
+ res.set("point", 5, cs);
+ break;
+ case GEOM_LINESTRING:
+ res.set("linestring", 10, cs);
+ break;
+ case GEOM_POLYGON:
+ res.set("polygon", 7, cs);
+ break;
+ case GEOM_MULTIPOINT:
+ res.set("multipoint", 10, cs);
+ break;
+ case GEOM_MULTILINESTRING:
+ res.set("multilinestring", 15, cs);
+ break;
+ case GEOM_MULTIPOLYGON:
+ res.set("multipolygon", 12, cs);
+ break;
+ case GEOM_GEOMETRYCOLLECTION:
+ res.set("geometrycollection", 18, cs);
+ break;
+ default:
+ res.set("geometry", 8, cs);
+ }
+}
+
+
+int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
+{
+ if (!length)
+ {
+ bzero(ptr, Field_blob::pack_length());
+ }
+ else
+ {
+ // Should check given WKB
+ if (length < 4 + 1 + 4 + 8 + 8) // SRID + WKB_HEADER + X + Y
+ return 1;
+ uint32 wkb_type= uint4korr(from + 5);
+ if (wkb_type < 1 || wkb_type > 7)
+ return 1;
+ Field_blob::store_length(length);
+ if (table->copy_blobs || length <= MAX_FIELD_WIDTH)
+ { // Must make a copy
+ value.copy(from, length, cs);
+ from= value.ptr();
+ }
+ bmove(ptr + packlength, (char*) &from, sizeof(char*));
+ }
+ return 0;
+}
+
+
/****************************************************************************
** enum type.
** This is a string which only can have a selection of different values.
@@ -4574,14 +4913,16 @@ void Field_enum::store_type(ulonglong value)
uint find_enum(TYPELIB *lib,const char *x, uint length)
{
const char *end=x+length;
- while (end > x && isspace(end[-1]))
+ while (end > x && my_isspace(system_charset_info,end[-1]))
end--;
const char *i;
const char *j;
for (uint pos=0 ; (j=lib->type_names[pos]) ; pos++)
{
- for (i=x ; i != end && toupper(*i) == toupper(*j) ; i++, j++) ;
+ for (i=x ; i != end &&
+ my_toupper(system_charset_info,*i) ==
+ my_toupper(system_charset_info,*j) ; i++, j++) ;
if (i == end && ! *j)
return(pos+1);
}
@@ -4594,50 +4935,57 @@ uint find_enum(TYPELIB *lib,const char *x, uint length)
** (if there isn't a empty value in the enum)
*/
-void Field_enum::store(const char *from,uint length)
+int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ int err= 0;
+ char buff[80];
+ String tmpstr(buff,sizeof(buff), &my_charset_bin);
+ /* Convert character set if nesessary */
+ if (use_conversion(cs, field_charset))
+ {
+ tmpstr.copy(from, length, cs, field_charset);
+ from= tmpstr.ptr();
+ length= tmpstr.length();
+ }
uint tmp=find_enum(typelib,from,length);
if (!tmp)
{
if (length < 6) // Can't be more than 99999 enums
{
/* This is for reading numbers with LOAD DATA INFILE */
- char buff[7], *end;
- const char *conv=from;
- if (from[length])
- {
- strmake(buff, from, length);
- conv=buff;
- }
- my_errno=0;
- tmp=(uint) strtoul(conv,&end,10);
- if (my_errno || end != conv+length || tmp > typelib->count)
+ char *end;
+ tmp=(uint) my_strntoul(cs,from,length,10,&end,&err);
+ if (err || end != from+length || tmp > typelib->count)
{
tmp=0;
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
}
}
else
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
}
store_type((ulonglong) tmp);
+ return err;
}
-void Field_enum::store(double nr)
+int Field_enum::store(double nr)
{
- Field_enum::store((longlong) nr);
+ return Field_enum::store((longlong) nr);
}
-void Field_enum::store(longlong nr)
+int Field_enum::store(longlong nr)
{
+ int error= 0;
if ((uint) nr > typelib->count || nr == 0)
{
- current_thd->cuted_fields++;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
nr=0;
+ error=1;
}
store_type((ulonglong) (uint) nr);
+ return error;
}
@@ -4700,7 +5048,8 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
val_ptr->length(0);
else
val_ptr->set((const char*) typelib->type_names[tmp-1],
- (uint) strlen(typelib->type_names[tmp-1]));
+ (uint) strlen(typelib->type_names[tmp-1]),
+ field_charset);
return val_ptr;
}
@@ -4737,89 +5086,117 @@ void Field_enum::sql_type(String &res) const
{
if (flag)
res.append(',');
- res.append('\'');
- append_unescaped(&res,*pos);
- res.append('\'');
+ append_unescaped(&res, *pos, strlen(*pos));
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.
-****************************************************************************/
+/*
+ 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.
+
+ If there was a value in string that wasn't in set, the 'err_pos' points to
+ the last invalid value found. 'err_len' will be set to length of the
+ error string.
+*/
-ulonglong find_set(TYPELIB *lib,const char *x,uint length)
+ulonglong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos,
+ uint *err_len, bool *set_warning)
{
- const char *end=x+length;
- while (end > x && isspace(end[-1]))
+ const char *end= x + length;
+ *err_pos= 0; // No error yet
+ while (end > x && my_isspace(system_charset_info, end[-1]))
end--;
- ulonglong found=0;
+ *err_len= 0;
+ ulonglong found= 0;
if (x != end)
{
- const char *start=x;
- bool error=0;
+ const char *start= x;
for (;;)
{
- const char *pos=start;
- for (; pos != end && *pos != field_separator ; pos++) ;
- uint find=find_enum(lib,start,(uint) (pos-start));
+ const char *pos= start;
+ uint var_len;
+
+ for (; pos != end && *pos != field_separator; pos++) ;
+ var_len= (uint) (pos - start);
+ uint find= find_enum(lib, start, var_len);
if (!find)
- error=1;
+ {
+ *err_pos= (char*) start;
+ *err_len= var_len;
+ *set_warning= 1;
+ }
else
- found|= ((longlong) 1 << (find-1));
+ found|= ((longlong) 1 << (find - 1));
if (pos == end)
- break;
- start=pos+1;
+ break;
+ start= pos + 1;
}
- if (error)
- current_thd->cuted_fields++;
}
return found;
}
-void Field_set::store(const char *from,uint length)
+int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
{
- ulonglong tmp=find_set(typelib,from,length);
+ bool set_warning= 0;
+ int err= 0;
+ char *not_used;
+ uint not_used2;
+ char buff[80];
+ String tmpstr(buff,sizeof(buff), &my_charset_bin);
+ /* Convert character set if nesessary */
+ if (use_conversion(cs, field_charset))
+ {
+ tmpstr.copy(from, length, cs, field_charset);
+ from= tmpstr.ptr();
+ length= tmpstr.length();
+ }
+ ulonglong tmp= find_set(typelib, from, length, &not_used, &not_used2,
+ &set_warning);
if (!tmp && length && length < 22)
{
/* This is for reading numbers with LOAD DATA INFILE */
- char buff[22], *end;
- const char *conv=from;
- if (from[length])
+ char *end;
+ tmp=my_strntoull(cs,from,length,10,&end,&err);
+ if (err || end != from+length ||
+ tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1))
{
- strmake(buff, from, length);
- conv=buff;
+ tmp=0;
+ THD *thd= current_thd;
+ if (thd->count_cuted_fields)
+ {
+ thd->cuted_fields++;
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED),
+ field_name, 0);
+ }
}
- my_errno=0;
- tmp=strtoull(conv,&end,10);
- if (my_errno || end != conv+length ||
- tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1))
- tmp=0;
- else
- current_thd->cuted_fields--; // Remove warning from find_set
}
store_type(tmp);
+ return err;
}
-void Field_set::store(longlong nr)
+int Field_set::store(longlong nr)
{
+ int error= 0;
if ((ulonglong) nr > (ulonglong) (((longlong) 1 << typelib->count) -
(longlong) 1))
{
- nr&= (longlong) (((longlong) 1 << typelib->count) - (longlong) 1);
- current_thd->cuted_fields++;
+ nr&= (longlong) (((longlong) 1 << typelib->count) - (longlong) 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ error=1;
}
store_type((ulonglong) nr);
+ return error;
}
@@ -4837,7 +5214,8 @@ String *Field_set::val_str(String *val_buffer,
if (val_buffer->length())
val_buffer->append(field_separator);
String str(typelib->type_names[bitnr],
- (uint) strlen(typelib->type_names[bitnr]));
+ (uint) strlen(typelib->type_names[bitnr]),
+ field_charset);
val_buffer->append(str);
}
tmp>>=1;
@@ -4857,9 +5235,7 @@ void Field_set::sql_type(String &res) const
{
if (flag)
res.append(',');
- res.append('\'');
- append_unescaped(&res,*pos);
- res.append('\'');
+ append_unescaped(&res, *pos, strlen(*pos));
flag=1;
}
res.append(')');
@@ -4869,7 +5245,7 @@ void Field_set::sql_type(String &res) const
bool Field::eq_def(Field *field)
{
- if (real_type() != field->real_type() || binary() != field->binary() ||
+ if (real_type() != field->real_type() || charset() != field->charset() ||
pack_length() != field->pack_length())
return 0;
return 1;
@@ -4884,7 +5260,8 @@ bool Field_enum::eq_def(Field *field)
if (typelib->count < from_lib->count)
return 0;
for (uint i=0 ; i < from_lib->count ; i++)
- if (my_strcasecmp(typelib->type_names[i],from_lib->type_names[i]))
+ if (my_strcasecmp(field_charset,
+ typelib->type_names[i],from_lib->type_names[i]))
return 0;
return 1;
}
@@ -4907,6 +5284,26 @@ bool Field_num::eq_def(Field *field)
** Handling of field and create_field
*****************************************************************************/
+void create_field::create_length_to_internal_length(void)
+{
+ switch (sql_type)
+ {
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ length*= charset->mbmaxlen;
+ pack_length= calc_pack_length(sql_type == FIELD_TYPE_VAR_STRING ?
+ FIELD_TYPE_STRING : sql_type, length);
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+}
+
/*
Make a field from the .frm file info
*/
@@ -4935,6 +5332,7 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
case FIELD_TYPE_BLOB: return 2+portable_sizeof_char_ptr;
case FIELD_TYPE_MEDIUM_BLOB: return 3+portable_sizeof_char_ptr;
case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr;
+ case FIELD_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr;
case FIELD_TYPE_SET:
case FIELD_TYPE_ENUM: abort(); return 0; // This shouldn't happen
default: return 0;
@@ -4960,6 +5358,8 @@ Field *make_field(char *ptr, uint32 field_length,
uchar *null_pos, uchar null_bit,
uint pack_flag,
enum_field_types field_type,
+ CHARSET_INFO *field_charset,
+ Field::geometry_type geom_type,
Field::utype unireg_check,
TYPELIB *interval,
const char *field_name,
@@ -4974,30 +5374,30 @@ Field *make_field(char *ptr, uint32 field_length,
{
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);
+ unireg_check, field_name, table, field_charset);
uint pack_length=calc_pack_length((enum_field_types)
f_packtype(pack_flag),
field_length);
+ if (f_is_geom(pack_flag))
+ return new Field_geom(ptr,null_pos,null_bit,
+ unireg_check, field_name, table,
+ pack_length, geom_type);
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 (f_is_geom(pack_flag))
- return 0;
-
+ pack_length, field_charset);
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);
+ pack_length, interval, field_charset);
else
return new Field_set(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
- pack_length, interval);
+ pack_length, interval, field_charset);
}
}
@@ -5047,28 +5447,28 @@ Field *make_field(char *ptr, uint32 field_length,
f_is_dec(pack_flag) == 0);
case FIELD_TYPE_TIMESTAMP:
return new Field_timestamp(ptr,field_length,
- unireg_check, field_name, table);
+ unireg_check, field_name, table, field_charset);
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);
+ unireg_check, field_name, table, field_charset);
case FIELD_TYPE_NEWDATE:
return new Field_newdate(ptr,null_pos,null_bit,
- unireg_check, field_name, table);
+ unireg_check, field_name, table, field_charset);
case FIELD_TYPE_TIME:
return new Field_time(ptr,null_pos,null_bit,
- unireg_check, field_name, table);
+ unireg_check, field_name, table, field_charset);
case FIELD_TYPE_DATETIME:
return new Field_datetime(ptr,null_pos,null_bit,
- unireg_check, field_name, table);
+ unireg_check, field_name, table, field_charset);
case FIELD_TYPE_NULL:
- return new Field_null(ptr,field_length,unireg_check,field_name,table);
+ return new Field_null(ptr,field_length,unireg_check,field_name,table, field_charset);
default: // Impossible (Wrong version)
break;
}
- return 0; // Impossible
+ return 0;
}
@@ -5083,6 +5483,8 @@ create_field::create_field(Field *old_field,Field *orig_field)
unireg_check=old_field->unireg_check;
pack_length=old_field->pack_length();
sql_type= old_field->real_type();
+ charset= old_field->charset(); // May be NULL ptr
+ comment= old_field->comment;
/* Fix if the original table had 4 byte pointer blobs */
if (flags & BLOB_FLAG)
@@ -5091,6 +5493,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
decimals= old_field->decimals();
if (sql_type == FIELD_TYPE_STRING)
{
+ /* Change CHAR -> VARCHAR if dynamic record length */
sql_type=old_field->type();
decimals=0;
}
@@ -5104,11 +5507,11 @@ create_field::create_field(Field *old_field,Field *orig_field)
orig_field)
{
char buff[MAX_FIELD_WIDTH],*pos;
- String tmp(buff,sizeof(buff));
+ String tmp(buff,sizeof(buff), charset);
- /* Get the value from record[2] (the default value row) */
+ /* Get the value from default_values */
my_ptrdiff_t diff= (my_ptrdiff_t) (orig_field->table->rec_buff_length*2);
- orig_field->move_field(diff); // Points now at record[2]
+ orig_field->move_field(diff); // Points now at default_values
bool is_null=orig_field->is_real_null();
orig_field->val_str(&tmp,&tmp);
orig_field->move_field(-diff); // Back to record[0]
@@ -5116,7 +5519,24 @@ create_field::create_field(Field *old_field,Field *orig_field)
{
pos= (char*) sql_memdup(tmp.ptr(),tmp.length()+1);
pos[tmp.length()]=0;
- def=new Item_string(pos,tmp.length());
+ def=new Item_string(pos,tmp.length(), charset);
}
}
+ if (sql_type == FIELD_TYPE_GEOMETRY)
+ {
+ geom_type= ((Field_geom*)old_field)->geom_type;
+ }
+}
+
+
+/* Warning handling */
+void Field::set_warning(const uint level, const uint code)
+{
+ THD *thd= current_thd;
+ if (thd->count_cuted_fields)
+ {
+ thd->cuted_fields++;
+ push_warning_printf(thd, (MYSQL_ERROR::enum_warning_level) level,
+ code, ER(code), field_name, thd->row_count);
+ }
}