diff options
Diffstat (limited to 'sql/field.cc')
-rw-r--r-- | sql/field.cc | 2148 |
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, ¬_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, + ¬_used); else - nr=strtoll(ptr,NULL,10); - *(ptr+field_length)=temp; - return(nr); + return my_strntoll(&my_charset_bin, ptr, field_length, 10, NULL, + ¬_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, ¬_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, ¬_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, ¬_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,<ime)) + { 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, ¬_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,¬_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,¬_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, ¬_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, ¬_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, ¬_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,¬_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, ¬_used, ¬_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); + } } |