summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc2117
1 files changed, 1469 insertions, 648 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index d7d7469ceed..890334e8c94 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -21,7 +21,6 @@
#include <m_ctype.h>
#include <myisam.h>
#include <my_dir.h>
-#include <assert.h>
#ifdef HAVE_INNOBASE_DB
#include "ha_innodb.h"
@@ -44,30 +43,24 @@
#else
#define MIN_HANDSHAKE_SIZE 6
#endif /* HAVE_OPENSSL */
-#define SCRAMBLE_LENGTH 8
-#define MEM_ROOT_BLOCK_SIZE 8192
-#define MEM_ROOT_PREALLOC 8192
-#define TRANS_MEM_ROOT_BLOCK_SIZE 4096
-#define TRANS_MEM_ROOT_PREALLOC 4096
-
-extern int yyparse(void);
+extern int yyparse(void *thd);
extern "C" pthread_mutex_t THR_LOCK_keycache;
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#endif
-static int check_for_max_user_connections(USER_CONN *uc);
+static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
static void decrease_user_connections(USER_CONN *uc);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
-static bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
-static void mysql_init_query(THD *thd);
static void remove_escape(char *name);
static void refresh_status(void);
static bool append_file_to_dir(THD *thd, char **filename_ptr,
char *table_name);
-static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result);
+
+static bool single_table_command_access(THD *thd, ulong privilege,
+ TABLE_LIST *tables, int *res);
const char *any_db="*any*"; // Special symbol for check_access
@@ -76,10 +69,11 @@ const char *command_name[]={
"Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
"Binlog Dump","Table Dump", "Connect Out", "Register Slave",
+ "Prepare", "Prepare Execute", "Long Data", "Close stmt",
"Error" // Last command number
};
-bool volatile abort_slave = 0;
+static char empty_c_string[1]= {0}; // Used for not defined 'db'
#ifdef __WIN__
static void test_signal(int sig_ptr)
@@ -130,7 +124,7 @@ extern pthread_mutex_t LOCK_user_conn;
static int get_or_create_user_conn(THD *thd, const char *user,
const char *host,
- USER_RESOURCES *mqh)
+ USER_RESOURCES *mqh)
{
int return_val=0;
uint temp_len, user_len, host_len;
@@ -152,7 +146,7 @@ static int get_or_create_user_conn(THD *thd, const char *user,
my_malloc(sizeof(struct user_conn) + temp_len+1,
MYF(MY_WME)))))
{
- send_error(&current_thd->net, 0, NullS); // Out of memory
+ send_error(thd, 0, NullS); // Out of memory
return_val=1;
goto end;
}
@@ -164,13 +158,13 @@ static int get_or_create_user_conn(THD *thd, const char *user,
uc->connections = 1;
uc->questions=uc->updates=uc->conn_per_hour=0;
uc->user_resources=*mqh;
- if (max_user_connections && mqh->connections > max_user_connections)
+ if (max_user_connections && mqh->connections > max_user_connections)
uc->user_resources.connections = max_user_connections;
uc->intime=thd->thr_create_time;
if (hash_insert(&hash_user_connections, (byte*) uc))
{
my_free((char*) uc,0);
- send_error(&current_thd->net, 0, NullS); // Out of memory
+ send_error(thd, 0, NullS); // Out of memory
return_val=1;
goto end;
}
@@ -179,63 +173,116 @@ static int get_or_create_user_conn(THD *thd, const char *user,
end:
(void) pthread_mutex_unlock(&LOCK_user_conn);
return return_val;
-
+
}
/*
Check if user is ok
- Updates:
- thd->{user,master_access,priv_user,priv_host,db,db_access}
+
+ SYNOPSIS
+ check_user()
+ thd Thread handle
+ command Command for connection (for log)
+ user Name of user trying to connect
+ passwd Scrambled password sent from client
+ db Database to connect to
+ check_count If set to 1, don't allow too many connection
+ simple_connect If 1 then client is of old type and we should connect
+ using the old method (no challange)
+ do_send_error Set to 1 if we should send error to user
+ prepared_scramble Buffer to store hash password of new connection
+ had_password Set to 1 if the user gave a password
+ cur_priv_version Check flag to know if someone flushed the privileges
+ since last code
+ hint_user Pointer used by acl_getroot() to remmeber user for
+ next call
+
+ RETURN
+ 0 ok
+ thd->user, thd->master_access, thd->priv_user, thd->db and
+ thd->db_access are updated
+ 1 Access denied; Error sent to client
+ -1 If do_send_error == 1: Failed connect, error sent to client
+ If do_send_error == 0: Prepare for stage of connect
*/
-static bool check_user(THD *thd,enum_server_command command, const char *user,
- const char *passwd, const char *db, bool check_count)
+static int check_user(THD *thd,enum_server_command command, const char *user,
+ const char *passwd, const char *db, bool check_count,
+ bool simple_connect, bool do_send_error,
+ char *prepared_scramble, bool had_password,
+ uint *cur_priv_version, ACL_USER** hint_user)
{
- NET *net= &thd->net;
thd->db=0;
thd->db_length=0;
USER_RESOURCES ur;
- char tmp_passwd[SCRAMBLE_LENGTH + 1];
-
- if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH)
- return 1;
+ char tmp_passwd[SCRAMBLE41_LENGTH+1];
+ DBUG_ENTER("check_user");
+
/*
Move password to temporary buffer as it may be stored in communication
buffer
*/
- strmov(tmp_passwd, passwd);
+ strmake(tmp_passwd, passwd, sizeof(tmp_passwd));
passwd= tmp_passwd; // Use local copy
- if (!(thd->user = my_strdup(user, MYF(0))))
+ /* We shall avoid dupplicate user allocations here */
+ if (!thd->user && !(thd->user = my_strdup(user, MYF(0))))
{
- send_error(net,ER_OUT_OF_RESOURCES);
- return 1;
+ send_error(thd,ER_OUT_OF_RESOURCES);
+ DBUG_RETURN(1);
}
thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
passwd, thd->scramble,
- &thd->priv_user, thd->priv_host,
- protocol_version == 9 ||
- !(thd->client_capabilities &
- CLIENT_LONG_PASSWORD),&ur);
+ &thd->priv_user, thd->priv_host,
+ (protocol_version == 9 ||
+ !(thd->client_capabilities &
+ CLIENT_LONG_PASSWORD)),
+ &ur,prepared_scramble,
+ cur_priv_version,hint_user);
+
DBUG_PRINT("info",
("Capabilities: %d packet_length: %ld Host: '%s' Login user: '%s' Priv_user: '%s' Using password: %s Access: %u db: '%s'",
thd->client_capabilities, thd->max_client_packet_length,
thd->host_or_ip, thd->user, thd->priv_user,
- passwd[0] ? "yes": "no",
+ had_password ? "yes": "no",
thd->master_access, thd->db ? thd->db : "*none*"));
+
+ /*
+ In case we're going to retry we should not send error message at this
+ point
+ */
if (thd->master_access & NO_ACCESS)
{
- net_printf(net, ER_ACCESS_DENIED_ERROR,
- thd->user,
- thd->host_or_ip,
- passwd[0] ? ER(ER_YES) : ER(ER_NO));
- mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
- thd->user,
- thd->host_or_ip,
- passwd[0] ? ER(ER_YES) : ER(ER_NO));
- return(1); // Error already given
+ if (do_send_error || !had_password || !*hint_user)
+ {
+ DBUG_PRINT("info",("Access denied"));
+ /*
+ Old client should get nicer error message if password version is
+ not supported
+ */
+ if (simple_connect && *hint_user && (*hint_user)->pversion)
+ {
+ net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ }
+ else
+ {
+ net_printf(thd, ER_ACCESS_DENIED_ERROR,
+ thd->user,
+ thd->host_or_ip,
+ had_password ? ER(ER_YES) : ER(ER_NO));
+ mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
+ thd->user,
+ thd->host_or_ip,
+ had_password ? ER(ER_YES) : ER(ER_NO));
+ }
+ DBUG_RETURN(1); // Error already given
+ }
+ DBUG_PRINT("info",("Prepare for second part of handshake"));
+ DBUG_RETURN(-1); // no report error in special handshake
}
+
if (check_count)
{
VOID(pthread_mutex_lock(&LOCK_thread_count));
@@ -244,8 +291,8 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (tmp)
{ // Too many connections
- send_error(net, ER_CON_COUNT_ERROR);
- return(1);
+ send_error(thd, ER_CON_COUNT_ERROR);
+ DBUG_RETURN(1);
}
}
mysql_log.write(thd,command,
@@ -259,22 +306,22 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
/* Don't allow user to connect if he has done too many queries */
if ((ur.questions || ur.updates || ur.connections || max_user_connections) &&
get_or_create_user_conn(thd,user,thd->host_or_ip,&ur))
- return -1;
+ DBUG_RETURN(1);
if (thd->user_connect && ((thd->user_connect->user_resources.connections) ||
max_user_connections) &&
- check_for_max_user_connections(thd->user_connect))
- return -1;
+ check_for_max_user_connections(thd, thd->user_connect))
+ DBUG_RETURN(1);
+
if (db && db[0])
{
- bool error=test(mysql_change_db(thd,db));
+ int error= test(mysql_change_db(thd,db));
if (error && thd->user_connect)
decrease_user_connections(thd->user_connect);
- return error;
+ DBUG_RETURN(error);
}
- else
- send_ok(net); // Ready to handle questions
+ send_ok(thd); // Ready to handle questions
thd->password= test(passwd[0]); // Remember for error messages
- return 0; // ok
+ DBUG_RETURN(0); // ok
}
@@ -295,35 +342,35 @@ extern "C" void free_user(struct user_conn *uc)
my_free((char*) uc,MYF(0));
}
-void init_max_user_conn(void)
+void init_max_user_conn(void)
{
- (void) hash_init(&hash_user_connections,max_connections,0,0,
+ (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
+ 0,0,
(hash_get_key) get_key_conn, (hash_free_key) free_user,
0);
}
-static int check_for_max_user_connections(USER_CONN *uc)
+static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
{
int error=0;
DBUG_ENTER("check_for_max_user_connections");
-
+
if (max_user_connections &&
(max_user_connections < (uint) uc->connections))
{
- net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, uc->user);
+ net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user);
error=1;
goto end;
}
- uc->connections++;
+ uc->connections++;
if (uc->user_resources.connections &&
uc->conn_per_hour++ >= uc->user_resources.connections)
{
- net_printf(&current_thd->net, ER_USER_LIMIT_REACHED, uc->user,
+ net_printf(thd, ER_USER_LIMIT_REACHED, uc->user,
"max_connections",
(long) uc->user_resources.connections);
error=1;
- goto end;
}
end:
DBUG_RETURN(error);
@@ -378,9 +425,13 @@ void init_update_queries(void)
uc_update_queries[SQLCOM_RESTORE_TABLE]=1;
uc_update_queries[SQLCOM_DELETE_MULTI]=1;
uc_update_queries[SQLCOM_DROP_INDEX]=1;
- uc_update_queries[SQLCOM_MULTI_UPDATE]=1;
+ uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
}
+bool is_update_query(enum enum_sql_command command)
+{
+ return uc_update_queries[command];
+}
/*
Check if maximum queries per hour limit has been reached
@@ -414,7 +465,7 @@ static bool check_mqh(THD *thd, uint check_command)
if (uc->user_resources.questions &&
uc->questions++ >= uc->user_resources.questions)
{
- net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
+ net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
(long) uc->user_resources.questions);
error=1;
goto end;
@@ -425,7 +476,7 @@ static bool check_mqh(THD *thd, uint check_command)
if (uc->user_resources.updates && uc_update_queries[check_command] &&
uc->updates++ >= uc->user_resources.updates)
{
- net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
+ net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
(long) uc->user_resources.updates);
error=1;
goto end;
@@ -440,7 +491,7 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
{
(void) pthread_mutex_lock(&LOCK_user_conn);
- if (lu) // for GRANT
+ if (lu) // for GRANT
{
USER_CONN *uc;
uint temp_len=lu->user.length+lu->host.length+2;
@@ -475,20 +526,36 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
/*
- Check connnetion and get priviliges
- Returns 0 on ok, -1 < if error is given > 0 on error.
+ Check connnectionn and get priviliges
+
+ SYNOPSIS
+ check_connections
+ thd Thread handle
+
+ RETURN
+ 0 ok
+ -1 Error, which is sent to user
+ > 0 Error code (not sent to user)
*/
+#ifndef EMBEDDED_LIBRARY
static int
check_connections(THD *thd)
{
+ int res;
uint connect_errors=0;
+ uint cur_priv_version;
+ bool using_password;
NET *net= &thd->net;
- /* Store the connection details */
- DBUG_PRINT("info", (("check_connections called by thread %d"),
- thd->thread_id));
+ char *end, *user, *passwd, *db;
+ char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble&hash */
+ char db_buff[NAME_LEN+1];
+ ACL_USER* cached_user=NULL; /* Initialise to NULL for first stage */
DBUG_PRINT("info",("New connection received on %s",
- vio_description(net->vio)));
+ vio_description(net->vio)));
+
+ /* Remove warning from valgrind. TODO: Fix it in password.c */
+ bzero((char*) &prepared_scramble[0], sizeof(prepared_scramble));
if (!thd->host) // If TCP/IP connection
{
char ip[30];
@@ -507,18 +574,20 @@ check_connections(THD *thd)
}
else
#endif
- if (!(specialflag & SPECIAL_NO_RESOLVE))
{
- vio_in_addr(net->vio,&thd->remote.sin_addr);
- thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
- /* Cut very long hostnames to avoid possible overflows */
- if (thd->host)
+ if (!(specialflag & SPECIAL_NO_RESOLVE))
{
- thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
- thd->host_or_ip= thd->host;
+ vio_in_addr(net->vio,&thd->remote.sin_addr);
+ thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
+ /* Cut very long hostnames to avoid possible overflows */
+ if (thd->host)
+ {
+ thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
+ thd->host_or_ip= thd->host;
+ }
+ if (connect_errors > max_connect_errors)
+ return(ER_HOST_IS_BLOCKED);
}
- if (connect_errors > max_connect_errors)
- return(ER_HOST_IS_BLOCKED);
}
DBUG_PRINT("info",("Host: %s ip: %s",
thd->host ? thd->host : "unknown host",
@@ -539,8 +608,9 @@ check_connections(THD *thd)
ulong pkt_len=0;
{
/* buff[] needs to big enough to hold the server_version variable */
- char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+32],*end;
- int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB;
+ char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+64];
+ ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
+ CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
if (opt_using_transactions)
client_flags|=CLIENT_TRANSACTIONS;
@@ -558,13 +628,15 @@ check_connections(THD *thd)
memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
end+=SCRAMBLE_LENGTH +1;
int2store(end,client_flags);
- end[2]=(char) MY_CHARSET_CURRENT;
+ end[2]=(char) default_charset_info->number;
int2store(end+3,thd->server_status);
bzero(end+5,13);
end+=18;
- if (net_write_command(net,(uchar) protocol_version, buff,
+
+ // At this point we write connection message and read reply
+ if (net_write_command(net,(uchar) protocol_version, "", 0, buff,
(uint) (end-buff)) ||
- (pkt_len= my_net_read(net)) == packet_error ||
+ (pkt_len= my_net_read(net)) == packet_error ||
pkt_len < MIN_HANDSHAKE_SIZE)
{
inc_host_errors(&thd->remote.sin_addr);
@@ -580,8 +652,58 @@ check_connections(THD *thd)
return(ER_OUT_OF_RESOURCES);
thd->client_capabilities=uint2korr(net->read_pos);
+#ifdef TO_BE_REMOVED_IN_4_1_RELEASE
+ /*
+ This is just a safety check against any client that would use the old
+ CLIENT_CHANGE_USER flag
+ */
+ if ((thd->client_capabilities & CLIENT_PROTOCOL_41) &&
+ !(thd->client_capabilities & (CLIENT_RESERVED |
+ CLIENT_SECURE_CONNECTION |
+ CLIENT_MULTI_RESULTS)))
+ thd->client_capabilities&= ~CLIENT_PROTOCOL_41;
+#endif
+ 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]));
+ /*
+ Use server character set and collation if
+ - client has not specified a character set
+ - client character set is the same as the servers
+ - client character set doesn't exists in server
+ */
+ if (!(thd->variables.character_set_client=
+ get_charset((uint) net->read_pos[8], MYF(0))) ||
+ !my_strcasecmp(&my_charset_latin1,
+ global_system_variables.character_set_client->name,
+ thd->variables.character_set_client->name))
+ {
+ thd->variables.character_set_client=
+ global_system_variables.character_set_client;
+ thd->variables.collation_connection=
+ global_system_variables.collation_connection;
+ thd->variables.character_set_results=
+ global_system_variables.character_set_results;
+ }
+ else
+ {
+ thd->variables.character_set_results=
+ thd->variables.collation_connection=
+ thd->variables.character_set_client;
+ }
+ thd->update_charset();
+ end= (char*) net->read_pos+32;
+ }
+ else
+ {
+ thd->max_client_packet_length= uint3korr(net->read_pos+2);
+ end= (char*) net->read_pos+5;
+ }
+
if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
- thd->sql_mode|= MODE_IGNORE_SPACE;
+ thd->variables.sql_mode|= MODE_IGNORE_SPACE;
#ifdef HAVE_OPENSSL
DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
if (thd->client_capabilities & CLIENT_SSL)
@@ -598,7 +720,7 @@ check_connections(THD *thd)
DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
pkt_len));
inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
+ return(ER_HANDSHAKE_ERROR);
}
DBUG_PRINT("info", ("Reading user information over SSL layer"));
if ((pkt_len=my_net_read(net)) == packet_error ||
@@ -610,31 +732,93 @@ check_connections(THD *thd)
return(ER_HANDSHAKE_ERROR);
}
}
- else
+#endif
+
+ if (end >= (char*) net->read_pos+ pkt_len +2)
{
- DBUG_PRINT("info", ("Leaving IO layer intact"));
- if (pkt_len < NORMAL_HANDSHAKE_SIZE)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return ER_HANDSHAKE_ERROR;
- }
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
}
-#endif
- thd->max_client_packet_length=uint3korr(net->read_pos+2);
- char *user= (char*) net->read_pos+5;
- char *passwd= strend(user)+1;
- char *db=0;
+ user= end;
+ passwd= strend(user)+1;
+ db=0;
+ using_password= test(passwd[0]);
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
- db=strend(passwd)+1;
+ {
+ db= strend(passwd)+1;
+ uint32 length= copy_and_convert(db_buff, sizeof(db_buff)-1,
+ system_charset_info,
+ db, strlen(db),
+ thd->charset());
+ db_buff[length]= 0;
+ db= db_buff;
+ }
+
+ /* We can get only old hash at this point */
+ if (using_password && strlen(passwd) != SCRAMBLE_LENGTH)
+ return ER_HANDSHAKE_ERROR;
+
if (thd->client_capabilities & CLIENT_INTERACTIVE)
thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
opt_using_transactions)
- thd->net.return_status= &thd->server_status;
+ net->return_status= &thd->server_status;
net->read_timeout=(uint) thd->variables.net_read_timeout;
- if (check_user(thd,COM_CONNECT, user, passwd, db, 1))
- return (-1);
+
+ /* Simple connect only for old clients. New clients always use secure auth */
+ bool simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
+
+ /* Check user permissions. If password failure we'll get scramble back */
+ if ((res=check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect,
+ simple_connect, prepared_scramble, using_password,
+ &cur_priv_version,
+ &cached_user)) < 0)
+ {
+ /* Store current used and database as they are erased with next packet */
+ char tmp_user[USERNAME_LENGTH+1];
+ char tmp_db[NAME_LEN+1];
+
+ /* If the client is old we just have to return error */
+ if (simple_connect)
+ return -1;
+
+ DBUG_PRINT("info",("password challenge"));
+
+ tmp_user[0]= tmp_db[0]= 0;
+ if (user)
+ strmake(tmp_user,user,USERNAME_LENGTH);
+ if (db)
+ strmake(tmp_db,db,NAME_LEN);
+
+ /* Write hash and encrypted scramble to client */
+ if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
+ net_flush(net))
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return ER_HANDSHAKE_ERROR;
+ }
+ /* Reading packet back */
+ if ((pkt_len= my_net_read(net)) == packet_error)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return ER_HANDSHAKE_ERROR;
+ }
+ /* We have to get very specific packet size */
+ if (pkt_len != SCRAMBLE41_LENGTH)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return ER_HANDSHAKE_ERROR;
+ }
+ /* Final attempt to check the user based on reply */
+ if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos,
+ tmp_db, 1, 0, 1, prepared_scramble, using_password,
+ &cur_priv_version,
+ &cached_user))
+ return -1;
+ }
+ else if (res)
+ return -1; // Error sent from check_user()
return 0;
}
@@ -653,7 +837,7 @@ pthread_handler_decl(handle_one_connection,arg)
// The following calls needs to be done before we call DBUG_ macros
if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
{
- close_connection(&thd->net,ER_OUT_OF_RESOURCES);
+ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
statistic_increment(aborted_connects,&LOCK_status);
end_thread(thd,0);
return 0;
@@ -680,7 +864,7 @@ pthread_handler_decl(handle_one_connection,arg)
#endif
if (thd->store_globals())
{
- close_connection(&thd->net,ER_OUT_OF_RESOURCES);
+ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
statistic_increment(aborted_connects,&LOCK_status);
end_thread(thd,0);
return 0;
@@ -695,10 +879,10 @@ pthread_handler_decl(handle_one_connection,arg)
if ((error=check_connections(thd)))
{ // Wrong permissions
if (error > 0)
- net_printf(net,error,thd->host_or_ip);
+ net_printf(thd,error,thd->host_or_ip);
#ifdef __NT__
if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
- sleep(1); /* must wait after eof() */
+ my_sleep(1000); /* must wait after eof() */
#endif
statistic_increment(aborted_connects,&LOCK_status);
goto end_thread;
@@ -715,9 +899,7 @@ pthread_handler_decl(handle_one_connection,arg)
thd->command=COM_SLEEP;
thd->version=refresh_version;
thd->set_time();
- init_sql_alloc(&thd->mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
- init_sql_alloc(&thd->transaction.mem_root,
- TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC);
+ thd->init_for_queries();
while (!net->error && net->vio != 0 && !thd->killed)
{
if (do_command(thd))
@@ -726,7 +908,7 @@ pthread_handler_decl(handle_one_connection,arg)
if (thd->user_connect)
decrease_user_connections(thd->user_connect);
free_root(&thd->mem_root,MYF(0));
- if (net->error && net->vio != 0)
+ if (net->error && net->vio != 0 && net->report_error)
{
if (!thd->killed && thd->variables.log_warnings)
sql_print_error(ER(ER_NEW_ABORTING_CONNECTION),
@@ -735,7 +917,7 @@ pthread_handler_decl(handle_one_connection,arg)
thd->host_or_ip,
(net->last_errno ? ER(net->last_errno) :
ER(ER_UNKNOWN_ERROR)));
- send_error(net,net->last_errno,NullS);
+ send_error(thd,net->last_errno,NullS);
statistic_increment(aborted_threads,&LOCK_status);
}
else if (thd->killed)
@@ -744,7 +926,7 @@ pthread_handler_decl(handle_one_connection,arg)
}
end_thread:
- close_connection(net);
+ close_connection(thd, 0, 1);
end_thread(thd,1);
/*
If end_thread returns, we are either running with --one-thread
@@ -770,8 +952,8 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
/* The following must be called before DBUG_ENTER */
if (my_thread_init() || thd->store_globals())
{
- close_connection(&thd->net,ER_OUT_OF_RESOURCES);
- thd->fatal_error=1;
+ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
+ thd->fatal_error();
goto end;
}
DBUG_ENTER("handle_bootstrap");
@@ -792,16 +974,14 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->priv_user=thd->user=(char*) my_strdup("boot", MYF(MY_WME));
buff= (char*) thd->net.buff;
- init_sql_alloc(&thd->mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
- init_sql_alloc(&thd->transaction.mem_root,
- TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC);
+ thd->init_for_queries();
while (fgets(buff, thd->net.max_packet, file))
{
uint length=(uint) strlen(buff);
- while (length && (isspace(buff[length-1]) || buff[length-1] == ';'))
+ while (length && (my_isspace(thd->charset(), buff[length-1]) ||
+ buff[length-1] == ';'))
length--;
buff[length]=0;
- thd->current_tablenr=0;
thd->query_length=length;
thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
thd->query[length] = '\0';
@@ -815,7 +995,7 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
}
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
- if (thd->fatal_error)
+ if (thd->is_fatal_error)
break;
free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
@@ -832,11 +1012,13 @@ end:
DBUG_RETURN(0); // Never reached
}
+#endif /* EMBEDDED_LIBRARY */
-inline void free_items(THD *thd)
-{
/* This works because items are allocated with sql_alloc() */
- for (Item *item=thd->free_list ; item ; item=item->next)
+
+void free_items(Item *item)
+{
+ for (; item ; item=item->next)
delete item;
}
@@ -856,12 +1038,12 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
if (!db || check_db_name(db))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
+ net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
goto err;
}
if (lower_case_table_names)
- casedn_str(tbl_name);
- remove_escape(tbl_name);
+ my_casedn_str(files_charset_info, tbl_name);
+ remove_escape(table_list->real_name);
if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
DBUG_RETURN(1);
@@ -876,7 +1058,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
thd->query = tbl_name;
if ((error = mysqld_dump_create_info(thd, table, -1)))
{
- my_error(ER_GET_ERRNO, MYF(0));
+ my_error(ER_GET_ERRNO, MYF(0), my_errno);
goto err;
}
net_flush(&thd->net);
@@ -891,6 +1073,7 @@ err:
/* Execute one command from socket (query or simple command) */
+#ifndef EMBEDDED_LIBRARY
bool do_command(THD *thd)
{
char *packet;
@@ -901,14 +1084,17 @@ bool do_command(THD *thd)
DBUG_ENTER("do_command");
net= &thd->net;
- thd->current_tablenr=0;
+ /*
+ indicator of uninitialized lex => normal flow of errors handling
+ (see my_message_sql)
+ */
+ thd->lex.current_select= 0;
packet=0;
old_timeout=net->read_timeout;
// Wait max for 8 hours
net->read_timeout=(uint) thd->variables.net_wait_timeout;
- net->last_error[0]=0; // Clear error message
- net->last_errno=0;
+ thd->clear_error(); // Clear error message
net_new_transaction(net);
if ((packet_length=my_net_read(net)) == packet_error)
@@ -922,7 +1108,7 @@ bool do_command(THD *thd)
statistic_increment(aborted_threads,&LOCK_status);
DBUG_RETURN(TRUE); // We have to close it.
}
- send_error(net,net->last_errno,NullS);
+ send_error(thd,net->last_errno,NullS);
net->error= 0;
DBUG_RETURN(FALSE);
}
@@ -939,13 +1125,14 @@ bool do_command(THD *thd)
net->read_timeout=old_timeout; // restore it
DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
}
+#endif /* EMBEDDED_LIBRARY */
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length)
{
NET *net= &thd->net;
- bool error=0;
+ bool error= 0;
/*
Commands which will always take a long time should be marked with
this so that they will not get logged to the slow query log
@@ -965,36 +1152,43 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->lex.select_lex.options=0; // We store status here
switch (command) {
case COM_INIT_DB:
+ {
+ LEX_STRING tmp;
statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
- if (!mysql_change_db(thd,packet))
+ thd->convert_string(&tmp, system_charset_info,
+ packet, strlen(packet), thd->charset());
+ if (!mysql_change_db(thd, tmp.str))
mysql_log.write(thd,command,"%s",thd->db);
break;
+ }
+#ifndef EMBEDDED_LIBRARY
case COM_REGISTER_SLAVE:
{
if (!register_slave(thd, (uchar*)packet, packet_length))
- send_ok(&thd->net);
+ send_ok(thd);
break;
}
+#endif
case COM_TABLE_DUMP:
- {
- statistic_increment(com_other, &LOCK_status);
- slow_command = TRUE;
- uint db_len = *(uchar*)packet;
- uint tbl_len = *(uchar*)(packet + db_len + 1);
- char* db = thd->alloc(db_len + tbl_len + 2);
- memcpy(db, packet + 1, db_len);
- char* tbl_name = db + db_len;
- *tbl_name++ = 0;
- memcpy(tbl_name, packet + db_len + 2, tbl_len);
- tbl_name[tbl_len] = 0;
- if (mysql_table_dump(thd, db, tbl_name, -1))
- send_error(&thd->net); // dump to NET
- break;
- }
+ {
+ char *db, *tbl_name;
+ uint db_len= *(uchar*) packet;
+ uint tbl_len= *(uchar*) (packet + db_len + 1);
+
+ statistic_increment(com_other, &LOCK_status);
+ slow_command= TRUE;
+ db= thd->alloc(db_len + tbl_len + 2);
+ tbl_name= strmake(db, packet + 1, db_len)+1;
+ strmake(tbl_name, packet + db_len + 2, tbl_len);
+ if (mysql_table_dump(thd, db, tbl_name, -1))
+ send_error(thd); // dump to NET
+ break;
+ }
+#ifndef EMBEDDED_LIBRARY
case COM_CHANGE_USER:
{
thd->change_user();
- clear_error_message(thd); // If errors from rollback
+ thd->clear_error(); // If errors from rollback
statistic_increment(com_other,&LOCK_status);
char *user= (char*) packet;
@@ -1006,63 +1200,165 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
uint save_db_access= thd->db_access;
uint save_db_length= thd->db_length;
char *save_user= thd->user;
+ thd->user=NULL; /* Needed for check_user to allocate new user */
char *save_priv_user= thd->priv_user;
char *save_db= thd->db;
- thd->user=0;
- USER_CONN *save_uc= thd->user_connect;
+ USER_CONN *save_uc= thd->user_connect;
+ bool simple_connect;
+ bool using_password;
+ char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */
+ char tmp_user[USERNAME_LENGTH+1];
+ char tmp_db[NAME_LEN+1];
+ ACL_USER* cached_user ; /* Cached user */
+ uint cur_priv_version; /* Cached grant version */
+ int res;
+ ulong pkt_len= 0; /* Length of reply packet */
+
+ bzero((char*) prepared_scramble, sizeof(prepared_scramble));
+ /* Small check for incomming packet */
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
- { // Check if protocol is ok
- send_error(net, ER_UNKNOWN_COM_ERROR);
- break;
- }
- if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0))
- { // Restore old user
- x_free(thd->user);
- thd->master_access=save_master_access;
- thd->db_access=save_db_access;
- thd->db=save_db;
- thd->db_length=save_db_length;
- thd->user=save_user;
- thd->priv_user=save_priv_user;
- break;
+ goto restore_user_err;
+
+ /* Now we shall basically perform authentication again */
+
+ /* We can get only old hash at this point */
+ if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
+ goto restore_user_err;
+
+ cached_user= NULL;
+
+ /* Simple connect only for old clients. New clients always use sec. auth*/
+ simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
+
+ /* Store information if we used password. passwd will be dammaged */
+ using_password=test(passwd[0]);
+
+ if (simple_connect) /* Restore scramble for old clients */
+ memcpy(thd->scramble,thd->old_scramble,9);
+
+ /*
+ Check user permissions. If password failure we'll get scramble back
+ Do not retry if we already have sent error (result>0)
+ */
+ if ((res=check_user(thd,COM_CHANGE_USER, user, passwd, db, 0,
+ simple_connect, simple_connect, prepared_scramble,
+ using_password, &cur_priv_version, &cached_user)) < 0)
+ {
+ /* If the client is old we just have to have auth failure */
+ if (simple_connect)
+ goto restore_user; /* Error is already reported */
+
+ /* Store current used and database as they are erased with next packet */
+ tmp_user[0]= tmp_db[0]= 0;
+ if (user)
+ strmake(tmp_user,user,USERNAME_LENGTH);
+ if (db)
+ strmake(tmp_db,db,NAME_LEN);
+
+ /* Write hash and encrypted scramble to client */
+ if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
+ net_flush(net))
+ goto restore_user_err;
+
+ /* Reading packet back */
+ if ((pkt_len=my_net_read(net)) == packet_error)
+ goto restore_user_err;
+
+ /* We have to get very specific packet size */
+ if (pkt_len != SCRAMBLE41_LENGTH)
+ goto restore_user;
+
+ /* Final attempt to check the user based on reply */
+ if (check_user(thd,COM_CHANGE_USER, tmp_user, (char*) net->read_pos,
+ tmp_db, 0, 0, 1, prepared_scramble, using_password,
+ &cur_priv_version, &cached_user))
+ goto restore_user;
}
+ else if (res)
+ goto restore_user;
+
+ /* Finally we've authenticated new user */
if (max_connections && save_uc)
decrease_user_connections(save_uc);
x_free((gptr) save_db);
x_free((gptr) save_user);
+ thd->password=using_password;
break;
- }
+ /* Bad luck we shall restore old user */
+restore_user_err:
+ send_error(thd, ER_UNKNOWN_COM_ERROR);
+
+restore_user:
+ x_free(thd->user);
+ thd->master_access=save_master_access;
+ thd->db_access=save_db_access;
+ thd->db=save_db;
+ thd->db_length=save_db_length;
+ thd->user=save_user;
+ thd->priv_user=save_priv_user;
+ break;
+ }
+#endif /* EMBEDDED_LIBRARY */
+ case COM_EXECUTE:
+ {
+ mysql_stmt_execute(thd, packet);
+ break;
+ }
+ case COM_LONG_DATA:
+ {
+ mysql_stmt_get_longdata(thd, packet, packet_length);
+ break;
+ }
+ case COM_PREPARE:
+ {
+ mysql_stmt_prepare(thd, packet, packet_length);
+ break;
+ }
+ case COM_CLOSE_STMT:
+ {
+ mysql_stmt_free(thd, packet);
+ break;
+ }
+ case COM_RESET_STMT:
+ {
+ mysql_stmt_reset(thd, packet);
+ break;
+ }
case COM_QUERY:
{
- packet_length--; // Remove end null
- /* Remove garage at start and end of query */
- while (isspace(packet[0]) && packet_length > 0)
- {
- packet++;
- packet_length--;
- }
- char *pos=packet+packet_length; // Point at end null
- while (packet_length > 0 && (pos[-1] == ';' || isspace(pos[-1])))
- {
- pos--;
- packet_length--;
- }
- /* We must allocate some extra memory for query cache */
- if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
- packet_length,
- thd->db_length+2+
- sizeof(ha_rows))))
- break;
- thd->query[packet_length]=0;
- thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory
- if (!(specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(),QUERY_PRIOR);
+ if (alloc_query(thd, packet, packet_length))
+ break; // fatal error is set
mysql_log.write(thd,command,"%s",thd->query);
DBUG_PRINT("query",("%-.4096s",thd->query));
- /* thd->query_length is set by mysql_parse() */
- mysql_parse(thd,thd->query,packet_length);
+ mysql_parse(thd,thd->query, thd->query_length);
+
+ while (!thd->killed && !thd->is_fatal_error && thd->lex.found_colon)
+ {
+ char *packet= thd->lex.found_colon;
+ /*
+ Multiple queries exits, execute them individually
+ */
+ if (thd->lock || thd->open_tables || thd->derived_tables)
+ close_thread_tables(thd);
+
+ ulong length= thd->query_length-(ulong)(thd->lex.found_colon-thd->query);
+
+ /* Remove garbage at start of query */
+ while (my_isspace(thd->charset(), *packet) && length > 0)
+ {
+ packet++;
+ length--;
+ }
+ thd->query_length= length;
+ thd->query= packet;
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->query_id= query_id++;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ mysql_parse(thd, packet, length);
+ }
+
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
DBUG_PRINT("info",("query ready"));
@@ -1070,28 +1366,33 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_FIELD_LIST: // This isn't actually needed
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
break;
#else
{
- char *fields;
+ char *fields, *pend;
TABLE_LIST table_list;
+ LEX_STRING conv_name;
+
statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
bzero((char*) &table_list,sizeof(table_list));
if (!(table_list.db=thd->db))
{
- send_error(net,ER_NO_DB_ERROR);
+ send_error(thd,ER_NO_DB_ERROR);
break;
}
thd->free_list=0;
- table_list.alias= table_list.real_name= thd->strdup(packet);
- packet=strend(packet)+1;
+ pend= strend(packet);
+ thd->convert_string(&conv_name, system_charset_info,
+ packet, (uint) (pend-packet), thd->charset());
+ table_list.alias= table_list.real_name= conv_name.str;
+ packet= pend+1;
// command not cachable => no gap for data base name
if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
break;
mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
if (lower_case_table_names)
- casedn_str(table_list.real_name);
+ my_casedn_str(files_charset_info, table_list.real_name);
remove_escape(table_list.real_name); // This can't have wildcards
if (check_access(thd,SELECT_ACL,table_list.db,&thd->col_access))
@@ -1100,7 +1401,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2))
break;
mysqld_list_fields(thd,&table_list,fields);
- free_items(thd);
+ free_items(thd->free_list);
break;
}
#endif
@@ -1118,7 +1419,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
// null test to handle EOM
if (!db || !strip_sp(db) || check_db_name(db))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
+ net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
break;
}
if (check_access(thd,CREATE_ACL,db,0,1))
@@ -1134,20 +1435,21 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
// null test to handle EOM
if (!db || !strip_sp(db) || check_db_name(db))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
+ net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
break;
}
if (check_access(thd,DROP_ACL,db,0,1))
break;
if (thd->locked_tables || thd->active_transaction())
{
- send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
break;
}
mysql_log.write(thd,command,db);
mysql_rm_db(thd,db,0,0);
break;
}
+#ifndef EMBEDDED_LIBRARY
case COM_BINLOG_DUMP:
{
statistic_increment(com_other,&LOCK_status);
@@ -1173,6 +1475,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
net->error = 0;
break;
}
+#endif
case COM_REFRESH:
{
statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
@@ -1180,31 +1483,35 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (check_global_access(thd,RELOAD_ACL))
break;
mysql_log.write(thd,command,NullS);
- /* error sending is deferred to reload_acl_and_cache */
- reload_acl_and_cache(thd, options, (TABLE_LIST*) 0) ;
+ if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, NULL))
+ send_error(thd, 0);
+ else
+ send_ok(thd);
break;
}
+#ifndef EMBEDDED_LIBRARY
case COM_SHUTDOWN:
statistic_increment(com_other,&LOCK_status);
if (check_global_access(thd,SHUTDOWN_ACL))
break; /* purecov: inspected */
DBUG_PRINT("quit",("Got shutdown command"));
mysql_log.write(thd,command,NullS);
- send_eof(net);
+ send_eof(thd);
#ifdef __WIN__
sleep(1); // must wait after eof()
#endif
#ifndef OS2
- send_eof(net); // This is for 'quit request'
+ send_eof(thd); // This is for 'quit request'
#endif
- close_connection(net);
+ close_connection(thd, 0, 1);
close_thread_tables(thd); // Free before kill
free_root(&thd->mem_root,MYF(0));
free_root(&thd->transaction.mem_root,MYF(0));
kill_mysql();
error=TRUE;
break;
-
+#endif
+#ifndef EMBEDDED_LIBRARY
case COM_STATISTICS:
{
mysql_log.write(thd,command,NullS);
@@ -1227,9 +1534,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
VOID(net_flush(net));
break;
}
+#endif
case COM_PING:
statistic_increment(com_other,&LOCK_status);
- send_ok(net); // Tell client we are alive
+ send_ok(thd); // Tell client we are alive
break;
case COM_PROCESS_INFO:
statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
@@ -1252,7 +1560,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break; /* purecov: inspected */
mysql_print_status(thd);
mysql_log.write(thd,command,NullS);
- send_eof(net);
+ send_eof(thd);
break;
case COM_SLEEP:
case COM_CONNECT: // Impossible here
@@ -1260,17 +1568,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_DELAYED_INSERT:
case COM_END:
default:
- send_error(net, ER_UNKNOWN_COM_ERROR);
+ send_error(thd, ER_UNKNOWN_COM_ERROR);
break;
}
- if (thd->lock || thd->open_tables)
+ if (thd->lock || thd->open_tables || thd->derived_tables)
{
thd->proc_info="closing tables";
close_thread_tables(thd); /* Free tables */
}
- if (thd->fatal_error)
- send_error(net,0); // End of memory ?
+ if (thd->is_fatal_error)
+ send_error(thd,0); // End of memory ?
time_t start_of_query=thd->start_time;
thd->end_time(); // Set start time
@@ -1302,24 +1610,85 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_RETURN(error);
}
+
+/*
+ Read query from packet and store in thd->query
+ Used in COM_QUERY and COM_PREPARE
+
+ DESCRIPTION
+ Sets the following THD variables:
+ query
+ query_length
+
+ RETURN VALUES
+ 0 ok
+ 1 error; In this case thd->fatal_error is set
+*/
+
+bool alloc_query(THD *thd, char *packet, ulong packet_length)
+{
+ packet_length--; // Remove end null
+ /* Remove garbage at start and end of query */
+ while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
+ {
+ packet++;
+ packet_length--;
+ }
+ char *pos=packet+packet_length; // Point at end null
+ while (packet_length > 0 &&
+ (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
+ {
+ pos--;
+ packet_length--;
+ }
+ /* We must allocate some extra memory for query cache */
+ if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
+ packet_length,
+ thd->db_length+2+
+ sizeof(ha_rows))))
+ return 1;
+ thd->query[packet_length]=0;
+ thd->query_length= packet_length;
+ thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory
+
+ if (!(specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_setprio(pthread_self(),QUERY_PRIOR);
+ return 0;
+}
+
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/
void
-mysql_execute_command(void)
+mysql_execute_command(THD *thd)
{
- int res=0;
- THD *thd=current_thd;
+ int res= 0;
LEX *lex= &thd->lex;
- TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first;
- SELECT_LEX *select_lex = lex->select;
+ TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first;
+ SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX_UNIT *unit= &lex->unit;
DBUG_ENTER("mysql_execute_command");
+ /*
+ Reset warning count for each query that uses tables
+ A better approach would be to reset this for any commands
+ that is not a SHOW command or a select that only access local
+ variables, but for now this is probably good enough.
+ */
+ if (tables || &lex->select_lex != lex->all_selects_list)
+ mysql_reset_errors(thd);
+ /*
+ Save old warning count to be able to send to client how many warnings we
+ got
+ */
+ thd->old_total_warn_count= thd->total_warn_count;
+
+#ifndef EMBEDDED_LIBRARY
if (thd->slave_thread)
{
- /*
+ /*
Skip if we are in the slave thread, some table rules have been
given and the table list says the query should not be replicated
*/
@@ -1331,9 +1700,9 @@ mysql_execute_command(void)
}
#ifndef TO_BE_DELETED
/*
- This is a workaround to deal with the shortcoming in 3.23.44-3.23.46
- masters in RELEASE_LOCK() logging. We re-write SELECT RELEASE_LOCK()
- as DO RELEASE_LOCK()
+ This is a workaround to deal with the shortcoming in 3.23.44-3.23.46
+ masters in RELEASE_LOCK() logging. We re-write SELECT RELEASE_LOCK()
+ as DO RELEASE_LOCK()
*/
if (lex->sql_command == SQLCOM_SELECT)
{
@@ -1342,8 +1711,34 @@ mysql_execute_command(void)
}
#endif
}
-
- if (lex->select_lex.next && create_total_list(thd,lex,&tables))
+#endif /* EMBEDDED_LIBRARY */
+ /*
+ TODO: make derived tables processing 'inside' SELECT processing.
+ TODO: solve problem with depended derived tables in subselects
+ */
+ if (lex->derived_tables)
+ {
+ for (SELECT_LEX *sl= lex->all_selects_list;
+ sl;
+ sl= sl->next_select_in_list())
+ {
+ for (TABLE_LIST *cursor= sl->get_table_list();
+ cursor;
+ cursor= cursor->next)
+ {
+ if (cursor->derived && (res=mysql_derived(thd, lex,
+ cursor->derived,
+ cursor)))
+ {
+ if (res < 0 || thd->net.report_error)
+ send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
+ DBUG_VOID_RETURN;
+ }
+ }
+ }
+ }
+ if (&lex->select_lex != lex->all_selects_list &&
+ lex->unit.create_total_list(thd, lex, &tables, 0))
DBUG_VOID_RETURN;
/*
@@ -1354,7 +1749,7 @@ mysql_execute_command(void)
!(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
(uc_update_queries[lex->sql_command] > 0))
{
- send_error(&thd->net,ER_CANT_UPDATE_WITH_READLOCK);
+ send_error(thd, ER_CANT_UPDATE_WITH_READLOCK);
DBUG_VOID_RETURN;
}
@@ -1362,9 +1757,7 @@ mysql_execute_command(void)
switch (lex->sql_command) {
case SQLCOM_SELECT:
{
- select_result *result;
- if (select_lex->options & SELECT_DESCRIBE)
- lex->exchange=0;
+ select_result *result=lex->result;
if (tables)
{
res=check_table_access(thd,
@@ -1381,92 +1774,121 @@ mysql_execute_command(void)
break; // Error message is given
}
- thd->offset_limit=select_lex->offset_limit;
- thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
- if (thd->select_limit < select_lex->select_limit)
- thd->select_limit= HA_POS_ERROR; // no limit
- if (thd->select_limit == HA_POS_ERROR)
+ unit->offset_limit_cnt= (ha_rows) unit->global_parameters->offset_limit;
+ unit->select_limit_cnt= (ha_rows) (unit->global_parameters->select_limit+
+ unit->global_parameters->offset_limit);
+ if (unit->select_limit_cnt <
+ (ha_rows) unit->global_parameters->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR; // no limit
+ if (unit->select_limit_cnt == HA_POS_ERROR)
select_lex->options&= ~OPTION_FOUND_ROWS;
- if (lex->exchange)
+ if (!(res=open_and_lock_tables(thd,tables)))
{
- if (lex->exchange->dumpfile)
+ if (lex->describe)
{
- if (!(result=new select_dump(lex->exchange)))
+ if (!(result= new select_send()))
{
- res= -1;
- break;
+ send_error(thd, ER_OUT_OF_RESOURCES);
+ DBUG_VOID_RETURN;
}
+ else
+ thd->send_explain_fields(result);
+ fix_tables_pointers(lex->all_selects_list);
+ res= mysql_explain_union(thd, &thd->lex.unit, result);
+ MYSQL_LOCK *save_lock= thd->lock;
+ thd->lock= (MYSQL_LOCK *)0;
+ result->send_eof();
+ thd->lock= save_lock;
}
else
{
- if (!(result=new select_export(lex->exchange)))
+ if (!result)
{
- res= -1;
- break;
- }
- }
- }
- else if (!(result=new select_send()))
- {
- res= -1;
+ if (!(result=new select_send()))
+ {
+ res= -1;
#ifdef DELETE_ITEMS
- delete select_lex->having;
- delete select_lex->where;
+ delete select_lex->having;
+ delete select_lex->where;
#endif
- break;
- }
- else
- {
- /*
- Normal select:
- Change lock if we are using SELECT HIGH PRIORITY,
- FOR UPDATE or IN SHARE MODE
-
- TODO: Delete the following loop when locks is set by sql_yacc
- */
- TABLE_LIST *table;
- for (table = tables ; table ; table=table->next)
- table->lock_type= lex->lock_option;
- }
-
- if (!(res=open_and_lock_tables(thd,tables)))
- {
- query_cache_store_query(thd, tables);
- res=handle_select(thd, lex, result);
+ break;
+ }
+ }
+ query_cache_store_query(thd, tables);
+ res=handle_select(thd, lex, result);
+ }
}
- else
- delete result;
break;
}
case SQLCOM_DO:
- res=mysql_do(thd, *lex->insert_list);
+ if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
+ (res= open_and_lock_tables(thd,tables))))
+ break;
+
+ fix_tables_pointers(lex->all_selects_list);
+ res= mysql_do(thd, *lex->insert_list);
+ if (thd->net.report_error)
+ res= -1;
break;
case SQLCOM_EMPTY_QUERY:
- send_ok(&thd->net);
+ send_ok(thd);
break;
+ case SQLCOM_HELP:
+ res= mysqld_help(thd,lex->help_arg);
+ break;
+
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_PURGE:
{
if (check_global_access(thd, SUPER_ACL))
goto error;
+ // PURGE MASTER LOGS TO 'file'
res = purge_master_logs(thd, lex->to_log);
break;
}
+ case SQLCOM_PURGE_BEFORE:
+ {
+ if (check_global_access(thd, SUPER_ACL))
+ goto error;
+ // PURGE MASTER LOGS BEFORE 'data'
+ res = purge_master_logs_before_date(thd, lex->purge_time);
+ break;
+ }
+#endif
+
+ case SQLCOM_SHOW_WARNS:
+ {
+ res= mysqld_show_warnings(thd, (ulong)
+ ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
+ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
+ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
+ ));
+ break;
+ }
+ case SQLCOM_SHOW_ERRORS:
+ {
+ res= mysqld_show_warnings(thd, (ulong)
+ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
+ break;
+ }
case SQLCOM_SHOW_NEW_MASTER:
{
if (check_global_access(thd, REPL_SLAVE_ACL))
goto error;
/* This query don't work now. See comment in repl_failsafe.cc */
#ifndef WORKING_NEW_MASTER
- net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
+ net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
res= 1;
#else
res = show_new_master(thd);
#endif
break;
}
+
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_SHOW_SLAVE_HOSTS:
{
if (check_global_access(thd, REPL_SLAVE_ACL))
@@ -1481,6 +1903,8 @@ mysql_execute_command(void)
res = show_binlog_events(thd);
break;
}
+#endif
+
case SQLCOM_BACKUP_TABLE:
{
if (check_db_used(thd,tables) ||
@@ -1500,6 +1924,17 @@ mysql_execute_command(void)
res = mysql_restore_table(thd, tables);
break;
}
+ case SQLCOM_PRELOAD_KEYS:
+ {
+ if (check_db_used(thd, tables) ||
+ check_access(thd, INDEX_ACL, tables->db, &tables->grant.privilege))
+ goto error;
+ res = mysql_preload_keys(thd, tables);
+ break;
+ }
+
+
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_CHANGE_MASTER:
{
if (check_global_access(thd, SUPER_ACL))
@@ -1527,7 +1962,7 @@ mysql_execute_command(void)
res = show_binlog_info(thd);
break;
}
-
+
case SQLCOM_LOAD_MASTER_DATA: // sync with master
if (check_global_access(thd, SUPER_ACL))
goto error;
@@ -1536,7 +1971,8 @@ mysql_execute_command(void)
else
res = load_master_data(thd);
break;
-
+#endif /* EMBEDDED_LIBRARY */
+
#ifdef HAVE_INNOBASE_DB
case SQLCOM_SHOW_INNODB_STATUS:
{
@@ -1547,6 +1983,7 @@ mysql_execute_command(void)
}
#endif
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_LOAD_MASTER_TABLE:
{
if (!tables->db)
@@ -1563,16 +2000,23 @@ mysql_execute_command(void)
if (error)
goto error;
}
+ if (strlen(tables->real_name) > NAME_LEN)
+ {
+ net_printf(thd,ER_WRONG_TABLE_NAME,tables->real_name);
+ break;
+ }
LOCK_ACTIVE_MI;
// fetch_master_table will send the error to the client on failure
if (!fetch_master_table(thd, tables->db, tables->real_name,
active_mi, 0))
{
- send_ok(&thd->net);
+ send_ok(thd);
}
UNLOCK_ACTIVE_MI;
break;
}
+#endif /* EMBEDDED_LIBRARY */
+
case SQLCOM_CREATE_TABLE:
{
ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
@@ -1596,7 +2040,7 @@ mysql_execute_command(void)
}
if (strlen(tables->real_name) > NAME_LEN)
{
- net_printf(&thd->net, ER_WRONG_TABLE_NAME, tables->alias);
+ net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias);
res=0;
break;
}
@@ -1618,25 +2062,22 @@ mysql_execute_command(void)
select_result *result;
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
- check_dup(tables->db, tables->real_name, tables->next))
+ find_real_table_in_list(tables->next, tables->db, tables->real_name))
{
- net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
+ net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
}
if (tables->next)
{
- TABLE_LIST *table;
if (check_table_access(thd, SELECT_ACL, tables->next))
goto error; // Error message is given
- /* TODO: Delete the following loop when locks is set by sql_yacc */
- for (table = tables->next ; table ; table=table->next)
- table->lock_type= lex->lock_option;
}
select_lex->options|= SELECT_NO_UNLOCK;
- thd->offset_limit=select_lex->offset_limit;
- thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
- if (thd->select_limit < select_lex->select_limit)
- thd->select_limit= HA_POS_ERROR; // No limit
+ unit->offset_limit_cnt= select_lex->offset_limit;
+ unit->select_limit_cnt= select_lex->select_limit+
+ select_lex->offset_limit;
+ if (unit->select_limit_cnt < select_lex->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR; // No limit
/* Skip first table, which is the table we are creating */
lex->select_lex.table_list.first=
@@ -1655,12 +2096,26 @@ mysql_execute_command(void)
}
else // regular create
{
- res = mysql_create_table(thd,tables->db ? tables->db : thd->db,
- tables->real_name, &lex->create_info,
- lex->create_list,
- lex->key_list,0, 0); // do logging
+ if (lex->name)
+ res= mysql_create_like_table(thd, tables, &lex->create_info,
+ (Table_ident *)lex->name);
+ else
+ {
+ List_iterator<create_field> fields(lex->create_list);
+ create_field *field;
+ while ((field= fields++))
+ {
+ if (!field->charset)
+ field->charset= lex->create_info.table_charset;
+ field->create_length_to_internal_length();
+ }
+ res= mysql_create_table(thd,tables->db ? tables->db : thd->db,
+ tables->real_name, &lex->create_info,
+ lex->create_list,
+ lex->key_list,0,0,0); // do logging
+ }
if (!res)
- send_ok(&thd->net);
+ send_ok(thd);
}
break;
}
@@ -1677,6 +2132,7 @@ mysql_execute_command(void)
res = mysql_create_index(thd, tables, lex->key_list);
break;
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_SLAVE_START:
{
LOCK_ACTIVE_MI;
@@ -1700,7 +2156,7 @@ mysql_execute_command(void)
*/
if (thd->locked_tables || thd->active_transaction())
{
- send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
break;
}
{
@@ -1709,16 +2165,18 @@ mysql_execute_command(void)
UNLOCK_ACTIVE_MI;
break;
}
+#endif
+
case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
break;
#else
{
ulong priv=0;
if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
{
- net_printf(&thd->net,ER_WRONG_TABLE_NAME,lex->name);
+ net_printf(thd,ER_WRONG_TABLE_NAME,lex->name);
res=0;
break;
}
@@ -1728,7 +2186,7 @@ mysql_execute_command(void)
select_lex->db=tables->db;
if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege) ||
check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv) ||
- check_merge_table_access(thd, tables->db,
+ check_merge_table_access(thd, tables->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
goto error; /* purecov: inspected */
@@ -1760,6 +2218,7 @@ mysql_execute_command(void)
&lex->create_info,
tables, lex->create_list,
lex->key_list, lex->drop_list, lex->alter_list,
+ select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
lex->drop_primary, lex->duplicates,
lex->alter_keys_onoff, lex->simple_alter);
@@ -1799,9 +2258,10 @@ mysql_execute_command(void)
res= -1;
break;
}
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
@@ -1810,10 +2270,11 @@ mysql_execute_command(void)
res = show_binlogs(thd);
break;
}
-#endif
+#endif
+#endif /* EMBEDDED_LIBRARY */
case SQLCOM_SHOW_CREATE:
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
@@ -1831,6 +2292,16 @@ mysql_execute_command(void)
check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
goto error; /* purecov: inspected */
res = mysql_repair_table(thd, tables, &lex->check_opt);
+ /* ! we write after unlocking the table */
+ if (!res && !lex->no_write_to_binlog)
+ {
+ mysql_update_log.write(thd, thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
+ }
+ }
break;
}
case SQLCOM_CHECK:
@@ -1847,6 +2318,16 @@ mysql_execute_command(void)
check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
goto error; /* purecov: inspected */
res = mysql_analyze_table(thd, tables, &lex->check_opt);
+ /* ! we write after unlocking the table */
+ if (!res && !lex->no_write_to_binlog)
+ {
+ mysql_update_log.write(thd, thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
+ }
+ }
break;
}
@@ -1867,54 +2348,70 @@ mysql_execute_command(void)
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
create_info.row_type=ROW_TYPE_DEFAULT;
+ create_info.table_charset=default_charset_info;
res= mysql_alter_table(thd, NullS, NullS, &create_info,
tables, lex->create_list,
lex->key_list, lex->drop_list, lex->alter_list,
- (ORDER *) 0,
- 0,DUP_ERROR);
+ 0, (ORDER *) 0,
+ 0, DUP_ERROR);
}
else
res = mysql_optimize_table(thd, tables, &lex->check_opt);
+ /* ! we write after unlocking the table */
+ if (!res && !lex->no_write_to_binlog)
+ {
+ mysql_update_log.write(thd, thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
+ }
+ }
break;
}
case SQLCOM_UPDATE:
- TABLE_LIST *table;
if (check_db_used(thd,tables))
goto error;
- for (table=tables ; table ; table=table->next)
- {
- if (check_access(thd,UPDATE_ACL,table->db,&table->grant.privilege))
+
+ if (single_table_command_access(thd, UPDATE_ACL, tables, &res))
goto error;
+
+ if (select_lex->item_list.elements != lex->value_list.elements)
+ {
+ send_error(thd,ER_WRONG_VALUE_COUNT);
+ DBUG_VOID_RETURN;
}
+ res= mysql_update(thd,tables,
+ select_lex->item_list,
+ lex->value_list,
+ select_lex->where,
+ select_lex->order_list.elements,
+ (ORDER *) select_lex->order_list.first,
+ select_lex->select_limit,
+ lex->duplicates);
+ if (thd->net.report_error)
+ res= -1;
+ break;
+ case SQLCOM_UPDATE_MULTI:
+ if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege))
+ goto error;
if (grant_option && check_grant(thd,UPDATE_ACL,tables))
goto error;
if (select_lex->item_list.elements != lex->value_list.elements)
{
- send_error(&thd->net,ER_WRONG_VALUE_COUNT);
+ send_error(thd,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
- if (select_lex->table_list.elements == 1)
- {
- res= mysql_update(thd,tables,
- select_lex->item_list,
- lex->value_list,
- select_lex->where,
- (ORDER *) select_lex->order_list.first,
- select_lex->select_limit,
- lex->duplicates);
- }
- else
{
const char *msg= 0;
- lex->sql_command= SQLCOM_MULTI_UPDATE;
if (select_lex->order_list.elements)
- msg="ORDER BY";
+ msg= "ORDER BY";
else if (select_lex->select_limit && select_lex->select_limit !=
HA_POS_ERROR)
- msg="LIMIT";
+ msg= "LIMIT";
if (msg)
{
- net_printf(&thd->net, ER_WRONG_USAGE, "UPDATE", msg);
+ net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg);
res= 1;
break;
}
@@ -1923,28 +2420,31 @@ mysql_execute_command(void)
&lex->value_list,
select_lex->where,
select_lex->options,
- lex->duplicates);
+ lex->duplicates, unit, select_lex);
}
break;
- case SQLCOM_INSERT:
- if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege))
- goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd,INSERT_ACL,tables))
- goto error;
- res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
- lex->duplicates);
- break;
case SQLCOM_REPLACE:
- if (check_access(thd,INSERT_ACL | DELETE_ACL,
- tables->db,&tables->grant.privilege))
- goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd,INSERT_ACL | DELETE_ACL,
- tables))
+ case SQLCOM_INSERT:
+ {
+ my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
+ ulong privilege= (lex->duplicates == DUP_REPLACE ?
+ INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
- goto error;
+ if (single_table_command_access(thd, privilege, tables, &res))
+ goto error;
+
+ if (select_lex->item_list.elements != lex->value_list.elements)
+ {
+ send_error(thd,ER_WRONG_VALUE_COUNT);
+ DBUG_VOID_RETURN;
+ }
res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
- DUP_REPLACE);
+ select_lex->item_list, lex->value_list,
+ (update ? DUP_UPDATE : lex->duplicates));
+ if (thd->net.report_error)
+ res= -1;
break;
+ }
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
@@ -1954,8 +2454,8 @@ mysql_execute_command(void)
select privileges for the rest
*/
{
- ulong privilege= (lex->sql_command == SQLCOM_INSERT_SELECT ?
- INSERT_ACL : INSERT_ACL | DELETE_ACL);
+ ulong privilege= (lex->duplicates == DUP_REPLACE ?
+ INSERT_ACL | DELETE_ACL : INSERT_ACL);
TABLE_LIST *save_next=tables->next;
tables->next=0;
if (check_access(thd, privilege,
@@ -1970,31 +2470,29 @@ mysql_execute_command(void)
select_lex->options|= SELECT_NO_UNLOCK;
select_result *result;
- thd->offset_limit=select_lex->offset_limit;
- thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
- if (thd->select_limit < select_lex->select_limit)
- thd->select_limit= HA_POS_ERROR; // No limit
+ unit->offset_limit_cnt= select_lex->offset_limit;
+ unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit;
+ if (unit->select_limit_cnt < select_lex->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR; // No limit
- if (check_dup(tables->db, tables->real_name, tables->next))
+ if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
{
/* Using same table for INSERT and SELECT */
select_lex->options |= OPTION_BUFFER_RESULT;
}
- {
- /* TODO: Delete the following loop when locks is set by sql_yacc */
- TABLE_LIST *table;
- for (table = tables->next ; table ; table=table->next)
- table->lock_type= lex->lock_option;
- }
/* Skip first table, which is the table we are inserting in */
lex->select_lex.table_list.first=
(byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
+ lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE;
+
if (!(res=open_and_lock_tables(thd, tables)))
{
if ((result=new select_insert(tables->table,&lex->field_list,
lex->duplicates)))
res=handle_select(thd,lex,result);
+ if (thd->net.report_error)
+ res= -1;
}
else
res= -1;
@@ -2011,22 +2509,23 @@ mysql_execute_command(void)
*/
if (thd->locked_tables || thd->active_transaction())
{
- send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
+ send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
goto error;
}
res=mysql_truncate(thd,tables);
break;
case SQLCOM_DELETE:
{
- if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
- goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd,DELETE_ACL,tables))
+ if (single_table_command_access(thd, DELETE_ACL, tables, &res))
goto error;
+
// Set privilege for the WHERE clause
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
res = mysql_delete(thd,tables, select_lex->where,
(ORDER*) select_lex->order_list.first,
select_lex->select_limit, select_lex->options);
+ if (thd->net.report_error)
+ res= -1;
break;
}
case SQLCOM_DELETE_MULTI:
@@ -2038,12 +2537,12 @@ mysql_execute_command(void)
/* sql_yacc guarantees that tables and aux_tables are not zero */
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
- check_table_access(thd,SELECT_ACL, tables) ||
+ check_table_access(thd,SELECT_ACL, tables) ||
check_table_access(thd,DELETE_ACL, aux_tables))
goto error;
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
- {
- send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ {
+ send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
goto error;
}
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
@@ -2059,36 +2558,52 @@ mysql_execute_command(void)
}
if (!walk)
{
- net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name);
+ net_printf(thd,ER_NONUNIQ_TABLE,auxi->real_name);
goto error;
}
walk->lock_type= auxi->lock_type;
- // Store address to table as we need it later
- auxi->table= my_reinterpret_cast(TABLE *) (walk);
+ auxi->table_list= walk; // Remember corresponding table
}
- if (add_item_to_list(new Item_null()))
+ if (add_item_to_list(thd, new Item_null()))
{
res= -1;
break;
}
- tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
thd->proc_info="init";
if ((res=open_and_lock_tables(thd,tables)))
break;
/* Fix tables-to-be-deleted-from list to point at opened tables */
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
- auxi->table= (my_reinterpret_cast(TABLE_LIST*) (auxi->table))->table;
-
- if (!thd->fatal_error && (result= new multi_delete(thd,aux_tables,
- table_count)))
- {
- res=mysql_select(thd,tables,select_lex->item_list,
- select_lex->where,
- (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
- (ORDER *)NULL,
- select_lex->options | thd->options |
- SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
- result);
+ auxi->table= auxi->table_list->table;
+ if (&lex->select_lex != lex->all_selects_list)
+ {
+ for (TABLE_LIST *t= select_lex->get_table_list();
+ t; t= t->next)
+ {
+ if (find_real_table_in_list(t->table_list->next, t->db, t->real_name))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), t->real_name);
+ res= -1;
+ break;
+ }
+ }
+ }
+ fix_tables_pointers(lex->all_selects_list);
+ if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
+ table_count)))
+ {
+ res= mysql_select(thd, &select_lex->ref_pointer_array,
+ select_lex->get_table_list(),
+ select_lex->with_wild,
+ select_lex->item_list,
+ select_lex->where,
+ 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
+ (ORDER *)NULL,
+ select_lex->options | thd->options |
+ SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
+ result, unit, select_lex, 0);
+ if (thd->net.report_error)
+ res= -1;
delete result;
}
else
@@ -2098,22 +2613,30 @@ mysql_execute_command(void)
}
case SQLCOM_DROP_TABLE:
{
- if (check_table_access(thd,DROP_ACL,tables))
- goto error; /* purecov: inspected */
- /*
- If this is a slave thread, we may sometimes execute some
- DROP / * 40005 TEMPORARY * / TABLE
- that come from parts of binlogs (likely if we use RESET SLAVE or CHANGE
- MASTER TO), while the temporary table has already been dropped.
- To not generate such irrelevant "table does not exist errors", we silently
- add IF EXISTS if TEMPORARY was used.
- */
- if (thd->slave_thread && lex->drop_temporary)
- lex->drop_if_exists= 1;
- if (end_active_trans(thd))
- res= -1;
+ if (!lex->drop_temporary)
+ {
+ if (check_table_access(thd,DROP_ACL,tables))
+ goto error; /* purecov: inspected */
+ if (end_active_trans(thd))
+ {
+ res= -1;
+ break;
+ }
+ }
else
- res = mysql_rm_table(thd,tables,lex->drop_if_exists);
+ {
+ /*
+ If this is a slave thread, we may sometimes execute some
+ DROP / * 40005 TEMPORARY * / TABLE
+ that come from parts of binlogs (likely if we use RESET SLAVE or CHANGE
+ MASTER TO), while the temporary table has already been dropped.
+ To not generate such irrelevant "table does not exist errors", we
+ silently add IF EXISTS if TEMPORARY was used.
+ */
+ if (thd->slave_thread)
+ lex->drop_if_exists= 1;
+ }
+ res= mysql_rm_table(thd,tables,lex->drop_if_exists, lex->drop_temporary);
}
break;
case SQLCOM_DROP_INDEX:
@@ -2130,7 +2653,7 @@ mysql_execute_command(void)
break;
case SQLCOM_SHOW_DATABASES:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
@@ -2145,6 +2668,15 @@ mysql_execute_command(void)
mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
thd->priv_user,lex->verbose);
break;
+ case SQLCOM_SHOW_TABLE_TYPES:
+ res= mysqld_show_table_types(thd);
+ break;
+ case SQLCOM_SHOW_PRIVILEGES:
+ res= mysqld_show_privileges(thd);
+ break;
+ case SQLCOM_SHOW_COLUMN_TYPES:
+ res= mysqld_show_column_types(thd);
+ break;
case SQLCOM_SHOW_STATUS:
res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
OPT_GLOBAL, &LOCK_status);
@@ -2155,34 +2687,41 @@ mysql_execute_command(void)
&LOCK_global_system_variables);
break;
case SQLCOM_SHOW_LOGS:
- {
- res= mysqld_show_logs(thd);
- break;
- }
+#ifdef DONT_ALLOW_SHOW_COMMANDS
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ DBUG_VOID_RETURN;
+#else
+ {
+ if (grant_option && check_access(thd, FILE_ACL, any_db))
+ goto error;
+ res= mysqld_show_logs(thd);
+ break;
+ }
+#endif
case SQLCOM_SHOW_TABLES:
/* FALL THROUGH */
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
char *db=select_lex->db ? select_lex->db : thd->db;
if (!db)
{
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
+ send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
goto error; /* purecov: inspected */
}
remove_escape(db); // Fix escaped '_'
if (check_db_name(db))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, db);
+ net_printf(thd,ER_WRONG_DB_NAME, db);
goto error;
}
if (check_access(thd,SELECT_ACL,db,&thd->col_access))
goto error; /* purecov: inspected */
if (!thd->col_access && check_grant_db(thd,db))
{
- net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
+ net_printf(thd, ER_DBACCESS_DENIED_ERROR,
thd->priv_user,
thd->priv_host,
db);
@@ -2201,16 +2740,22 @@ mysql_execute_command(void)
case SQLCOM_SHOW_OPEN_TABLES:
res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
break;
+ case SQLCOM_SHOW_CHARSETS:
+ res= mysqld_show_charsets(thd,(lex->wild ? lex->wild->ptr() : NullS));
+ break;
+ case SQLCOM_SHOW_COLLATIONS:
+ res= mysqld_show_collations(thd,(lex->wild ? lex->wild->ptr() : NullS));
+ break;
case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
char *db=tables->db;
if (!*db)
{
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
+ send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
goto error; /* purecov: inspected */
}
remove_escape(db); // Fix escaped '_'
@@ -2228,14 +2773,14 @@ mysql_execute_command(void)
#endif
case SQLCOM_SHOW_KEYS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
char *db=tables->db;
if (!db)
{
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
+ send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
goto error; /* purecov: inspected */
}
remove_escape(db); // Fix escaped '_'
@@ -2254,10 +2799,11 @@ mysql_execute_command(void)
case SQLCOM_CHANGE_DB:
mysql_change_db(thd,select_lex->db);
break;
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_LOAD:
{
uint privilege= (lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | UPDATE_ACL | DELETE_ACL : INSERT_ACL);
+ INSERT_ACL | DELETE_ACL : INSERT_ACL);
if (!lex->local_file)
{
@@ -2269,7 +2815,7 @@ mysql_execute_command(void)
if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
! opt_local_infile)
{
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);
+ send_error(thd,ER_NOT_ALLOWED_COMMAND);
goto error;
}
if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
@@ -2280,10 +2826,18 @@ mysql_execute_command(void)
lex->duplicates, (bool) lex->local_file, lex->lock_option);
break;
}
+#endif /* EMBEDDED_LIBRARY */
case SQLCOM_SET_OPTION:
- if (!(res=sql_set_variables(thd, &lex->var_list)))
- send_ok(&thd->net);
+ if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
+ (res= open_and_lock_tables(thd,tables))))
+ break;
+ fix_tables_pointers(lex->all_selects_list);
+ if (!(res= sql_set_variables(thd, &lex->var_list)))
+ send_ok(thd);
+ if (thd->net.report_error)
+ res= -1;
break;
+
case SQLCOM_UNLOCK_TABLES:
unlock_locked_tables(thd);
if (thd->options & OPTION_TABLE_LOCK)
@@ -2293,7 +2847,7 @@ mysql_execute_command(void)
}
if (thd->global_read_lock)
unlock_global_read_lock(thd);
- send_ok(&thd->net);
+ send_ok(thd);
break;
case SQLCOM_LOCK_TABLES:
unlock_locked_tables(thd);
@@ -2307,7 +2861,7 @@ mysql_execute_command(void)
{
thd->locked_tables=thd->lock;
thd->lock=0;
- send_ok(&thd->net);
+ send_ok(thd);
}
else
thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
@@ -2317,7 +2871,7 @@ mysql_execute_command(void)
{
if (!strip_sp(lex->name) || check_db_name(lex->name))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
+ net_printf(thd,ER_WRONG_DB_NAME, lex->name);
break;
}
/*
@@ -2327,6 +2881,7 @@ mysql_execute_command(void)
do_db/ignore_db. And as this query involves no tables, tables_ok()
above was not called. So we have to check rules again here.
*/
+#ifdef HAVE_REPLICATION
if (thd->slave_thread &&
(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
!db_ok_with_wild_table(lex->name)))
@@ -2334,17 +2889,17 @@ mysql_execute_command(void)
my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
break;
}
-
+#endif
if (check_access(thd,CREATE_ACL,lex->name,0,1))
break;
- res=mysql_create_db(thd,lex->name,lex->create_info.options,0);
+ res=mysql_create_db(thd,lex->name,&lex->create_info,0);
break;
}
case SQLCOM_DROP_DB:
{
if (!strip_sp(lex->name) || check_db_name(lex->name))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
+ net_printf(thd,ER_WRONG_DB_NAME, lex->name);
break;
}
/*
@@ -2354,6 +2909,7 @@ mysql_execute_command(void)
do_db/ignore_db. And as this query involves no tables, tables_ok()
above was not called. So we have to check rules again here.
*/
+#ifdef HAVE_REPLICATION
if (thd->slave_thread &&
(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
!db_ok_with_wild_table(lex->name)))
@@ -2361,22 +2917,57 @@ mysql_execute_command(void)
my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
break;
}
+#endif
if (check_access(thd,DROP_ACL,lex->name,0,1))
break;
if (thd->locked_tables || thd->active_transaction())
{
- send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
goto error;
}
res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0);
break;
}
+ case SQLCOM_ALTER_DB:
+ {
+ if (!strip_sp(lex->name) || check_db_name(lex->name))
+ {
+ net_printf(thd,ER_WRONG_DB_NAME, lex->name);
+ break;
+ }
+ if (check_access(thd,ALTER_ACL,lex->name,0,1))
+ break;
+ if (thd->locked_tables || thd->active_transaction())
+ {
+ send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ goto error;
+ }
+ res=mysql_alter_db(thd,lex->name,&lex->create_info);
+ break;
+ }
+ case SQLCOM_SHOW_CREATE_DB:
+ {
+ if (!strip_sp(lex->name) || check_db_name(lex->name))
+ {
+ net_printf(thd,ER_WRONG_DB_NAME, lex->name);
+ break;
+ }
+ if (check_access(thd,DROP_ACL,lex->name,0,1))
+ break;
+ if (thd->locked_tables || thd->active_transaction())
+ {
+ send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ goto error;
+ }
+ res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
+ break;
+ }
case SQLCOM_CREATE_FUNCTION:
if (check_access(thd,INSERT_ACL,"mysql",0,1))
break;
#ifdef HAVE_DLOPEN
if (!(res = mysql_create_function(thd,&lex->udf)))
- send_ok(&thd->net);
+ send_ok(thd);
#else
res= -1;
#endif
@@ -2385,12 +2976,44 @@ mysql_execute_command(void)
if (check_access(thd,DELETE_ACL,"mysql",0,1))
break;
#ifdef HAVE_DLOPEN
- if (!(res = mysql_drop_function(thd,lex->udf.name)))
- send_ok(&thd->net);
+ if (!(res = mysql_drop_function(thd,&lex->udf.name)))
+ send_ok(thd);
#else
res= -1;
#endif
break;
+ case SQLCOM_DROP_USER:
+ {
+ if (check_access(thd, GRANT_ACL,"mysql",0,1))
+ break;
+ if (!(res= mysql_drop_user(thd, lex->users_list)))
+ {
+ mysql_update_log.write(thd, thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
+ }
+ send_ok(thd);
+ }
+ break;
+ }
+ case SQLCOM_REVOKE_ALL:
+ {
+ if (check_access(thd, GRANT_ACL ,"mysql",0,1))
+ break;
+ if (!(res = mysql_revoke_all(thd, lex->users_list)))
+ {
+ mysql_update_log.write(thd, thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
+ }
+ send_ok(thd);
+ }
+ break;
+ }
case SQLCOM_REVOKE:
case SQLCOM_GRANT:
{
@@ -2414,7 +3037,8 @@ mysql_execute_command(void)
if (user->password.str &&
(strcmp(thd->user,user->user.str) ||
user->host.str &&
- my_strcasecmp(user->host.str, thd->host_or_ip)))
+ my_strcasecmp(&my_charset_latin1,
+ user->host.str, thd->host_or_ip)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1))
goto error;
@@ -2445,7 +3069,7 @@ mysql_execute_command(void)
{
if (lex->columns.elements)
{
- send_error(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
+ send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE);
res=1;
}
else
@@ -2470,13 +3094,42 @@ mysql_execute_command(void)
}
break;
}
- case SQLCOM_FLUSH:
case SQLCOM_RESET:
+ /*
+ RESET commands are never written to the binary log, so we have to
+ initialize this variable because RESET shares the same code as FLUSH
+ */
+ lex->no_write_to_binlog= 1;
+ case SQLCOM_FLUSH:
+ {
if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
goto error;
- /* error sending is deferred to reload_acl_and_cache */
- reload_acl_and_cache(thd, lex->type, tables) ;
+ /*
+ reload_acl_and_cache() will tell us if we are allowed to write to the
+ binlog or not.
+ */
+ bool write_to_binlog;
+ if (reload_acl_and_cache(thd, lex->type, tables, &write_to_binlog))
+ send_error(thd, 0);
+ else
+ {
+ /*
+ We WANT to write and we CAN write.
+ ! we write after unlocking the table.
+ */
+ if (!lex->no_write_to_binlog && write_to_binlog)
+ {
+ mysql_update_log.write(thd, thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
+ }
+ }
+ send_ok(thd);
+ }
break;
+ }
case SQLCOM_KILL:
kill_one_thread(thd,lex->thread_id);
break;
@@ -2529,7 +3182,7 @@ mysql_execute_command(void)
thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS;
- send_ok(&thd->net);
+ send_ok(thd);
}
break;
case SQLCOM_COMMIT:
@@ -2543,7 +3196,7 @@ mysql_execute_command(void)
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_commit(thd))
{
- send_ok(&thd->net);
+ send_ok(thd);
}
else
res= -1;
@@ -2563,9 +3216,9 @@ mysql_execute_command(void)
message in the error log, so we don't send it.
*/
if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
- send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
+ send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
else
- send_ok(&thd->net);
+ send_ok(thd);
}
else
res= -1;
@@ -2575,32 +3228,72 @@ mysql_execute_command(void)
if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
{
if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
- send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
+ send_warning(thd, ER_WARNING_NOT_COMPLETE_ROLLBACK, 0);
else
- send_ok(&thd->net);
+ send_ok(thd);
}
else
res= -1;
break;
case SQLCOM_SAVEPOINT:
if (!ha_savepoint(thd, lex->savepoint_name))
- send_ok(&thd->net);
+ send_ok(thd);
else
res= -1;
break;
default: /* Impossible */
- send_ok(&thd->net);
+ send_ok(thd);
break;
}
thd->proc_info="query end"; // QQ
if (res < 0)
- send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0);
+ send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
error:
DBUG_VOID_RETURN;
}
+/*
+ Check grants for commands which work only with one table and all other
+ tables belong to subselects.
+
+ SYNOPSYS
+ single_table_command_access()
+ thd - Thread handler
+ privilege - asked privelage
+ tables - table list of command
+ res - pointer on result code variable
+
+ RETURN
+ 0 - OK
+ 1 - access denied
+*/
+
+static bool single_table_command_access(THD *thd, ulong privilege,
+ TABLE_LIST *tables, int *res)
+
+{
+ if (check_access(thd, privilege, tables->db, &tables->grant.privilege))
+ return 1;
+
+ // Show only 1 table for check_grant
+ TABLE_LIST *subselects_tables= tables->next;
+ tables->next= 0;
+ if (grant_option && check_grant(thd, privilege, tables))
+ return 1;
+
+ // check rights on tables of subselect (if exists)
+ if (subselects_tables)
+ {
+ tables->next= subselects_tables;
+ if ((*res= check_table_access(thd, SELECT_ACL, subselects_tables)))
+ return 1;
+ }
+ return 0;
+}
+
+
/****************************************************************************
Get the user (global) and database privileges for all used tables
@@ -2636,7 +3329,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
{
if (!no_errors)
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */
+ send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
DBUG_RETURN(TRUE); /* purecov: tested */
}
@@ -2651,7 +3344,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if (!(thd->master_access & SELECT_ACL) &&
(db && (!thd->db || strcmp(db,thd->db))))
db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
- thd->priv_user, db); /* purecov: inspected */
+ thd->priv_user, db, test(want_access & GRANT_ACL));
*save_priv=thd->master_access | db_access;
DBUG_RETURN(FALSE);
}
@@ -2659,7 +3352,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
! db && dont_check_global_grants)
{ // We can never grant this
if (!no_errors)
- net_printf(&thd->net,ER_ACCESS_DENIED_ERROR,
+ net_printf(thd,ER_ACCESS_DENIED_ERROR,
thd->priv_user,
thd->priv_host,
thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
@@ -2671,7 +3364,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if (db && (!thd->db || strcmp(db,thd->db)))
db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
- thd->priv_user, db); /* purecov: inspected */
+ thd->priv_user, db, test(want_access & GRANT_ACL));
else
db_access=thd->db_access;
// Remove SHOW attribute and access rights we already have
@@ -2684,7 +3377,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
!(want_access & ~TABLE_ACLS)))
DBUG_RETURN(FALSE); /* Ok */
if (!no_errors)
- net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
+ net_printf(thd,ER_DBACCESS_DENIED_ERROR,
thd->priv_user,
thd->priv_host,
db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
@@ -2717,7 +3410,7 @@ bool check_global_access(THD *thd, ulong want_access)
if ((thd->master_access & want_access))
return 0;
get_privilege_desc(command, sizeof(command), want_access);
- net_printf(&thd->net,ER_SPECIFIC_ACCESS_DENIED_ERROR,
+ net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
command);
return 1;
}
@@ -2737,6 +3430,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
TABLE_LIST *org_tables=tables;
for (; tables ; tables=tables->next)
{
+ if (tables->derived || (tables->table && (int)tables->table->tmp_table))
+ continue;
if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
thd->db)
tables->grant.privilege= want_access;
@@ -2772,7 +3467,7 @@ static bool check_db_used(THD *thd,TABLE_LIST *tables)
{
if (!(tables->db=thd->db))
{
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */
+ send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
return TRUE; /* purecov: tested */
}
}
@@ -2793,11 +3488,6 @@ static bool check_merge_table_access(THD *thd, char *db,
{
if (!tmp->db || !tmp->db[0])
tmp->db=db;
- else if (strcmp(tmp->db,db))
- {
- send_error(&thd->net,ER_UNION_TABLES_IN_DIFFERENT_DIR);
- return 1;
- }
}
error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
table_list);
@@ -2825,7 +3515,7 @@ bool check_stack_overrun(THD *thd,char *buf __attribute__((unused)))
{
sprintf(errbuff[0],ER(ER_STACK_OVERRUN),stack_used,thread_stack);
my_message(ER_STACK_OVERRUN,errbuff[0],MYF(0));
- thd->fatal_error=1;
+ thd->fatal_error();
return 1;
}
return 0;
@@ -2865,108 +3555,199 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize)
/****************************************************************************
- Initialize global thd variables needed for query
+ Initialize global thd variables needed for query
****************************************************************************/
-static void
+void
mysql_init_query(THD *thd)
{
DBUG_ENTER("mysql_init_query");
- thd->lex.select_lex.item_list.empty();
- thd->lex.value_list.empty();
- thd->lex.select_lex.table_list.elements=0;
- thd->free_list=0; thd->lex.union_option=0;
- thd->lex.select = &thd->lex.select_lex;
- thd->lex.select_lex.table_list.first=0;
- thd->lex.select_lex.table_list.next= (byte**) &thd->lex.select_lex.table_list.first;
- thd->lex.select_lex.next=0;
- thd->lex.olap=0;
- thd->lex.select->olap= UNSPECIFIED_OLAP_TYPE;
- thd->fatal_error=0; // Safety
- thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
- thd->rand_used=0;
- thd->sent_row_count=thd->examined_row_count=0;
- thd->safe_to_cache_query=1;
+ LEX *lex=&thd->lex;
+ lex->unit.init_query();
+ lex->unit.init_select();
+ lex->unit.thd= thd;
+ lex->select_lex.init_query();
+ lex->value_list.empty();
+ lex->param_list.empty();
+ lex->unit.next= lex->unit.master=
+ lex->unit.link_next= lex->unit.return_to=0;
+ lex->unit.prev= lex->unit.link_prev= 0;
+ lex->unit.slave= lex->unit.global_parameters= lex->current_select=
+ lex->all_selects_list= &lex->select_lex;
+ lex->select_lex.master= &lex->unit;
+ lex->select_lex.prev= &lex->unit.slave;
+ lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
+ lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
+ lex->describe= 0;
+ lex->derived_tables= FALSE;
+ lex->lock_option= TL_READ;
+ lex->found_colon= 0;
+ lex->safe_to_cache_query= 1;
+ thd->select_number= lex->select_lex.select_number= 1;
+ thd->free_list= 0;
+ thd->total_warn_count=0; // Warnings for this query
+ thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
+ thd->sent_row_count= thd->examined_row_count= 0;
+ thd->is_fatal_error= thd->rand_used= 0;
+ thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
+ thd->tmp_table_used= 0;
+ if (opt_bin_log)
+ reset_dynamic(&thd->user_var_events);
+ thd->clear_error();
DBUG_VOID_RETURN;
}
+
void
mysql_init_select(LEX *lex)
{
- SELECT_LEX *select_lex = lex->select;
- select_lex->where=select_lex->having=0;
+ SELECT_LEX *select_lex= lex->current_select;
+ select_lex->init_select();
select_lex->select_limit= lex->thd->variables.select_limit;
- select_lex->offset_limit=0;
- select_lex->options=0;
- select_lex->linkage=UNSPECIFIED_TYPE;
- select_lex->olap= UNSPECIFIED_OLAP_TYPE;
- lex->exchange = 0;
- lex->proc_list.first=0;
- select_lex->order_list.empty();
- select_lex->group_list.empty();
- select_lex->next = (SELECT_LEX *)NULL;
+ if (select_lex == &lex->select_lex)
+ {
+ lex->exchange= 0;
+ lex->result= 0;
+ lex->proc_list.first= 0;
+ }
}
bool
-mysql_new_select(LEX *lex)
+mysql_new_select(LEX *lex, bool move_down)
{
- SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX));
+ SELECT_LEX *select_lex = new(&lex->thd->mem_root) SELECT_LEX();
if (!select_lex)
return 1;
- lex->select->next=select_lex;
- lex->select=select_lex;
- select_lex->table_list.next= (byte**) &select_lex->table_list.first;
- select_lex->item_list.empty();
- select_lex->when_list.empty();
- select_lex->expr_list.empty();
- select_lex->interval_list.empty();
- select_lex->use_index.empty();
- select_lex->ftfunc_list.empty();
+ select_lex->select_number= ++lex->thd->select_number;
+ select_lex->init_query();
+ select_lex->init_select();
+ if (move_down)
+ {
+ /* first select_lex of subselect or derived table */
+ SELECT_LEX_UNIT *unit= new(&lex->thd->mem_root) SELECT_LEX_UNIT();
+ if (!unit)
+ return 1;
+ unit->init_query();
+ unit->init_select();
+ unit->thd= lex->thd;
+ unit->include_down(lex->current_select);
+ unit->link_next= 0;
+ unit->link_prev= 0;
+ unit->return_to= lex->current_select;
+ select_lex->include_down(unit);
+ // TODO: assign resolve_mode for fake subquery after merging with new tree
+ }
+ else
+ {
+ select_lex->include_neighbour(lex->current_select);
+ SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ SELECT_LEX *fake= unit->fake_select_lex;
+ if (!fake)
+ {
+ /*
+ as far as we included SELECT_LEX for UNION unit should have
+ fake SELECT_LEX for UNION processing
+ */
+ fake= unit->fake_select_lex= new(&lex->thd->mem_root) SELECT_LEX();
+ fake->include_standalone(unit,
+ (SELECT_LEX_NODE**)&unit->fake_select_lex);
+ fake->select_number= INT_MAX;
+ fake->make_empty_select();
+ fake->linkage= GLOBAL_OPTIONS_TYPE;
+ fake->select_limit= lex->thd->variables.select_limit;
+ }
+ }
+
+ select_lex->master_unit()->global_parameters= select_lex;
+ select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
+ lex->current_select= select_lex;
+ select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
return 0;
}
+/*
+ Create a select to return the same output as 'SELECT @@var_name'.
+
+ SYNOPSIS
+ create_select_for_variable()
+ var_name Variable name
+
+ DESCRIPTION
+ Used for SHOW COUNT(*) [ WARNINGS | ERROR]
+
+ This will crash with a core dump if the variable doesn't exists
+*/
+
+void create_select_for_variable(const char *var_name)
+{
+ THD *thd;
+ LEX *lex;
+ LEX_STRING tmp, null_lex_string;
+ DBUG_ENTER("create_select_for_variable");
+
+ thd= current_thd;
+ lex= &thd->lex;
+ mysql_init_select(lex);
+ lex->sql_command= SQLCOM_SELECT;
+ tmp.str= (char*) var_name;
+ tmp.length=strlen(var_name);
+ bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
+ add_item_to_list(thd, get_system_var(thd, OPT_SESSION, tmp,
+ null_lex_string));
+ DBUG_VOID_RETURN;
+}
+
void mysql_init_multi_delete(LEX *lex)
{
- lex->sql_command = SQLCOM_DELETE_MULTI;
+ lex->sql_command= SQLCOM_DELETE_MULTI;
mysql_init_select(lex);
- lex->select->select_limit=lex->thd->select_limit=HA_POS_ERROR;
- lex->select->table_list.save_and_clear(&lex->auxilliary_table_list);
+ lex->select_lex.select_limit= lex->unit.select_limit_cnt=
+ HA_POS_ERROR;
+ lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list);
}
void
-mysql_parse(THD *thd,char *inBuf,uint length)
+mysql_parse(THD *thd, char *inBuf, uint length)
{
DBUG_ENTER("mysql_parse");
mysql_init_query(thd);
- thd->query_length = length;
if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
{
LEX *lex=lex_start(thd, (uchar*) inBuf, length);
- if (!yyparse() && ! thd->fatal_error)
+ if (!yyparse((void *)thd) && ! thd->is_fatal_error)
{
if (mqh_used && thd->user_connect &&
- check_mqh(thd, thd->lex.sql_command))
+ check_mqh(thd, lex->sql_command))
{
thd->net.error = 0;
}
else
{
- mysql_execute_command();
- query_cache_end_of_result(&thd->net);
+ if (thd->net.report_error)
+ send_error(thd, 0, NullS);
+ else
+ {
+ mysql_execute_command(thd);
+#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
+ query_cache_end_of_result(&thd->net);
+#endif
+ }
}
}
else
{
DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
- thd->fatal_error));
+ thd->is_fatal_error));
+#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
query_cache_abort(&thd->net);
+#endif
}
thd->proc_info="freeing items";
- free_items(thd); /* Free strings used by items */
+ free_items(thd->free_list); /* Free strings used by items */
lex_end(lex);
}
DBUG_VOID_RETURN;
@@ -2978,33 +3759,35 @@ mysql_parse(THD *thd,char *inBuf,uint length)
** Return 0 if ok
******************************************************************************/
-bool add_field_to_list(char *field_name, enum_field_types type,
+bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
char *length, char *decimals,
- uint type_modifier, Item *default_value,char *change,
- TYPELIB *interval)
+ uint type_modifier,
+ Item *default_value, Item *comment,
+ char *change, TYPELIB *interval, CHARSET_INFO *cs,
+ uint uint_geom_type)
{
register create_field *new_field;
- THD *thd=current_thd;
LEX *lex= &thd->lex;
uint allowed_type_modifier=0;
+ char warn_buff[MYSQL_ERRMSG_SIZE];
DBUG_ENTER("add_field_to_list");
if (strlen(field_name) > NAME_LEN)
{
- net_printf(&thd->net, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
+ net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
if (type_modifier & PRI_KEY_FLAG)
{
lex->col_list.push_back(new key_part_spec(field_name,0));
- lex->key_list.push_back(new Key(Key::PRIMARY,NullS,
+ lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
lex->col_list));
lex->col_list.empty();
}
if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
{
lex->col_list.push_back(new key_part_spec(field_name,0));
- lex->key_list.push_back(new Key(Key::UNIQUE,NullS,
+ lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF,
lex->col_list));
lex->col_list.empty();
}
@@ -3017,27 +3800,21 @@ bool add_field_to_list(char *field_name, enum_field_types type,
if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
NOT_NULL_FLAG)
{
- net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
+ net_printf(thd,ER_INVALID_DEFAULT,field_name);
DBUG_RETURN(1);
}
}
-#ifdef MYSQL41000
else if (type_modifier & AUTO_INCREMENT_FLAG)
{
- net_printf(&thd->net, ER_INVALID_DEFAULT, field_name);
+ net_printf(thd, ER_INVALID_DEFAULT, field_name);
DBUG_RETURN(1);
}
-#endif
}
if (!(new_field=new create_field()))
DBUG_RETURN(1);
new_field->field=0;
new_field->field_name=field_name;
-#ifdef MYSQL41000
new_field->def= default_value;
-#else
- new_field->def= (type_modifier & AUTO_INCREMENT_FLAG ? 0 : default_value);
-#endif
new_field->flags= type_modifier;
new_field->unireg_check= (type_modifier & AUTO_INCREMENT_FLAG ?
Field::NEXT_NUMBER : Field::NONE);
@@ -3048,6 +3825,20 @@ bool add_field_to_list(char *field_name, enum_field_types type,
new_field->change=change;
new_field->interval=0;
new_field->pack_length=0;
+ new_field->charset=cs;
+ new_field->geom_type= (Field::geometry_type) uint_geom_type;
+
+ if (!comment)
+ {
+ new_field->comment.str=0;
+ new_field->comment.length=0;
+ }
+ else
+ {
+ /* In this case comment is always of type Item_string */
+ new_field->comment.str= (char*) comment->str_value.ptr();
+ new_field->comment.length=comment->str_value.length();
+ }
if (length && !(new_field->length= (uint) atoi(length)))
length=0; /* purecov: inspected */
uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
@@ -3078,10 +3869,7 @@ bool add_field_to_list(char *field_name, enum_field_types type,
if (!length) new_field->length=20;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_VAR_STRING:
case FIELD_TYPE_NULL:
- case FIELD_TYPE_GEOMETRY:
break;
case FIELD_TYPE_DECIMAL:
if (!length)
@@ -3093,17 +3881,43 @@ bool add_field_to_list(char *field_name, enum_field_types type,
new_field->length++;
}
break;
+ case FIELD_TYPE_STRING:
+ case FIELD_TYPE_VAR_STRING:
+ if (new_field->length <= MAX_FIELD_CHARLENGTH || default_value)
+ break;
+ /* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */
+ new_field->sql_type= FIELD_TYPE_BLOB;
+ sprintf(warn_buff, ER(ER_AUTO_CONVERT), field_name, "CHAR",
+ (cs == &my_charset_bin) ? "BLOB" : "TEXT");
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_AUTO_CONVERT,
+ warn_buff);
+ /* fall through */
case FIELD_TYPE_BLOB:
case FIELD_TYPE_TINY_BLOB:
case FIELD_TYPE_LONG_BLOB:
case FIELD_TYPE_MEDIUM_BLOB:
+ case FIELD_TYPE_GEOMETRY:
+ if (new_field->length)
+ {
+ /* The user has given a length to the blob column */
+ if (new_field->length < 256)
+ type= FIELD_TYPE_TINY_BLOB;
+ if (new_field->length < 65536)
+ type= FIELD_TYPE_BLOB;
+ else if (new_field->length < 256L*256L*256L)
+ type= FIELD_TYPE_MEDIUM_BLOB;
+ else
+ type= FIELD_TYPE_LONG_BLOB;
+ new_field->length= 0;
+ }
+ new_field->sql_type= type;
if (default_value) // Allow empty as default value
{
String str,*res;
res=default_value->val_str(&str);
if (res->length())
{
- net_printf(&thd->net,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
+ net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
new_field->def=0;
@@ -3123,7 +3937,7 @@ bool add_field_to_list(char *field_name, enum_field_types type,
uint tmp_length=new_field->length;
if (tmp_length > PRECISION_FOR_DOUBLE)
{
- net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name);
+ net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
DBUG_RETURN(1);
}
else if (tmp_length > PRECISION_FOR_FLOAT)
@@ -3177,7 +3991,7 @@ bool add_field_to_list(char *field_name, enum_field_types type,
{
if (interval->count > sizeof(longlong)*8)
{
- net_printf(&thd->net,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
+ net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
new_field->pack_length=(interval->count+7)/8;
@@ -3193,13 +4007,18 @@ bool add_field_to_list(char *field_name, enum_field_types type,
set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
if (default_value)
{
+ char *not_used;
+ uint not_used2;
+ bool not_used3;
+
thd->cuted_fields=0;
String str,*res;
res=default_value->val_str(&str);
- (void) find_set(interval,res->ptr(),res->length());
+ (void) find_set(interval, res->ptr(), res->length(), &not_used,
+ &not_used2, &not_used3);
if (thd->cuted_fields)
{
- net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
+ net_printf(thd,ER_INVALID_DEFAULT,field_name);
DBUG_RETURN(1);
}
}
@@ -3222,7 +4041,7 @@ bool add_field_to_list(char *field_name, enum_field_types type,
res=default_value->val_str(&str);
if (!find_enum(interval,res->ptr(),res->length()))
{
- net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
+ net_printf(thd,ER_INVALID_DEFAULT,field_name);
DBUG_RETURN(1);
}
}
@@ -3230,18 +4049,20 @@ bool add_field_to_list(char *field_name, enum_field_types type,
}
}
- if (new_field->length >= MAX_FIELD_WIDTH ||
+ if ((new_field->length > MAX_FIELD_CHARLENGTH && type != FIELD_TYPE_SET &&
+ type != FIELD_TYPE_ENUM) ||
(!new_field->length && !(new_field->flags & BLOB_FLAG) &&
- type != FIELD_TYPE_STRING && type != FIELD_TYPE_VAR_STRING))
+ type != FIELD_TYPE_STRING &&
+ type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
{
- net_printf(&thd->net,ER_TOO_BIG_FIELDLENGTH,field_name,
- MAX_FIELD_WIDTH-1); /* purecov: inspected */
+ net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
+ MAX_FIELD_CHARLENGTH); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
type_modifier&= AUTO_INCREMENT_FLAG;
if ((~allowed_type_modifier) & type_modifier)
{
- net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name);
+ net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
DBUG_RETURN(1);
}
if (!new_field->pack_length)
@@ -3268,7 +4089,7 @@ add_proc_to_list(THD* thd, Item *item)
ORDER *order;
Item **item_ptr;
- if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
+ if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
return 1;
item_ptr = (Item**) (order+1);
*item_ptr= item;
@@ -3294,8 +4115,8 @@ static void remove_escape(char *name)
#ifdef USE_MB
int l;
/* if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
- if (use_mb(default_charset_info) &&
- (l = my_ismbchar(default_charset_info, name, strend)))
+ if (use_mb(system_charset_info) &&
+ (l = my_ismbchar(system_charset_info, name, strend)))
{
while (l--)
*to++ = *name++;
@@ -3315,12 +4136,12 @@ static void remove_escape(char *name)
****************************************************************************/
-bool add_to_list(SQL_LIST &list,Item *item,bool asc)
+bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
{
ORDER *order;
Item **item_ptr;
DBUG_ENTER("add_to_list");
- if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
+ if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
DBUG_RETURN(1);
item_ptr = (Item**) (order+1);
*item_ptr=item;
@@ -3352,14 +4173,15 @@ bool add_to_list(SQL_LIST &list,Item *item,bool asc)
# Pointer to TABLE_LIST element added to the total table list
*/
-TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
- ulong table_options,
- thr_lock_type lock_type,
- List<String> *use_index,
- List<String> *ignore_index)
+TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
+ Table_ident *table,
+ LEX_STRING *alias,
+ ulong table_options,
+ thr_lock_type lock_type,
+ List<String> *use_index,
+ List<String> *ignore_index)
{
register TABLE_LIST *ptr;
- THD *thd=current_thd;
char *alias_str;
DBUG_ENTER("add_table_to_list");
@@ -3369,17 +4191,23 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
if (check_table_name(table->table.str,table->table.length) ||
table->db.str && check_db_name(table->db.str))
{
- net_printf(&thd->net,ER_WRONG_TABLE_NAME,table->table.str);
+ net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str);
DBUG_RETURN(0);
}
if (!alias) /* Alias is case sensitive */
+ {
+ if (table->sel)
+ {
+ net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
+ DBUG_RETURN(0);
+ }
if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
DBUG_RETURN(0);
-
+ }
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(0); /* purecov: inspected */
- if (table->db.str)
+ if (table->db.str)
{
ptr->db= table->db.str;
ptr->db_length= table->db.length;
@@ -3391,17 +4219,21 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
}
else
{
- ptr->db= (char*) "";
+ /* The following can't be "" as we may do 'casedn_str()' on it */
+ ptr->db= empty_c_string;
ptr->db_length= 0;
}
-
+
ptr->alias= alias_str;
- table_case_convert(table->table.str, table->table.length);
+ if (lower_case_table_names && table->table.length)
+ my_casedn_str(files_charset_info, table->table.str);
ptr->real_name=table->table.str;
ptr->real_name_length=table->table.length;
- ptr->lock_type= lock_type;
+ ptr->lock_type= lock_type;
ptr->updating= test(table_options & TL_OPTION_UPDATING);
ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
+ ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
+ ptr->derived= table->sel;
if (use_index)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
sizeof(*use_index));
@@ -3412,21 +4244,22 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
/* check that used name is unique */
if (lock_type != TL_IGNORE)
{
- for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ;
+ for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
tables ;
tables=tables->next)
{
if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db))
{
- net_printf(&thd->net,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
+ net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
DBUG_RETURN(0); /* purecov: tested */
}
}
}
- thd->lex.select->table_list.link_in_list((byte*) ptr,(byte**) &ptr->next);
+ table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
DBUG_RETURN(ptr);
}
+
/*
Set lock for all tables in current select level
@@ -3440,15 +4273,14 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
query
*/
-void set_lock_for_tables(thr_lock_type lock_type)
+void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
{
- THD *thd=current_thd;
bool for_update= lock_type >= TL_READ_NO_INSERT;
DBUG_ENTER("set_lock_for_tables");
DBUG_PRINT("enter", ("lock_type: %d for_update: %d", lock_type,
for_update));
- for (TABLE_LIST *tables= (TABLE_LIST*) thd->lex.select->table_list.first ;
+ for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
tables ;
tables=tables->next)
{
@@ -3459,67 +4291,6 @@ void set_lock_for_tables(thr_lock_type lock_type)
}
-/*
-** This is used for UNION to create a new table list of all used tables
-** The table_list->table entry in all used tables are set to point
-** to the entries in this list.
-*/
-
-static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result)
-{
- /* Handle the case when we are not using union */
- if (!lex->select_lex.next)
- {
- *result= (TABLE_LIST*) lex->select_lex.table_list.first;
- return 0;
- }
-
- SELECT_LEX *sl;
- TABLE_LIST **new_table_list= result, *aux;
-
- *new_table_list=0; // end result list
- for (sl= &lex->select_lex; sl; sl=sl->next)
- {
- if (sl->order_list.first && sl->next && !sl->braces)
- {
- net_printf(&thd->net,ER_WRONG_USAGE,"UNION","ORDER BY");
- return 1;
- }
- if ((aux= (TABLE_LIST*) sl->table_list.first))
- {
- TABLE_LIST *next;
- for (; aux; aux=next)
- {
- TABLE_LIST *cursor;
- next= aux->next;
- for (cursor= *result; cursor; cursor=cursor->next)
- if (!strcmp(cursor->db,aux->db) &&
- !strcmp(cursor->real_name,aux->real_name) &&
- !strcmp(cursor->alias, aux->alias))
- break;
- if (!cursor)
- {
- /* Add not used table to the total table list */
- if (!(cursor = (TABLE_LIST *) thd->memdup((char*) aux,
- sizeof(*aux))))
- {
- send_error(&thd->net,0);
- return 1;
- }
- *new_table_list= cursor;
- new_table_list= &cursor->next;
- *new_table_list=0; // end result list
- }
- else
- aux->shared=1; // Mark that it's used twice
- aux->table= my_reinterpret_cast(TABLE *) (cursor);
- }
- }
- }
- return 0;
-}
-
-
void add_join_on(TABLE_LIST *b,Item *expr)
{
if (expr)
@@ -3559,26 +4330,33 @@ void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
b->natural_join=a;
}
- /* Check if name is used in table list */
-static bool check_dup(const char *db, const char *name, TABLE_LIST *tables)
-{
- for (; tables ; tables=tables->next)
- if (!strcmp(name,tables->real_name) && !strcmp(db,tables->db))
- return 1;
- return 0;
-}
+/*
+ Reload/resets privileges and the different caches.
+ SYNOPSIS
+ reload_acl_and_cache()
+ thd Thread handler
+ options What should be reset/reloaded (tables, privileges,
+ slave...)
+ tables Tables to flush (if any)
+ write_to_binlog Depending on 'options', it may be very bad to write the
+ query to the binlog (e.g. FLUSH SLAVE); this is a
+ pointer where, if it is not NULL, reload_acl_and_cache()
+ will put 0 if it thinks we really should not write to
+ the binlog. Otherwise it will put 1.
-/*
- Reload/resets privileges and the different caches
+ RETURN
+ 0 ok
+ !=0 error
*/
-bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
+bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
+ bool *write_to_binlog)
{
bool result=0;
- bool error_already_sent=0;
select_errors=0; /* Write if more errors */
+ bool tmp_write_to_binlog= 1;
if (options & REFRESH_GRANT)
{
acl_reload(thd);
@@ -3592,14 +4370,28 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
Flush the normal query log, the update log, the binary log,
the slow query log, and the relay log (if it exists).
*/
+
+ /*
+ Writing this command to the binlog may result in infinite loops when doing
+ mysqlbinlog|mysql, and anyway it does not really make sense to log it
+ automatically (would cause more trouble to users than it would help them)
+ */
+ tmp_write_to_binlog= 0;
mysql_log.new_file(1);
mysql_update_log.new_file(1);
mysql_bin_log.new_file(1);
mysql_slow_log.new_file(1);
+#ifdef HAVE_REPLICATION
+ if (expire_logs_days)
+ {
+ long purge_time= time(0) - expire_logs_days*24*60*60;
+ if (purge_time >= 0)
+ mysql_bin_log.purge_logs_before_date(purge_time);
+ }
LOCK_ACTIVE_MI;
rotate_relay_log(active_mi);
UNLOCK_ACTIVE_MI;
-
+#endif
if (ha_flush_logs())
result=1;
if (flush_error_log())
@@ -3616,10 +4408,16 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
query_cache.flush(); // RESET QUERY CACHE
}
#endif /*HAVE_QUERY_CACHE*/
- if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
+ /*
+ Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
+ (see sql_yacc.yy)
+ */
+ if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
{
if ((options & REFRESH_READ_LOCK) && thd)
{
+ // writing to the binlog could cause deadlocks, as we don't log UNLOCK TABLES
+ tmp_write_to_binlog= 0;
if (lock_global_read_lock(thd))
return 1;
}
@@ -3631,9 +4429,14 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
refresh_status();
if (options & REFRESH_THREADS)
flush_thread_cache();
+#ifndef EMBEDDED_LIBRARY
if (options & REFRESH_MASTER)
+ {
+ tmp_write_to_binlog= 0;
if (reset_master(thd))
result=1;
+ }
+#endif
#ifdef OPENSSL
if (options & REFRESH_DES_KEY_FILE)
{
@@ -3641,33 +4444,20 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
result=load_des_key_file(des_key_file);
}
#endif
+#ifndef EMBEDDED_LIBRARY
if (options & REFRESH_SLAVE)
{
+ tmp_write_to_binlog= 0;
LOCK_ACTIVE_MI;
if (reset_slave(thd, active_mi))
- {
result=1;
- /*
- reset_slave() sends error itself.
- If it didn't, one would either change reset_slave()'s prototype, to
- pass *errorcode and *errmsg to it when it's called or
- change reset_slave to use my_error() to register the error.
- */
- error_already_sent=1;
- }
UNLOCK_ACTIVE_MI;
}
+#endif
if (options & REFRESH_USER_RESOURCES)
reset_mqh(thd,(LEX_USER *) NULL);
-
- if (thd && !error_already_sent)
- {
- if (result)
- send_error(&thd->net,0);
- else
- send_ok(&thd->net);
- }
-
+ if (write_to_binlog)
+ *write_to_binlog= tmp_write_to_binlog;
return result;
}
@@ -3713,9 +4503,9 @@ void kill_one_thread(THD *thd, ulong id)
}
if (!error)
- send_ok(&thd->net);
+ send_ok(thd);
else
- net_printf(&thd->net,error,id);
+ net_printf(thd,error,id);
}
/* Clear most status variables */
@@ -3759,6 +4549,7 @@ static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
return 0;
}
+
/*
Check if the select is a simple select (not an union)
@@ -3773,13 +4564,43 @@ static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
bool check_simple_select()
{
THD *thd= current_thd;
- if (thd->lex.select != &thd->lex.select_lex)
+ if (thd->lex.current_select != &thd->lex.select_lex)
{
char command[80];
strmake(command, thd->lex.yylval->symbol.str,
min(thd->lex.yylval->symbol.length, sizeof(command)-1));
- net_printf(&thd->net, ER_CANT_USE_OPTION_HERE, command);
+ net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
return 1;
}
return 0;
}
+
+compare_func_creator comp_eq_creator(bool invert)
+{
+ return invert?&Item_bool_func2::ne_creator:&Item_bool_func2::eq_creator;
+}
+
+compare_func_creator comp_ge_creator(bool invert)
+{
+ return invert?&Item_bool_func2::lt_creator:&Item_bool_func2::ge_creator;
+}
+
+compare_func_creator comp_gt_creator(bool invert)
+{
+ return invert?&Item_bool_func2::le_creator:&Item_bool_func2::gt_creator;
+}
+
+compare_func_creator comp_le_creator(bool invert)
+{
+ return invert?&Item_bool_func2::gt_creator:&Item_bool_func2::le_creator;
+}
+
+compare_func_creator comp_lt_creator(bool invert)
+{
+ return invert?&Item_bool_func2::ge_creator:&Item_bool_func2::lt_creator;
+}
+
+compare_func_creator comp_ne_creator(bool invert)
+{
+ return invert?&Item_bool_func2::eq_creator:&Item_bool_func2::ne_creator;
+}