summaryrefslogtreecommitdiff
path: root/sql/field.cc
diff options
context:
space:
mode:
authorAlexander Nozdrin <alik@sun.com>2010-01-18 23:19:19 +0300
committerAlexander Nozdrin <alik@sun.com>2010-01-18 23:19:19 +0300
commit40271e4f5edacc6fe90ed74a087e5ff25daea899 (patch)
treed38210df12297fa40d9edbf59cbb72329a4ccad4 /sql/field.cc
parent0ae23cd69d3c13dba2a73750e93abf3342f21eb4 (diff)
parent33c075e842324cfdf0aab055c2db8d0d50bcbc68 (diff)
downloadmariadb-git-40271e4f5edacc6fe90ed74a087e5ff25daea899.tar.gz
Manual merge from mysql-next-mr.
Conflicts: - sql/sql_plugin.cc
Diffstat (limited to 'sql/field.cc')
-rw-r--r--sql/field.cc536
1 files changed, 250 insertions, 286 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 0934bb04ccd..a07493a6964 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -31,9 +31,6 @@
#include "slave.h" // Pull in rpl_master_has_bug()
#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
@@ -50,7 +47,7 @@ template class List_iterator<Create_field>;
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) \
@@ -59,6 +56,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 DBUG_ASSERT(!table || (!table->write_set || bitmap_is_set(table->write_set, field_index)))
+#define FLAGSTR(S,F) ((S) & (F) ? #F " " : "")
+
/*
Rules for merging different types of fields in UNION
@@ -997,6 +996,22 @@ 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.
+ */
+namespace {
+ int compare(unsigned int a, unsigned int b)
+ {
+ if (a < b)
+ return -1;
+ if (b < a)
+ return 1;
+ return 0;
+}
+}
+
+/**
Detect Item_result by given field type of UNION merge result.
@param field_type given field type
@@ -1395,22 +1410,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)))
+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;
}
@@ -2304,13 +2345,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)
{
@@ -2723,17 +2758,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))
@@ -2893,33 +2917,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)))
+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;
}
@@ -4231,67 +4238,20 @@ String *Field_float::val_str(String *val_buffer,
uint to_length=max(field_length,70);
val_buffer->alloc(to_length);
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);
return val_buffer;
@@ -4479,8 +4439,12 @@ int Field_real::truncate(double *nr, double max_value)
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)
@@ -4590,68 +4554,14 @@ String *Field_double::val_str(String *val_buffer,
uint to_length=max(field_length, DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE);
val_buffer->alloc(to_length);
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;
+ len= my_fcvt(nr, dec, to, NULL);
- (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
-
- val_buffer->length((uint) (to-val_buffer->ptr()));
+ val_buffer->length((uint) len);
if (zerofill)
prepend_zeros(val_buffer);
return val_buffer;
@@ -6448,84 +6358,18 @@ int Field_str::store(double nr)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
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)));
-
- /* 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));
+ size_t length;
+ my_bool 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)
+ length= my_gcvt(nr, MY_GCVT_ARG_DOUBLE, local_char_length, buff, &error);
+ 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());
}
@@ -6675,8 +6519,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)
+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 };
@@ -6684,7 +6531,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);
+ return Field::compatible_field_size(field_metadata, rli_arg, mflags, order_var);
}
@@ -6745,6 +6592,8 @@ uchar *Field_string::pack(uchar *to, const uchar *from,
{
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);
@@ -7407,6 +7256,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? */
@@ -7601,7 +7451,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);
}
@@ -7817,8 +7667,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);
}
@@ -8626,6 +8478,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.
@@ -8633,6 +8488,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;
}
@@ -8917,9 +8773,17 @@ uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg)
*/
int Field_bit::do_save_field_metadata(uchar *metadata_ptr)
{
- *metadata_ptr= bit_len;
- *(metadata_ptr + 1)= bytes_in_rec;
- return 2;
+ 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
+ explicitly using the field_length.
+ */
+ metadata_ptr[0]= field_length % 8;
+ metadata_ptr[1]= field_length / 8;
+ DBUG_RETURN(2);
}
@@ -8944,34 +8808,34 @@ 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).
+bool
+Field_bit::compatible_field_size(uint field_metadata,
+ Relay_log_info * __attribute__((unused)),
+ uint16 mflags,
+ int *order_var)
+{
+ 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
+ moving both bit lengths to an even multiple of 8.
- @param field_metadata Encoded size in field metadata
+ We do this by computing the number of bytes to store the field
+ instead, and then compare the result.
+ */
+ if (!(mflags & Table_map_log_event::TM_BIT_LEN_EXACT_F)) {
+ from_bit_len= (from_bit_len + 7) / 8;
+ to_bit_len= (to_bit_len + 7) / 8;
+ }
- @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)))
-{
- int compatible= 0;
- uint const source_size= pack_length_from_metadata(field_metadata);
- uint const destination_size= row_pack_length();
- uint const from_bit_len= field_metadata & 0x00ff;
- uint const from_len= (field_metadata >> 8U) & 0x00ff;
- if ((bit_len == 0) || (from_bit_len == 0))
- compatible= (source_size <= destination_size);
- else if (from_bit_len > bit_len)
- compatible= (from_len < bytes_in_rec);
- else
- compatible= ((from_bit_len <= bit_len) && (from_len <= bytes_in_rec));
- return (compatible);
+ *order_var= compare(from_bit_len, to_bit_len);
+ DBUG_RETURN(TRUE);
}
@@ -9037,8 +8901,15 @@ const uchar *
Field_bit::unpack(uchar *to, const uchar *from, uint param_data,
bool low_byte_first __attribute__((unused)))
{
+ 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.
@@ -9059,7 +8930,7 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data,
from++;
}
memcpy(to, from, bytes_in_rec);
- return from + bytes_in_rec;
+ DBUG_RETURN(from + bytes_in_rec);
}
/*
@@ -9085,7 +8956,7 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data,
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);
}
@@ -9213,8 +9084,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)
{
+ DBUG_ENTER("Create_field::init_for_tmp_table");
+
field_name= "";
sql_type= sql_type_arg;
char_length= length= length_arg;;
@@ -9222,10 +9096,92 @@ 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));
+
+ /*
+ 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_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ pack_flag= FIELDFLAG_DECIMAL | 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 != ~0U);
+ pack_flag|= pack_length_to_packflag(pack_length);
+ 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, 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),
+ f_packtype(pack_flag)));
+ DBUG_VOID_RETURN;
}
@@ -9731,6 +9687,14 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length,
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))