summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2020-09-03 20:27:12 +0300
committerSergei Golubchik <serg@mariadb.org>2021-05-19 22:54:11 +0200
commit949d10bea27050970bf04aeaac4217e24997ce95 (patch)
tree4b1278de9d03ef2f858e4d12551d430c94eceaff
parenta206658b985fe5e18fb5692fdb3698dad5aca70a (diff)
downloadmariadb-git-949d10bea27050970bf04aeaac4217e24997ce95.tar.gz
Don't reset StringBuffers in loops when not needed
- Moved out creating StringBuffers in loops and instead create them outside and just reset the buffer if it was not allocated (to avoid a possible malloc/free for every entry) Other things related to set_buffer_if_not_allocated() - Changed Valuebuffer to not call set_buffer_if_not_allocated() when it is created. - Fixed geometry functions to reset string length before calling String::reserve(). This is because one should not access length() of an undefined. - Added Item_func_conv_charset::save_in_field() as the item is using str_value to store cached values, which conflicts with Item::save_str_in_field(). - Changed Item_proc_string to not store the string value in sql_string as this clashes with Item::save_str_in_field(). - Locally store value of full_name_cstring() in analyse::end_of_records() as Item::save_str_in_field() may overwrite it. - Marked some strings as set_thread_specific() - Added String::free_buffer() to be used internally in String functions to just free the buffer but not reset other String values. - Fixed uses_buffer_owned_by() to check for allocated length instead of strlength, which could be marked MEM_UNDEFINED().
-rw-r--r--sql/item.cc4
-rw-r--r--sql/item.h25
-rw-r--r--sql/item_geofunc.cc22
-rw-r--r--sql/item_strfunc.cc21
-rw-r--r--sql/item_strfunc.h1
-rw-r--r--sql/item_sum.cc2
-rw-r--r--sql/procedure.cc2
-rw-r--r--sql/procedure.h24
-rw-r--r--sql/protocol.cc10
-rw-r--r--sql/sp.cc1
-rw-r--r--sql/sql_analyse.cc13
-rw-r--r--sql/sql_select.cc4
-rw-r--r--sql/sql_show.cc8
-rw-r--r--sql/sql_string.cc5
-rw-r--r--sql/sql_string.h67
-rw-r--r--sql/sql_type.h2
-rw-r--r--sql/table.cc7
17 files changed, 151 insertions, 67 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 40583fd4359..1c6074e1916 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -4306,7 +4306,7 @@ bool Item_param::set_from_item(THD *thd, Item *item)
DBUG_RETURN(set_limit_clause_param(val));
}
}
- struct st_value tmp;
+ st_value tmp;
if (!item->save_in_value(thd, &tmp))
{
const Type_handler *h= item->type_handler();
@@ -4849,7 +4849,7 @@ bool
Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
{
Item *arg= *it;
- struct st_value tmp;
+ st_value tmp;
/*
The OUT parameter is bound to some data type.
It's important not to touch m_type_handler,
diff --git a/sql/item.h b/sql/item.h
index b5e3c14be43..d8991567250 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -42,8 +42,13 @@ C_MODE_START
3. change type of m_decmal to struct st_my_decimal and move inside the union
4. move the definition to some file in /include
*/
-struct st_value
+class st_value
{
+public:
+ st_value() {}
+ st_value(char *buffer, size_t buffer_size) :
+ m_string(buffer, buffer_size, &my_charset_bin)
+ {}
enum enum_dynamic_column_type m_type;
union
{
@@ -61,6 +66,10 @@ C_MODE_END
class Value: public st_value
{
public:
+ Value(char *buffer, size_t buffer_size) : st_value(buffer, buffer_size)
+ {}
+ Value()
+ {}
bool is_null() const { return m_type == DYN_COL_NULL; }
bool is_longlong() const
{
@@ -77,14 +86,12 @@ template<size_t buffer_size>
class ValueBuffer: public Value
{
char buffer[buffer_size];
- void reset_buffer()
- {
- m_string.set(buffer, buffer_size, &my_charset_bin);
- }
public:
- ValueBuffer()
+ ValueBuffer(): Value(buffer, buffer_size)
+ {}
+ void reset_buffer()
{
- reset_buffer();
+ m_string.set_buffer_if_not_allocated(buffer, buffer_size, &my_charset_bin);
}
};
@@ -996,7 +1003,7 @@ public:
/*
str_values's main purpose is to be used to cache the value in
- save_in_field
+ save_in_field. Calling full_name() for Item_field will also use str_value.
*/
String str_value;
@@ -1167,7 +1174,7 @@ public:
DBUG_ASSERT(0);
}
- bool save_in_value(THD *thd, struct st_value *value)
+ bool save_in_value(THD *thd, st_value *value)
{
return type_handler()->Item_save_in_value(thd, this, value);
}
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 4bdb0b85cd0..49b85e2213b 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -100,12 +100,12 @@ String *Item_func_geometry_from_wkb::val_str(String *str)
srid= (uint32)args[1]->val_int();
str->set_charset(&my_charset_bin);
+ str->length(0);
if (str->reserve(SRID_SIZE, 512))
{
null_value= TRUE; /* purecov: inspected */
return 0; /* purecov: inspected */
}
- str->length(0);
str->q_append(srid);
if ((null_value=
(args[0]->null_value ||
@@ -144,9 +144,9 @@ String *Item_func_geometry_from_json::val_str(String *str)
srid= (uint32)args[2]->val_int();
str->set_charset(&my_charset_bin);
+ str->length(0);
if (str->reserve(SRID_SIZE, 512))
return 0;
- str->length(0);
str->q_append(srid);
json_scan_start(&je, js->charset(), (const uchar *) js->ptr(),
@@ -456,9 +456,9 @@ String *Item_func_boundary::val_str(String *str_value)
goto mem_error;
str_value->set_charset(&my_charset_bin);
+ str_value->length(0);
if (str_value->reserve(SRID_SIZE, 512))
goto mem_error;
- str_value->length(0);
str_value->q_append(srid);
if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
@@ -487,9 +487,9 @@ String *Item_func_centroid::val_str(String *str)
return 0;
str->set_charset(&my_charset_bin);
+ str->length(0);
if (str->reserve(SRID_SIZE, 512))
return 0;
- str->length(0);
srid= uint4korr(swkb->ptr());
str->q_append(srid);
@@ -616,9 +616,9 @@ String *Item_func_convexhull::val_str(String *str_value)
build_result:
str_value->set_charset(&my_charset_bin);
+ str_value->length(0);
if (str_value->reserve(SRID_SIZE, 512))
goto mem_error;
- str_value->length(0);
str_value->q_append(srid);
if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
@@ -762,9 +762,9 @@ skip_point:;
build_result:
str_value->set_charset(&my_charset_bin);
+ str_value->length(0);
if (str_value->reserve(SRID_SIZE, 512))
goto mem_error;
- str_value->length(0);
str_value->q_append(srid);
if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
@@ -800,9 +800,9 @@ String *Item_func_spatial_decomp::val_str(String *str)
srid= uint4korr(swkb->ptr());
str->set_charset(&my_charset_bin);
+ str->length(0);
if (str->reserve(SRID_SIZE, 512))
goto err;
- str->length(0);
str->q_append(srid);
switch (decomp_func) {
case SP_STARTPOINT:
@@ -847,10 +847,10 @@ String *Item_func_spatial_decomp_n::val_str(String *str)
return 0;
str->set_charset(&my_charset_bin);
+ str->length(0);
if (str->reserve(SRID_SIZE, 512))
goto err;
srid= uint4korr(swkb->ptr());
- str->length(0);
str->q_append(srid);
switch (decomp_func_n)
{
@@ -1575,9 +1575,9 @@ String *Item_func_spatial_operation::val_str(String *str_value)
str_value->set_charset(&my_charset_bin);
+ str_value->length(0);
if (str_value->reserve(SRID_SIZE, 512))
goto exit;
- str_value->length(0);
str_value->q_append(srid);
if (!Geometry::create_from_opresult(&g1.buffer, str_value, res_receiver))
@@ -2045,9 +2045,9 @@ String *Item_func_buffer::val_str(String *str_value)
return_empty_result:
str_value->set_charset(&my_charset_bin);
+ str_value->length(0);
if (str_value->reserve(SRID_SIZE, 512))
goto mem_error;
- str_value->length(0);
str_value->q_append(srid);
if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
@@ -2737,10 +2737,10 @@ String *Item_func_pointonsurface::val_str(String *str)
goto exit;
str->set_charset(&my_charset_bin);
+ str->length(0);
if (str->reserve(SRID_SIZE, 512))
goto mem_error;
- str->length(0);
srid= uint4korr(res->ptr());
str->q_append(srid);
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index ec43ae81710..03b93f78775 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -3507,6 +3507,27 @@ String *Item_func_conv::val_str(String *str)
}
+/*
+ This function is needed as Item_func_conc_charset stores cached values
+ in str_value.
+*/
+
+int Item_func_conv_charset::save_in_field(Field *field, bool no_conversions)
+{
+ String *result;
+ CHARSET_INFO *cs= collation.collation;
+
+ result= val_str(&str_value);
+ if (null_value)
+ return set_field_to_null_with_conversions(field, no_conversions);
+
+ /* NOTE: If null_value == FALSE, "result" must be not NULL. */
+ field->set_notnull();
+ int error= field->store(result->ptr(),result->length(),cs);
+ return error;
+}
+
+
String *Item_func_conv_charset::val_str(String *str)
{
DBUG_ASSERT(fixed());
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 74e6add3f87..44ca750d617 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -1785,6 +1785,7 @@ public:
void print(String *str, enum_query_type query_type) override;
Item *get_copy(THD *thd) override
{ return get_item_copy<Item_func_conv_charset>(thd, this); }
+ int save_in_field(Field*, bool) override;
};
class Item_func_set_collation :public Item_str_func
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 4a87a1632b2..c61d8562fd4 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -4159,6 +4159,8 @@ bool Item_func_group_concat::add(bool exclude_nulls)
if (field->is_null_in_record((const uchar*) table->record[0]) &&
exclude_nulls)
return 0; // Skip row if it contains null
+
+ buf.set_buffer_if_not_allocated(&my_charset_bin);
if (tree && (res= field->val_str(&buf)))
row_str_len+= res->length();
}
diff --git a/sql/procedure.cc b/sql/procedure.cc
index 92df43bb0e3..21afef274bc 100644
--- a/sql/procedure.cc
+++ b/sql/procedure.cc
@@ -46,7 +46,7 @@ my_decimal *Item_proc_string::val_decimal(my_decimal *decimal_value)
{
if (null_value)
return 0;
- string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value);
+ string2my_decimal(E_DEC_FATAL_ERROR, &value, decimal_value);
return (decimal_value);
}
diff --git a/sql/procedure.h b/sql/procedure.h
index c83a52ff19c..c59b766d2b9 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -130,34 +130,40 @@ public:
class Item_proc_string :public Item_proc
{
+ String value;
public:
Item_proc_string(THD *thd, const char *name_par, uint length):
- Item_proc(thd, name_par) { this->max_length=length; }
+ Item_proc(thd, name_par)
+ {
+ this->max_length=length;
+ value.set_thread_specific();
+ }
const Type_handler *type_handler() const override
{ return &type_handler_varchar; }
- void set(double nr) override { str_value.set_real(nr, 2, default_charset()); }
- void set(longlong nr) override { str_value.set(nr, default_charset()); }
+ void set(double nr) override { value.set_real(nr, 2, default_charset()); }
+ void set(longlong nr) override { value.set(nr, default_charset()); }
void set(const char *str, uint length, CHARSET_INFO *cs) override
- { str_value.copy(str,length,cs); }
+ { value.copy(str,length,cs); }
double val_real() override
{
int err_not_used;
char *end_not_used;
- CHARSET_INFO *cs= str_value.charset();
- return cs->strntod((char*) str_value.ptr(), str_value.length(),
+ CHARSET_INFO *cs= value.charset();
+ return cs->strntod((char*) value.ptr(), value.length(),
&end_not_used, &err_not_used);
}
longlong val_int() override
{
int err;
- CHARSET_INFO *cs=str_value.charset();
- return cs->strntoll(str_value.ptr(),str_value.length(),10,NULL,&err);
+ CHARSET_INFO *cs=value.charset();
+ return cs->strntoll(value.ptr(), value.length(), 10, NULL, &err);
}
String *val_str(String*) override
{
- return null_value ? (String*) 0 : (String*) &str_value;
+ return null_value ? (String*) 0 : &value;
}
my_decimal *val_decimal(my_decimal *) override;
+ void cleanup() override { value.free(); }
unsigned int size_of() { return sizeof(*this);}
};
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 15fca88080e..70b526b581f 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -1316,18 +1316,12 @@ bool Protocol_text::store_field_metadata_for_list_fields(const THD *thd,
bool Protocol::send_result_set_row(List<Item> *row_items)
{
List_iterator_fast<Item> it(*row_items);
-
+ ValueBuffer<MAX_FIELD_WIDTH> value_buffer;
DBUG_ENTER("Protocol::send_result_set_row");
for (Item *item= it++; item; item= it++)
{
- /*
- ValueBuffer::m_string can be altered during Item::send().
- It's important to declare value_buffer inside the loop,
- to have ValueBuffer::m_string point to ValueBuffer::buffer
- on every iteration.
- */
- ValueBuffer<MAX_FIELD_WIDTH> value_buffer;
+ value_buffer.reset_buffer();
if (item->send(this, &value_buffer))
{
// If we're out of memory, reclaim some, to help us recover.
diff --git a/sql/sp.cc b/sql/sp.cc
index 12fb7e79cde..0b34d75cfec 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -960,6 +960,7 @@ Sp_handler::db_load_routine(THD *thd, const Database_qualified_name *name,
newlex.current_select= NULL;
defstr.set_charset(creation_ctx->get_client_cs());
+ defstr.set_thread_specific();
/*
We have to add DEFINER clause and provide proper routine characterstics in
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index a6fc7c25e55..d609fff5487 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -683,10 +683,19 @@ int analyse::end_of_records()
String *res, s_min(buff, sizeof(buff),&my_charset_bin),
s_max(buff, sizeof(buff),&my_charset_bin),
ans(buff, sizeof(buff),&my_charset_bin);
+ StringBuffer<NAME_LEN> name;
for (; f != f_end; f++)
{
- func_items[0]->set((*f)->item->full_name());
+ /*
+ We have to make a copy of full_name() as it stores it's value in str_value,
+ which is reset by save_str_in_field
+ */
+ LEX_CSTRING col_name= (*f)->item->full_name_cstring();
+ name.set_buffer_if_not_allocated(&my_charset_bin);
+ name.copy(col_name.str, col_name.length, &my_charset_bin);
+ func_items[0]->set((char*) name.ptr(), name.length(), &my_charset_bin);
+
if (!(*f)->found)
{
func_items[1]->null_value = 1;
@@ -1232,4 +1241,4 @@ uint check_ulonglong(const char *str, uint length)
}
while (*cmp && *cmp++ == *str++) ;
return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
-} /* check_ulonlong */
+} /* check_ulonglong */
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 2fdb89f301c..62eb66be646 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -4551,9 +4551,11 @@ void JOIN::exec_inner()
{
List_iterator_fast<Item> const_item_it(exec_const_order_group_cond);
Item *cur_const_item;
+ StringBuffer<MAX_FIELD_WIDTH> tmp;
while ((cur_const_item= const_item_it++))
{
- cur_const_item->val_str(); // This caches val_str() to Item::str_value
+ tmp.set_buffer_if_not_allocated(&my_charset_bin);
+ cur_const_item->val_str(&tmp);
if (unlikely(thd->is_error()))
{
error= thd->is_error();
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index bd73220310f..8e7e042264b 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2410,6 +2410,7 @@ int show_create_table_ex(THD *thd, TABLE_LIST *table_list,
/* Add table level check constraints */
if (share->table_check_constraints)
{
+ StringBuffer<MAX_FIELD_WIDTH> str(&my_charset_utf8mb4_general_ci);
for (uint i= share->field_check_constraints;
i < share->table_check_constraints ; i++)
{
@@ -2418,7 +2419,8 @@ int show_create_table_ex(THD *thd, TABLE_LIST *table_list,
if (share->period.constr_name.streq(check->name))
continue;
- StringBuffer<MAX_FIELD_WIDTH> str(&my_charset_utf8mb4_general_ci);
+ str.set_buffer_if_not_allocated(&my_charset_utf8mb4_general_ci);
+ str.length(0); // Print appends to str
check->print(&str);
packet->append(STRING_WITH_LEN(",\n "));
@@ -3036,14 +3038,16 @@ int select_result_text_buffer::append_row(List<Item> &items, bool send_names)
rows.push_back(row, thd->mem_root))
return true;
+ StringBuffer<32> buf;
+
while ((item= it++))
{
DBUG_ASSERT(column < n_columns);
- StringBuffer<32> buf;
const char *data_ptr;
char *ptr;
size_t data_len;
+ buf.set_buffer_if_not_allocated(&my_charset_bin);
if (send_names)
{
DBUG_ASSERT(strlen(item->name.str) == item->name.length);
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index aca9ede9000..c9117451374 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -40,7 +40,7 @@ bool Binary_string::real_alloc(size_t length)
str_length=0;
if (Alloced_length < arg_length)
{
- free();
+ free_buffer();
if (!(Ptr=(char*) my_malloc(STRING_PSI_MEMORY_KEY,
arg_length,MYF(MY_WME | (thread_specific ?
MY_THREAD_SPECIFIC : 0)))))
@@ -1112,7 +1112,8 @@ uint
String_copier::well_formed_copy(CHARSET_INFO *to_cs,
char *to, size_t to_length,
CHARSET_INFO *from_cs,
- const char *from, size_t from_length, size_t nchars)
+ const char *from, size_t from_length,
+ size_t nchars)
{
if ((to_cs == &my_charset_bin) ||
(from_cs == &my_charset_bin) ||
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 809e8cb8275..bb6e68ab31c 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -48,7 +48,8 @@ inline uint32 copy_and_convert(char *to, size_t to_length,
const char *from, size_t from_length,
CHARSET_INFO *from_cs, uint *errors)
{
- return my_convert(to, (uint)to_length, to_cs, from, (uint)from_length, from_cs, errors);
+ return my_convert(to, (uint)to_length, to_cs, from, (uint)from_length,
+ from_cs, errors);
}
@@ -110,7 +111,8 @@ public:
"dstcs" and "srccs" cannot be &my_charset_bin.
*/
size_t convert_fix(CHARSET_INFO *dstcs, char *dst, size_t dst_length,
- CHARSET_INFO *srccs, const char *src, size_t src_length, size_t nchars)
+ CHARSET_INFO *srccs, const char *src, size_t src_length,
+ size_t nchars)
{
return my_convert_fix(dstcs, dst, dst_length,
srccs, src, src_length, nchars, this, this);
@@ -119,10 +121,12 @@ public:
Copy a string. Fix bad bytes/characters to '?'.
*/
uint well_formed_copy(CHARSET_INFO *to_cs, char *to, size_t to_length,
- CHARSET_INFO *from_cs, const char *from, size_t from_length, size_t nchars);
+ CHARSET_INFO *from_cs, const char *from,
+ size_t from_length, size_t nchars);
// Same as above, but without the "nchars" limit.
uint well_formed_copy(CHARSET_INFO *to_cs, char *to, size_t to_length,
- CHARSET_INFO *from_cs, const char *from, size_t from_length)
+ CHARSET_INFO *from_cs, const char *from,
+ size_t from_length)
{
return well_formed_copy(to_cs, to, to_length,
from_cs, from, from_length,
@@ -369,6 +373,7 @@ public:
class Binary_string: public Static_binary_string
{
+protected:
uint32 Alloced_length, extra_alloc;
bool alloced, thread_specific;
void init_private_data()
@@ -376,6 +381,14 @@ class Binary_string: public Static_binary_string
Alloced_length= extra_alloc= 0;
alloced= thread_specific= false;
}
+ inline void free_buffer()
+ {
+ if (alloced)
+ {
+ alloced=0;
+ my_free(Ptr);
+ }
+ }
public:
Binary_string()
{
@@ -430,7 +443,7 @@ public:
inline bool uses_buffer_owned_by(const Binary_string *s) const
{
- return (s->alloced && Ptr >= s->Ptr && Ptr < s->Ptr + s->str_length);
+ return (s->alloced && Ptr >= s->Ptr && Ptr < s->Ptr + s->Alloced_length);
}
/* Swap two string objects. Efficient way to exchange data without memcpy. */
@@ -450,7 +463,7 @@ public:
*/
void set_alloced(char *str, size_t length_arg, size_t alloced_length_arg)
{
- free();
+ free_buffer();
Static_binary_string::set(str, length_arg);
DBUG_ASSERT(alloced_length_arg < UINT_MAX32);
Alloced_length= (uint32) alloced_length_arg;
@@ -461,15 +474,17 @@ public:
}
inline void set(const char *str, size_t arg_length)
{
- free();
+ free_buffer();
Static_binary_string::set((char *) str, arg_length);
+ Alloced_length= 0;
}
void set(Binary_string &str, size_t offset, size_t arg_length)
{
DBUG_ASSERT(&str != this);
- free();
+ free_buffer();
Static_binary_string::set((char*) str.ptr() + offset, arg_length);
+ Alloced_length= 0;
if (str.Alloced_length)
Alloced_length= (uint32) (str.Alloced_length - offset);
}
@@ -507,12 +522,14 @@ public:
if (!alloced)
{
/*
- Following should really be set_str(str, 0), but some code may
- depend on that the String lenth is same as buffer length.
+ Following should really set str_length= 0, but some code may
+ depend on that the String length is same as buffer length.
*/
Static_binary_string::set(str, arg_length);
Alloced_length= (uint32) arg_length;
}
+ /* One should set str_length before using it */
+ MEM_UNDEFINED(&str_length, sizeof(str_length));
}
inline Binary_string& operator=(const Binary_string &s)
@@ -660,19 +677,20 @@ public:
inline void free()
{
- if (alloced)
- {
- alloced=0;
- my_free(Ptr);
- }
+ free_buffer();
+ /*
+ We have to clear the values as some Strings, like in Field, are
+ reused after free(). Because of this we cannot use MEM_UNDEFINED() here.
+ */
+ Ptr= 0;
+ str_length= 0;
Alloced_length= extra_alloc= 0;
- Static_binary_string::set(NULL, 0); // Safety, probably not needed
}
inline bool alloc(size_t arg_length)
{
/*
- Allocate if we need more space or if we don't have p_done any
+ Allocate if we need more space or if we don't have done any
allocation yet (we don't want to have Ptr to be NULL for empty strings).
Note that if arg_length == Alloced_length then we don't allocate.
@@ -911,7 +929,8 @@ public:
if (unlikely(alloc(tocs->mbmaxlen * src_length)))
return true;
str_length= copier->well_formed_copy(tocs, Ptr, alloced_length(),
- fromcs, src, (uint)src_length, (uint)nchars);
+ fromcs, src, (uint) src_length,
+ (uint) nchars);
set_charset(tocs);
return false;
}
@@ -1066,6 +1085,18 @@ public:
{
length(0);
}
+ void set_buffer_if_not_allocated(CHARSET_INFO *cs)
+ {
+ if (!is_alloced())
+ {
+ Ptr= buff;
+ Alloced_length= (uint32) buff_sz;
+ }
+ str_length= 0; /* Safety, not required */
+ /* One should set str_length before using it */
+ MEM_UNDEFINED(&str_length, sizeof(str_length));
+ set_charset(cs);
+ }
};
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 0d62d9738d6..d1af12418a2 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -81,7 +81,7 @@ class Type_handler_hybrid_field_type;
class Sort_param;
class Arg_comparator;
class Spvar_definition;
-struct st_value;
+class st_value;
class Protocol;
class handler;
struct TABLE;
diff --git a/sql/table.cc b/sql/table.cc
index f907ae04f52..37bc5d62d4d 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -6144,6 +6144,8 @@ int TABLE::verify_constraints(bool ignore_failure)
{
if (versioned() && !vers_end_field()->is_max())
return VIEW_CHECK_OK;
+
+ StringBuffer<MAX_FIELD_WIDTH> field_error(system_charset_info);
for (Virtual_column_info **chk= check_constraints ; *chk ; chk++)
{
/*
@@ -6153,10 +6155,13 @@ int TABLE::verify_constraints(bool ignore_failure)
if (((*chk)->expr->val_int() == 0 && !(*chk)->expr->null_value) ||
in_use->is_error())
{
- StringBuffer<MAX_FIELD_WIDTH> field_error(system_charset_info);
enum_vcol_info_type vcol_type= (*chk)->get_vcol_type();
DBUG_ASSERT(vcol_type == VCOL_CHECK_TABLE ||
vcol_type == VCOL_CHECK_FIELD);
+
+ field_error.set_buffer_if_not_allocated(system_charset_info);
+ field_error.length(0);
+
if (vcol_type == VCOL_CHECK_FIELD)
{
field_error.append(s->table_name);