summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorJan Lindström <jan.lindstrom@mariadb.com>2017-08-09 08:56:11 +0300
committerJan Lindström <jan.lindstrom@mariadb.com>2017-08-09 08:56:11 +0300
commit56b03e308fb4c0feee166ddf6a707d855affa3c3 (patch)
treefc4e16093800cf4cbf1cc54fceb0b7280c4212ba /sql
parent4f40f87c48a9ee252f797b5d760a6b6f07cc3815 (diff)
parenta346a5613ee7c0b17b0b4ce377659c996ef6bb75 (diff)
downloadmariadb-git-56b03e308fb4c0feee166ddf6a707d855affa3c3.tar.gz
Merge tag 'mariadb-10.0.32' into 10.0-galera
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt15
-rw-r--r--sql/contributors.h2
-rw-r--r--sql/field.cc21
-rw-r--r--sql/field.h10
-rw-r--r--sql/ha_partition.cc210
-rw-r--r--sql/handler.cc4
-rw-r--r--sql/item.cc13
-rw-r--r--sql/item.h35
-rw-r--r--sql/item_cmpfunc.cc15
-rw-r--r--sql/item_cmpfunc.h2
-rw-r--r--sql/item_func.cc5
-rw-r--r--sql/item_func.h29
-rw-r--r--sql/item_geofunc.cc2
-rw-r--r--sql/item_geofunc.h2
-rw-r--r--sql/item_strfunc.cc254
-rw-r--r--sql/item_strfunc.h18
-rw-r--r--sql/item_subselect.cc6
-rw-r--r--sql/item_timefunc.cc2
-rw-r--r--sql/lock.cc37
-rw-r--r--sql/log.cc2
-rw-r--r--sql/multi_range_read.cc22
-rw-r--r--sql/mysqld.cc10
-rw-r--r--sql/net_serv.cc2
-rw-r--r--sql/opt_range.cc9
-rw-r--r--sql/opt_subselect.cc4
-rw-r--r--sql/partition_info.cc14
-rw-r--r--sql/partition_info.h5
-rw-r--r--sql/records.cc1
-rw-r--r--sql/rpl_handler.cc2
-rw-r--r--sql/rpl_mi.cc6
-rw-r--r--sql/rpl_rli.cc66
-rw-r--r--sql/rpl_rli.h12
-rw-r--r--sql/slave.cc39
-rw-r--r--sql/spatial.cc27
-rw-r--r--sql/sql_class.cc24
-rw-r--r--sql/sql_derived.cc2
-rw-r--r--sql/sql_load.cc2
-rw-r--r--sql/sql_parse.cc31
-rw-r--r--sql/sql_partition.cc158
-rw-r--r--sql/sql_partition.h12
-rw-r--r--sql/sql_partition_admin.cc8
-rw-r--r--sql/sql_plugin.cc20
-rw-r--r--sql/sql_priv.h2
-rw-r--r--sql/sql_repl.cc6
-rw-r--r--sql/sql_select.cc75
-rw-r--r--sql/sql_select.h8
-rw-r--r--sql/sql_show.cc18
-rw-r--r--sql/sql_union.cc18
-rw-r--r--sql/sys_vars.cc4
-rw-r--r--sql/threadpool_unix.cc14
-rw-r--r--sql/uniques.cc16
51 files changed, 823 insertions, 498 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 8606fd6890d..0f771d26bb5 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -43,15 +43,22 @@ SET_SOURCE_FILES_PROPERTIES(${GEN_SOURCES}
# Gen_lex_token
# Make sure sql_yacc.h is generated before compiling gen_lex_token
+
+IF(NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ SET(DEPENDS_gen_lex_token DEPENDS gen_lex_token)
+ SET(DEPENDS_gen_lex_hash DEPENDS gen_lex_hash)
+ENDIF()
+
+
IF(NOT CMAKE_CROSSCOMPILING)
- ADD_EXECUTABLE(gen_lex_token gen_lex_token.cc)
- ADD_DEPENDENCIES(gen_lex_token GenServerSource)
+ ADD_EXECUTABLE(gen_lex_token gen_lex_token.cc
+ ${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.h)
ENDIF()
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lex_token.h
COMMAND gen_lex_token > lex_token.h
- DEPENDS gen_lex_token
+ ${DEPENDS_gen_lex_token}
)
ADD_DEFINITIONS(-DMYSQL_SERVER -DHAVE_EVENT_SCHEDULER)
@@ -318,7 +325,7 @@ ENDIF()
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h
COMMAND gen_lex_hash > lex_hash.h
- DEPENDS gen_lex_hash
+ ${DEPENDS_gen_lex_hash}
)
MYSQL_ADD_EXECUTABLE(mysql_tzinfo_to_sql tztime.cc COMPONENT Server)
diff --git a/sql/contributors.h b/sql/contributors.h
index 3a771e2b493..88a4a088acf 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -39,9 +39,11 @@ struct show_table_contributors_st show_table_contributors[]= {
/* MariaDB foundation sponsors, in contribution, size , time order */
{"Booking.com", "https://www.booking.com", "Founding member, Platinum Sponsor of the MariaDB Foundation"},
{"Alibaba Cloud", "https://intl.aliyun.com", "Platinum Sponsor of the MariaDB Foundation"},
+ {"Tencent Cloud", "https://cloud.tencent.com", "Platinum Sponsor of the MariaDB Foundation"},
{"MariaDB Corporation", "https://mariadb.com", "Founding member, Gold Sponsor of the MariaDB Foundation"},
{"Visma", "https://visma.com", "Gold Sponsor of the MariaDB Foundation"},
{"DBS", "https://dbs.com", "Gold Sponsor of the MariaDB Foundation"},
+ {"IBM", "https://www.ibm.com", "Gold Sponsor of the MariaDB Foundation"},
{"Nexedi", "https://www.nexedi.com", "Silver Sponsor of the MariaDB Foundation"},
{"Acronis", "http://www.acronis.com", "Silver Sponsor of the MariaDB Foundation"},
{"Auttomattic", "https://automattic.com", "Bronze Sponsor of the MariaDB Foundation"},
diff --git a/sql/field.cc b/sql/field.cc
index 7d7fad2d84d..7a44bcadd3c 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -6403,9 +6403,6 @@ uint Field::is_equal(Create_field *new_field)
uint Field_str::is_equal(Create_field *new_field)
{
- if (field_flags_are_binary() != new_field->field_flags_are_binary())
- return 0;
-
return ((new_field->sql_type == real_type()) &&
new_field->charset == field_charset &&
new_field->length == max_display_length());
@@ -7810,9 +7807,6 @@ uint Field_blob::max_packed_col_length(uint max_length)
uint Field_blob::is_equal(Create_field *new_field)
{
- if (field_flags_are_binary() != new_field->field_flags_are_binary())
- return 0;
-
return ((new_field->sql_type == get_blob_type_from_length(max_data_length()))
&& new_field->charset == field_charset &&
new_field->pack_length == pack_length());
@@ -7933,6 +7927,18 @@ Field::geometry_type Field_geom::geometry_type_merge(geometry_type a,
return Field::GEOM_GEOMETRY;
}
+
+uint Field_geom::is_equal(Create_field *new_field)
+{
+ return new_field->sql_type == MYSQL_TYPE_GEOMETRY &&
+ /*
+ - Allow ALTER..INPLACE to supertype (GEOMETRY),
+ e.g. POINT to GEOMETRY or POLYGON to GEOMETRY.
+ - Allow ALTER..INPLACE to the same geometry type: POINT -> POINT
+ */
+ (new_field->geom_type == geom_type ||
+ new_field->geom_type == GEOM_GEOMETRY);
+}
#endif /*HAVE_SPATIAL*/
/****************************************************************************
@@ -8336,8 +8342,7 @@ uint Field_enum::is_equal(Create_field *new_field)
The fields are compatible if they have the same flags,
type, charset and have the same underlying length.
*/
- if (new_field->field_flags_are_binary() != field_flags_are_binary() ||
- new_field->sql_type != real_type() ||
+ if (new_field->sql_type != real_type() ||
new_field->charset != field_charset ||
new_field->pack_length != pack_length())
return IS_EQUAL_NO;
diff --git a/sql/field.h b/sql/field.h
index 2770b8be213..e7bd5532ae6 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1080,10 +1080,6 @@ protected:
const uchar *unpack_int64(uchar* to, const uchar *from, const uchar *from_end)
{ return unpack_int(to, from, from_end, 8); }
- bool field_flags_are_binary()
- {
- return (flags & (BINCMP_FLAG | BINARY_FLAG)) != 0;
- }
double pos_in_interval_val_real(Field *min, Field *max);
double pos_in_interval_val_str(Field *min, Field *max, uint data_offset);
};
@@ -2620,6 +2616,7 @@ public:
enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; }
bool match_collation_to_optimize_range() const { return false; }
void sql_type(String &str) const;
+ uint is_equal(Create_field *new_field);
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
@@ -2967,11 +2964,6 @@ public:
uint uint_geom_type, Virtual_column_info *vcol_info,
engine_option_value *option_list, bool check_exists);
- bool field_flags_are_binary()
- {
- return (flags & (BINCMP_FLAG | BINARY_FLAG)) != 0;
- }
-
ha_storage_media field_storage_type() const
{
return (ha_storage_media)
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index e854045661b..4441e975f93 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -680,7 +680,7 @@ int ha_partition::create(const char *name, TABLE *table_arg,
HA_CREATE_INFO *create_info)
{
int error;
- char name_buff[FN_REFLEN], name_lc_buff[FN_REFLEN];
+ char name_buff[FN_REFLEN + 1], name_lc_buff[FN_REFLEN];
char *name_buffer_ptr;
const char *path;
uint i;
@@ -722,8 +722,9 @@ int ha_partition::create(const char *name, TABLE *table_arg,
for (j= 0; j < m_part_info->num_subparts; j++)
{
part_elem= sub_it++;
- create_partition_name(name_buff, path, name_buffer_ptr,
- NORMAL_PART_NAME, FALSE);
+ if ((error= create_partition_name(name_buff, sizeof(name_buff), path,
+ name_buffer_ptr, NORMAL_PART_NAME, FALSE)))
+ goto create_error;
if ((error= set_up_table_before_create(table_arg, name_buff,
create_info, part_elem)) ||
((error= (*file)->ha_create(name_buff, table_arg, create_info))))
@@ -735,8 +736,9 @@ int ha_partition::create(const char *name, TABLE *table_arg,
}
else
{
- create_partition_name(name_buff, path, name_buffer_ptr,
- NORMAL_PART_NAME, FALSE);
+ if ((error= create_partition_name(name_buff, sizeof(name_buff), path,
+ name_buffer_ptr, NORMAL_PART_NAME, FALSE)))
+ goto create_error;
if ((error= set_up_table_before_create(table_arg, name_buff,
create_info, part_elem)) ||
((error= (*file)->ha_create(name_buff, table_arg, create_info))))
@@ -752,9 +754,9 @@ create_error:
name_buffer_ptr= m_name_buffer_ptr;
for (abort_file= file, file= m_file; file < abort_file; file++)
{
- create_partition_name(name_buff, path, name_buffer_ptr, NORMAL_PART_NAME,
- FALSE);
- (void) (*file)->ha_delete_table((const char*) name_buff);
+ if (!create_partition_name(name_buff, sizeof(name_buff), path,
+ name_buffer_ptr, NORMAL_PART_NAME, FALSE))
+ (void) (*file)->ha_delete_table((const char*) name_buff);
name_buffer_ptr= strend(name_buffer_ptr) + 1;
}
handler::delete_table(name);
@@ -781,7 +783,7 @@ create_error:
int ha_partition::drop_partitions(const char *path)
{
List_iterator<partition_element> part_it(m_part_info->partitions);
- char part_name_buff[FN_REFLEN];
+ char part_name_buff[FN_REFLEN + 1];
uint num_parts= m_part_info->partitions.elements;
uint num_subparts= m_part_info->num_subparts;
uint i= 0;
@@ -814,9 +816,11 @@ int ha_partition::drop_partitions(const char *path)
{
partition_element *sub_elem= sub_it++;
part= i * num_subparts + j;
- create_subpartition_name(part_name_buff, path,
- part_elem->partition_name,
- sub_elem->partition_name, name_variant);
+ if ((ret_error= create_subpartition_name(part_name_buff,
+ sizeof(part_name_buff), path,
+ part_elem->partition_name,
+ sub_elem->partition_name, name_variant)))
+ error= ret_error;
file= m_file[part];
DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff));
if ((ret_error= file->ha_delete_table(part_name_buff)))
@@ -827,15 +831,19 @@ int ha_partition::drop_partitions(const char *path)
}
else
{
- create_partition_name(part_name_buff, path,
- part_elem->partition_name, name_variant,
- TRUE);
- file= m_file[i];
- DBUG_PRINT("info", ("Drop partition %s", part_name_buff));
- if ((ret_error= file->ha_delete_table(part_name_buff)))
+ if ((ret_error= create_partition_name(part_name_buff,
+ sizeof(part_name_buff), path,
+ part_elem->partition_name, name_variant, TRUE)))
error= ret_error;
- if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos))
- error= 1;
+ else
+ {
+ file= m_file[i];
+ DBUG_PRINT("info", ("Drop partition %s", part_name_buff));
+ if ((ret_error= file->ha_delete_table(part_name_buff)))
+ error= ret_error;
+ if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos))
+ error= 1;
+ }
}
if (part_elem->part_state == PART_IS_CHANGED)
part_elem->part_state= PART_NORMAL;
@@ -871,8 +879,8 @@ int ha_partition::rename_partitions(const char *path)
{
List_iterator<partition_element> part_it(m_part_info->partitions);
List_iterator<partition_element> temp_it(m_part_info->temp_partitions);
- char part_name_buff[FN_REFLEN];
- char norm_name_buff[FN_REFLEN];
+ char part_name_buff[FN_REFLEN + 1];
+ char norm_name_buff[FN_REFLEN + 1];
uint num_parts= m_part_info->partitions.elements;
uint part_count= 0;
uint num_subparts= m_part_info->num_subparts;
@@ -914,10 +922,11 @@ int ha_partition::rename_partitions(const char *path)
{
sub_elem= sub_it++;
file= m_reorged_file[part_count++];
- create_subpartition_name(norm_name_buff, path,
- part_elem->partition_name,
- sub_elem->partition_name,
- NORMAL_PART_NAME);
+ if ((ret_error= create_subpartition_name(norm_name_buff,
+ sizeof(norm_name_buff), path,
+ part_elem->partition_name,
+ sub_elem->partition_name, NORMAL_PART_NAME)))
+ error= ret_error;
DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff));
if ((ret_error= file->ha_delete_table(norm_name_buff)))
error= ret_error;
@@ -930,16 +939,20 @@ int ha_partition::rename_partitions(const char *path)
else
{
file= m_reorged_file[part_count++];
- create_partition_name(norm_name_buff, path,
- part_elem->partition_name, NORMAL_PART_NAME,
- TRUE);
- DBUG_PRINT("info", ("Delete partition %s", norm_name_buff));
- if ((ret_error= file->ha_delete_table(norm_name_buff)))
+ if ((ret_error= create_partition_name(norm_name_buff,
+ sizeof(norm_name_buff), path,
+ part_elem->partition_name, NORMAL_PART_NAME, TRUE)))
error= ret_error;
- else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos))
- error= 1;
else
- part_elem->log_entry= NULL; /* Indicate success */
+ {
+ DBUG_PRINT("info", ("Delete partition %s", norm_name_buff));
+ if ((ret_error= file->ha_delete_table(norm_name_buff)))
+ error= ret_error;
+ else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos))
+ error= 1;
+ else
+ part_elem->log_entry= NULL; /* Indicate success */
+ }
}
} while (++i < temp_partitions);
(void) sync_ddl_log();
@@ -982,10 +995,11 @@ int ha_partition::rename_partitions(const char *path)
{
sub_elem= sub_it++;
part= i * num_subparts + j;
- create_subpartition_name(norm_name_buff, path,
- part_elem->partition_name,
- sub_elem->partition_name,
- NORMAL_PART_NAME);
+ if ((ret_error= create_subpartition_name(norm_name_buff,
+ sizeof(norm_name_buff), path,
+ part_elem->partition_name,
+ sub_elem->partition_name, NORMAL_PART_NAME)))
+ error= ret_error;
if (part_elem->part_state == PART_IS_CHANGED)
{
file= m_reorged_file[part_count++];
@@ -997,10 +1011,11 @@ int ha_partition::rename_partitions(const char *path)
(void) sync_ddl_log();
}
file= m_new_file[part];
- create_subpartition_name(part_name_buff, path,
- part_elem->partition_name,
- sub_elem->partition_name,
- TEMP_PART_NAME);
+ if ((ret_error= create_subpartition_name(part_name_buff,
+ sizeof(part_name_buff), path,
+ part_elem->partition_name,
+ sub_elem->partition_name, TEMP_PART_NAME)))
+ error= ret_error;
DBUG_PRINT("info", ("Rename subpartition from %s to %s",
part_name_buff, norm_name_buff));
if ((ret_error= file->ha_rename_table(part_name_buff,
@@ -1014,32 +1029,36 @@ int ha_partition::rename_partitions(const char *path)
}
else
{
- create_partition_name(norm_name_buff, path,
- part_elem->partition_name, NORMAL_PART_NAME,
- TRUE);
- if (part_elem->part_state == PART_IS_CHANGED)
+ if ((ret_error= create_partition_name(norm_name_buff,
+ sizeof(norm_name_buff), path,
+ part_elem->partition_name, NORMAL_PART_NAME, TRUE)) ||
+ (ret_error= create_partition_name(part_name_buff,
+ sizeof(part_name_buff), path,
+ part_elem->partition_name, TEMP_PART_NAME, TRUE)))
+ error= ret_error;
+ else
{
- file= m_reorged_file[part_count++];
- DBUG_PRINT("info", ("Delete partition %s", norm_name_buff));
- if ((ret_error= file->ha_delete_table(norm_name_buff)))
+ if (part_elem->part_state == PART_IS_CHANGED)
+ {
+ file= m_reorged_file[part_count++];
+ DBUG_PRINT("info", ("Delete partition %s", norm_name_buff));
+ if ((ret_error= file->ha_delete_table(norm_name_buff)))
+ error= ret_error;
+ else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos))
+ error= 1;
+ (void) sync_ddl_log();
+ }
+ file= m_new_file[i];
+ DBUG_PRINT("info", ("Rename partition from %s to %s",
+ part_name_buff, norm_name_buff));
+ if ((ret_error= file->ha_rename_table(part_name_buff,
+ norm_name_buff)))
error= ret_error;
else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos))
error= 1;
- (void) sync_ddl_log();
+ else
+ part_elem->log_entry= NULL;
}
- file= m_new_file[i];
- create_partition_name(part_name_buff, path,
- part_elem->partition_name, TEMP_PART_NAME,
- TRUE);
- DBUG_PRINT("info", ("Rename partition from %s to %s",
- part_name_buff, norm_name_buff));
- if ((ret_error= file->ha_rename_table(part_name_buff,
- norm_name_buff)))
- error= ret_error;
- else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos))
- error= 1;
- else
- part_elem->log_entry= NULL;
}
}
} while (++i < num_parts);
@@ -1655,7 +1674,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
{
List_iterator<partition_element> part_it(m_part_info->partitions);
List_iterator <partition_element> t_it(m_part_info->temp_partitions);
- char part_name_buff[FN_REFLEN];
+ char part_name_buff[FN_REFLEN + 1];
uint num_parts= m_part_info->partitions.elements;
uint num_subparts= m_part_info->num_subparts;
uint i= 0;
@@ -1883,10 +1902,14 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
do
{
partition_element *sub_elem= sub_it++;
- create_subpartition_name(part_name_buff, path,
- part_elem->partition_name,
- sub_elem->partition_name,
- name_variant);
+ if ((error= create_subpartition_name(part_name_buff,
+ sizeof(part_name_buff), path,
+ part_elem->partition_name, sub_elem->partition_name,
+ name_variant)))
+ {
+ cleanup_new_partition(part_count);
+ DBUG_RETURN(error);
+ }
part= i * num_subparts + j;
DBUG_PRINT("info", ("Add subpartition %s", part_name_buff));
if ((error= prepare_new_partition(table, create_info,
@@ -1904,9 +1927,14 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
}
else
{
- create_partition_name(part_name_buff, path,
- part_elem->partition_name, name_variant,
- TRUE);
+ if ((error= create_partition_name(part_name_buff,
+ sizeof(part_name_buff), path, part_elem->partition_name,
+ name_variant, TRUE)))
+ {
+ cleanup_new_partition(part_count);
+ DBUG_RETURN(error);
+ }
+
DBUG_PRINT("info", ("Add partition %s", part_name_buff));
if ((error= prepare_new_partition(table, create_info,
new_file_array[i],
@@ -2277,8 +2305,8 @@ uint ha_partition::del_ren_table(const char *from, const char *to)
{
int save_error= 0;
int error;
- char from_buff[FN_REFLEN], to_buff[FN_REFLEN], from_lc_buff[FN_REFLEN],
- to_lc_buff[FN_REFLEN];
+ char from_buff[FN_REFLEN + 1], to_buff[FN_REFLEN + 1],
+ from_lc_buff[FN_REFLEN], to_lc_buff[FN_REFLEN];
char *name_buffer_ptr;
const char *from_path;
const char *to_path= NULL;
@@ -2314,13 +2342,15 @@ uint ha_partition::del_ren_table(const char *from, const char *to)
i= 0;
do
{
- create_partition_name(from_buff, from_path, name_buffer_ptr,
- NORMAL_PART_NAME, FALSE);
+ if ((error= create_partition_name(from_buff, sizeof(from_buff), from_path,
+ name_buffer_ptr, NORMAL_PART_NAME, FALSE)))
+ goto rename_error;
if (to != NULL)
{ // Rename branch
- create_partition_name(to_buff, to_path, name_buffer_ptr,
- NORMAL_PART_NAME, FALSE);
+ if ((error= create_partition_name(to_buff, sizeof(to_buff), to_path,
+ name_buffer_ptr, NORMAL_PART_NAME, FALSE)))
+ goto rename_error;
error= (*file)->ha_rename_table(from_buff, to_buff);
if (error)
goto rename_error;
@@ -2349,12 +2379,14 @@ rename_error:
for (abort_file= file, file= m_file; file < abort_file; file++)
{
/* Revert the rename, back from 'to' to the original 'from' */
- create_partition_name(from_buff, from_path, name_buffer_ptr,
- NORMAL_PART_NAME, FALSE);
- create_partition_name(to_buff, to_path, name_buffer_ptr,
- NORMAL_PART_NAME, FALSE);
- /* Ignore error here */
- (void) (*file)->ha_rename_table(to_buff, from_buff);
+ if (!create_partition_name(from_buff, sizeof(from_buff), from_path,
+ name_buffer_ptr, NORMAL_PART_NAME, FALSE) &&
+ !create_partition_name(to_buff, sizeof(to_buff), to_path,
+ name_buffer_ptr, NORMAL_PART_NAME, FALSE))
+ {
+ /* Ignore error here */
+ (void) (*file)->ha_rename_table(to_buff, from_buff);
+ }
name_buffer_ptr= strend(name_buffer_ptr) + 1;
}
DBUG_RETURN(error);
@@ -3421,7 +3453,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
char *name_buffer_ptr;
int error= HA_ERR_INITIALIZATION;
handler **file;
- char name_buff[FN_REFLEN];
+ char name_buff[FN_REFLEN + 1];
ulonglong check_table_flags;
DBUG_ENTER("ha_partition::open");
@@ -3475,8 +3507,9 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
file= m_is_clone_of->m_file;
for (i= 0; i < m_tot_parts; i++)
{
- create_partition_name(name_buff, name, name_buffer_ptr, NORMAL_PART_NAME,
- FALSE);
+ if ((error= create_partition_name(name_buff, sizeof(name_buff), name,
+ name_buffer_ptr, NORMAL_PART_NAME, FALSE)))
+ goto err_handler;
/* ::clone() will also set ha_share from the original. */
if (!(m_file[i]= file[i]->clone(name_buff, m_clone_mem_root)))
{
@@ -3492,8 +3525,9 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
file= m_file;
do
{
- create_partition_name(name_buff, name, name_buffer_ptr, NORMAL_PART_NAME,
- FALSE);
+ if ((error= create_partition_name(name_buff, sizeof(name_buff), name,
+ name_buffer_ptr, NORMAL_PART_NAME, FALSE)))
+ goto err_handler;
table->s->connect_string = m_connect_string[(uint)(file-m_file)];
if ((error= (*file)->ha_open(table, name_buff, mode,
test_if_locked | HA_OPEN_NO_PSI_CALL)))
diff --git a/sql/handler.cc b/sql/handler.cc
index 91dde9a8d27..19f648219ac 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -3720,6 +3720,8 @@ void handler::print_error(int error, myf errflag)
*/
bool handler::get_error_message(int error, String* buf)
{
+ DBUG_EXECUTE_IF("external_lock_failure",
+ buf->set_ascii(STRING_WITH_LEN("KABOOM!")););
return FALSE;
}
@@ -6044,6 +6046,8 @@ int handler::ha_external_lock(THD *thd, int lock_type)
MYSQL_TABLE_LOCK_WAIT(m_psi, PSI_TABLE_EXTERNAL_LOCK, lock_type,
{ error= external_lock(thd, lock_type); })
+ DBUG_EXECUTE_IF("external_lock_failure", error= HA_ERR_GENERIC;);
+
if (error == 0 || lock_type == F_UNLCK)
{
m_lock_type= lock_type;
diff --git a/sql/item.cc b/sql/item.cc
index 4ce8396f71e..6bd982f8854 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2010, 2017, MariaDB
+ Copyright (c) 2010, 2017, MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -847,6 +847,7 @@ Item_ident::Item_ident(Name_resolution_context *context_arg,
cached_table(0), depended_from(0), can_be_depended(TRUE)
{
name = (char*) field_name_arg;
+ name_length= name ? strlen(name) : 0;
}
@@ -859,6 +860,7 @@ Item_ident::Item_ident(TABLE_LIST *view_arg, const char *field_name_arg)
cached_table(NULL), depended_from(NULL), can_be_depended(TRUE)
{
name = (char*) field_name_arg;
+ name_length= name ? strlen(name) : 0;
}
@@ -1263,6 +1265,7 @@ Item *Item::const_charset_converter(CHARSET_INFO *tocs,
DBUG_ASSERT(fixed);
StringBuffer<64>tmp;
String *s= val_str(&tmp);
+
if (!s)
return new Item_null((char *) func_name, tocs);
@@ -4564,7 +4567,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
int cur_match_degree= 0;
/* SELECT list element with explicit alias */
- if ((*(cur_group->item))->name &&
+ if ((*(cur_group->item))->name && !table_name &&
!(*(cur_group->item))->is_autogenerated_name &&
!my_strcasecmp(system_charset_info,
(*(cur_group->item))->name, field_name))
@@ -4987,6 +4990,12 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
0));
+ if (thd->lex->in_sum_func &&
+ thd->lex->in_sum_func->nest_level >= select->nest_level)
+ {
+ set_if_bigger(thd->lex->in_sum_func->max_arg_level,
+ select->nest_level);
+ }
/*
A reference to a view field had been found and we
substituted it instead of this Item (find_field_in_tables
diff --git a/sql/item.h b/sql/item.h
index 4d33a0eb6c1..f363950b9bc 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -830,25 +830,20 @@ public:
store return value of this method.
NOTE
- Buffer passed via argument should only be used if the item itself
- doesn't have an own String buffer. In case when the item maintains
- it's own string buffer, it's preferable to return it instead to
- minimize number of mallocs/memcpys.
- The caller of this method can modify returned string, but only in case
- when it was allocated on heap, (is_alloced() is true). This allows
- the caller to efficiently use a buffer allocated by a child without
- having to allocate a buffer of it's own. The buffer, given to
- val_str() as argument, belongs to the caller and is later used by the
- caller at it's own choosing.
- A few implications from the above:
- - unless you return a string object which only points to your buffer
- but doesn't manages it you should be ready that it will be
- modified.
- - even for not allocated strings (is_alloced() == false) the caller
- can change charset (see Item_func_{typecast/binary}. XXX: is this
- a bug?
- - still you should try to minimize data copying and return internal
- object whenever possible.
+ The caller can modify the returned String, if it's not marked
+ "const" (with the String::mark_as_const() method). That means that
+ if the item returns its own internal buffer (e.g. tmp_value), it
+ *must* be marked "const" [1]. So normally it's preferrable to
+ return the result value in the String, that was passed as an
+ argument. But, for example, SUBSTR() returns a String that simply
+ points into the buffer of SUBSTR()'s args[0]->val_str(). Such a
+ String is always "const", so it's ok to use tmp_value for that and
+ avoid reallocating/copying of the argument String.
+
+ [1] consider SELECT CONCAT(f, ":", f) FROM (SELECT func() AS f);
+ here the return value of f() is used twice in the top-level
+ select, and if they share the same tmp_value buffer, modifying the
+ first one will implicitly modify the second too.
RETURN
In case of NULL value return 0 (NULL pointer) and set null_value flag
@@ -1476,7 +1471,7 @@ public:
virtual Item *expr_cache_insert_transformer(uchar *thd_arg) { return this; }
virtual bool expr_cache_is_needed(THD *) { return FALSE; }
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
- bool needs_charset_converter(uint32 length, CHARSET_INFO *tocs)
+ bool needs_charset_converter(uint32 length, CHARSET_INFO *tocs) const
{
/*
This will return "true" if conversion happens:
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 038a0ebabc2..0134f628c80 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -5110,7 +5110,7 @@ void Regexp_processor_pcre::set_recursion_limit(THD *thd)
DBUG_ASSERT(thd == current_thd);
stack_used= available_stack_size(thd->thread_stack, &stack_used);
m_pcre_extra.match_limit_recursion=
- (my_thread_stack_size - stack_used)/my_pcre_frame_size;
+ (my_thread_stack_size - STACK_MIN_SIZE - stack_used)/my_pcre_frame_size;
}
@@ -5372,6 +5372,12 @@ void Regexp_processor_pcre::fix_owner(Item_func *owner,
}
+bool Item_func_regex::fix_fields(THD *thd, Item **ref)
+{
+ re.set_recursion_limit(thd);
+ return Item_bool_func::fix_fields(thd, ref);
+}
+
void
Item_func_regex::fix_length_and_dec()
{
@@ -5398,6 +5404,13 @@ longlong Item_func_regex::val_int()
}
+bool Item_func_regexp_instr::fix_fields(THD *thd, Item **ref)
+{
+ re.set_recursion_limit(thd);
+ return Item_int_func::fix_fields(thd, ref);
+}
+
+
void
Item_func_regexp_instr::fix_length_and_dec()
{
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 17ad1bd8c7d..ba0af32d76f 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1652,6 +1652,7 @@ public:
DBUG_VOID_RETURN;
}
longlong val_int();
+ bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
const char *func_name() const { return "regexp"; }
@@ -1679,6 +1680,7 @@ public:
DBUG_VOID_RETURN;
}
longlong val_int();
+ bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
const char *func_name() const { return "regexp_instr"; }
};
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 9c5ef502693..7e4ddb7427c 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -848,8 +848,9 @@ void Item_func_num1::fix_length_and_dec()
{
DBUG_ENTER("Item_func_num1::fix_length_and_dec");
DBUG_PRINT("info", ("name %s", func_name()));
- switch (cached_result_type= args[0]->cast_to_int_type()) {
+ switch (args[0]->cast_to_int_type()) {
case INT_RESULT:
+ cached_result_type= INT_RESULT;
max_length= args[0]->max_length;
unsigned_flag= args[0]->unsigned_flag;
break;
@@ -860,8 +861,8 @@ void Item_func_num1::fix_length_and_dec()
max_length= float_length(decimals);
break;
case TIME_RESULT:
- cached_result_type= DECIMAL_RESULT;
case DECIMAL_RESULT:
+ cached_result_type= DECIMAL_RESULT;
decimals= args[0]->decimal_scale(); // Do not preserve NOT_FIXED_DEC
max_length= args[0]->max_length;
break;
diff --git a/sql/item_func.h b/sql/item_func.h
index 0141619dced..5db92b6f3fe 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1174,7 +1174,11 @@ public:
longlong val_int();
const char *func_name() const { return "coercibility"; }
void fix_length_and_dec() { max_length=10; maybe_null= 0; }
- table_map not_null_tables() const { return 0; }
+ bool eval_not_null_tables(uchar *opt_arg)
+ {
+ not_null_tables_cache= 0;
+ return 0;
+ }
};
class Item_func_locate :public Item_int_func
@@ -1445,7 +1449,11 @@ public:
}
void cleanup();
Item_result result_type () const { return udf.result_type(); }
- table_map not_null_tables() const { return 0; }
+ bool eval_not_null_tables(uchar *opt_arg)
+ {
+ not_null_tables_cache= 0;
+ return 0;
+ }
bool is_expensive() { return 1; }
virtual void print(String *str, enum_query_type query_type);
};
@@ -1922,7 +1930,11 @@ public:
bool is_expensive_processor(uchar *arg) { return TRUE; }
enum Functype functype() const { return FT_FUNC; }
const char *func_name() const { return "match"; }
- table_map not_null_tables() const { return 0; }
+ bool eval_not_null_tables(uchar *opt_arg)
+ {
+ not_null_tables_cache= 0;
+ return 0;
+ }
bool fix_fields(THD *thd, Item **ref);
bool eq(const Item *, bool binary_cmp) const;
/* The following should be safe, even if we compare doubles */
@@ -2159,6 +2171,11 @@ public:
{
return TRUE;
}
+ bool eval_not_null_tables(uchar *opt_arg)
+ {
+ not_null_tables_cache= 0;
+ return 0;
+ }
};
@@ -2206,7 +2223,11 @@ public:
void fix_length_and_dec();
enum Item_result result_type () const { return last_value->result_type(); }
const char *func_name() const { return "last_value"; }
- table_map not_null_tables() const { return 0; }
+ bool eval_not_null_tables(uchar *opt_arg)
+ {
+ not_null_tables_cache= 0;
+ return 0;
+ }
enum_field_types field_type() const { return last_value->field_type(); }
bool const_item() const { return 0; }
void evaluate_sideeffects();
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 568a28e6465..a9e39ab717a 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -1268,7 +1268,7 @@ String *Item_func_buffer::val_str(String *str_value)
{
DBUG_ENTER("Item_func_buffer::val_str");
DBUG_ASSERT(fixed == 1);
- String *obj= args[0]->val_str(&tmp_value);
+ String *obj= args[0]->val_str(str_value);
double dist= args[1]->val_real();
Geometry_buffer buffer;
Geometry *g;
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index 62d2198e221..d32edff599c 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -171,7 +171,6 @@ public:
class Item_func_spatial_collection: public Item_geometry_func
{
- String tmp_value;
enum Geometry::wkbType coll_type;
enum Geometry::wkbType item_type;
public:
@@ -325,7 +324,6 @@ protected:
Gcalc_result_receiver res_receiver;
Gcalc_operation_reducer operation;
- String tmp_value;
public:
Item_func_buffer(Item *obj, Item *distance):
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 7cd712cc5e1..c3043adac47 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -73,8 +73,14 @@ size_t username_char_length= 80;
Conversion happens only in case of "tricky" Item character set (e.g. UCS2).
Normally conversion does not happen, and val_str_ascii() is immediately
returned instead.
+
+ No matter if conversion is needed or not needed,
+ the result is always returned in "str" (see MDEV-10306 why).
+
+ @param [OUT] str - Store the result here
+ @param [IN] ascii_buffer - Use this temporary buffer to call val_str_ascii()
*/
-String *Item_func::val_str_from_val_str_ascii(String *str, String *str2)
+String *Item_func::val_str_from_val_str_ascii(String *str, String *ascii_buffer)
{
DBUG_ASSERT(fixed == 1);
@@ -86,19 +92,19 @@ String *Item_func::val_str_from_val_str_ascii(String *str, String *str2)
return res;
}
- DBUG_ASSERT(str != str2);
+ DBUG_ASSERT(str != ascii_buffer);
uint errors;
- String *res= val_str_ascii(str);
+ String *res= val_str_ascii(ascii_buffer);
if (!res)
return 0;
- if ((null_value= str2->copy(res->ptr(), res->length(),
- &my_charset_latin1, collation.collation,
- &errors)))
+ if ((null_value= str->copy(res->ptr(), res->length(),
+ &my_charset_latin1, collation.collation,
+ &errors)))
return 0;
- return str2;
+ return str;
}
@@ -368,12 +374,12 @@ void Item_func_sha2::fix_length_and_dec()
/* Implementation of AES encryption routines */
-String *Item_func_aes_encrypt::val_str(String *str)
+String *Item_func_aes_encrypt::val_str(String *str2)
{
DBUG_ASSERT(fixed == 1);
char key_buff[80];
String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info);
- String *sptr= args[0]->val_str(str); // String to encrypt
+ String *sptr= args[0]->val_str(&str_value); // String to encrypt
String *key= args[1]->val_str(&tmp_key_value); // key
int aes_length;
if (sptr && key) // we need both arguments to be not NULL
@@ -381,15 +387,15 @@ String *Item_func_aes_encrypt::val_str(String *str)
null_value=0;
aes_length=my_aes_get_size(sptr->length()); // Calculate result length
- if (!str_value.alloc(aes_length)) // Ensure that memory is free
+ if (!str2->alloc(aes_length)) // Ensure that memory is free
{
// finally encrypt directly to allocated buffer.
- if (my_aes_encrypt(sptr->ptr(),sptr->length(), (char*) str_value.ptr(),
+ if (my_aes_encrypt(sptr->ptr(),sptr->length(), (char*) str2->ptr(),
key->ptr(), key->length()) == aes_length)
{
// We got the expected result length
- str_value.length((uint) aes_length);
- return &str_value;
+ str2->length((uint) aes_length);
+ return str2;
}
}
}
@@ -412,22 +418,22 @@ String *Item_func_aes_decrypt::val_str(String *str)
String *sptr, *key;
DBUG_ENTER("Item_func_aes_decrypt::val_str");
- sptr= args[0]->val_str(str); // String to decrypt
+ sptr= args[0]->val_str(&str_value); // String to decrypt
key= args[1]->val_str(&tmp_key_value); // Key
if (sptr && key) // Need to have both arguments not NULL
{
null_value=0;
- if (!str_value.alloc(sptr->length())) // Ensure that memory is free
+ if (!str->alloc(sptr->length())) // Ensure that memory is free
{
// finally decrypt directly to allocated buffer.
int length;
length=my_aes_decrypt(sptr->ptr(), sptr->length(),
- (char*) str_value.ptr(),
+ (char*) str->ptr(),
key->ptr(), key->length());
if (length >= 0) // if we got correct data data
{
- str_value.length((uint) length);
- DBUG_RETURN(&str_value);
+ str->length((uint) length);
+ DBUG_RETURN(str);
}
}
}
@@ -464,7 +470,7 @@ void Item_func_to_base64::fix_length_and_dec()
String *Item_func_to_base64::val_str_ascii(String *str)
{
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
bool too_long= false;
int length;
if (!res ||
@@ -472,7 +478,7 @@ String *Item_func_to_base64::val_str_ascii(String *str)
(too_long=
((uint) (length= base64_needed_encoded_length((int) res->length())) >
current_thd->variables.max_allowed_packet)) ||
- tmp_value.alloc((uint) length))
+ str->alloc((uint) length))
{
null_value= 1; // NULL input, too long input, or OOM.
if (too_long)
@@ -484,11 +490,11 @@ String *Item_func_to_base64::val_str_ascii(String *str)
}
return 0;
}
- base64_encode(res->ptr(), (int) res->length(), (char*) tmp_value.ptr());
+ base64_encode(res->ptr(), (int) res->length(), (char*) str->ptr());
DBUG_ASSERT(length > 0);
- tmp_value.length((uint) length - 1); // Without trailing '\0'
+ str->length((uint) length - 1); // Without trailing '\0'
null_value= 0;
- return &tmp_value;
+ return str;
}
@@ -509,7 +515,7 @@ void Item_func_from_base64::fix_length_and_dec()
String *Item_func_from_base64::val_str(String *str)
{
- String *res= args[0]->val_str_ascii(str);
+ String *res= args[0]->val_str_ascii(&tmp_value);
int length;
const char *end_ptr;
@@ -527,11 +533,11 @@ String *Item_func_from_base64::val_str(String *str)
goto err;
}
- if (tmp_value.alloc((uint) length))
+ if (str->alloc((uint) length))
goto err;
if ((length= base64_decode(res->ptr(), (int) res->length(),
- (char *) tmp_value.ptr(), &end_ptr, 0)) < 0 ||
+ (char *) str->ptr(), &end_ptr, 0)) < 0 ||
end_ptr < res->ptr() + res->length())
{
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -540,9 +546,9 @@ String *Item_func_from_base64::val_str(String *str)
goto err;
}
- tmp_value.length((uint) length);
+ str->length((uint) length);
null_value= 0;
- return &tmp_value;
+ return str;
err:
null_value= 1; // NULL input, too long input, OOM, or badly formed input
return 0;
@@ -797,7 +803,7 @@ String *Item_func_des_encrypt::val_str(String *str)
struct st_des_keyschedule keyschedule;
const char *append_str="********";
uint key_number, res_length, tail;
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
if ((null_value= args[0]->null_value))
return 0; // ENCRYPT(NULL) == NULL
@@ -821,7 +827,7 @@ String *Item_func_des_encrypt::val_str(String *str)
}
else
{
- String *keystr=args[1]->val_str(&tmp_value);
+ String *keystr= args[1]->val_str(str);
if (!keystr)
goto error;
key_number=127; // User key string
@@ -853,23 +859,23 @@ String *Item_func_des_encrypt::val_str(String *str)
tmp_arg.length(0);
tmp_arg.append(res->ptr(), res->length());
code= ER_OUT_OF_RESOURCES;
- if (tmp_arg.append(append_str, tail) || tmp_value.alloc(res_length+1))
+ if (tmp_arg.append(append_str, tail) || str->alloc(res_length+1))
goto error;
tmp_arg[res_length-1]=tail; // save extra length
- tmp_value.realloc(res_length+1);
- tmp_value.length(res_length+1);
- tmp_value.set_charset(&my_charset_bin);
- tmp_value[0]=(char) (128 | key_number);
+ str->realloc(res_length+1);
+ str->length(res_length+1);
+ str->set_charset(&my_charset_bin);
+ (*str)[0]=(char) (128 | key_number);
// Real encryption
bzero((char*) &ivec,sizeof(ivec));
DES_ede3_cbc_encrypt((const uchar*) (tmp_arg.ptr()),
- (uchar*) (tmp_value.ptr()+1),
+ (uchar*) (str->ptr()+1),
res_length,
&keyschedule.ks1,
&keyschedule.ks2,
&keyschedule.ks3,
&ivec, TRUE);
- return &tmp_value;
+ return str;
error:
push_warning_printf(current_thd,Sql_condition::WARN_LEVEL_WARN,
@@ -893,7 +899,7 @@ String *Item_func_des_decrypt::val_str(String *str)
DES_cblock ivec;
struct st_des_keyblock keyblock;
struct st_des_keyschedule keyschedule;
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
uint length,tail;
if ((null_value= args[0]->null_value))
@@ -917,7 +923,7 @@ String *Item_func_des_decrypt::val_str(String *str)
else
{
// We make good 24-byte (168 bit) key from given plaintext key with MD5
- String *keystr=args[1]->val_str(&tmp_value);
+ String *keystr= args[1]->val_str(str);
if (!keystr)
goto error;
@@ -932,23 +938,23 @@ String *Item_func_des_decrypt::val_str(String *str)
DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3);
}
code= ER_OUT_OF_RESOURCES;
- if (tmp_value.alloc(length-1))
+ if (str->alloc(length-1))
goto error;
bzero((char*) &ivec,sizeof(ivec));
DES_ede3_cbc_encrypt((const uchar*) res->ptr()+1,
- (uchar*) (tmp_value.ptr()),
+ (uchar*) (str->ptr()),
length-1,
&keyschedule.ks1,
&keyschedule.ks2,
&keyschedule.ks3,
&ivec, FALSE);
/* Restore old length of key */
- if ((tail=(uint) (uchar) tmp_value[length-2]) > 8)
+ if ((tail=(uint) (uchar) (*str)[length-2]) > 8)
goto wrong_key; // Wrong key
- tmp_value.length(length-1-tail);
- tmp_value.set_charset(&my_charset_bin);
- return &tmp_value;
+ str->length(length-1-tail);
+ str->set_charset(&my_charset_bin);
+ return str;
error:
push_warning_printf(current_thd,Sql_condition::WARN_LEVEL_WARN,
@@ -1136,25 +1142,26 @@ void Item_func_concat_ws::fix_length_and_dec()
String *Item_func_reverse::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res = args[0]->val_str(str);
- char *ptr, *end, *tmp;
+ String *res= args[0]->val_str(&tmp_value);
+ const char *ptr, *end;
+ char *tmp;
if ((null_value=args[0]->null_value))
return 0;
/* An empty string is a special case as the string pointer may be null */
if (!res->length())
return make_empty_result();
- if (tmp_value.alloced_length() < res->length() &&
- tmp_value.realloc(res->length()))
+ if (str->alloced_length() < res->length() &&
+ str->realloc(res->length()))
{
null_value= 1;
return 0;
}
- tmp_value.length(res->length());
- tmp_value.set_charset(res->charset());
- ptr= (char *) res->ptr();
- end= ptr + res->length();
- tmp= (char *) tmp_value.ptr() + tmp_value.length();
+ str->length(res->length());
+ str->set_charset(res->charset());
+ ptr= res->ptr();
+ end= res->end();
+ tmp= (char *) str->end();
#ifdef USE_MB
if (use_mb(res->charset()))
{
@@ -1164,7 +1171,7 @@ String *Item_func_reverse::val_str(String *str)
if ((l= my_ismbchar(res->charset(),ptr,end)))
{
tmp-= l;
- DBUG_ASSERT(tmp >= tmp_value.ptr());
+ DBUG_ASSERT(tmp >= str->ptr());
memcpy(tmp,ptr,l);
ptr+= l;
}
@@ -1178,7 +1185,7 @@ String *Item_func_reverse::val_str(String *str)
while (ptr < end)
*--tmp= *ptr++;
}
- return &tmp_value;
+ return str;
}
@@ -1336,6 +1343,13 @@ void Item_func_replace::fix_length_and_dec()
/*********************************************************************/
+bool Item_func_regexp_replace::fix_fields(THD *thd, Item **ref)
+{
+ re.set_recursion_limit(thd);
+ return Item_str_func::fix_fields(thd, ref);
+}
+
+
void Item_func_regexp_replace::fix_length_and_dec()
{
if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 3))
@@ -1471,6 +1485,13 @@ err:
}
+bool Item_func_regexp_substr::fix_fields(THD *thd, Item **ref)
+{
+ re.set_recursion_limit(thd);
+ return Item_str_func::fix_fields(thd, ref);
+}
+
+
void Item_func_regexp_substr::fix_length_and_dec()
{
if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 2))
@@ -2344,6 +2365,7 @@ String *Item_func_database::val_str(String *str)
}
else
str->copy(thd->db, thd->db_length, system_charset_info);
+ null_value= 0;
return str;
}
@@ -2378,6 +2400,28 @@ bool Item_func_user::init(const char *user, const char *host)
}
+Item *Item_func_sysconst::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ /*
+ During view or prepared statement creation, the item should not
+ make use of const_charset_converter as it would imply substitution
+ with constant items which is not correct. Functions can have different
+ values during view creation and view execution based on context.
+
+ Return the identical item during view creation and prepare.
+ */
+ if (!Item_func_sysconst::const_item())
+ return this;
+ return const_charset_converter(tocs, true, fully_qualified_func_name());
+}
+
+bool Item_func_sysconst::const_item() const
+{
+ if (current_thd->lex->is_ps_or_view_context_analysis())
+ return false;
+ return true;
+}
+
bool Item_func_user::fix_fields(THD *thd, Item **ref)
{
return (Item_func_sysconst::fix_fields(thd, ref) ||
@@ -2403,21 +2447,19 @@ bool Item_func_current_role::fix_fields(THD *thd, Item **ref)
Security_context *ctx= context->security_ctx
? context->security_ctx : thd->security_ctx;
-
if (ctx->priv_role[0])
{
if (str_value.copy(ctx->priv_role, strlen(ctx->priv_role),
system_charset_info))
return 1;
-
str_value.mark_as_const();
+ null_value= maybe_null= 0;
return 0;
}
null_value= maybe_null= 1;
return 0;
}
-
void Item_func_soundex::fix_length_and_dec()
{
uint32 char_length= args[0]->max_char_length();
@@ -2425,7 +2467,6 @@ void Item_func_soundex::fix_length_and_dec()
DBUG_ASSERT(collation.collation != NULL);
set_if_bigger(char_length, 4);
fix_char_length(char_length);
- tmp_value.set_charset(collation.collation);
}
@@ -2470,7 +2511,7 @@ static bool my_uni_isalpha(int wc)
String *Item_func_soundex::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res =args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
char last_ch,ch;
CHARSET_INFO *cs= collation.collation;
my_wc_t wc;
@@ -2480,10 +2521,11 @@ String *Item_func_soundex::val_str(String *str)
if ((null_value= args[0]->null_value))
return 0; /* purecov: inspected */
- if (tmp_value.alloc(MY_MAX(res->length(), 4 * cs->mbminlen)))
- return str; /* purecov: inspected */
- char *to= (char *) tmp_value.ptr();
- char *to_end= to + tmp_value.alloced_length();
+ if (str->alloc(MY_MAX(res->length(), 4 * cs->mbminlen)))
+ return &tmp_value; /* purecov: inspected */
+ str->set_charset(collation.collation);
+ char *to= (char *) str->ptr();
+ char *to_end= to + str->alloced_length();
char *from= (char *) res->ptr(), *end= from + res->length();
for ( ; ; ) /* Skip pre-space */
@@ -2568,8 +2610,8 @@ String *Item_func_soundex::val_str(String *str)
to+= nbytes;
}
- tmp_value.length((uint) (to-tmp_value.ptr()));
- return &tmp_value;
+ str->length((uint) (to - str->ptr()));
+ return str;
}
@@ -3378,16 +3420,16 @@ String *Item_func_conv_charset::val_str(String *str)
DBUG_ASSERT(fixed == 1);
if (use_cached_value)
return null_value ? 0 : &str_value;
- String *arg= args[0]->val_str(str);
+ String *arg= args[0]->val_str(&tmp_value);
uint dummy_errors;
if (args[0]->null_value)
{
null_value=1;
return 0;
}
- null_value= tmp_value.copy(arg->ptr(), arg->length(), arg->charset(),
- conv_charset, &dummy_errors);
- return null_value ? 0 : check_well_formed_result(&tmp_value);
+ null_value= str->copy(arg->ptr(), arg->length(), arg->charset(),
+ conv_charset, &dummy_errors);
+ return null_value ? 0 : check_well_formed_result(str);
}
void Item_func_conv_charset::fix_length_and_dec()
@@ -3530,7 +3572,7 @@ String *Item_func_weight_string::val_str(String *str)
DBUG_ASSERT(fixed == 1);
if (args[0]->result_type() != STRING_RESULT ||
- !(res= args[0]->val_str(str)))
+ !(res= args[0]->val_str(&tmp_value)))
goto nl;
/*
@@ -3577,19 +3619,19 @@ String *Item_func_weight_string::val_str(String *str)
goto nl;
}
- if (tmp_value.alloc(tmp_length))
+ if (str->alloc(tmp_length))
goto nl;
frm_length= cs->coll->strnxfrm(cs,
- (uchar *) tmp_value.ptr(), tmp_length,
+ (uchar *) str->ptr(), tmp_length,
nweights ? nweights : tmp_length,
(const uchar *) res->ptr(), res->length(),
flags);
DBUG_ASSERT(frm_length <= tmp_length);
- tmp_value.length(frm_length);
+ str->length(frm_length);
null_value= 0;
- return &tmp_value;
+ return str;
nl:
null_value= 1;
@@ -3630,18 +3672,18 @@ String *Item_func_hex::val_str_ascii(String *str)
}
/* Convert given string to a hex string, character by character */
- res= args[0]->val_str(str);
- if (!res || tmp_value.alloc(res->length()*2+1))
+ res= args[0]->val_str(&tmp_value);
+ if (!res || str->alloc(res->length()*2+1))
{
null_value=1;
return 0;
}
null_value=0;
- tmp_value.length(res->length()*2);
- tmp_value.set_charset(&my_charset_latin1);
+ str->length(res->length()*2);
+ str->set_charset(&my_charset_latin1);
- octet2hex((char*) tmp_value.ptr(), res->ptr(), res->length());
- return &tmp_value;
+ octet2hex((char*) str->ptr(), res->ptr(), res->length());
+ return str;
}
/** Convert given hex string to a binary string. */
@@ -3654,8 +3696,8 @@ String *Item_func_unhex::val_str(String *str)
uint length;
DBUG_ASSERT(fixed == 1);
- res= args[0]->val_str(str);
- if (!res || tmp_value.alloc(length= (1+res->length())/2))
+ res= args[0]->val_str(&tmp_value);
+ if (!res || str->alloc(length= (1+res->length())/2))
{
null_value=1;
return 0;
@@ -3663,8 +3705,8 @@ String *Item_func_unhex::val_str(String *str)
from= res->ptr();
null_value= 0;
- tmp_value.length(length);
- to= (char*) tmp_value.ptr();
+ str->length(length);
+ to= (char*) str->ptr();
if (res->length() % 2)
{
int hex_char;
@@ -3682,7 +3724,7 @@ String *Item_func_unhex::val_str(String *str)
if ((null_value= (hex_char == -1)))
return 0;
}
- return &tmp_value;
+ return str;
}
@@ -3928,7 +3970,7 @@ String *Item_func_quote::val_str(String *str)
ulong max_allowed_packet= current_thd->variables.max_allowed_packet;
char *from, *to, *end, *start;
- String *arg= args[0]->val_str(str);
+ String *arg= args[0]->val_str(&tmp_value);
uint arg_length, new_length;
if (!arg) // Null argument
{
@@ -3955,7 +3997,7 @@ String *Item_func_quote::val_str(String *str)
set_if_smaller(new_length, max_allowed_packet);
}
- if (tmp_value.alloc(new_length))
+ if (str->alloc(new_length))
goto null;
if (collation.collation->mbmaxlen > 1)
@@ -3963,7 +4005,7 @@ String *Item_func_quote::val_str(String *str)
CHARSET_INFO *cs= collation.collation;
int mblen;
uchar *to_end;
- to= (char*) tmp_value.ptr();
+ to= (char*) str->ptr();
to_end= (uchar*) to + new_length;
/* Put leading quote */
@@ -4000,14 +4042,14 @@ String *Item_func_quote::val_str(String *str)
if ((mblen= cs->cset->wc_mb(cs, '\'', (uchar *) to, to_end)) <= 0)
goto toolong;
to+= mblen;
- new_length= to - tmp_value.ptr();
+ new_length= to - str->ptr();
goto ret;
}
/*
We replace characters from the end to the beginning
*/
- to= (char*) tmp_value.ptr() + new_length - 1;
+ to= (char*) str->ptr() + new_length - 1;
*to--= '\'';
for (start= (char*) arg->ptr(),end= start + arg_length; end-- != start; to--)
{
@@ -4037,10 +4079,10 @@ String *Item_func_quote::val_str(String *str)
*to= '\'';
ret:
- tmp_value.length(new_length);
- tmp_value.set_charset(collation.collation);
+ str->length(new_length);
+ str->set_charset(collation.collation);
null_value= 0;
- return &tmp_value;
+ return str;
toolong:
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -4113,7 +4155,7 @@ String *Item_func_compress::val_str(String *str)
char *tmp, *last_char;
DBUG_ASSERT(fixed == 1);
- if (!(res= args[0]->val_str(str)))
+ if (!(res= args[0]->val_str(&tmp_value)))
{
null_value= 1;
return 0;
@@ -4134,13 +4176,13 @@ String *Item_func_compress::val_str(String *str)
// Check new_size overflow: new_size <= res->length()
if (((uint32) (new_size+5) <= res->length()) ||
- buffer.realloc((uint32) new_size + 4 + 1))
+ str->realloc((uint32) new_size + 4 + 1))
{
null_value= 1;
return 0;
}
- body= ((Byte*)buffer.ptr()) + 4;
+ body= ((Byte*)str->ptr()) + 4;
// As far as we have checked res->is_empty() we can use ptr()
if ((err= my_compress_buffer(body, &new_size, (const uchar *)res->ptr(),
@@ -4152,7 +4194,7 @@ String *Item_func_compress::val_str(String *str)
return 0;
}
- tmp= (char*)buffer.ptr(); // int4store is a macro; avoid side effects
+ tmp= (char*) str->ptr(); // int4store is a macro; avoid side effects
int4store(tmp, res->length() & 0x3FFFFFFF);
/* This is to ensure that things works for CHAR fields, which trim ' ': */
@@ -4163,15 +4205,15 @@ String *Item_func_compress::val_str(String *str)
new_size++;
}
- buffer.length((uint32)new_size + 4);
- return &buffer;
+ str->length((uint32)new_size + 4);
+ return str;
}
String *Item_func_uncompress::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
ulong new_size;
int err;
uint code;
@@ -4202,14 +4244,14 @@ String *Item_func_uncompress::val_str(String *str)
max_allowed_packet));
goto err;
}
- if (buffer.realloc((uint32)new_size))
+ if (str->realloc((uint32)new_size))
goto err;
- if ((err= uncompress((Byte*)buffer.ptr(), &new_size,
+ if ((err= uncompress((Byte*)str->ptr(), &new_size,
((const Bytef*)res->ptr())+4,res->length()-4)) == Z_OK)
{
- buffer.length((uint32) new_size);
- return &buffer;
+ str->length((uint32) new_size);
+ return str;
}
code= ((err == Z_BUF_ERROR) ? ER_ZLIB_Z_BUF_ERROR :
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 2886cb68f9b..1b133d1d885 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -87,7 +87,6 @@ public:
class Item_func_md5 :public Item_str_ascii_func
{
- String tmp_value;
public:
Item_func_md5(Item *a) :Item_str_ascii_func(a) {}
String *val_str_ascii(String *);
@@ -167,7 +166,6 @@ public:
class Item_func_decode_histogram :public Item_str_func
{
- String tmp_value;
public:
Item_func_decode_histogram(Item *a, Item *b)
:Item_str_func(a, b) {}
@@ -233,6 +231,7 @@ public:
DBUG_VOID_RETURN;
}
String *val_str(String *str);
+ bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
const char *func_name() const { return "regexp_replace"; }
};
@@ -253,6 +252,7 @@ public:
DBUG_VOID_RETURN;
}
String *val_str(String *str);
+ bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
const char *func_name() const { return "regexp_substr"; }
};
@@ -542,10 +542,7 @@ class Item_func_sysconst :public Item_str_func
public:
Item_func_sysconst()
{ collation.set(system_charset_info,DERIVATION_SYSCONST); }
- Item *safe_charset_converter(CHARSET_INFO *tocs)
- {
- return const_charset_converter(tocs, true, fully_qualified_func_name());
- }
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
/*
Used to create correct Item name in new converted item in
safe_charset_converter, return string representation of this function
@@ -557,6 +554,7 @@ public:
return trace_unsupported_by_check_vcol_func_processor(
fully_qualified_func_name());
}
+ bool const_item() const;
};
@@ -635,7 +633,7 @@ public:
String *val_str(String *)
{
DBUG_ASSERT(fixed == 1);
- return (null_value ? 0 : &str_value);
+ return null_value ? NULL : &str_value;
}
};
@@ -677,7 +675,6 @@ public:
class Item_func_format :public Item_str_ascii_func
{
- String tmp_str;
MY_LOCALE *locale;
public:
Item_func_format(Item *org, Item *dec): Item_str_ascii_func(org, dec) {}
@@ -731,7 +728,6 @@ public:
class Item_func_binlog_gtid_pos :public Item_str_func
{
- String tmp_value;
public:
Item_func_binlog_gtid_pos(Item *arg1,Item *arg2) :Item_str_func(arg1,arg2) {}
String *val_str(String *);
@@ -1108,7 +1104,7 @@ public:
class Item_func_compress: public Item_str_func
{
- String buffer;
+ String tmp_value;
public:
Item_func_compress(Item *a):Item_str_func(a){}
void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;}
@@ -1118,7 +1114,7 @@ public:
class Item_func_uncompress: public Item_str_func
{
- String buffer;
+ String tmp_value;
public:
Item_func_uncompress(Item *a): Item_str_func(a){}
void fix_length_and_dec(){ maybe_null= 1; max_length= MAX_BLOB_WIDTH; }
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 70b730a5a33..198657636f6 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -329,7 +329,8 @@ bool Item_subselect::enumerate_field_refs_processor(uchar *arg)
while ((upper= it++))
{
- if (upper->item->walk(&Item::enumerate_field_refs_processor, FALSE, arg))
+ if (upper->item &&
+ upper->item->walk(&Item::enumerate_field_refs_processor, FALSE, arg))
return TRUE;
}
return FALSE;
@@ -3327,7 +3328,8 @@ bool Item_in_subselect::init_cond_guards()
{
DBUG_ASSERT(thd);
uint cols_num= left_expr->cols();
- if (!abort_on_null && left_expr->maybe_null && !pushed_cond_guards)
+ if (!abort_on_null && !pushed_cond_guards &&
+ (left_expr->maybe_null || cols_num > 1))
{
if (!(pushed_cond_guards= (bool*)thd->alloc(sizeof(bool) * cols_num)))
return TRUE;
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index fa1c3d0da90..d9bfeed418a 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -3105,7 +3105,7 @@ get_date_time_result_type(const char *format, uint length)
const char *val= format;
const char *end= format + length;
- for (; val != end && val != end; val++)
+ for (; val != end; val++)
{
if (*val == '%' && val+1 != end)
{
diff --git a/sql/lock.cc b/sql/lock.cc
index f7b9980ef05..965f7dcab99 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -96,7 +96,6 @@ extern HASH open_cache;
static int lock_external(THD *thd, TABLE **table,uint count);
static int unlock_external(THD *thd, TABLE **table,uint count);
-static void print_lock_error(int error, TABLE *);
/* Map the return value of thr_lock to an error from errmsg.txt */
static int thr_lock_errno_to_mysql[]=
@@ -374,7 +373,7 @@ static int lock_external(THD *thd, TABLE **tables, uint count)
if ((error=(*tables)->file->ha_external_lock(thd,lock_type)))
{
- print_lock_error(error, *tables);
+ (*tables)->file->print_error(error, MYF(0));
while (--i)
{
tables--;
@@ -691,8 +690,8 @@ static int unlock_external(THD *thd, TABLE **table,uint count)
(*table)->current_lock = F_UNLCK;
if ((error=(*table)->file->ha_external_lock(thd, F_UNLCK)))
{
- error_code=error;
- print_lock_error(error_code, *table);
+ error_code= error;
+ (*table)->file->print_error(error, MYF(0));
}
}
table++;
@@ -914,36 +913,6 @@ bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type,
}
-static void print_lock_error(int error, TABLE *table)
-{
- int textno;
- DBUG_ENTER("print_lock_error");
-
- switch (error) {
- case HA_ERR_LOCK_WAIT_TIMEOUT:
- textno=ER_LOCK_WAIT_TIMEOUT;
- break;
- case HA_ERR_READ_ONLY_TRANSACTION:
- textno=ER_READ_ONLY_TRANSACTION;
- break;
- case HA_ERR_LOCK_DEADLOCK:
- textno=ER_LOCK_DEADLOCK;
- break;
- case HA_ERR_WRONG_COMMAND:
- my_error(ER_ILLEGAL_HA, MYF(0), table->file->table_type(),
- table->s->db.str, table->s->table_name.str);
- DBUG_VOID_RETURN;
- default:
- textno=ER_CANT_LOCK;
- break;
- }
-
- my_error(textno, MYF(0), error);
-
- DBUG_VOID_RETURN;
-}
-
-
/****************************************************************************
Handling of global read locks
diff --git a/sql/log.cc b/sql/log.cc
index 596a0a449d2..c1c6a4758d7 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -9612,8 +9612,8 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
sizeof(xev->xid));
if (!x || my_hash_insert(&xids, x))
goto err2;
- break;
}
+ break;
}
case BINLOG_CHECKPOINT_EVENT:
if (first_round && do_xa)
diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc
index e856400466d..1b79f815a0f 100644
--- a/sql/multi_range_read.cc
+++ b/sql/multi_range_read.cc
@@ -1231,28 +1231,18 @@ bool DsMrr_impl::setup_buffer_sharing(uint key_size_in_keybuf,
ptrdiff_t bytes_for_keys= (full_buf_end - full_buf) - bytes_for_rowids;
- if (bytes_for_keys < key_buff_elem_size + 1)
- {
- ptrdiff_t add= key_buff_elem_size + 1 - bytes_for_keys;
- bytes_for_keys= key_buff_elem_size + 1;
- bytes_for_rowids -= add;
- }
-
- if (bytes_for_rowids < (ptrdiff_t)rowid_buf_elem_size + 1)
- {
- ptrdiff_t add= (ptrdiff_t)(rowid_buf_elem_size + 1 - bytes_for_rowids);
- bytes_for_rowids= (ptrdiff_t)rowid_buf_elem_size + 1;
- bytes_for_keys -= add;
- }
+ if (bytes_for_keys < key_buff_elem_size + 1 ||
+ bytes_for_rowids < (ptrdiff_t)rowid_buf_elem_size + 1)
+ return TRUE; /* Failed to provide minimum space for one of the buffers */
rowid_buffer_end= full_buf + bytes_for_rowids;
rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end);
key_buffer= &backward_key_buf;
key_buffer->set_buffer_space(rowid_buffer_end, full_buf_end);
- if (!key_buffer->have_space_for(key_buff_elem_size) ||
- !rowid_buffer.have_space_for((size_t)rowid_buf_elem_size))
- return TRUE; /* Failed to provide minimum space for one of the buffers */
+ /* The above code guarantees that the buffers are big enough */
+ DBUG_ASSERT(key_buffer->have_space_for(key_buff_elem_size) &&
+ rowid_buffer.have_space_for((size_t)rowid_buf_elem_size));
return FALSE;
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index baf3d0f6758..45e6b3666bf 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3619,7 +3619,6 @@ sizeof(load_default_groups)/sizeof(load_default_groups[0]);
#endif
-#ifndef EMBEDDED_LIBRARY
/**
This function is used to check for stack overrun for pathological
cases of regular expressions and 'like' expressions.
@@ -3648,8 +3647,6 @@ check_enough_stack_size(int recurse_level)
return 0;
return check_enough_stack_size_slow();
}
-#endif
-
/*
@@ -3671,11 +3668,12 @@ static void init_pcre()
{
pcre_malloc= pcre_stack_malloc= my_str_malloc_mysqld;
pcre_free= pcre_stack_free= my_str_free_mysqld;
-#ifndef EMBEDDED_LIBRARY
pcre_stack_guard= check_enough_stack_size_slow;
/* See http://pcre.org/original/doc/html/pcrestack.html */
- my_pcre_frame_size= -pcre_exec(NULL, NULL, NULL, -999, -999, 0, NULL, 0) + 16;
-#endif
+ my_pcre_frame_size= -pcre_exec(NULL, NULL, NULL, -999, -999, 0, NULL, 0);
+ // pcre can underestimate its stack usage. Use a safe value, as in the manual
+ set_if_bigger(my_pcre_frame_size, 500);
+ my_pcre_frame_size += 16; // Again, safety margin, see the manual
}
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index f52549bfd0b..90a5da6a927 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2012, 2016, MariaDB
+ Copyright (c) 2012, 2017, MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 481d8445fa8..3563058282b 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -7949,8 +7949,10 @@ static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param,
DBUG_ENTER("get_full_func_mm_tree");
#ifdef HAVE_SPATIAL
+ Field::geometry_type sav_geom_type;
if (field_item->field->type() == MYSQL_TYPE_GEOMETRY)
{
+ sav_geom_type= ((Field_geom*) field_item->field)->geom_type;
/* We have to be able to store all sorts of spatial features here */
((Field_geom*) field_item->field)->geom_type= Field::GEOM_GEOMETRY;
}
@@ -7982,6 +7984,13 @@ static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param,
}
}
}
+
+#ifdef HAVE_SPATIAL
+ if (field_item->field->type() == MYSQL_TYPE_GEOMETRY)
+ {
+ ((Field_geom*) field_item->field)->geom_type= sav_geom_type;
+ }
+#endif /*HAVE_SPATIAL*/
DBUG_RETURN(ftree);
}
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 03204a627ed..cc63efa7d8c 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -3433,6 +3433,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
table_map remaining_tables= 0;
table_map handled_tabs= 0;
join->sjm_lookup_tables= 0;
+ join->sjm_scan_tables= 0;
for (tablenr= table_count - 1 ; tablenr != join->const_tables - 1; tablenr--)
{
POSITION *pos= join->best_positions + tablenr;
@@ -3491,6 +3492,9 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
for (i= tablenr; i != (first + sjm->tables - 1); i--)
rem_tables |= join->best_positions[i].table->table->map;
+ for (i= first; i < first+ sjm->tables; i++)
+ join->sjm_scan_tables |= join->best_positions[i].table->table->map;
+
POSITION dummy;
join->cur_sj_inner_tables= 0;
for (i= first + sjm->tables; i <= tablenr; i++)
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 1eee5df2bc5..915477a45ed 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -892,6 +892,7 @@ char* partition_info::find_duplicate_field()
*/
partition_element *partition_info::get_part_elem(const char *partition_name,
char *file_name,
+ size_t file_name_size,
uint32 *part_id)
{
List_iterator<partition_element> part_it(partitions);
@@ -913,10 +914,10 @@ partition_element *partition_info::get_part_elem(const char *partition_name,
sub_part_elem->partition_name, partition_name))
{
if (file_name)
- create_subpartition_name(file_name, "",
- part_elem->partition_name,
- partition_name,
- NORMAL_PART_NAME);
+ if (create_subpartition_name(file_name, file_name_size, "",
+ part_elem->partition_name,
+ partition_name, NORMAL_PART_NAME))
+ DBUG_RETURN(NULL);
*part_id= j + (i * num_subparts);
DBUG_RETURN(sub_part_elem);
}
@@ -931,8 +932,9 @@ partition_element *partition_info::get_part_elem(const char *partition_name,
part_elem->partition_name, partition_name))
{
if (file_name)
- create_partition_name(file_name, "", partition_name,
- NORMAL_PART_NAME, TRUE);
+ if (create_partition_name(file_name, file_name_size, "",
+ partition_name, NORMAL_PART_NAME, TRUE))
+ DBUG_RETURN(NULL);
*part_id= i;
DBUG_RETURN(part_elem);
}
diff --git a/sql/partition_info.h b/sql/partition_info.h
index 8ad7b1fd1fd..a80295edde0 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -340,9 +340,8 @@ public:
bool init_column_part();
bool add_column_list_value(THD *thd, Item *item);
void set_show_version_string(String *packet);
- partition_element *get_part_elem(const char *partition_name,
- char *file_name,
- uint32 *part_id);
+ partition_element *get_part_elem(const char *partition_name, char *file_name,
+ size_t file_name_size, uint32 *part_id);
void report_part_expr_error(bool use_subpart_expr);
bool set_used_partition(List<Item> &fields,
List<Item> &values,
diff --git a/sql/records.cc b/sql/records.cc
index 940fd97d123..f7d038f8650 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -1,5 +1,6 @@
/*
Copyright (c) 2000, 2010, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2017, MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/rpl_handler.cc b/sql/rpl_handler.cc
index 917a9d11b5a..d97e0e07f52 100644
--- a/sql/rpl_handler.cc
+++ b/sql/rpl_handler.cc
@@ -261,7 +261,7 @@ int Binlog_storage_delegate::after_flush(THD *thd,
thd->semisync_info= log_info;
}
- strcpy(log_info->log_file, log_file+dirname_length(log_file));
+ strmake_buf(log_info->log_file, log_file+dirname_length(log_file));
log_info->log_pos = log_pos;
FOREACH_OBSERVER(ret, after_flush, false,
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index d63bf8fc29c..c23190cda2b 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2006, 2012, Oracle and/or its affiliates.
- Copyright (c) 2010, 2011, Monty Program Ab
+/* Copyright (c) 2006, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2017, MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -715,7 +715,6 @@ void end_master_info(Master_info* mi)
if (!mi->inited)
DBUG_VOID_RETURN;
- end_relay_log_info(&mi->rli);
if (mi->fd >= 0)
{
end_io_cache(&mi->file);
@@ -754,6 +753,7 @@ void free_key_master_info(Master_info *mi)
/* We use 2 here instead of 1 just to make it easier when debugging */
mi->killed= 2;
end_master_info(mi);
+ end_relay_log_info(&mi->rli);
mi->unlock_slave_threads();
delete mi;
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 928fbd3d7c1..eac4149cb06 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2006, 2013, Oracle and/or its affiliates.
- Copyright (c) 2010, 2013, Monty Program Ab
+/* Copyright (c) 2006, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2017, MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -54,8 +54,8 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery)
sync_counter(0), is_relay_log_recovery(is_slave_recovery),
save_temporary_tables(0), mi(0),
inuse_relaylog_list(0), last_inuse_relaylog(0),
- cur_log_old_open_count(0), group_relay_log_pos(0),
- event_relay_log_pos(0),
+ cur_log_old_open_count(0), error_on_rli_init_info(false),
+ group_relay_log_pos(0), event_relay_log_pos(0),
#if HAVE_valgrind
is_fake(FALSE),
#endif
@@ -119,7 +119,7 @@ int init_relay_log_info(Relay_log_info* rli,
const char* info_fname)
{
char fname[FN_REFLEN+128];
- int info_fd;
+ int info_fd= -1;
const char* msg = 0;
int error = 0;
DBUG_ENTER("init_relay_log_info");
@@ -129,6 +129,8 @@ int init_relay_log_info(Relay_log_info* rli,
DBUG_RETURN(0);
fn_format(fname, info_fname, mysql_data_home, "", 4+32);
mysql_mutex_lock(&rli->data_lock);
+ if (rli->error_on_rli_init_info)
+ goto err;
info_fd = rli->info_fd;
rli->cur_log_fd = -1;
rli->slave_skip_counter=0;
@@ -254,8 +256,8 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
if ((info_fd= mysql_file_open(key_file_relay_log_info,
fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
{
- sql_print_error("Failed to create a new relay log info file (\
-file '%s', errno %d)", fname, my_errno);
+ sql_print_error("Failed to create a new relay log info file ("
+ "file '%s', errno %d)", fname, my_errno);
msg= current_thd->get_stmt_da()->message();
goto err;
}
@@ -436,16 +438,21 @@ Failed to open the existing relay log info file '%s' (errno %d)",
goto err;
}
rli->inited= 1;
+ rli->error_on_rli_init_info= false;
mysql_mutex_unlock(&rli->data_lock);
DBUG_RETURN(0);
err:
- sql_print_error("%s", msg);
+ rli->error_on_rli_init_info= true;
+ if (msg)
+ sql_print_error("%s", msg);
end_io_cache(&rli->info_file);
if (info_fd >= 0)
mysql_file_close(info_fd, MYF(0));
rli->info_fd= -1;
+ mysql_mutex_lock(rli->relay_log.get_log_lock());
rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
+ mysql_mutex_unlock(rli->relay_log.get_log_lock());
mysql_mutex_unlock(&rli->data_lock);
DBUG_RETURN(1);
}
@@ -1101,6 +1108,8 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
const char** errmsg)
{
int error=0;
+ const char *ln;
+ char name_buf[FN_REFLEN];
DBUG_ENTER("purge_relay_logs");
/*
@@ -1127,12 +1136,37 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
if (!rli->inited)
{
DBUG_PRINT("info", ("rli->inited == 0"));
- DBUG_RETURN(0);
- }
-
- DBUG_ASSERT(rli->slave_running == 0);
- DBUG_ASSERT(rli->mi->slave_running == 0);
+ if (rli->error_on_rli_init_info)
+ {
+ ln= rli->relay_log.generate_name(opt_relay_logname, "-relay-bin",
+ 1, name_buf);
+ if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln, TRUE))
+ {
+ sql_print_error("Unable to purge relay log files. Failed to open relay "
+ "log index file:%s.", rli->relay_log.get_index_fname());
+ DBUG_RETURN(1);
+ }
+ mysql_mutex_lock(rli->relay_log.get_log_lock());
+ if (rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND,
+ (rli->max_relay_log_size ? rli->max_relay_log_size :
+ max_binlog_size), 1, TRUE))
+ {
+ sql_print_error("Unable to purge relay log files. Failed to open relay "
+ "log file:%s.", rli->relay_log.get_log_fname());
+ mysql_mutex_unlock(rli->relay_log.get_log_lock());
+ DBUG_RETURN(1);
+ }
+ mysql_mutex_unlock(rli->relay_log.get_log_lock());
+ }
+ else
+ DBUG_RETURN(0);
+ }
+ else
+ {
+ DBUG_ASSERT(rli->slave_running == 0);
+ DBUG_ASSERT(rli->mi->slave_running == 0);
+ }
mysql_mutex_lock(&rli->data_lock);
/*
@@ -1179,6 +1213,12 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
rli->group_relay_log_name[0]= rli->event_relay_log_name[0]= 0;
}
+ if (!rli->inited && rli->error_on_rli_init_info)
+ {
+ mysql_mutex_lock(rli->relay_log.get_log_lock());
+ rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
+ mysql_mutex_unlock(rli->relay_log.get_log_lock());
+ }
err:
#ifndef DBUG_OFF
char buf[22];
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 7fc41786957..e3f8e10a705 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2005, 2012, Oracle and/or its affiliates.
+/* Copyright (c) 2005, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2017, MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -176,7 +177,14 @@ public:
a different log under our feet
*/
uint32 cur_log_old_open_count;
-
+
+ /*
+ If on init_info() call error_on_rli_init_info is true that means
+ that previous call to init_info() terminated with an error, RESET
+ SLAVE must be executed and the problem fixed manually.
+ */
+ bool error_on_rli_init_info;
+
/*
Let's call a group (of events) :
- a transaction
diff --git a/sql/slave.cc b/sql/slave.cc
index b1cda1129bd..f785e4f345c 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2009, 2017, MariaDB
+/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2017, MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -388,6 +388,7 @@ int init_slave()
{
delete active_mi;
active_mi= 0;
+ sql_print_error("Failed to allocate memory for the Master Info structure");
goto err;
}
@@ -449,7 +450,6 @@ end:
DBUG_RETURN(error);
err:
- sql_print_error("Failed to allocate memory for the Master Info structure");
error= 1;
goto end;
}
@@ -2369,6 +2369,7 @@ static void write_ignored_events_info_to_relay_log(THD *thd, Master_info *mi)
}
if (rli->ign_gtids.count())
{
+ DBUG_ASSERT(!rli->is_in_group()); // Ensure no active transaction
glev= new Gtid_list_log_event(&rli->ign_gtids,
Gtid_list_log_event::FLAG_IGN_GTIDS);
rli->ign_gtids.reset();
@@ -5405,7 +5406,9 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
bool gtid_skip_enqueue= false;
bool got_gtid_event= false;
rpl_gtid event_gtid;
-
+#ifndef DBUG_OFF
+ static uint dbug_rows_event_count= 0;
+#endif
/*
FD_q must have been prepared for the first R_a event
inside get_master_version_and_clock()
@@ -5472,6 +5475,26 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
(uchar)buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT /* a way to escape */)
DBUG_RETURN(queue_old_event(mi,buf,event_len));
+#ifdef ENABLED_DEBUG_SYNC
+ /*
+ A (+d,dbug.rows_events_to_delay_relay_logging)-test is supposed to
+ create a few Write_log_events and after receiving the 1st of them
+ the IO thread signals to launch the SQL thread, and sets itself to
+ wait for a release signal.
+ */
+ DBUG_EXECUTE_IF("dbug.rows_events_to_delay_relay_logging",
+ if ((buf[EVENT_TYPE_OFFSET] == WRITE_ROWS_EVENT_V1 ||
+ buf[EVENT_TYPE_OFFSET] == WRITE_ROWS_EVENT) &&
+ ++dbug_rows_event_count == 2)
+ {
+ const char act[]=
+ "now SIGNAL start_sql_thread "
+ "WAIT_FOR go_on_relay_logging";
+ DBUG_ASSERT(debug_sync_service);
+ DBUG_ASSERT(!debug_sync_set_action(current_thd,
+ STRING_WITH_LEN(act)));
+ };);
+#endif
mysql_mutex_lock(&mi->data_lock);
switch ((uchar)buf[EVENT_TYPE_OFFSET]) {
@@ -6089,6 +6112,7 @@ void end_relay_log_info(Relay_log_info* rli)
mysql_mutex_t *log_lock;
DBUG_ENTER("end_relay_log_info");
+ rli->error_on_rli_init_info= false;
if (!rli->inited)
DBUG_VOID_RETURN;
if (rli->info_fd >= 0)
@@ -6676,9 +6700,12 @@ static Log_event* next_event(rpl_group_info *rgi, ulonglong *event_size)
DBUG_RETURN(ev);
}
- if (rli->ign_gtids.count())
+ if (rli->ign_gtids.count() && !rli->is_in_group())
{
- /* We generate and return a Gtid_list, to update gtid_slave_pos. */
+ /*
+ We generate and return a Gtid_list, to update gtid_slave_pos,
+ unless being in the middle of a group.
+ */
DBUG_PRINT("info",("seeing ignored end gtids"));
ev= new Gtid_list_log_event(&rli->ign_gtids,
Gtid_list_log_event::FLAG_IGN_GTIDS);
diff --git a/sql/spatial.cc b/sql/spatial.cc
index bfe302f332e..b03a8b6da07 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -1150,8 +1150,8 @@ int Gis_polygon::centroid_xy(double *x, double *y) const
uint32 n_points, org_n_points;
double prev_x, prev_y;
double cur_area= 0;
- double cur_cx= 0;
- double cur_cy= 0;
+ double cur_cx= 0, cur_cy= 0;
+ double sum_cx= 0, sum_cy= 0;
if (no_data(data, 4))
return 1;
@@ -1165,17 +1165,32 @@ int Gis_polygon::centroid_xy(double *x, double *y) const
while (--n_points) // One point is already read
{
double tmp_x, tmp_y;
+ double loc_area;
get_point(&tmp_x, &tmp_y, data);
data+= POINT_DATA_SIZE;
- cur_area+= (prev_x + tmp_x) * (prev_y - tmp_y);
+ loc_area= prev_x * tmp_y - tmp_x * prev_y;
+ cur_area+= loc_area;
cur_cx+= tmp_x;
cur_cy+= tmp_y;
+ sum_cx+= (prev_x + tmp_x) * loc_area;
+ sum_cy+= (prev_y + tmp_y) * loc_area;
+
prev_x= tmp_x;
prev_y= tmp_y;
}
- cur_area= fabs(cur_area) / 2;
- cur_cx= cur_cx / (org_n_points - 1);
- cur_cy= cur_cy / (org_n_points - 1);
+
+ if (fabs(cur_area) > 1e-10)
+ {
+ cur_cx= sum_cx / cur_area / 3.0;
+ cur_cy= sum_cy / cur_area / 3.0;
+ }
+ else
+ {
+ cur_cx= cur_cx / (org_n_points - 1);
+ cur_cy= cur_cy / (org_n_points - 1);
+ }
+
+ cur_area= fabs(cur_area);
if (!first_loop)
{
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 7a87ec3bd87..f0543becc0c 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -729,12 +729,6 @@ extern "C"
@param buffer pointer to preferred result buffer
@param length length of buffer
@param max_query_len how many chars of query to copy (0 for all)
-
- @req LOCK_thread_count
-
- @note LOCK_thread_count mutex is not necessary when the function is invoked on
- the currently running thread (current_thd) or if the caller in some other
- way guarantees that access to thd->query is serialized.
@return Pointer to string
*/
@@ -748,6 +742,9 @@ char *thd_get_error_context_description(THD *thd, char *buffer,
const Security_context *sctx= &thd->main_security_ctx;
char header[256];
int len;
+
+ mysql_mutex_lock(&LOCK_thread_count);
+
/*
The pointers thd->query and thd->proc_info might change since they are
being modified concurrently. This is acceptable for proc_info since its
@@ -803,6 +800,7 @@ char *thd_get_error_context_description(THD *thd, char *buffer,
}
mysql_mutex_unlock(&thd->LOCK_thd_data);
}
+ mysql_mutex_unlock(&LOCK_thread_count);
if (str.c_ptr_safe() == buffer)
return buffer;
@@ -1596,6 +1594,8 @@ void THD::init(void)
server_status= SERVER_STATUS_AUTOCOMMIT;
if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
+ if (variables.sql_mode & MODE_ANSI_QUOTES)
+ server_status|= SERVER_STATUS_ANSI_QUOTES;
transaction.all.modified_non_trans_table=
transaction.stmt.modified_non_trans_table= FALSE;
@@ -4158,7 +4158,7 @@ void Security_context::destroy()
if (external_user)
{
my_free(external_user);
- user= NULL;
+ external_user= NULL;
}
my_free(ip);
@@ -4368,6 +4368,10 @@ extern "C" enum thd_kill_levels thd_kill_level(const MYSQL_THD thd)
however not more often than global.progress_report_time.
If global.progress_report_time is 0, then don't send progress reports, but
check every second if the value has changed
+
+ We clear any errors that we get from sending the progress packet to
+ the client as we don't want to set an error without the caller knowing
+ about it.
*/
static void thd_send_progress(THD *thd)
@@ -4384,8 +4388,12 @@ static void thd_send_progress(THD *thd)
thd->progress.next_report_time= (report_time +
seconds_to_next * 1000000000ULL);
if (global_system_variables.progress_report_time &&
- thd->variables.progress_report_time)
+ thd->variables.progress_report_time && !thd->is_error())
+ {
net_send_progress_packet(thd);
+ if (thd->is_error())
+ thd->clear_error();
+ }
}
}
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index af5b016df9d..2ca97a32071 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -537,6 +537,8 @@ bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived)
DBUG_ASSERT(derived->table);
}
}
+ else
+ derived->table= derived->merge_underlying_list->table;
DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index c391cfba00c..fe72d40b802 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2010, 2016, MariaDB
+ Copyright (c) 2010, 2017, MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index f39566cec34..9f0b6e25a5c 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1168,20 +1168,16 @@ static my_bool deny_updates_if_read_only_option(THD *thd,
if (lex->sql_command == SQLCOM_UPDATE_MULTI)
DBUG_RETURN(FALSE);
- const my_bool create_temp_tables=
- (lex->sql_command == SQLCOM_CREATE_TABLE) &&
- lex->create_info.tmp_table();
-
- const my_bool drop_temp_tables=
- (lex->sql_command == SQLCOM_DROP_TABLE) &&
- lex->drop_temporary;
-
- const my_bool update_real_tables=
- some_non_temp_table_to_be_updated(thd, all_tables) &&
- !(create_temp_tables || drop_temp_tables);
-
+ /*
+ a table-to-be-created is not in the temp table list yet,
+ so CREATE TABLE needs a special treatment
+ */
+ const bool update_real_tables=
+ lex->sql_command == SQLCOM_CREATE_TABLE
+ ? !(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
+ : some_non_temp_table_to_be_updated(thd, all_tables);
- const my_bool create_or_drop_databases=
+ const bool create_or_drop_databases=
(lex->sql_command == SQLCOM_CREATE_DB) ||
(lex->sql_command == SQLCOM_DROP_DB);
@@ -1719,9 +1715,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
kill_zombie_dump_threads(slave_server_id);
thd->variables.server_id = slave_server_id;
- general_log_print(thd, command, "Log: '%s' Pos: %ld", packet+10,
- (long) pos);
- mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
+ const char *name= packet + 10;
+ size_t nlen= strlen(name);
+
+ general_log_print(thd, command, "Log: '%s' Pos: %lu", name, pos);
+ if (nlen < FN_REFLEN)
+ mysql_binlog_send(thd, thd->strmake(name, nlen), (my_off_t)pos, flags);
unregister_slave(thd,1,1);
/* fake COM_QUIT -- if we get here, the thread needs to terminate */
error = TRUE;
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index be7824aae9e..960b90a3cc7 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -1870,6 +1870,22 @@ static int add_subpartition_by(File fptr)
return err + add_partition_by(fptr);
}
+static int add_name_string(File fptr, const char *name)
+{
+ int err;
+ String name_string("", 0, system_charset_info);
+ THD *thd= current_thd;
+ ulonglong save_sql_mode= thd->variables.sql_mode;
+ thd->variables.sql_mode&= ~MODE_ANSI_QUOTES;
+ ulonglong save_options= thd->variables.option_bits;
+ thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE;
+ append_identifier(thd, &name_string, name, strlen(name));
+ thd->variables.sql_mode= save_sql_mode;
+ thd->variables.option_bits= save_options;
+ err= add_string_object(fptr, &name_string);
+ return err;
+}
+
static int add_part_field_list(File fptr, List<char> field_list)
{
uint i, num_fields;
@@ -1881,15 +1897,7 @@ static int add_part_field_list(File fptr, List<char> field_list)
err+= add_begin_parenthesis(fptr);
while (i < num_fields)
{
- const char *field_str= part_it++;
- String field_string("", 0, system_charset_info);
- THD *thd= current_thd;
- ulonglong save_options= thd->variables.option_bits;
- thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE;
- append_identifier(thd, &field_string, field_str,
- strlen(field_str));
- thd->variables.option_bits= save_options;
- err+= add_string_object(fptr, &field_string);
+ err+= add_name_string(fptr, part_it++);
if (i != (num_fields-1))
err+= add_comma(fptr);
i++;
@@ -1898,20 +1906,6 @@ static int add_part_field_list(File fptr, List<char> field_list)
return err;
}
-static int add_name_string(File fptr, const char *name)
-{
- int err;
- String name_string("", 0, system_charset_info);
- THD *thd= current_thd;
- ulonglong save_options= thd->variables.option_bits;
- thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE;
- append_identifier(thd, &name_string, name,
- strlen(name));
- thd->variables.option_bits= save_options;
- err= add_string_object(fptr, &name_string);
- return err;
-}
-
static int add_int(File fptr, longlong number)
{
char buff[32];
@@ -5994,8 +5988,8 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
DDL_LOG_ENTRY ddl_log_entry;
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
- char tmp_path[FN_REFLEN];
- char normal_path[FN_REFLEN];
+ char tmp_path[FN_REFLEN + 1];
+ char normal_path[FN_REFLEN + 1];
List_iterator<partition_element> part_it(part_info->partitions);
uint temp_partitions= part_info->temp_partitions.elements;
uint num_elements= part_info->partitions.elements;
@@ -6019,14 +6013,15 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
ddl_log_entry.next_entry= *next_entry;
ddl_log_entry.handler_name=
ha_resolve_storage_engine_name(sub_elem->engine_type);
- create_subpartition_name(tmp_path, path,
- part_elem->partition_name,
- sub_elem->partition_name,
- TEMP_PART_NAME);
- create_subpartition_name(normal_path, path,
- part_elem->partition_name,
- sub_elem->partition_name,
- NORMAL_PART_NAME);
+ if (create_subpartition_name(tmp_path, sizeof(tmp_path), path,
+ part_elem->partition_name,
+ sub_elem->partition_name,
+ TEMP_PART_NAME) ||
+ create_subpartition_name(normal_path, sizeof(normal_path), path,
+ part_elem->partition_name,
+ sub_elem->partition_name,
+ NORMAL_PART_NAME))
+ DBUG_RETURN(TRUE);
ddl_log_entry.name= normal_path;
ddl_log_entry.from_name= tmp_path;
if (part_elem->part_state == PART_IS_CHANGED)
@@ -6047,12 +6042,13 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
ddl_log_entry.next_entry= *next_entry;
ddl_log_entry.handler_name=
ha_resolve_storage_engine_name(part_elem->engine_type);
- create_partition_name(tmp_path, path,
- part_elem->partition_name,
- TEMP_PART_NAME, TRUE);
- create_partition_name(normal_path, path,
- part_elem->partition_name,
- NORMAL_PART_NAME, TRUE);
+ if (create_partition_name(tmp_path, sizeof(tmp_path), path,
+ part_elem->partition_name, TEMP_PART_NAME,
+ TRUE) ||
+ create_partition_name(normal_path, sizeof(normal_path), path,
+ part_elem->partition_name, NORMAL_PART_NAME,
+ TRUE))
+ DBUG_RETURN(TRUE);
ddl_log_entry.name= normal_path;
ddl_log_entry.from_name= tmp_path;
if (part_elem->part_state == PART_IS_CHANGED)
@@ -6091,7 +6087,7 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
DDL_LOG_ENTRY ddl_log_entry;
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
- char tmp_path[FN_LEN];
+ char tmp_path[FN_REFLEN + 1];
List_iterator<partition_element> part_it(part_info->partitions);
List_iterator<partition_element> temp_it(part_info->temp_partitions);
uint num_temp_partitions= part_info->temp_partitions.elements;
@@ -6130,10 +6126,10 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
ddl_log_entry.next_entry= *next_entry;
ddl_log_entry.handler_name=
ha_resolve_storage_engine_name(sub_elem->engine_type);
- create_subpartition_name(tmp_path, path,
- part_elem->partition_name,
- sub_elem->partition_name,
- name_variant);
+ if (create_subpartition_name(tmp_path, sizeof(tmp_path), path,
+ part_elem->partition_name,
+ sub_elem->partition_name, name_variant))
+ DBUG_RETURN(TRUE);
ddl_log_entry.name= tmp_path;
if (write_ddl_log_entry(&ddl_log_entry, &log_entry))
{
@@ -6149,9 +6145,10 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
ddl_log_entry.next_entry= *next_entry;
ddl_log_entry.handler_name=
ha_resolve_storage_engine_name(part_elem->engine_type);
- create_partition_name(tmp_path, path,
- part_elem->partition_name,
- name_variant, TRUE);
+ if (create_partition_name(tmp_path, sizeof(tmp_path), path,
+ part_elem->partition_name, name_variant,
+ TRUE))
+ DBUG_RETURN(TRUE);
ddl_log_entry.name= tmp_path;
if (write_ddl_log_entry(&ddl_log_entry, &log_entry))
{
@@ -8263,31 +8260,41 @@ static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter)
return res;
}
+/* used in error messages below */
+static const char *longest_str(const char *s1, const char *s2,
+ const char *s3=0)
+{
+ if (strlen(s2) > strlen(s1)) s1= s2;
+ if (s3 && strlen(s3) > strlen(s1)) s1= s3;
+ return s1;
+}
+
/*
Create partition names
SYNOPSIS
create_partition_name()
- out:out Created partition name string
+ out:out The buffer for the created partition name string
+ must be *at least* of FN_REFLEN+1 bytes
in1 First part
in2 Second part
name_variant Normal, temporary or renamed partition name
RETURN VALUE
- NONE
+ 0 if ok, error if name too long
DESCRIPTION
This method is used to calculate the partition name, service routine to
the del_ren_cre_table method.
*/
-void create_partition_name(char *out, const char *in1,
- const char *in2, uint name_variant,
- bool translate)
+int create_partition_name(char *out, size_t outlen, const char *in1,
+ const char *in2, uint name_variant, bool translate)
{
char transl_part_name[FN_REFLEN];
- const char *transl_part;
+ const char *transl_part, *end;
+ DBUG_ASSERT(outlen >= FN_REFLEN + 1); // consistency! same limit everywhere
if (translate)
{
@@ -8297,11 +8304,17 @@ void create_partition_name(char *out, const char *in1,
else
transl_part= in2;
if (name_variant == NORMAL_PART_NAME)
- strxmov(out, in1, "#P#", transl_part, NullS);
+ end= strxnmov(out, outlen-1, in1, "#P#", transl_part, NullS);
else if (name_variant == TEMP_PART_NAME)
- strxmov(out, in1, "#P#", transl_part, "#TMP#", NullS);
+ end= strxnmov(out, outlen-1, in1, "#P#", transl_part, "#TMP#", NullS);
else if (name_variant == RENAMED_PART_NAME)
- strxmov(out, in1, "#P#", transl_part, "#REN#", NullS);
+ end= strxnmov(out, outlen-1, in1, "#P#", transl_part, "#REN#", NullS);
+ if (end - out == static_cast<ptrdiff_t>(outlen-1))
+ {
+ my_error(ER_PATH_LENGTH, MYF(0), longest_str(in1, transl_part));
+ return HA_WRONG_CREATE_OPTION;
+ }
+ return 0;
}
@@ -8310,37 +8323,46 @@ void create_partition_name(char *out, const char *in1,
SYNOPSIS
create_subpartition_name()
- out:out Created partition name string
+ out:out The buffer for the created partition name string
+ must be *at least* of FN_REFLEN+1 bytes
in1 First part
in2 Second part
in3 Third part
name_variant Normal, temporary or renamed partition name
RETURN VALUE
- NONE
+ 0 if ok, error if name too long
DESCRIPTION
This method is used to calculate the subpartition name, service routine to
the del_ren_cre_table method.
*/
-void create_subpartition_name(char *out, const char *in1,
- const char *in2, const char *in3,
- uint name_variant)
+int create_subpartition_name(char *out, size_t outlen,
+ const char *in1, const char *in2,
+ const char *in3, uint name_variant)
{
- char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN];
+ char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN], *end;
+ DBUG_ASSERT(outlen >= FN_REFLEN + 1); // consistency! same limit everywhere
tablename_to_filename(in2, transl_part_name, FN_REFLEN);
tablename_to_filename(in3, transl_subpart_name, FN_REFLEN);
if (name_variant == NORMAL_PART_NAME)
- strxmov(out, in1, "#P#", transl_part_name,
- "#SP#", transl_subpart_name, NullS);
+ end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name,
+ "#SP#", transl_subpart_name, NullS);
else if (name_variant == TEMP_PART_NAME)
- strxmov(out, in1, "#P#", transl_part_name,
- "#SP#", transl_subpart_name, "#TMP#", NullS);
+ end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name,
+ "#SP#", transl_subpart_name, "#TMP#", NullS);
else if (name_variant == RENAMED_PART_NAME)
- strxmov(out, in1, "#P#", transl_part_name,
- "#SP#", transl_subpart_name, "#REN#", NullS);
+ end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name,
+ "#SP#", transl_subpart_name, "#REN#", NullS);
+ if (end - out == static_cast<ptrdiff_t>(outlen-1))
+ {
+ my_error(ER_PATH_LENGTH, MYF(0),
+ longest_str(in1, transl_part_name, transl_subpart_name));
+ return HA_WRONG_CREATE_OPTION;
+ }
+ return 0;
}
uint get_partition_field_store_length(Field *field)
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index 5da132661c9..1b7735b5e96 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -274,12 +274,12 @@ bool partition_key_modified(TABLE *table, const MY_BITMAP *fields);
#define partition_key_modified(X,Y) 0
#endif
-void create_partition_name(char *out, const char *in1,
- const char *in2, uint name_variant,
- bool translate);
-void create_subpartition_name(char *out, const char *in1,
- const char *in2, const char *in3,
- uint name_variant);
+int __attribute__((warn_unused_result))
+ create_partition_name(char *out, size_t outlen, const char *in1, const char
+ *in2, uint name_variant, bool translate);
+int __attribute__((warn_unused_result))
+ create_subpartition_name(char *out, size_t outlen, const char *in1, const
+ char *in2, const char *in3, uint name_variant);
void set_field_ptr(Field **ptr, const uchar *new_buf, const uchar *old_buf);
void set_key_field_ptr(KEY *key_info, const uchar *new_buf,
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index f520281135a..2a76c8d6671 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -491,7 +491,7 @@ bool Sql_cmd_alter_table_exchange_partition::
partition_element *part_elem;
char *partition_name;
char temp_name[FN_REFLEN+1];
- char part_file_name[FN_REFLEN+1];
+ char part_file_name[2*FN_REFLEN+1];
char swap_file_name[FN_REFLEN+1];
char temp_file_name[FN_REFLEN+1];
uint swap_part_id;
@@ -586,9 +586,9 @@ bool Sql_cmd_alter_table_exchange_partition::
temp_name, "", FN_IS_TMP);
if (!(part_elem= part_table->part_info->get_part_elem(partition_name,
- part_file_name +
- part_file_name_len,
- &swap_part_id)))
+ part_file_name + part_file_name_len,
+ sizeof(part_file_name) - part_file_name_len,
+ &swap_part_id)))
{
// my_error(ER_UNKNOWN_PARTITION, MYF(0), partition_name,
// part_table->alias);
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index eb8e0004380..df24f398e97 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -306,6 +306,12 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin);
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
static void reap_plugins(void);
+bool plugin_is_forced(struct st_plugin_int *p)
+{
+ return p->load_option == PLUGIN_FORCE ||
+ p->load_option == PLUGIN_FORCE_PLUS_PERMANENT;
+}
+
static void report_error(int where_to, uint error, ...)
{
va_list args;
@@ -1360,7 +1366,7 @@ static int plugin_initialize(MEM_ROOT *tmp_root, struct st_plugin_int *plugin,
if (options_only || state == PLUGIN_IS_DISABLED)
{
- ret= 0;
+ ret= !options_only && plugin_is_forced(plugin);
goto err;
}
@@ -1671,8 +1677,7 @@ int plugin_init(int *argc, char **argv, int flags)
while ((plugin_ptr= *(--reap)))
{
mysql_mutex_unlock(&LOCK_plugin);
- if (plugin_ptr->load_option == PLUGIN_FORCE ||
- plugin_ptr->load_option == PLUGIN_FORCE_PLUS_PERMANENT)
+ if (plugin_is_forced(plugin_ptr))
reaped_mandatory_plugin= TRUE;
plugin_deinitialize(plugin_ptr, true);
mysql_mutex_lock(&LOCK_plugin);
@@ -3542,8 +3547,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
plugin_dash.length + 1);
strxmov(plugin_name_with_prefix_ptr, plugin_dash.str, plugin_name_ptr, NullS);
- if (tmp->load_option != PLUGIN_FORCE &&
- tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT)
+ if (!plugin_is_forced(tmp))
{
/* support --skip-plugin-foo syntax */
options[0].name= plugin_name_ptr;
@@ -3861,8 +3865,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
We adjust the default value to account for the hardcoded exceptions
we have set for the federated and ndbcluster storage engines.
*/
- if (tmp->load_option != PLUGIN_FORCE &&
- tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT)
+ if (!plugin_is_forced(tmp))
opts[0].def_value= opts[1].def_value= plugin_load_option;
error= handle_options(argc, &argv, opts, NULL);
@@ -3878,8 +3881,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
Set plugin loading policy from option value. First element in the option
list is always the <plugin name> option value.
*/
- if (tmp->load_option != PLUGIN_FORCE &&
- tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT)
+ if (!plugin_is_forced(tmp))
plugin_load_option= (enum_plugin_load_option) *(ulong*) opts[0].value;
}
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index 09a22ba0444..2c9a22d4bd9 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -121,7 +121,7 @@
#define OPTION_AUTOCOMMIT (1ULL << 8) // THD, user
#define OPTION_BIG_SELECTS (1ULL << 9) // THD, user
#define OPTION_LOG_OFF (1ULL << 10) // THD, user
-#define OPTION_QUOTE_SHOW_CREATE (1ULL << 11) // THD, user, unused
+#define OPTION_QUOTE_SHOW_CREATE (1ULL << 11) // THD, user
#define TMP_TABLE_ALL_COLUMNS (1ULL << 12) // SELECT, intern
#define OPTION_WARNINGS (1ULL << 13) // THD, user
#define OPTION_AUTO_IS_NULL (1ULL << 14) // THD, user, binlog
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index bd0d31213e6..f1bbe58a8b8 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2008, 2014, SkySQL Ab.
+/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2017, MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -2665,6 +2665,7 @@ impossible position";
loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK);
break;
}
+ /* fall through */
default:
errmsg = "could not find next log";
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
@@ -3150,6 +3151,7 @@ int reset_slave(THD *thd, Master_info* mi)
// close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0
end_master_info(mi);
+ end_relay_log_info(&mi->rli);
// and delete these two files
create_logfile_name_with_suffix(master_info_file_tmp,
sizeof(master_info_file_tmp),
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 6a281a4583e..7be9bfb7838 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1305,6 +1305,7 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S
DBUG_PRINT("info",("Select tables optimized away"));
zero_result_cause= "Select tables optimized away";
tables_list= 0; // All tables resolved
+ select_lex->min_max_opt_list.empty();
const_tables= top_join_tab_count= table_count;
/*
Extract all table-independent conditions and replace the WHERE
@@ -2942,8 +2943,11 @@ void JOIN::exec_inner()
if (sort_table_cond)
{
if (!curr_table->select)
+ {
if (!(curr_table->select= new SQL_SELECT))
DBUG_VOID_RETURN;
+ curr_table->select->head= curr_table->table;
+ }
if (!curr_table->select->cond)
curr_table->select->cond= sort_table_cond;
else
@@ -8076,6 +8080,63 @@ bool JOIN_TAB::hash_join_is_possible()
}
+/**
+ @brief
+ Check whether a KEYUSE can be really used for access this join table
+
+ @param join Join structure with the best join order
+ for which the check is performed
+ @param keyuse Evaluated KEYUSE structure
+
+ @details
+ This function is supposed to be used after the best execution plan have been
+ already chosen and the JOIN_TAB array for the best join order been already set.
+ For a given KEYUSE to access this JOIN_TAB in the best execution plan the
+ function checks whether it really can be used. The function first performs
+ the check with access_from_tables_is_allowed(). If it succeeds it checks
+ whether the keyuse->val does not use some fields of a materialized semijoin
+ nest that cannot be used to build keys to access outer tables.
+ Such KEYUSEs exists for the query like this:
+ select * from ot
+ where ot.c in (select it1.c from it1, it2 where it1.c=f(it2.c))
+ Here we have two KEYUSEs to access table ot: with val=it1.c and val=f(it2.c).
+ However if the subquery was materialized the second KEYUSE cannot be employed
+ to access ot.
+
+ @retval true the given keyuse can be used for ref access of this JOIN_TAB
+ @retval false otherwise
+*/
+
+bool JOIN_TAB::keyuse_is_valid_for_access_in_chosen_plan(JOIN *join,
+ KEYUSE *keyuse)
+{
+ if (!access_from_tables_is_allowed(keyuse->used_tables,
+ join->sjm_lookup_tables))
+ return false;
+ if (join->sjm_scan_tables & table->map)
+ return true;
+ table_map keyuse_sjm_scan_tables= keyuse->used_tables &
+ join->sjm_scan_tables;
+ if (!keyuse_sjm_scan_tables)
+ return true;
+ uint sjm_tab_nr= 0;
+ while (!(keyuse_sjm_scan_tables & table_map(1) << sjm_tab_nr))
+ sjm_tab_nr++;
+ JOIN_TAB *sjm_tab= join->map2table[sjm_tab_nr];
+ TABLE_LIST *emb_sj_nest= sjm_tab->emb_sj_nest;
+ if (!(emb_sj_nest->sj_mat_info && emb_sj_nest->sj_mat_info->is_used &&
+ emb_sj_nest->sj_mat_info->is_sj_scan))
+ return true;
+ st_select_lex *sjm_sel= emb_sj_nest->sj_subq_pred->unit->first_select();
+ for (uint i= 0; i < sjm_sel->item_list.elements; i++)
+ {
+ if (sjm_sel->ref_pointer_array[i] == keyuse->val)
+ return true;
+ }
+ return false;
+}
+
+
static uint
cache_record_length(JOIN *join,uint idx)
{
@@ -8623,6 +8684,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
do
{
if (!(~used_tables & keyuse->used_tables) &&
+ join_tab->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) &&
are_tables_local(join_tab, keyuse->used_tables))
{
if (first_keyuse)
@@ -8637,6 +8699,8 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
{
if (curr->keypart == keyuse->keypart &&
!(~used_tables & curr->used_tables) &&
+ join_tab->keyuse_is_valid_for_access_in_chosen_plan(join,
+ keyuse) &&
are_tables_local(join_tab, curr->used_tables))
break;
}
@@ -8671,6 +8735,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
do
{
if (!(~used_tables & keyuse->used_tables) &&
+ join_tab->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) &&
are_tables_local(join_tab, keyuse->used_tables))
{
bool add_key_part= TRUE;
@@ -8680,7 +8745,9 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
{
if (curr->keypart == keyuse->keypart &&
!(~used_tables & curr->used_tables) &&
- are_tables_local(join_tab, curr->used_tables))
+ join_tab->keyuse_is_valid_for_access_in_chosen_plan(join,
+ curr) &&
+ are_tables_local(join_tab, curr->used_tables))
{
keyuse->keypart= NO_KEYPART;
add_key_part= FALSE;
@@ -8782,8 +8849,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
do
{
if (!(~used_tables & keyuse->used_tables) &&
- j->access_from_tables_is_allowed(keyuse->used_tables,
- join->sjm_lookup_tables))
+ j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse))
{
if (are_tables_local(j, keyuse->val->used_tables()))
{
@@ -8853,8 +8919,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
for (i=0 ; i < keyparts ; keyuse++,i++)
{
while (((~used_tables) & keyuse->used_tables) ||
- !j->access_from_tables_is_allowed(keyuse->used_tables,
- join->sjm_lookup_tables) ||
+ !j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) ||
keyuse->keypart == NO_KEYPART ||
(keyuse->keypart !=
(is_hash_join_key_no(key) ?
diff --git a/sql/sql_select.h b/sql/sql_select.h
index d51bca785a5..4f1b7bd7e05 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -534,6 +534,8 @@ typedef struct st_join_table {
!(used_sjm_lookup_tables & ~emb_sj_nest->sj_inner_tables));
}
+ bool keyuse_is_valid_for_access_in_chosen_plan(JOIN *join, KEYUSE *keyuse);
+
void remove_redundant_bnl_scan_conds();
} JOIN_TAB;
@@ -1000,6 +1002,11 @@ public:
to materialize and access by lookups
*/
table_map sjm_lookup_tables;
+ /**
+ Bitmap of semijoin tables that the chosen plan decided
+ to materialize to scan the results of materialization
+ */
+ table_map sjm_scan_tables;
/*
Constant tables for which we have found a row (as opposed to those for
which we didn't).
@@ -1341,6 +1348,7 @@ public:
pre_sort_join_tab= NULL;
emb_sjm_nest= NULL;
sjm_lookup_tables= 0;
+ sjm_scan_tables= 0;
exec_saved_explain= false;
/*
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index ce9815216bb..1918cbab720 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1169,8 +1169,13 @@ bool mysqld_show_create_db(THD *thd, LEX_STRING *dbname,
if (test_all_bits(sctx->master_access, DB_ACLS))
db_access=DB_ACLS;
else
- db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname->str, 0) |
- sctx->master_access);
+ {
+ db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname->str, 0) |
+ sctx->master_access;
+ if (sctx->priv_role[0])
+ db_access|= acl_get("", "", sctx->priv_role, dbname->str, 0);
+ }
+
if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname->str))
{
status_var_increment(thd->status_var.access_denied_errors);
@@ -5170,8 +5175,10 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
- acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) ||
- !check_grant_db(thd, db_name->str))
+ acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, false) ||
+ (sctx->priv_role[0] ?
+ acl_get("", "", sctx->priv_role, db_name->str, false) : 0) ||
+ !check_grant_db(thd, db_name->str))
#endif
{
load_db_opt_by_name(thd, db_name->str, &create);
@@ -5359,7 +5366,10 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
HA_STATUS_TIME |
HA_STATUS_VARIABLE_EXTRA |
HA_STATUS_AUTO)) != 0)
+ {
+ file->print_error(info_error, MYF(0));
goto err;
+ }
enum row_type row_type = file->get_row_type();
switch (row_type) {
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index cfa907b9ddc..16de451211f 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2010, 2014, SkySQL Ab.
+/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2017, Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -360,6 +360,19 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
Item *item_tmp;
while ((item_tmp= it++))
{
+ /*
+ If the outer query has a GROUP BY clause, an outer reference to this
+ query block may have been wrapped in a Item_outer_ref, which has not
+ been fixed yet. An Item_type_holder must be created based on a fixed
+ Item, so use the inner Item instead.
+ */
+ DBUG_ASSERT(item_tmp->fixed ||
+ (item_tmp->type() == Item::REF_ITEM &&
+ ((Item_ref *)(item_tmp))->ref_type() ==
+ Item_ref::OUTER_REF));
+ if (!item_tmp->fixed)
+ item_tmp= item_tmp->real_item();
+
/* Error's in 'new' will be detected after loop */
types.push_back(new Item_type_holder(thd_arg, item_tmp));
}
@@ -1076,4 +1089,3 @@ void st_select_lex_unit::set_unique_exclude()
}
}
}
-
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 4ae5379289e..000a424faeb 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -2920,6 +2920,10 @@ static bool fix_sql_mode(sys_var *self, THD *thd, enum_var_type type)
thd->server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
else
thd->server_status&= ~SERVER_STATUS_NO_BACKSLASH_ESCAPES;
+ if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
+ thd->server_status|= SERVER_STATUS_ANSI_QUOTES;
+ else
+ thd->server_status&= ~SERVER_STATUS_ANSI_QUOTES;
}
return false;
}
diff --git a/sql/threadpool_unix.cc b/sql/threadpool_unix.cc
index 9e2ffc9aee0..7689816ca8b 100644
--- a/sql/threadpool_unix.cc
+++ b/sql/threadpool_unix.cc
@@ -982,24 +982,26 @@ static void thread_group_close(thread_group_t *thread_group)
if (pipe(thread_group->shutdown_pipe))
{
- DBUG_VOID_RETURN;
+ goto end;
}
/* Wake listener */
if (io_poll_associate_fd(thread_group->pollfd,
thread_group->shutdown_pipe[0], NULL))
{
- DBUG_VOID_RETURN;
+ goto end;
+ }
+ {
+ char c= 0;
+ if (write(thread_group->shutdown_pipe[1], &c, 1) < 0)
+ goto end;
}
- char c= 0;
- if (write(thread_group->shutdown_pipe[1], &c, 1) < 0)
- DBUG_VOID_RETURN;
-
/* Wake all workers. */
while(wake_thread(thread_group) == 0)
{
}
+end:
mysql_mutex_unlock(&thread_group->mutex);
DBUG_VOID_RETURN;
diff --git a/sql/uniques.cc b/sql/uniques.cc
index c755293035b..31c00667440 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -483,7 +483,7 @@ void put_counter_into_merged_element(void *ptr, uint ofs, element_count cnt)
<> 0 error
*/
-static bool merge_walk(uchar *merge_buffer, ulong merge_buffer_size,
+static bool merge_walk(uchar *merge_buffer, size_t merge_buffer_size,
uint key_length, BUFFPEK *begin, BUFFPEK *end,
tree_walk_action walk_action, void *walk_action_arg,
qsort_cmp2 compare, void *compare_arg,
@@ -492,7 +492,7 @@ static bool merge_walk(uchar *merge_buffer, ulong merge_buffer_size,
BUFFPEK_COMPARE_CONTEXT compare_context = { compare, compare_arg };
QUEUE queue;
if (end <= begin ||
- merge_buffer_size < (ulong) (key_length * (end - begin + 1)) ||
+ merge_buffer_size < (size_t) (key_length * (end - begin + 1)) ||
init_queue(&queue, (uint) (end - begin), offsetof(BUFFPEK, key), 0,
buffpek_compare, &compare_context, 0, 0))
return 1;
@@ -642,15 +642,19 @@ bool Unique::walk(TABLE *table, tree_walk_action action, void *walk_action_arg)
return 1;
if (flush_io_cache(&file) || reinit_io_cache(&file, READ_CACHE, 0L, 0, 0))
return 1;
- size_t buff_sz= (max_in_memory_size / full_size + 1) * full_size;
+ /*
+ merge_buffer must fit at least MERGEBUFF2 keys, because
+ merge_index() can merge that many BUFFPEKs at once.
+ */
+ size_t buff_sz= MY_MAX(MERGEBUFF2, max_in_memory_size/full_size+1) * full_size;
if (!(merge_buffer = (uchar *)my_malloc(buff_sz, MYF(MY_THREAD_SPECIFIC|MY_WME))))
return 1;
if (buff_sz < full_size * (file_ptrs.elements + 1UL))
res= merge(table, merge_buffer, buff_sz >= full_size * MERGEBUFF2) ;
-
+
if (!res)
- {
- res= merge_walk(merge_buffer, (ulong) max_in_memory_size, full_size,
+ {
+ res= merge_walk(merge_buffer, buff_sz, full_size,
(BUFFPEK *) file_ptrs.buffer,
(BUFFPEK *) file_ptrs.buffer + file_ptrs.elements,
action, walk_action_arg,