summaryrefslogtreecommitdiff
path: root/sql/field.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/field.cc')
-rw-r--r--sql/field.cc843
1 files changed, 608 insertions, 235 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 9b6465988f6..1f97e587eb3 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -27,7 +27,7 @@
#pragma implementation // gcc: Class implementation
#endif
-#include <my_global.h>
+#include "mariadb.h"
#include "sql_priv.h"
#include "sql_select.h"
#include "rpl_rli.h" // Pull in Relay_log_info
@@ -51,7 +51,7 @@
*****************************************************************************/
static const char *zero_timestamp="0000-00-00 00:00:00.000000";
-LEX_CSTRING temp_lex_str= {"temp", 4};
+LEX_CSTRING temp_lex_str= {STRING_WITH_LEN("temp")};
uchar Field_null::null[1]={1};
const char field_separator=',';
@@ -1228,7 +1228,7 @@ bool Field::can_optimize_range(const Item_bool_func *cond,
}
-int Field::store_hex_hybrid(const char *str, uint length)
+int Field::store_hex_hybrid(const char *str, size_t length)
{
DBUG_ASSERT(result_type() != STRING_RESULT);
ulonglong nr;
@@ -1467,8 +1467,7 @@ Value_source::Converter_string_to_number::check_edom_and_truncation(THD *thd,
int Field_num::check_edom_and_important_data_truncation(const char *type,
bool edom,
CHARSET_INFO *cs,
- const char *str,
- uint length,
+ const char *str, size_t length,
const char *end)
{
/* Test if we get an empty string or garbage */
@@ -1490,7 +1489,7 @@ int Field_num::check_edom_and_important_data_truncation(const char *type,
int Field_num::check_edom_and_truncation(const char *type, bool edom,
CHARSET_INFO *cs,
- const char *str, uint length,
+ const char *str, size_t length,
const char *end)
{
int rc= check_edom_and_important_data_truncation(type, edom,
@@ -1524,7 +1523,7 @@ int Field_num::check_edom_and_truncation(const char *type, bool edom,
1 error
*/
-bool Field_num::get_int(CHARSET_INFO *cs, const char *from, uint len,
+bool Field_num::get_int(CHARSET_INFO *cs, const char *from, size_t len,
longlong *rnd, ulonglong unsigned_max,
longlong signed_min, longlong signed_max)
{
@@ -1557,7 +1556,7 @@ bool Field_num::get_int(CHARSET_INFO *cs, const char *from, uint len,
goto out_of_range;
}
}
- if (get_thd()->count_cuted_fields &&
+ if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
check_int(cs, from, len, end, error))
return 1;
return 0;
@@ -1568,7 +1567,7 @@ out_of_range:
}
-double Field_real::get_double(const char *str, uint length, CHARSET_INFO *cs,
+double Field_real::get_double(const char *str, size_t length, CHARSET_INFO *cs,
int *error)
{
char *end;
@@ -1578,7 +1577,7 @@ double Field_real::get_double(const char *str, uint length, CHARSET_INFO *cs,
set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
*error= 1;
}
- else if (get_thd()->count_cuted_fields &&
+ else if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
check_edom_and_truncation("double", str == end,
cs, str, length, end))
*error= 1;
@@ -1642,7 +1641,8 @@ String *Field::val_int_as_str(String *val_buffer, bool unsigned_val)
Field::Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
uchar null_bit_arg,
utype unireg_check_arg, const LEX_CSTRING *field_name_arg)
- :ptr(ptr_arg), null_ptr(null_ptr_arg), table(0), orig_table(0),
+ :ptr(ptr_arg), invisible(VISIBLE),
+ null_ptr(null_ptr_arg), table(0), orig_table(0),
table_name(0), field_name(*field_name_arg), option_list(0),
option_struct(0), key_start(0), part_of_key(0),
part_of_key_not_clustered(0), part_of_sortkey(0),
@@ -1753,7 +1753,7 @@ bool Field::compatible_field_size(uint field_metadata,
}
-int Field::store(const char *to, uint length, CHARSET_INFO *cs,
+int Field::store(const char *to, size_t length, CHARSET_INFO *cs,
enum_check_fields check_level)
{
int res;
@@ -1912,7 +1912,7 @@ 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;
- if (orig_table->pos_in_table_list &&
+ 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);
@@ -2040,6 +2040,48 @@ bool Field_num::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
}
+bool Field_vers_trx_id::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate, ulonglong trx_id)
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ DBUG_ASSERT(ltime);
+ if (!table || !table->s)
+ return true;
+ DBUG_ASSERT(table->versioned(VERS_TRX_ID) ||
+ (table->versioned() && table->s->table_category == TABLE_CATEGORY_TEMPORARY));
+ if (!trx_id)
+ return true;
+
+ THD *thd= get_thd();
+ DBUG_ASSERT(thd);
+ if (trx_id == ULONGLONG_MAX)
+ {
+ thd->variables.time_zone->gmt_sec_to_TIME(ltime, TIMESTAMP_MAX_VALUE);
+ ltime->second_part= TIME_MAX_SECOND_PART;
+ return false;
+ }
+ if (cached == trx_id)
+ {
+ *ltime= cache;
+ return false;
+ }
+
+ TR_table trt(thd);
+ bool found= trt.query(trx_id);
+ if (found)
+ {
+ trt[TR_table::FLD_COMMIT_TS]->get_date(&cache, fuzzydate);
+ *ltime= cache;
+ cached= trx_id;
+ return false;
+ }
+
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_VERS_NO_TRX_ID, ER_THD(thd, ER_VERS_NO_TRX_ID),
+ (longlong) trx_id);
+ return true;
+}
+
+
Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
const LEX_CSTRING *field_name_arg,
@@ -2232,8 +2274,11 @@ Field *Field::make_new_field(MEM_ROOT *root, TABLE *new_table,
*/
tmp->unireg_check= Field::NONE;
tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG |
- ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
+ ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG |
+ VERS_SYS_START_FLAG | VERS_SYS_END_FLAG |
+ VERS_UPDATE_UNVERSIONED_FLAG);
tmp->reset_fields();
+ tmp->invisible= VISIBLE;
return tmp;
}
@@ -2420,7 +2465,7 @@ void Field_decimal::overflow(bool negative)
}
-int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs)
+int Field_decimal::store(const char *from_arg, size_t len, CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
char buff[STRING_BUFFER_USUAL_SIZE];
@@ -2564,7 +2609,7 @@ int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs)
it makes the code easer to read.
*/
- if (get_thd()->count_cuted_fields)
+ if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
// Skip end spaces
for (;from != end && my_isspace(&my_charset_bin, *from); from++) ;
@@ -2734,7 +2779,8 @@ int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs)
{
if (pos == right_wall)
{
- if (get_thd()->count_cuted_fields && !is_cuted_fields_incr)
+ if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
+ !is_cuted_fields_incr)
break; // Go on below to see if we lose non zero digits
return 0;
}
@@ -2800,7 +2846,6 @@ int Field_decimal::store(double nr)
return 1;
}
- reg4 uint i;
size_t length;
uchar fyllchar,*to;
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
@@ -2816,7 +2861,7 @@ int Field_decimal::store(double nr)
else
{
to=ptr;
- for (i=field_length-length ; i-- > 0 ;)
+ for (size_t i=field_length-length ; i-- > 0 ;)
*to++ = fyllchar;
memcpy(to,buff,length);
return 0;
@@ -3102,7 +3147,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
}
-int Field_new_decimal::store(const char *from, uint length,
+int Field_new_decimal::store(const char *from, size_t length,
CHARSET_INFO *charset_arg)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
@@ -3127,7 +3172,7 @@ int Field_new_decimal::store(const char *from, uint length,
DBUG_RETURN(1);
}
- if (thd->count_cuted_fields)
+ if (thd->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
if (check_edom_and_important_data_truncation("decimal",
err && err != E_DEC_TRUNCATED,
@@ -3172,7 +3217,7 @@ int Field_new_decimal::store(const char *from, uint length,
- in err2: store_value() truncated 1.123 to 1.12, e.g. for DECIMAL(10,2)
Also, we send a note if a string had some trailing spaces: '1.12 '
*/
- if (thd->count_cuted_fields &&
+ if (thd->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
(err == E_DEC_TRUNCATED ||
err2 == E_DEC_TRUNCATED ||
end < from + length))
@@ -3309,7 +3354,7 @@ int Field_new_decimal::cmp(const uchar *a,const uchar*b)
void Field_new_decimal::sort_string(uchar *buff,
- uint length __attribute__((unused)))
+ uint)
{
memcpy(buff, ptr, bin_size);
}
@@ -3335,7 +3380,7 @@ void Field_new_decimal::sql_type(String &str) const
@returns number of bytes written to metadata_ptr
*/
-int Field_new_decimal::do_save_field_metadata(uchar *metadata_ptr)
+int Field_new_decimal::save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= precision;
*(metadata_ptr + 1)= decimals();
@@ -3493,7 +3538,7 @@ int Field_num::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg)
** tiny int
****************************************************************************/
-int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
+int Field_tiny::store(const char *from,size_t len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
int error;
@@ -3669,7 +3714,7 @@ void Field_tiny::sql_type(String &res) const
Field type short int (2 byte)
****************************************************************************/
-int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
+int Field_short::store(const char *from,size_t len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
int store_tmp;
@@ -3858,7 +3903,7 @@ void Field_short::sql_type(String &res) const
Field type medium int (3 byte)
****************************************************************************/
-int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
+int Field_medium::store(const char *from,size_t len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
int store_tmp;
@@ -4049,7 +4094,7 @@ void Field_medium::sql_type(String &res) const
** long int
****************************************************************************/
-int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
+int Field_long::store(const char *from,size_t len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
long store_tmp;
@@ -4177,17 +4222,17 @@ String *Field_long::val_str(String *val_buffer,
{
ASSERT_COLUMN_MARKED_FOR_READ;
CHARSET_INFO *cs= &my_charset_numeric;
- uint length;
- uint mlength=MY_MAX(field_length+1,12*cs->mbmaxlen);
+ size_t length;
+ size_t mlength=MY_MAX(field_length+1,12*cs->mbmaxlen);
val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
int32 j;
j=sint4korr(ptr);
if (unsigned_flag)
- length=cs->cset->long10_to_str(cs,to,mlength, 10,(long) (uint32)j);
+ length=cs->cset->long10_to_str(cs,to,mlength, 10,(uint32) j);
else
- length=cs->cset->long10_to_str(cs,to,mlength,-10,(long) j);
+ length=cs->cset->long10_to_str(cs,to,mlength,-10,j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
@@ -4236,7 +4281,7 @@ void Field_long::sql_type(String &res) const
Field type longlong int (8 bytes)
****************************************************************************/
-int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
+int Field_longlong::store(const char *from,size_t len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
int error= 0;
@@ -4249,7 +4294,7 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (get_thd()->count_cuted_fields &&
+ else if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
check_int(cs, from, len, end, error))
error= 1;
else
@@ -4383,6 +4428,26 @@ void Field_longlong::sql_type(String &res) const
add_zerofill_and_unsigned(res);
}
+void Field_longlong::set_max()
+{
+ ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ set_notnull();
+ int8store(ptr, unsigned_flag ? ULONGLONG_MAX : LONGLONG_MAX);
+}
+
+bool Field_longlong::is_max()
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ if (unsigned_flag)
+ {
+ ulonglong j;
+ j= uint8korr(ptr);
+ return j == ULONGLONG_MAX;
+ }
+ longlong j;
+ j= sint8korr(ptr);
+ return j == LONGLONG_MAX;
+}
/*
Floating-point numbers
@@ -4392,7 +4457,7 @@ void Field_longlong::sql_type(String &res) const
single precision float
****************************************************************************/
-int Field_float::store(const char *from,uint len,CHARSET_INFO *cs)
+int Field_float::store(const char *from,size_t len,CHARSET_INFO *cs)
{
int error;
Field_float::store(get_double(from, len, cs, &error));
@@ -4544,7 +4609,7 @@ bool Field_float::send_binary(Protocol *protocol)
@returns number of bytes written to metadata_ptr
*/
-int Field_float::do_save_field_metadata(uchar *metadata_ptr)
+int Field_float::save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= pack_length();
return 1;
@@ -4571,7 +4636,7 @@ void Field_float::sql_type(String &res) const
double precision floating point numbers
****************************************************************************/
-int Field_double::store(const char *from,uint len,CHARSET_INFO *cs)
+int Field_double::store(const char *from,size_t len,CHARSET_INFO *cs)
{
int error;
Field_double::store(get_double(from, len, cs, &error));
@@ -4861,7 +4926,7 @@ void Field_double::sort_string(uchar *to,uint length __attribute__((unused)))
@returns number of bytes written to metadata_ptr
*/
-int Field_double::do_save_field_metadata(uchar *metadata_ptr)
+int Field_double::save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= pack_length();
return 1;
@@ -5031,7 +5096,7 @@ int Field_timestamp::store_time_dec(const MYSQL_TIME *ltime, uint dec)
}
-int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
+int Field_timestamp::store(const char *from,size_t len,CHARSET_INFO *cs)
{
MYSQL_TIME l_time;
MYSQL_TIME_STATUS status;
@@ -5320,36 +5385,6 @@ static longlong read_lowendian(const uchar *from, uint bytes)
}
}
-static void store_bigendian(ulonglong num, uchar *to, uint bytes)
-{
- switch(bytes) {
- case 1: mi_int1store(to, num); break;
- case 2: mi_int2store(to, num); break;
- case 3: mi_int3store(to, num); break;
- case 4: mi_int4store(to, num); break;
- case 5: mi_int5store(to, num); break;
- case 6: mi_int6store(to, num); break;
- case 7: mi_int7store(to, num); break;
- case 8: mi_int8store(to, num); break;
- default: DBUG_ASSERT(0);
- }
-}
-
-static longlong read_bigendian(const uchar *from, uint bytes)
-{
- switch(bytes) {
- case 1: return mi_uint1korr(from);
- case 2: return mi_uint2korr(from);
- case 3: return mi_uint3korr(from);
- case 4: return mi_uint4korr(from);
- case 5: return mi_uint5korr(from);
- case 6: return mi_uint6korr(from);
- case 7: return mi_uint7korr(from);
- case 8: return mi_sint8korr(from);
- default: DBUG_ASSERT(0); return 0;
- }
-}
-
void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part)
{
mi_int4store(ptr, timestamp);
@@ -5455,6 +5490,27 @@ void Field_timestampf::store_TIME(my_time_t timestamp, ulong sec_part)
my_timestamp_to_binary(&tm, ptr, dec);
}
+void Field_timestampf::set_max()
+{
+ DBUG_ENTER("Field_timestampf::set_max");
+ ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ DBUG_ASSERT(dec == TIME_SECOND_PART_DIGITS);
+
+ set_notnull();
+ mi_int4store(ptr, TIMESTAMP_MAX_VALUE);
+ mi_int3store(ptr + 4, TIME_MAX_SECOND_PART);
+
+ DBUG_VOID_RETURN;
+}
+
+bool Field_timestampf::is_max()
+{
+ DBUG_ENTER("Field_timestampf::is_max");
+ ASSERT_COLUMN_MARKED_FOR_READ;
+
+ DBUG_RETURN(mi_sint4korr(ptr) == TIMESTAMP_MAX_VALUE &&
+ mi_sint3korr(ptr + 4) == TIME_MAX_SECOND_PART);
+}
my_time_t Field_timestampf::get_timestamp(const uchar *pos,
ulong *sec_part) const
@@ -5541,7 +5597,7 @@ int Field_temporal_with_date::store_TIME_with_warning(MYSQL_TIME *ltime,
}
-int Field_temporal_with_date::store(const char *from, uint len, CHARSET_INFO *cs)
+int Field_temporal_with_date::store(const char *from, size_t len, CHARSET_INFO *cs)
{
MYSQL_TIME ltime;
MYSQL_TIME_STATUS status;
@@ -5737,7 +5793,7 @@ void Field_time::store_TIME(const MYSQL_TIME *ltime)
int3store(ptr,tmp);
}
-int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
+int Field_time::store(const char *from,size_t len,CHARSET_INFO *cs)
{
MYSQL_TIME ltime;
MYSQL_TIME_STATUS status;
@@ -6164,7 +6220,7 @@ bool Field_timef::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
** Can handle 2 byte or 4 byte years!
****************************************************************************/
-int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
+int Field_year::store(const char *from, size_t len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
char *end;
@@ -6178,7 +6234,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
return 1;
}
- if (get_thd()->count_cuted_fields &&
+ if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
(error= check_int(cs, from, len, end, error)))
{
if (error == 1) /* empty or incorrect string */
@@ -6886,7 +6942,7 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end,
bool count_spaces)
{
THD *thd= get_thd();
- if ((pstr < end) && thd->count_cuted_fields)
+ if ((pstr < end) && thd->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
if (test_if_important_data(field_charset, pstr, end))
{
@@ -6908,7 +6964,7 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end,
/* Copy a string and fill with space */
-int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
+int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
uint copy_length;
@@ -6932,6 +6988,20 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
}
+int Field_str::store(longlong nr, bool unsigned_val)
+{
+ char buff[64];
+ uint length;
+ length= (uint) (field_charset->cset->longlong10_to_str)(field_charset,
+ buff,
+ sizeof(buff),
+ (unsigned_val ? 10:
+ -10),
+ nr);
+ return store(buff, length, field_charset);
+}
+
+
/**
Store double value in Field_string or Field_varstring.
@@ -6944,7 +7014,8 @@ int Field_str::store(double nr)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
- uint local_char_length= field_length / charset()->mbmaxlen;
+ uint local_char_length= MY_MIN(sizeof(buff),
+ field_length / field_charset->mbmaxlen);
size_t length= 0;
my_bool error= (local_char_length == 0);
@@ -6959,7 +7030,7 @@ int Field_str::store(double nr)
else
set_warning(WARN_DATA_TRUNCATED, 1);
}
- return store(buff, length, &my_charset_numeric);
+ return store(buff, (uint)length, &my_charset_numeric);
}
uint Field::is_equal(Create_field *new_field)
@@ -6976,17 +7047,6 @@ uint Field_str::is_equal(Create_field *new_field)
}
-int Field_string::store(longlong nr, bool unsigned_val)
-{
- char buff[64];
- int l;
- CHARSET_INFO *cs=charset();
- l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff),
- unsigned_val ? 10 : -10, nr);
- return Field_string::store(buff,(uint)l,cs);
-}
-
-
int Field_longstr::store_decimal(const my_decimal *d)
{
char buff[DECIMAL_MAX_STR_LENGTH+1];
@@ -7102,7 +7162,7 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)),
ASSERT_COLUMN_MARKED_FOR_READ;
/* See the comment for Field_long::store(long long) */
DBUG_ASSERT(!table || table->in_use == current_thd);
- uint length;
+ size_t length;
if (get_thd()->variables.sql_mode &
MODE_PAD_CHAR_TO_FULL_LENGTH)
length= my_charpos(field_charset, ptr, ptr + field_length,
@@ -7165,11 +7225,11 @@ Field_string::compatible_field_size(uint field_metadata,
int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
- uint a_len, b_len;
+ size_t a_len, b_len;
if (field_charset->mbmaxlen != 1)
{
- uint char_len= field_length/field_charset->mbmaxlen;
+ size_t char_len= field_length/field_charset->mbmaxlen;
a_len= my_charpos(field_charset, a_ptr, a_ptr + field_length, char_len);
b_len= my_charpos(field_charset, b_ptr, b_ptr + field_length, char_len);
}
@@ -7187,7 +7247,7 @@ int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
void Field_string::sort_string(uchar *to,uint length)
{
- uint tmp __attribute__((unused))=
+ IF_DBUG(size_t tmp= ,)
field_charset->coll->strnxfrm(field_charset,
to, length,
char_length() *
@@ -7203,7 +7263,7 @@ void Field_string::sql_type(String &res) const
{
THD *thd= table->in_use;
CHARSET_INFO *cs=res.charset();
- ulong length;
+ size_t length;
length= cs->cset->snprintf(cs,(char*) res.ptr(),
res.alloced_length(), "%s(%d)",
@@ -7220,9 +7280,9 @@ void Field_string::sql_type(String &res) const
uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
{
- uint length= MY_MIN(field_length,max_length);
- uint local_char_length= max_length/field_charset->mbmaxlen;
- DBUG_PRINT("debug", ("Packing field '%s' - length: %u ", field_name.str,
+ size_t length= MY_MIN(field_length,max_length);
+ size_t local_char_length= max_length/field_charset->mbmaxlen;
+ DBUG_PRINT("debug", ("Packing field '%s' - length: %zu ", field_name.str,
length));
if (length > local_char_length)
@@ -7266,7 +7326,7 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
the master.
@note For information about how the length is packed, see @c
- Field_string::do_save_field_metadata
+ Field_string::save_field_metadata
@param to Destination of the data
@param from Source of the data
@@ -7349,7 +7409,7 @@ Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end,
@returns number of bytes written to metadata_ptr
*/
-int Field_string::do_save_field_metadata(uchar *metadata_ptr)
+int Field_string::save_field_metadata(uchar *metadata_ptr)
{
DBUG_ASSERT(field_length < 1024);
DBUG_ASSERT((real_type() & 0xF0) == 0xF0);
@@ -7377,14 +7437,14 @@ uint Field_string::max_packed_col_length(uint max_length)
uint Field_string::get_key_image(uchar *buff, uint length, imagetype type_arg)
{
- uint bytes = my_charpos(field_charset, (char*) ptr,
+ size_t bytes = my_charpos(field_charset, (char*) ptr,
(char*) ptr + field_length,
length / field_charset->mbmaxlen);
memcpy(buff, ptr, bytes);
if (bytes < length)
field_charset->cset->fill(field_charset, (char*) buff + bytes,
length - bytes, field_charset->pad_char);
- return bytes;
+ return (uint)bytes;
}
@@ -7446,14 +7506,14 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16;
@returns number of bytes written to metadata_ptr
*/
-int Field_varstring::do_save_field_metadata(uchar *metadata_ptr)
+int Field_varstring::save_field_metadata(uchar *metadata_ptr)
{
DBUG_ASSERT(field_length <= 65535);
int2store((char*)metadata_ptr, field_length);
return 2;
}
-int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
+int Field_varstring::store(const char *from,size_t length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
uint copy_length;
@@ -7473,20 +7533,6 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
}
-int Field_varstring::store(longlong nr, bool unsigned_val)
-{
- char buff[64];
- uint length;
- length= (uint) (field_charset->cset->longlong10_to_str)(field_charset,
- buff,
- sizeof(buff),
- (unsigned_val ? 10:
- -10),
- nr);
- return Field_varstring::store(buff, length, field_charset);
-}
-
-
double Field_varstring::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
@@ -7568,8 +7614,8 @@ int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length)
{
- uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- uint local_char_length= max_key_length / field_charset->mbmaxlen;
+ size_t length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
+ size_t local_char_length= max_key_length / field_charset->mbmaxlen;
local_char_length= my_charpos(field_charset, ptr + length_bytes,
ptr + length_bytes + length, local_char_length);
@@ -7603,26 +7649,29 @@ int Field_varstring::key_cmp(const uchar *a,const uchar *b)
void Field_varstring::sort_string(uchar *to,uint length)
{
- uint tot_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
+ String buf;
+
+ val_str(&buf, &buf);
if (field_charset == &my_charset_bin)
{
/* Store length last in high-byte order to sort longer strings first */
if (length_bytes == 1)
- to[length-1]= tot_length;
+ to[length - 1]= buf.length();
else
- mi_int2store(to+length-2, tot_length);
+ mi_int2store(to + length - 2, buf.length());
length-= length_bytes;
}
-
- tot_length= field_charset->coll->strnxfrm(field_charset,
- to, length,
- char_length() *
- field_charset->strxfrm_multiply,
- ptr + length_bytes, tot_length,
- MY_STRXFRM_PAD_WITH_SPACE |
- MY_STRXFRM_PAD_TO_MAXLEN);
- DBUG_ASSERT(tot_length == length);
+
+#ifndef DBUG_OFF
+ size_t rc=
+#endif
+ field_charset->coll->strnxfrm(field_charset, to, length,
+ char_length() * field_charset->strxfrm_multiply,
+ (const uchar*) buf.ptr(), buf.length(),
+ MY_STRXFRM_PAD_WITH_SPACE |
+ MY_STRXFRM_PAD_TO_MAXLEN);
+ DBUG_ASSERT(rc == length);
}
@@ -7638,16 +7687,22 @@ enum ha_base_keytype Field_varstring::key_type() const
}
+/*
+ Compressed columns need one extra byte to store the compression method.
+ This byte is invisible to the end user, but not for the storage engine.
+*/
+
void Field_varstring::sql_type(String &res) const
{
THD *thd= table->in_use;
CHARSET_INFO *cs=res.charset();
- ulong length;
+ size_t length;
length= cs->cset->snprintf(cs,(char*) res.ptr(),
res.alloced_length(), "%s(%d)",
(has_charset() ? "varchar" : "varbinary"),
- (int) field_length / charset()->mbmaxlen);
+ (int) field_length / charset()->mbmaxlen -
+ MY_TEST(compression_method()));
res.length(length);
if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) &&
has_charset() && (charset()->state & MY_CS_BINSORT))
@@ -7749,32 +7804,36 @@ uint Field_varstring::max_packed_col_length(uint max_length)
uint Field_varstring::get_key_image(uchar *buff, uint length,
imagetype type_arg)
{
- uint f_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- uint local_char_length= length / field_charset->mbmaxlen;
- uchar *pos= ptr+length_bytes;
- local_char_length= my_charpos(field_charset, pos, pos + f_length,
- local_char_length);
- set_if_smaller(f_length, local_char_length);
+ String val;
+ uint local_char_length;
+ my_bitmap_map *old_map;
+
+ old_map= dbug_tmp_use_all_columns(table, table->read_set);
+ val_str(&val, &val);
+ dbug_tmp_restore_column_map(table->read_set, old_map);
+
+ local_char_length= val.charpos(length / field_charset->mbmaxlen);
+ if (local_char_length < val.length())
+ val.length(local_char_length);
/* Key is always stored with 2 bytes */
- int2store(buff,f_length);
- memcpy(buff+HA_KEY_BLOB_LENGTH, pos, f_length);
- if (f_length < length)
+ int2store(buff, val.length());
+ memcpy(buff + HA_KEY_BLOB_LENGTH, val.ptr(), val.length());
+ if (val.length() < length)
{
/*
Must clear this as we do a memcmp in opt_range.cc to detect
identical keys
*/
- bzero(buff+HA_KEY_BLOB_LENGTH+f_length, (length-f_length));
+ memset(buff + HA_KEY_BLOB_LENGTH + val.length(), 0, length - val.length());
}
- return HA_KEY_BLOB_LENGTH+f_length;
+ return HA_KEY_BLOB_LENGTH + val.length();
}
void Field_varstring::set_key_image(const uchar *buff,uint length)
{
length= uint2korr(buff); // Real length is here
- (void) Field_varstring::store((const char*) buff+HA_KEY_BLOB_LENGTH, length,
- field_charset);
+ (void) store((const char*) buff + HA_KEY_BLOB_LENGTH, length, field_charset);
}
@@ -7831,13 +7890,14 @@ Field *Field_varstring::new_key_field(MEM_ROOT *root, TABLE *new_table,
uint Field_varstring::is_equal(Create_field *new_field)
{
if (new_field->type_handler() == type_handler() &&
- new_field->charset == field_charset)
+ new_field->charset == field_charset &&
+ !new_field->compression_method() == !compression_method())
{
- if (new_field->length == max_display_length())
+ if (new_field->length == field_length)
return IS_EQUAL_YES;
- if (new_field->length > max_display_length() &&
- ((new_field->length <= 255 && max_display_length() <= 255) ||
- (new_field->length > 255 && max_display_length() > 255)))
+ if (new_field->length > field_length &&
+ ((new_field->length <= 255 && field_length <= 255) ||
+ (new_field->length > 255 && field_length > 255)))
return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer variable length
}
return IS_EQUAL_NO;
@@ -7859,6 +7919,201 @@ void Field_varstring::hash(ulong *nr, ulong *nr2)
}
+/**
+ Compress field
+
+ @param[out] to destination buffer for compressed data
+ @param[in,out] to_length in: size of to, out: compressed data length
+ @param[in] from data to compress
+ @param[in] length from length
+ @param[in] cs from character set
+
+ In worst case (no compression performed) storage requirement is increased by
+ 1 byte to store header. If it exceeds field length, normal data truncation is
+ performed.
+
+ Generic compressed header format (1 byte):
+
+ Bits 1-4: method specific bits
+ Bits 5-8: compression method
+
+ If compression method is 0 then header is immediately followed by
+ uncompressed data.
+
+ If compression method is zlib:
+
+ Bits 1-3: number of bytes occupied by original data length
+ Bits 4: true if zlib wrapper not present
+ Bits 5-8: store 8 (zlib)
+
+ Header is immediately followed by original data length,
+ followed by compressed data.
+*/
+
+int Field_longstr::compress(char *to, uint *to_length,
+ const char *from, uint length,
+ CHARSET_INFO *cs)
+{
+ THD *thd= get_thd();
+ char *buf= 0;
+ int rc= 0;
+
+ if (length == 0)
+ {
+ *to_length= 0;
+ return 0;
+ }
+
+ if (String::needs_conversion_on_storage(length, cs, field_charset) ||
+ *to_length <= length)
+ {
+ String_copier copier;
+ const char *end= from + length;
+
+ if (!(buf= (char*) my_malloc(*to_length - 1, MYF(MY_WME))))
+ {
+ *to_length= 0;
+ return -1;
+ }
+
+ length= copier.well_formed_copy(field_charset, buf, *to_length - 1,
+ cs, from, length,
+ (*to_length - 1) / field_charset->mbmaxlen);
+ rc= check_conversion_status(&copier, end, cs, true);
+ from= buf;
+ DBUG_ASSERT(length > 0);
+ }
+
+ if (length >= thd->variables.column_compression_threshold &&
+ (*to_length= compression_method()->compress(thd, to, from, length)))
+ status_var_increment(thd->status_var.column_compressions);
+ else
+ {
+ /* Store uncompressed */
+ to[0]= 0;
+ memcpy(to + 1, from, length);
+ *to_length= length + 1;
+ }
+
+ if (buf)
+ my_free(buf);
+ return rc;
+}
+
+
+/*
+ Memory is allocated only when original data was actually compressed.
+ Otherwise val_ptr points at data located immediately after header.
+
+ Data can be stored uncompressed if data was shorter than threshold
+ or compressed data was longer than original data.
+*/
+
+String *Field_longstr::uncompress(String *val_buffer, String *val_ptr,
+ const uchar *from, uint from_length)
+{
+ if (from_length)
+ {
+ uchar method= (*from & 0xF0) >> 4;
+
+ /* Uncompressed data */
+ if (!method)
+ {
+ val_ptr->set((const char*) from + 1, from_length - 1, field_charset);
+ return val_ptr;
+ }
+
+ if (compression_methods[method].uncompress)
+ {
+ if (!compression_methods[method].uncompress(val_buffer, from, from_length,
+ field_length))
+ {
+ val_buffer->set_charset(field_charset);
+ status_var_increment(get_thd()->status_var.column_decompressions);
+ return val_buffer;
+ }
+ }
+ }
+
+ /*
+ It would be better to return 0 in case of errors, but to take the
+ safer route, let's return a zero string and let the general
+ handler catch the error.
+ */
+ val_ptr->set("", 0, field_charset);
+ return val_ptr;
+}
+
+
+int Field_varstring_compressed::store(const char *from, size_t length,
+ CHARSET_INFO *cs)
+{
+ ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ uint to_length= (uint)MY_MIN(field_length, field_charset->mbmaxlen * length + 1);
+ int rc= compress((char*) get_data(), &to_length, from, (uint)length, cs);
+ store_length(to_length);
+ return rc;
+}
+
+
+String *Field_varstring_compressed::val_str(String *val_buffer, String *val_ptr)
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ return uncompress(val_buffer, val_ptr, get_data(), get_length());
+}
+
+
+double Field_varstring_compressed::val_real(void)
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ THD *thd= get_thd();
+ String buf;
+ val_str(&buf, &buf);
+ return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset,
+ buf.ptr(), buf.length()).result();
+}
+
+
+longlong Field_varstring_compressed::val_int(void)
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ THD *thd= get_thd();
+ String buf;
+ val_str(&buf, &buf);
+ return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset,
+ buf.ptr(), buf.length()).result();
+}
+
+
+int Field_varstring_compressed::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
+ uint max_len)
+{
+ String a, b;
+ uint a_length, b_length;
+
+ if (length_bytes == 1)
+ {
+ a_length= (uint) *a_ptr;
+ b_length= (uint) *b_ptr;
+ }
+ else
+ {
+ a_length= uint2korr(a_ptr);
+ b_length= uint2korr(b_ptr);
+ }
+
+ uncompress(&a, &a, a_ptr + length_bytes, a_length);
+ uncompress(&b, &b, b_ptr + length_bytes, b_length);
+
+ if (a.length() > max_len)
+ a.length(max_len);
+ if (b.length() > max_len)
+ b.length(max_len);
+
+ return sortcmp(&a, &b, field_charset);
+}
+
+
/****************************************************************************
** blob type
** A blob is saved as a length and a pointer. The length is stored in the
@@ -7901,6 +8156,7 @@ uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg) const
int Field_blob::copy_value(Field_blob *from)
{
DBUG_ASSERT(field_charset == from->charset());
+ DBUG_ASSERT(!compression_method() == !from->compression_method());
int rc= 0;
uint32 length= from->get_length();
uchar *data= from->get_ptr();
@@ -7919,10 +8175,10 @@ int Field_blob::copy_value(Field_blob *from)
}
-int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
+int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
- uint copy_length, new_length;
+ size_t copy_length, new_length;
String_copier copier;
char *tmp;
char buff[STRING_BUFFER_USUAL_SIZE];
@@ -7941,7 +8197,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
DBUG_ASSERT(length <= max_data_length());
new_length= length;
- copy_length= (uint)MY_MIN(UINT_MAX,table->in_use->variables.group_concat_max_len);
+ copy_length= (size_t)MY_MIN(UINT_MAX,table->in_use->variables.group_concat_max_len);
if (new_length > copy_length)
{
new_length= Well_formed_prefix(cs,
@@ -7994,7 +8250,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
return 0;
}
copy_length= copier.well_formed_copy(field_charset,
- (char*) value.ptr(), new_length,
+ (char*) value.ptr(), (uint)new_length,
cs, from, length);
Field_blob::store_length(copy_length);
bmove(ptr+packlength,(uchar*) &tmp,sizeof(char*));
@@ -8008,22 +8264,6 @@ oom_error:
}
-int Field_blob::store(double nr)
-{
- CHARSET_INFO *cs=charset();
- value.set_real(nr, NOT_FIXED_DEC, cs);
- return Field_blob::store(value.ptr(),(uint) value.length(), cs);
-}
-
-
-int Field_blob::store(longlong nr, bool unsigned_val)
-{
- CHARSET_INFO *cs=charset();
- value.set_int(nr, unsigned_val, cs);
- return Field_blob::store(value.ptr(), (uint) value.length(), cs);
-}
-
-
double Field_blob::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
@@ -8133,7 +8373,7 @@ int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
uint Field_blob::get_key_image(uchar *buff,uint length, imagetype type_arg)
{
- uint32 blob_length= get_length(ptr);
+ size_t blob_length= get_length(ptr);
uchar *blob;
#ifdef HAVE_SPATIAL
@@ -8151,7 +8391,7 @@ uint Field_blob::get_key_image(uchar *buff,uint length, imagetype type_arg)
return image_length;
}
blob= get_ptr();
- gobj= Geometry::construct(&buffer, (char*) blob, blob_length);
+ gobj= Geometry::construct(&buffer, (char*) blob, (uint32)blob_length);
if (!gobj || gobj->get_mbr(&mbr, &dummy))
bzero(buff, image_length);
else
@@ -8166,12 +8406,12 @@ uint Field_blob::get_key_image(uchar *buff,uint length, imagetype type_arg)
#endif /*HAVE_SPATIAL*/
blob= get_ptr();
- uint local_char_length= length / field_charset->mbmaxlen;
+ size_t local_char_length= length / field_charset->mbmaxlen;
local_char_length= my_charpos(field_charset, blob, blob + blob_length,
local_char_length);
set_if_smaller(blob_length, local_char_length);
- if ((uint32) length > blob_length)
+ if (length > blob_length)
{
/*
Must clear this as we do a memcmp in opt_range.cc to detect
@@ -8197,14 +8437,14 @@ void Field_blob::set_key_image(const uchar *buff,uint length)
int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length)
{
uchar *blob1;
- uint blob_length=get_length(ptr);
+ size_t blob_length=get_length(ptr);
memcpy(&blob1, ptr+packlength, sizeof(char*));
CHARSET_INFO *cs= charset();
- uint local_char_length= max_key_length / cs->mbmaxlen;
+ size_t local_char_length= max_key_length / cs->mbmaxlen;
local_char_length= my_charpos(cs, blob1, blob1+blob_length,
local_char_length);
set_if_smaller(blob_length, local_char_length);
- return Field_blob::cmp(blob1, blob_length,
+ return Field_blob::cmp(blob1, (uint32)blob_length,
key_ptr+HA_KEY_BLOB_LENGTH,
uint2korr(key_ptr));
}
@@ -8240,9 +8480,9 @@ Field *Field_blob::new_key_field(MEM_ROOT *root, TABLE *new_table,
@returns number of bytes written to metadata_ptr
*/
-int Field_blob::do_save_field_metadata(uchar *metadata_ptr)
+int Field_blob::save_field_metadata(uchar *metadata_ptr)
{
- DBUG_ENTER("Field_blob::do_save_field_metadata");
+ DBUG_ENTER("Field_blob::save_field_metadata");
*metadata_ptr= pack_length_no_ptr();
DBUG_PRINT("debug", ("metadata: %u (pack_length_no_ptr)", *metadata_ptr));
DBUG_RETURN(1);
@@ -8258,33 +8498,30 @@ uint32 Field_blob::sort_length() const
void Field_blob::sort_string(uchar *to,uint length)
{
- uchar *blob;
- uint blob_length=get_length();
+ String buf;
- if (!blob_length && field_charset->pad_char == 0)
+ val_str(&buf, &buf);
+ if (!buf.length() && field_charset->pad_char == 0)
bzero(to,length);
else
{
if (field_charset == &my_charset_bin)
{
- uchar *pos;
-
/*
Store length of blob last in blob to shorter blobs before longer blobs
*/
length-= packlength;
- pos= to+length;
-
- store_bigendian(blob_length, pos, packlength);
+ store_bigendian(buf.length(), to + length, packlength);
}
- memcpy(&blob, ptr+packlength, sizeof(char*));
-
- blob_length= field_charset->coll->strnxfrm(field_charset,
- to, length, length,
- blob, blob_length,
- MY_STRXFRM_PAD_WITH_SPACE |
- MY_STRXFRM_PAD_TO_MAXLEN);
- DBUG_ASSERT(blob_length == length);
+
+#ifndef DBUG_OFF
+ size_t rc=
+#endif
+ field_charset->coll->strnxfrm(field_charset, to, length, length,
+ (const uchar*) buf.ptr(), buf.length(),
+ MY_STRXFRM_PAD_WITH_SPACE |
+ MY_STRXFRM_PAD_TO_MAXLEN);
+ DBUG_ASSERT(rc == length);
}
}
@@ -8380,11 +8617,9 @@ const uchar *Field_blob::unpack(uchar *to, const uchar *from,
DBUG_RETURN(0); // Error in data
uint32 const length= get_length(from, master_packlength);
DBUG_DUMP("packed", from, length + master_packlength);
- bitmap_set_bit(table->write_set, field_index);
if (from + master_packlength + length > from_end)
DBUG_RETURN(0);
- store(reinterpret_cast<const char*>(from) + master_packlength,
- length, field_charset);
+ set_ptr(length, const_cast<uchar*> (from) + master_packlength);
DBUG_RETURN(from + master_packlength + length);
}
@@ -8403,11 +8638,68 @@ uint Field_blob::max_packed_col_length(uint max_length)
}
+/*
+ Blob fields are regarded equal if they have same character set,
+ same blob store length and if either both are compressed or both are
+ uncompressed.
+ The logic for compression is that we don't have to uncompress and compress
+ again an already compressed field just because compression method changes.
+*/
+
uint Field_blob::is_equal(Create_field *new_field)
{
return new_field->type_handler() == type_handler() &&
new_field->charset == field_charset &&
- new_field->pack_length == pack_length();
+ new_field->pack_length == pack_length() &&
+ !new_field->compression_method() == !compression_method();
+}
+
+
+int Field_blob_compressed::store(const char *from, size_t length,
+ CHARSET_INFO *cs)
+{
+ ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ uint to_length= (uint)MY_MIN(max_data_length(), field_charset->mbmaxlen * length + 1);
+ int rc;
+
+ if (value.alloc(to_length))
+ {
+ set_ptr((uint32) 0, NULL);
+ return -1;
+ }
+
+ rc= compress((char*) value.ptr(), &to_length, from, (uint)length, cs);
+ set_ptr(to_length, (uchar*) value.ptr());
+ return rc;
+}
+
+
+String *Field_blob_compressed::val_str(String *val_buffer, String *val_ptr)
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ return uncompress(val_buffer, val_ptr, get_ptr(), get_length());
+}
+
+
+double Field_blob_compressed::val_real(void)
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ THD *thd= get_thd();
+ String buf;
+ val_str(&buf, &buf);
+ return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset,
+ buf.ptr(), buf.length()).result();
+}
+
+
+longlong Field_blob_compressed::val_int(void)
+{
+ ASSERT_COLUMN_MARKED_FOR_READ;
+ THD *thd= get_thd();
+ String buf;
+ val_str(&buf, &buf);
+ return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset,
+ buf.ptr(), buf.length()).result();
}
@@ -8461,7 +8753,7 @@ uint gis_field_options_image(uchar *buff, List<Create_field> &create_fields)
}
-uint gis_field_options_read(const uchar *buf, uint buf_len,
+uint gis_field_options_read(const uchar *buf, size_t buf_len,
Field_geom::storage_type *st_type,uint *precision, uint *scale, uint *srid)
{
const uchar *buf_end= buf + buf_len;
@@ -8567,7 +8859,7 @@ int Field_geom::store_decimal(const my_decimal *)
}
-int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
+int Field_geom::store(const char *from, size_t length, CHARSET_INFO *cs)
{
if (!length)
bzero(ptr, Field_blob::pack_length());
@@ -8584,7 +8876,7 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
wkb_type > (uint32) Geometry::wkb_last)
goto err;
- if (geom_type != Field::GEOM_GEOMETRY &&
+ if (geom_type != Field::GEOM_GEOMETRY &&
geom_type != Field::GEOM_GEOMETRYCOLLECTION &&
(uint32) geom_type != wkb_type)
{
@@ -8692,7 +8984,7 @@ void Field_enum::store_type(ulonglong value)
(if there isn't a empty value in the enum)
*/
-int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
+int Field_enum::store(const char *from,size_t length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
int err= 0;
@@ -8709,7 +9001,7 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
}
/* Remove end space */
- length= field_charset->cset->lengthsp(field_charset, from, length);
+ length= (uint)field_charset->cset->lengthsp(field_charset, from, length);
uint tmp=find_type2(typelib, from, length, field_charset);
if (!tmp)
{
@@ -8724,7 +9016,7 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
set_warning(WARN_DATA_TRUNCATED, 1);
err= 1;
}
- if (!get_thd()->count_cuted_fields && !length)
+ if ((get_thd()->count_cuted_fields <= CHECK_FIELD_EXPRESSION) && !length)
err= 0;
}
else
@@ -8751,7 +9043,7 @@ int Field_enum::store(longlong nr, bool unsigned_val)
if ((ulonglong) nr > typelib->count || nr == 0)
{
set_warning(WARN_DATA_TRUNCATED, 1);
- if (nr != 0 || get_thd()->count_cuted_fields)
+ if (nr != 0 || get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
nr= 0;
error= 1;
@@ -8786,7 +9078,7 @@ longlong Field_enum::val_int(void)
@returns number of bytes written to metadata_ptr
*/
-int Field_enum::do_save_field_metadata(uchar *metadata_ptr)
+int Field_enum::save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= real_type();
*(metadata_ptr + 1)= pack_length();
@@ -8875,7 +9167,7 @@ Field *Field_enum::make_new_field(MEM_ROOT *root, TABLE *new_table,
*/
-int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
+int Field_set::store(const char *from,size_t length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
bool got_warning= 0;
@@ -9294,14 +9586,14 @@ uint Field_bit::is_equal(Create_field *new_field)
}
-int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
+int Field_bit::store(const char *from, size_t length, CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
int delta;
for (; length && !*from; from++, length--) // skip left 0's
;
- delta= bytes_in_rec - length;
+ delta= (int)(bytes_in_rec - length);
if (delta < -1 ||
(delta == -1 && (uchar) *from > ((1 << bit_len) - 1)) ||
@@ -9505,9 +9797,9 @@ uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg)
@returns number of bytes written to metadata_ptr
*/
-int Field_bit::do_save_field_metadata(uchar *metadata_ptr)
+int Field_bit::save_field_metadata(uchar *metadata_ptr)
{
- DBUG_ENTER("Field_bit::do_save_field_metadata");
+ DBUG_ENTER("Field_bit::save_field_metadata");
DBUG_PRINT("debug", ("bit_len: %d, bytes_in_rec: %d",
bit_len, bytes_in_rec));
/*
@@ -9577,9 +9869,9 @@ Field_bit::compatible_field_size(uint field_metadata,
void Field_bit::sql_type(String &res) const
{
CHARSET_INFO *cs= res.charset();
- ulong length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ size_t length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
"bit(%d)", (int) field_length);
- res.length((uint) length);
+ res.length(length);
}
@@ -9730,7 +10022,7 @@ Field_bit_as_char::Field_bit_as_char(uchar *ptr_arg, uint32 len_arg,
}
-int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
+int Field_bit_as_char::store(const char *from, size_t length, CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
int delta;
@@ -9738,7 +10030,7 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
for (; length && !*from; from++, length--) // skip left 0's
;
- delta= bytes_in_rec - length;
+ delta= (int)(bytes_in_rec - length);
if (delta < 0 ||
(delta == 0 && bits && (uint) (uchar) *from >= (uint) (1 << bits)))
@@ -9761,9 +10053,9 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
void Field_bit_as_char::sql_type(String &res) const
{
CHARSET_INFO *cs= res.charset();
- ulong length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ size_t length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
"bit(%d)", (int) field_length);
- res.length((uint) length);
+ res.length(length);
}
@@ -9839,7 +10131,7 @@ bool Column_definition::create_interval_from_interval_list(MEM_ROOT *mem_root,
}
}
interval->type_names[i]= value.str;
- interval->type_lengths[i]= value.length;
+ interval->type_lengths[i]= (uint)value.length;
}
interval->type_names[interval->count]= 0; // End marker
interval->type_lengths[interval->count]= 0;
@@ -9977,6 +10269,8 @@ bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name,
uint filter= VCOL_IMPOSSIBLE;
if (type != VCOL_GENERATED_VIRTUAL && type != VCOL_DEFAULT)
filter|= VCOL_NOT_STRICTLY_DETERMINISTIC;
+ if (type == VCOL_GENERATED_VIRTUAL)
+ filter|= VCOL_NOT_VIRTUAL;
if (ret || (res.errors & filter))
{
@@ -10178,8 +10472,8 @@ bool Column_definition::check(THD *thd)
TIMESTAMP columns get implicit DEFAULT value when
explicit_defaults_for_timestamp is not set.
*/
- if (opt_explicit_defaults_for_timestamp ||
- !is_timestamp_type())
+ if ((opt_explicit_defaults_for_timestamp ||
+ !is_timestamp_type()) && !vers_sys_field())
{
flags|= NO_DEFAULT_VALUE_FLAG;
}
@@ -10234,7 +10528,8 @@ Field *make_field(TABLE_SHARE *share,
Field::geometry_type geom_type, uint srid,
Field::utype unireg_check,
TYPELIB *interval,
- const LEX_CSTRING *field_name)
+ const LEX_CSTRING *field_name,
+ uint32 flags)
{
uchar *UNINIT_VAR(bit_ptr);
uchar UNINIT_VAR(bit_offset);
@@ -10289,6 +10584,16 @@ Field *make_field(TABLE_SHARE *share,
unireg_check, field_name,
field_charset);
if (field_type == MYSQL_TYPE_VARCHAR)
+ {
+ if (unireg_check == Field::TMYSQL_COMPRESSED)
+ return new (mem_root)
+ Field_varstring_compressed(
+ ptr, field_length,
+ HA_VARCHAR_PACKLENGTH(field_length),
+ null_pos, null_bit,
+ unireg_check, field_name,
+ share, field_charset, zlib_compression_method);
+
return new (mem_root)
Field_varstring(ptr,field_length,
HA_VARCHAR_PACKLENGTH(field_length),
@@ -10296,6 +10601,7 @@ Field *make_field(TABLE_SHARE *share,
unireg_check, field_name,
share,
field_charset);
+ }
return 0; // Error
}
@@ -10317,10 +10623,18 @@ Field *make_field(TABLE_SHARE *share,
}
#endif
if (f_is_blob(pack_flag))
+ {
+ if (unireg_check == Field::TMYSQL_COMPRESSED)
+ return new (mem_root)
+ Field_blob_compressed(ptr, null_pos, null_bit,
+ unireg_check, field_name, share,
+ pack_length, field_charset, zlib_compression_method);
+
return new (mem_root)
Field_blob(ptr,null_pos,null_bit,
unireg_check, field_name, share,
pack_length, field_charset);
+ }
if (interval)
{
if (f_is_enum(pack_flag))
@@ -10400,11 +10714,22 @@ Field *make_field(TABLE_SHARE *share,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
case MYSQL_TYPE_LONGLONG:
- return new (mem_root)
- Field_longlong(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
+ if (flags & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG))
+ {
+ return new (mem_root)
+ Field_vers_trx_id(ptr, field_length, null_pos, null_bit,
+ unireg_check, field_name,
+ f_is_zerofill(pack_flag) != 0,
+ f_is_dec(pack_flag) == 0);
+ }
+ else
+ {
+ return new (mem_root)
+ Field_longlong(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name,
+ f_is_zerofill(pack_flag) != 0,
+ f_is_dec(pack_flag) == 0);
+ }
case MYSQL_TYPE_TIMESTAMP:
{
uint dec= field_length > MAX_DATETIME_WIDTH ?
@@ -10481,6 +10806,11 @@ Field *make_field(TABLE_SHARE *share,
return 0;
}
+bool Field_vers_trx_id::test_if_equality_guarantees_uniqueness(const Item* item) const
+{
+ return item->type() == Item::DATE_ITEM;
+}
+
/** Create a field suitable for create of table. */
@@ -10499,10 +10829,27 @@ Column_definition::Column_definition(THD *thd, Field *old_field,
comment= old_field->comment;
decimals= old_field->decimals();
vcol_info= old_field->vcol_info;
- default_value= orig_field ? orig_field->default_value : 0;
- check_constraint= orig_field ? orig_field->check_constraint : 0;
option_list= old_field->option_list;
pack_flag= 0;
+ compression_method_ptr= 0;
+ versioning= VERSIONING_NOT_SET;
+ invisible= old_field->invisible;
+
+ if (orig_field)
+ {
+ default_value= orig_field->default_value;
+ check_constraint= orig_field->check_constraint;
+ if (orig_field->unireg_check == Field::TMYSQL_COMPRESSED)
+ {
+ unireg_check= Field::TMYSQL_COMPRESSED;
+ compression_method_ptr= zlib_compression_method;
+ }
+ }
+ else
+ {
+ default_value= 0;
+ check_constraint= 0;
+ }
switch (real_field_type()) {
case MYSQL_TYPE_TINY_BLOB:
@@ -10523,7 +10870,8 @@ Column_definition::Column_definition(THD *thd, Field *old_field,
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
/* This is corrected in create_length_to_internal_length */
- length= (length+charset->mbmaxlen-1) / charset->mbmaxlen;
+ length= (length+charset->mbmaxlen-1) / charset->mbmaxlen -
+ MY_TEST(old_field->compression_method());
break;
#ifdef HAVE_SPATIAL
case MYSQL_TYPE_GEOMETRY:
@@ -10623,6 +10971,7 @@ Column_definition::redefine_stage1_common(const Column_definition *dup_field,
flags= dup_field->flags;
interval= dup_field->interval;
vcol_info= dup_field->vcol_info;
+ invisible= dup_field->invisible;
}
@@ -10687,6 +11036,29 @@ bool Column_definition::has_default_expression()
(flags & BLOB_FLAG)));
}
+
+bool Column_definition::set_compressed(const char *method)
+{
+ enum enum_field_types sql_type= real_field_type();
+ /* We can't use f_is_blob here as pack_flag is not yet set */
+ if (sql_type == MYSQL_TYPE_VARCHAR || sql_type == MYSQL_TYPE_TINY_BLOB ||
+ sql_type == MYSQL_TYPE_BLOB || sql_type == MYSQL_TYPE_MEDIUM_BLOB ||
+ sql_type == MYSQL_TYPE_LONG_BLOB)
+ {
+ if (!method || !strcmp(method, zlib_compression_method->name))
+ {
+ unireg_check= Field::TMYSQL_COMPRESSED;
+ compression_method_ptr= zlib_compression_method;
+ return false;
+ }
+ my_error(ER_UNKNOWN_COMPRESSION_METHOD, MYF(0), method);
+ }
+ else
+ my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name.str);
+ return true;
+}
+
+
/**
maximum possible display length for blob.
@@ -10725,11 +11097,12 @@ uint32 Field_blob::max_display_length()
@param cut_increment - whenever we should increase cut fields count
@note
- This function won't produce warning and increase cut fields counter
- if count_cuted_fields == CHECK_FIELD_IGNORE for current thread.
+ This function won't produce warning or notes or increase cut fields counter
+ if count_cuted_fields == CHECK_FIELD_IGNORE or CHECK_FIELD_EXPRESSION
+ for the current thread.
- if count_cuted_fields == CHECK_FIELD_IGNORE then we ignore notes.
- This allows us to avoid notes in optimisation, like convert_constant_item().
+ 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
@@ -10746,7 +11119,7 @@ Field::set_warning(Sql_condition::enum_warning_level level, uint code,
will have table == NULL.
*/
THD *thd= get_thd();
- if (thd->count_cuted_fields)
+ if (thd->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
thd->cuted_fields+= cut_increment;
push_warning_printf(thd, level, code, ER_THD(thd, code), field_name.str,