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.cc1679
1 files changed, 1081 insertions, 598 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index fa4a4fd4f3b..e649f109a0d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,16 +14,38 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#ifdef EMBEDDED_LIBRARY
+#define net_read_timeout net_read_timeout1
+#define net_write_timeout net_write_timeout1
+#endif
#include "mysql_priv.h"
#include "sql_acl.h"
#include "sql_repl.h"
+#include "repl_failsafe.h"
#include <m_ctype.h>
#include <thr_alarm.h>
#include <myisam.h>
#include <my_dir.h>
#include <assert.h>
+#ifdef HAVE_OPENSSL
+/*
+ Without SSL the handshake consists of one packet. This packet
+ has both client capabilites and scrambled password.
+ With SSL the handshake might consist of two packets. If the first
+ packet (client capabilities) has CLIENT_SSL flag set, we have to
+ switch to SSL and read the second packet. The scrambled password
+ is in the second packet and client_capabilites field will be ignored.
+ Maybe it is better to accept flags other than CLIENT_SSL from the
+ second packet?
+*/
+#define SSL_HANDSHAKE_SIZE 2
+#define NORMAL_HANDSHAKE_SIZE 6
+#define MIN_HANDSHAKE_SIZE 2
+#else
+#define MIN_HANDSHAKE_SIZE 6
+#endif /* HAVE_OPENSSL */
#define SCRAMBLE_LENGTH 8
@@ -33,16 +55,18 @@ extern "C" pthread_mutex_t THR_LOCK_keycache;
extern "C" int gethostname(char *name, int namelen);
#endif
-static int check_for_max_user_connections(const char *user, int u_length,
- const char *host);
-static void decrease_user_connections(const char *user, const char *host);
+static int check_for_max_user_connections(UC *uc);
+static bool check_mqh(THD *thd);
+static void decrease_user_connections(UC *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(THD *thd,const char *db,const char *name,
- 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);
const char *any_db="*any*"; // Special symbol for check_access
@@ -50,13 +74,13 @@ const char *command_name[]={
"Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
"Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
- "Binlog Dump","Table Dump", "Connect Out"
+ "Binlog Dump","Table Dump", "Connect Out", "Register Slave"
};
bool volatile abort_slave = 0;
#ifdef HAVE_OPENSSL
-extern VioSSLAcceptorFd* ssl_acceptor_fd;
+extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd;
#endif /* HAVE_OPENSSL */
#ifdef __WIN__
@@ -66,8 +90,8 @@ static void test_signal(int sig_ptr)
MessageBox(NULL,"Test signal","DBUG",MB_OK);
#endif
#if defined(OS2)
- fprintf( stderr, "Test signal %d\n", sig_ptr);
- fflush( stderr);
+ fprintf(stderr, "Test signal %d\n", sig_ptr);
+ fflush(stderr);
#endif
}
static void init_signals(void)
@@ -93,43 +117,98 @@ inline bool end_active_trans(THD *thd)
}
+static HASH hash_user_connections;
+extern pthread_mutex_t LOCK_user_conn;
+
+static int get_or_create_user_conn(THD *thd, const char *user,
+ const char *host,
+ uint max_questions)
+{
+ int return_val=0;
+ uint temp_len;
+ char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
+ struct user_conn *uc;
+
+ DBUG_ASSERT(user != 0);
+ DBUG_ASSERT(host != 0);
+
+ temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user)-1, user, "@", host,
+ NullS) - temp_user);
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ if (!(uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (byte*) temp_user, temp_len)))
+ {
+ /* First connection for user; Create a user connection object */
+ if (!(uc= ((struct user_conn*)
+ my_malloc(sizeof(struct user_conn) + temp_len+1,
+ MYF(MY_WME)))))
+ {
+ send_error(&current_thd->net, 0, NullS); // Out of memory
+ return_val=1;
+ goto end;
+ }
+ uc->user=(char*) (uc+1);
+ memcpy(uc->user,temp_user,temp_len+1);
+ uc->len = temp_len;
+ uc->connections = 1;
+ uc->questions=0;
+ uc->max_questions=max_questions;
+ 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
+ return_val=1;
+ goto end;
+ }
+ }
+ thd->user_connect=uc;
+end:
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ return return_val;
+
+}
+
+
/*
-** Check if user is ok
-** Updates:
-** thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access
+ Check if user is ok
+ Updates:
+ thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access
*/
static bool check_user(THD *thd,enum_server_command command, const char *user,
const char *passwd, const char *db, bool check_count)
{
NET *net= &thd->net;
+ uint max_questions=0;
thd->db=0;
+ thd->db_length=0;
if (!(thd->user = my_strdup(user, MYF(0))))
{
send_error(net,ER_OUT_OF_RESOURCES);
return 1;
}
- thd->master_access=acl_getroot(thd->host, thd->ip, thd->user,
+ thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
passwd, thd->scramble, &thd->priv_user,
protocol_version == 9 ||
!(thd->client_capabilities &
- CLIENT_LONG_PASSWORD));
- DBUG_PRINT("general",
+ CLIENT_LONG_PASSWORD),&max_questions);
+ DBUG_PRINT("info",
("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
thd->client_capabilities, thd->max_packet_length,
- thd->host ? thd->host : thd->ip, thd->priv_user,
+ thd->host_or_ip, thd->priv_user,
passwd[0] ? "yes": "no",
thd->master_access, thd->db ? thd->db : "*none*"));
if (thd->master_access & NO_ACCESS)
{
net_printf(net, ER_ACCESS_DENIED_ERROR,
thd->user,
- thd->host ? thd->host : thd->ip,
+ 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 ? thd->host : thd->ip ? thd->ip : "unknown ip",
+ thd->host_or_ip,
passwd[0] ? ER(ER_YES) : ER(ER_NO));
return(1); // Error already given
}
@@ -150,17 +229,20 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
(char*) "%s@%s on %s" :
(char*) "%s@%s as anonymous on %s"),
user,
- thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
+ thd->host_or_ip,
db ? db : (char*) "");
thd->db_access=0;
- if (max_user_connections &&
- check_for_max_user_connections(user, strlen(user), thd->host))
+ /* Don't allow user to connect if he has done too many queries */
+ if ((max_questions || max_user_connections) && get_or_create_user_conn(thd,user,thd->host_or_ip,max_questions))
+ return -1;
+ if (max_user_connections && thd->user_connect &&
+ check_for_max_user_connections(thd->user_connect))
return -1;
if (db && db[0])
{
bool error=test(mysql_change_db(thd,db));
- if (error)
- decrease_user_connections(thd->user,thd->host);
+ if (error && thd->user_connect)
+ decrease_user_connections(thd->user_connect);
return error;
}
else
@@ -169,19 +251,10 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
}
/*
-** check for maximum allowable user connections
-** if mysql server is started with corresponding
-** variable that is greater then 0
+ Check for maximum allowable user connections, if the mysqld server is
+ started with corresponding variable that is greater then 0.
*/
-static HASH hash_user_connections;
-extern pthread_mutex_t LOCK_user_conn;
-
-struct user_conn {
- char *user;
- uint len, connections;
-};
-
static byte* get_key_conn(user_conn *buff, uint *length,
my_bool not_used __attribute__((unused)))
{
@@ -189,8 +262,6 @@ static byte* get_key_conn(user_conn *buff, uint *length,
return (byte*) buff->user;
}
-#define DEF_USER_COUNT 50
-
static void free_user(struct user_conn *uc)
{
my_free((char*) uc,MYF(0));
@@ -198,100 +269,44 @@ static void free_user(struct user_conn *uc)
void init_max_user_conn(void)
{
- (void) hash_init(&hash_user_connections,DEF_USER_COUNT,0,0,
+ (void) hash_init(&hash_user_connections,max_connections,0,0,
(hash_get_key) get_key_conn, (void (*)(void*)) free_user,
0);
}
-static int check_for_max_user_connections(const char *user, int u_length,
- const char *host)
+static int check_for_max_user_connections(UC *uc)
{
- int error=1;
- uint temp_len;
- char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
- struct user_conn *uc;
- if (!user)
- user="";
- if (!host)
- host="";
+ int error=0;
DBUG_ENTER("check_for_max_user_connections");
- DBUG_PRINT("enter",("user: '%s' host: '%s'", user, host));
-
- temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
- NullS) - temp_user);
- (void) pthread_mutex_lock(&LOCK_user_conn);
- uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len);
- if (uc) /* user found ; check for no. of connections */
- {
- if (max_user_connections == (uint) uc->connections)
- {
- net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, temp_user);
- goto end;
- }
- uc->connections++;
- }
- else
+
+ if (max_user_connections <= (uint) uc->connections)
{
- /* the user is not found in the cache; Insert it */
- struct user_conn *uc= ((struct user_conn*)
- my_malloc(sizeof(struct user_conn) + temp_len+1,
- MYF(MY_WME)));
- if (!uc)
- {
- send_error(&current_thd->net, 0, NullS); // Out of memory
- goto end;
- }
- uc->user=(char*) (uc+1);
- memcpy(uc->user,temp_user,temp_len+1);
- uc->len = temp_len;
- uc->connections = 1;
- if (hash_insert(&hash_user_connections, (byte*) uc))
- {
- my_free((char*) uc,0);
- send_error(&current_thd->net, 0, NullS); // Out of memory
- goto end;
- }
+ net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, uc->user);
+ error=1;
+ goto end;
}
- error=0;
+ uc->connections++;
end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
DBUG_RETURN(error);
}
-static void decrease_user_connections(const char *user, const char *host)
+static void decrease_user_connections(UC *uc)
{
- char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
- int temp_len;
- struct user_conn *uc;
if (!max_user_connections)
return;
- if (!user)
- user="";
- if (!host)
- host="";
- DBUG_ENTER("decrease_user_connections");
- DBUG_PRINT("enter",("user: '%s' host: '%s'", user, host));
- temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
- NullS) - temp_user);
- (void) pthread_mutex_lock(&LOCK_user_conn);
+ DBUG_ENTER("decrease_user_connections");
- uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len);
- dbug_assert(uc != 0); // We should always find the user
- if (!uc)
- goto end; // Safety; Something went wrong
- if (! --uc->connections)
+ if (!--uc->connections && !mqh_used)
{
/* Last connection for user; Delete it */
+ (void) pthread_mutex_lock(&LOCK_user_conn);
(void) hash_delete(&hash_user_connections,(byte*) uc);
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
}
-end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
DBUG_VOID_RETURN;
}
@@ -303,22 +318,93 @@ void free_max_user_conn(void)
/*
-** check connnetion and get priviliges
-** returns 0 on ok, -1 < if error is given > 0 on error.
+ Check if maximum queries per hour limit has been reached
+ returns 0 if OK.
+
+ In theory we would need a mutex in the UC structure for this to be 100 %
+ safe, but as the worst scenario is that we would miss counting a couple of
+ queries, this isn't critical.
*/
+static bool check_mqh(THD *thd)
+{
+ bool error=0;
+ DBUG_ENTER("check_mqh");
+ UC *uc=thd->user_connect;
+ DBUG_ASSERT(uc != 0);
+
+ bool my_start = thd->start_time != 0;
+ time_t check_time = (my_start) ? thd->start_time : time(NULL);
+ if (check_time - uc->intime >= 3600)
+ {
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ uc->questions=1;
+ uc->intime=check_time;
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ }
+ else if (uc->max_questions && ++(uc->questions) > uc->max_questions)
+ {
+ net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
+ (long) uc->max_questions);
+ error=1;
+ goto end;
+ }
+
+end:
+ DBUG_RETURN(error);
+}
+
+
+static void reset_mqh(THD *thd, LEX_USER *lu, uint mq)
+{
+
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ if (lu) // for GRANT
+ {
+ UC *uc;
+ uint temp_len=lu->user.length+lu->host.length+2;
+ char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
+
+ memcpy(temp_user,lu->user.str,lu->user.length);
+ memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
+ temp_user[lu->user.length]=temp_user[temp_len-1]=0;
+ if ((uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (byte*) temp_user, temp_len)))
+ {
+ uc->questions=0;
+ uc->max_questions=mq;
+ }
+ }
+ else // for FLUSH PRIVILEGES
+ {
+ for (uint idx=0;idx < hash_user_connections.records; idx++)
+ {
+ char user[USERNAME_LENGTH+1];
+ char *where;
+ UC *uc=(struct user_conn *) hash_element(&hash_user_connections, idx);
+ where=strchr(uc->user,'@');
+ strmake(user,uc->user,where - uc->user);
+ uc->max_questions=get_mqh(user,where+1);
+ }
+ }
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+}
+
+
+/*
+ Check connnetion and get priviliges
+ Returns 0 on ok, -1 < if error is given > 0 on error.
+*/
static int
check_connections(THD *thd)
{
uint connect_errors=0;
NET *net= &thd->net;
- /*
- ** store the connection details
- */
+ /* Store the connection details */
DBUG_PRINT("info", (("check_connections called by thread %d"),
thd->thread_id));
- DBUG_PRINT("general",("New connection received on %s",
+ DBUG_PRINT("info",("New connection received on %s",
vio_description(net->vio)));
if (!thd->host) // If TCP/IP connection
{
@@ -328,6 +414,7 @@ check_connections(THD *thd)
return (ER_BAD_HOST_ERROR);
if (!(thd->ip = my_strdup(ip,MYF(0))))
return (ER_OUT_OF_RESOURCES);
+ thd->host_or_ip=thd->ip;
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
/* Fast local hostname resolve for Win32 */
if (!strcmp(thd->ip,"127.0.0.1"))
@@ -341,65 +428,50 @@ check_connections(THD *thd)
if (connect_errors > max_connect_errors)
return(ER_HOST_IS_BLOCKED);
}
- DBUG_PRINT("general",("Host: %s ip: %s",
- thd->host ? thd->host : "unknown host",
- thd->ip ? thd->ip : "unknown ip"));
+ DBUG_PRINT("info",("Host: %s ip: %s",
+ thd->host ? thd->host : "unknown host",
+ thd->ip ? thd->ip : "unknown ip"));
if (acl_check_host(thd->host,thd->ip))
return(ER_HOST_NOT_PRIVILEGED);
}
else /* Hostname given means that the connection was on a socket */
{
- DBUG_PRINT("general",("Host: %s",thd->host));
+ DBUG_PRINT("info",("Host: %s",thd->host));
+ thd->host_or_ip=thd->host;
thd->ip=0;
bzero((char*) &thd->remote,sizeof(struct sockaddr));
}
vio_keepalive(net->vio, TRUE);
- /* nasty, but any other way? */
- uint pkt_len = 0;
+ 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;
+
if (opt_using_transactions)
client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
+#ifdef HAVE_OPENSSL
+ if (ssl_acceptor_fd)
+ client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */
+#endif /* HAVE_OPENSSL */
- end=strmov(buff,server_version)+1;
+ end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1;
int4store((uchar*) end,thd->thread_id);
end+=4;
memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
end+=SCRAMBLE_LENGTH +1;
-#ifdef HAVE_OPENSSL
- if (ssl_acceptor_fd)
- client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */
- /*
- * Without SSL the handshake consists of one packet. This packet
- * has both client capabilites and scrambled password.
- * With SSL the handshake might consist of two packets. If the first
- * packet (client capabilities) has CLIENT_SSL flag set, we have to
- * switch to SSL and read the second packet. The scrambled password
- * is in the second packet and client_capabilites field will be ignored.
- * Maybe it is better to accept flags other than CLIENT_SSL from the
- * second packet?
- */
-#define SSL_HANDSHAKE_SIZE 2
-#define NORMAL_HANDSHAKE_SIZE 6
-#define MIN_HANDSHAKE_SIZE 2
-
-#else
-#define MIN_HANDSHAKE_SIZE 6
-#endif /* HAVE_OPENSSL */
int2store(end,client_flags);
- end[2]=MY_CHARSET_CURRENT;
+ end[2]=(char) MY_CHARSET_CURRENT;
int2store(end+3,thd->server_status);
bzero(end+5,13);
end+=18;
- if (net_write_command(net,protocol_version, buff,
+ if (net_write_command(net,(uchar) protocol_version, 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);
@@ -418,23 +490,18 @@ check_connections(THD *thd)
if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
thd->sql_mode|= MODE_IGNORE_SPACE;
#ifdef HAVE_OPENSSL
- DBUG_PRINT("info",
- ("pkt_len:%d, client capabilities: %d",
- pkt_len, thd->client_capabilities) );
+ DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
if (thd->client_capabilities & CLIENT_SSL)
{
- DBUG_PRINT("info", ("Agreed to change IO layer to SSL") );
/* Do the SSL layering. */
DBUG_PRINT("info", ("IO layer change in progress..."));
- VioSocket* vio_socket = my_reinterpret_cast(VioSocket*)(net->vio);
- VioSSL* vio_ssl = ssl_acceptor_fd->accept(vio_socket);
- net->vio = my_reinterpret_cast(NetVio*) (vio_ssl);
+ sslaccept(ssl_acceptor_fd, net->vio, thd->inactive_timeout);
DBUG_PRINT("info", ("Reading user information over SSL layer"));
if ((pkt_len=my_net_read(net)) == packet_error ||
pkt_len < NORMAL_HANDSHAKE_SIZE)
{
- DBUG_PRINT("info", ("pkt_len:%d", pkt_len));
- DBUG_PRINT("error", ("Failed to read user information"));
+ DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
+ pkt_len));
inc_host_errors(&thd->remote.sin_addr);
return(ER_HANDSHAKE_ERROR);
}
@@ -463,7 +530,7 @@ check_connections(THD *thd)
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
opt_using_transactions)
thd->net.return_status= &thd->server_status;
- net->timeout=net_read_timeout;
+ net->timeout=(uint) net_read_timeout;
if (check_user(thd,COM_CONNECT, user, passwd, db, 1))
return (-1);
thd->password=test(passwd[0]);
@@ -481,9 +548,9 @@ pthread_handler_decl(handle_one_connection,arg)
pthread_detach_this_thread();
-#if !defined( __WIN__) && !defined(OS2) /* Win32 calls this in pthread_create */
- if (my_thread_init()) // needed to be called first before we call
- // DBUG_ macros
+#if !defined( __WIN__) && !defined(OS2) // Win32 calls this in pthread_create
+ // The following calls needs to be done before we call DBUG_ macros
+ if (my_thread_init())
{
close_connection(&thd->net,ER_OUT_OF_RESOURCES);
statistic_increment(aborted_connects,&LOCK_thread_count);
@@ -492,13 +559,13 @@ pthread_handler_decl(handle_one_connection,arg)
}
#endif
- // handle_one_connection() is the only way a thread would start
- // and would always be on top of the stack
- // therefore, the thread stack always starts at the address of the first
- // local variable of handle_one_connection, which is thd
- // we need to know the start of the stack so that we could check for
- // stack overruns
-
+ /*
+ handle_one_connection() is the only way a thread would start
+ and would always be on top of the stack, therefore, the thread
+ stack always starts at the address of the first local variable
+ of handle_one_connection, which is thd. We need to know the
+ start of the stack so that we could check for stack overruns.
+ */
DBUG_PRINT("info", ("handle_one_connection called by thread %d\n",
thd->thread_id));
// now that we've called my_thread_init(), it is safe to call DBUG_*
@@ -530,7 +597,7 @@ pthread_handler_decl(handle_one_connection,arg)
if ((error=check_connections(thd)))
{ // Wrong permissions
if (error > 0)
- net_printf(net,error,thd->host ? thd->host : thd->ip);
+ net_printf(net,error,thd->host_or_ip);
#ifdef __NT__
if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
sleep(1); /* must wait after eof() */
@@ -554,21 +621,22 @@ pthread_handler_decl(handle_one_connection,arg)
if (do_command(thd))
break;
}
+ if (thd->user_connect)
+ decrease_user_connections(thd->user_connect);
free_root(&thd->mem_root,MYF(0));
if (net->error && net->vio != 0)
{
if (!thd->killed && opt_warnings)
- sql_print_error(ER(ER_NEW_ABORTING_CONNECTION),
- thd->thread_id,(thd->db ? thd->db : "unconnected"),
- thd->user ? thd->user : "unauthenticated",
- (thd->host ? thd->host : thd->ip ? thd->ip : "unknown"),
- (net->last_errno ? ER(net->last_errno) :
- ER(ER_UNKNOWN_ERROR)));
+ sql_print_error(ER(ER_NEW_ABORTING_CONNECTION),
+ thd->thread_id,(thd->db ? thd->db : "unconnected"),
+ thd->user ? thd->user : "unauthenticated",
+ thd->host_or_ip,
+ (net->last_errno ? ER(net->last_errno) :
+ ER(ER_UNKNOWN_ERROR)));
send_error(net,net->last_errno,NullS);
thread_safe_increment(aborted_threads,&LOCK_thread_count);
}
-
- decrease_user_connections(thd->user,thd->host);
+
end_thread:
close_connection(net);
end_thread(thd,1);
@@ -628,8 +696,17 @@ pthread_handler_decl(handle_bootstrap,arg)
length--;
buff[length]=0;
thd->current_tablenr=0;
- thd->query= thd->memdup(buff,length+1);
+ thd->query_length=length;
+ thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
+ thd->query[length] = '\0';
thd->query_id=query_id++;
+ if (thd->user_connect && check_mqh(thd))
+ {
+ thd->net.error = 0;
+ close_thread_tables(thd); // Free tables
+ free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ break;
+ }
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
if (thd->fatal_error)
@@ -664,7 +741,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
int error = 0;
DBUG_ENTER("mysql_table_dump");
db = (db && db[0]) ? db : thd->db;
- if (!(table_list = (TABLE_LIST*) sql_calloc(sizeof(TABLE_LIST))))
+ if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(1); // out of memory
table_list->db = db;
table_list->real_name = table_list->name = tbl_name;
@@ -686,21 +763,19 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
goto err;
thd->free_list = 0;
+ thd->query_length=(uint) strlen(tbl_name);
thd->query = tbl_name;
- if((error = mysqld_dump_create_info(thd, table, -1)))
- {
- my_error(ER_GET_ERRNO, MYF(0));
- goto err;
- }
+ if ((error = mysqld_dump_create_info(thd, table, -1)))
+ {
+ my_error(ER_GET_ERRNO, MYF(0));
+ goto err;
+ }
net_flush(&thd->net);
- error = table->file->dump(thd,fd);
- if(error)
- my_error(ER_GET_ERRNO, MYF(0));
+ if ((error = table->file->dump(thd,fd)))
+ my_error(ER_GET_ERRNO, MYF(0));
err:
-
close_thread_tables(thd);
-
DBUG_RETURN(error);
}
@@ -710,13 +785,10 @@ err:
bool do_command(THD *thd)
{
char *packet;
- uint old_timeout,packet_length;
- bool error=0;
+ uint old_timeout;
+ ulong packet_length;
NET *net;
enum enum_server_command command;
- // 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
- bool slow_command=FALSE;
DBUG_ENTER("do_command");
net= &thd->net;
@@ -724,26 +796,42 @@ bool do_command(THD *thd)
packet=0;
old_timeout=net->timeout;
- net->timeout=thd->inactive_timeout; /* Wait max for 8 hours */
+ net->timeout=(uint) thd->inactive_timeout; // Wait max for 8 hours
net->last_error[0]=0; // Clear error message
net->last_errno=0;
net_new_transaction(net);
if ((packet_length=my_net_read(net)) == packet_error)
{
- DBUG_PRINT("general",("Got error reading command from socket %s",
- vio_description(net->vio) ));
+ DBUG_PRINT("info",("Got error reading command from socket %s",
+ vio_description(net->vio) ));
return TRUE;
}
else
{
packet=(char*) net->read_pos;
command = (enum enum_server_command) (uchar) packet[0];
- DBUG_PRINT("general",("Command on %s = %d (%s)",
- vio_description(net->vio), command,
- command_name[command]));
+ DBUG_PRINT("info",("Command on %s = %d (%s)",
+ vio_description(net->vio), command,
+ command_name[command]));
}
- net->timeout=old_timeout; /* Timeout */
+ net->timeout=old_timeout; // Timeout for writing
+ DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
+}
+
+
+bool dispatch_command(enum enum_server_command command, THD *thd,
+ char* packet, uint packet_length)
+{
+ NET *net= &thd->net;
+ 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
+ */
+ bool slow_command=FALSE;
+ DBUG_ENTER("dispatch_command");
+
thd->command=command;
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id=query_id;
@@ -752,27 +840,34 @@ bool do_command(THD *thd)
thread_running++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->set_time();
- thd->lex.options=0; // We store status here
- switch(command) {
+ thd->lex.select_lex.options=0; // We store status here
+ switch (command) {
case COM_INIT_DB:
thread_safe_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_thread_count);
- if (!mysql_change_db(thd,packet+1))
+ if (!mysql_change_db(thd,packet))
mysql_log.write(thd,command,"%s",thd->db);
break;
+ case COM_REGISTER_SLAVE:
+ {
+ if (register_slave(thd, (uchar*)packet, packet_length))
+ send_error(&thd->net);
+ else
+ send_ok(&thd->net);
+ break;
+ }
case COM_TABLE_DUMP:
{
thread_safe_increment(com_other,&LOCK_thread_count);
slow_command = TRUE;
- char* data = packet + 1;
- uint db_len = *data;
- uint tbl_len = *(data + db_len + 1);
- char* db = sql_alloc(db_len + tbl_len + 2);
- memcpy(db, data + 1, db_len);
+ 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, data + db_len + 2, tbl_len);
+ memcpy(tbl_name, packet + db_len + 2, tbl_len);
tbl_name[tbl_len] = 0;
- if(mysql_table_dump(thd, db, tbl_name, -1))
+ if (mysql_table_dump(thd, db, tbl_name, -1))
send_error(&thd->net); // dump to NET
break;
@@ -780,16 +875,18 @@ bool do_command(THD *thd)
case COM_CHANGE_USER:
{
thread_safe_increment(com_other,&LOCK_thread_count);
- char *user= (char*) packet+1;
+ char *user= (char*) packet;
char *passwd= strend(user)+1;
char *db= strend(passwd)+1;
/* Save user and privileges */
uint save_master_access=thd->master_access;
uint save_db_access= thd->db_access;
+ uint save_db_length= thd->db_length;
char *save_user= thd->user;
char *save_priv_user= thd->priv_user;
char *save_db= thd->db;
+ UC *save_uc= thd->user_connect;
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
{ // Check if protocol is ok
@@ -803,11 +900,13 @@ bool do_command(THD *thd)
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;
}
- decrease_user_connections (save_user, thd->host);
+ if (max_connections && save_uc)
+ decrease_user_connections(save_uc);
x_free((gptr) save_db);
x_free((gptr) save_user);
thd->password=test(passwd[0]);
@@ -816,28 +915,44 @@ bool do_command(THD *thd)
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
- /* Remove garage at end of query */
- while (packet_length > 0 && pos[-1] == ';')
+ while (packet_length > 0 && (pos[-1] == ';' || isspace(pos[-1])))
{
pos--;
packet_length--;
}
- *pos=0;
- if (!(thd->query= (char*) thd->memdup((gptr) (packet+1),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)))
break;
+ thd->query[packet_length]=0;
thd->packet.shrink(net_buffer_length); // Reclaim some memory
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
mysql_log.write(thd,command,"%s",thd->query);
DBUG_PRINT("query",("%s",thd->query));
- mysql_parse(thd,thd->query,packet_length-1);
+ if (thd->user_connect && check_mqh(thd))
+ {
+ error = TRUE; // Abort client
+ net->error = 0; // Don't give abort message
+ break;
+ }
+ /* thd->query_length is set by mysql_parse() */
+ mysql_parse(thd,thd->query,packet_length);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
DBUG_PRINT("info",("query ready"));
break;
}
- case COM_FIELD_LIST: // This isn't actually neaded
+ case COM_FIELD_LIST: // This isn't actually needed
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
break;
@@ -853,8 +968,11 @@ bool do_command(THD *thd)
break;
}
thd->free_list=0;
- table_list.name=table_list.real_name=thd->strdup(packet+1);
- thd->query=fields=thd->strdup(strend(packet+1)+1);
+ table_list.name=table_list.real_name=thd->strdup(packet);
+ packet=strend(packet)+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);
remove_escape(table_list.real_name); // This can't have wildcards
@@ -875,10 +993,10 @@ bool do_command(THD *thd)
error=TRUE; // End server
break;
- case COM_CREATE_DB:
+ case COM_CREATE_DB: // QQ: To be removed
{
- char *db=thd->strdup(packet+1);
thread_safe_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_thread_count);
+ char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !stripp_sp(db) || check_db_name(db))
{
@@ -887,44 +1005,49 @@ bool do_command(THD *thd)
}
if (check_access(thd,CREATE_ACL,db,0,1))
break;
- mysql_log.write(thd,command,packet+1);
- mysql_create_db(thd,db,0);
+ mysql_log.write(thd,command,packet);
+ mysql_create_db(thd,db,0,0);
break;
}
- case COM_DROP_DB:
+ case COM_DROP_DB: // QQ: To be removed
{
- char *db=thd->strdup(packet+1);
thread_safe_increment(com_stat[SQLCOM_DROP_DB],&LOCK_thread_count);
+ char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !stripp_sp(db) || check_db_name(db))
{
net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
break;
}
- if (check_access(thd,DROP_ACL,db,0,1) || end_active_trans(thd))
+ if (thd->locked_tables || thd->active_transaction())
+ {
+ send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
break;
+ }
mysql_log.write(thd,command,db);
- mysql_rm_db(thd,db,0);
+ mysql_rm_db(thd,db,0,0);
break;
}
case COM_BINLOG_DUMP:
{
thread_safe_increment(com_other,&LOCK_thread_count);
slow_command = TRUE;
- if(check_access(thd, FILE_ACL, any_db))
+ if (check_access(thd, FILE_ACL, any_db))
break;
mysql_log.write(thd,command, 0);
ulong pos;
ushort flags;
uint32 slave_server_id;
- pos = uint4korr(packet + 1);
- flags = uint2korr(packet + 5);
+ pos = uint4korr(packet);
+ flags = uint2korr(packet + 4);
pthread_mutex_lock(&LOCK_server_id);
- kill_zombie_dump_threads(slave_server_id = uint4korr(packet+7));
+ thd->server_id=0; /* avoid suicide */
+ kill_zombie_dump_threads(slave_server_id = uint4korr(packet+6));
thd->server_id = slave_server_id;
pthread_mutex_unlock(&LOCK_server_id);
- mysql_binlog_send(thd, thd->strdup(packet + 11), pos, flags);
+ mysql_binlog_send(thd, thd->strdup(packet + 10), pos, flags);
+ unregister_slave(thd,1,1);
// fake COM_QUIT -- if we get here, the thread needs to terminate
error = TRUE;
net->error = 0;
@@ -932,8 +1055,8 @@ bool do_command(THD *thd)
}
case COM_REFRESH:
{
- uint options=(uchar) packet[1];
thread_safe_increment(com_stat[SQLCOM_FLUSH],&LOCK_thread_count);
+ ulong options= (ulong) (uchar) packet[0];
if (check_access(thd,RELOAD_ACL,any_db))
break;
mysql_log.write(thd,command,NullS);
@@ -941,6 +1064,8 @@ bool do_command(THD *thd)
send_error(net,0);
else
send_eof(net);
+ if (mqh_used)
+ reset_mqh(thd,(LEX_USER *) NULL, 0);
break;
}
case COM_SHUTDOWN:
@@ -970,7 +1095,7 @@ bool do_command(THD *thd)
char buff[200];
ulong uptime = (ulong) (thd->start_time - start_time);
sprintf((char*) buff,
- "Uptime: %ld Threads: %d Questions: %lu Slow queries: %ld Opens: %ld Flush tables: %ld Open tables: %d Queries per second avg: %.3f",
+ "Uptime: %ld Threads: %d Questions: %lu Slow queries: %ld Opens: %ld Flush tables: %ld Open tables: %u Queries per second avg: %.3f",
uptime,
(int) thread_count,thd->query_id,long_query_count,
opened_tables,refresh_version, cached_tables(),
@@ -999,7 +1124,7 @@ bool do_command(THD *thd)
case COM_PROCESS_KILL:
{
thread_safe_increment(com_stat[SQLCOM_KILL],&LOCK_thread_count);
- ulong id=(ulong) uint4korr(packet+1);
+ ulong id=(ulong) uint4korr(packet);
kill_one_thread(thd,id);
break;
}
@@ -1037,7 +1162,7 @@ bool do_command(THD *thd)
thd->proc_info="logging slow query";
if ((ulong) (thd->start_time - thd->time_after_lock) > long_query_time ||
- ((thd->lex.options &
+ ((thd->lex.select_lex.options &
(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED)) &&
(specialflag & SPECIAL_LONG_LOG_FORMAT)))
{
@@ -1068,33 +1193,47 @@ mysql_execute_command(void)
int res=0;
THD *thd=current_thd;
LEX *lex= &thd->lex;
- TABLE_LIST *tables=(TABLE_LIST*) lex->table_list.first;
+ TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first;
+ SELECT_LEX *select_lex = lex->select;
DBUG_ENTER("mysql_execute_command");
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
- if(table_rules_on && tables && !tables_ok(thd,tables))
+ /*
+ 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
+ */
+ if (table_rules_on && tables && !tables_ok(thd,tables))
DBUG_VOID_RETURN;
- // 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()
+#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()
+ */
if (lex->sql_command == SQLCOM_SELECT)
{
lex->sql_command = SQLCOM_DO;
- lex->insert_list = &lex->item_list;
+ lex->insert_list = &select_lex->item_list;
}
+#endif
}
+ /*
+ 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
+ */
+ if ((lex->select_lex.next && create_total_list(thd,lex,&tables)) ||
+ (table_rules_on && tables && thd->slave_thread &&
+ !tables_ok(thd,tables)))
+ DBUG_VOID_RETURN;
+
thread_safe_increment(com_stat[lex->sql_command],&LOCK_thread_count);
switch (lex->sql_command) {
case SQLCOM_SELECT:
{
select_result *result;
- if (lex->options & SELECT_DESCRIBE)
+ if (select_lex->options & SELECT_DESCRIBE)
lex->exchange=0;
if (tables)
{
@@ -1112,10 +1251,12 @@ mysql_execute_command(void)
break; // Error message is given
}
- thd->offset_limit=lex->offset_limit;
- thd->select_limit=lex->select_limit+lex->offset_limit;
- if (thd->select_limit < lex->select_limit)
+ 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)
+ select_lex->options&= ~OPTION_FOUND_ROWS;
if (lex->exchange)
{
@@ -1140,8 +1281,8 @@ mysql_execute_command(void)
{
res= -1;
#ifdef DELETE_ITEMS
- delete lex->having;
- delete lex->where;
+ delete select_lex->having;
+ delete select_lex->where;
#endif
break;
}
@@ -1159,22 +1300,11 @@ mysql_execute_command(void)
if (!(res=open_and_lock_tables(thd,tables)))
{
- res=mysql_select(thd,tables,lex->item_list,
- lex->where,
- (ORDER*) lex->order_list.first,
- (ORDER*) lex->group_list.first,
- lex->having,
- (ORDER*) lex->proc_list.first,
- lex->options | thd->options,
- result);
- if (res)
- result->abort();
+ query_cache.store_query(thd, tables);
+ res=handle_select(thd, lex, result);
}
- delete result;
-#ifdef DELETE_ITEMS
- delete lex->having;
- delete lex->where;
-#endif
+ else
+ delete result;
break;
}
case SQLCOM_DO:
@@ -1186,54 +1316,86 @@ mysql_execute_command(void)
break;
case SQLCOM_PURGE:
- {
- if (check_process_priv(thd))
- goto error;
- res = purge_master_logs(thd, lex->to_log);
- break;
- }
+ {
+ if (check_process_priv(thd))
+ goto error;
+ res = purge_master_logs(thd, lex->to_log);
+ break;
+ }
+ case SQLCOM_SHOW_NEW_MASTER:
+ {
+ if (check_access(thd, FILE_ACL, any_db))
+ goto error;
+ res = show_new_master(thd);
+ break;
+ }
+ case SQLCOM_SHOW_SLAVE_HOSTS:
+ {
+ if (check_access(thd, FILE_ACL, any_db))
+ goto error;
+ res = show_slave_hosts(thd);
+ break;
+ }
+ case SQLCOM_SHOW_BINLOG_EVENTS:
+ {
+ if (check_access(thd, FILE_ACL, any_db))
+ goto error;
+ res = show_binlog_events(thd);
+ break;
+ }
case SQLCOM_BACKUP_TABLE:
- {
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL, tables) ||
- check_access(thd, FILE_ACL, any_db))
- goto error; /* purecov: inspected */
- res = mysql_backup_table(thd, tables);
+ {
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd,SELECT_ACL, tables) ||
+ check_access(thd, FILE_ACL, any_db))
+ goto error; /* purecov: inspected */
+ res = mysql_backup_table(thd, tables);
- break;
- }
+ break;
+ }
case SQLCOM_RESTORE_TABLE:
- {
- if (check_db_used(thd,tables) ||
- check_table_access(thd,INSERT_ACL, tables) ||
- check_access(thd, FILE_ACL, any_db))
- goto error; /* purecov: inspected */
- res = mysql_restore_table(thd, tables);
- break;
- }
+ {
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd,INSERT_ACL, tables) ||
+ check_access(thd, FILE_ACL, any_db))
+ goto error; /* purecov: inspected */
+ res = mysql_restore_table(thd, tables);
+ break;
+ }
case SQLCOM_CHANGE_MASTER:
- {
- if(check_access(thd, PROCESS_ACL, any_db))
- goto error;
- res = change_master(thd);
- break;
- }
+ {
+ if (check_access(thd, PROCESS_ACL, any_db))
+ goto error;
+ LOCK_ACTIVE_MI;
+ res = change_master(thd,active_mi);
+ UNLOCK_ACTIVE_MI;
+ break;
+ }
case SQLCOM_SHOW_SLAVE_STAT:
- {
- if (check_process_priv(thd))
- goto error;
- res = show_master_info(thd);
- break;
- }
+ {
+ if (check_process_priv(thd))
+ goto error;
+ LOCK_ACTIVE_MI;
+ res = show_master_info(thd,active_mi);
+ UNLOCK_ACTIVE_MI;
+ break;
+ }
case SQLCOM_SHOW_MASTER_STAT:
- {
- if (check_process_priv(thd))
- goto error;
- res = show_binlog_info(thd);
- break;
- }
+ {
+ if (check_process_priv(thd))
+ goto error;
+ res = show_binlog_info(thd);
+ break;
+ }
+
+ case SQLCOM_LOAD_MASTER_DATA: // sync with master
+ if (check_process_priv(thd))
+ goto error;
+ res = load_master_data(thd);
+ break;
+
case SQLCOM_LOAD_MASTER_TABLE:
-
+ {
if (!tables->db)
tables->db=thd->db;
if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege))
@@ -1246,21 +1408,23 @@ mysql_execute_command(void)
bool error=check_grant(thd,CREATE_ACL,tables);
tables->next=tmp_table_list;
if (error)
- goto error;
+ goto error;
}
if (strlen(tables->name) > NAME_LEN)
{
net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->name);
break;
}
-
- thd->last_nx_table = tables->real_name;
- thd->last_nx_db = tables->db;
- if (fetch_nx_table(thd, &glob_mi))
- break; // fetch_nx_table did send the error to the client
- send_ok(&thd->net);
+ 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);
+ }
+ UNLOCK_ACTIVE_MI;
break;
-
+ }
case SQLCOM_CREATE_TABLE:
if (!tables->db)
tables->db=thd->db;
@@ -1285,12 +1449,25 @@ mysql_execute_command(void)
res=0;
break;
}
- if (lex->item_list.elements) // With select
+#ifndef HAVE_READLINK
+ lex->create_info.data_file_name=lex->create_info.index_file_name=0;
+#else
+ /* Fix names if symlinked tables */
+ if (append_file_to_dir(thd, &lex->create_info.data_file_name,
+ tables->name) ||
+ append_file_to_dir(thd,&lex->create_info.index_file_name,
+ tables->name))
+ {
+ res=-1;
+ break;
+ }
+#endif
+ if (select_lex->item_list.elements) // With select
{
select_result *result;
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
- check_dup(thd,tables->db,tables->real_name,tables->next))
+ check_dup(tables->db, tables->real_name, tables->next))
{
net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
@@ -1303,31 +1480,22 @@ mysql_execute_command(void)
for (table = tables->next ; table ; table=table->next)
table->lock_type= lex->lock_option;
}
- thd->offset_limit=lex->offset_limit;
- thd->select_limit=lex->select_limit+lex->offset_limit;
- if (thd->select_limit < lex->select_limit)
+ 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
+ /* Skip first table, which is the table we are creating */
+ lex->select_lex.table_list.first=
+ (byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
if (!(res=open_and_lock_tables(thd,tables->next)))
{
- if ((result=new select_create(tables->db ? tables->db : thd->db,
- tables->real_name, &lex->create_info,
- lex->create_list,
- lex->key_list,
- lex->item_list,lex->duplicates)))
- {
- res=mysql_select(thd,tables->next,lex->item_list,
- lex->where,
- (ORDER*) lex->order_list.first,
- (ORDER*) lex->group_list.first,
- lex->having,
- (ORDER*) lex->proc_list.first,
- lex->options | thd->options,
- result);
- if (res)
- result->abort();
- delete result;
- }
+ if ((result=new select_create(tables->db ? tables->db : thd->db,
+ tables->real_name, &lex->create_info,
+ lex->create_list,
+ lex->key_list,
+ select_lex->item_list,lex->duplicates)))
+ res=handle_select(thd, lex, result);
else
res= -1;
}
@@ -1356,12 +1524,19 @@ mysql_execute_command(void)
break;
case SQLCOM_SLAVE_START:
- start_slave(thd);
+ {
+ LOCK_ACTIVE_MI;
+ start_slave(thd,active_mi,1 /* net report*/);
+ UNLOCK_ACTIVE_MI;
break;
+ }
case SQLCOM_SLAVE_STOP:
- stop_slave(thd);
+ {
+ LOCK_ACTIVE_MI;
+ stop_slave(thd,active_mi,1/* net report*/);
+ UNLOCK_ACTIVE_MI;
break;
-
+ }
case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
@@ -1377,10 +1552,10 @@ mysql_execute_command(void)
}
if (!tables->db)
tables->db=thd->db;
- if (!lex->db)
- lex->db=tables->db;
+ if (!select_lex->db)
+ select_lex->db=tables->db;
if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege) ||
- check_access(thd,INSERT_ACL | CREATE_ACL,lex->db,&priv) ||
+ check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv) ||
check_merge_table_access(thd, tables->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
@@ -1396,22 +1571,27 @@ mysql_execute_command(void)
TABLE_LIST tmp_table;
bzero((char*) &tmp_table,sizeof(tmp_table));
tmp_table.real_name=lex->name;
- tmp_table.db=lex->db;
+ tmp_table.db=select_lex->db;
tmp_table.grant.privilege=priv;
if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables))
goto error;
}
}
+ /* Don't yet allow changing of symlinks with ALTER TABLE */
+ lex->create_info.data_file_name=lex->create_info.index_file_name=0;
/* ALTER TABLE ends previous transaction */
if (end_active_trans(thd))
res= -1;
else
- res= mysql_alter_table(thd, lex->db, lex->name,
+ {
+ res= mysql_alter_table(thd, select_lex->db, lex->name,
&lex->create_info,
tables, lex->create_list,
lex->key_list, lex->drop_list, lex->alter_list,
- (ORDER *) lex->order_list.first,
- lex->drop_primary, lex->duplicates);
+ (ORDER *) select_lex->order_list.first,
+ lex->drop_primary, lex->duplicates,
+ lex->alter_keys_onoff, lex->simple_alter);
+ }
break;
}
#endif
@@ -1435,11 +1615,12 @@ mysql_execute_command(void)
old_list.next=new_list.next=0;
if (check_grant(thd,ALTER_ACL,&old_list) ||
(!test_all_bits(table->next->grant.privilege,
- INSERT_ACL | CREATE_ACL) &&
+ INSERT_ACL | CREATE_ACL) &&
check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list)))
goto error;
}
}
+ query_cache.invalidate(tables);
if (end_active_trans(thd))
res= -1;
else if (mysql_rename_tables(thd,tables))
@@ -1473,21 +1654,23 @@ mysql_execute_command(void)
}
#endif
case SQLCOM_REPAIR:
- {
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
- goto error; /* purecov: inspected */
- res = mysql_repair_table(thd, tables, &lex->check_opt);
- break;
- }
+ {
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
+ goto error; /* purecov: inspected */
+ res = mysql_repair_table(thd, tables, &lex->check_opt);
+ query_cache.invalidate(tables);
+ break;
+ }
case SQLCOM_CHECK:
- {
- if (check_db_used(thd,tables) ||
- check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables))
- goto error; /* purecov: inspected */
- res = mysql_check_table(thd, tables, &lex->check_opt);
- break;
- }
+ {
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables))
+ goto error; /* purecov: inspected */
+ res = mysql_check_table(thd, tables, &lex->check_opt);
+ query_cache.invalidate(tables);
+ break;
+ }
case SQLCOM_ANALYZE:
{
if (check_db_used(thd,tables) ||
@@ -1529,23 +1712,73 @@ mysql_execute_command(void)
goto error;
if (grant_option && check_grant(thd,UPDATE_ACL,tables))
goto error;
- if (lex->item_list.elements != lex->value_list.elements)
+ if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(&thd->net,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
- res = mysql_update(thd,tables,
- lex->item_list,
- lex->value_list,
- lex->where,
- lex->select_limit,
- lex->duplicates,
- lex->lock_option);
+ 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,
+ lex->lock_option);
#ifdef DELETE_ITEMS
- delete lex->where;
+ delete select_lex->where;
#endif
- break;
+ }
+ else
+ {
+ multi_update *result;
+ uint table_count;
+ TABLE_LIST *auxi;
+ lex->sql_command=SQLCOM_MULTI_UPDATE;
+ for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
+ {
+ table_count++;
+ auxi->lock_type=TL_WRITE;
+ }
+ if (select_lex->order_list.elements || (select_lex->select_limit && select_lex->select_limit < INT_MAX))
+ {
+ send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /// will have to come up with something better eventually
+ DBUG_VOID_RETURN;
+ }
+ tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
+ if ((res=open_and_lock_tables(thd,tables)))
+ break;
+ if (!setup_fields(thd,tables,select_lex->item_list,1,0,0) &&
+ !setup_fields(thd,tables,lex->value_list,0,0,0) && ! thd->fatal_error &&
+ (result=new multi_update(thd,tables,select_lex->item_list,lex->duplicates,
+ lex->lock_option, table_count)))
+ {
+ List <Item> total_list;
+ List_iterator <Item> field_list(select_lex->item_list);
+ List_iterator <Item> value_list(lex->value_list);
+ Item *item;
+ while ((item=field_list++))
+ total_list.push_back(item);
+ while ((item=value_list++))
+ total_list.push_back(item);
+
+ res=mysql_select(thd,tables,total_list,
+ select_lex->where,
+ (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
+ (ORDER *)NULL,
+ select_lex->options | thd->options |
+ SELECT_NO_JOIN_CACHE,
+ result);
+ delete result;
+ }
+ else
+ res= -1; // Error is not sent
+ close_thread_tables(thd);
+ }
+ break;
case SQLCOM_INSERT:
if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege))
goto error; /* purecov: inspected */
@@ -1570,6 +1803,7 @@ mysql_execute_command(void)
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
+
// Check that we have modify privileges for the first table and
// select privileges for the rest
{
@@ -1587,51 +1821,50 @@ mysql_execute_command(void)
}
select_result *result;
- thd->offset_limit=lex->offset_limit;
- thd->select_limit=lex->select_limit+lex->offset_limit;
- if (thd->select_limit < lex->select_limit)
+ 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 (check_dup(thd,tables->db,tables->real_name,tables->next))
+ if (check_dup(tables->db, tables->real_name, tables->next))
{
net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
}
- tables->lock_type=TL_WRITE; // update first table
+ tables->lock_type=TL_WRITE; // update first table
{
TABLE_LIST *table;
for (table = tables->next ; table ; table=table->next)
table->lock_type= lex->lock_option;
}
- if (!(res=open_and_lock_tables(thd,tables)))
+
+ /* 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);
+ if (!(res=open_and_lock_tables(thd, tables)))
{
if ((result=new select_insert(tables->table,&lex->field_list,
- lex->sql_command == SQLCOM_REPLACE_SELECT ?
- DUP_REPLACE : DUP_IGNORE)))
- {
- res=mysql_select(thd,tables->next,lex->item_list,
- lex->where,
- (ORDER*) lex->order_list.first,
- (ORDER*) lex->group_list.first,
- lex->having,
- (ORDER*) lex->proc_list.first,
- lex->options | thd->options,
- result);
- delete result;
- }
- else
- res= -1;
+ lex->duplicates)))
+ res=handle_select(thd,lex,result);
}
-#ifdef DELETE_ITEMS
- delete lex->having;
- delete lex->where;
-#endif
+ else
+ res= -1;
break;
}
case SQLCOM_TRUNCATE:
- lex->where=0;
- lex->select_limit=HA_POS_ERROR;
- /* Fall through */
+ if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
+ goto error; /* purecov: inspected */
+ /*
+ Don't allow this within a transaction because we want to use
+ re-generate table
+ */
+ if (thd->locked_tables || thd->active_transaction())
+ {
+ send_error(&thd->net,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))
@@ -1644,20 +1877,87 @@ mysql_execute_command(void)
if (lex->sql_command == SQLCOM_TRUNCATE && end_active_trans(thd))
res= -1;
else
- res = mysql_delete(thd,tables,lex->where,lex->select_limit,
- lex->lock_option, lex->options);
+ res = mysql_delete(thd,tables, select_lex->where,
+ (ORDER*) select_lex->order_list.first,
+ select_lex->select_limit, lex->lock_option,
+ select_lex->options);
break;
}
- case SQLCOM_DROP_TABLE:
+ case SQLCOM_DELETE_MULTI:
+ {
+ TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first;
+ TABLE_LIST *auxi;
+ uint table_count=0;
+ multi_delete *result;
+
+ /* 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,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);
+ goto error;
+ }
+ for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
{
- if (check_table_access(thd,DROP_ACL,tables))
- goto error; /* purecov: inspected */
- if (end_active_trans(thd))
- res= -1;
- else
- res = mysql_rm_table(thd,tables,lex->drop_if_exists);
+ table_count++;
+ /* All tables in aux_tables must be found in FROM PART */
+ TABLE_LIST *walk;
+ for (walk=(TABLE_LIST*) tables ; walk ; walk=walk->next)
+ {
+ if (!strcmp(auxi->real_name,walk->real_name) &&
+ !strcmp(walk->db,auxi->db))
+ break;
+ }
+ if (!walk)
+ {
+ net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name);
+ goto error;
+ }
+ auxi->lock_type=walk->lock_type=TL_WRITE;
+ auxi->table= (TABLE *) walk; // Remember corresponding table
}
+ tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
+ if (add_item_to_list(new Item_null()))
+ {
+ res= -1;
+ break;
+ }
+ 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= ((TABLE_LIST*) auxi->table)->table;
+ if (!thd->fatal_error && (result=new multi_delete(thd,aux_tables,
+ lex->lock_option,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,
+ result);
+ delete result;
+ }
+ else
+ res= -1; // Error is not sent
+ close_thread_tables(thd);
break;
+ }
+ case SQLCOM_DROP_TABLE:
+ {
+ if (check_table_access(thd,DROP_ACL,tables))
+ goto error; /* purecov: inspected */
+ if (end_active_trans(thd))
+ res= -1;
+ else
+ res = mysql_rm_table(thd,tables,lex->drop_if_exists);
+ }
+ break;
case SQLCOM_DROP_INDEX:
if (!tables->db)
tables->db=thd->db;
@@ -1672,7 +1972,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->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
@@ -1708,13 +2008,12 @@ mysql_execute_command(void)
#endif
case SQLCOM_SHOW_TABLES:
/* FALL THROUGH */
- case SQLCOM_SHOW_OPEN_TABLES:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
- char *db=lex->db ? lex->db : thd->db;
+ char *db=select_lex->db ? select_lex->db : thd->db;
if (!db)
{
send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
@@ -1729,34 +2028,32 @@ mysql_execute_command(void)
if (check_access(thd,SELECT_ACL,db,&thd->col_access))
goto error; /* purecov: inspected */
/* grant is checked in mysqld_show_tables */
- if (lex->sql_command == SQLCOM_SHOW_OPEN_TABLES)
- res= mysqld_show_open_tables(thd,db,
- (lex->wild ? lex->wild->ptr() : NullS));
- else if (lex->options & SELECT_DESCRIBE)
+ if (select_lex->options & SELECT_DESCRIBE)
res= mysqld_extend_show_tables(thd,db,
- (lex->wild ? lex->wild->ptr() : NullS));
+ (lex->wild ? lex->wild->ptr() : NullS));
else
res= mysqld_show_tables(thd,db,
(lex->wild ? lex->wild->ptr() : NullS));
break;
}
#endif
+ case SQLCOM_SHOW_OPEN_TABLES:
+ res= mysqld_show_open_tables(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 */
DBUG_VOID_RETURN;
#else
{
- char *db=tables->db ? tables->db : thd->db;
- if (!db)
+ char *db=tables->db;
+ if (!*db)
{
send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
goto error; /* purecov: inspected */
}
remove_escape(db); // Fix escaped '_'
remove_escape(tables->name);
- if (!tables->db)
- tables->db=thd->db;
if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access))
goto error; /* purecov: inspected */
tables->grant.privilege=thd->col_access;
@@ -1774,7 +2071,7 @@ mysql_execute_command(void)
DBUG_VOID_RETURN;
#else
{
- char *db=tables->db ? tables->db : thd->db;
+ char *db=tables->db;
if (!db)
{
send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
@@ -1794,7 +2091,7 @@ mysql_execute_command(void)
}
#endif
case SQLCOM_CHANGE_DB:
- mysql_change_db(thd,lex->db);
+ mysql_change_db(thd,select_lex->db);
break;
case SQLCOM_LOAD:
{
@@ -1815,7 +2112,7 @@ mysql_execute_command(void)
goto error;
}
if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
- grant_option && check_grant(thd,privilege,tables))
+ grant_option && check_grant(thd,privilege,tables))
goto error;
}
res=mysql_load(thd, lex->exchange, tables, lex->field_list,
@@ -1824,22 +2121,17 @@ mysql_execute_command(void)
}
case SQLCOM_SET_OPTION:
{
- uint org_options=thd->options;
- thd->options=lex->options;
+ ulong org_options=thd->options;
+ thd->options=select_lex->options;
thd->update_lock_default= ((thd->options & OPTION_LOW_PRIORITY_UPDATES) ?
TL_WRITE_LOW_PRIORITY : TL_WRITE);
- thd->default_select_limit=lex->select_limit;
+ thd->default_select_limit=select_lex->select_limit;
thd->tx_isolation=lex->tx_isolation;
- if (thd->gemini_spin_retries != lex->gemini_spin_retries)
- {
- thd->gemini_spin_retries= lex->gemini_spin_retries;
- ha_set_spin_retries(thd->gemini_spin_retries);
- }
DBUG_PRINT("info",("options: %ld limit: %ld",
thd->options,(long) thd->default_select_limit));
/* Check if auto_commit mode changed */
- if ((org_options ^ lex->options) & OPTION_NOT_AUTO_COMMIT)
+ if ((org_options ^ select_lex->options) & OPTION_NOT_AUTO_COMMIT)
{
if ((org_options & OPTION_NOT_AUTO_COMMIT))
{
@@ -1873,13 +2165,7 @@ mysql_execute_command(void)
thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
}
if (thd->global_read_lock)
- {
- thd->global_read_lock=0;
- pthread_mutex_lock(&LOCK_open);
- global_read_lock--;
- pthread_cond_broadcast(&COND_refresh);
- pthread_mutex_unlock(&LOCK_open);
- }
+ unlock_global_read_lock(thd);
send_ok(&thd->net);
break;
case SQLCOM_LOCK_TABLES:
@@ -1891,6 +2177,8 @@ mysql_execute_command(void)
}
if (check_db_used(thd,tables) || end_active_trans(thd))
goto error;
+ if (grant_option && check_grant(thd,SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL,tables))
+ goto error;
thd->in_lock_tables=1;
thd->options|= OPTION_TABLE_LOCK;
if (!(res=open_and_lock_tables(thd,tables)))
@@ -1904,30 +2192,34 @@ mysql_execute_command(void)
thd->in_lock_tables=0;
break;
case SQLCOM_CREATE_DB:
+ {
+ if (!stripp_sp(lex->name) || check_db_name(lex->name))
{
- if (!stripp_sp(lex->name) || check_db_name(lex->name))
- {
- net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
- break;
- }
- if (check_access(thd,CREATE_ACL,lex->name,0,1))
- break;
- mysql_create_db(thd,lex->name,lex->create_info.options);
+ net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
break;
}
+ if (check_access(thd,CREATE_ACL,lex->name,0,1))
+ break;
+ res=mysql_create_db(thd,lex->name,lex->create_info.options,0);
+ break;
+ }
case SQLCOM_DROP_DB:
+ {
+ if (!stripp_sp(lex->name) || check_db_name(lex->name))
{
- if (!stripp_sp(lex->name) || check_db_name(lex->name))
- {
- net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
- break;
- }
- if (check_access(thd,DROP_ACL,lex->name,0,1) ||
- end_active_trans(thd))
- break;
- mysql_rm_db(thd,lex->name,lex->drop_if_exists);
+ net_printf(&thd->net,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->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ goto error;
}
+ res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0);
+ break;
+ }
case SQLCOM_CREATE_FUNCTION:
if (check_access(thd,INSERT_ACL,"mysql",0,1))
break;
@@ -1948,78 +2240,83 @@ mysql_execute_command(void)
res= -1;
#endif
break;
- case SQLCOM_REVOKE:
- case SQLCOM_GRANT:
- {
- if (tables && !tables->db)
- tables->db=thd->db;
- if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
- tables && tables->db ? tables->db : lex->db,
- tables ? &tables->grant.privilege : 0,
- tables ? 0 : 1))
- goto error;
-
- /* Check that the user isn't trying to change a password for another
- user if he doesn't have UPDATE privilege to the MySQL database */
-
- if (thd->user) // If not replication
- {
- LEX_USER *user;
- List_iterator <LEX_USER> user_list(lex->users_list);
- while ((user=user_list++))
- {
- if (user->password.str &&
- (strcmp(thd->user,user->user.str) ||
- user->host.str &&
- my_strcasecmp(user->host.str, thd->host ? thd->host : thd->ip)))
- {
- if (check_access(thd, UPDATE_ACL, "mysql",0,1))
- goto error;
- break; // We are allowed to do changes
- }
- }
- }
- if (tables)
- {
- if (grant_option && check_grant(thd,
- (lex->grant | lex->grant_tot_col |
- GRANT_ACL),
- tables))
- goto error;
- res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
- lex->grant, lex->sql_command == SQLCOM_REVOKE);
- if(!res)
- {
- mysql_update_log.write(thd, thd->query,thd->query_length);
- if (mysql_bin_log.is_open())
- {
- Query_log_event qinfo(thd, thd->query);
- mysql_bin_log.write(&qinfo);
- }
- }
- }
- else
- {
- if (lex->columns.elements)
- {
- net_printf(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
- res=1;
- }
- else
- res = mysql_grant(thd, lex->db, lex->users_list, lex->grant,
- lex->sql_command == SQLCOM_REVOKE);
- if (!res)
- {
- mysql_update_log.write(thd, thd->query,thd->query_length);
- if (mysql_bin_log.is_open())
- {
- Query_log_event qinfo(thd, thd->query);
- mysql_bin_log.write(&qinfo);
- }
- }
- }
- break;
- }
+ case SQLCOM_REVOKE:
+ case SQLCOM_GRANT:
+ {
+ if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
+ tables && tables->db ? tables->db : select_lex->db,
+ tables ? &tables->grant.privilege : 0,
+ tables ? 0 : 1))
+ goto error;
+
+ /* Check that the user isn't trying to change a password for another
+ user if he doesn't have UPDATE privilege to the MySQL database */
+
+ if (thd->user) // If not replication
+ {
+ LEX_USER *user;
+ List_iterator <LEX_USER> user_list(lex->users_list);
+ while ((user=user_list++))
+ {
+ if (user->password.str &&
+ (strcmp(thd->user,user->user.str) ||
+ user->host.str &&
+ my_strcasecmp(user->host.str, thd->host_or_ip)))
+ {
+ if (check_access(thd, UPDATE_ACL, "mysql",0,1))
+ goto error;
+ break; // We are allowed to do changes
+ }
+ }
+ }
+ if (tables)
+ {
+ if (grant_option && check_grant(thd,
+ (lex->grant | lex->grant_tot_col |
+ GRANT_ACL),
+ tables))
+ goto error;
+ if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
+ lex->grant,
+ lex->sql_command == SQLCOM_REVOKE)))
+ {
+ mysql_update_log.write(thd, thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ }
+ }
+ else
+ {
+ if (lex->columns.elements)
+ {
+ send_error(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
+ res=1;
+ }
+ else
+ res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
+ lex->sql_command == SQLCOM_REVOKE);
+ if (!res)
+ {
+ mysql_update_log.write(thd, thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ if (mqh_used && lex->mqh)
+ {
+ List_iterator <LEX_USER> str_list(lex->users_list);
+ LEX_USER *user;
+ while ((user=str_list++))
+ reset_mqh(thd,user,lex->mqh);
+ }
+ }
+ }
+ break;
+ }
case SQLCOM_FLUSH:
case SQLCOM_RESET:
if (check_access(thd,RELOAD_ACL,any_db) || check_db_used(thd, tables))
@@ -2034,13 +2331,40 @@ mysql_execute_command(void)
break;
case SQLCOM_SHOW_GRANTS:
res=0;
- if ((thd->priv_user && !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
+ if ((thd->priv_user &&
+ !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
!check_access(thd, SELECT_ACL, "mysql",0,1))
{
res = mysql_show_grants(thd,lex->grant_user);
}
break;
+ case SQLCOM_HA_OPEN:
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd,SELECT_ACL, tables))
+ goto error;
+ res = mysql_ha_open(thd, tables);
+ break;
+ case SQLCOM_HA_CLOSE:
+ if (check_db_used(thd,tables))
+ goto error;
+ res = mysql_ha_close(thd, tables);
+ break;
+ case SQLCOM_HA_READ:
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd,SELECT_ACL, tables))
+ goto error;
+ res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
+ lex->insert_list, lex->ha_rkey_mode, select_lex->where,
+ select_lex->select_limit, select_lex->offset_limit);
+ break;
+
case SQLCOM_BEGIN:
+ if (thd->locked_tables)
+ {
+ thd->lock=thd->locked_tables;
+ thd->locked_tables=0; // Will be automaticly closed
+ close_thread_tables(thd); // Free tables
+ }
if (end_active_trans(thd))
{
res= -1;
@@ -2059,13 +2383,17 @@ mysql_execute_command(void)
even if there is a problem with the OPTION_AUTO_COMMIT flag
(Which of course should never happen...)
*/
+ {
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_commit(thd))
+ {
send_ok(&thd->net);
+ }
else
res= -1;
break;
+ }
case SQLCOM_ROLLBACK:
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_rollback(thd))
@@ -2104,7 +2432,7 @@ error:
bool
check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
- bool dont_check_global_grants)
+ bool dont_check_global_grants, bool no_errors)
{
uint db_access,dummy;
if (save_priv)
@@ -2112,9 +2440,10 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
else
save_priv= &dummy;
- if (!db && !thd->db && !dont_check_global_grants)
+ if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
{
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */
+ if (!no_errors)
+ send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */
return TRUE; /* purecov: tested */
}
@@ -2126,16 +2455,17 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
if ((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL) ||
! db && dont_check_global_grants)
{ // We can never grant this
- net_printf(&thd->net,ER_ACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
- thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
+ if (!no_errors)
+ net_printf(&thd->net,ER_ACCESS_DENIED_ERROR,
+ thd->priv_user,
+ thd->host_or_ip,
+ thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
return TRUE; /* purecov: tested */
}
if (db == any_db)
return FALSE; // Allow select on anything
-
+
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 */
@@ -2149,10 +2479,11 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
((grant_option && !dont_check_global_grants) &&
!(want_access & ~TABLE_ACLS)))
return FALSE; /* Ok */
- net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
- db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
+ if (!no_errors)
+ net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
+ thd->priv_user,
+ thd->host_or_ip,
+ db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
return TRUE; /* purecov: tested */
}
@@ -2169,7 +2500,8 @@ bool check_process_priv(THD *thd)
*/
bool
-check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
+check_table_access(THD *thd,uint want_access,TABLE_LIST *tables,
+ bool no_errors)
{
uint found=0,found_access=0;
TABLE_LIST *org_tables=tables;
@@ -2184,20 +2516,20 @@ check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
tables->grant.privilege=found_access;
else
{
- if (check_access(thd,want_access,tables->db,&tables->grant.privilege))
+ if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
+ 0, no_errors))
return TRUE; // Access denied
found_access=tables->grant.privilege;
found=1;
}
}
- else if (check_access(thd,want_access,tables->db,&tables->grant.privilege))
+ else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
+ 0, no_errors))
return TRUE; // Access denied
}
if (grant_option)
- {
- want_access &= ~EXTRA_ACL; // Remove SHOW attribute
- return check_grant(thd,want_access,org_tables);
- }
+ return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
+ test(want_access & EXTRA_ACL), no_errors);
return FALSE;
}
@@ -2301,42 +2633,75 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize)
/****************************************************************************
- Initialize global thd variables neaded for query
+ Initialize global thd variables needed for query
****************************************************************************/
static void
mysql_init_query(THD *thd)
{
DBUG_ENTER("mysql_init_query");
- thd->lex.item_list.empty();
+ thd->lex.select_lex.item_list.empty();
thd->lex.value_list.empty();
- thd->lex.table_list.elements=0;
- thd->free_list=0;
-
- thd->lex.table_list.first=0;
- thd->lex.table_list.next= (byte**) &thd->lex.table_list.first;
+ 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->fatal_error=0; // Safety
thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
thd->sent_row_count=thd->examined_row_count=0;
+ thd->safe_to_cache_query=1;
DBUG_VOID_RETURN;
}
void
mysql_init_select(LEX *lex)
{
- lex->where=lex->having=0;
- lex->select_limit=current_thd->default_select_limit;
- lex->offset_limit=0L;
- lex->options=0;
+ SELECT_LEX *select_lex = lex->select;
+ select_lex->where=select_lex->having=0;
+ select_lex->select_limit=lex->thd->default_select_limit;
+ select_lex->offset_limit=0;
+ select_lex->options=0;
+ select_lex->linkage=UNSPECIFIED_TYPE;
lex->exchange = 0;
lex->proc_list.first=0;
- lex->order_list.elements=lex->group_list.elements=0;
- lex->order_list.first=0;
- lex->order_list.next= (byte**) &lex->order_list.first;
- lex->group_list.first=0;
- lex->group_list.next= (byte**) &lex->group_list.first;
+ select_lex->order_list.elements=select_lex->group_list.elements=0;
+ select_lex->order_list.first=0;
+ select_lex->order_list.next= (byte**) &select_lex->order_list.first;
+ select_lex->group_list.first=0;
+ select_lex->group_list.next= (byte**) &select_lex->group_list.first;
+ select_lex->next = (SELECT_LEX *)NULL;
+}
+
+bool
+mysql_new_select(LEX *lex)
+{
+ SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(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();
+ return 0;
}
+void mysql_init_multi_delete(LEX *lex)
+{
+ lex->sql_command = SQLCOM_DELETE_MULTI;
+ mysql_init_select(lex);
+ lex->select->select_limit=HA_POS_ERROR;
+ lex->auxilliary_table_list=lex->select_lex.table_list;
+ lex->select->table_list.elements=0;
+ lex->select->table_list.first=0;
+ lex->select->table_list.next= (byte**) &(lex->select->table_list.first);
+}
void
mysql_parse(THD *thd,char *inBuf,uint length)
@@ -2345,12 +2710,20 @@ mysql_parse(THD *thd,char *inBuf,uint length)
mysql_init_query(thd);
thd->query_length = length;
- LEX *lex=lex_start(thd, (uchar*) inBuf, length);
- if (!yyparse() && ! thd->fatal_error)
- mysql_execute_command();
- thd->proc_info="freeing items";
- free_items(thd); /* Free strings used by items */
- lex_end(lex);
+ if (query_cache.send_result_to_client(thd, inBuf, length) <= 0)
+ {
+ LEX *lex=lex_start(thd, (uchar*) inBuf, length);
+ if (!yyparse() && ! thd->fatal_error)
+ {
+ mysql_execute_command();
+ query_cache_end_of_result(&thd->net);
+ }
+ else
+ query_cache_abort(&thd->net);
+ thd->proc_info="freeing items";
+ free_items(thd); /* Free strings used by items */
+ lex_end(lex);
+ }
DBUG_VOID_RETURN;
}
@@ -2656,6 +3029,8 @@ add_proc_to_list(Item *item)
static void remove_escape(char *name)
{
+ if (!*name) // For empty DB names
+ return;
char *to;
#ifdef USE_MB
char *strend=name+(uint) strlen(name);
@@ -2675,7 +3050,7 @@ static void remove_escape(char *name)
}
#endif
if (*name == '\\' && name[1])
- name++; // Skipp '\\'
+ name++; // Skip '\\'
*to++= *name;
}
*to=0;
@@ -2714,7 +3089,6 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
register TABLE_LIST *ptr;
THD *thd=current_thd;
char *alias_str;
- const char *current_db;
DBUG_ENTER("add_table_to_list");
if (!table)
@@ -2729,15 +3103,19 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
}
if (!alias) /* Alias is case sensitive */
- if (!(alias_str=sql_strmake(alias_str,table->table.length)))
+ if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
DBUG_RETURN(0);
- if (lower_case_table_names)
- casedn_str(table->table.str);
+
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(0); /* purecov: inspected */
- ptr->db= table->db.str;
- ptr->real_name=table->table.str;
+ ptr->db= table->db.str ? table->db.str : (thd->db ? thd->db : (char*) "");
ptr->name=alias_str;
+ if (lower_case_table_names)
+ {
+ casedn_str(ptr->db);
+ casedn_str(table->table.str);
+ }
+ ptr->real_name=table->table.str;
ptr->lock_type=flags;
ptr->updating=updating;
if (use_index)
@@ -2748,26 +3126,86 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
sizeof(*ignore_index));
/* check that used name is unique */
- current_db=thd->db ? thd->db : "";
-
if (flags != TL_IGNORE)
{
- for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.table_list.first ; tables ;
+ for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ;
+ tables ;
tables=tables->next)
{
- if (!strcmp(alias_str,tables->name) &&
- !strcmp(ptr->db ? ptr->db : current_db,
- tables->db ? tables->db : current_db))
+ if (!strcmp(alias_str,tables->name) && !strcmp(ptr->db, tables->db))
{
net_printf(&thd->net,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
DBUG_RETURN(0); /* purecov: tested */
}
}
}
- link_in_list(&thd->lex.table_list,(byte*) ptr,(byte**) &ptr->next);
+ link_in_list(&thd->lex.select->table_list,(byte*) ptr,(byte**) &ptr->next);
DBUG_RETURN(ptr);
}
+
+/*
+** 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->name, aux->name))
+ break;
+ if (!cursor)
+ {
+ /* Add not used table to the total table list */
+ aux->lock_type= lex->lock_option;
+ 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=(TABLE *) cursor;
+ }
+ }
+ }
+ return 0;
+}
+
+
void add_join_on(TABLE_LIST *b,Item *expr)
{
if (!b->on_expr)
@@ -2787,22 +3225,20 @@ void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
/* Check if name is used in table list */
-static bool check_dup(THD *thd,const char *db,const char *name,
- TABLE_LIST *tables)
+static bool check_dup(const char *db, const char *name, TABLE_LIST *tables)
{
- const char *thd_db=thd->db ? thd->db : any_db;
for (; tables ; tables=tables->next)
- if (!strcmp(name,tables->real_name) &&
- !strcmp(db ? db : thd_db, tables->db ? tables->db : thd_db))
+ if (!strcmp(name,tables->real_name) && !strcmp(db,tables->db))
return 1;
return 0;
}
-bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
+bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
{
bool result=0;
select_errors=0; /* Write if more errors */
+ // TODO: figure out what's up with the commented out line below
// mysql_log.flush(); // Flush log
if (options & REFRESH_GRANT)
{
@@ -2818,12 +3254,21 @@ bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
if (ha_flush_logs())
result=1;
}
+ if (options & REFRESH_QUERY_CACHE_FREE)
+ {
+ query_cache.pack(); // FLUSH QUERY CACHE
+ options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
+ }
+ if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
+ {
+ query_cache.flush(); // RESET QUERY CACHE
+ }
if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
{
- if ((options & REFRESH_READ_LOCK) && thd && ! thd->global_read_lock)
+ if ((options & REFRESH_READ_LOCK) && thd)
{
- thd->global_read_lock=1;
- thread_safe_increment(global_read_lock,&LOCK_open);
+ if (lock_global_read_lock(thd))
+ return 1;
}
result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
}
@@ -2834,10 +3279,22 @@ bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
if (options & REFRESH_THREADS)
flush_thread_cache();
if (options & REFRESH_MASTER)
- reset_master();
- if (options & REFRESH_SLAVE)
- reset_slave();
-
+ if (reset_master(thd))
+ result=1;
+#ifdef OPENSSL
+ if (options & REFRESH_DES_KEY_FILE)
+ {
+ if (des_key_file)
+ result=load_des_key_file(des_key_file);
+ }
+#endif
+ if (options & REFRESH_SLAVE)
+ {
+ LOCK_ACTIVE_MI;
+ if (reset_slave(active_mi))
+ result=1;
+ UNLOCK_ACTIVE_MI;
+ }
return result;
}
@@ -2855,7 +3312,7 @@ void kill_one_thread(THD *thd, ulong id)
if ((thd->master_access & PROCESS_ACL) ||
!strcmp(thd->user,tmp->user))
{
- tmp->prepare_to_die();
+ tmp->awake(1 /*prepare to die*/);
error=0;
}
else
@@ -2884,3 +3341,29 @@ static void refresh_status(void)
pthread_mutex_unlock(&LOCK_status);
pthread_mutex_unlock(&THR_LOCK_keycache);
}
+
+
+ /* If pointer is not a null pointer, append filename to it */
+
+static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
+{
+ char buff[FN_REFLEN],*ptr, *end;
+ if (!*filename_ptr)
+ return 0; // nothing to do
+
+ /* Check that the filename is not too long and it's a hard path */
+ if (strlen(*filename_ptr)+strlen(table_name) >= FN_REFLEN-1 ||
+ !test_if_hard_path(*filename_ptr))
+ {
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
+ return 1;
+ }
+ /* Fix is using unix filename format on dos */
+ strmov(buff,*filename_ptr);
+ end=convert_dirname(buff, *filename_ptr, NullS);
+ if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
+ return 1; // End of memory
+ *filename_ptr=ptr;
+ strxmov(ptr,buff,table_name,NullS);
+ return 0;
+}