summaryrefslogtreecommitdiff
path: root/sql/field.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/field.cc')
-rw-r--r--sql/field.cc1476
1 files changed, 569 insertions, 907 deletions
diff --git a/sql/field.cc b/sql/field.cc
index aeaf1a7a21e..f5b43c69f63 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -27,15 +27,21 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
#include "sql_select.h"
#include "rpl_rli.h" // Pull in Relay_log_info
#include "slave.h" // Pull in rpl_master_has_bug()
+#include "strfunc.h" // find_type2, find_set
+#include "sql_time.h" // str_to_datetime_with_warn,
+ // str_to_time_with_warn,
+ // TIME_to_timestamp,
+ // make_time, make_date,
+ // make_truncated_value_warning
+#include "tztime.h" // struct Time_zone
+#include "filesort.h" // change_double_for_sort
+#include "log_event.h" // class Table_map_log_event
#include <m_ctype.h>
#include <errno.h>
-#ifdef HAVE_FCONVERT
-#include <floatingpoint.h>
-#endif
// Maximum allowed exponent value for converting string to decimal
#define MAX_EXPONENT 1024
@@ -63,7 +69,7 @@ static uint time_hires_bytes[MAX_DATETIME_PRECISION+1]= { 3, 4, 4, 5, 5, 5, 6 };
uchar Field_null::null[1]={1};
const char field_separator=',';
-#define DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE 320
+#define DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE FLOATING_POINT_BUFFER
#define LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE 128
#define DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE 128
#define BLOB_PACK_LENGTH_TO_MAX_LENGH(arg) \
@@ -72,6 +78,8 @@ const char field_separator=',';
#define ASSERT_COLUMN_MARKED_FOR_READ DBUG_ASSERT(!table || (!table->read_set || bitmap_is_set(table->read_set, field_index)))
#define ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED DBUG_ASSERT(!table || (!table->write_set || bitmap_is_set(table->write_set, field_index) || bitmap_is_set(table->vcol_set, field_index)))
+#define FLAGSTR(S,F) ((S) & (F) ? #F " " : "")
+
/*
Rules for merging different types of fields in UNION
@@ -1010,6 +1018,25 @@ test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend)
/**
+ Function to compare two unsigned integers for their relative order.
+ Used below. In an anonymous namespace to not clash with definitions
+ in other files.
+ */
+
+CPP_UNNAMED_NS_START
+
+int compare(unsigned int a, unsigned int b)
+{
+ if (a < b)
+ return -1;
+ if (b < a)
+ return 1;
+ return 0;
+}
+
+CPP_UNNAMED_NS_END
+
+/**
Detect Item_result by given field type of UNION merge result.
@param field_type given field type
@@ -1029,6 +1056,36 @@ Item_result Field::result_merge_type(enum_field_types field_type)
Static help functions
*****************************************************************************/
+/**
+ Output a warning for erroneous conversion of strings to numerical
+ values. For use with ER_TRUNCATED_WRONG_VALUE[_FOR_FIELD]
+
+ @param thd THD object
+ @param str pointer to string that failed to be converted
+ @param length length of string
+ @param cs charset for string
+ @param typestr string describing type converted to
+ @param error error value to output
+ @param field_name (for *_FOR_FIELD) name of field
+ @param row_num (for *_FOR_FIELD) row number
+ */
+static void push_numerical_conversion_warning(THD* thd, const char* str,
+ uint length, CHARSET_INFO* cs,
+ const char* typestr, int error,
+ const char* field_name="UNKNOWN",
+ ulong row_num=0)
+{
+ char buf[max(max(DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE,
+ LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE),
+ DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE)];
+
+ String tmp(buf, sizeof(buf), cs);
+ tmp.copy(str, length, cs);
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ error, ER(error), typestr, tmp.c_ptr(),
+ field_name, row_num);
+}
+
/**
Check whether a field type can be partially indexed by a key.
@@ -1122,14 +1179,12 @@ int Field_num::check_int(CHARSET_INFO *cs, const char *str, int length,
/* Test if we get an empty string or wrong integer */
if (str == int_end || error == MY_ERRNO_EDOM)
{
- char buff[128];
- String tmp(buff, (uint32) sizeof(buff), system_charset_info);
- tmp.copy(str, length, system_charset_info);
+ ErrConvString err(str, length, cs);
push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
- "integer", tmp.c_ptr(), field_name,
- (ulong) table->in_use->row_count);
+ "integer", err.ptr(), field_name,
+ (ulong) table->in_use->warning_info->current_row_for_warning());
return 1;
}
/* Test if we have garbage at the end of the given string. */
@@ -1236,61 +1291,6 @@ int Field::warn_if_overflow(int op_result)
}
-#ifdef NOT_USED
-static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
-{
- cs= system_charset_info; // QQ move test_if_real into CHARSET_INFO struct
-
- while (length && my_isspace(cs,*str))
- { // Allow start space
- length--; str++;
- }
- if (!length)
- return 0;
- if (*str == '+' || *str == '-')
- {
- length--; str++;
- if (!length || !(my_isdigit(cs,*str) || *str == '.'))
- return 0;
- }
- while (length && my_isdigit(cs,*str))
- {
- length--; str++;
- }
- if (!length)
- return 1;
- if (*str == '.')
- {
- length--; str++;
- while (length && my_isdigit(cs,*str))
- {
- length--; str++;
- }
- }
- if (!length)
- return 1;
- if (*str == 'E' || *str == 'e')
- {
- if (length < 3 || (str[1] != '+' && str[1] != '-') ||
- !my_isdigit(cs,str[2]))
- return 0;
- length-=3;
- str+=3;
- while (length && my_isdigit(cs,*str))
- {
- length--; str++;
- }
- }
- for (; length ; length--, str++)
- { // Allow end space
- if (!my_isspace(cs,*str))
- return 0;
- }
- return 1;
-}
-#endif
-
-
/**
Interpret field value as an integer but return the result as a string.
@@ -1343,7 +1343,7 @@ void Field::hash(ulong *nr, ulong *nr2)
else
{
uint len= pack_length();
- CHARSET_INFO *cs= charset();
+ CHARSET_INFO *cs= sort_charset();
cs->coll->hash_sort(cs, ptr, len, nr, nr2);
}
}
@@ -1381,24 +1381,48 @@ bool Field::send_binary(Protocol *protocol)
/**
Check to see if field size is compatible with destination.
- This method is used in row-based replication to verify that the slave's
- field size is less than or equal to the master's field size. The
- encoded field metadata (from the master or source) is decoded and compared
- to the size of this field (the slave or destination).
+ This method is used in row-based replication to verify that the
+ slave's field size is less than or equal to the master's field
+ size. The encoded field metadata (from the master or source) is
+ decoded and compared to the size of this field (the slave or
+ destination).
+
+ @note
+
+ The comparison is made so that if the source data (from the master)
+ is less than the target data (on the slave), -1 is returned in @c
+ <code>*order_var</code>. This implies that a conversion is
+ necessary, but that it is lossy and can result in truncation of the
+ value.
+
+ If the source data is strictly greater than the target data, 1 is
+ returned in <code>*order_var</code>. This implies that the source
+ type can is contained in the target type and that a conversion is
+ necessary but is non-lossy.
+
+ If no conversion is required to fit the source type in the target
+ type, 0 is returned in <code>*order_var</code>.
@param field_metadata Encoded size in field metadata
@param mflags Flags from the table map event for the table.
+ @param order_var Pointer to variable where the order
+ between the source field and this field
+ will be returned.
- @retval 0 if this field's size is < the source field's size
- @retval 1 if this field's size is >= the source field's size
+ @return @c true if this field's size is compatible with the
+ master's field size, @c false otherwise.
*/
-int Field::compatible_field_size(uint field_metadata,
- const Relay_log_info *rli_arg __attribute__((unused)),
- uint16 mflags __attribute__((unused)))
+bool Field::compatible_field_size(uint field_metadata,
+ Relay_log_info *rli_arg __attribute__((unused)),
+ uint16 mflags __attribute__((unused)),
+ int *order_var)
{
uint const source_size= pack_length_from_metadata(field_metadata);
uint const destination_size= row_pack_length();
- return (source_size <= destination_size);
+ DBUG_PRINT("debug", ("real_type: %d, source_size: %u, destination_size: %u",
+ real_type(), source_size, destination_size));
+ *order_var = compare(source_size, destination_size);
+ return true;
}
@@ -1533,7 +1557,12 @@ void Field::make_field(Send_field *field)
if (orig_table && orig_table->s->db.str && *orig_table->s->db.str)
{
field->db_name= orig_table->s->db.str;
- field->org_table_name= orig_table->s->table_name.str;
+ if (orig_table->pos_in_table_list &&
+ orig_table->pos_in_table_list->schema_table)
+ field->org_table_name= (orig_table->pos_in_table_list->
+ schema_table->table_name);
+ else
+ field->org_table_name= orig_table->s->table_name.str;
}
else
field->org_table_name= field->db_name= "";
@@ -1740,12 +1769,12 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
}
-bool Field::get_date(MYSQL_TIME *ltime,uint fuzzydate)
+bool Field::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
{
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_datetime_with_warn(res->ptr(), res->length(),
+ str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
return 1;
return 0;
@@ -1763,7 +1792,9 @@ int Field::store_time_dec(MYSQL_TIME *ltime, uint dec)
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
char buff[MAX_DATE_STRING_REP_LENGTH];
uint length= (uint) my_TIME_to_str(ltime, buff, dec);
- return store(buff, length, &my_charset_bin);
+ /* Avoid conversion when field character set is ASCII compatible */
+ return store(buff, length, (charset()->state & MY_CS_NONASCII) ?
+ &my_charset_latin1 : charset());
}
@@ -1773,7 +1804,7 @@ bool Field::optimize_range(uint idx, uint part)
}
-Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field::new_field(MEM_ROOT *root, TABLE *new_table,
bool keep_type __attribute__((unused)))
{
Field *tmp;
@@ -1794,7 +1825,7 @@ Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table,
}
-Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field::new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit)
{
@@ -1811,7 +1842,7 @@ Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table,
/* This is used to generate a field in TABLE from TABLE_SHARE */
-Field *Field::clone(MEM_ROOT *root, struct st_table *new_table)
+Field *Field::clone(MEM_ROOT *root, TABLE *new_table)
{
Field *tmp;
if ((tmp= (Field*) memdup_root(root,(char*) this,size_of())))
@@ -2272,13 +2303,7 @@ int Field_decimal::store(double nr)
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
fyllchar = zerofill ? (char) '0' : (char) ' ';
-#ifdef HAVE_SNPRINTF
- buff[sizeof(buff)-1]=0; // Safety
- snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr);
- length= strlen(buff);
-#else
- length= my_sprintf(buff,(buff,"%.*f",dec,nr));
-#endif
+ length= my_fcvt(nr, dec, buff, NULL);
if (length > field_length)
{
@@ -2361,7 +2386,7 @@ String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
size_t tmp_length;
for (str=ptr ; *str == ' ' ; str++) ;
- val_ptr->set_charset(&my_charset_bin);
+ val_ptr->set_charset(&my_charset_numeric);
tmp_length= (size_t) (str-ptr);
if (field_length < tmp_length) // Error in data
val_ptr->length(0);
@@ -2491,7 +2516,7 @@ Field *Field_new_decimal::create_from_item (Item *item)
{
uint8 dec= item->decimals;
uint8 intg= item->decimal_precision() - dec;
- uint32 len= item->max_length;
+ uint32 len= item->max_char_length();
DBUG_ASSERT (item->result_type() == DECIMAL_RESULT);
@@ -2634,15 +2659,12 @@ int Field_new_decimal::store(const char *from, uint length,
&decimal_value)) &&
table->in_use->abort_on_warning)
{
- /* Because "from" is not NUL-terminated and we use %s in the ER() */
- String from_as_str;
- from_as_str.copy(from, length, &my_charset_bin);
-
- push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ErrConvString errmsg(from, length, &my_charset_bin);
+ push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
- "decimal", from_as_str.c_ptr(), field_name,
- (ulong) table->in_use->row_count);
+ "decimal", errmsg.ptr(), field_name,
+ (ulong) table->in_use->warning_info->current_row_for_warning());
DBUG_RETURN(err);
}
@@ -2657,18 +2679,15 @@ int Field_new_decimal::store(const char *from, uint length,
break;
case E_DEC_BAD_NUM:
{
- /* Because "from" is not NUL-terminated and we use %s in the ER() */
- String from_as_str;
- from_as_str.copy(from, length, &my_charset_bin);
-
- push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
- ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
- "decimal", from_as_str.c_ptr(), field_name,
- (ulong) table->in_use->row_count);
- my_decimal_set_zero(&decimal_value);
-
- break;
+ ErrConvString errmsg(from, length, &my_charset_bin);
+ push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
+ ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+ "decimal", errmsg.ptr(), field_name,
+ (ulong) table->in_use->warning_info->
+ current_row_for_warning());
+ my_decimal_set_zero(&decimal_value);
+ break;
}
}
@@ -2697,17 +2716,6 @@ int Field_new_decimal::store(double nr)
err= double2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, nr,
&decimal_value);
- /*
- TODO: fix following when double2my_decimal when double2decimal
- will return E_DEC_TRUNCATED always correctly
- */
- if (!err)
- {
- double nr2;
- my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &nr2);
- if (nr2 != nr)
- err= E_DEC_TRUNCATED;
- }
if (err)
{
if (check_overflow(err))
@@ -2800,6 +2808,7 @@ String *Field_new_decimal::val_str(String *val_buffer,
uint fixed_precision= zerofill ? precision : 0;
my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
fixed_precision, dec, '0', val_buffer);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -2867,34 +2876,16 @@ uint Field_new_decimal::pack_length_from_metadata(uint field_metadata)
}
-/**
- Check to see if field size is compatible with destination.
-
- This method is used in row-based replication to verify that the slave's
- field size is less than or equal to the master's field size. The
- encoded field metadata (from the master or source) is decoded and compared
- to the size of this field (the slave or destination).
-
- @param field_metadata Encoded size in field metadata
-
- @retval 0 if this field's size is < the source field's size
- @retval 1 if this field's size is >= the source field's size
-*/
-int Field_new_decimal::compatible_field_size(uint field_metadata,
- const Relay_log_info * __attribute__((unused)),
- uint16 mflags __attribute__((unused)))
+bool Field_new_decimal::compatible_field_size(uint field_metadata,
+ Relay_log_info * __attribute__((unused)),
+ uint16 mflags __attribute__((unused)),
+ int *order_var)
{
- int compatible= 0;
uint const source_precision= (field_metadata >> 8U) & 0x00ff;
uint const source_decimal= field_metadata & 0x00ff;
- uint const source_size= my_decimal_get_binary_size(source_precision,
- source_decimal);
- uint const destination_size= row_pack_length();
- compatible= (source_size <= destination_size);
- if (compatible)
- compatible= (source_precision <= precision) &&
- (source_decimal <= decimals());
- return (compatible);
+ int order= compare(source_precision, precision);
+ *order_var= order != 0 ? order : compare(source_decimal, dec);
+ return true;
}
@@ -3100,7 +3091,7 @@ String *Field_tiny::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
- CHARSET_INFO *cs= &my_charset_bin;
+ CHARSET_INFO *cs= &my_charset_numeric;
uint length;
uint mlength=max(field_length+1,5*cs->mbmaxlen);
val_buffer->alloc(mlength);
@@ -3116,6 +3107,7 @@ String *Field_tiny::val_str(String *val_buffer,
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
+ val_buffer->set_charset(cs);
return val_buffer;
}
@@ -3281,7 +3273,7 @@ String *Field_short::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
- CHARSET_INFO *cs= &my_charset_bin;
+ CHARSET_INFO *cs= &my_charset_numeric;
uint length;
uint mlength=max(field_length+1,7*cs->mbmaxlen);
val_buffer->alloc(mlength);
@@ -3297,6 +3289,7 @@ String *Field_short::val_str(String *val_buffer,
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
+ val_buffer->set_charset(cs);
return val_buffer;
}
@@ -3470,7 +3463,7 @@ String *Field_medium::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
- CHARSET_INFO *cs= &my_charset_bin;
+ CHARSET_INFO *cs= &my_charset_numeric;
uint length;
uint mlength=max(field_length+1,10*cs->mbmaxlen);
val_buffer->alloc(mlength);
@@ -3481,6 +3474,7 @@ String *Field_medium::val_str(String *val_buffer,
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer); /* purecov: inspected */
+ val_buffer->set_charset(cs);
return val_buffer;
}
@@ -3658,7 +3652,7 @@ String *Field_long::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
- CHARSET_INFO *cs= &my_charset_bin;
+ CHARSET_INFO *cs= &my_charset_numeric;
uint length;
uint mlength=max(field_length+1,12*cs->mbmaxlen);
val_buffer->alloc(mlength);
@@ -3673,6 +3667,7 @@ String *Field_long::val_str(String *val_buffer,
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
+ val_buffer->set_charset(cs);
return val_buffer;
}
@@ -3807,7 +3802,7 @@ 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;
+ CHARSET_INFO *cs= &my_charset_numeric;
uint length;
uint mlength=max(field_length+1,22*cs->mbmaxlen);
val_buffer->alloc(mlength);
@@ -3820,6 +3815,7 @@ String *Field_longlong::val_str(String *val_buffer,
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
+ val_buffer->set_charset(cs);
return val_buffer;
}
@@ -3941,75 +3937,35 @@ String *Field_float::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
+ DBUG_ASSERT(!zerofill || field_length <= MAX_FIELD_CHARLENGTH);
float nr;
float4get(nr,ptr);
- uint to_length=max(field_length,70);
- val_buffer->alloc(to_length);
+ uint to_length= 70;
+ if (val_buffer->alloc(to_length))
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ return val_buffer;
+ }
+
char *to=(char*) val_buffer->ptr();
+ size_t len;
if (dec >= NOT_FIXED_DEC)
- {
- sprintf(to,"%-*.*g",(int) field_length,FLT_DIG,nr);
- to=strcend(to,' ');
- *to=0;
- }
+ len= my_gcvt(nr, MY_GCVT_ARG_FLOAT, to_length - 1, to, NULL);
else
{
-#ifdef HAVE_FCONVERT
- char buff[70],*pos=buff;
- int decpt,sign,tmp_dec=dec;
-
- VOID(sfconvert(&nr,tmp_dec,&decpt,&sign,buff));
- if (sign)
- {
- *to++='-';
- }
- if (decpt < 0)
- { /* val_buffer is < 0 */
- *to++='0';
- if (!tmp_dec)
- goto end;
- *to++='.';
- if (-decpt > tmp_dec)
- decpt= - (int) tmp_dec;
- tmp_dec=(uint) ((int) tmp_dec+decpt);
- while (decpt++ < 0)
- *to++='0';
- }
- else if (decpt == 0)
- {
- *to++= '0';
- if (!tmp_dec)
- goto end;
- *to++='.';
- }
- else
- {
- while (decpt-- > 0)
- *to++= *pos++;
- if (!tmp_dec)
- goto end;
- *to++='.';
- }
- while (tmp_dec--)
- *to++= *pos++;
-#else
-#ifdef HAVE_SNPRINTF
- to[to_length-1]=0; // Safety
- snprintf(to,to_length-1,"%.*f",dec,nr);
- to=strend(to);
-#else
- to+= my_sprintf(to,(to,"%.*f",dec,nr));
-#endif
-#endif
+ /*
+ We are safe here because the buffer length is 70, and
+ fabs(float) < 10^39, dec < NOT_FIXED_DEC. So the resulting string
+ will be not longer than 69 chars + terminating '\0'.
+ */
+ len= my_fcvt(nr, dec, to, NULL);
}
-#ifdef HAVE_FCONVERT
- end:
-#endif
- val_buffer->length((uint) (to-val_buffer->ptr()));
+ val_buffer->length((uint) len);
if (zerofill)
prepend_zeros(val_buffer);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -4038,7 +3994,7 @@ void Field_float::sort_string(uchar *to,uint length __attribute__((unused)))
else
{
#ifdef WORDS_BIGENDIAN
- memcpy_fixed(tmp,&nr,sizeof(nr));
+ memcpy(tmp, &nr, sizeof(nr));
#else
tmp[0]= ptr[3]; tmp[1]=ptr[2]; tmp[2]= ptr[1]; tmp[3]=ptr[0];
#endif
@@ -4185,8 +4141,12 @@ int truncate_double(double *nr, uint field_length, uint dec,
max_value*= log_10[order];
max_value-= 1.0 / log_10[dec];
- double tmp= rint((res - floor(res)) * log_10[dec]) / log_10[dec];
- res= floor(res) + tmp;
+ /* Check for infinity so we don't get NaN in calculations */
+ if (!my_isinf(res))
+ {
+ double tmp= rint((res - floor(res)) * log_10[dec]) / log_10[dec];
+ res= floor(res) + tmp;
+ }
}
if (res < -max_value)
@@ -4288,13 +4248,11 @@ longlong Field_double::val_int(void)
res= double_to_longlong(j, 0, &error);
if (error)
{
- char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
- String tmp(buf, sizeof(buf), &my_charset_latin1), *str;
- str= val_str(&tmp, 0);
+ ErrConvDouble err(j);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE), "INTEGER",
- str->c_ptr());
+ err.ptr());
}
return res;
}
@@ -4308,7 +4266,7 @@ my_decimal *Field_real::val_decimal(my_decimal *decimal_value)
}
-bool Field_real::get_date(MYSQL_TIME *ltime,uint fuzzydate)
+bool Field_real::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
{
ASSERT_COLUMN_MARKED_FOR_READ;
double nr= val_real();
@@ -4320,76 +4278,29 @@ String *Field_double::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
+ DBUG_ASSERT(!zerofill || field_length <= MAX_FIELD_CHARLENGTH);
double nr;
float8get(nr,ptr);
uint to_length= DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE;
- val_buffer->alloc(to_length);
+ if (val_buffer->alloc(to_length))
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ return val_buffer;
+ }
+
char *to=(char*) val_buffer->ptr();
+ size_t len;
if (dec >= NOT_FIXED_DEC)
- {
- sprintf(to,"%-*.*g",(int) field_length,DBL_DIG,nr);
- to=strcend(to,' ');
- }
+ len= my_gcvt(nr, MY_GCVT_ARG_DOUBLE, to_length - 1, to, NULL);
else
- {
-#ifdef HAVE_FCONVERT
- char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
- char *pos= buff;
- int decpt,sign,tmp_dec=dec;
-
- VOID(fconvert(nr,tmp_dec,&decpt,&sign,buff));
- if (sign)
- {
- *to++='-';
- }
- if (decpt < 0)
- { /* val_buffer is < 0 */
- *to++='0';
- if (!tmp_dec)
- goto end;
- *to++='.';
- if (-decpt > tmp_dec)
- decpt= - (int) tmp_dec;
- tmp_dec=(uint) ((int) tmp_dec+decpt);
- while (decpt++ < 0)
- *to++='0';
- }
- else if (decpt == 0)
- {
- *to++= '0';
- if (!tmp_dec)
- goto end;
- *to++='.';
- }
- else
- {
- while (decpt-- > 0)
- *to++= *pos++;
- if (!tmp_dec)
- goto end;
- *to++='.';
- }
- while (tmp_dec--)
- *to++= *pos++;
-#else
-#ifdef HAVE_SNPRINTF
- to[to_length-1]=0; // Safety
- snprintf(to,to_length-1,"%.*f",dec,nr);
- to=strend(to);
-#else
- to+= my_sprintf(to,(to,"%.*f",dec,nr));
-#endif
-#endif
- }
-#ifdef HAVE_FCONVERT
- end:
-#endif
+ len= my_fcvt(nr, dec, to, NULL);
- val_buffer->length((uint) (to-val_buffer->ptr()));
+ val_buffer->length((uint) len);
if (zerofill)
prepend_zeros(val_buffer);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -4507,7 +4418,7 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
unireg_check_arg, field_name_arg, cs)
{
/* For 4.0 MYD and 4.0 InnoDB compatibility */
- flags|= UNSIGNED_FLAG;
+ flags|= UNSIGNED_FLAG | BINARY_FLAG;
if (unireg_check != NONE && !share->timestamp_field)
{
/* This timestamp has auto-update */
@@ -4560,8 +4471,9 @@ my_time_t Field_timestamp::get_timestamp(ulong *sec_part) const
return sint4korr(ptr);
}
+
int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time,
- const Lazy_string *str,
+ const ErrConv *str,
bool was_cut,
bool have_smth_to_conv)
{
@@ -4604,7 +4516,7 @@ int Field_timestamp::store_time_dec(MYSQL_TIME *ltime, uint dec)
THD *thd= table->in_use;
int unused;
MYSQL_TIME l_time= *ltime;
- Lazy_string_time str(ltime);
+ ErrConvTime str(ltime);
bool valid= !check_date(&l_time, pack_time(&l_time) != 0,
(thd->variables.sql_mode & MODE_NO_ZERO_DATE) |
MODE_NO_ZERO_IN_DATE, &unused);
@@ -4618,11 +4530,11 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
MYSQL_TIME l_time;
int error;
int have_smth_to_conv;
- Lazy_string_str str(from, len);
+ ErrConvString str(from, len, cs);
THD *thd= table->in_use;
/* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
- have_smth_to_conv= (str_to_datetime(from, len, &l_time,
+ have_smth_to_conv= (str_to_datetime(cs, from, len, &l_time,
(thd->variables.sql_mode &
MODE_NO_ZERO_DATE) |
MODE_NO_ZERO_IN_DATE, &error) >
@@ -4635,7 +4547,7 @@ int Field_timestamp::store(double nr)
{
MYSQL_TIME l_time;
int error;
- Lazy_string_double str(nr);
+ ErrConvDouble str(nr);
THD *thd= table->in_use;
longlong tmp= double_to_datetime(nr, &l_time, (thd->variables.sql_mode &
@@ -4649,7 +4561,7 @@ int Field_timestamp::store(longlong nr, bool unsigned_val)
{
MYSQL_TIME l_time;
int error;
- Lazy_string_num str(nr);
+ ErrConvInteger str(nr);
THD *thd= table->in_use;
/* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
@@ -4668,54 +4580,34 @@ double Field_timestamp::val_real(void)
longlong Field_timestamp::val_int(void)
{
- MYSQL_TIME time_tmp;
- THD *thd= table->in_use;
-
- thd->time_zone_used= 1;
- ulong sec_part;
- my_time_t temp= get_timestamp(&sec_part);
-
- /*
- Field_timestamp() and Field_timestamp_hres() shares this code.
- This is why are also testing sec_part below.
- */
+ MYSQL_TIME ltime;
+ if (get_date(&ltime, TIME_NO_ZERO_DATE))
+ return 0;
- if (temp == 0 && sec_part == 0)
- return(0);
-
- thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t)temp);
-
- 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;
+ return ltime.year * 10000000000LL + ltime.month * 100000000LL +
+ ltime.day * 1000000L + ltime.hour * 10000L +
+ ltime.minute * 100 + ltime.second;
}
String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
{
- uint32 temp2;
- THD *thd= table->in_use;
- MYSQL_TIME time_tmp;
+ MYSQL_TIME ltime;
+ uint32 temp, temp2;
char *to;
val_buffer->alloc(field_length+1);
to= (char*) val_buffer->ptr();
val_buffer->length(field_length);
- thd->time_zone_used= 1;
- ulong sec_part;
- my_time_t temp= get_timestamp(&sec_part);
-
- if (temp == 0 && sec_part == 0)
+ if (get_date(&ltime, TIME_NO_ZERO_DATE))
{ /* Zero time is "000000" */
- val_ptr->set(zero_timestamp, field_length, &my_charset_bin);
+ val_ptr->set(zero_timestamp, field_length, &my_charset_numeric);
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);
-
- temp= time_tmp.year % 100;
+ val_buffer->set_charset(&my_charset_numeric); // Safety
+
+ temp= ltime.year % 100;
if (temp < YY_PART_YEAR - 1)
{
*to++= '2';
@@ -4730,36 +4622,37 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
*to++= (char) ('0'+(char) (temp2));
*to++= (char) ('0'+(char) (temp));
*to++= '-';
- temp=time_tmp.month;
+ temp=ltime.month;
temp2=temp/10; temp=temp-temp2*10;
*to++= (char) ('0'+(char) (temp2));
*to++= (char) ('0'+(char) (temp));
*to++= '-';
- temp=time_tmp.day;
+ temp=ltime.day;
temp2=temp/10; temp=temp-temp2*10;
*to++= (char) ('0'+(char) (temp2));
*to++= (char) ('0'+(char) (temp));
*to++= ' ';
- temp=time_tmp.hour;
+ temp=ltime.hour;
temp2=temp/10; temp=temp-temp2*10;
*to++= (char) ('0'+(char) (temp2));
*to++= (char) ('0'+(char) (temp));
*to++= ':';
- temp=time_tmp.minute;
+ temp=ltime.minute;
temp2=temp/10; temp=temp-temp2*10;
*to++= (char) ('0'+(char) (temp2));
*to++= (char) ('0'+(char) (temp));
*to++= ':';
- temp=time_tmp.second;
+ temp=ltime.second;
temp2=temp/10; temp=temp-temp2*10;
*to++= (char) ('0'+(char) (temp2));
*to++= (char) ('0'+(char) (temp));
*to= 0;
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
-bool Field_timestamp::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+bool Field_timestamp::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
THD *thd= table->in_use;
thd->time_zone_used= 1;
@@ -4922,21 +4815,13 @@ my_time_t Field_timestamp_hires::get_timestamp(ulong *sec_part) const
double Field_timestamp_hires::val_real(void)
{
- MYSQL_TIME time_tmp;
- THD *thd= table->in_use;
-
- thd->time_zone_used= 1;
- ulong sec_part;
- my_time_t temp= get_timestamp(&sec_part);
-
- if (temp == 0 && sec_part == 0)
- return(0);
-
- thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t)temp);
+ MYSQL_TIME ltime;
+ if (get_date(&ltime, TIME_NO_ZERO_DATE))
+ return 0;
- return time_tmp.year * 1e10 + time_tmp.month * 1e8 +
- time_tmp.day * 1e6 + time_tmp.hour * 1e4 +
- time_tmp.minute * 1e2 + time_tmp.second + sec_part*1e-6;
+ return ltime.year * 1e10 + ltime.month * 1e8 +
+ ltime.day * 1e6 + ltime.hour * 1e4 +
+ ltime.minute * 1e2 + ltime.second + ltime.second_part*1e-6;
}
String *Field_timestamp_hires::val_str(String *val_buffer, String *val_ptr)
@@ -4972,7 +4857,7 @@ int Field_timestamp_hires::store_decimal(const my_decimal *d)
MYSQL_TIME ltime;
longlong tmp;
THD *thd= table->in_use;
- Lazy_string_decimal str(d);
+ ErrConvDecimal str(d);
if (my_decimal2seconds(d, &nr, &sec_part))
{
@@ -5044,7 +4929,7 @@ void Field_timestamp_hires::make_field(Send_field *field)
This is used by opt_range.cc:get_mm_leaf().
*/
int Field_temporal::store_TIME_with_warning(MYSQL_TIME *ltime,
- const Lazy_string *str,
+ const ErrConv *str,
int was_cut, int have_smth_to_conv)
{
MYSQL_ERROR::enum_warning_level trunc_level= MYSQL_ERROR::WARN_LEVEL_WARN;
@@ -5054,7 +4939,7 @@ int Field_temporal::store_TIME_with_warning(MYSQL_TIME *ltime,
if (was_cut == 0 &&
have_smth_to_conv == 0 &&
- temporal_type() != MYSQL_TIMESTAMP_TIME) // special case: zero date
+ mysql_type_to_time_type(type()) != MYSQL_TIMESTAMP_TIME) // special case: zero date
was_cut= MYSQL_TIME_WARN_OUT_OF_RANGE;
else
if (!have_smth_to_conv)
@@ -5064,7 +4949,7 @@ int Field_temporal::store_TIME_with_warning(MYSQL_TIME *ltime,
ret= 1;
}
else if (!(was_cut & MYSQL_TIME_WARN_TRUNCATED) &&
- temporal_type() == MYSQL_TIMESTAMP_DATE &&
+ mysql_type_to_time_type(type()) == MYSQL_TIMESTAMP_DATE &&
(ltime->hour || ltime->minute || ltime->second || ltime->second_part))
{
trunc_level= MYSQL_ERROR::WARN_LEVEL_NOTE;
@@ -5072,7 +4957,7 @@ int Field_temporal::store_TIME_with_warning(MYSQL_TIME *ltime,
ret= 3;
}
else if (!(was_cut & MYSQL_TIME_WARN_TRUNCATED) &&
- temporal_type() == MYSQL_TIMESTAMP_TIME &&
+ mysql_type_to_time_type(type()) == MYSQL_TIMESTAMP_TIME &&
(ltime->year || ltime->month))
{
ltime->year= ltime->month= ltime->day= 0;
@@ -5093,10 +4978,10 @@ int Field_temporal::store_TIME_with_warning(MYSQL_TIME *ltime,
*/
if (was_cut & MYSQL_TIME_WARN_TRUNCATED)
set_datetime_warning(trunc_level, WARN_DATA_TRUNCATED,
- str, temporal_type(), 1);
+ str, mysql_type_to_time_type(type()), 1);
if (was_cut & MYSQL_TIME_WARN_OUT_OF_RANGE)
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE,
- str, temporal_type(), 1);
+ str, mysql_type_to_time_type(type()), 1);
store_TIME(ltime);
return was_cut ? ret : 0;
@@ -5109,9 +4994,9 @@ int Field_temporal::store(const char *from,uint len,CHARSET_INFO *cs)
int error;
enum enum_mysql_timestamp_type func_res;
THD *thd= table->in_use;
- Lazy_string_str str(from, len);
+ ErrConvString str(from, len, cs);
- func_res= str_to_datetime(from, len, &ltime,
+ func_res= str_to_datetime(cs, from, len, &ltime,
(TIME_FUZZY_DATE |
(thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
@@ -5126,7 +5011,7 @@ int Field_temporal::store(double nr)
int error= 0;
MYSQL_TIME ltime;
THD *thd= table->in_use;
- Lazy_string_double str(nr);
+ ErrConvDouble str(nr);
longlong tmp= double_to_datetime(nr, &ltime,
(TIME_FUZZY_DATE |
@@ -5144,7 +5029,7 @@ int Field_temporal::store(longlong nr, bool unsigned_val)
MYSQL_TIME ltime;
longlong tmp;
THD *thd= table->in_use;
- Lazy_string_num str(nr);
+ ErrConvInteger str(nr);
tmp= number_to_datetime(nr, 0, &ltime, (TIME_FUZZY_DATE |
(thd->variables.sql_mode &
@@ -5160,7 +5045,7 @@ int Field_temporal::store_time_dec(MYSQL_TIME *ltime, uint dec)
{
int error = 0, have_smth_to_conv= 1;
MYSQL_TIME l_time= *ltime;
- Lazy_string_time str(ltime);
+ ErrConvTime str(ltime);
/*
We don't perform range checking here since values stored in TIME
structure always fit into DATETIME range.
@@ -5204,15 +5089,15 @@ void Field_time::store_TIME(MYSQL_TIME *ltime)
int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
{
MYSQL_TIME ltime;
- Lazy_string_str str(from, len);
+ ErrConvString str(from, len, cs);
int was_cut;
int have_smth_to_conv=
- str_to_time(from, len, &ltime,
+ str_to_time(cs, from, len, &ltime,
table->in_use->variables.sql_mode &
(MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
MODE_INVALID_DATES),
&was_cut) > MYSQL_TIMESTAMP_ERROR;
-
+
return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
}
@@ -5220,7 +5105,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_time::store_time_dec(MYSQL_TIME *ltime, uint dec)
{
MYSQL_TIME l_time= *ltime;
- Lazy_string_time str(ltime);
+ ErrConvTime str(ltime);
int was_cut= 0;
int have_smth_to_conv= !check_time_range(&l_time, decimals(), &was_cut);
@@ -5231,7 +5116,7 @@ int Field_time::store_time_dec(MYSQL_TIME *ltime, uint dec)
int Field_time::store(double nr)
{
MYSQL_TIME ltime;
- Lazy_string_double str(nr);
+ ErrConvDouble str(nr);
int was_cut;
bool neg= nr < 0;
if (neg)
@@ -5247,7 +5132,7 @@ int Field_time::store(double nr)
int Field_time::store(longlong nr, bool unsigned_val)
{
MYSQL_TIME ltime;
- Lazy_string_num str(nr);
+ ErrConvInteger str(nr);
int was_cut;
int have_smth_to_conv= !number_to_time(nr < 0, nr < 0 ? -nr : nr,
0, &ltime, &was_cut);
@@ -5299,7 +5184,7 @@ String *Field_time::val_str(String *val_buffer,
uint length= (uint) my_time_to_str(&ltime,
const_cast<char*>(val_buffer->ptr()), 0);
val_buffer->length(length);
- val_buffer->set_charset(&my_charset_bin);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -5312,7 +5197,7 @@ String *Field_time::val_str(String *val_buffer,
DATE_FORMAT(time, "%l.%i %p")
*/
-bool Field_time::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+bool Field_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
THD *thd= table->in_use;
if (!(fuzzydate & (TIME_FUZZY_DATE|TIME_TIME_ONLY)))
@@ -5320,7 +5205,7 @@ bool Field_time::get_date(MYSQL_TIME *ltime, uint fuzzydate)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
ER(ER_WARN_DATA_OUT_OF_RANGE), field_name,
- thd->row_count);
+ thd->warning_info->current_row_for_warning());
return 1;
}
long tmp=(long) sint3korr(ptr);
@@ -5375,6 +5260,7 @@ int Field_time_hires::reset()
return 0;
}
+
void Field_time_hires::store_TIME(MYSQL_TIME *ltime)
{
ulonglong packed= sec_part_shift(pack_time(ltime), dec) + zero_point;
@@ -5385,7 +5271,7 @@ int Field_time_hires::store_decimal(const my_decimal *d)
{
ulonglong nr;
ulong sec_part;
- Lazy_string_decimal str(d);
+ ErrConvDecimal str(d);
MYSQL_TIME ltime;
int was_cut;
bool neg= my_decimal2seconds(d, &nr, &sec_part);
@@ -5429,7 +5315,7 @@ String *Field_time_hires::val_str(String *str,
return str;
}
-bool Field_time_hires::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+bool Field_time_hires::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
uint32 len= pack_length();
longlong packed= read_bigendian(ptr, len);
@@ -5439,7 +5325,7 @@ bool Field_time_hires::get_date(MYSQL_TIME *ltime, uint fuzzydate)
unpack_time(packed, ltime);
/*
unpack_time() returns MYSQL_TIMESTAMP_DATETIME.
- To get MYSQL_TIMESTAMP_TIME we few adjustments
+ To get MYSQL_TIMESTAMP_TIME we need few adjustments
*/
ltime->time_type= MYSQL_TIMESTAMP_TIME;
ltime->hour+= (ltime->month*32+ltime->day)*24;
@@ -5560,7 +5446,7 @@ int Field_year::store(longlong nr, bool unsigned_val)
int Field_year::store_time_dec(MYSQL_TIME *ltime, uint dec)
{
- Lazy_string_time str(ltime);
+ ErrConvTime str(ltime);
if (Field_year::store(ltime->year, 0))
return 1;
@@ -5604,11 +5490,12 @@ String *Field_year::val_str(String *val_buffer,
val_buffer->length(field_length);
char *to=(char*) val_buffer->ptr();
sprintf(to,field_length == 2 ? "%02d" : "%04d",(int) Field_year::val_int());
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
-bool Field_year::get_date(MYSQL_TIME *ltime,uint fuzzydate)
+bool Field_year::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
{
int tmp= (int) ptr[0];
if (tmp || field_length != 4)
@@ -5683,7 +5570,7 @@ String *Field_date::val_str(String *val_buffer,
uint length= (uint) my_date_to_str(&ltime,
const_cast<char*>(val_buffer->ptr()));
val_buffer->length(length);
- val_buffer->set_charset(&my_charset_bin);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
@@ -5774,11 +5661,12 @@ String *Field_newdate::val_str(String *val_buffer,
*pos--= (char) ('0'+part%10); part/=10;
*pos--= (char) ('0'+part%10); part/=10;
*pos= (char) ('0'+part);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
-bool Field_newdate::get_date(MYSQL_TIME *ltime,uint fuzzydate)
+bool Field_newdate::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
{
uint32 tmp=(uint32) uint3korr(ptr);
ltime->day= tmp & 31;
@@ -5894,10 +5782,11 @@ String *Field_datetime::val_str(String *val_buffer,
*pos--= (char) ('0'+(char) (part3%10)); part3/=10;
*pos--= (char) ('0'+(char) (part3%10)); part3/=10;
*pos=(char) ('0'+(char) part3);
+ val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
-bool Field_datetime::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+bool Field_datetime::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
longlong tmp=Field_datetime::val_int();
uint32 part1,part2;
@@ -5914,7 +5803,7 @@ bool Field_datetime::get_date(MYSQL_TIME *ltime, uint fuzzydate)
ltime->month= (int) (part1/100%100);
ltime->year= (int) (part1/10000);
if (!tmp)
- return (fuzzydate & TIME_NO_ZERO_DATE) != 0;
+ return fuzzydate & TIME_NO_ZERO_DATE;
if (!ltime->month || !ltime->day)
return !(fuzzydate & TIME_FUZZY_DATE);
return 0;
@@ -5950,7 +5839,7 @@ void Field_datetime::sql_type(String &res) const
void Field_datetime_hires::store_TIME(MYSQL_TIME *ltime)
{
ulonglong packed= sec_part_shift(pack_time(ltime), dec);
- store_bigendian(packed, ptr, pack_length());
+ store_bigendian(packed, ptr, Field_datetime_hires::pack_length());
}
int Field_datetime_hires::store_decimal(const my_decimal *d)
@@ -5961,7 +5850,7 @@ int Field_datetime_hires::store_decimal(const my_decimal *d)
MYSQL_TIME ltime;
longlong tmp;
THD *thd= table->in_use;
- Lazy_string_decimal str(d);
+ ErrConvDecimal str(d);
if (my_decimal2seconds(d, &nr, &sec_part))
{
@@ -6013,9 +5902,9 @@ String *Field_datetime_hires::val_str(String *str,
return str;
}
-bool Field_datetime_hires::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+bool Field_datetime_hires::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
- ulonglong packed= read_bigendian(ptr, pack_length());
+ ulonglong packed= read_bigendian(ptr, Field_datetime_hires::pack_length());
unpack_time(sec_part_unshift(packed, dec), ltime);
if (!packed)
return fuzzydate & TIME_NO_ZERO_DATE;
@@ -6031,15 +5920,15 @@ uint32 Field_datetime_hires::pack_length() const
int Field_datetime_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
- ulonglong a=read_bigendian(a_ptr, pack_length());
- ulonglong b=read_bigendian(b_ptr, pack_length());
+ ulonglong a=read_bigendian(a_ptr, Field_datetime_hires::pack_length());
+ ulonglong b=read_bigendian(b_ptr, Field_datetime_hires::pack_length());
return a < b ? -1 : a > b ? 1 : 0;
}
void Field_datetime_hires::sort_string(uchar *to,
uint length __attribute__((unused)))
{
- DBUG_ASSERT(length == pack_length());
+ DBUG_ASSERT(length == Field_datetime_hires::pack_length());
memcpy(to, ptr, length);
}
@@ -6097,21 +5986,20 @@ check_string_copy_error(Field_str *field,
{
const char *pos;
char tmp[32];
-
+ THD *thd= field->table->in_use;
+
if (!(pos= well_formed_error_pos) &&
!(pos= cannot_convert_error_pos))
return FALSE;
convert_to_printable(tmp, sizeof(tmp), pos, (end - pos), cs, 6);
- push_warning_printf(field->table->in_use,
- field->table->in_use->abort_on_warning ?
- MYSQL_ERROR::WARN_LEVEL_ERROR :
+ push_warning_printf(thd,
MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
+ ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
"string", tmp, field->field_name,
- (ulong) field->table->in_use->row_count);
+ thd->warning_info->current_row_for_warning());
return TRUE;
}
@@ -6145,7 +6033,7 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end,
if (test_if_important_data(field_charset, pstr, end))
{
if (table->in_use->abort_on_warning)
- set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1);
else
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
return 2;
@@ -6207,91 +6095,22 @@ int Field_str::store(double nr)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
- uint length;
uint local_char_length= field_length / charset()->mbmaxlen;
- double anr= fabs(nr);
- bool fractional= (anr != floor(anr));
- int neg= (nr < 0.0) ? 1 : 0;
- uint max_length;
- int exp;
- uint digits;
- uint i;
-
- /* Calculate the exponent from the 'e'-format conversion */
- if (anr < 1.0 && anr > 0)
- {
- for (exp= 0; anr < 1e-100; exp-= 100, anr*= 1e100)
- ;
- for (; anr < 1e-10; exp-= 10, anr*= 1e10)
- ;
- for (i= 1; anr < 1 / log_10[i]; exp--, i++)
- ;
- exp--;
- }
- else
- {
- for (exp= 0; anr > 1e100; exp+= 100, anr/= 1e100)
- ;
- for (; anr > 1e10; exp+= 10, anr/= 1e10)
- ;
- for (i= 1; anr > log_10[i]; exp++, i++)
- ;
- }
-
- max_length= local_char_length - neg;
-
- /*
- Since in sprintf("%g") precision means the number of significant digits,
- calculate the maximum number of significant digits if the 'f'-format
- would be used (+1 for decimal point if the number has a fractional part).
- */
- digits= max(1, (int) max_length - fractional);
- /*
- If the exponent is negative, decrease digits by the number of leading zeros
- after the decimal point that do not count as significant digits.
- */
- if (exp < 0)
- digits= max(1, (int) digits + exp);
- /*
- 'e'-format is used only if the exponent is less than -4 or greater than or
- equal to the precision. In this case we need to adjust the number of
- significant digits to take "e+NN" + decimal point into account (hence -5).
- We also have to reserve one additional character if abs(exp) >= 100.
- */
- if (exp >= (int) digits || exp < -4)
- digits= max(1, (int) (max_length - 5 - (exp >= 100 || exp <= -100)));
+ size_t length= 0;
+ my_bool error= (local_char_length == 0);
- /* Limit precision to DBL_DIG to avoid garbage past significant digits */
- set_if_smaller(digits, DBL_DIG);
-
- length= (uint) my_sprintf(buff, (buff, "%-.*g", digits, nr));
+ // my_gcvt() requires width > 0, and we may have a CHAR(0) column.
+ if (!error)
+ length= my_gcvt(nr, MY_GCVT_ARG_DOUBLE, local_char_length, buff, &error);
-#ifdef __WIN__
- /*
- Windows always zero-pads the exponent to 3 digits, we want to remove the
- leading 0 to match the sprintf() output on other platforms.
- */
- if ((exp >= (int) digits || exp < -4) && exp > -100 && exp < 100)
+ if (error)
{
- DBUG_ASSERT(length >= 6); /* 1e+NNN */
- uint tmp= length - 3;
- buff[tmp]= buff[tmp + 1];
- tmp++;
- buff[tmp]= buff[tmp + 1];
- length--;
+ if (table->in_use->abort_on_warning)
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1);
+ else
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
}
-#endif
-
- /*
- +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 local_char_length < 5 is for extreme cases,
- like inserting 500.0 in char(1)
- */
- DBUG_ASSERT(local_char_length < 5 || length <= local_char_length+1);
- return store(buff, length, charset());
+ return store(buff, length, &my_charset_numeric);
}
@@ -6326,7 +6145,7 @@ int Field_string::store(longlong nr, bool unsigned_val)
int Field_longstr::store_decimal(const my_decimal *d)
{
char buff[DECIMAL_MAX_STR_LENGTH+1];
- String str(buff, sizeof(buff), &my_charset_bin);
+ String str(buff, sizeof(buff), &my_charset_numeric);
my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
return store(str.ptr(), str.length(), str.charset());
}
@@ -6351,13 +6170,11 @@ double Field_string::val_real(void)
!check_if_only_end_space(cs, end,
(char*) ptr + field_length))))
{
- char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
- String tmp(buf, sizeof(buf), cs);
- tmp.copy((char*) ptr, field_length, cs);
+ ErrConvString err((char*) ptr, field_length, cs);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRUNCATED_WRONG_VALUE,
- ER(ER_TRUNCATED_WRONG_VALUE),
- "DOUBLE", tmp.c_ptr());
+ ER_TRUNCATED_WRONG_VALUE,
+ ER(ER_TRUNCATED_WRONG_VALUE), "DOUBLE",
+ err.ptr());
}
return result;
}
@@ -6377,13 +6194,11 @@ longlong Field_string::val_int(void)
!check_if_only_end_space(cs, end,
(char*) ptr + field_length))))
{
- char buf[LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE];
- String tmp(buf, sizeof(buf), cs);
- tmp.copy((char*) ptr, field_length, cs);
+ ErrConvString err((char*) ptr, field_length, cs);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE),
- "INTEGER", tmp.c_ptr());
+ "INTEGER", err.ptr());
}
return result;
}
@@ -6415,14 +6230,11 @@ my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
charset(), decimal_value);
if (!table->in_use->no_errors && err)
{
- char buf[DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE];
- CHARSET_INFO *cs= charset();
- String tmp(buf, sizeof(buf), cs);
- tmp.copy((char*) ptr, field_length, cs);
+ ErrConvString errmsg((char*) ptr, field_length, charset());
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE),
- "DECIMAL", tmp.c_ptr());
+ "DECIMAL", errmsg.ptr());
}
return decimal_value;
@@ -6447,9 +6259,11 @@ check_field_for_37426(const void *param_arg)
}
#endif
-int Field_string::compatible_field_size(uint field_metadata,
- const Relay_log_info *rli_arg,
- uint16 mflags __attribute__((unused)))
+bool
+Field_string::compatible_field_size(uint field_metadata,
+ Relay_log_info *rli_arg,
+ uint16 mflags __attribute__((unused)),
+ int *order_var)
{
#ifdef HAVE_REPLICATION
const Check_field_param check_param = { this };
@@ -6457,7 +6271,7 @@ int Field_string::compatible_field_size(uint field_metadata,
check_field_for_37426, &check_param))
return FALSE; // Not compatible field sizes
#endif
- return Field::compatible_field_size(field_metadata, rli_arg, mflags);
+ return Field::compatible_field_size(field_metadata, rli_arg, mflags, order_var);
}
@@ -6486,9 +6300,8 @@ int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
void Field_string::sort_string(uchar *to,uint length)
{
- IF_DBUG(uint tmp=) my_strnxfrm(field_charset,
- to, length,
- ptr, field_length);
+ uint tmp __attribute__((unused))=
+ my_strnxfrm(field_charset, to, length, ptr, field_length);
DBUG_ASSERT(tmp == length);
}
@@ -6516,12 +6329,26 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
{
uint length= min(field_length,max_length);
uint local_char_length= max_length/field_charset->mbmaxlen;
+ DBUG_PRINT("debug", ("Packing field '%s' - length: %u ", field_name, length));
+
if (length > local_char_length)
local_char_length= my_charpos(field_charset, from, from+length,
local_char_length);
set_if_smaller(length, local_char_length);
- while (length && from[length-1] == field_charset->pad_char)
- length--;
+
+ /*
+ TODO: change charset interface to add a new function that does
+ the following or add a flag to lengthsp to do it itself
+ (this is for not packing padding adding bytes in BINARY
+ fields).
+ */
+ if (field_charset->mbmaxlen == 1)
+ {
+ while (length && from[length-1] == field_charset->pad_char)
+ length --;
+ }
+ else
+ length= field_charset->cset->lengthsp(field_charset, (const char*) from, length);
// Length always stored little-endian
*to++= (uchar) length;
@@ -6593,7 +6420,7 @@ Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end,
memcpy(to, from, length);
// Pad the string with the pad character of the fields charset
- bfill(to + length, field_length - length, field_charset->pad_char);
+ field_charset->cset->fill(field_charset, (char*) to + length, field_length - length, field_charset->pad_char);
return from+length;
}
@@ -6640,86 +6467,6 @@ int Field_string::do_save_field_metadata(uchar *metadata_ptr)
}
-/*
- Compare two packed keys
-
- SYNOPSIS
- pack_cmp()
- a New key
- b Original key
- length Key length
- insert_or_update 1 if this is an insert or update
-
- RETURN
- < 0 a < b
- 0 a = b
- > 0 a > b
-*/
-
-int Field_string::pack_cmp(const uchar *a, const uchar *b, uint length,
- bool insert_or_update)
-{
- uint a_length, b_length;
- if (length > 255)
- {
- a_length= uint2korr(a);
- b_length= uint2korr(b);
- a+= 2;
- b+= 2;
- }
- else
- {
- a_length= (uint) *a++;
- b_length= (uint) *b++;
- }
- return field_charset->coll->strnncollsp(field_charset,
- a, a_length,
- b, b_length,
- insert_or_update);
-}
-
-
-/**
- Compare a packed key against row.
-
- @param key Original key
- @param length Key length. (May be less than field length)
- @param insert_or_update 1 if this is an insert or update
-
- @return
- < 0 row < key
- @return
- 0 row = key
- @return
- > 0 row > key
-*/
-
-int Field_string::pack_cmp(const uchar *key, uint length,
- bool insert_or_update)
-{
- uint row_length, local_key_length;
- uchar *end;
- if (length > 255)
- {
- local_key_length= uint2korr(key);
- key+= 2;
- }
- else
- local_key_length= (uint) *key++;
-
- /* Only use 'length' of key, not field_length */
- end= ptr + length;
- while (end > ptr && end[-1] == ' ')
- end--;
- row_length= (uint) (end - ptr);
-
- return field_charset->coll->strnncollsp(field_charset,
- ptr, row_length,
- key, local_key_length,
- insert_or_update);
-}
-
-
uint Field_string::packed_col_length(const uchar *data_ptr, uint length)
{
if (length > 255)
@@ -6747,7 +6494,7 @@ uint Field_string::get_key_image(uchar *buff, uint length, imagetype type_arg)
}
-Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field_string::new_field(MEM_ROOT *root, TABLE *new_table,
bool keep_type)
{
Field *field;
@@ -6857,22 +6604,46 @@ int Field_varstring::store(longlong nr, bool unsigned_val)
double Field_varstring::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- int not_used;
- char *end_not_used;
+ int error;
+ char *end;
+ double result;
+ CHARSET_INFO* cs= charset();
+
uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- return my_strntod(field_charset, (char*) ptr+length_bytes, length,
- &end_not_used, &not_used);
+ result= my_strntod(cs, (char*)ptr+length_bytes, length, &end, &error);
+
+ if (!table->in_use->no_errors &&
+ (error || (length != (uint)(end - (char*)ptr+length_bytes) &&
+ !check_if_only_end_space(cs, end, (char*)ptr+length_bytes+length))))
+ {
+ push_numerical_conversion_warning(current_thd, (char*)ptr+length_bytes,
+ length, cs,"DOUBLE",
+ ER_TRUNCATED_WRONG_VALUE);
+ }
+ return result;
}
longlong Field_varstring::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- int not_used;
- char *end_not_used;
+ int error;
+ char *end;
+ CHARSET_INFO *cs= charset();
+
uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- return my_strntoll(field_charset, (char*) ptr+length_bytes, length, 10,
- &end_not_used, &not_used);
+ longlong result= my_strntoll(cs, (char*) ptr+length_bytes, length, 10,
+ &end, &error);
+
+ if (!table->in_use->no_errors &&
+ (error || (length != (uint)(end - (char*)ptr+length_bytes) &&
+ !check_if_only_end_space(cs, end, (char*)ptr+length_bytes+length))))
+ {
+ push_numerical_conversion_warning(current_thd, (char*)ptr+length_bytes,
+ length, cs, "INTEGER",
+ ER_TRUNCATED_WRONG_VALUE);
+ }
+ return result;
}
String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
@@ -6888,9 +6659,17 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value)
{
ASSERT_COLUMN_MARKED_FOR_READ;
+ CHARSET_INFO *cs= charset();
uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr+length_bytes, length,
- charset(), decimal_value);
+ int error= str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr+length_bytes, length,
+ cs, decimal_value);
+
+ if (!table->in_use->no_errors && error)
+ {
+ push_numerical_conversion_warning(current_thd, (char*)ptr+length_bytes,
+ length, cs, "DECIMAL",
+ ER_TRUNCATED_WRONG_VALUE);
+ }
return decimal_value;
}
@@ -7044,89 +6823,6 @@ uchar *Field_varstring::pack(uchar *to, const uchar *from, uint max_length)
}
-uchar *
-Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length)
-{
- uint length= length_bytes == 1 ? (uint) *key : uint2korr(key);
- uint local_char_length= ((field_charset->mbmaxlen > 1) ?
- max_length/field_charset->mbmaxlen : max_length);
- key+= length_bytes;
- if (length > local_char_length)
- {
- local_char_length= my_charpos(field_charset, key, key+length,
- local_char_length);
- set_if_smaller(length, local_char_length);
- }
- *to++= (char) (length & 255);
- if (max_length > 255)
- *to++= (char) (length >> 8);
- if (length)
- memcpy(to, key, length);
- return to+length;
-}
-
-
-/**
- Unpack a key into a record buffer.
-
- A VARCHAR 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'.
-
- @param to Pointer into the record buffer.
- @param key Pointer to the packed key.
- @param max_length Key length limit from key description.
-
- @return
- Pointer to end of 'key' (To the next key part if multi-segment key)
-*/
-
-#ifdef NOT_USED
-const uchar *
-Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length)
-{
- /* get length of the blob key */
- uint32 length= *key++;
- if (max_length > 255)
- length+= (*key++) << 8;
-
- /* put the length into the record buffer */
- if (length_bytes == 1)
- *ptr= (uchar) length;
- else
- int2store(ptr, length);
- memcpy(ptr + length_bytes, key, length);
- return key + length;
-}
-#endif
-
-/**
- Create a packed key that will be used for storage in the index tree.
-
- @param to Store packed key segment here
- @param from Key segment (as given to index_read())
- @param max_length Max length of key
-
- @return
- end of key storage
-*/
-
-uchar * Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from,
- uint max_length)
-{
- /* Key length is always stored as 2 bytes */
- 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;
-}
-
-
/**
Unpack a varstring field from row data.
@@ -7176,59 +6872,6 @@ Field_varstring::unpack(uchar *to, const uchar *from, const uchar *from_end,
}
-int Field_varstring::pack_cmp(const uchar *a, const uchar *b,
- uint key_length_arg,
- bool insert_or_update)
-{
- uint a_length, b_length;
- if (key_length_arg > 255)
- {
- a_length=uint2korr(a); a+= 2;
- b_length=uint2korr(b); b+= 2;
- }
- else
- {
- a_length= (uint) *a++;
- b_length= (uint) *b++;
- }
- return field_charset->coll->strnncollsp(field_charset,
- a, a_length,
- b, b_length,
- insert_or_update);
-}
-
-
-int Field_varstring::pack_cmp(const uchar *b, uint key_length_arg,
- bool insert_or_update)
-{
- uchar *a= ptr+ length_bytes;
- uint a_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- uint b_length;
- uint local_char_length= ((field_charset->mbmaxlen > 1) ?
- key_length_arg / field_charset->mbmaxlen :
- key_length_arg);
-
- if (key_length_arg > 255)
- {
- b_length=uint2korr(b); b+= HA_KEY_BLOB_LENGTH;
- }
- else
- b_length= (uint) *b++;
-
- if (a_length > local_char_length)
- {
- local_char_length= my_charpos(field_charset, a, a+a_length,
- local_char_length);
- set_if_smaller(a_length, local_char_length);
- }
-
- return field_charset->coll->strnncollsp(field_charset,
- a, a_length,
- b, b_length,
- insert_or_update);
-}
-
-
uint Field_varstring::packed_col_length(const uchar *data_ptr, uint length)
{
if (length > 255)
@@ -7296,7 +6939,7 @@ int Field_varstring::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
}
-Field *Field_varstring::new_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field_varstring::new_field(MEM_ROOT *root, TABLE *new_table,
bool keep_type)
{
Field_varstring *res= (Field_varstring*) Field::new_field(root, new_table,
@@ -7308,7 +6951,7 @@ Field *Field_varstring::new_field(MEM_ROOT *root, struct st_table *new_table,
Field *Field_varstring::new_key_field(MEM_ROOT *root,
- struct st_table *new_table,
+ TABLE *new_table,
uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit)
{
@@ -7372,6 +7015,7 @@ Field_blob::Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
cs),
packlength(blob_pack_length)
{
+ DBUG_ASSERT(blob_pack_length <= 4); // Only pack lengths 1-4 supported currently
flags|= BLOB_FLAG;
share->blob_fields++;
/* TODO: why do not fill table->s->blob_field array here? */
@@ -7478,7 +7122,7 @@ oom_error:
int Field_blob::store(double nr)
{
CHARSET_INFO *cs=charset();
- value.set_real(nr, 2, cs);
+ value.set_real(nr, NOT_FIXED_DEC, cs);
return Field_blob::store(value.ptr(),(uint) value.length(), cs);
}
@@ -7499,7 +7143,7 @@ double Field_blob::val_real(void)
uint32 length;
CHARSET_INFO *cs;
- memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
+ memcpy(&blob, ptr+packlength, sizeof(char*));
if (!blob)
return 0.0;
length= get_length(ptr);
@@ -7513,7 +7157,7 @@ longlong Field_blob::val_int(void)
ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *blob;
- memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
+ memcpy(&blob, ptr+packlength, sizeof(char*));
if (!blob)
return 0;
uint32 length=get_length(ptr);
@@ -7525,7 +7169,7 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
{
ASSERT_COLUMN_MARKED_FOR_READ;
char *blob;
- memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
+ memcpy(&blob, ptr+packlength, sizeof(char*));
if (!blob)
val_ptr->set("",0,charset()); // A bit safer than ->length(0)
else
@@ -7539,7 +7183,7 @@ my_decimal *Field_blob::val_decimal(my_decimal *decimal_value)
ASSERT_COLUMN_MARKED_FOR_READ;
const char *blob;
size_t length;
- memcpy_fixed(&blob, ptr+packlength, sizeof(const uchar*));
+ memcpy(&blob, ptr+packlength, sizeof(const uchar*));
if (!blob)
{
blob= "";
@@ -7567,8 +7211,8 @@ int Field_blob::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
uint max_length)
{
uchar *blob1,*blob2;
- memcpy_fixed(&blob1,a_ptr+packlength,sizeof(char*));
- memcpy_fixed(&blob2,b_ptr+packlength,sizeof(char*));
+ memcpy(&blob1, a_ptr+packlength, sizeof(char*));
+ memcpy(&blob2, b_ptr+packlength, sizeof(char*));
uint a_len= get_length(a_ptr), b_len= get_length(b_ptr);
set_if_smaller(a_len, max_length);
set_if_smaller(b_len, max_length);
@@ -7582,8 +7226,8 @@ int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
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*));
+ memcpy(&a, a_ptr+packlength, sizeof(char*));
+ memcpy(&b, b_ptr+packlength, sizeof(char*));
a_length=get_length(a_ptr);
if (a_length > max_length)
a_length=max_length;
@@ -7664,7 +7308,7 @@ int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length)
{
uchar *blob1;
uint blob_length=get_length(ptr);
- memcpy_fixed(&blob1,ptr+packlength,sizeof(char*));
+ memcpy(&blob1, ptr+packlength, sizeof(char*));
CHARSET_INFO *cs= charset();
uint local_char_length= max_key_length / cs->mbmaxlen;
local_char_length= my_charpos(cs, blob1, blob1+blob_length,
@@ -7694,8 +7338,10 @@ int Field_blob::key_cmp(const uchar *a,const uchar *b)
*/
int Field_blob::do_save_field_metadata(uchar *metadata_ptr)
{
+ DBUG_ENTER("Field_blob::do_save_field_metadata");
*metadata_ptr= pack_length_no_ptr();
- return 1;
+ DBUG_PRINT("debug", ("metadata: %u (pack_length_no_ptr)", *metadata_ptr));
+ DBUG_RETURN(1);
}
@@ -7727,7 +7373,7 @@ void Field_blob::sort_string(uchar *to,uint length)
store_bigendian(blob_length, pos, packlength);
}
- memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
+ memcpy(&blob, ptr+packlength, sizeof(char*));
blob_length=my_strnxfrm(field_charset,
to, length, blob, blob_length);
@@ -7757,10 +7403,6 @@ void Field_blob::sql_type(String &res) const
uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length)
{
- DBUG_ENTER("Field_blob::pack");
- DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx; max_length: %u",
- (ulong) to, (ulong) from, max_length));
- DBUG_DUMP("record", from, table->s->reclength);
uchar *save= ptr;
ptr= (uchar*) from;
uint32 length=get_length(); // Length of from string
@@ -7781,8 +7423,7 @@ uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length)
memcpy(to+packlength, from,length);
}
ptr=save; // Restore org row pointer
- DBUG_DUMP("packed", to, packlength + length);
- DBUG_RETURN(to+packlength+length);
+ return to+packlength+length;
}
@@ -7824,136 +7465,6 @@ const uchar *Field_blob::unpack(uchar *to, const uchar *from,
DBUG_RETURN(from + master_packlength + length);
}
-/* Keys for blobs are like keys on varchars */
-
-int Field_blob::pack_cmp(const uchar *a, const uchar *b, uint key_length_arg,
- bool insert_or_update)
-{
- uint a_length, b_length;
- if (key_length_arg > 255)
- {
- a_length=uint2korr(a); a+=2;
- b_length=uint2korr(b); b+=2;
- }
- else
- {
- a_length= (uint) *a++;
- b_length= (uint) *b++;
- }
- return field_charset->coll->strnncollsp(field_charset,
- a, a_length,
- b, b_length,
- insert_or_update);
-}
-
-
-int Field_blob::pack_cmp(const uchar *b, uint key_length_arg,
- bool insert_or_update)
-{
- uchar *a;
- uint a_length, b_length;
- memcpy_fixed(&a,ptr+packlength,sizeof(char*));
- if (!a)
- return key_length_arg > 0 ? -1 : 0;
-
- a_length= get_length(ptr);
- if (key_length_arg > 255)
- {
- b_length= uint2korr(b); b+=2;
- }
- else
- b_length= (uint) *b++;
- return field_charset->coll->strnncollsp(field_charset,
- a, a_length,
- b, b_length,
- insert_or_update);
-}
-
-/** Create a packed key that will be used for storage from a MySQL row. */
-
-uchar *
-Field_blob::pack_key(uchar *to, const uchar *from, uint max_length)
-{
- uchar *save= ptr;
- ptr= (uchar*) from;
- uint32 length=get_length(); // Length of from string
- uint local_char_length= ((field_charset->mbmaxlen > 1) ?
- max_length/field_charset->mbmaxlen : max_length);
- if (length)
- get_ptr((uchar**) &from);
- if (length > local_char_length)
- local_char_length= my_charpos(field_charset, from, from+length,
- local_char_length);
- set_if_smaller(length, local_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.
-
- 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.
-
-
- @param to Pointer into the record buffer.
- @param from Pointer to the packed key.
- @param max_length Key length limit from key description.
-
- @return
- Pointer into 'from' past the last byte copied from packed key.
-*/
-
-#ifdef NOT_USED
-const uchar *
-Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length)
-{
- /* get length of the blob key */
- uint32 length= *from++;
- if (max_length > 255)
- length+= *from++ << 8;
-
- /* put the length into the record buffer */
- store_length(to, packlength, 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;
-}
-#endif
-
-/** Create a packed key that will be used for storage from a MySQL key. */
-
-uchar *Field_blob::pack_key_from_key_image(uchar *to, const uchar *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 uchar *data_ptr, uint length)
{
@@ -8261,7 +7772,7 @@ void Field_enum::sql_type(String &res) const
}
-Field *Field_enum::new_field(MEM_ROOT *root, struct st_table *new_table,
+Field *Field_enum::new_field(MEM_ROOT *root, TABLE *new_table,
bool keep_type)
{
Field_enum *res= (Field_enum*) Field::new_field(root, new_table, keep_type);
@@ -8487,6 +7998,24 @@ uint Field_enum::is_equal(Create_field *new_field)
}
+uchar *Field_enum::pack(uchar *to, const uchar *from, uint max_length)
+{
+ DBUG_ENTER("Field_enum::pack");
+ DBUG_PRINT("debug", ("packlength: %d", packlength));
+ DBUG_DUMP("from", from, packlength);
+ DBUG_RETURN(pack_int(to, from, packlength));
+}
+
+const uchar *Field_enum::unpack(uchar *to, const uchar *from,
+ const uchar *from_end, uint param_data)
+{
+ DBUG_ENTER("Field_enum::unpack");
+ DBUG_PRINT("debug", ("packlength: %d", packlength));
+ DBUG_DUMP("from", from, packlength);
+ DBUG_RETURN(unpack_int(to, from, from_end, packlength));
+}
+
+
/**
@return
returns 1 if the fields are equally defined
@@ -8559,6 +8088,9 @@ Field_bit::Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7),
bytes_in_rec(len_arg / 8)
{
+ DBUG_ENTER("Field_bit::Field_bit");
+ DBUG_PRINT("enter", ("ptr_arg: %p, null_ptr_arg: %p, len_arg: %u, bit_len: %u, bytes_in_rec: %u",
+ ptr_arg, null_ptr_arg, len_arg, bit_len, bytes_in_rec));
flags|= UNSIGNED_FLAG;
/*
Ensure that Field::eq() can distinguish between two different bit fields.
@@ -8566,6 +8098,7 @@ Field_bit::Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
*/
if (!null_ptr_arg)
null_bit= bit_ofs_arg;
+ DBUG_VOID_RETURN;
}
@@ -8614,7 +8147,7 @@ Field_bit::do_last_null_byte() const
Field *Field_bit::new_key_field(MEM_ROOT *root,
- struct st_table *new_table,
+ TABLE *new_table,
uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit)
{
@@ -8656,7 +8189,7 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
set_rec_bits((1 << bit_len) - 1, bit_ptr, bit_ofs, bit_len);
memset(ptr, 0xff, bytes_in_rec);
if (table->in_use->really_abort_on_warning())
- set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1);
else
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
return 1;
@@ -8751,7 +8284,7 @@ String *Field_bit::val_str(String *val_buffer,
mi_int8store(buff,bits);
val_buffer->alloc(length);
- memcpy_fixed((char*) val_buffer->ptr(), buff+8-length, length);
+ memcpy((char *) val_buffer->ptr(), buff+8-length, length);
val_buffer->length(length);
val_buffer->set_charset(&my_charset_bin);
return val_buffer;
@@ -8851,6 +8384,9 @@ uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg)
*/
int Field_bit::do_save_field_metadata(uchar *metadata_ptr)
{
+ DBUG_ENTER("Field_bit::do_save_field_metadata");
+ DBUG_PRINT("debug", ("bit_len: %d, bytes_in_rec: %d",
+ bit_len, bytes_in_rec));
/*
Since this class and Field_bit_as_char have different ideas of
what should be stored here, we compute the values of the metadata
@@ -8858,7 +8394,7 @@ int Field_bit::do_save_field_metadata(uchar *metadata_ptr)
*/
metadata_ptr[0]= field_length % 8;
metadata_ptr[1]= field_length / 8;
- return 2;
+ DBUG_RETURN(2);
}
@@ -8883,26 +8419,19 @@ uint Field_bit::pack_length_from_metadata(uint field_metadata)
}
-/**
- Check to see if field size is compatible with destination.
-
- This method is used in row-based replication to verify that the slave's
- field size is less than or equal to the master's field size. The
- encoded field metadata (from the master or source) is decoded and compared
- to the size of this field (the slave or destination).
-
- @param field_metadata Encoded size in field metadata
-
- @retval 0 if this field's size is < the source field's size
- @retval 1 if this field's size is >= the source field's size
-*/
-int Field_bit::compatible_field_size(uint field_metadata,
- const Relay_log_info * __attribute__((unused)),
- uint16 mflags)
+bool
+Field_bit::compatible_field_size(uint field_metadata,
+ Relay_log_info * __attribute__((unused)),
+ uint16 mflags,
+ int *order_var)
{
- uint from_bit_len= 8 * (field_metadata >> 8) + (field_metadata & 0xff);
+ DBUG_ENTER("Field_bit::compatible_field_size");
+ DBUG_ASSERT((field_metadata >> 16) == 0);
+ uint from_bit_len=
+ 8 * (field_metadata >> 8) + (field_metadata & 0xff);
uint to_bit_len= max_display_length();
-
+ DBUG_PRINT("debug", ("from_bit_len: %u, to_bit_len: %u",
+ from_bit_len, to_bit_len));
/*
If the bit length exact flag is clear, we are dealing with an old
master, so we allow some less strict behaviour if replicating by
@@ -8916,7 +8445,8 @@ int Field_bit::compatible_field_size(uint field_metadata,
to_bit_len= (to_bit_len + 7) / 8;
}
- return from_bit_len <= to_bit_len;
+ *order_var= compare(from_bit_len, to_bit_len);
+ DBUG_RETURN(TRUE);
}
@@ -8981,8 +8511,15 @@ const uchar *
Field_bit::unpack(uchar *to, const uchar *from, const uchar *from_end,
uint param_data)
{
+ DBUG_ENTER("Field_bit::unpack");
+ DBUG_PRINT("enter", ("to: %p, from: %p, param_data: 0x%x",
+ to, from, param_data));
+ DBUG_PRINT("debug", ("bit_ptr: %p, bit_len: %u, bit_ofs: %u",
+ bit_ptr, bit_len, bit_ofs));
uint const from_len= (param_data >> 8U) & 0x00ff;
uint const from_bit_len= param_data & 0x00ff;
+ DBUG_PRINT("debug", ("from_len: %u, from_bit_len: %u",
+ from_len, from_bit_len));
/*
If the parameter data is zero (i.e., undefined), or if the master
and slave have the same sizes, then use the old unpack() method.
@@ -9006,7 +8543,7 @@ Field_bit::unpack(uchar *to, const uchar *from, const uchar *from_end,
from++;
}
memcpy(to, from, bytes_in_rec);
- return from + bytes_in_rec;
+ DBUG_RETURN(from + bytes_in_rec);
}
/*
@@ -9038,7 +8575,7 @@ Field_bit::unpack(uchar *to, const uchar *from, const uchar *from_end,
bitmap_set_bit(table->write_set,field_index);
store(value, new_len, system_charset_info);
my_afree(value);
- return from + len;
+ DBUG_RETURN(from + len);
}
@@ -9087,7 +8624,7 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
if (bits)
*ptr&= ((1 << bits) - 1); /* set first uchar */
if (table->in_use->really_abort_on_warning())
- set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1);
else
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
return 1;
@@ -9168,8 +8705,11 @@ void Create_field::create_length_to_internal_length(void)
*/
void Create_field::init_for_tmp_table(enum_field_types sql_type_arg,
uint32 length_arg, uint32 decimals_arg,
- bool maybe_null, bool is_unsigned)
+ bool maybe_null, bool is_unsigned,
+ uint pack_length_arg)
{
+ DBUG_ENTER("Create_field::init_for_tmp_table");
+
field_name= "";
sql_type= sql_type_arg;
char_length= length= length_arg;;
@@ -9177,12 +8717,97 @@ void Create_field::init_for_tmp_table(enum_field_types sql_type_arg,
interval= 0;
charset= &my_charset_bin;
geom_type= Field::GEOM_GEOMETRY;
- pack_flag= (FIELDFLAG_NUMBER |
- ((decimals_arg & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) |
- (maybe_null ? FIELDFLAG_MAYBE_NULL : 0) |
- (is_unsigned ? 0 : FIELDFLAG_DECIMAL));
+
+ DBUG_PRINT("enter", ("sql_type: %d, length: %u, pack_length: %u",
+ sql_type_arg, length_arg, pack_length_arg));
+
+ /*
+ These pack flags are crafted to get it correctly through the
+ branches of make_field().
+ */
+ switch (sql_type_arg)
+ {
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_SET:
+ pack_flag= 0;
+ break;
+
+ case MYSQL_TYPE_GEOMETRY:
+ pack_flag= FIELDFLAG_GEOM;
+ break;
+
+ case MYSQL_TYPE_ENUM:
+ pack_flag= FIELDFLAG_INTERVAL;
+ break;
+
+ case MYSQL_TYPE_NEWDECIMAL:
+ DBUG_ASSERT(decimals_arg <= DECIMAL_MAX_SCALE);
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ pack_flag= FIELDFLAG_NUMBER |
+ (decimals_arg & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT;
+ break;
+
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ pack_flag= FIELDFLAG_BLOB;
+ break;
+
+ case MYSQL_TYPE_BIT:
+ pack_flag= FIELDFLAG_NUMBER | FIELDFLAG_TREAT_BIT_AS_CHAR;
+ break;
+
+ default:
+ pack_flag= FIELDFLAG_NUMBER;
+ break;
+ }
+
+ /*
+ Set the pack flag correctly for the blob-like types. This sets the
+ packtype to something that make_field can use. If the pack type is
+ not set correctly, the packlength will be reeeeally wierd (like
+ 129 or so).
+ */
+ switch (sql_type_arg)
+ {
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ // If you are going to use the above types, you have to pass a
+ // pack_length as parameter. Assert that is really done.
+ DBUG_ASSERT(pack_length_arg != ~0U);
+ pack_flag|= pack_length_to_packflag(pack_length_arg);
+ break;
+ default:
+ /* Nothing */
+ break;
+ }
+
+ pack_flag|=
+ (maybe_null ? FIELDFLAG_MAYBE_NULL : 0) |
+ (is_unsigned ? 0 : FIELDFLAG_DECIMAL);
+
+ DBUG_PRINT("debug", ("pack_flag: %s%s%s%s%s%s, pack_type: %d",
+ FLAGSTR(pack_flag, FIELDFLAG_BINARY),
+ FLAGSTR(pack_flag, FIELDFLAG_NUMBER),
+ FLAGSTR(pack_flag, FIELDFLAG_INTERVAL),
+ FLAGSTR(pack_flag, FIELDFLAG_GEOM),
+ FLAGSTR(pack_flag, FIELDFLAG_BLOB),
+ FLAGSTR(pack_flag, FIELDFLAG_DECIMAL),
+ f_packtype(pack_flag)));
vcol_info= 0;
stored_in_db= TRUE;
+
+ DBUG_VOID_RETURN;
}
@@ -9596,8 +9221,8 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
- charset= &my_charset_bin;
- flags|= BINCMP_FLAG;
+ charset= &my_charset_numeric;
+ flags|= BINARY_FLAG;
default: break;
}
@@ -9681,6 +9306,7 @@ uint pack_length_to_packflag(uint type)
return 0; // This shouldn't happen
}
+
Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length,
uchar *null_pos, uchar null_bit,
uint pack_flag,
@@ -9720,10 +9346,18 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length,
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
- field_charset= &my_charset_bin;
+ field_charset= &my_charset_numeric;
default: break;
}
+ DBUG_PRINT("debug", ("field_type: %d, field_length: %u, interval: %p, pack_flag: %s%s%s%s%s",
+ field_type, field_length, interval,
+ FLAGSTR(pack_flag, FIELDFLAG_BINARY),
+ FLAGSTR(pack_flag, FIELDFLAG_INTERVAL),
+ FLAGSTR(pack_flag, FIELDFLAG_NUMBER),
+ FLAGSTR(pack_flag, FIELDFLAG_PACK),
+ FLAGSTR(pack_flag, FIELDFLAG_BLOB)));
+
if (f_is_alpha(pack_flag))
{
if (!f_is_packed(pack_flag))
@@ -9961,6 +9595,39 @@ Create_field::Create_field(Field *old_field,Field *orig_field)
/**
+ maximum possible character length for blob.
+
+ This method is used in Item_field::set_field to calculate
+ max_length for Item.
+
+ For example:
+ CREATE TABLE t2 SELECT CONCAT(tinyblob_utf8_column) FROM t1;
+ must create a "VARCHAR(255) CHARACTER SET utf8" column.
+
+ @return
+ length
+*/
+
+uint32 Field_blob::char_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;
+ }
+}
+
+
+/**
Makes a clone of this object for ALTER/CREATE TABLE
@param mem_root MEM_ROOT where to clone the field
@@ -10016,11 +9683,6 @@ uint32 Field_blob::max_display_length()
if count_cuted_fields == CHECK_FIELD_IGNORE then we ignore notes.
This allows us to avoid notes in optimisation, like convert_constant_item().
-
- @retval
- 1 if count_cuted_fields == CHECK_FIELD_IGNORE and error level is not NOTE
- @retval
- 0 otherwise
*/
void
@@ -10036,7 +9698,7 @@ Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code,
{
thd->cuted_fields+= cuted_increment;
push_warning_printf(thd, level, code, ER(code), field_name,
- thd->row_count);
+ thd->warning_info->current_row_for_warning());
}
}
@@ -10056,11 +9718,11 @@ Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code,
thread.
See also bug#2336
-*/
+*/
void Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level,
- uint code, const Lazy_string *str,
+ uint code, const ErrConv *str,
timestamp_type ts_type, int cuted_increment)
{
THD *thd= table->in_use;