summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2020-10-31 21:06:49 +0100
committerOleksandr Byelkin <sanja@mariadb.com>2020-10-31 21:06:49 +0100
commit80c951ce2875aac521b82323b5b6ebf638593445 (patch)
treedf22c24e1fbe48362bd0eed50ec0c164e6c7e674 /sql
parent1fddccf676e213f94923f5efaaa76d9793b19a89 (diff)
parent794f66513967891520ec432123dcff8270871b93 (diff)
downloadmariadb-git-80c951ce2875aac521b82323b5b6ebf638593445.tar.gz
Merge branch '10.3' into 10.4
Diffstat (limited to 'sql')
-rw-r--r--sql/field.h3
-rw-r--r--sql/filesort.cc14
-rw-r--r--sql/item_cmpfunc.cc4
-rw-r--r--sql/item_func.cc6
-rw-r--r--sql/my_decimal.h6
-rw-r--r--sql/opt_sum.cc24
-rw-r--r--sql/sql_base.cc2
-rw-r--r--sql/sql_class.h2
-rw-r--r--sql/sql_parse.cc64
-rw-r--r--sql/sql_prepare.cc196
-rw-r--r--sql/sql_type.h16
-rw-r--r--sql/sys_vars.ic6
12 files changed, 295 insertions, 48 deletions
diff --git a/sql/field.h b/sql/field.h
index b3bc2d4dbea..a512d74b444 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1394,6 +1394,8 @@ public:
virtual uint max_packed_col_length(uint max_length)
{ return max_length;}
+ virtual bool is_packable() const { return false; }
+
uint offset(const uchar *record) const
{
return (uint) (ptr - record);
@@ -1986,6 +1988,7 @@ public:
bool can_optimize_range(const Item_bool_func *cond,
const Item *item,
bool is_eq_func) const;
+ bool is_packable() const { return true; }
};
/* base class for float and double and decimal (old one) */
diff --git a/sql/filesort.cc b/sql/filesort.cc
index aa25474be1a..ad4cb2b6e6b 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1978,7 +1978,14 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
if (sortorder->field)
{
CHARSET_INFO *cs= sortorder->field->sort_charset();
+ sortorder->type= sortorder->field->is_packable() ?
+ SORT_FIELD_ATTR::VARIABLE_SIZE :
+ SORT_FIELD_ATTR::FIXED_SIZE;
+
sortorder->length= sortorder->field->sort_length();
+ if (sortorder->is_variable_sized())
+ set_if_smaller(sortorder->length, thd->variables.max_sort_length);
+
if (use_strnxfrm((cs=sortorder->field->sort_charset())))
{
*multi_byte_charset= true;
@@ -1989,6 +1996,10 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
}
else
{
+ sortorder->type= sortorder->item->type_handler()->is_packable() ?
+ SORT_FIELD_ATTR::VARIABLE_SIZE :
+ SORT_FIELD_ATTR::FIXED_SIZE;
+
sortorder->item->type_handler()->sortlength(thd, sortorder->item,
sortorder);
if (use_strnxfrm(sortorder->item->collation.collation))
@@ -1998,7 +2009,8 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
if (sortorder->item->maybe_null)
length++; // Place for NULL marker
}
- set_if_smaller(sortorder->length, thd->variables.max_sort_length);
+ if (sortorder->is_variable_sized())
+ set_if_smaller(sortorder->length, thd->variables.max_sort_length);
length+=sortorder->length;
}
sortorder->field= (Field*) 0; // end marker
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 2904980c825..bf992886eda 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -866,6 +866,8 @@ int Arg_comparator::compare_decimal()
{
if (set_null)
owner->null_value= 0;
+ val1.round_self_if_needed((*a)->decimals, HALF_UP);
+ val2.round_self_if_needed((*b)->decimals, HALF_UP);
return val1.cmp(val2);
}
}
@@ -888,6 +890,8 @@ int Arg_comparator::compare_e_decimal()
VDec val1(*a), val2(*b);
if (val1.is_null() || val2.is_null())
return MY_TEST(val1.is_null() && val2.is_null());
+ val1.round_self_if_needed((*a)->decimals, HALF_UP);
+ val2.round_self_if_needed((*b)->decimals, HALF_UP);
return MY_TEST(val1.cmp(val2) == 0);
}
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 7a15f919742..6c0835be985 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1481,14 +1481,13 @@ double Item_func_div::real_op()
my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
{
int err;
- my_decimal tmp;
VDec2_lazy val(args[0], args[1]);
if ((null_value= val.has_null()))
return 0;
if ((err= check_decimal_overflow(my_decimal_div(E_DEC_FATAL_ERROR &
~E_DEC_OVERFLOW &
~E_DEC_DIV_ZERO,
- &tmp,
+ decimal_value,
val.m_a.ptr(), val.m_b.ptr(),
prec_increment))) > 3)
{
@@ -1497,7 +1496,6 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
null_value= 1;
return 0;
}
- tmp.round_to(decimal_value, decimals, HALF_UP);
return decimal_value;
}
@@ -3928,6 +3926,8 @@ int Interruptible_wait::wait(mysql_cond_t *cond, mysql_mutex_t *mutex)
timeout= m_abs_timeout;
error= mysql_cond_timedwait(cond, mutex, &timeout);
+ if (m_thd->check_killed())
+ break;
if (error == ETIMEDOUT || error == ETIME)
{
/* Return error if timed out or connection is broken. */
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index a7f6fc9e88d..9b1aebb98b5 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -207,15 +207,15 @@ public:
{
return to_string(to, 0, 0, 0);
}
- String *to_string_round(String *to, uint scale, my_decimal *round_buff) const
+ String *to_string_round(String *to, int scale, my_decimal *round_buff) const
{
(void) round_to(round_buff, scale, HALF_UP); // QQ: check result?
return round_buff->to_string(to);
}
- int round_to(my_decimal *to, uint scale, decimal_round_mode mode,
+ int round_to(my_decimal *to, int scale, decimal_round_mode mode,
int mask= E_DEC_FATAL_ERROR) const
{
- return check_result(mask, decimal_round(this, to, (int) scale, mode));
+ return check_result(mask, decimal_round(this, to, scale, mode));
}
int to_binary(uchar *bin, int prec, int scale,
uint mask= E_DEC_FATAL_ERROR) const;
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 0a3c30a176d..af2d9ddc2e7 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -399,20 +399,28 @@ int opt_sum_query(THD *thd,
break;
}
longlong info_limit= 1;
- table->file->info_push(INFO_KIND_FORCE_LIMIT_BEGIN, &info_limit);
- if (likely(!(error= table->file->ha_index_init((uint) ref.key, 1))))
- error= (is_max ?
- get_index_max_value(table, &ref, range_fl) :
- get_index_min_value(table, &ref, item_field, range_fl,
- prefix_len));
+ error= 0;
+ table->file->info_push(INFO_KIND_FORCE_LIMIT_BEGIN, &info_limit);
+ if (!table->const_table)
+ {
+ if (likely(!(error= table->file->ha_index_init((uint) ref.key,
+ 1))))
+ error= (is_max ?
+ get_index_max_value(table, &ref, range_fl) :
+ get_index_min_value(table, &ref, item_field, range_fl,
+ prefix_len));
+ }
/* Verify that the read tuple indeed matches the search key */
if (!error &&
reckey_in_range(is_max, &ref, item_field->field,
conds, range_fl, prefix_len))
error= HA_ERR_KEY_NOT_FOUND;
- table->file->ha_end_keyread();
- table->file->ha_index_end();
+ if (!table->const_table)
+ {
+ table->file->ha_end_keyread();
+ table->file->ha_index_end();
+ }
table->file->info_push(INFO_KIND_FORCE_LIMIT_END, NULL);
if (error)
{
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 9648f8922c2..4be70abb7db 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2020,7 +2020,7 @@ retry_share:
#ifdef WITH_WSREP
if (!((flags & MYSQL_OPEN_IGNORE_FLUSH) ||
- (wsrep_on(thd) && thd->wsrep_applier)))
+ (thd->wsrep_applier)))
#else
if (!(flags & MYSQL_OPEN_IGNORE_FLUSH))
#endif
diff --git a/sql/sql_class.h b/sql/sql_class.h
index fb22b0bcf6d..8c479db8936 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -6088,6 +6088,8 @@ struct SORT_FIELD_ATTR
{
uint length; /* Length of sort field */
uint suffix_length; /* Length suffix (0-4) */
+ enum Type { FIXED_SIZE, VARIABLE_SIZE } type;
+ bool is_variable_sized() { return type == VARIABLE_SIZE; }
};
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 6eb147d0480..8cb25197ea2 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -104,6 +104,8 @@
#include "my_json_writer.h"
+#define PRIV_LOCK_TABLES (SELECT_ACL | LOCK_TABLES_ACL)
+
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
#ifdef WITH_ARIA_STORAGE_ENGINE
@@ -1101,7 +1103,6 @@ int bootstrap(MYSQL_FILE *file)
thd->reset_kill_query(); /* Ensure that killed_errmsg is released */
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
thd->lex->restore_set_statement_var();
}
delete thd;
@@ -2939,6 +2940,36 @@ retry:
goto err;
}
}
+ /*
+ Check privileges of view tables here, after views were opened.
+ Either definer or invoker has to have PRIV_LOCK_TABLES to be able
+ to lock view and its tables. For mysqldump (that locks views
+ before dumping their structures) compatibility we allow locking
+ views that select from I_S or P_S tables, but downrade the lock
+ to TL_READ
+ */
+ if (table->belong_to_view &&
+ check_single_table_access(thd, PRIV_LOCK_TABLES, table, 1))
+ {
+ if (table->grant.m_internal.m_schema_access)
+ table->lock_type= TL_READ;
+ else
+ {
+ bool error= true;
+ if (Security_context *sctx= table->security_ctx)
+ {
+ table->security_ctx= 0;
+ error= check_single_table_access(thd, PRIV_LOCK_TABLES, table, 1);
+ table->security_ctx= sctx;
+ }
+ if (error)
+ {
+ my_error(ER_VIEW_INVALID, MYF(0), table->belong_to_view->view_db.str,
+ table->belong_to_view->view_name.str);
+ goto err;
+ }
+ }
+ }
}
if (lock_tables(thd, tables, counter, 0) ||
@@ -5415,7 +5446,7 @@ mysql_execute_command(THD *thd)
if (first_table && lex->type & (REFRESH_READ_LOCK|REFRESH_FOR_EXPORT))
{
/* Check table-level privileges. */
- if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
+ if (check_table_access(thd, PRIV_LOCK_TABLES, all_tables,
FALSE, UINT_MAX, FALSE))
goto error;
@@ -6755,7 +6786,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
@param thd Thread handler
@param privilege requested privilege
- @param all_tables global table list of query
+ @param tables global table list of query
@param no_errors FALSE/TRUE - report/don't report error to
the client (using my_error() call).
@@ -6765,28 +6796,25 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
1 access denied, error is sent to client
*/
-bool check_single_table_access(THD *thd, ulong privilege,
- TABLE_LIST *all_tables, bool no_errors)
+bool check_single_table_access(THD *thd, ulong privilege, TABLE_LIST *tables,
+ bool no_errors)
{
- Switch_to_definer_security_ctx backup_sctx(thd, all_tables);
+ Switch_to_definer_security_ctx backup_sctx(thd, tables);
const char *db_name;
- if ((all_tables->view || all_tables->field_translation) &&
- !all_tables->schema_table)
- db_name= all_tables->view_db.str;
+ if ((tables->view || tables->field_translation) && !tables->schema_table)
+ db_name= tables->view_db.str;
else
- db_name= all_tables->db.str;
+ db_name= tables->db.str;
- if (check_access(thd, privilege, db_name,
- &all_tables->grant.privilege,
- &all_tables->grant.m_internal,
- 0, no_errors))
+ if (check_access(thd, privilege, db_name, &tables->grant.privilege,
+ &tables->grant.m_internal, 0, no_errors))
return 1;
/* Show only 1 table for check_grant */
- if (!(all_tables->belong_to_view &&
- (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
- check_grant(thd, privilege, all_tables, FALSE, 1, no_errors))
+ if (!(tables->belong_to_view &&
+ (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
+ check_grant(thd, privilege, tables, FALSE, 1, no_errors))
return 1;
return 0;
@@ -9870,7 +9898,7 @@ static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables)
if (is_temporary_table(table))
continue;
- if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, table,
+ if (check_table_access(thd, PRIV_LOCK_TABLES, table,
FALSE, 1, FALSE))
return TRUE;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 518df6eb6a2..5240680aa95 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -124,6 +124,9 @@ When one supplies long data for a placeholder:
#include "transaction.h" // trans_rollback_implicit
#include "wsrep_mysqld.h"
+/* Constants defining bits in parameter type flags. Flags are read from high byte of short value */
+static const uint PARAMETER_FLAG_UNSIGNED = 128U << 8;
+
/**
A result class used to send cursor rows using the binary protocol.
*/
@@ -950,11 +953,73 @@ static bool insert_bulk_params(Prepared_statement *stmt,
DBUG_RETURN(0);
}
-static bool set_conversion_functions(Prepared_statement *stmt,
- uchar **data, uchar *data_end)
+
+/**
+ Checking if parameter type and flags are valid
+
+ @param typecode ushort value with type in low byte, and flags in high byte
+
+ @retval true this parameter is wrong
+ @retval false this parameter is OK
+*/
+
+static bool
+parameter_type_sanity_check(ushort typecode)
+{
+ /* Checking if type in lower byte is valid */
+ switch (typecode & 0xff) {
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_GEOMETRY:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_NEWDATE:
+ break;
+ /*
+ This types normally cannot be sent by client, so maybe it'd be
+ better to treat them like an error here.
+ */
+ case MYSQL_TYPE_TIMESTAMP2:
+ case MYSQL_TYPE_TIME2:
+ case MYSQL_TYPE_DATETIME2:
+ default:
+ return true;
+ };
+
+ // In Flags in high byte only unsigned bit may be set
+ if (typecode & ((~PARAMETER_FLAG_UNSIGNED) & 0x0000ff00))
+ {
+ return true;
+ }
+ return false;
+}
+
+static bool
+set_conversion_functions(Prepared_statement *stmt, uchar **data)
{
uchar *read_pos= *data;
- const uint signed_bit= 1 << 15;
+
DBUG_ENTER("set_conversion_functions");
/*
First execute or types altered by the client, setup the
@@ -967,12 +1032,17 @@ static bool set_conversion_functions(Prepared_statement *stmt,
{
ushort typecode;
- if (read_pos >= data_end)
- DBUG_RETURN(1);
-
+ /*
+ stmt_execute_packet_sanity_check has already verified, that there
+ are enough data in the packet for data types
+ */
typecode= sint2korr(read_pos);
read_pos+= 2;
- (**it).unsigned_flag= MY_TEST(typecode & signed_bit);
+ if (parameter_type_sanity_check(typecode))
+ {
+ DBUG_RETURN(1);
+ }
+ (**it).unsigned_flag= MY_TEST(typecode & PARAMETER_FLAG_UNSIGNED);
(*it)->setup_conversion(thd, (uchar) (typecode & 0xff));
(*it)->sync_clones();
}
@@ -982,7 +1052,7 @@ static bool set_conversion_functions(Prepared_statement *stmt,
static bool setup_conversion_functions(Prepared_statement *stmt,
- uchar **data, uchar *data_end,
+ uchar **data,
bool bulk_protocol= 0)
{
/* skip null bits */
@@ -995,7 +1065,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt,
if (*read_pos++) //types supplied / first execute
{
*data= read_pos;
- bool res= set_conversion_functions(stmt, data, data_end);
+ bool res= set_conversion_functions(stmt, data);
DBUG_RETURN(res);
}
*data= read_pos;
@@ -3146,11 +3216,19 @@ static void mysql_stmt_execute_common(THD *thd,
void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
{
+ const uint packet_min_lenght= 9;
uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround
+
+ DBUG_ENTER("mysqld_stmt_execute");
+
+ if (packet_length < packet_min_lenght)
+ {
+ my_error(ER_MALFORMED_PACKET, MYF(0));
+ DBUG_VOID_RETURN;
+ }
ulong stmt_id= uint4korr(packet);
ulong flags= (ulong) packet[4];
uchar *packet_end= packet + packet_length;
- DBUG_ENTER("mysqld_stmt_execute");
packet+= 9; /* stmt_id + 5 bytes of flags */
@@ -3206,6 +3284,84 @@ void mysqld_stmt_bulk_execute(THD *thd, char *packet_arg, uint packet_length)
DBUG_VOID_RETURN;
}
+/**
+ Additional packet checks for direct execution
+
+ @param thd THD handle
+ @param stmt prepared statement being directly executed
+ @param paket packet with parameters to bind
+ @param packet_end pointer to the byte after parameters end
+ @param bulk_op is it bulk operation
+ @param direct_exec is it direct execution
+ @param read_bytes need to read types (only with bulk_op)
+
+ @retval true this parameter is wrong
+ @retval false this parameter is OK
+*/
+
+static bool
+stmt_execute_packet_sanity_check(Prepared_statement *stmt,
+ uchar *packet, uchar *packet_end,
+ bool bulk_op, bool direct_exec,
+ bool read_types)
+{
+
+ DBUG_ASSERT((!read_types) || (read_types && bulk_op));
+ if (stmt->param_count > 0)
+ {
+ uint packet_length= static_cast<uint>(packet_end - packet);
+ uint null_bitmap_bytes= (bulk_op ? 0 : (stmt->param_count + 7)/8);
+ uint min_len_for_param_count = null_bitmap_bytes
+ + (bulk_op ? 0 : 1); /* sent types byte */
+
+ if (!bulk_op && packet_length >= min_len_for_param_count)
+ {
+ if ((read_types= packet[null_bitmap_bytes]))
+ {
+ /*
+ Should be 0 or 1. If the byte is not 1, that could mean,
+ e.g. that we read incorrect byte due to incorrect number
+ of sent parameters for direct execution (i.e. null bitmap
+ is shorter or longer, than it should be)
+ */
+ if (packet[null_bitmap_bytes] != '\1')
+ {
+ return true;
+ }
+ }
+ }
+
+ if (read_types)
+ {
+ /* 2 bytes per parameter of the type and flags */
+ min_len_for_param_count+= 2*stmt->param_count;
+ }
+ else
+ {
+ /*
+ If types are not sent, there is nothing to do here.
+ But for direct execution types should always be sent
+ */
+ return direct_exec;
+ }
+
+ /*
+ If true, the packet is guaranteed too short for the number of
+ parameters in the PS
+ */
+ return (packet_length < min_len_for_param_count);
+ }
+ else
+ {
+ /*
+ If there is no parameters, this should be normally already end
+ of the packet. If it's not - then error
+ */
+ return (packet_end > packet);
+ }
+ return false;
+}
+
/**
Common part of prepared statement execution
@@ -3245,6 +3401,22 @@ static void mysql_stmt_execute_common(THD *thd,
llstr(stmt_id, llbuf), "mysqld_stmt_execute");
DBUG_VOID_RETURN;
}
+
+ /*
+ In case of direct execution application decides how many parameters
+ to send.
+
+ Thus extra checks are required to prevent crashes caused by incorrect
+ interpretation of the packet data. Plus there can be always a broken
+ evil client.
+ */
+ if (stmt_execute_packet_sanity_check(stmt, packet, packet_end, bulk_op,
+ stmt_id == LAST_STMT_ID, read_types))
+ {
+ my_error(ER_MALFORMED_PACKET, MYF(0));
+ DBUG_VOID_RETURN;
+ }
+
stmt->read_types= read_types;
#if defined(ENABLED_PROFILING)
@@ -4157,7 +4329,7 @@ Prepared_statement::set_parameters(String *expanded_query,
{
#ifndef EMBEDDED_LIBRARY
uchar *null_array= packet;
- res= (setup_conversion_functions(this, &packet, packet_end) ||
+ res= (setup_conversion_functions(this, &packet) ||
set_params(this, null_array, packet, packet_end, expanded_query));
#else
/*
@@ -4357,7 +4529,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query,
#ifndef EMBEDDED_LIBRARY
if (read_types &&
- set_conversion_functions(this, &packet, packet_end))
+ set_conversion_functions(this, &packet))
#else
// bulk parameters are not supported for embedded, so it will an error
#endif
diff --git a/sql/sql_type.h b/sql/sql_type.h
index c1b13dfa811..939c651233c 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -230,7 +230,7 @@ class Dec_ptr_and_buffer: public Dec_ptr
protected:
my_decimal m_buffer;
public:
- int round_to(my_decimal *to, uint scale, decimal_round_mode mode)
+ int round_to(my_decimal *to, int scale, decimal_round_mode mode)
{
DBUG_ASSERT(m_ptr);
return m_ptr->round_to(to, scale, mode);
@@ -239,6 +239,14 @@ public:
{
return round_to(&m_buffer, scale, mode);
}
+ int round_self_if_needed(int scale, decimal_round_mode mode)
+ {
+ if (scale >= m_ptr->frac)
+ return E_DEC_OK;
+ int res= m_ptr->round_to(&m_buffer, scale, mode);
+ m_ptr= &m_buffer;
+ return res;
+ }
String *to_string_round(String *to, uint dec)
{
/*
@@ -3647,6 +3655,8 @@ public:
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const= 0;
+ virtual bool is_packable() const { return false; }
+
virtual uint32 max_display_length(const Item *item) const= 0;
virtual uint32 Item_decimal_notation_int_digits(const Item *item) const { return 0; }
virtual uint32 calc_pack_length(uint32 length) const= 0;
@@ -4788,7 +4798,11 @@ public:
void sortlength(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const;
+
+ bool is_packable()const { return true; }
+
bool union_element_finalize(const Item * item) const;
+
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic
index 9ab424b3f8d..50e2ec46222 100644
--- a/sql/sys_vars.ic
+++ b/sql/sys_vars.ic
@@ -726,7 +726,11 @@ public:
{ DBUG_ASSERT(FALSE); }
void global_save_default(THD *thd, set_var *var)
- { DBUG_ASSERT(FALSE); }
+ {
+ char *ptr= (char*)(intptr)option.def_value;
+ var->save_result.string_value.str= ptr;
+ var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
+ }
bool session_update(THD *thd, set_var *var)
{