field.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:179k
- double a,b;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- float8get(a,a_ptr);
- float8get(b,b_ptr);
- }
- else
- #endif
- {
- doubleget(a, a_ptr);
- doubleget(b, b_ptr);
- }
- return (a < b) ? -1 : (a > b) ? 1 : 0;
- }
- #define DBL_EXP_DIG (sizeof(double)*8-DBL_MANT_DIG)
- /* The following should work for IEEE */
- void Field_double::sort_string(char *to,uint length __attribute__((unused)))
- {
- double nr;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- float8get(nr,ptr);
- }
- else
- #endif
- doubleget(nr,ptr);
- change_double_for_sort(nr, (byte*) to);
- }
- void Field_double::sql_type(String &res) const
- {
- CHARSET_INFO *cs=res.charset();
- if (dec == NOT_FIXED_DEC)
- {
- res.set_ascii("double",6);
- }
- else
- {
- res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
- "double(%d,%d)",(int) field_length,dec));
- }
- add_zerofill_and_unsigned(res);
- }
- /*
- TIMESTAMP type.
- Holds datetime values in range from 1970-01-01 00:00:01 UTC to
- 2038-01-01 00:00:00 UTC stored as number of seconds since Unix
- Epoch in UTC.
-
- Up to one of timestamps columns in the table can be automatically
- set on row update and/or have NOW() as default value.
- TABLE::timestamp_field points to Field object for such timestamp with
- auto-set-on-update. TABLE::time_stamp holds offset in record + 1 for this
- field, and is used by handler code which performs updates required.
-
- Actually SQL-99 says that we should allow niladic functions (like NOW())
- as defaults for any field. Current limitations (only NOW() and only
- for one TIMESTAMP field) are because of restricted binary .frm format
- and should go away in the future.
-
- Also because of this limitation of binary .frm format we use 5 different
- unireg_check values with TIMESTAMP field to distinguish various cases of
- DEFAULT or ON UPDATE values. These values are:
-
- TIMESTAMP_OLD_FIELD - old timestamp, if there was not any fields with
- auto-set-on-update (or now() as default) in this table before, then this
- field has NOW() as default and is updated when row changes, else it is
- field which has 0 as default value and is not automaitcally updated.
- TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
- automatically (TIMESTAMP DEFAULT NOW())
- TIMESTAMP_UN_FIELD - field which is set on update automatically but has not
- NOW() as default (but it may has 0 or some other const timestamp as
- default) (TIMESTAMP ON UPDATE NOW()).
- TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
- update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW())
- NONE - field which is not auto-set on update with some other than NOW()
- default value (TIMESTAMP DEFAULT 0).
- Note that TIMESTAMP_OLD_FIELD's are never created explicitly now, they are
- left only for preserving ability to read old tables. Such fields replaced
- with their newer analogs in CREATE TABLE and in SHOW CREATE TABLE. This is
- because we want to prefer NONE unireg_check before TIMESTAMP_OLD_FIELD for
- "TIMESTAMP DEFAULT 'Const'" field. (Old timestamps allowed such
- specification too but ignored default value for first timestamp, which of
- course is non-standard.) In most cases user won't notice any change, only
- exception is different behavior of old/new timestamps during ALTER TABLE.
- */
- Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
- uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg,
- const char *field_name_arg,
- struct st_table *table_arg,
- CHARSET_INFO *cs)
- :Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg, cs)
- {
- /* For 4.0 MYD and 4.0 InnoDB compatibility */
- flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
- if (table && !table->timestamp_field &&
- unireg_check != NONE)
- {
- /* This timestamp has auto-update */
- table->timestamp_field= this;
- flags|=TIMESTAMP_FLAG;
- }
- }
- /*
- Get auto-set type for TIMESTAMP field.
- SYNOPSIS
- get_auto_set_type()
- DESCRIPTION
- Returns value indicating during which operations this TIMESTAMP field
- should be auto-set to current timestamp.
- */
- timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
- {
- switch (unireg_check)
- {
- case TIMESTAMP_DN_FIELD:
- return TIMESTAMP_AUTO_SET_ON_INSERT;
- case TIMESTAMP_UN_FIELD:
- return TIMESTAMP_AUTO_SET_ON_UPDATE;
- case TIMESTAMP_OLD_FIELD:
- /*
- Altough we can have several such columns in legacy tables this
- function should be called only for first of them (i.e. the one
- having auto-set property).
- */
- DBUG_ASSERT(table->timestamp_field == this);
- /* Fall-through */
- case TIMESTAMP_DNUN_FIELD:
- return TIMESTAMP_AUTO_SET_ON_BOTH;
- default:
- /*
- Normally this function should not be called for TIMESTAMPs without
- auto-set property.
- */
- DBUG_ASSERT(0);
- return TIMESTAMP_NO_AUTO_SET;
- }
- }
- int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
- {
- TIME l_time;
- my_time_t tmp= 0;
- int error;
- bool have_smth_to_conv;
- bool in_dst_time_gap;
- THD *thd= table->in_use;
- have_smth_to_conv= (str_to_datetime(from, len, &l_time, 0, &error) >
- MYSQL_TIMESTAMP_ERROR);
-
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
- from, len, MYSQL_TIMESTAMP_DATETIME, 1);
- if (have_smth_to_conv)
- {
- if (!(tmp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- from, len, MYSQL_TIMESTAMP_DATETIME, !error);
-
- error= 1;
- }
- else if (in_dst_time_gap)
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_INVALID_TIMESTAMP,
- from, len, MYSQL_TIMESTAMP_DATETIME, !error);
- error= 1;
- }
- }
- if (error > 1)
- error= 2;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int4store(ptr,tmp);
- }
- else
- #endif
- longstore(ptr,tmp);
- return error;
- }
- int Field_timestamp::store(double nr)
- {
- int error= 0;
- if (nr < 0 || nr > 99991231235959.0)
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- nr, MYSQL_TIMESTAMP_DATETIME);
- nr= 0; // Avoid overflow on buff
- error= 1;
- }
- error|= Field_timestamp::store((longlong) rint(nr));
- return error;
- }
- int Field_timestamp::store(longlong nr)
- {
- TIME l_time;
- my_time_t timestamp= 0;
- int error;
- bool in_dst_time_gap;
- THD *thd= table->in_use;
- if (number_to_TIME(nr, &l_time, 0, &error))
- {
- if (!(timestamp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- nr, MYSQL_TIMESTAMP_DATETIME, 1);
- error= 1;
- }
-
- if (in_dst_time_gap)
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_INVALID_TIMESTAMP,
- nr, MYSQL_TIMESTAMP_DATETIME, !error);
- error= 1;
- }
- }
- else if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED,
- nr, MYSQL_TIMESTAMP_DATETIME, 1);
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int4store(ptr,timestamp);
- }
- else
- #endif
- longstore(ptr,(uint32) timestamp);
-
- return error;
- }
- double Field_timestamp::val_real(void)
- {
- return (double) Field_timestamp::val_int();
- }
- longlong Field_timestamp::val_int(void)
- {
- uint32 temp;
- TIME time_tmp;
- THD *thd= table->in_use;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- temp=uint4korr(ptr);
- else
- #endif
- longget(temp,ptr);
- if (temp == 0L) // No time
- return(0); /* purecov: inspected */
-
- thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t)temp);
- thd->time_zone_used= 1;
-
- return time_tmp.year * LL(10000000000) + time_tmp.month * LL(100000000) +
- time_tmp.day * 1000000L + time_tmp.hour * 10000L +
- time_tmp.minute * 100 + time_tmp.second;
- }
- String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
- {
- uint32 temp, temp2;
- TIME time_tmp;
- THD *thd= table->in_use;
- char *to;
- val_buffer->alloc(field_length+1);
- to= (char*) val_buffer->ptr();
- val_buffer->length(field_length);
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- temp=uint4korr(ptr);
- else
- #endif
- longget(temp,ptr);
- if (temp == 0L)
- { /* Zero time is "000000" */
- val_ptr->set("0000-00-00 00:00:00", 19, &my_charset_bin);
- return val_ptr;
- }
- val_buffer->set_charset(&my_charset_bin); // Safety
-
- thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,(my_time_t)temp);
- thd->time_zone_used= 1;
- temp= time_tmp.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=time_tmp.month;
- temp2=temp/10; temp=temp-temp2*10;
- *to++= (char) ('0'+(char) (temp2));
- *to++= (char) ('0'+(char) (temp));
- *to++= '-';
- temp=time_tmp.day;
- temp2=temp/10; temp=temp-temp2*10;
- *to++= (char) ('0'+(char) (temp2));
- *to++= (char) ('0'+(char) (temp));
- *to++= ' ';
- temp=time_tmp.hour;
- temp2=temp/10; temp=temp-temp2*10;
- *to++= (char) ('0'+(char) (temp2));
- *to++= (char) ('0'+(char) (temp));
- *to++= ':';
- temp=time_tmp.minute;
- temp2=temp/10; temp=temp-temp2*10;
- *to++= (char) ('0'+(char) (temp2));
- *to++= (char) ('0'+(char) (temp));
- *to++= ':';
- temp=time_tmp.second;
- 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, uint fuzzydate)
- {
- long temp;
- THD *thd= table->in_use;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- temp=uint4korr(ptr);
- else
- #endif
- longget(temp,ptr);
- if (temp == 0L)
- { /* Zero time is "000000" */
- if (!fuzzydate)
- return 1;
- bzero((char*) ltime,sizeof(*ltime));
- }
- else
- {
- thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)temp);
- thd->time_zone_used= 1;
- }
- return 0;
- }
- 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, TIME_FUZZY_DATE);
- return protocol->store(&tm);
- }
- int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
- {
- int32 a,b;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- a=sint4korr(a_ptr);
- b=sint4korr(b_ptr);
- }
- else
- #endif
- {
- longget(a,a_ptr);
- longget(b,b_ptr);
- }
- return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
- }
- void Field_timestamp::sort_string(char *to,uint length __attribute__((unused)))
- {
- #ifdef WORDS_BIGENDIAN
- if (!table->db_low_byte_first)
- {
- to[0] = ptr[0];
- to[1] = ptr[1];
- to[2] = ptr[2];
- to[3] = ptr[3];
- }
- else
- #endif
- {
- to[0] = ptr[3];
- to[1] = ptr[2];
- to[2] = ptr[1];
- to[3] = ptr[0];
- }
- }
- void Field_timestamp::sql_type(String &res) const
- {
- res.set_ascii("timestamp", 9);
- }
- void Field_timestamp::set_time()
- {
- long tmp= (long) table->in_use->query_start();
- set_notnull();
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int4store(ptr,tmp);
- }
- else
- #endif
- longstore(ptr,tmp);
- }
- /****************************************************************************
- ** time type
- ** In string context: HH:MM:SS
- ** In number context: HHMMSS
- ** Stored as a 3 byte unsigned int
- ****************************************************************************/
- int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
- {
- TIME ltime;
- long tmp;
- int error;
- if (str_to_time(from, len, <ime, &error))
- {
- tmp=0L;
- error= 2;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
- from, len, MYSQL_TIMESTAMP_TIME, 1);
- }
- else
- {
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED,
- from, len, MYSQL_TIMESTAMP_TIME, 1);
- if (ltime.month)
- ltime.day=0;
- tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second);
- if (tmp > 8385959)
- {
- tmp=8385959;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- from, len, MYSQL_TIMESTAMP_TIME, !error);
- error= 1;
- }
- if (error > 1)
- error= 2;
- }
-
- if (ltime.neg)
- tmp= -tmp;
- error |= Field_time::store((longlong) tmp);
- return error;
- }
- int Field_time::store(double nr)
- {
- long tmp;
- int error= 0;
- if (nr > 8385959.0)
- {
- tmp=8385959L;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME);
- error= 1;
- }
- else if (nr < -8385959.0)
- {
- tmp= -8385959L;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME);
- error= 1;
- }
- else
- {
- tmp=(long) floor(fabs(nr)); // Remove fractions
- if (nr < 0)
- tmp= -tmp;
- if (tmp % 100 > 59 || tmp/100 % 100 > 59)
- {
- tmp=0;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_TIME);
- error= 1;
- }
- }
- int3store(ptr,tmp);
- return error;
- }
- int Field_time::store(longlong nr)
- {
- long tmp;
- int error= 0;
- if (nr > (longlong) 8385959L)
- {
- tmp=8385959L;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_TIME, 1);
- error= 1;
- }
- else if (nr < (longlong) -8385959L)
- {
- tmp= -8385959L;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_TIME, 1);
- error= 1;
- }
- else
- {
- tmp=(long) nr;
- if (tmp % 100 > 59 || tmp/100 % 100 > 59)
- {
- tmp=0;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_TIME, 1);
- error= 1;
- }
- }
- int3store(ptr,tmp);
- return error;
- }
- double Field_time::val_real(void)
- {
- uint32 j= (uint32) uint3korr(ptr);
- return (double) j;
- }
- 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)))
- {
- TIME ltime;
- val_buffer->alloc(19);
- long tmp=(long) sint3korr(ptr);
- ltime.neg= 0;
- if (tmp < 0)
- {
- tmp= -tmp;
- ltime.neg= 1;
- }
- ltime.day= (uint) 0;
- ltime.hour= (uint) (tmp/10000);
- ltime.minute= (uint) (tmp/100 % 100);
- ltime.second= (uint) (tmp % 100);
- make_time((DATE_TIME_FORMAT*) 0, <ime, val_buffer);
- return val_buffer;
- }
- /*
- Normally we would not consider 'time' as a vaild date, but we allow
- get_date() here to be able to do things like
- DATE_FORMAT(time, "%l.%i %p")
- */
-
- bool Field_time::get_date(TIME *ltime, uint fuzzydate)
- {
- long tmp;
- if (!fuzzydate)
- {
- push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- ER(ER_WARN_DATA_OUT_OF_RANGE), field_name,
- table->in_use->row_count);
- return 1;
- }
- tmp=(long) sint3korr(ptr);
- ltime->neg=0;
- if (tmp < 0)
- {
- ltime->neg= 1;
- tmp=-tmp;
- }
- ltime->hour=tmp/10000;
- tmp-=ltime->hour*10000;
- ltime->minute= tmp/100;
- ltime->second= tmp % 100;
- ltime->year= ltime->month= ltime->day= ltime->second_part= 0;
- return 0;
- }
- bool Field_time::get_time(TIME *ltime)
- {
- long tmp=(long) sint3korr(ptr);
- ltime->neg=0;
- if (tmp < 0)
- {
- 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= MYSQL_TIMESTAMP_TIME;
- return 0;
- }
- bool Field_time::send_binary(Protocol *protocol)
- {
- TIME tm;
- Field_time::get_time(&tm);
- tm.day= tm.hour/24; // Move hours to days
- tm.hour-= tm.day*24;
- return protocol->store_time(&tm);
- }
- int Field_time::cmp(const char *a_ptr, const char *b_ptr)
- {
- int32 a,b;
- a=(int32) sint3korr(a_ptr);
- b=(int32) sint3korr(b_ptr);
- return (a < b) ? -1 : (a > b) ? 1 : 0;
- }
- void Field_time::sort_string(char *to,uint length __attribute__((unused)))
- {
- to[0] = (uchar) (ptr[2] ^ 128);
- to[1] = ptr[1];
- to[2] = ptr[0];
- }
- void Field_time::sql_type(String &res) const
- {
- res.set_ascii("time", 4);
- }
- /****************************************************************************
- ** year type
- ** Save in a byte the year 0, 1901->2155
- ** Can handle 2 byte or 4 byte years!
- ****************************************************************************/
- int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
- {
- int err;
- char *end;
- long nr= my_strntol(cs, from, len, 10, &end, &err);
- if (err)
- {
- if (table->in_use->count_cuted_fields)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- *ptr= 0;
- return 0;
- }
- if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
- {
- *ptr=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- return 1;
- }
- if (table->in_use->count_cuted_fields && !test_if_int(from,len,end,cs))
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- if (nr != 0 || len != 4)
- {
- if (nr < YY_PART_YEAR)
- nr+=100; // 2000 - 2069
- else if (nr > 1900)
- nr-= 1900;
- }
- *ptr= (char) (unsigned char) nr;
- return 0;
- }
- int Field_year::store(double nr)
- {
- if (nr < 0.0 || nr >= 2155.0)
- {
- (void) Field_year::store((longlong) -1);
- return 1;
- }
- else
- return Field_year::store((longlong) nr);
- }
- int Field_year::store(longlong nr)
- {
- if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
- {
- *ptr=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- return 1;
- }
- if (nr != 0 || field_length != 4) // 0000 -> 0; 00 -> 2000
- {
- if (nr < YY_PART_YEAR)
- nr+=100; // 2000 - 2069
- else if (nr > 1900)
- 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)
- {
- return (double) Field_year::val_int();
- }
- longlong Field_year::val_int(void)
- {
- int tmp= (int) ((uchar*) ptr)[0];
- if (field_length != 4)
- tmp%=100; // Return last 2 char
- else if (tmp)
- tmp+=1900;
- return (longlong) tmp;
- }
- String *Field_year::val_str(String *val_buffer,
- String *val_ptr __attribute__((unused)))
- {
- val_buffer->alloc(5);
- val_buffer->length(field_length);
- char *to=(char*) val_buffer->ptr();
- sprintf(to,field_length == 2 ? "%02d" : "%04d",(int) Field_year::val_int());
- return val_buffer;
- }
- void Field_year::sql_type(String &res) const
- {
- CHARSET_INFO *cs=res.charset();
- res.length(cs->cset->snprintf(cs,(char*)res.ptr(),res.alloced_length(),
- "year(%d)",(int) field_length));
- }
- /****************************************************************************
- ** date type
- ** In string context: YYYY-MM-DD
- ** In number context: YYYYMMDD
- ** Stored as a 4 byte unsigned int
- ****************************************************************************/
- int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
- {
- TIME l_time;
- uint32 tmp;
- int error;
-
- if (str_to_datetime(from, len, &l_time, 1, &error) <= MYSQL_TIMESTAMP_ERROR)
- {
- tmp=0;
- error= 2;
- }
- else
- tmp=(uint32) l_time.year*10000L + (uint32) (l_time.month*100+l_time.day);
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
- from, len, MYSQL_TIMESTAMP_DATE, 1);
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int4store(ptr,tmp);
- }
- else
- #endif
- longstore(ptr,tmp);
- return error;
- }
- 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;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- nr, MYSQL_TIMESTAMP_DATE);
- error= 1;
- }
- else
- tmp=(long) rint(nr);
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int4store(ptr,tmp);
- }
- else
- #endif
- longstore(ptr,tmp);
- return error;
- }
- 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;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- nr, MYSQL_TIMESTAMP_DATE, 0);
- error= 1;
- }
- else
- tmp=(long) nr;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int4store(ptr,tmp);
- }
- 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);
- }
- double Field_date::val_real(void)
- {
- int32 j;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- j=sint4korr(ptr);
- else
- #endif
- longget(j,ptr);
- return (double) (uint32) j;
- }
- longlong Field_date::val_int(void)
- {
- int32 j;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- j=sint4korr(ptr);
- else
- #endif
- longget(j,ptr);
- return (longlong) (uint32) j;
- }
- String *Field_date::val_str(String *val_buffer,
- String *val_ptr __attribute__((unused)))
- {
- TIME ltime;
- val_buffer->alloc(field_length);
- int32 tmp;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- tmp=sint4korr(ptr);
- else
- #endif
- longget(tmp,ptr);
- ltime.neg= 0;
- ltime.year= (int) ((uint32) tmp/10000L % 10000);
- ltime.month= (int) ((uint32) tmp/100 % 100);
- ltime.day= (int) ((uint32) tmp % 100);
- make_date((DATE_TIME_FORMAT *) 0, <ime, val_buffer);
- return val_buffer;
- }
- int Field_date::cmp(const char *a_ptr, const char *b_ptr)
- {
- int32 a,b;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- a=sint4korr(a_ptr);
- b=sint4korr(b_ptr);
- }
- else
- #endif
- {
- longget(a,a_ptr);
- longget(b,b_ptr);
- }
- return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
- }
- void Field_date::sort_string(char *to,uint length __attribute__((unused)))
- {
- #ifdef WORDS_BIGENDIAN
- if (!table->db_low_byte_first)
- {
- to[0] = ptr[0];
- to[1] = ptr[1];
- to[2] = ptr[2];
- to[3] = ptr[3];
- }
- else
- #endif
- {
- to[0] = ptr[3];
- to[1] = ptr[2];
- to[2] = ptr[1];
- to[3] = ptr[0];
- }
- }
- void Field_date::sql_type(String &res) const
- {
- res.set_ascii("date", 4);
- }
- /****************************************************************************
- ** The new date type
- ** This is identical to the old date type, but stored on 3 bytes instead of 4
- ** In number context: YYYYMMDD
- ****************************************************************************/
- int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
- {
- TIME l_time;
- long tmp;
- int error;
- if (str_to_datetime(from, len, &l_time, 1, &error) <= MYSQL_TIMESTAMP_ERROR)
- {
- tmp=0L;
- error= 2;
- }
- else
- tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
- from, len, MYSQL_TIMESTAMP_DATE, 1);
-
- int3store(ptr,tmp);
- return error;
- }
- int Field_newdate::store(double nr)
- {
- if (nr < 0.0 || nr > 99991231235959.0)
- {
- (void) Field_newdate::store((longlong) -1);
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATE);
- return 1;
- }
- else
- return Field_newdate::store((longlong) rint(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;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_DATE, 1);
- error= 1;
- }
- else
- {
- tmp=(int32) nr;
- if (tmp)
- {
- if (tmp < YY_PART_YEAR*10000L) // Fix short dates
- tmp+= (uint32) 20000000L;
- else if (tmp < 999999L)
- tmp+= (uint32) 19000000L;
- }
- uint month= (uint) ((tmp/100) % 100);
- uint day= (uint) (tmp%100);
- if (month > 12 || day > 31)
- {
- tmp=0L; // Don't allow date to change
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_DATE, 1);
- 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)
- {
- long tmp;
- if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME)
- tmp=ltime->year*16*32+ltime->month*32+ltime->day;
- else
- {
- tmp=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- }
- 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)
- {
- return (double) Field_newdate::val_int();
- }
- longlong Field_newdate::val_int(void)
- {
- ulong j= uint3korr(ptr);
- j= (j % 32L)+(j / 32L % 16L)*100L + (j/(16L*32L))*10000L;
- return (longlong) j;
- }
- String *Field_newdate::val_str(String *val_buffer,
- String *val_ptr __attribute__((unused)))
- {
- val_buffer->alloc(field_length);
- val_buffer->length(field_length);
- uint32 tmp=(uint32) uint3korr(ptr);
- int part;
- char *pos=(char*) val_buffer->ptr()+10;
- /* Open coded to get more speed */
- *pos--=0; // End NULL
- part=(int) (tmp & 31);
- *pos--= (char) ('0'+part%10);
- *pos--= (char) ('0'+part/10);
- *pos--= '-';
- part=(int) (tmp >> 5 & 15);
- *pos--= (char) ('0'+part%10);
- *pos--= (char) ('0'+part/10);
- *pos--= '-';
- part=(int) (tmp >> 9);
- *pos--= (char) ('0'+part%10); part/=10;
- *pos--= (char) ('0'+part%10); part/=10;
- *pos--= (char) ('0'+part%10); part/=10;
- *pos= (char) ('0'+part);
- return val_buffer;
- }
- bool Field_newdate::get_date(TIME *ltime,uint fuzzydate)
- {
- if (is_null())
- return 1;
- uint32 tmp=(uint32) uint3korr(ptr);
- ltime->day= tmp & 31;
- ltime->month= (tmp >> 5) & 15;
- ltime->year= (tmp >> 9);
- ltime->time_type= MYSQL_TIMESTAMP_DATE;
- ltime->hour= ltime->minute= ltime->second= ltime->second_part= ltime->neg= 0;
- return (!fuzzydate && (!ltime->month || !ltime->day)) ? 1 : 0;
- }
- bool Field_newdate::get_time(TIME *ltime)
- {
- return Field_newdate::get_date(ltime,0);
- }
- int Field_newdate::cmp(const char *a_ptr, const char *b_ptr)
- {
- uint32 a,b;
- a=(uint32) uint3korr(a_ptr);
- b=(uint32) uint3korr(b_ptr);
- return (a < b) ? -1 : (a > b) ? 1 : 0;
- }
- void Field_newdate::sort_string(char *to,uint length __attribute__((unused)))
- {
- to[0] = ptr[2];
- to[1] = ptr[1];
- to[2] = ptr[0];
- }
- void Field_newdate::sql_type(String &res) const
- {
- res.set_ascii("date", 4);
- }
- /****************************************************************************
- ** datetime type
- ** In string context: YYYY-MM-DD HH:MM:DD
- ** In number context: YYYYMMDDHHMMDD
- ** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int.
- ****************************************************************************/
- int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
- {
- TIME time_tmp;
- int error;
- ulonglong tmp= 0;
-
- if (str_to_datetime(from, len, &time_tmp, 1, &error) > MYSQL_TIMESTAMP_ERROR)
- tmp= TIME_to_ulonglong_datetime(&time_tmp);
-
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- from, len, MYSQL_TIMESTAMP_DATETIME, 1);
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int8store(ptr,tmp);
- }
- else
- #endif
- longlongstore(ptr,tmp);
- return error;
- }
- int Field_datetime::store(double nr)
- {
- int error= 0;
- if (nr < 0.0 || nr > 99991231235959.0)
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- nr, MYSQL_TIMESTAMP_DATETIME);
- nr=0.0;
- error= 1;
- }
- error |= Field_datetime::store((longlong) rint(nr));
- return error;
- }
- int Field_datetime::store(longlong nr)
- {
- TIME not_used;
- int error;
- longlong initial_nr= nr;
-
- nr= number_to_TIME(nr, ¬_used, 1, &error);
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED, initial_nr,
- MYSQL_TIMESTAMP_DATETIME, 1);
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int8store(ptr,nr);
- }
- else
- #endif
- longlongstore(ptr,nr);
- return error;
- }
- void Field_datetime::store_time(TIME *ltime,timestamp_type type)
- {
- longlong tmp;
- /*
- We don't perform range checking here since values stored in TIME
- structure always fit into DATETIME range.
- */
- if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME)
- tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+
- (ltime->hour*10000L+ltime->minute*100+ltime->second));
- else
- {
- tmp=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- }
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int8store(ptr,tmp);
- }
- else
- #endif
- longlongstore(ptr,tmp);
- }
- bool Field_datetime::send_binary(Protocol *protocol)
- {
- TIME tm;
- Field_datetime::get_date(&tm, TIME_FUZZY_DATE);
- return protocol->store(&tm);
- }
- double Field_datetime::val_real(void)
- {
- return (double) Field_datetime::val_int();
- }
- longlong Field_datetime::val_int(void)
- {
- longlong j;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- j=sint8korr(ptr);
- else
- #endif
- longlongget(j,ptr);
- return j;
- }
- String *Field_datetime::val_str(String *val_buffer,
- String *val_ptr __attribute__((unused)))
- {
- val_buffer->alloc(field_length);
- val_buffer->length(field_length);
- ulonglong tmp;
- long part1,part2;
- char *pos;
- int part3;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- tmp=sint8korr(ptr);
- else
- #endif
- longlongget(tmp,ptr);
- /*
- Avoid problem with slow longlong aritmetic and sprintf
- */
- part1=(long) (tmp/LL(1000000));
- part2=(long) (tmp - (ulonglong) part1*LL(1000000));
- pos=(char*) val_buffer->ptr()+19;
- *pos--=0;
- *pos--= (char) ('0'+(char) (part2%10)); part2/=10;
- *pos--= (char) ('0'+(char) (part2%10)); part3= (int) (part2 / 10);
- *pos--= ':';
- *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
- *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
- *pos--= ':';
- *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
- *pos--= (char) ('0'+(char) part3);
- *pos--= ' ';
- *pos--= (char) ('0'+(char) (part1%10)); part1/=10;
- *pos--= (char) ('0'+(char) (part1%10)); part1/=10;
- *pos--= '-';
- *pos--= (char) ('0'+(char) (part1%10)); part1/=10;
- *pos--= (char) ('0'+(char) (part1%10)); part3= (int) (part1/10);
- *pos--= '-';
- *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
- *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
- *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
- *pos=(char) ('0'+(char) part3);
- return val_buffer;
- }
- bool Field_datetime::get_date(TIME *ltime, uint fuzzydate)
- {
- longlong tmp=Field_datetime::val_int();
- uint32 part1,part2;
- part1=(uint32) (tmp/LL(1000000));
- part2=(uint32) (tmp - (ulonglong) part1*LL(1000000));
- ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
- ltime->neg= 0;
- ltime->second_part= 0;
- ltime->second= (int) (part2%100);
- ltime->minute= (int) (part2/100%100);
- ltime->hour= (int) (part2/10000);
- ltime->day= (int) (part1%100);
- ltime->month= (int) (part1/100%100);
- ltime->year= (int) (part1/10000);
- return (!fuzzydate && (!ltime->month || !ltime->day)) ? 1 : 0;
- }
- bool Field_datetime::get_time(TIME *ltime)
- {
- return Field_datetime::get_date(ltime,0);
- }
- int Field_datetime::cmp(const char *a_ptr, const char *b_ptr)
- {
- longlong a,b;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- a=sint8korr(a_ptr);
- b=sint8korr(b_ptr);
- }
- else
- #endif
- {
- longlongget(a,a_ptr);
- longlongget(b,b_ptr);
- }
- return ((ulonglong) a < (ulonglong) b) ? -1 :
- ((ulonglong) a > (ulonglong) b) ? 1 : 0;
- }
- void Field_datetime::sort_string(char *to,uint length __attribute__((unused)))
- {
- #ifdef WORDS_BIGENDIAN
- if (!table->db_low_byte_first)
- {
- to[0] = ptr[0];
- to[1] = ptr[1];
- to[2] = ptr[2];
- to[3] = ptr[3];
- to[4] = ptr[4];
- to[5] = ptr[5];
- to[6] = ptr[6];
- to[7] = ptr[7];
- }
- else
- #endif
- {
- to[0] = ptr[7];
- to[1] = ptr[6];
- to[2] = ptr[5];
- to[3] = ptr[4];
- to[4] = ptr[3];
- to[5] = ptr[2];
- to[6] = ptr[1];
- to[7] = ptr[0];
- }
- }
- void Field_datetime::sql_type(String &res) const
- {
- res.set_ascii("datetime", 8);
- }
- /****************************************************************************
- ** string type
- ** A string may be varchar or binary
- ****************************************************************************/
- /* Copy a string and fill with space */
- int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
- {
- int error= 0, well_formed_error;
- uint32 not_used;
- char buff[80];
- String tmpstr(buff,sizeof(buff), &my_charset_bin);
- uint copy_length;
-
- /* See the comment for Field_long::store(long long) */
- DBUG_ASSERT(table->in_use == current_thd);
-
- /* Convert character set if nesessary */
- if (String::needs_conversion(length, cs, field_charset, ¬_used))
- {
- uint conv_errors;
- tmpstr.copy(from, length, cs, field_charset, &conv_errors);
- from= tmpstr.ptr();
- length= tmpstr.length();
- if (conv_errors)
- error= 2;
- }
- /*
- Make sure we don't break a multibyte sequence
- as well as don't copy a malformed data.
- */
- copy_length= field_charset->cset->well_formed_len(field_charset,
- from,from+length,
- field_length/
- field_charset->mbmaxlen,
- &well_formed_error);
- memcpy(ptr,from,copy_length);
- if (copy_length < field_length) // Append spaces if shorter
- field_charset->cset->fill(field_charset,ptr+copy_length,
- field_length-copy_length,' ');
-
- if ((copy_length < length) && table->in_use->count_cuted_fields)
- { // Check if we loosed some info
- const char *end=from+length;
- from+= copy_length;
- from+= field_charset->cset->scan(field_charset, from, end,
- MY_SEQ_SPACES);
- if (from != end)
- error= 2;
- }
- if (error)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- return error;
- }
- /*
- Store double value in Field_string or Field_varstring.
- SYNOPSIS
- store(double nr)
- nr number
- DESCRIPTION
- Pretty prints double number into field_length characters buffer.
- */
- int Field_str::store(double nr)
- {
- char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
- uint length;
- bool use_scientific_notation= TRUE;
- uint char_length= field_length / charset()->mbmaxlen;
- /*
- Check fabs(nr) against longest value that can be stored in field,
- which depends on whether the value is < 1 or not, and negative or not
- */
- double anr= fabs(nr);
- int neg= (nr < 0.0) ? 1 : 0;
- if (char_length > 4 && char_length < 32 &&
- (anr < 1.0 ? anr > 1/(log_10[max(0,(int) char_length-neg-2)]) /* -2 for "0." */
- : anr < log_10[char_length-neg]-1))
- use_scientific_notation= FALSE;
- length= (uint) my_sprintf(buff, (buff, "%-.*g",
- (use_scientific_notation ?
- max(0, (int)char_length-neg-5) :
- char_length),
- nr));
- /*
- +1 below is because "precision" in %g above means the
- max. number of significant digits, not the output width.
- Thus the width can be larger than number of significant digits by 1
- (for decimal point)
- the test for char_length < 5 is for extreme cases,
- like inserting 500.0 in char(1)
- */
- DBUG_ASSERT(char_length < 5 || length <= char_length+1);
- return store((const char *) buff, length, charset());
- }
- int Field_string::store(longlong nr)
- {
- 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)
- {
- int not_used;
- char *end_not_used;
- CHARSET_INFO *cs=charset();
- return my_strntod(cs, ptr, field_length, &end_not_used, ¬_used);
- }
- longlong Field_string::val_int(void)
- {
- int not_used;
- CHARSET_INFO *cs=charset();
- return my_strntoll(cs,ptr,field_length,10,NULL,¬_used);
- }
- String *Field_string::val_str(String *val_buffer __attribute__((unused)),
- String *val_ptr)
- {
- uint length= field_charset->cset->lengthsp(field_charset, ptr, field_length);
- /* See the comment for Field_long::store(long long) */
- DBUG_ASSERT(table->in_use == current_thd);
- val_ptr->set((const char*) ptr, length, field_charset);
- return val_ptr;
- }
- int Field_string::cmp(const char *a_ptr, const char *b_ptr)
- {
- uint a_len, b_len;
- 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
- */
- return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a_ptr, field_length,
- (const uchar*) b_ptr,
- field_length);
- }
- if (field_charset->mbmaxlen != 1)
- {
- uint char_len= field_length/field_charset->mbmaxlen;
- a_len= my_charpos(field_charset, a_ptr, a_ptr + field_length, char_len);
- b_len= my_charpos(field_charset, b_ptr, b_ptr + field_length, char_len);
- }
- else
- a_len= b_len= field_length;
- return my_strnncoll(field_charset,(const uchar*) a_ptr, a_len,
- (const uchar*) b_ptr, b_len);
- }
- void Field_string::sort_string(char *to,uint length)
- {
- uint tmp=my_strnxfrm(field_charset,
- (unsigned char *) to, length,
- (unsigned char *) ptr, field_length);
- DBUG_ASSERT(tmp == length);
- }
- void Field_string::sql_type(String &res) const
- {
- THD *thd= table->in_use;
- 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) ?
- (has_charset() ? "varchar" : "varbinary") :
- (has_charset() ? "char" : "binary")),
- (int) field_length / charset()->mbmaxlen);
- res.length(length);
- if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) &&
- has_charset() && (charset()->state & MY_CS_BINSORT))
- res.append(" binary");
- }
- char *Field_string::pack(char *to, const char *from, uint max_length)
- {
- uint length= min(field_length,max_length);
- uint char_length= max_length/field_charset->mbmaxlen;
- if (length > char_length)
- char_length= my_charpos(field_charset, from, from+length, char_length);
- set_if_smaller(length, char_length);
- while (length && from[length-1] == ' ')
- length--;
- *to++= (char) (uchar) length;
- if (field_length > 255)
- *to++= (char) (uchar) (length >> 8);
- memcpy(to, from, length);
- return to+length;
- }
- const char *Field_string::unpack(char *to, const char *from)
- {
- uint length;
- if (field_length > 255)
- {
- length= uint2korr(from);
- from+= 2;
- }
- else
- length= (uint) (uchar) *from++;
- memcpy(to, from, (int) length);
- bfill(to+length, field_length - length, ' ');
- return from+length;
- }
- int Field_string::pack_cmp(const char *a, const char *b, uint length)
- {
- uint a_length, b_length;
- if (field_length > 255)
- {
- a_length= uint2korr(a);
- b_length= uint2korr(b);
- a+= 2;
- b+= 2;
- }
- else
- {
- a_length= (uint) (uchar) *a++;
- b_length= (uint) (uchar) *b++;
- }
- return my_strnncoll(field_charset,
- (const uchar*)a,a_length,
- (const uchar*)b,b_length);
- }
- int Field_string::pack_cmp(const char *b, uint length)
- {
- uint b_length;
- if (field_length > 255)
- {
- b_length= uint2korr(b);
- b+= 2;
- }
- else
- b_length= (uint) (uchar) *b++;
- char *end= ptr + field_length;
- while (end > ptr && end[-1] == ' ')
- end--;
- uint a_length = (uint) (end - ptr);
- return my_strnncoll(field_charset,
- (const uchar*)ptr,a_length,
- (const uchar*)b, b_length);
- }
- uint Field_string::packed_col_length(const char *data_ptr, uint length)
- {
- if (length > 255)
- return uint2korr(data_ptr)+2;
- else
- return (uint) ((uchar) *data_ptr)+1;
- }
- uint Field_string::max_packed_col_length(uint max_length)
- {
- return (max_length > 255 ? 2 : 1)+max_length;
- }
- /****************************************************************************
- ** VARCHAR type (Not available for the end user yet)
- ****************************************************************************/
- int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
- {
- int error= 0;
- uint32 not_used;
- char buff[80];
- String tmpstr(buff,sizeof(buff), &my_charset_bin);
- /* Convert character set if nesessary */
- if (String::needs_conversion(length, cs, field_charset, ¬_used))
- {
- uint conv_errors;
- tmpstr.copy(from, length, cs, field_charset, &conv_errors);
- from= tmpstr.ptr();
- length= tmpstr.length();
- if (conv_errors)
- error= 2;
- }
- if (length > field_length)
- {
- length=field_length;
- error= 2;
- }
- if (error)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- memcpy(ptr+HA_KEY_BLOB_LENGTH,from,length);
- int2store(ptr, length);
- return error;
- }
- int Field_varstring::store(longlong nr)
- {
- 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)
- {
- int not_used;
- uint length=uint2korr(ptr)+HA_KEY_BLOB_LENGTH;
- CHARSET_INFO *cs=charset();
- char *end_not_used;
- return my_strntod(cs, ptr+HA_KEY_BLOB_LENGTH, length, &end_not_used,
- ¬_used);
- }
- longlong Field_varstring::val_int(void)
- {
- int not_used;
- uint length=uint2korr(ptr)+HA_KEY_BLOB_LENGTH;
- CHARSET_INFO *cs=charset();
- return my_strntoll(cs,ptr+HA_KEY_BLOB_LENGTH,length,10,NULL, ¬_used);
- }
- String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
- String *val_ptr)
- {
- uint length=uint2korr(ptr);
- val_ptr->set((const char*) ptr+HA_KEY_BLOB_LENGTH,length,field_charset);
- return val_ptr;
- }
- 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;
- diff= my_strnncoll(field_charset,
- (const uchar*) a_ptr+HA_KEY_BLOB_LENGTH,
- min(a_length,b_length),
- (const uchar*) b_ptr+HA_KEY_BLOB_LENGTH,
- 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);
- tot_length= my_strnxfrm(field_charset,
- (uchar*) to, length,
- (uchar*) ptr+HA_KEY_BLOB_LENGTH,
- tot_length);
- DBUG_ASSERT(tot_length == length);
- }
- void Field_varstring::sql_type(String &res) const
- {
- 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)
- {
- uint length=uint2korr(from);
- if (length > max_length)
- length=max_length;
- *to++= (char) (length & 255);
- if (max_length > 255)
- *to++= (char) (length >> 8);
- if (length)
- memcpy(to, from+HA_KEY_BLOB_LENGTH, length);
- return to+length;
- }
- char *Field_varstring::pack_key(char *to, const char *from, uint max_length)
- {
- uint length=uint2korr(from);
- uint char_length= (field_charset->mbmaxlen > 1) ?
- max_length/field_charset->mbmaxlen : max_length;
- from+=HA_KEY_BLOB_LENGTH;
- if (length > char_length)
- char_length= my_charpos(field_charset, from, from+length, char_length);
- set_if_smaller(length, char_length);
- *to++= (char) (length & 255);
- if (max_length > 255)
- *to++= (char) (length >> 8);
- if (length)
- memcpy(to, from, length);
- return to+length;
- }
- const char *Field_varstring::unpack(char *to, const char *from)
- {
- uint length;
- if (field_length > 255)
- {
- length= (uint) (uchar) (*to= *from++);
- to[1]=0;
- }
- else
- {
- length=uint2korr(from);
- to[0] = *from++;
- to[1] = *from++;
- }
- if (length)
- memcpy(to+HA_KEY_BLOB_LENGTH, from, length);
- return from+length;
- }
- int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
- {
- uint a_length;
- uint b_length;
- if (key_length > 255)
- {
- a_length=uint2korr(a); a+= 2;
- b_length=uint2korr(b); b+= 2;
- }
- else
- {
- a_length= (uint) (uchar) *a++;
- b_length= (uint) (uchar) *b++;
- }
- 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)
- {
- char *a= ptr+HA_KEY_BLOB_LENGTH;
- uint a_length= uint2korr(ptr);
- uint b_length;
- if (key_length > 255)
- {
- b_length=uint2korr(b); b+= 2;
- }
- else
- {
- b_length= (uint) (uchar) *b++;
- }
- 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)
- {
- if (length > 255)
- return uint2korr(data_ptr)+HA_KEY_BLOB_LENGTH;
- else
- return (uint) ((uchar) *data_ptr)+1;
- }
- 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)
- {
- uint f_length=uint2korr(ptr);
- if (f_length > length)
- f_length= length;
- int2store(buff,length);
- memcpy(buff+HA_KEY_BLOB_LENGTH, ptr+HA_KEY_BLOB_LENGTH, length);
- #ifdef HAVE_purify
- if (f_length < length)
- bzero(buff+HA_KEY_BLOB_LENGTH+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+HA_KEY_BLOB_LENGTH, length, cs);
- }
- /****************************************************************************
- ** blob type
- ** A blob is saved as a length and a pointer. The length is stored in the
- ** packlength slot and may be from 1-4.
- ****************************************************************************/
- Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg, const char *field_name_arg,
- struct st_table *table_arg,uint blob_pack_length,
- CHARSET_INFO *cs)
- :Field_str(ptr_arg, BLOB_PACK_LENGTH_TO_MAX_LENGH(blob_pack_length),
- null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
- table_arg, cs),
- packlength(blob_pack_length)
- {
- flags|= BLOB_FLAG;
- if (table)
- table->blob_fields++;
- }
- void Field_blob::store_length(uint32 number)
- {
- switch (packlength) {
- case 1:
- ptr[0]= (uchar) number;
- break;
- case 2:
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int2store(ptr,(unsigned short) number);
- }
- else
- #endif
- shortstore(ptr,(unsigned short) number);
- break;
- case 3:
- int3store(ptr,number);
- break;
- case 4:
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int4store(ptr,number);
- }
- else
- #endif
- longstore(ptr,number);
- }
- }
- uint32 Field_blob::get_length(const char *pos)
- {
- switch (packlength) {
- case 1:
- return (uint32) (uchar) pos[0];
- case 2:
- {
- uint16 tmp;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- tmp=sint2korr(pos);
- else
- #endif
- shortget(tmp,pos);
- return (uint32) tmp;
- }
- case 3:
- return (uint32) uint3korr(pos);
- case 4:
- {
- uint32 tmp;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- tmp=uint4korr(pos);
- else
- #endif
- longget(tmp,pos);
- return (uint32) tmp;
- }
- }
- return 0; // Impossible
- }
- /*
- Put a blob length field into a record buffer.
- SYNOPSIS
- Field_blob::put_length()
- pos Pointer into the record buffer.
- length The length value to put.
- DESCRIPTION
- Depending on the maximum length of a blob, its length field is
- put into 1 to 4 bytes. This is a property of the blob object,
- described by 'packlength'.
- RETURN
- nothing
- */
- void Field_blob::put_length(char *pos, uint32 length)
- {
- switch (packlength) {
- case 1:
- *pos= (char) length;
- break;
- case 2:
- int2store(pos, length);
- break;
- case 3:
- int3store(pos, length);
- break;
- case 4:
- int4store(pos, length);
- break;
- }
- }
- int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
- {
- int error= 0, well_formed_error;
- if (!length)
- {
- bzero(ptr,Field_blob::pack_length());
- }
- else
- {
- bool was_conversion;
- char buff[80];
- String tmpstr(buff,sizeof(buff), &my_charset_bin);
- uint copy_length;
- uint32 not_used;
- /* Convert character set if nesessary */
- if ((was_conversion= String::needs_conversion(length, cs, field_charset,
- ¬_used)))
- {
- uint conv_errors;
- tmpstr.copy(from, length, cs, field_charset, &conv_errors);
- from= tmpstr.ptr();
- length= tmpstr.length();
- if (conv_errors)
- error= 2;
- }
-
- copy_length= max_data_length();
- /*
- copy_length is ok as last argument to well_formed_len as this is never
- used to limit the length of the data. The cut of long data is done with
- the 'min()' call below.
- */
- copy_length= field_charset->cset->well_formed_len(field_charset,
- from,from +
- min(length, copy_length),
- copy_length,
- &well_formed_error);
- if (copy_length < length)
- error= 2;
- Field_blob::store_length(copy_length);
- if (was_conversion || table->copy_blobs || copy_length <= MAX_FIELD_WIDTH)
- { // Must make a copy
- if (from != value.ptr()) // For valgrind
- {
- value.copy(from,copy_length,charset());
- from=value.ptr();
- }
- }
- bmove(ptr+packlength,(char*) &from,sizeof(char*));
- }
- if (error)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- return 0;
- }
- int Field_blob::store(double nr)
- {
- CHARSET_INFO *cs=charset();
- value.set(nr, 2, cs);
- return Field_blob::store(value.ptr(),(uint) value.length(), cs);
- }
- int Field_blob::store(longlong nr)
- {
- 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;
- char *end_not_used;
- memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
- if (!blob)
- return 0.0;
- uint32 length=get_length(ptr);
- CHARSET_INFO *cs=charset();
- return my_strntod(cs,blob,length, &end_not_used, ¬_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);
- return my_strntoll(charset(),blob,length,10,NULL,¬_used);
- }
- String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
- String *val_ptr)
- {
- char *blob;
- memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
- if (!blob)
- val_ptr->set("",0,charset()); // A bit safer than ->length(0)
- else
- val_ptr->set((const char*) blob,get_length(ptr),charset());
- return val_ptr;
- }
- int Field_blob::cmp(const char *a,uint32 a_length, const char *b,
- uint32 b_length)
- {
- return field_charset->coll->strnncoll(field_charset,
- (const uchar*)a, a_length,
- (const uchar*)b, b_length,
- 0);
- }
- int Field_blob::cmp(const char *a_ptr, const char *b_ptr)
- {
- char *blob1,*blob2;
- memcpy_fixed(&blob1,a_ptr+packlength,sizeof(char*));
- memcpy_fixed(&blob2,b_ptr+packlength,sizeof(char*));
- return Field_blob::cmp(blob1,get_length(a_ptr),
- blob2,get_length(b_ptr));
- }
- int Field_blob::cmp_offset(uint row_offset)
- {
- return Field_blob::cmp(ptr,ptr+row_offset);
- }
- int Field_blob::cmp_binary_offset(uint row_offset)
- {
- return cmp_binary(ptr, ptr+row_offset);
- }
- int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
- uint32 max_length)
- {
- char *a,*b;
- uint diff;
- uint32 a_length,b_length;
- memcpy_fixed(&a,a_ptr+packlength,sizeof(char*));
- memcpy_fixed(&b,b_ptr+packlength,sizeof(char*));
- a_length=get_length(a_ptr);
- if (a_length > max_length)
- a_length=max_length;
- b_length=get_length(b_ptr);
- if (b_length > max_length)
- b_length=max_length;
- diff=memcmp(a,b,min(a_length,b_length));
- return diff ? diff : (int) (a_length - b_length);
- }
- /* The following is used only when comparing a key */
- void Field_blob::get_key_image(char *buff,uint length,
- CHARSET_INFO *cs, imagetype type)
- {
- uint32 blob_length= get_length(ptr);
- char *blob;
- #ifdef HAVE_SPATIAL
- if (type == itMBR)
- {
- const char *dummy;
- MBR mbr;
- Geometry_buffer buffer;
- Geometry *gobj;
- if (blob_length < SRID_SIZE)
- {
- bzero(buff, SIZEOF_STORED_DOUBLE*4);
- return;
- }
- get_ptr(&blob);
- gobj= Geometry::construct(&buffer, blob, blob_length);
- if (gobj->get_mbr(&mbr, &dummy))
- bzero(buff, SIZEOF_STORED_DOUBLE*4);
- else
- {
- float8store(buff, mbr.xmin);
- float8store(buff+8, mbr.xmax);
- float8store(buff+16, mbr.ymin);
- float8store(buff+24, mbr.ymax);
- }
- return;
- }
- #endif /*HAVE_SPATIAL*/
- get_ptr(&blob);
- uint char_length= length / cs->mbmaxlen;
- char_length= my_charpos(cs, blob, blob + blob_length, char_length);
- set_if_smaller(blob_length, char_length);
- if ((uint32) length > blob_length)
- {
- /*
- Must clear this as we do a memcmp in opt_range.cc to detect
- identical keys
- */
- bzero(buff+HA_KEY_BLOB_LENGTH+blob_length, (length-blob_length));
- length=(uint) blob_length;
- }
- int2store(buff,length);
- memcpy(buff+HA_KEY_BLOB_LENGTH, blob, length);
- }
- void Field_blob::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
- {
- length= uint2korr(buff);
- (void) Field_blob::store(buff+HA_KEY_BLOB_LENGTH, length, cs);
- }
- int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
- {
- char *blob1;
- uint blob_length=get_length(ptr);
- memcpy_fixed(&blob1,ptr+packlength,sizeof(char*));
- CHARSET_INFO *cs= charset();
- uint char_length= max_key_length / cs->mbmaxlen;
- char_length= my_charpos(cs, blob1, blob1+blob_length, char_length);
- set_if_smaller(blob_length, char_length);
- return Field_blob::cmp(blob1,min(blob_length, max_key_length),
- (char*) key_ptr+HA_KEY_BLOB_LENGTH,
- uint2korr(key_ptr));
- }
- int Field_blob::key_cmp(const byte *a,const byte *b)
- {
- return Field_blob::cmp((char*) a+HA_KEY_BLOB_LENGTH, uint2korr(a),
- (char*) b+HA_KEY_BLOB_LENGTH, uint2korr(b));
- }
- void Field_blob::sort_string(char *to,uint length)
- {
- char *blob;
- uint blob_length=get_length();
- if (!blob_length)
- bzero(to,length);
- else
- {
- memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
-
- blob_length=my_strnxfrm(field_charset,
- (uchar*) to, length,
- (uchar*) blob, blob_length);
- DBUG_ASSERT(blob_length == length);
- }
- }
- void Field_blob::sql_type(String &res) const
- {
- const char *str;
- uint length;
- switch (packlength) {
- 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");
- }
- }
- char *Field_blob::pack(char *to, const char *from, uint max_length)
- {
- char *save=ptr;
- ptr=(char*) from;
- uint32 length=get_length(); // Length of from string
- if (length > max_length)
- {
- ptr=to;
- length=max_length;
- store_length(length); // Store max length
- ptr=(char*) from;
- }
- else
- memcpy(to,from,packlength); // Copy length
- if (length)
- {
- get_ptr((char**) &from);
- memcpy(to+packlength, from,length);
- }
- ptr=save; // Restore org row pointer
- return to+packlength+length;
- }
- const char *Field_blob::unpack(char *to, const char *from)
- {
- memcpy(to,from,packlength);
- uint32 length=get_length(from);
- from+=packlength;
- if (length)
- memcpy_fixed(to+packlength, &from, sizeof(from));
- else
- bzero(to+packlength,sizeof(from));
- return from+length;
- }
- /* Keys for blobs are like keys on varchars */
- int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
- {
- uint a_length;
- uint b_length;
- if (key_length > 255)
- {
- a_length=uint2korr(a); a+=2;
- b_length=uint2korr(b); b+=2;
- }
- else
- {
- a_length= (uint) (uchar) *a++;
- b_length= (uint) (uchar) *b++;
- }
- return my_strnncoll(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length);
- }
- int Field_blob::pack_cmp(const char *b, uint key_length)
- {
- char *a;
- memcpy_fixed(&a,ptr+packlength,sizeof(char*));
- if (!a)
- return key_length > 0 ? -1 : 0;
- uint a_length=get_length(ptr);
- uint b_length;
- if (key_length > 255)
- {
- b_length=uint2korr(b); b+=2;
- }
- else
- {
- b_length= (uint) (uchar) *b++;
- }
- 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 */
- char *Field_blob::pack_key(char *to, const char *from, uint max_length)
- {
- char *save=ptr;
- ptr=(char*) from;
- uint32 length=get_length(); // Length of from string
- uint char_length= (field_charset->mbmaxlen > 1) ?
- max_length/field_charset->mbmaxlen : max_length;
- if (length)
- get_ptr((char**) &from);
- if (length > char_length)
- char_length= my_charpos(field_charset, from, from+length, char_length);
- set_if_smaller(length, char_length);
- *to++= (uchar) length;
- if (max_length > 255) // 2 byte length
- *to++= (uchar) (length >> 8);
- memcpy(to, from, length);
- ptr=save; // Restore org row pointer
- return to+length;
- }
- /*
- Unpack a blob key into a record buffer.
- SYNOPSIS
- Field_blob::unpack_key()
- to Pointer into the record buffer.
- from Pointer to the packed key.
- max_length Key length limit from key description.
- DESCRIPTION
- A blob key has a maximum size of 64K-1.
- In its packed form, the length field is one or two bytes long,
- depending on 'max_length'.
- Depending on the maximum length of a blob, its length field is
- put into 1 to 4 bytes. This is a property of the blob object,
- described by 'packlength'.
- Blobs are internally stored apart from the record buffer, which
- contains a pointer to the blob buffer.
- RETURN
- Pointer into 'from' past the last byte copied from packed key.
- */
- const char *Field_blob::unpack_key(char *to, const char *from, uint max_length)
- {
- /* get length of the blob key */
- uint32 length= *((uchar*) from++);
- if (max_length > 255)
- length+= (*((uchar*) from++)) << 8;
- /* put the length into the record buffer */
- put_length(to, length);
- /* put the address of the blob buffer or NULL */
- if (length)
- memcpy_fixed(to + packlength, &from, sizeof(from));
- else
- bzero(to + packlength, sizeof(from));
- /* point to first byte of next field in 'from' */
- return from + length;
- }
- /* Create a packed key that will be used for storage from a MySQL key */
- char *Field_blob::pack_key_from_key_image(char *to, const char *from,
- uint max_length)
- {
- uint length=uint2korr(from);
- if (length > max_length)
- length=max_length;
- *to++= (char) (length & 255);
- if (max_length > 255)
- *to++= (char) (length >> 8);
- if (length)
- memcpy(to, from+HA_KEY_BLOB_LENGTH, length);
- return to+length;
- }
- uint Field_blob::packed_col_length(const char *data_ptr, uint length)
- {
- if (length > 255)
- return uint2korr(data_ptr)+2;
- else
- return (uint) ((uchar) *data_ptr)+1;
- }
- uint Field_blob::max_packed_col_length(uint max_length)
- {
- return (max_length > 255 ? 2 : 1)+max_length;
- }
- #ifdef HAVE_SPATIAL
- void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
- imagetype type)
- {
- char *blob;
- const char *dummy;
- MBR mbr;
- ulong blob_length= get_length(ptr);
- Geometry_buffer buffer;
- Geometry *gobj;
- if (blob_length < SRID_SIZE)
- {
- bzero(buff, SIZEOF_STORED_DOUBLE*4);
- return;
- }
- get_ptr(&blob);
- gobj= Geometry::construct(&buffer, blob, blob_length);
- if (gobj->get_mbr(&mbr, &dummy))
- bzero(buff, SIZEOF_STORED_DOUBLE*4);
- else
- {
- float8store(buff, mbr.xmin);
- float8store(buff + 8, mbr.xmax);
- float8store(buff + 16, mbr.ymin);
- float8store(buff + 24, mbr.ymax);
- }
- }
- 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
- {
- // Check given WKB
- uint32 wkb_type;
- if (length < SRID_SIZE + WKB_HEADER_SIZE + SIZEOF_STORED_DOUBLE*2)
- goto err;
- wkb_type= uint4korr(from + SRID_SIZE + 1);
- if (wkb_type < (uint32) Geometry::wkb_point ||
- wkb_type > (uint32) Geometry::wkb_end)
- 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;
- err:
- bzero(ptr, Field_blob::pack_length());
- return -1;
- }
- #endif /*HAVE_SPATIAL*/
- /****************************************************************************
- ** enum type.
- ** This is a string which only can have a selection of different values.
- ** If one uses this string in a number context one gets the type number.
- ****************************************************************************/
- enum ha_base_keytype Field_enum::key_type() const
- {
- switch (packlength) {
- default: return HA_KEYTYPE_BINARY;
- case 2: return HA_KEYTYPE_USHORT_INT;
- case 3: return HA_KEYTYPE_UINT24;
- case 4: return HA_KEYTYPE_ULONG_INT;
- case 8: return HA_KEYTYPE_ULONGLONG;
- }
- }
- void Field_enum::store_type(ulonglong value)
- {
- switch (packlength) {
- case 1: ptr[0]= (uchar) value; break;
- case 2:
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int2store(ptr,(unsigned short) value);
- }
- else
- #endif
- shortstore(ptr,(unsigned short) value);
- break;
- case 3: int3store(ptr,(long) value); break;
- case 4:
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int4store(ptr,value);
- }
- else
- #endif
- longstore(ptr,(long) value);
- break;
- case 8:
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int8store(ptr,value);
- }
- else
- #endif
- longlongstore(ptr,value); break;
- }
- }
- /*
- ** Note. Storing a empty string in a enum field gives a warning
- ** (if there isn't a empty value in the enum)
- */
- int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
- {
- int err= 0;
- uint32 not_used;
- char buff[80];
- String tmpstr(buff,sizeof(buff), &my_charset_bin);
- /* Convert character set if nesessary */
- if (String::needs_conversion(length, cs, field_charset, ¬_used))
- {
- uint dummy_errors;
- tmpstr.copy(from, length, cs, field_charset, &dummy_errors);
- from= tmpstr.ptr();
- length= tmpstr.length();
- }
- /* Remove end space */
- length= field_charset->cset->lengthsp(field_charset, from, length);
- uint tmp=find_type2(typelib, from, length, field_charset);
- if (!tmp)
- {
- if (length < 6) // Can't be more than 99999 enums
- {
- /* This is for reading numbers with LOAD DATA INFILE */
- char *end;
- tmp=(uint) my_strntoul(cs,from,length,10,&end,&err);
- if (err || end != from+length || tmp > typelib->count)
- {
- tmp=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- }
- }
- else
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- }
- store_type((ulonglong) tmp);
- return err;
- }
- int Field_enum::store(double nr)
- {
- return Field_enum::store((longlong) nr);
- }
- int Field_enum::store(longlong nr)
- {
- int error= 0;
- if ((uint) nr > typelib->count || nr == 0)
- {
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- nr=0;
- error=1;
- }
- store_type((ulonglong) (uint) nr);
- return error;
- }
- double Field_enum::val_real(void)
- {
- return (double) Field_enum::val_int();
- }
- longlong Field_enum::val_int(void)
- {
- switch (packlength) {
- case 1:
- return (longlong) (uchar) ptr[0];
- case 2:
- {
- uint16 tmp;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- tmp=sint2korr(ptr);
- else
- #endif
- shortget(tmp,ptr);
- return (longlong) tmp;
- }
- case 3:
- return (longlong) uint3korr(ptr);
- case 4:
- {
- uint32 tmp;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- tmp=uint4korr(ptr);
- else
- #endif
- longget(tmp,ptr);
- return (longlong) tmp;
- }
- case 8:
- {
- longlong tmp;
- #ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- tmp=sint8korr(ptr);
- else
- #endif
- longlongget(tmp,ptr);
- return tmp;
- }
- }
- return 0; // impossible
- }
- String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
- String *val_ptr)
- {
- uint tmp=(uint) Field_enum::val_int();
- if (!tmp || tmp > typelib->count)
- val_ptr->set("", 0, field_charset);
- else
- val_ptr->set((const char*) typelib->type_names[tmp-1],
- typelib->type_lengths[tmp-1],
- field_charset);
- return val_ptr;
- }
- int Field_enum::cmp(const char *a_ptr, const char *b_ptr)
- {
- char *old=ptr;
- ptr=(char*) a_ptr;
- ulonglong a=Field_enum::val_int();
- ptr=(char*) b_ptr;
- ulonglong b=Field_enum::val_int();
- ptr=old;
- return (a < b) ? -1 : (a > b) ? 1 : 0;
- }
- void Field_enum::sort_string(char *to,uint length __attribute__((unused)))
- {
- ulonglong value=Field_enum::val_int();
- to+=packlength-1;
- for (uint i=0 ; i < packlength ; i++)
- {
- *to-- = (uchar) (value & 255);
- value>>=8;
- }
- }
- void Field_enum::sql_type(String &res) const
- {
- char buffer[255];
- String enum_item(buffer, sizeof(buffer), res.charset());
- res.length(0);
- res.append("enum(");
- bool flag=0;
- uint *len= typelib->type_lengths;
- for (const char **pos= typelib->type_names; *pos; pos++, len++)
- {
- uint dummy_errors;
- if (flag)
- res.append(',');
- /* convert to res.charset() == utf8, then quote */
- enum_item.copy(*pos, *len, charset(), res.charset(), &dummy_errors);
- append_unescaped(&res, enum_item.ptr(), enum_item.length());
- 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.
- */
- int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
- {
- bool got_warning= 0;
- int err= 0;
- char *not_used;
- uint not_used2;
- uint32 not_used_offset;
- char buff[80];
- String tmpstr(buff,sizeof(buff), &my_charset_bin);
- /* Convert character set if nesessary */
- if (String::needs_conversion(length, cs, field_charset, ¬_used_offset))
- {
- uint dummy_errors;
- tmpstr.copy(from, length, cs, field_charset, &dummy_errors);
- from= tmpstr.ptr();
- length= tmpstr.length();
- }
- ulonglong tmp= find_set(typelib, from, length, field_charset,
- ¬_used, ¬_used2, &got_warning);
- if (!tmp && length && length < 22)
- {
- /* This is for reading numbers with LOAD DATA INFILE */
- char *end;
- tmp=my_strntoull(cs,from,length,10,&end,&err);
- if (err || end != from+length ||
- tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1))
- {
- tmp=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- }
- }
- else if (got_warning)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- store_type(tmp);
- return err;
- }
- 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);
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- error=1;
- }
- store_type((ulonglong) nr);
- return error;
- }
- String *Field_set::val_str(String *val_buffer,
- String *val_ptr __attribute__((unused)))
- {
- ulonglong tmp=(ulonglong) Field_enum::val_int();
- uint bitnr=0;
- val_buffer->length(0);
- val_buffer->set_charset(field_charset);
- while (tmp && bitnr < (uint) typelib->count)
- {
- if (tmp & 1)
- {
- if (val_buffer->length())
- val_buffer->append(&field_separator, 1, &my_charset_latin1);
- String str(typelib->type_names[bitnr],
- typelib->type_lengths[bitnr],
- field_charset);
- val_buffer->append(str);
- }
- tmp>>=1;
- bitnr++;
- }
- return val_buffer;
- }
- void Field_set::sql_type(String &res) const
- {
- char buffer[255];
- String set_item(buffer, sizeof(buffer), res.charset());
- res.length(0);
- res.append("set(");
- bool flag=0;
- uint *len= typelib->type_lengths;
- for (const char **pos= typelib->type_names; *pos; pos++, len++)
- {
- uint dummy_errors;
- if (flag)
- res.append(',');
- /* convert to res.charset() == utf8, then quote */
- set_item.copy(*pos, *len, charset(), res.charset(), &dummy_errors);
- append_unescaped(&res, set_item.ptr(), set_item.length());
- flag= 1;
- }
- res.append(')');
- }
- /* returns 1 if the fields are equally defined */
- bool Field::eq_def(Field *field)
- {
- if (real_type() != field->real_type() || charset() != field->charset() ||
- pack_length() != field->pack_length())
- return 0;
- return 1;
- }
- bool Field_enum::eq_def(Field *field)
- {
- if (!Field::eq_def(field))
- return 0;
- TYPELIB *from_lib=((Field_enum*) field)->typelib;
- if (typelib->count < from_lib->count)
- return 0;
- for (uint i=0 ; i < from_lib->count ; i++)
- if (my_strnncoll(field_charset,
- (const uchar*)typelib->type_names[i],
- strlen(typelib->type_names[i]),
- (const uchar*)from_lib->type_names[i],
- strlen(from_lib->type_names[i])))
- return 0;
- return 1;
- }
- bool Field_num::eq_def(Field *field)
- {
- if (!Field::eq_def(field))
- return 0;
- Field_num *from_num= (Field_num*) field;
- if (unsigned_flag != from_num->unsigned_flag ||
- zerofill && !from_num->zerofill && !zero_pack() ||
- dec != from_num->dec)
- return 0;
- return 1;
- }
- /*****************************************************************************
- ** Handling of field and create_field
- *****************************************************************************/
- /*
- Convert create_field::length from number of characters to number of bytes
- SYNOPSIS
- create_field::create_length_to_internal_length()
-
- DESCRIPTION
- Convert create_field::length from number of characters to number of bytes,
- save original value in chars_length.
- */
- void create_field::create_length_to_internal_length(void)
- {
- chars_length= length;
- 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;
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- length*= charset->mbmaxlen;
- break;
- default:
- /* do nothing */
- break;
- }
- }
- /*
- Make a field from the .frm file info
- */
- uint32 calc_pack_length(enum_field_types type,uint32 length)
- {
- switch (type) {
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_DECIMAL: return (length);
- case FIELD_TYPE_VAR_STRING: return (length+HA_KEY_BLOB_LENGTH);
- case FIELD_TYPE_YEAR:
- case FIELD_TYPE_TINY : return 1;
- case FIELD_TYPE_SHORT : return 2;
- case FIELD_TYPE_INT24:
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_TIME: return 3;
- case FIELD_TYPE_TIMESTAMP:
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_LONG : return 4;
- case FIELD_TYPE_FLOAT : return sizeof(float);
- case FIELD_TYPE_DOUBLE: return sizeof(double);
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */
- case FIELD_TYPE_NULL : return 0;
- case FIELD_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr;
- 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;
- }
- return 0; // Keep compiler happy
- }
- uint pack_length_to_packflag(uint type)
- {
- switch (type) {
- case 1: return f_settype((uint) FIELD_TYPE_TINY);
- case 2: return f_settype((uint) FIELD_TYPE_SHORT);
- case 3: return f_settype((uint) FIELD_TYPE_INT24);
- case 4: return f_settype((uint) FIELD_TYPE_LONG);
- case 8: return f_settype((uint) FIELD_TYPE_LONGLONG);
- }
- return 0; // This shouldn't happen
- }
- Field *make_field(char *ptr, uint32 field_length,
- uchar *null_pos, 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,
- struct st_table *table)
- {
- if (!f_maybe_null(pack_flag))
- {
- null_pos=0;
- null_bit=0;
- }
- switch (field_type)
- {
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_TIME:
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_TIMESTAMP:
- field_charset= &my_charset_bin;
- default: break;
- }
- if (f_is_alpha(pack_flag))
- {
- if (!f_is_packed(pack_flag))
- {
- if (field_type == FIELD_TYPE_STRING ||
- field_type == FIELD_TYPE_DECIMAL || // 3.23 or 4.0 string
- field_type == FIELD_TYPE_VAR_STRING)
- return new Field_string(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
- field_charset);
- return 0; // Error
- }
- uint pack_length=calc_pack_length((enum_field_types)
- f_packtype(pack_flag),
- field_length);
- #ifdef HAVE_SPATIAL
- if (f_is_geom(pack_flag))
- return new Field_geom(ptr,null_pos,null_bit,
- unireg_check, field_name, table,
- pack_length, geom_type);
- #endif
- if (f_is_blob(pack_flag))
- return new Field_blob(ptr,null_pos,null_bit,
- unireg_check, field_name, table,
- 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, field_charset);
- else
- return new Field_set(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
- pack_length, interval, field_charset);
- }
- }
- switch (field_type) {
- case FIELD_TYPE_DECIMAL:
- return new Field_decimal(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
- f_decimals(pack_flag),
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_FLOAT:
- return new Field_float(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
- f_decimals(pack_flag),
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag)== 0);
- case FIELD_TYPE_DOUBLE:
- return new Field_double(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
- f_decimals(pack_flag),
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag)== 0);
- case FIELD_TYPE_TINY:
- return new Field_tiny(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_SHORT:
- return new Field_short(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_INT24:
- return new Field_medium(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_LONG:
- return new Field_long(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_LONGLONG:
- return new Field_longlong(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_TIMESTAMP:
- return new Field_timestamp(ptr,field_length, null_pos, null_bit,
- 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, field_charset);
- case FIELD_TYPE_NEWDATE:
- return new Field_newdate(ptr,null_pos,null_bit,
- 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, field_charset);
- case FIELD_TYPE_DATETIME:
- return new Field_datetime(ptr,null_pos,null_bit,
- unireg_check, field_name, table, field_charset);
- case FIELD_TYPE_NULL:
- return new Field_null(ptr,field_length,unireg_check,field_name,table, field_charset);
- default: // Impossible (Wrong version)
- break;
- }
- return 0;
- }
- /* Create a field suitable for create of table */
- create_field::create_field(Field *old_field,Field *orig_field)
- {
- field= old_field;
- field_name=change=old_field->field_name;
- length= old_field->field_length;
- flags= old_field->flags;
- unireg_check=old_field->unireg_check;
- pack_length=old_field->pack_length();
- sql_type= old_field->real_type();
- 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)
- pack_length= (pack_length- old_field->table->blob_ptr_size +
- portable_sizeof_char_ptr);
- switch (sql_type)
- {
- case FIELD_TYPE_BLOB:
- switch (pack_length - portable_sizeof_char_ptr)
- {
- case 1: sql_type= FIELD_TYPE_TINY_BLOB; break;
- case 2: sql_type= FIELD_TYPE_BLOB; break;
- case 3: sql_type= FIELD_TYPE_MEDIUM_BLOB; break;
- default: sql_type= FIELD_TYPE_LONG_BLOB; break;
- }
- length=(length+charset->mbmaxlen-1)/charset->mbmaxlen; // QQ: Probably not needed
- break;
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_VAR_STRING:
- length=(length+charset->mbmaxlen-1)/charset->mbmaxlen;
- break;
- default:
- break;
- }
- decimals= old_field->decimals();
- if (sql_type == FIELD_TYPE_STRING)
- {
- /* Change CHAR -> VARCHAR if dynamic record length */
- sql_type=old_field->type();
- decimals=0;
- }
- if (flags & (ENUM_FLAG | SET_FLAG))
- interval= ((Field_enum*) old_field)->typelib;
- else
- interval=0;
- def=0;
- if (!old_field->is_real_null() && ! (flags & BLOB_FLAG) &&
- old_field->ptr && orig_field)
- {
- char buff[MAX_FIELD_WIDTH],*pos;
- String tmp(buff,sizeof(buff), charset);
- /* 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 default_values
- bool is_null=orig_field->is_real_null();
- orig_field->val_str(&tmp);
- orig_field->move_field(-diff); // Back to record[0]
- if (!is_null)
- {
- pos= (char*) sql_memdup(tmp.ptr(),tmp.length()+1);
- pos[tmp.length()]=0;
- def= new Item_string(pos, tmp.length(), charset);
- }
- }
- #ifdef HAVE_SPATIAL
- if (sql_type == FIELD_TYPE_GEOMETRY)
- {
- geom_type= ((Field_geom*)old_field)->geom_type;
- }
- #endif
- }
- /* Warning handling */
- /*
- Produce warning or note about data saved into field
- SYNOPSYS
- set_warning()
- level - level of message (Note/Warning/Error)
- code - error code of message to be produced
- cuted_increment - whenever we should increase cut fields count or not
- NOTE
- This function won't produce warning and increase cut fields counter
- if count_cuted_fields == FIELD_CHECK_IGNORE for current thread.
- RETURN VALUE
- true - if count_cuted_fields == FIELD_CHECK_IGNORE
- false - otherwise
- */
- bool
- Field::set_warning(const uint level, const uint code, int cuted_increment)
- {
- THD *thd= table->in_use;
- if (thd->count_cuted_fields)
- {
- thd->cuted_fields+= cuted_increment;
- push_warning_printf(thd, (MYSQL_ERROR::enum_warning_level) level,
- code, ER(code), field_name, thd->row_count);
- return 0;
- }
- return 1;
- }
- /*
- Produce warning or note about datetime string data saved into field
- SYNOPSYS
- set_warning()
- level - level of message (Note/Warning/Error)
- code - error code of message to be produced
- str - string value which we tried to save
- str_len - length of string which we tried to save
- ts_type - type of datetime value (datetime/date/time)
- cuted_increment - whenever we should increase cut fields count or not
-
- NOTE
- This function will always produce some warning but won't increase cut
- fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current
- thread.
- */
- void
- Field::set_datetime_warning(const uint level, const uint code,
- const char *str, uint str_length,
- timestamp_type ts_type, int cuted_increment)
- {
- if (set_warning(level, code, cuted_increment))
- make_truncated_value_warning(table->in_use, str, str_length, ts_type);
- }
- /*
- Produce warning or note about integer datetime value saved into field
- SYNOPSYS
- set_warning()
- level - level of message (Note/Warning/Error)
- code - error code of message to be produced
- nr - numeric value which we tried to save
- ts_type - type of datetime value (datetime/date/time)
- cuted_increment - whenever we should increase cut fields count or not
-
- NOTE
- This function will always produce some warning but won't increase cut
- fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current
- thread.
- */
- void
- Field::set_datetime_warning(const uint level, const uint code,
- longlong nr, timestamp_type ts_type,
- int cuted_increment)
- {
- if (set_warning(level, code, cuted_increment))
- {
- char str_nr[22];
- char *str_end= longlong10_to_str(nr, str_nr, -10);
- make_truncated_value_warning(table->in_use, str_nr, str_end - str_nr,
- ts_type);
- }
- }
- /*
- Produce warning or note about double datetime data saved into field
- SYNOPSYS
- set_warning()
- level - level of message (Note/Warning/Error)
- code - error code of message to be produced
- nr - double value which we tried to save
- ts_type - type of datetime value (datetime/date/time)
-
- NOTE
- This function will always produce some warning but won't increase cut
- fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current
- thread.
- */
- void
- Field::set_datetime_warning(const uint level, const uint code,
- double nr, timestamp_type ts_type)
- {
- if (set_warning(level, code, 1))
- {
- /* DBL_DIG is enough to print '-[digits].E+###' */
- char str_nr[DBL_DIG + 8];
- uint str_len= my_sprintf(str_nr, (str_nr, "%g", nr));
- make_truncated_value_warning(table->in_use, str_nr, str_len, ts_type);
- }
- }
- /*
- maximum possible display length for blob
- SYNOPSIS
- Field_blob::max_length()
- RETURN
- length
- */
- uint32 Field_blob::max_length()
- {
- switch (packlength)
- {
- case 1:
- return 255;
- case 2:
- return 65535;
- case 3:
- return 16777215;
- case 4:
- return (uint32) 4294967295U;
- default:
- DBUG_ASSERT(0); // we should never go here
- return 0;
- }
- }