summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorKaren Langford <karen.langford@oracle.com>2011-07-06 00:56:51 +0200
committerKaren Langford <karen.langford@oracle.com>2011-07-06 00:56:51 +0200
commitf6398a86dde400bc97009350c61dd9a9d3c1d715 (patch)
treeeefc26771a8f290ae8b29e9d7ecb41b19010a909 /sql
parentc2e8aacb3f4fa952d4a9f6757dad1654ec70f49b (diff)
parentae46a66099cfe66e9423a2cc9ef0c5e2097ae73d (diff)
downloadmariadb-git-f6398a86dde400bc97009350c61dd9a9d3c1d715.tar.gz
Merge from mysql-5.1.58-release
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc4
-rw-r--r--sql/item_subselect.cc8
-rw-r--r--sql/item_sum.cc6
-rw-r--r--sql/mysql_priv.h7
-rw-r--r--sql/mysqld.cc20
-rw-r--r--sql/sp_head.cc3
-rw-r--r--sql/sql_connect.cc217
-rw-r--r--sql/sql_lex.cc5
-rw-r--r--sql/sql_lex.h28
-rw-r--r--sql/sql_load.cc18
-rw-r--r--sql/sql_partition.cc36
-rw-r--r--sql/sql_select.cc12
12 files changed, 225 insertions, 139 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 15fd5489d32..930c5d7426e 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -4466,14 +4466,14 @@ mark_non_agg_field:
SELECT_LEX *select_lex= cached_table ?
cached_table->select_lex : context->select_lex;
if (!thd->lex->in_sum_func)
- select_lex->full_group_by_flag|= NON_AGG_FIELD_USED;
+ select_lex->set_non_agg_field_used(true);
else
{
if (outer_fixed)
thd->lex->in_sum_func->outer_fields.push_back(this);
else if (thd->lex->in_sum_func->nest_level !=
thd->lex->current_select->nest_level)
- select_lex->full_group_by_flag|= NON_AGG_FIELD_USED;
+ select_lex->set_non_agg_field_used(true);
}
}
return FALSE;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 53d4ac2d0a8..10dd6c93717 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1016,6 +1016,14 @@ Item_in_subselect::single_value_transformer(JOIN *join,
it.replace(item);
}
+ DBUG_EXECUTE("where",
+ print_where(item, "rewrite with MIN/MAX", QT_ORDINARY););
+ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY)
+ {
+ DBUG_ASSERT(select_lex->non_agg_field_used());
+ select_lex->set_non_agg_field_used(false);
+ }
+
save_allow_sum_func= thd->lex->allow_sum_func;
thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
/*
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index d480fae8a4c..40ac31918be 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -247,10 +247,10 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
in_sum_func->outer_fields.push_back(field);
}
else
- sel->full_group_by_flag|= NON_AGG_FIELD_USED;
+ sel->set_non_agg_field_used(true);
}
if (sel->nest_level > aggr_level &&
- (sel->full_group_by_flag & SUM_FUNC_USED) &&
+ (sel->agg_func_used()) &&
!sel->group_list.elements)
{
my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS,
@@ -259,7 +259,7 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
}
}
}
- aggr_sel->full_group_by_flag|= SUM_FUNC_USED;
+ aggr_sel->set_agg_func_used(true);
update_used_tables();
thd->lex->in_sum_func= in_sum_func;
return FALSE;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 9d692ec5ba1..4b89a7a7961 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1476,13 +1476,6 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
extern Item **not_found_item;
/*
- A set of constants used for checking non aggregated fields and sum
- functions mixture in the ONLY_FULL_GROUP_BY_MODE.
-*/
-#define NON_AGG_FIELD_USED 1
-#define SUM_FUNC_USED 2
-
-/*
This enumeration type is used only by the function find_item_in_list
to return the info on how an item has been resolved against a list
of possibly aliased items.
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 4c573e1ded1..d205cbf6e9c 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -8973,12 +8973,15 @@ fn_format_relative_to_data_home(char * to, const char *name,
bool is_secure_file_path(char *path)
{
char buff1[FN_REFLEN], buff2[FN_REFLEN];
+ size_t opt_secure_file_priv_len;
/*
All paths are secure if opt_secure_file_path is 0
*/
if (!opt_secure_file_priv)
return TRUE;
+ opt_secure_file_priv_len= strlen(opt_secure_file_priv);
+
if (strlen(path) >= FN_REFLEN)
return FALSE;
@@ -8996,11 +8999,24 @@ bool is_secure_file_path(char *path)
return FALSE;
}
convert_dirname(buff2, buff1, NullS);
- if (strncmp(opt_secure_file_priv, buff2, strlen(opt_secure_file_priv)))
- return FALSE;
+ if (!lower_case_file_system)
+ {
+ if (strncmp(opt_secure_file_priv, buff2, opt_secure_file_priv_len))
+ return FALSE;
+ }
+ else
+ {
+ if (files_charset_info->coll->strnncoll(files_charset_info,
+ (uchar *) buff2, strlen(buff2),
+ (uchar *) opt_secure_file_priv,
+ opt_secure_file_priv_len,
+ TRUE))
+ return FALSE;
+ }
return TRUE;
}
+
static int fix_paths(void)
{
char buff[FN_REFLEN],*pos;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 0ec8ce11c65..95a7eda0540 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2403,7 +2403,8 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
bzero((char*) &tables,sizeof(tables));
tables.db= (char*) "mysql";
tables.table_name= tables.alias= (char*) "proc";
- *full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1, TRUE) ||
+ *full_access= ((!check_table_access(thd, SELECT_ACL, &tables, 1, TRUE) &&
+ (tables.grant.privilege & SELECT_ACL) != 0) ||
(!strcmp(sp->m_definer_user.str,
thd->security_ctx->priv_user) &&
!strcmp(sp->m_definer_host.str,
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 2a2f11e7f46..44b4af74ef1 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -21,23 +21,10 @@
#include "mysql_priv.h"
-#ifdef HAVE_OPENSSL
-/*
- Without SSL the handshake consists of one packet. This packet
- has both client capabilites and scrambled password.
- With SSL the handshake might consist of two packets. If the first
- packet (client capabilities) has CLIENT_SSL flag set, we have to
- switch to SSL and read the second packet. The scrambled password
- is in the second packet and client_capabilites field will be ignored.
- Maybe it is better to accept flags other than CLIENT_SSL from the
- second packet?
-*/
-#define SSL_HANDSHAKE_SIZE 2
-#define NORMAL_HANDSHAKE_SIZE 6
-#define MIN_HANDSHAKE_SIZE 2
-#else
-#define MIN_HANDSHAKE_SIZE 6
-#endif /* HAVE_OPENSSL */
+/** Size of the header fields of an authentication packet. */
+#define AUTH_PACKET_HEADER_SIZE_PROTO_41 32
+#define AUTH_PACKET_HEADER_SIZE_PROTO_40 5
+#define AUTH_PACKET_HEADER_SIZE_CONNJ_SSL 4
#ifdef __WIN__
extern void win_install_sigabrt_handler();
@@ -822,6 +809,14 @@ static int check_connection(THD *thd)
ulong pkt_len= 0;
char *end;
+ bool packet_has_required_size= false;
+ char *db;
+ size_t db_len;
+ char *passwd;
+ size_t passwd_len;
+ char *user;
+ size_t user_len;
+
DBUG_PRINT("info",
("New connection received on %s", vio_description(net->vio)));
#ifdef SIGNAL_WITH_VIO_CLOSE
@@ -930,8 +925,7 @@ static int check_connection(THD *thd)
/* At this point we write connection message and read reply */
if (net_write_command(net, (uchar) protocol_version, (uchar*) "", 0,
(uchar*) buff, (size_t) (end-buff)) ||
- (pkt_len= my_net_read(net)) == packet_error ||
- pkt_len < MIN_HANDSHAKE_SIZE)
+ (pkt_len= my_net_read(net)) == packet_error)
{
inc_host_errors(&thd->remote.sin_addr);
my_error(ER_HANDSHAKE_ERROR, MYF(0));
@@ -946,22 +940,82 @@ static int check_connection(THD *thd)
if (thd->packet.alloc(thd->variables.net_buffer_length))
return 1; /* The error is set by alloc(). */
- thd->client_capabilities= uint2korr(net->read_pos);
+ uint charset_code= 0;
+ end= (char *)net->read_pos;
+ /*
+ In order to safely scan a head for '\0' string terminators
+ we must keep track of how many bytes remain in the allocated
+ buffer or we might read past the end of the buffer.
+ */
+ size_t bytes_remaining_in_packet= pkt_len;
+
+ /*
+ Peek ahead on the client capability packet and determine which version of
+ the protocol should be used.
+ */
+ if (bytes_remaining_in_packet < 2)
+ goto error;
+
+ thd->client_capabilities= uint2korr(end);
+
+ /*
+ Connector/J only sends client capabilities (4 bytes) before starting SSL
+ negotiation so we don't have char_set and other information for client in
+ packet read. In that case, skip reading those information. The below code
+ is patch for this.
+ */
+ if(bytes_remaining_in_packet == AUTH_PACKET_HEADER_SIZE_CONNJ_SSL &&
+ (thd->client_capabilities & CLIENT_SSL))
+ {
+ thd->client_capabilities= uint4korr(end);
+ thd->max_client_packet_length= global_system_variables.max_allowed_packet;
+ charset_code= default_charset_info->number;
+ end+= AUTH_PACKET_HEADER_SIZE_CONNJ_SSL;
+ bytes_remaining_in_packet-= AUTH_PACKET_HEADER_SIZE_CONNJ_SSL;
+ goto skip_to_ssl;
+ }
+
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
+ packet_has_required_size= bytes_remaining_in_packet >=
+ AUTH_PACKET_HEADER_SIZE_PROTO_41;
+ else
+ packet_has_required_size= bytes_remaining_in_packet >=
+ AUTH_PACKET_HEADER_SIZE_PROTO_40;
+
+ if (!packet_has_required_size)
+ goto error;
+
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
- thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
- thd->max_client_packet_length= uint4korr(net->read_pos+4);
- DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
- if (thd_init_client_charset(thd, (uint) net->read_pos[8]))
- return 1;
- thd->update_charset();
- end= (char*) net->read_pos+32;
+ thd->client_capabilities= uint4korr(end);
+ thd->max_client_packet_length= uint4korr(end + 4);
+ charset_code= (uint)(uchar)*(end + 8);
+ /*
+ Skip 23 remaining filler bytes which have no particular meaning.
+ */
+ end+= AUTH_PACKET_HEADER_SIZE_PROTO_41;
+ bytes_remaining_in_packet-= AUTH_PACKET_HEADER_SIZE_PROTO_41;
}
else
{
- thd->max_client_packet_length= uint3korr(net->read_pos+2);
- end= (char*) net->read_pos+5;
+ thd->client_capabilities= uint2korr(end);
+ thd->max_client_packet_length= uint3korr(end + 2);
+ end+= AUTH_PACKET_HEADER_SIZE_PROTO_40;
+ bytes_remaining_in_packet-= AUTH_PACKET_HEADER_SIZE_PROTO_40;
+ /**
+ Old clients didn't have their own charset. Instead the assumption
+ was that they used what ever the server used.
+ */
+ charset_code= default_charset_info->number;
}
+
+skip_to_ssl:
+
+ DBUG_PRINT("info", ("client_character_set: %u", charset_code));
+ if (thd_init_client_charset(thd, charset_code))
+ goto error;
+ thd->update_charset();
+
/*
Disable those bits which are not supported by the server.
This is a precautionary measure, if the client lies. See Bug#27944.
@@ -972,42 +1026,63 @@ static int check_connection(THD *thd)
thd->variables.sql_mode|= MODE_IGNORE_SPACE;
#ifdef HAVE_OPENSSL
DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
+
+ /*
+ If client requested SSL then we must stop parsing, try to switch to SSL,
+ and wait for the client to send a new handshake packet.
+ The client isn't expected to send any more bytes until SSL is initialized.
+ */
if (thd->client_capabilities & CLIENT_SSL)
{
/* Do the SSL layering. */
if (!ssl_acceptor_fd)
- {
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0));
- return 1;
- }
+ goto error;
+
DBUG_PRINT("info", ("IO layer change in progress..."));
if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout))
{
DBUG_PRINT("error", ("Failed to accept new SSL connection"));
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0));
- return 1;
+ goto error;
}
+
DBUG_PRINT("info", ("Reading user information over SSL layer"));
- if ((pkt_len= my_net_read(net)) == packet_error ||
- pkt_len < NORMAL_HANDSHAKE_SIZE)
+ if ((pkt_len= my_net_read(net)) == packet_error)
{
DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
pkt_len));
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0));
- return 1;
+ goto error;
}
- }
-#endif /* HAVE_OPENSSL */
+ /*
+ A new packet was read and the statistics reflecting the remaining bytes
+ in the packet must be updated.
+ */
+ bytes_remaining_in_packet= pkt_len;
- if (end > (char *)net->read_pos + pkt_len)
- {
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0));
- return 1;
+ /*
+ After the SSL handshake is performed the client resends the handshake
+ packet but because of legacy reasons we chose not to parse the packet
+ fields a second time and instead only assert the length of the packet.
+ */
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
+ {
+
+ packet_has_required_size= bytes_remaining_in_packet >=
+ AUTH_PACKET_HEADER_SIZE_PROTO_41;
+ end= (char *)net->read_pos + AUTH_PACKET_HEADER_SIZE_PROTO_41;
+ bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_41;
+ }
+ else
+ {
+ packet_has_required_size= bytes_remaining_in_packet >=
+ AUTH_PACKET_HEADER_SIZE_PROTO_40;
+ end= (char *)net->read_pos + AUTH_PACKET_HEADER_SIZE_PROTO_40;
+ bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_40;
+ }
+
+ if (!packet_has_required_size)
+ goto error;
}
+#endif /* HAVE_OPENSSL */
if (thd->client_capabilities & CLIENT_INTERACTIVE)
thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
@@ -1028,29 +1103,17 @@ static int check_connection(THD *thd)
else
get_string= get_40_protocol_string;
- /*
- In order to safely scan a head for '\0' string terminators
- we must keep track of how many bytes remain in the allocated
- buffer or we might read past the end of the buffer.
- */
- size_t bytes_remaining_in_packet= pkt_len - (end - (char *)net->read_pos);
-
- size_t user_len;
- char *user= get_string(&end, &bytes_remaining_in_packet, &user_len);
+ user= get_string(&end, &bytes_remaining_in_packet, &user_len);
if (user == NULL)
- {
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0));
- return 1;
- }
+ goto error;
/*
Old clients send a null-terminated string as password; new clients send
the size (1 byte) + string (not null-terminated). Hence in case of empty
password both send '\0'.
*/
- size_t passwd_len= 0;
- char *passwd= NULL;
+ passwd_len= 0;
+ passwd= NULL;
if (thd->client_capabilities & CLIENT_SECURE_CONNECTION)
{
@@ -1069,24 +1132,16 @@ static int check_connection(THD *thd)
}
if (passwd == NULL)
- {
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0));
- return 1;
- }
+ goto error;
- size_t db_len= 0;
- char *db= NULL;
+ db_len= 0;
+ db= NULL;
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
{
db= get_string(&end, &bytes_remaining_in_packet, &db_len);
if (db == NULL)
- {
- inc_host_errors(&thd->remote.sin_addr);
- my_error(ER_HANDSHAKE_ERROR, MYF(0));
- return 1;
- }
+ goto error;
}
char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
@@ -1134,11 +1189,14 @@ static int check_connection(THD *thd)
user[user_len]= '\0';
}
- if (thd->main_security_ctx.user)
- x_free(thd->main_security_ctx.user);
if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME))))
return 1; /* The error is set by my_strdup(). */
return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
+
+error:
+ inc_host_errors(&thd->remote.sin_addr);
+ my_error(ER_HANDSHAKE_ERROR, MYF(0));
+ return 1;
}
@@ -1388,3 +1446,4 @@ end_thread:
}
}
#endif /* EMBEDDED_LIBRARY */
+
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index f5c41b30659..f0289ab86ce 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1623,6 +1623,8 @@ void st_select_lex::init_query()
nest_level= 0;
link_next= 0;
lock_option= TL_READ_DEFAULT;
+ m_non_agg_field_used= false;
+ m_agg_func_used= false;
}
void st_select_lex::init_select()
@@ -1653,7 +1655,8 @@ void st_select_lex::init_select()
non_agg_fields.empty();
cond_value= having_value= Item::COND_UNDEF;
inner_refs_list.empty();
- full_group_by_flag= 0;
+ m_non_agg_field_used= false;
+ m_agg_func_used= false;
}
/*
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 07551f51a8a..b4dbbc5162e 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -715,16 +715,7 @@ public:
joins on the right.
*/
List<String> *prev_join_using;
- /*
- Bitmap used in the ONLY_FULL_GROUP_BY_MODE to prevent mixture of aggregate
- functions and non aggregated fields when GROUP BY list is absent.
- Bits:
- 0 - non aggregated fields are used in this select,
- defined as NON_AGG_FIELD_USED.
- 1 - aggregate functions are used in this select,
- defined as SUM_FUNC_USED.
- */
- uint8 full_group_by_flag;
+
void init_query();
void init_select();
st_select_lex_unit* master_unit();
@@ -832,7 +823,22 @@ public:
void clear_index_hints(void) { index_hints= NULL; }
-private:
+ /*
+ For MODE_ONLY_FULL_GROUP_BY we need to maintain two flags:
+ - Non-aggregated fields are used in this select.
+ - Aggregate functions are used in this select.
+ In MODE_ONLY_FULL_GROUP_BY only one of these may be true.
+ */
+ bool non_agg_field_used() const { return m_non_agg_field_used; }
+ bool agg_func_used() const { return m_agg_func_used; }
+
+ void set_non_agg_field_used(bool val) { m_non_agg_field_used= val; }
+ void set_agg_func_used(bool val) { m_agg_func_used= val; }
+
+private:
+ bool m_non_agg_field_used;
+ bool m_agg_func_used;
+
/* current index hint kind. used in filling up index_hints */
enum index_hint_type current_index_hint_type;
index_clause_map current_index_hint_clause;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 84d355ba2b5..6a0e5fd9133 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -350,21 +350,21 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
#if !defined(__WIN__) && ! defined(__NETWARE__)
MY_STAT stat_info;
- if (!my_stat(name,&stat_info,MYF(MY_WME)))
- DBUG_RETURN(TRUE);
+ if (!my_stat(name, &stat_info, MYF(MY_WME)))
+ DBUG_RETURN(TRUE);
// if we are not in slave thread, the file must be:
if (!thd->slave_thread &&
- !((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others
- (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
- ((stat_info.st_mode & S_IFREG) == S_IFREG ||
- (stat_info.st_mode & S_IFIFO) == S_IFIFO)))
+ !((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others
+ (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink
+ ((stat_info.st_mode & S_IFREG) == S_IFREG || // and a regular file
+ (stat_info.st_mode & S_IFIFO) == S_IFIFO))) // or FIFO
{
- my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name);
- DBUG_RETURN(TRUE);
+ my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name);
+ DBUG_RETURN(TRUE);
}
if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
- is_fifo = 1;
+ is_fifo= 1;
#endif
if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index d743c5908ca..0b103dcbda9 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -930,9 +930,6 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
const char *save_where;
char* db_name;
char db_name_string[FN_REFLEN];
- bool save_use_only_table_context;
- uint8 saved_full_group_by_flag;
- nesting_map saved_allow_sum_func;
DBUG_ENTER("fix_fields_part_func");
if (part_info->fixed)
@@ -999,23 +996,26 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
of interesting side effects, both desirable and undesirable.
*/
- save_use_only_table_context= thd->lex->use_only_table_context;
- thd->lex->use_only_table_context= TRUE;
- thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
- saved_full_group_by_flag= thd->lex->current_select->full_group_by_flag;
- saved_allow_sum_func= thd->lex->allow_sum_func;
- thd->lex->allow_sum_func= 0;
+ {
+ const bool save_use_only_table_context= thd->lex->use_only_table_context;
+ thd->lex->use_only_table_context= TRUE;
+ thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
+ const bool save_agg_field= thd->lex->current_select->non_agg_field_used();
+ const bool save_agg_func= thd->lex->current_select->agg_func_used();
+ const nesting_map saved_allow_sum_func= thd->lex->allow_sum_func;
+ thd->lex->allow_sum_func= 0;
- error= func_expr->fix_fields(thd, (Item**)&func_expr);
-
- /*
- Restore full_group_by_flag and allow_sum_func,
- fix_fields should not affect mysql_select later, see Bug#46923.
- */
- thd->lex->current_select->full_group_by_flag= saved_full_group_by_flag;
- thd->lex->allow_sum_func= saved_allow_sum_func;
+ error= func_expr->fix_fields(thd, (Item**)&func_expr);
- thd->lex->use_only_table_context= save_use_only_table_context;
+ /*
+ Restore agg_field/agg_func and allow_sum_func,
+ fix_fields should not affect mysql_select later, see Bug#46923.
+ */
+ thd->lex->current_select->set_non_agg_field_used(save_agg_field);
+ thd->lex->current_select->set_agg_func_used(save_agg_func);
+ thd->lex->allow_sum_func= saved_allow_sum_func;
+ thd->lex->use_only_table_context= save_use_only_table_context;
+ }
context->table_list= save_table_list;
context->first_name_resolution_table= save_first_table;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 46e9ad242b3..2346f744b47 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -426,19 +426,18 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array,
int res;
nesting_map save_allow_sum_func=thd->lex->allow_sum_func ;
/*
- Need to save the value, so we can turn off only the new NON_AGG_FIELD
+ Need to save the value, so we can turn off only any new non_agg_field_used
additions coming from the WHERE
*/
- uint8 saved_flag= thd->lex->current_select->full_group_by_flag;
+ const bool saved_non_agg_field_used=
+ thd->lex->current_select->non_agg_field_used();
DBUG_ENTER("setup_without_group");
thd->lex->allow_sum_func&= ~(1 << thd->lex->current_select->nest_level);
res= setup_conds(thd, tables, leaves, conds);
/* it's not wrong to have non-aggregated columns in a WHERE */
- if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY)
- thd->lex->current_select->full_group_by_flag= saved_flag |
- (thd->lex->current_select->full_group_by_flag & ~NON_AGG_FIELD_USED);
+ thd->lex->current_select->set_non_agg_field_used(saved_non_agg_field_used);
thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields,
@@ -644,7 +643,8 @@ JOIN::prepare(Item ***rref_pointer_array,
aggregate functions with implicit grouping (there is no GROUP BY).
*/
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !group_list &&
- select_lex->full_group_by_flag == (NON_AGG_FIELD_USED | SUM_FUNC_USED))
+ select_lex->non_agg_field_used() &&
+ select_lex->agg_func_used())
{
my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS,
ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0));