mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			2570 lines
		
	
	
		
			72 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2570 lines
		
	
	
		
			72 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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
 | 
						|
   the Free Software Foundation; either version 2 of the License, or
 | 
						|
   (at your option) any later version.
 | 
						|
 | 
						|
   This program is distributed in the hope that it will be useful,
 | 
						|
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
   GNU General Public License for more details.
 | 
						|
 | 
						|
   You should have received a copy of the GNU General Public License
 | 
						|
   along with this program; if not, write to the Free Software
 | 
						|
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
						|
 | 
						|
 | 
						|
#include "mysql_priv.h"
 | 
						|
#include "sql_acl.h"
 | 
						|
#include "sql_repl.h"
 | 
						|
#include <m_ctype.h>
 | 
						|
#include <thr_alarm.h>
 | 
						|
#include <myisam.h>
 | 
						|
#include <my_dir.h>
 | 
						|
 | 
						|
#define SCRAMBLE_LENGTH 8
 | 
						|
 | 
						|
 | 
						|
extern int yyparse(void);
 | 
						|
extern "C" pthread_mutex_t THR_LOCK_keycache;
 | 
						|
#ifdef SOLARIS
 | 
						|
extern "C" int gethostname(char *name, int namelen);
 | 
						|
#endif
 | 
						|
 | 
						|
static bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables);
 | 
						|
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 void mysql_init_query(THD *thd);
 | 
						|
static void remove_escape(char *name);
 | 
						|
static void refresh_status(void);
 | 
						|
 | 
						|
const char *any_db="*any*";	// Special symbol for check_access
 | 
						|
 | 
						|
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"
 | 
						|
};
 | 
						|
 | 
						|
bool volatile abort_slave = 0;
 | 
						|
 | 
						|
#ifdef HAVE_OPENSSL
 | 
						|
extern VioSSLAcceptorFd* ssl_acceptor_fd;
 | 
						|
#endif /* HAVE_OPENSSL */
 | 
						|
 | 
						|
#ifdef __WIN__
 | 
						|
static void  test_signal(int sig_ptr)
 | 
						|
{
 | 
						|
#ifndef DBUG_OFF
 | 
						|
  MessageBox(NULL,"Test signal","DBUG",MB_OK);
 | 
						|
#endif
 | 
						|
}
 | 
						|
static void init_signals(void)
 | 
						|
{
 | 
						|
  int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
 | 
						|
  for(int i=0 ; i < 7 ; i++)
 | 
						|
    signal( signals[i], test_signal) ;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static inline bool end_active_trans(THD *thd)
 | 
						|
{
 | 
						|
  if (!(thd->options & OPTION_AUTO_COMMIT) ||
 | 
						|
      (thd->options & OPTION_BEGIN))
 | 
						|
  {
 | 
						|
    if (ha_commit(thd))
 | 
						|
      return 1;
 | 
						|
    thd->options&= ~(ulong) (OPTION_BEGIN);
 | 
						|
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
** 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;
 | 
						|
  thd->db=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,
 | 
						|
				 passwd, thd->scramble, &thd->priv_user,
 | 
						|
				 protocol_version == 9 ||
 | 
						|
				 !(thd->client_capabilities &
 | 
						|
				   CLIENT_LONG_PASSWORD));
 | 
						|
  DBUG_PRINT("general",
 | 
						|
	     ("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,
 | 
						|
	      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,
 | 
						|
	       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",
 | 
						|
		    passwd[0] ? ER(ER_YES) : ER(ER_NO));
 | 
						|
    return(1);					// Error already given
 | 
						|
  }
 | 
						|
  if (check_count)
 | 
						|
  {
 | 
						|
    VOID(pthread_mutex_lock(&LOCK_thread_count));
 | 
						|
    bool tmp=(thread_count - delayed_insert_threads >= max_connections &&
 | 
						|
	      !(thd->master_access & PROCESS_ACL));
 | 
						|
    VOID(pthread_mutex_unlock(&LOCK_thread_count));
 | 
						|
    if (tmp)
 | 
						|
    {						// Too many connections
 | 
						|
      send_error(net, ER_CON_COUNT_ERROR);
 | 
						|
      return(1);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  mysql_log.write(thd,command,
 | 
						|
		  (thd->priv_user == thd->user ?
 | 
						|
		   (char*) "%s@%s on %s" :
 | 
						|
		   (char*) "%s@%s as anonymous on %s"),
 | 
						|
		  user,
 | 
						|
		  thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
 | 
						|
		  db ? db : (char*) "");
 | 
						|
  thd->db_access=0;
 | 
						|
  if (db && db[0])
 | 
						|
    return test(mysql_change_db(thd,db));
 | 
						|
  else
 | 
						|
    send_ok(net);				// Ready to handle questions
 | 
						|
  return 0;					// ok
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
** 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
 | 
						|
  */
 | 
						|
  DBUG_PRINT("info", (("check_connections called by thread %d"),
 | 
						|
	     thd->thread_id));
 | 
						|
  DBUG_PRINT("general",("New connection received on %s",
 | 
						|
			vio_description(net->vio)));
 | 
						|
  if (!thd->host)                           // If TCP/IP connection
 | 
						|
  {
 | 
						|
    char ip[17];
 | 
						|
 | 
						|
    if (vio_peer_addr(net->vio,ip))
 | 
						|
      return (ER_BAD_HOST_ERROR);
 | 
						|
    if (!(thd->ip = my_strdup(ip,MYF(0))))
 | 
						|
      return (ER_OUT_OF_RESOURCES);
 | 
						|
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
 | 
						|
    /* Fast local hostname resolve for Win32 */
 | 
						|
    if (!strcmp(thd->ip,"127.0.0.1"))
 | 
						|
      thd->host=(char*) localhost;
 | 
						|
    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);
 | 
						|
      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"));
 | 
						|
    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));
 | 
						|
    thd->ip=0;
 | 
						|
    bzero((char*) &thd->remote,sizeof(struct sockaddr));
 | 
						|
  }
 | 
						|
  vio_keepalive(net->vio, TRUE);
 | 
						|
 | 
						|
  /* nasty, but any other way? */
 | 
						|
  uint pkt_len = 0;
 | 
						|
  {
 | 
						|
    char buff[60],*end;
 | 
						|
    int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
 | 
						|
	               CLIENT_TRANSACTIONS;
 | 
						|
    LINT_INIT(pkt_len);
 | 
						|
 | 
						|
    end=strmov(buff,server_version)+1;
 | 
						|
    int4store((uchar*) end,thd->thread_id);
 | 
						|
    end+=4;
 | 
						|
    memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
 | 
						|
    end+=SCRAMBLE_LENGTH +1;
 | 
						|
#ifdef HAVE_COMPRESS
 | 
						|
    client_flags |= CLIENT_COMPRESS;
 | 
						|
#endif /* HAVE_COMPRESS */
 | 
						|
#ifdef HAVE_OPENSSL
 | 
						|
    if (ssl_acceptor_fd!=0)
 | 
						|
      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;
 | 
						|
    int2store(end+3,thd->server_status);
 | 
						|
    bzero(end+5,13);
 | 
						|
    end+=18;
 | 
						|
    if (net_write_command(net,protocol_version, buff,
 | 
						|
			  (uint) (end-buff)) ||
 | 
						|
       (pkt_len=my_net_read(net)) == packet_error ||
 | 
						|
	pkt_len < MIN_HANDSHAKE_SIZE)
 | 
						|
    {
 | 
						|
      inc_host_errors(&thd->remote.sin_addr);
 | 
						|
      return(ER_HANDSHAKE_ERROR);
 | 
						|
    }
 | 
						|
  }
 | 
						|
#ifdef _CUSTOMCONFIG_
 | 
						|
#include "_cust_sql_parse.h"
 | 
						|
#endif
 | 
						|
  if (connect_errors)
 | 
						|
    reset_host_errors(&thd->remote.sin_addr);
 | 
						|
  if (thd->packet.alloc(net_buffer_length))
 | 
						|
    return(ER_OUT_OF_RESOURCES);
 | 
						|
 | 
						|
  thd->client_capabilities=uint2korr(net->read_pos);
 | 
						|
#ifdef HAVE_OPENSSL
 | 
						|
  DBUG_PRINT("info",
 | 
						|
	     ("pkt_len:%d, client capabilities: %d",
 | 
						|
	      pkt_len, 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);
 | 
						|
    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"));
 | 
						|
      inc_host_errors(&thd->remote.sin_addr);
 | 
						|
      return(ER_HANDSHAKE_ERROR);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    DBUG_PRINT("info", ("Leaving IO layer intact"));
 | 
						|
    if (pkt_len < NORMAL_HANDSHAKE_SIZE)
 | 
						|
    {
 | 
						|
      inc_host_errors(&thd->remote.sin_addr);
 | 
						|
      return ER_HANDSHAKE_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  thd->max_packet_length=uint3korr(net->read_pos+2);
 | 
						|
  char *user=   (char*) net->read_pos+5;
 | 
						|
  char *passwd= strend(user)+1;
 | 
						|
  char *db=0;
 | 
						|
  if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH)
 | 
						|
    return ER_HANDSHAKE_ERROR;
 | 
						|
  if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
 | 
						|
    db=strend(passwd)+1;
 | 
						|
  if (thd->client_capabilities & CLIENT_INTERACTIVE)
 | 
						|
    thd->inactive_timeout=net_interactive_timeout;
 | 
						|
  if (thd->client_capabilities & CLIENT_TRANSACTIONS)
 | 
						|
    thd->net.return_status= &thd->server_status;
 | 
						|
  net->timeout=net_read_timeout;
 | 
						|
  if (check_user(thd,COM_CONNECT, user, passwd, db, 1))
 | 
						|
    return (-1);
 | 
						|
  thd->password=test(passwd[0]);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
pthread_handler_decl(handle_one_connection,arg)
 | 
						|
{
 | 
						|
  THD *thd=(THD*) arg;
 | 
						|
  uint launch_time  =
 | 
						|
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
 | 
						|
  if (launch_time >= slow_launch_time)
 | 
						|
    statistic_increment(slow_launch_threads,&LOCK_status );
 | 
						|
 | 
						|
  pthread_detach_this_thread();
 | 
						|
 | 
						|
#ifndef __WIN__	/* Win32 calls this in pthread_create */
 | 
						|
  if (my_thread_init()) // needed to be called first before we call
 | 
						|
    // DBUG_ macros
 | 
						|
  {
 | 
						|
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
 | 
						|
    statistic_increment(aborted_connects,&LOCK_thread_count);
 | 
						|
    end_thread(thd,0);
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
#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
 | 
						|
 | 
						|
  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_*
 | 
						|
 | 
						|
#ifdef __WIN__
 | 
						|
  init_signals();				// IRENA; testing ?
 | 
						|
#else
 | 
						|
  sigset_t set;
 | 
						|
  VOID(sigemptyset(&set));			// Get mask in use
 | 
						|
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
 | 
						|
#endif
 | 
						|
  if (thd->store_globals())
 | 
						|
  {
 | 
						|
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
 | 
						|
    statistic_increment(aborted_connects,&LOCK_thread_count);
 | 
						|
    end_thread(thd,0);
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  do
 | 
						|
  {
 | 
						|
    int error;
 | 
						|
    NET *net= &thd->net;
 | 
						|
 | 
						|
    thd->mysys_var=my_thread_var;
 | 
						|
    thd->dbug_thread_id=my_thread_id();
 | 
						|
    thd->thread_stack= (char*) &thd;
 | 
						|
 | 
						|
    if ((error=check_connections(thd)))
 | 
						|
    {						// Wrong permissions
 | 
						|
      if (error > 0)
 | 
						|
	net_printf(net,error,thd->host ? thd->host : thd->ip);
 | 
						|
#ifdef __NT__
 | 
						|
      if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
 | 
						|
	sleep(1);				/* must wait after eof() */
 | 
						|
#endif
 | 
						|
      statistic_increment(aborted_connects,&LOCK_thread_count);
 | 
						|
      goto end_thread;
 | 
						|
    }
 | 
						|
 | 
						|
    if (thd->max_join_size == HA_POS_ERROR)
 | 
						|
      thd->options |= OPTION_BIG_SELECTS;
 | 
						|
    if (thd->client_capabilities & CLIENT_COMPRESS)
 | 
						|
      net->compress=1;				// Use compression
 | 
						|
    if (thd->options & OPTION_ANSI_MODE)
 | 
						|
      thd->client_capabilities|=CLIENT_IGNORE_SPACE;
 | 
						|
 | 
						|
    thd->proc_info=0;				// Remove 'login'
 | 
						|
    thd->command=COM_SLEEP;
 | 
						|
    thd->version=refresh_version;
 | 
						|
    thd->set_time();
 | 
						|
    init_sql_alloc(&thd->mem_root,8192,8192);
 | 
						|
    while (!net->error && net->vio != 0 && !thd->killed)
 | 
						|
    {
 | 
						|
      if (do_command(thd))
 | 
						|
	break;
 | 
						|
    }
 | 
						|
    free_root(&thd->mem_root,MYF(0));
 | 
						|
    if (net->error && net->vio != 0)
 | 
						|
    {
 | 
						|
      sql_print_error(ER(ER_NEW_ABORTING_CONNECTION),
 | 
						|
		      thd->thread_id,(thd->db ? thd->db : "unconnected"),
 | 
						|
		      thd->user,
 | 
						|
		      (thd->host ? thd->host : thd->ip ? thd->ip : "unknown"),
 | 
						|
		      (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);
 | 
						|
    }
 | 
						|
 | 
						|
end_thread:
 | 
						|
    close_connection(net);
 | 
						|
    end_thread(thd,1);
 | 
						|
    /*
 | 
						|
      If end_thread returns, we are either running with --one-thread
 | 
						|
      or this thread has been schedule to handle the next query
 | 
						|
    */
 | 
						|
    thd= current_thd;
 | 
						|
  } while (!(test_flags & TEST_NO_THREADS));
 | 
						|
  /* The following is only executed if we are not using --one-thread */
 | 
						|
  return(0);					/* purecov: deadcode */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int handle_bootstrap(THD *thd,FILE *file)
 | 
						|
{
 | 
						|
  DBUG_ENTER("handle_bootstrap");
 | 
						|
  thd->thread_stack= (char*) &thd;
 | 
						|
 | 
						|
  if (init_thr_lock() ||
 | 
						|
      my_pthread_setspecific_ptr(THR_THD,  thd) ||
 | 
						|
      my_pthread_setspecific_ptr(THR_MALLOC, &thd->mem_root) ||
 | 
						|
      my_pthread_setspecific_ptr(THR_NET,  &thd->net))
 | 
						|
  {
 | 
						|
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
 | 
						|
    DBUG_RETURN(-1);
 | 
						|
  }
 | 
						|
  thd->mysys_var=my_thread_var;
 | 
						|
  thd->dbug_thread_id=my_thread_id();
 | 
						|
#ifndef __WIN__
 | 
						|
  sigset_t set;
 | 
						|
  VOID(sigemptyset(&set));			// Get mask in use
 | 
						|
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
 | 
						|
#endif
 | 
						|
 | 
						|
  if (thd->max_join_size == (ulong) ~0L)
 | 
						|
    thd->options |= OPTION_BIG_SELECTS;
 | 
						|
 | 
						|
  thd->proc_info=0;
 | 
						|
  thd->version=refresh_version;
 | 
						|
 | 
						|
  char *buff= (char*) thd->net.buff;
 | 
						|
  init_sql_alloc(&thd->mem_root,8192,8192);
 | 
						|
  while (fgets(buff, thd->net.max_packet, file))
 | 
						|
  {
 | 
						|
    uint length=(uint) strlen(buff);
 | 
						|
    while (length && (isspace(buff[length-1]) || buff[length-1] == ';'))
 | 
						|
      length--;
 | 
						|
    buff[length]=0;
 | 
						|
    thd->current_tablenr=0;
 | 
						|
    thd->query= thd->memdup(buff,length+1);
 | 
						|
    thd->query_id=query_id++;
 | 
						|
    mysql_parse(thd,thd->query,length);
 | 
						|
    close_thread_tables(thd);			// Free tables
 | 
						|
    if (thd->fatal_error)
 | 
						|
    {
 | 
						|
      DBUG_RETURN(-1);
 | 
						|
    }
 | 
						|
    free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
 | 
						|
  }
 | 
						|
  free_root(&thd->mem_root,MYF(0));
 | 
						|
  DBUG_RETURN(0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static 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)
 | 
						|
    delete item;
 | 
						|
}
 | 
						|
 | 
						|
int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
 | 
						|
{
 | 
						|
  TABLE* table;
 | 
						|
  TABLE_LIST* table_list;
 | 
						|
  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))))
 | 
						|
     DBUG_RETURN(1); // out of memory
 | 
						|
  table_list->db = db;
 | 
						|
  table_list->real_name = table_list->name = tbl_name;
 | 
						|
  table_list->lock_type = TL_READ_NO_INSERT;
 | 
						|
  table_list->next = 0;
 | 
						|
  remove_escape(table_list->real_name);
 | 
						|
 | 
						|
  if(!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
 | 
						|
    DBUG_RETURN(1);
 | 
						|
 | 
						|
  if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege))
 | 
						|
    goto err;
 | 
						|
  if (grant_option && check_grant(thd, SELECT_ACL, table_list))
 | 
						|
    goto err;
 | 
						|
 | 
						|
  thd->free_list = 0;
 | 
						|
  thd->query = tbl_name;
 | 
						|
  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));
 | 
						|
 | 
						|
err:
 | 
						|
 | 
						|
  close_thread_tables(thd);
 | 
						|
 | 
						|
  DBUG_RETURN(error);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/* Execute one command from socket (query or simple command) */
 | 
						|
 | 
						|
bool do_command(THD *thd)
 | 
						|
{
 | 
						|
  char *packet;
 | 
						|
  uint old_timeout,packet_length;
 | 
						|
  bool	error=0;
 | 
						|
  NET *net;
 | 
						|
  enum enum_server_command command;
 | 
						|
  DBUG_ENTER("do_command");
 | 
						|
 | 
						|
  net= &thd->net;
 | 
						|
  thd->current_tablenr=0;
 | 
						|
 | 
						|
  packet=0;
 | 
						|
  old_timeout=net->timeout;
 | 
						|
  net->timeout=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) ));
 | 
						|
    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]));
 | 
						|
  }
 | 
						|
  net->timeout=old_timeout;			/* Timeout */
 | 
						|
  thd->command=command;
 | 
						|
  VOID(pthread_mutex_lock(&LOCK_thread_count));
 | 
						|
  thd->query_id=query_id;
 | 
						|
  if (command != COM_STATISTICS && command != COM_PING)
 | 
						|
    query_id++;
 | 
						|
  thread_running++;
 | 
						|
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
 | 
						|
  thd->set_time();
 | 
						|
  switch(command) {
 | 
						|
  case COM_INIT_DB:
 | 
						|
    if (!mysql_change_db(thd,packet+1))
 | 
						|
      mysql_log.write(thd,command,"%s",thd->db);
 | 
						|
    break;
 | 
						|
  case COM_TABLE_DUMP:
 | 
						|
    {
 | 
						|
      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);
 | 
						|
      char* tbl_name = db + db_len;
 | 
						|
      *tbl_name++ = 0;
 | 
						|
      memcpy(tbl_name, data + 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;
 | 
						|
    }
 | 
						|
  case COM_CHANGE_USER:
 | 
						|
  {
 | 
						|
    char *user=   (char*) packet+1;
 | 
						|
    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;
 | 
						|
    char *save_user=	    thd->user;
 | 
						|
    char *save_priv_user=   thd->priv_user;
 | 
						|
    char *save_db=	    thd->db;
 | 
						|
 | 
						|
    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);
 | 
						|
      x_free(thd->db);
 | 
						|
      thd->master_access=save_master_access;
 | 
						|
      thd->db_access=save_db_access;
 | 
						|
      thd->db=save_db;
 | 
						|
      thd->user=save_user;
 | 
						|
      thd->priv_user=save_priv_user;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    x_free((gptr) save_db);
 | 
						|
    x_free((gptr) save_user);
 | 
						|
    thd->password=test(passwd[0]);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  case COM_QUERY:
 | 
						|
  {
 | 
						|
    char *pos=packet+packet_length;		// Point at end null
 | 
						|
    /* Remove garage at end of query */
 | 
						|
    while (packet_length > 0 && pos[-1] == ';')
 | 
						|
    {
 | 
						|
      pos--;
 | 
						|
      packet_length--;
 | 
						|
    }
 | 
						|
    *pos=0;
 | 
						|
    if (!(thd->query= (char*) thd->memdup((gptr) (packet+1),packet_length)))
 | 
						|
      break;
 | 
						|
    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 (!(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
 | 
						|
#ifdef DONT_ALLOW_SHOW_COMMANDS
 | 
						|
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
 | 
						|
    break;
 | 
						|
#else
 | 
						|
  {
 | 
						|
    char *fields;
 | 
						|
    TABLE_LIST table_list;
 | 
						|
    bzero((char*) &table_list,sizeof(table_list));
 | 
						|
    if (!(table_list.db=thd->db))
 | 
						|
    {
 | 
						|
      send_error(net,ER_NO_DB_ERROR);
 | 
						|
      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);
 | 
						|
    mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
 | 
						|
    remove_escape(table_list.real_name);	// This can't have wildcards
 | 
						|
 | 
						|
    if (check_access(thd,SELECT_ACL,table_list.db,&thd->col_access))
 | 
						|
      break;
 | 
						|
    table_list.grant.privilege=thd->col_access;
 | 
						|
    if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2))
 | 
						|
      break;
 | 
						|
    mysqld_list_fields(thd,&table_list,fields);
 | 
						|
    free_items(thd);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  case COM_QUIT:
 | 
						|
    mysql_log.write(thd,command,NullS);
 | 
						|
    net->error=0;				// Don't give 'abort' message
 | 
						|
    error=TRUE;					// End server
 | 
						|
    break;
 | 
						|
 | 
						|
  case COM_CREATE_DB:
 | 
						|
    {
 | 
						|
      char *db=thd->strdup(packet+1);
 | 
						|
      if (check_access(thd,CREATE_ACL,db,0,1))
 | 
						|
	break;
 | 
						|
      mysql_log.write(thd,command,packet+1);
 | 
						|
      mysql_create_db(thd,db,0);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  case COM_DROP_DB:
 | 
						|
    {
 | 
						|
      char *db=thd->strdup(packet+1);
 | 
						|
      if (check_access(thd,DROP_ACL,db,0,1))
 | 
						|
	break;
 | 
						|
      mysql_log.write(thd,command,db);
 | 
						|
      mysql_rm_db(thd,db,0);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  case COM_BINLOG_DUMP:
 | 
						|
    {
 | 
						|
      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);
 | 
						|
      pthread_mutex_lock(&LOCK_server_id);
 | 
						|
      kill_zombie_dump_threads(slave_server_id = uint4korr(packet+7));
 | 
						|
      thd->server_id = slave_server_id;
 | 
						|
      pthread_mutex_unlock(&LOCK_server_id);
 | 
						|
      mysql_binlog_send(thd, strdup(packet + 11), pos, flags);
 | 
						|
      // fake COM_QUIT -- if we get here, the thread needs to terminate
 | 
						|
      error = TRUE;
 | 
						|
      net->error = 0;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  case COM_REFRESH:
 | 
						|
    {
 | 
						|
      uint options=(uchar) packet[1];
 | 
						|
      if (check_access(thd,RELOAD_ACL,any_db))
 | 
						|
	break;
 | 
						|
      mysql_log.write(thd,command,NullS);
 | 
						|
      if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0))
 | 
						|
	send_error(net,0);
 | 
						|
      else
 | 
						|
	send_eof(net);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  case COM_SHUTDOWN:
 | 
						|
    if (check_access(thd,SHUTDOWN_ACL,any_db))
 | 
						|
      break; /* purecov: inspected */
 | 
						|
    DBUG_PRINT("quit",("Got shutdown command"));
 | 
						|
    mysql_log.write(thd,command,NullS);
 | 
						|
    send_eof(net);
 | 
						|
#ifdef __WIN__
 | 
						|
    sleep(1);					// must wait after eof()
 | 
						|
#endif
 | 
						|
    send_eof(net);				// This is for 'quit request'
 | 
						|
    close_connection(net);
 | 
						|
    close_thread_tables(thd);			// Free before kill
 | 
						|
    free_root(&thd->mem_root,MYF(0));
 | 
						|
    kill_mysql();
 | 
						|
    error=TRUE;
 | 
						|
    break;
 | 
						|
 | 
						|
  case COM_STATISTICS:
 | 
						|
  {
 | 
						|
    mysql_log.write(thd,command,NullS);
 | 
						|
    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,
 | 
						|
	    (int) thread_count,thd->query_id,long_query_count,
 | 
						|
	    opened_tables,refresh_version, cached_tables(),
 | 
						|
	    uptime ? (float)thd->query_id/(float)uptime : 0);
 | 
						|
#ifdef SAFEMALLOC
 | 
						|
    if (lCurMemory)				// Using SAFEMALLOC
 | 
						|
      sprintf(strend(buff), "  Memory in use: %ldK  Max memory used: %ldK",
 | 
						|
	      (lCurMemory+1023L)/1024L,(lMaxMemory+1023L)/1024L);
 | 
						|
 #endif
 | 
						|
    VOID(my_net_write(net, buff,(uint) strlen(buff)));
 | 
						|
    VOID(net_flush(net));
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case COM_PING:
 | 
						|
    send_ok(net);				// Tell client we are alive
 | 
						|
    break;
 | 
						|
  case COM_PROCESS_INFO:
 | 
						|
    if (!thd->priv_user[0] && check_access(thd,PROCESS_ACL,any_db))
 | 
						|
      break;
 | 
						|
    mysql_log.write(thd,command,NullS);
 | 
						|
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
 | 
						|
			  thd->priv_user,0);
 | 
						|
    break;
 | 
						|
  case COM_PROCESS_KILL:
 | 
						|
  {
 | 
						|
    ulong id=(ulong) uint4korr(packet+1);
 | 
						|
    kill_one_thread(thd,id);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case COM_DEBUG:
 | 
						|
    if (check_access(thd,PROCESS_ACL,any_db))
 | 
						|
      break;					/* purecov: inspected */
 | 
						|
    mysql_print_status(thd);
 | 
						|
    mysql_log.write(thd,command,NullS);
 | 
						|
    send_eof(net);
 | 
						|
    break;
 | 
						|
  case COM_SLEEP:
 | 
						|
  case COM_CONNECT:				// Impossible here
 | 
						|
  case COM_TIME:				// Impossible from client
 | 
						|
  case COM_DELAYED_INSERT:
 | 
						|
  default:
 | 
						|
    send_error(net, ER_UNKNOWN_COM_ERROR);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  if (thd->lock || thd->open_tables)
 | 
						|
  {
 | 
						|
    thd->proc_info="closing tables";
 | 
						|
    close_thread_tables(thd);			/* Free tables */
 | 
						|
  }
 | 
						|
  thd->proc_info="cleaning up";
 | 
						|
 | 
						|
  if (thd->fatal_error)
 | 
						|
    send_error(net,0);				// End of memory ?
 | 
						|
 | 
						|
  time_t start_of_query=thd->start_time;
 | 
						|
  thd->end_time();				// Set start time
 | 
						|
  /* If not reading from backup and if the query took too long */
 | 
						|
  if (!thd->user_time)
 | 
						|
  {
 | 
						|
    if ((ulong) (thd->start_time - thd->time_after_lock) > long_query_time ||
 | 
						|
	((thd->options & (OPTION_NO_INDEX_USED | OPTION_NO_GOOD_INDEX_USED)) &&
 | 
						|
	 (specialflag & SPECIAL_LONG_LOG_FORMAT)))
 | 
						|
    {
 | 
						|
      long_query_count++;
 | 
						|
      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  thd->proc_info="cleaning up2";
 | 
						|
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
 | 
						|
  thd->proc_info=0;
 | 
						|
  thd->command=COM_SLEEP;
 | 
						|
  thd->query=0;
 | 
						|
  thread_running--;
 | 
						|
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
 | 
						|
  thd->packet.shrink(net_buffer_length);	// Reclaim some memory
 | 
						|
  free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
 | 
						|
  DBUG_RETURN(error);
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************************
 | 
						|
** mysql_execute_command
 | 
						|
** Execute command saved in thd and current_lex->sql_command
 | 
						|
****************************************************************************/
 | 
						|
 | 
						|
void
 | 
						|
mysql_execute_command(void)
 | 
						|
{
 | 
						|
  int	res=0;
 | 
						|
  THD	*thd=current_thd;
 | 
						|
  LEX	*lex=current_lex;
 | 
						|
  TABLE_LIST *tables=(TABLE_LIST*) lex->table_list.first;
 | 
						|
  DBUG_ENTER("mysql_execute_command");
 | 
						|
 | 
						|
  if(thd->slave_thread && table_rules_on && tables && !tables_ok(thd,tables))
 | 
						|
    DBUG_VOID_RETURN; // 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
 | 
						|
  
 | 
						|
  switch (lex->sql_command) {
 | 
						|
  case SQLCOM_SELECT:
 | 
						|
  {
 | 
						|
    select_result *result;
 | 
						|
    if (lex->options & SELECT_DESCRIBE)
 | 
						|
      lex->exchange=0;
 | 
						|
    if (tables)
 | 
						|
    {
 | 
						|
      res=check_table_access(thd,
 | 
						|
			     lex->exchange ? SELECT_ACL | FILE_ACL :
 | 
						|
			     SELECT_ACL,
 | 
						|
			     tables);
 | 
						|
    }
 | 
						|
    else
 | 
						|
      res=check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
 | 
						|
		       any_db);
 | 
						|
    if (res)
 | 
						|
    {
 | 
						|
      res=0;
 | 
						|
      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->select_limit= HA_POS_ERROR;		// no limit
 | 
						|
 | 
						|
    if (lex->exchange)
 | 
						|
    {
 | 
						|
      if (lex->exchange->dumpfile)
 | 
						|
      {
 | 
						|
	if (!(result=new select_dump(lex->exchange)))
 | 
						|
	{
 | 
						|
	  res= -1;
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
	if (!(result=new select_export(lex->exchange)))
 | 
						|
	{
 | 
						|
	  res= -1;
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else if (!(result=new select_send()))
 | 
						|
    {
 | 
						|
      res= -1;
 | 
						|
#ifdef DELETE_ITEMS
 | 
						|
      delete lex->having;
 | 
						|
      delete lex->where;
 | 
						|
#endif
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (lex->options & SELECT_HIGH_PRIORITY)
 | 
						|
    {
 | 
						|
      TABLE_LIST *table;
 | 
						|
      for (table = tables ; table ; table=table->next)
 | 
						|
	table->lock_type=TL_READ_HIGH_PRIORITY;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!(res=open_and_lock_tables(thd,tables)))
 | 
						|
    {
 | 
						|
      res=mysql_select(thd,tables,lex->item_list,
 | 
						|
		       lex->where,
 | 
						|
                       lex->ftfunc_list,
 | 
						|
		       (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;
 | 
						|
#ifdef DELETE_ITEMS
 | 
						|
    delete lex->having;
 | 
						|
    delete lex->where;
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case SQLCOM_PURGE:
 | 
						|
    {
 | 
						|
      if(check_access(thd, PROCESS_ACL, any_db))
 | 
						|
	goto error;
 | 
						|
      res = purge_master_logs(thd, lex->to_log);
 | 
						|
      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);
 | 
						|
 | 
						|
      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;
 | 
						|
    }
 | 
						|
  case SQLCOM_CHANGE_MASTER:
 | 
						|
    {
 | 
						|
      if(check_access(thd, PROCESS_ACL, any_db))
 | 
						|
	goto error;
 | 
						|
      res = change_master(thd);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  case SQLCOM_SHOW_SLAVE_STAT:
 | 
						|
    {
 | 
						|
      if(check_access(thd, PROCESS_ACL, any_db))
 | 
						|
	goto error;
 | 
						|
      res = show_master_info(thd);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  case SQLCOM_SHOW_MASTER_STAT:
 | 
						|
    {
 | 
						|
      if (check_access(thd, PROCESS_ACL, any_db))
 | 
						|
	goto error;
 | 
						|
      res = show_binlog_info(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))
 | 
						|
      goto error;				/* purecov: inspected */
 | 
						|
    if (grant_option)
 | 
						|
    {
 | 
						|
      /* Check that the first table has CREATE privilege */
 | 
						|
      TABLE_LIST *tmp_table_list=tables->next;
 | 
						|
      tables->next=0;
 | 
						|
      bool error=check_grant(thd,CREATE_ACL,tables);
 | 
						|
      tables->next=tmp_table_list;
 | 
						|
      if (error)
 | 
						|
	  goto error;
 | 
						|
    }
 | 
						|
    if (strlen(tables->name) > NAME_LEN)
 | 
						|
    {
 | 
						|
      net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->name);
 | 
						|
      res=0;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    thd->last_nx_table = tables->real_name;
 | 
						|
    thd->last_nx_db = tables->db;
 | 
						|
    if(fetch_nx_table(thd, &glob_mi))
 | 
						|
      // fetch_nx_table is responsible for sending
 | 
						|
      // the error
 | 
						|
      {
 | 
						|
	res = 0;
 | 
						|
	thd->net.no_send_ok = 0; // easier to do it here
 | 
						|
	// this way we make sure that when we are done, we are clean
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
    res = 0;
 | 
						|
    send_ok(&thd->net);
 | 
						|
    break;
 | 
						|
 | 
						|
  case SQLCOM_CREATE_TABLE:
 | 
						|
    if (!tables->db)
 | 
						|
      tables->db=thd->db;
 | 
						|
    if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege) ||
 | 
						|
	check_merge_table_access(thd, tables->db,
 | 
						|
				 (TABLE_LIST *)
 | 
						|
				 lex->create_info.merge_list.first))
 | 
						|
      goto error;				/* purecov: inspected */
 | 
						|
    if (grant_option)
 | 
						|
    {
 | 
						|
      /* Check that the first table has CREATE privilege */
 | 
						|
      TABLE_LIST *tmp_table_list=tables->next;
 | 
						|
      tables->next=0;
 | 
						|
      bool error=check_grant(thd,CREATE_ACL,tables);
 | 
						|
      tables->next=tmp_table_list;
 | 
						|
      if (error)
 | 
						|
	goto error;
 | 
						|
    }
 | 
						|
    if (strlen(tables->name) > NAME_LEN)
 | 
						|
    {
 | 
						|
      net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->name);
 | 
						|
      res=0;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    if (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))
 | 
						|
      {
 | 
						|
	net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
 | 
						|
	DBUG_VOID_RETURN;
 | 
						|
      }
 | 
						|
      if (tables->next)
 | 
						|
      {
 | 
						|
	if (check_table_access(thd, SELECT_ACL, tables->next))
 | 
						|
	  goto error;				// 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->select_limit= HA_POS_ERROR;		// No limit
 | 
						|
 | 
						|
      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,
 | 
						|
                           lex->ftfunc_list,
 | 
						|
			   (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;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	  res= -1;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    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 (!res)
 | 
						|
	send_ok(&thd->net);
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case SQLCOM_CREATE_INDEX:
 | 
						|
    if (!tables->db)
 | 
						|
      tables->db=thd->db;
 | 
						|
    if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege))
 | 
						|
      goto error; /* purecov: inspected */
 | 
						|
    if (grant_option && check_grant(thd,INDEX_ACL,tables))
 | 
						|
      goto error;
 | 
						|
    res = mysql_create_index(thd, tables, lex->key_list);
 | 
						|
    break;
 | 
						|
 | 
						|
  case SQLCOM_SLAVE_START:
 | 
						|
    start_slave(thd);
 | 
						|
    break;
 | 
						|
  case SQLCOM_SLAVE_STOP:
 | 
						|
    stop_slave(thd);
 | 
						|
    break;
 | 
						|
 | 
						|
  case SQLCOM_ALTER_TABLE:
 | 
						|
#if defined(DONT_ALLOW_SHOW_COMMANDS)
 | 
						|
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
 | 
						|
    break;
 | 
						|
#else
 | 
						|
    {
 | 
						|
      uint priv=0;
 | 
						|
      if (lex->name && strlen(lex->name) > NAME_LEN)
 | 
						|
      {
 | 
						|
	net_printf(&thd->net,ER_WRONG_TABLE_NAME,lex->name);
 | 
						|
	res=0;
 | 
						|
	break;
 | 
						|
      }
 | 
						|
      if (!tables->db)
 | 
						|
	tables->db=thd->db;
 | 
						|
      if (!lex->db)
 | 
						|
	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_merge_table_access(thd, tables->db, 
 | 
						|
				   (TABLE_LIST *)
 | 
						|
				   lex->create_info.merge_list.first))
 | 
						|
	goto error;				/* purecov: inspected */
 | 
						|
      if (!tables->db)
 | 
						|
	tables->db=thd->db;
 | 
						|
      if (grant_option)
 | 
						|
      {
 | 
						|
	if (check_grant(thd,ALTER_ACL,tables))
 | 
						|
	  goto error;
 | 
						|
	if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
 | 
						|
	{					// Rename of table
 | 
						|
	  TABLE_LIST tmp_table;
 | 
						|
	  bzero((char*) &tmp_table,sizeof(tmp_table));
 | 
						|
	  tmp_table.real_name=lex->name;
 | 
						|
	  tmp_table.db=lex->db;
 | 
						|
	  tmp_table.grant.privilege=priv;
 | 
						|
	  if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables))
 | 
						|
	    goto error;
 | 
						|
	}
 | 
						|
      }
 | 
						|
      /* ALTER TABLE ends previous transaction */
 | 
						|
      if (end_active_trans(thd))
 | 
						|
	res= -1;
 | 
						|
      else
 | 
						|
	res= mysql_alter_table(thd, 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);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
  case SQLCOM_RENAME_TABLE:
 | 
						|
  {
 | 
						|
    TABLE_LIST *table;
 | 
						|
    if (check_db_used(thd,tables))
 | 
						|
      goto error;
 | 
						|
    for (table=tables ; table ; table=table->next->next)
 | 
						|
    {
 | 
						|
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
 | 
						|
		       &table->grant.privilege) ||
 | 
						|
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next->db,
 | 
						|
		       &table->next->grant.privilege))
 | 
						|
	goto error;
 | 
						|
      if (grant_option)
 | 
						|
      {
 | 
						|
	TABLE_LIST old_list,new_list;
 | 
						|
	old_list=table[0];
 | 
						|
	new_list=table->next[0];
 | 
						|
	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) &&
 | 
						|
	     check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list)))
 | 
						|
	  goto error;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (mysql_rename_tables(thd,tables))
 | 
						|
      res= -1;
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case SQLCOM_SHOW_BINLOGS:
 | 
						|
#ifdef DONT_ALLOW_SHOW_COMMANDS
 | 
						|
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
 | 
						|
    DBUG_VOID_RETURN;
 | 
						|
#else
 | 
						|
    {
 | 
						|
      if(check_access(thd, PROCESS_ACL, any_db))
 | 
						|
	goto error;
 | 
						|
      res = show_binlogs(thd);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
#endif    
 | 
						|
  case SQLCOM_SHOW_CREATE:
 | 
						|
#ifdef DONT_ALLOW_SHOW_COMMANDS
 | 
						|
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
 | 
						|
    DBUG_VOID_RETURN;
 | 
						|
#else
 | 
						|
    {
 | 
						|
      if (check_db_used(thd, tables) ||
 | 
						|
	  check_access(thd, SELECT_ACL | EXTRA_ACL, tables->db,
 | 
						|
		       &tables->grant.privilege))
 | 
						|
	goto error;
 | 
						|
      res = mysqld_show_create(thd, tables);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
#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;
 | 
						|
    }
 | 
						|
  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;
 | 
						|
    }
 | 
						|
  case SQLCOM_ANALYZE:
 | 
						|
  {
 | 
						|
    if (check_db_used(thd,tables) ||
 | 
						|
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
 | 
						|
      goto error; /* purecov: inspected */
 | 
						|
    res = mysql_analyze_table(thd, tables, &lex->check_opt);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  case SQLCOM_OPTIMIZE:
 | 
						|
  {
 | 
						|
    HA_CREATE_INFO create_info;
 | 
						|
    if (check_db_used(thd,tables) ||
 | 
						|
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
 | 
						|
      goto error; /* purecov: inspected */
 | 
						|
    if (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC))
 | 
						|
    {
 | 
						|
      /* Use ALTER TABLE */
 | 
						|
      lex->create_list.empty();
 | 
						|
      lex->key_list.empty();
 | 
						|
      lex->col_list.empty();
 | 
						|
      lex->drop_list.empty();
 | 
						|
      lex->alter_list.empty();
 | 
						|
      bzero((char*) &create_info,sizeof(create_info));
 | 
						|
      create_info.db_type=DB_TYPE_DEFAULT;
 | 
						|
      create_info.row_type=ROW_TYPE_DEFAULT;
 | 
						|
      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);
 | 
						|
    }
 | 
						|
    else
 | 
						|
      res = mysql_optimize_table(thd, tables, &lex->check_opt);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case SQLCOM_UPDATE:
 | 
						|
    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 (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);
 | 
						|
 | 
						|
#ifdef DELETE_ITEMS
 | 
						|
    delete lex->where;
 | 
						|
#endif
 | 
						|
    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,
 | 
						|
		       lex->lock_option);
 | 
						|
    break;
 | 
						|
  case SQLCOM_REPLACE:
 | 
						|
    if (check_access(thd,INSERT_ACL | UPDATE_ACL | DELETE_ACL,
 | 
						|
		     tables->db,&tables->grant.privilege))
 | 
						|
      goto error; /* purecov: inspected */
 | 
						|
    if (grant_option && check_grant(thd,INSERT_ACL | UPDATE_ACL | DELETE_ACL,
 | 
						|
				    tables))
 | 
						|
 | 
						|
      goto error;
 | 
						|
    res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
 | 
						|
		       DUP_REPLACE,
 | 
						|
		       lex->lock_option);
 | 
						|
    break;
 | 
						|
  case SQLCOM_REPLACE_SELECT:
 | 
						|
  case SQLCOM_INSERT_SELECT:
 | 
						|
  {
 | 
						|
    // Check that we have modify privileges for the first table and
 | 
						|
    // select privileges for the rest
 | 
						|
    uint privilege= (lex->sql_command == SQLCOM_INSERT_SELECT ?
 | 
						|
		     INSERT_ACL : INSERT_ACL | UPDATE_ACL | DELETE_ACL);
 | 
						|
    TABLE_LIST *save_next=tables->next;
 | 
						|
    tables->next=0;
 | 
						|
    if (check_access(thd, privilege,
 | 
						|
		     tables->db,&tables->grant.privilege) ||
 | 
						|
	(grant_option && check_grant(thd, privilege, tables)))
 | 
						|
      goto error;
 | 
						|
    tables->next=save_next;
 | 
						|
    if ((res=check_table_access(thd, SELECT_ACL, save_next)))
 | 
						|
      goto error;
 | 
						|
 | 
						|
    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->select_limit= HA_POS_ERROR;		// No limit
 | 
						|
 | 
						|
    if (check_dup(thd,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
 | 
						|
    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,
 | 
						|
                         lex->ftfunc_list,
 | 
						|
			 (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;
 | 
						|
    }
 | 
						|
#ifdef DELETE_ITEMS
 | 
						|
    delete lex->having;
 | 
						|
    delete lex->where;
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case SQLCOM_DELETE:
 | 
						|
  case SQLCOM_TRUNCATE:
 | 
						|
  {
 | 
						|
    if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
 | 
						|
      goto error; /* purecov: inspected */
 | 
						|
    if (grant_option && check_grant(thd,DELETE_ACL,tables))
 | 
						|
      goto error;
 | 
						|
    // Set privilege for the WHERE clause
 | 
						|
    tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
 | 
						|
    /* TRUNCATE ends previous transaction */
 | 
						|
    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);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case SQLCOM_DROP_TABLE:
 | 
						|
    {
 | 
						|
      if (check_table_access(thd,DROP_ACL,tables))
 | 
						|
	goto error;				/* purecov: inspected */
 | 
						|
      res = mysql_rm_table(thd,tables,lex->drop_if_exists);
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case SQLCOM_DROP_INDEX:
 | 
						|
    if (!tables->db)
 | 
						|
      tables->db=thd->db;
 | 
						|
    if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege))
 | 
						|
      goto error;				/* purecov: inspected */
 | 
						|
    if (grant_option && check_grant(thd,INDEX_ACL,tables))
 | 
						|
      goto error;
 | 
						|
    res = mysql_drop_index(thd, tables, lex->drop_list);
 | 
						|
    break;
 | 
						|
  case SQLCOM_SHOW_DATABASES:
 | 
						|
#if defined(DONT_ALLOW_SHOW_COMMANDS)
 | 
						|
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
 | 
						|
    DBUG_VOID_RETURN;
 | 
						|
#else
 | 
						|
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
 | 
						|
	check_access(thd,PROCESS_ACL,any_db))
 | 
						|
      goto error;
 | 
						|
    res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
 | 
						|
    break;
 | 
						|
#endif
 | 
						|
  case SQLCOM_SHOW_PROCESSLIST:
 | 
						|
    if (!thd->priv_user[0] && check_access(thd,PROCESS_ACL,any_db))
 | 
						|
      break;
 | 
						|
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
 | 
						|
			  thd->priv_user,lex->verbose);
 | 
						|
    break;
 | 
						|
  case SQLCOM_SHOW_STATUS:
 | 
						|
    res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars);
 | 
						|
    break;
 | 
						|
  case SQLCOM_SHOW_VARIABLES:
 | 
						|
    res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
 | 
						|
		     init_vars);
 | 
						|
    break;
 | 
						|
  case SQLCOM_SHOW_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;
 | 
						|
      if (!db)
 | 
						|
      {
 | 
						|
	send_error(&thd->net,ER_NO_DB_ERROR);	/* purecov: inspected */
 | 
						|
	goto error;				/* purecov: inspected */
 | 
						|
      }
 | 
						|
      remove_escape(db);				// Fix escaped '_'
 | 
						|
      if (strlen(db) > NAME_LEN)
 | 
						|
      {
 | 
						|
	net_printf(&thd->net,ER_WRONG_DB_NAME, db);
 | 
						|
	goto error;
 | 
						|
      }
 | 
						|
      if (check_access(thd,SELECT_ACL,db,&thd->col_access))
 | 
						|
	goto error;				/* purecov: inspected */
 | 
						|
      /* grant is checked in mysqld_show_tables */
 | 
						|
      if (lex->options & SELECT_DESCRIBE)
 | 
						|
      res= mysqld_extend_show_tables(thd,db,
 | 
						|
				     (lex->wild ? lex->wild->ptr() : NullS));
 | 
						|
      else
 | 
						|
	res= mysqld_show_tables(thd,db,
 | 
						|
				(lex->wild ? lex->wild->ptr() : NullS));
 | 
						|
      break;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
  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)
 | 
						|
      {
 | 
						|
	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;
 | 
						|
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
 | 
						|
	goto error;
 | 
						|
      res= mysqld_show_fields(thd,tables,
 | 
						|
			      (lex->wild ? lex->wild->ptr() : NullS));
 | 
						|
      break;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
  case SQLCOM_SHOW_KEYS:
 | 
						|
#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)
 | 
						|
      {
 | 
						|
	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,db,&thd->col_access))
 | 
						|
	goto error; /* purecov: inspected */
 | 
						|
      tables->grant.privilege=thd->col_access;
 | 
						|
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
 | 
						|
	goto error;
 | 
						|
      res= mysqld_show_keys(thd,tables);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
  case SQLCOM_CHANGE_DB:
 | 
						|
    mysql_change_db(thd,lex->db);
 | 
						|
    break;
 | 
						|
  case SQLCOM_LOAD:
 | 
						|
  {
 | 
						|
    uint privilege= (lex->duplicates == DUP_REPLACE ?
 | 
						|
		     INSERT_ACL | UPDATE_ACL | DELETE_ACL : INSERT_ACL);
 | 
						|
    if (!(lex->local_file && (thd->client_capabilities & CLIENT_LOCAL_FILES)))
 | 
						|
    {
 | 
						|
      if (check_access(thd,privilege | FILE_ACL,tables->db))
 | 
						|
	goto error;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
 | 
						|
	 grant_option && check_grant(thd,privilege,tables))
 | 
						|
	goto error;
 | 
						|
    }
 | 
						|
    res=mysql_load(thd, lex->exchange, tables, lex->field_list,
 | 
						|
		   lex->duplicates, (bool) lex->local_file, lex->lock_option);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case SQLCOM_SET_OPTION:
 | 
						|
  {
 | 
						|
    uint org_options=thd->options;
 | 
						|
    thd->options=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;
 | 
						|
    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_AUTO_COMMIT)
 | 
						|
    {
 | 
						|
      if (!(org_options & OPTION_AUTO_COMMIT))
 | 
						|
      {
 | 
						|
	/* We changed to auto_commit mode */
 | 
						|
	thd->options&= ~(ulong) (OPTION_BEGIN);
 | 
						|
	thd->server_status|= SERVER_STATUS_AUTOCOMMIT;
 | 
						|
	if (ha_commit(thd))
 | 
						|
	{
 | 
						|
	  res= -1;
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
      }
 | 
						|
      else
 | 
						|
	thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT;
 | 
						|
    }
 | 
						|
    send_ok(&thd->net);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case SQLCOM_UNLOCK_TABLES:
 | 
						|
    if (thd->locked_tables)
 | 
						|
    {
 | 
						|
      thd->lock=thd->locked_tables;
 | 
						|
      thd->locked_tables=0;			// Will be automaticly closed
 | 
						|
    }
 | 
						|
    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);
 | 
						|
    }
 | 
						|
    send_ok(&thd->net);
 | 
						|
    break;
 | 
						|
  case SQLCOM_LOCK_TABLES:
 | 
						|
    if (thd->locked_tables)
 | 
						|
    {
 | 
						|
      thd->lock=thd->locked_tables;
 | 
						|
      thd->locked_tables=0;			// Will be automaticly closed
 | 
						|
      close_thread_tables(thd);
 | 
						|
    }
 | 
						|
    if (check_db_used(thd,tables))
 | 
						|
      goto error;
 | 
						|
    thd->in_lock_tables=1;
 | 
						|
    if (!(res=open_and_lock_tables(thd,tables)))
 | 
						|
    {
 | 
						|
      thd->locked_tables=thd->lock;
 | 
						|
      thd->lock=0;
 | 
						|
      send_ok(&thd->net);
 | 
						|
    }
 | 
						|
    thd->in_lock_tables=0;
 | 
						|
    break;
 | 
						|
  case SQLCOM_CREATE_DB:
 | 
						|
    {
 | 
						|
      if (check_access(thd,CREATE_ACL,lex->name,0,1))
 | 
						|
	break;
 | 
						|
      mysql_create_db(thd,lex->name,lex->create_info.options);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  case SQLCOM_DROP_DB:
 | 
						|
    {
 | 
						|
      if (check_access(thd,DROP_ACL,lex->name,0,1))
 | 
						|
	break;
 | 
						|
      mysql_rm_db(thd,lex->name,lex->drop_if_exists);
 | 
						|
      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);
 | 
						|
#else
 | 
						|
    res= -1;
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  case SQLCOM_DROP_FUNCTION:
 | 
						|
    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);
 | 
						|
#else
 | 
						|
    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_FLUSH:
 | 
						|
  case SQLCOM_RESET:
 | 
						|
    if (check_access(thd,RELOAD_ACL,any_db) || check_db_used(thd, tables))
 | 
						|
      goto error;
 | 
						|
    if (reload_acl_and_cache(thd, lex->type, tables))
 | 
						|
      send_error(&thd->net,0);
 | 
						|
    else
 | 
						|
      send_ok(&thd->net);
 | 
						|
    break;
 | 
						|
  case SQLCOM_KILL:
 | 
						|
    kill_one_thread(thd,lex->thread_id);
 | 
						|
    break;
 | 
						|
  case SQLCOM_SHOW_GRANTS:
 | 
						|
    res=0;
 | 
						|
    if ((thd->user && !strcmp(thd->user,lex->grant_user->user.str)) ||
 | 
						|
	!(check_access(thd, SELECT_ACL, "mysql")))
 | 
						|
    {
 | 
						|
      res = mysql_show_grants(thd,lex->grant_user);
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case SQLCOM_BEGIN:
 | 
						|
    thd->options|= OPTION_BEGIN;
 | 
						|
    thd->server_status|= SERVER_STATUS_IN_TRANS;
 | 
						|
    send_ok(&thd->net);
 | 
						|
    break;
 | 
						|
  case SQLCOM_COMMIT:
 | 
						|
    /*
 | 
						|
      We don't use end_active_trans() here to ensure that this works
 | 
						|
      even if there is a problem with the OPTION_AUTO_COMMIT flag
 | 
						|
      (Which of course should never happen...)
 | 
						|
    */
 | 
						|
    thd->options&= ~(ulong) (OPTION_BEGIN);
 | 
						|
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
 | 
						|
    if (!ha_commit(thd))
 | 
						|
      send_ok(&thd->net);
 | 
						|
    else
 | 
						|
      res= -1;
 | 
						|
    break;
 | 
						|
  case SQLCOM_ROLLBACK:
 | 
						|
    thd->options&= ~(ulong) (OPTION_BEGIN);
 | 
						|
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
 | 
						|
    if (!ha_rollback(thd))
 | 
						|
      send_ok(&thd->net);
 | 
						|
    else
 | 
						|
      res= -1;
 | 
						|
    break;
 | 
						|
  default:					/* Impossible */
 | 
						|
    send_ok(&thd->net);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  thd->proc_info="query end";			// QQ
 | 
						|
  if (res < 0)
 | 
						|
    send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0);
 | 
						|
 | 
						|
error:
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/****************************************************************************
 | 
						|
** Get the user (global) and database privileges for all used tables
 | 
						|
** Returns true (error) if we can't get the privileges and we don't use
 | 
						|
** table/column grants.
 | 
						|
** The idea of EXTRA_ACL is that one will be granted access to the table if
 | 
						|
** one has the asked privilege on any column combination of the table; For
 | 
						|
** example to be able to check a table one needs to have SELECT privilege on
 | 
						|
** any column of the table.
 | 
						|
****************************************************************************/
 | 
						|
 | 
						|
bool
 | 
						|
check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
 | 
						|
	     bool no_grant)
 | 
						|
{
 | 
						|
  uint db_access,dummy;
 | 
						|
  if (save_priv)
 | 
						|
    *save_priv=0;
 | 
						|
  else
 | 
						|
    save_priv= &dummy;
 | 
						|
 | 
						|
  if (!db && !thd->db && !no_grant)
 | 
						|
  {
 | 
						|
    send_error(&thd->net,ER_NO_DB_ERROR);	/* purecov: tested */
 | 
						|
    return TRUE;				/* purecov: tested */
 | 
						|
  }
 | 
						|
 | 
						|
  if ((thd->master_access & want_access) == want_access)
 | 
						|
  {
 | 
						|
    *save_priv=thd->master_access;
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
  if ((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL) ||
 | 
						|
      ! db && no_grant)
 | 
						|
  {						// 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 */
 | 
						|
    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 */
 | 
						|
  else
 | 
						|
    db_access=thd->db_access;
 | 
						|
  want_access &= ~EXTRA_ACL;			// Remove SHOW attribute
 | 
						|
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
 | 
						|
  if (db_access == want_access ||
 | 
						|
      ((grant_option && !no_grant) && !(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 */
 | 
						|
  return TRUE;					/* purecov: tested */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
** Check the privilege for all used tables.  Table privileges are cached
 | 
						|
** in the table list for GRANT checking
 | 
						|
*/
 | 
						|
 | 
						|
static bool
 | 
						|
check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
 | 
						|
{
 | 
						|
  uint found=0,found_access=0;
 | 
						|
  TABLE_LIST *org_tables=tables;
 | 
						|
  for (; tables ; tables=tables->next)
 | 
						|
  {
 | 
						|
    if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
 | 
						|
	thd->db)
 | 
						|
      tables->grant.privilege= want_access;
 | 
						|
    else if (tables->db && tables->db == thd->db)
 | 
						|
    {
 | 
						|
      if (found && !grant_option)		// db already checked
 | 
						|
	tables->grant.privilege=found_access;
 | 
						|
      else
 | 
						|
      {
 | 
						|
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege))
 | 
						|
	  return TRUE;				// Access denied
 | 
						|
	found_access=tables->grant.privilege;
 | 
						|
	found=1;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege))
 | 
						|
      return TRUE;				// Access denied
 | 
						|
  }
 | 
						|
  if (grant_option)
 | 
						|
  {
 | 
						|
    want_access &= ~EXTRA_ACL;			// Remove SHOW attribute
 | 
						|
    return check_grant(thd,want_access,org_tables);
 | 
						|
  }
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static bool check_db_used(THD *thd,TABLE_LIST *tables)
 | 
						|
{
 | 
						|
  for (; tables ; tables=tables->next)
 | 
						|
  {
 | 
						|
    if (!tables->db)
 | 
						|
    {
 | 
						|
      if (!(tables->db=thd->db))
 | 
						|
      {
 | 
						|
	send_error(&thd->net,ER_NO_DB_ERROR);	/* purecov: tested */
 | 
						|
	return TRUE;				/* purecov: tested */
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list)
 | 
						|
{
 | 
						|
  int error=0;
 | 
						|
  if (table_list)
 | 
						|
  {
 | 
						|
    /* Force all tables to use the current database */
 | 
						|
    TABLE_LIST *tmp;
 | 
						|
    for (tmp=table_list; tmp ; tmp=tmp->next)
 | 
						|
      tmp->db=db;
 | 
						|
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
 | 
						|
			     table_list);
 | 
						|
  }
 | 
						|
  return error;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/****************************************************************************
 | 
						|
	Check stack size; Send error if there isn't enough stack to continue
 | 
						|
****************************************************************************/
 | 
						|
 | 
						|
#if STACK_DIRECTION < 0
 | 
						|
#define used_stack(A,B) (long) (A - B)
 | 
						|
#else
 | 
						|
#define used_stack(A,B) (long) (B - A)
 | 
						|
#endif
 | 
						|
 | 
						|
bool check_stack_overrun(THD *thd,char *buf __attribute__((unused)))
 | 
						|
{
 | 
						|
  long stack_used;
 | 
						|
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
 | 
						|
      (long) thread_stack_min)
 | 
						|
  {
 | 
						|
    sprintf(errbuff[0],ER(ER_STACK_OVERRUN),stack_used,thread_stack);
 | 
						|
    my_message(ER_STACK_OVERRUN,errbuff[0],MYF(0));
 | 
						|
    thd->fatal_error=1;
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
#define MY_YACC_INIT 1000			// Start with big alloc
 | 
						|
#define MY_YACC_MAX  32000			// Because of 'short'
 | 
						|
 | 
						|
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize)
 | 
						|
{
 | 
						|
  LEX	*lex=current_lex;
 | 
						|
  int  old_info=0;
 | 
						|
  if ((uint) *yystacksize >= MY_YACC_MAX)
 | 
						|
    return 1;
 | 
						|
  if (!lex->yacc_yyvs)
 | 
						|
    old_info= *yystacksize;
 | 
						|
  *yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX);
 | 
						|
  if (!(lex->yacc_yyvs= (char*)
 | 
						|
	my_realloc((gptr) lex->yacc_yyvs,
 | 
						|
		   *yystacksize*sizeof(**yyvs),
 | 
						|
		   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
 | 
						|
      !(lex->yacc_yyss= (char*)
 | 
						|
	my_realloc((gptr) lex->yacc_yyss,
 | 
						|
		   *yystacksize*sizeof(**yyss),
 | 
						|
		   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
 | 
						|
    return 1;
 | 
						|
  if (old_info)
 | 
						|
  {						// Copy old info from stack
 | 
						|
    memcpy(lex->yacc_yyss, (gptr) *yyss, old_info*sizeof(**yyss));
 | 
						|
    memcpy(lex->yacc_yyvs, (gptr) *yyvs, old_info*sizeof(**yyvs));
 | 
						|
  }
 | 
						|
  *yyss=(short*) lex->yacc_yyss;
 | 
						|
  *yyvs=(YYSTYPE*) lex->yacc_yyvs;
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/****************************************************************************
 | 
						|
	Initialize global thd variables neaded for query
 | 
						|
****************************************************************************/
 | 
						|
 | 
						|
static void
 | 
						|
mysql_init_query(THD *thd)
 | 
						|
{
 | 
						|
  DBUG_ENTER("mysql_init_query");
 | 
						|
  thd->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->fatal_error=0;				// Safety
 | 
						|
  thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
 | 
						|
  thd->sent_row_count=0;
 | 
						|
  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;
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
mysql_parse(THD *thd,char *inBuf,uint length)
 | 
						|
{
 | 
						|
  DBUG_ENTER("mysql_parse");
 | 
						|
 | 
						|
  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);
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
inline static void
 | 
						|
link_in_list(SQL_LIST *list,byte *element,byte **next)
 | 
						|
{
 | 
						|
  list->elements++;
 | 
						|
  (*list->next)=element;
 | 
						|
  list->next=next;
 | 
						|
  *next=0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*****************************************************************************
 | 
						|
** Store field definition for create
 | 
						|
** Return 0 if ok
 | 
						|
******************************************************************************/
 | 
						|
 | 
						|
bool add_field_to_list(char *field_name, enum_field_types type,
 | 
						|
		       char *length, char *decimals,
 | 
						|
		       uint type_modifier, Item *default_value,char *change,
 | 
						|
		       TYPELIB *interval)
 | 
						|
{
 | 
						|
  register create_field *new_field;
 | 
						|
  THD	*thd=current_thd;
 | 
						|
  LEX  *lex= &thd->lex;
 | 
						|
  uint allowed_type_modifier=0;
 | 
						|
  DBUG_ENTER("add_field_to_list");
 | 
						|
 | 
						|
  if (strlen(field_name) > NAME_LEN)
 | 
						|
  {
 | 
						|
    net_printf(&thd->net, 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->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->col_list));
 | 
						|
    lex->col_list.empty();
 | 
						|
  }
 | 
						|
 | 
						|
  if (default_value && default_value->type() == Item::NULL_ITEM)
 | 
						|
  {
 | 
						|
    if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
 | 
						|
	NOT_NULL_FLAG)
 | 
						|
    {
 | 
						|
      net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
 | 
						|
      DBUG_RETURN(1);
 | 
						|
    }
 | 
						|
    default_value=0;
 | 
						|
  }
 | 
						|
  if (!(new_field=new create_field()))
 | 
						|
    DBUG_RETURN(1);
 | 
						|
  new_field->field=0;
 | 
						|
  new_field->field_name=field_name;
 | 
						|
  new_field->def= (type_modifier & AUTO_INCREMENT_FLAG ? 0 : default_value);
 | 
						|
  new_field->flags= type_modifier;
 | 
						|
  new_field->unireg_check= (type_modifier & AUTO_INCREMENT_FLAG ?
 | 
						|
			    Field::NEXT_NUMBER : Field::NONE);
 | 
						|
  new_field->decimals= decimals ? (uint) set_zone(atoi(decimals),0,
 | 
						|
						  NOT_FIXED_DEC-1) : 0;
 | 
						|
  new_field->sql_type=type;
 | 
						|
  new_field->length=0;
 | 
						|
  new_field->change=change;
 | 
						|
  new_field->interval=0;
 | 
						|
  new_field->pack_length=0;
 | 
						|
  if (length)
 | 
						|
    if (!(new_field->length= (uint) atoi(length)))
 | 
						|
      length=0; /* purecov: inspected */
 | 
						|
  uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
 | 
						|
 | 
						|
  if (new_field->length && new_field->decimals &&
 | 
						|
      new_field->length < new_field->decimals+2 &&
 | 
						|
      new_field->decimals != NOT_FIXED_DEC)
 | 
						|
    new_field->length=new_field->decimals+2; /* purecov: inspected */
 | 
						|
 | 
						|
  switch (type) {
 | 
						|
  case FIELD_TYPE_TINY:
 | 
						|
    if (!length) new_field->length=3+sign_len;
 | 
						|
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_SHORT:
 | 
						|
    if (!length) new_field->length=5+sign_len;
 | 
						|
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_INT24:
 | 
						|
    if (!length) new_field->length=8+sign_len;
 | 
						|
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_LONG:
 | 
						|
    if (!length) new_field->length=10+sign_len;
 | 
						|
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_LONGLONG:
 | 
						|
    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:
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_DECIMAL:
 | 
						|
    if (!length)
 | 
						|
      new_field->length = 10;			// Default length for DECIMAL
 | 
						|
    new_field->length+=sign_len;
 | 
						|
    if (new_field->decimals)
 | 
						|
      new_field->length++;
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_BLOB:
 | 
						|
  case FIELD_TYPE_TINY_BLOB:
 | 
						|
  case FIELD_TYPE_LONG_BLOB:
 | 
						|
  case FIELD_TYPE_MEDIUM_BLOB:
 | 
						|
    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 */
 | 
						|
	DBUG_RETURN(1); /* purecov: inspected */
 | 
						|
      }
 | 
						|
      new_field->def=0;
 | 
						|
    }
 | 
						|
    new_field->flags|=BLOB_FLAG;
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_YEAR:
 | 
						|
    if (!length || new_field->length != 2)
 | 
						|
      new_field->length=4;			// Default length
 | 
						|
    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_FLOAT:
 | 
						|
    /* change FLOAT(precision) to FLOAT or DOUBLE */
 | 
						|
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
 | 
						|
    if (length && !decimals)
 | 
						|
    {
 | 
						|
      uint tmp_length=new_field->length;
 | 
						|
      if (tmp_length > PRECISION_FOR_DOUBLE)
 | 
						|
      {
 | 
						|
	net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name);
 | 
						|
	DBUG_RETURN(1);
 | 
						|
      }
 | 
						|
      else if (tmp_length > PRECISION_FOR_FLOAT)
 | 
						|
      {
 | 
						|
	new_field->sql_type=FIELD_TYPE_DOUBLE;
 | 
						|
	new_field->length=DBL_DIG+7;			// -[digits].E+###
 | 
						|
      }
 | 
						|
      else
 | 
						|
	new_field->length=FLT_DIG+6;			// -[digits].E+##
 | 
						|
      new_field->decimals= NOT_FIXED_DEC;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    if (!length)
 | 
						|
    {
 | 
						|
      new_field->length =  FLT_DIG+6;
 | 
						|
      new_field->decimals= NOT_FIXED_DEC;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_DOUBLE:
 | 
						|
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
 | 
						|
    if (!length)
 | 
						|
    {
 | 
						|
      new_field->length = DBL_DIG+7;
 | 
						|
      new_field->decimals=NOT_FIXED_DEC;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_TIMESTAMP:
 | 
						|
    if (!length)
 | 
						|
      new_field->length= 14;			// Full date YYYYMMDDHHMMSS
 | 
						|
    else
 | 
						|
    {
 | 
						|
      new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
 | 
						|
      new_field->length= min(new_field->length,14); /* purecov: inspected */
 | 
						|
    }
 | 
						|
    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG | NOT_NULL_FLAG;
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_DATE:				// Old date type
 | 
						|
    if (protocol_version != PROTOCOL_VERSION-1)
 | 
						|
      new_field->sql_type=FIELD_TYPE_NEWDATE;
 | 
						|
    /* fall trough */
 | 
						|
  case FIELD_TYPE_NEWDATE:
 | 
						|
    new_field->length=10;
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_TIME:
 | 
						|
    new_field->length=10;
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_DATETIME:
 | 
						|
    new_field->length=19;
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_SET:
 | 
						|
    {
 | 
						|
      if (interval->count > sizeof(longlong)*8)
 | 
						|
      {
 | 
						|
	net_printf(&thd->net,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
 | 
						|
	DBUG_RETURN(1);				/* purecov: inspected */
 | 
						|
      }
 | 
						|
      new_field->pack_length=(interval->count+7)/8;
 | 
						|
      if (new_field->pack_length > 4)
 | 
						|
	new_field->pack_length=8;
 | 
						|
      new_field->interval=interval;
 | 
						|
      new_field->length=0;
 | 
						|
      for (const char **pos=interval->type_names; *pos ; pos++)
 | 
						|
	new_field->length+=(uint) strlen(*pos)+1;
 | 
						|
      new_field->length--;
 | 
						|
      set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
 | 
						|
      if (default_value)
 | 
						|
      {
 | 
						|
	thd->cuted_fields=0;
 | 
						|
	String str,*res;
 | 
						|
	res=default_value->val_str(&str);
 | 
						|
	(void) find_set(interval,res->ptr(),res->length());
 | 
						|
	if (thd->cuted_fields)
 | 
						|
	{
 | 
						|
	  net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
 | 
						|
	  DBUG_RETURN(1);
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case FIELD_TYPE_ENUM:
 | 
						|
    {
 | 
						|
      new_field->interval=interval;
 | 
						|
      new_field->pack_length=interval->count < 256 ? 1 : 2; // Should be safe
 | 
						|
      new_field->length=(uint) strlen(interval->type_names[0]);
 | 
						|
      for (const char **pos=interval->type_names+1; *pos ; pos++)
 | 
						|
      {
 | 
						|
	uint length=(uint) strlen(*pos);
 | 
						|
	set_if_bigger(new_field->length,length);
 | 
						|
      }
 | 
						|
      set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
 | 
						|
      if (default_value)
 | 
						|
      {
 | 
						|
	String str,*res;
 | 
						|
	res=default_value->val_str(&str);
 | 
						|
	if (!find_enum(interval,res->ptr(),res->length()))
 | 
						|
	{
 | 
						|
	  net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
 | 
						|
	  DBUG_RETURN(1);
 | 
						|
	}
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (new_field->length >= MAX_FIELD_WIDTH ||
 | 
						|
      (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
 | 
						|
       type != FIELD_TYPE_STRING))
 | 
						|
  {
 | 
						|
    net_printf(&thd->net,ER_TOO_BIG_FIELDLENGTH,field_name,
 | 
						|
	       MAX_FIELD_WIDTH-1);		/* 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);
 | 
						|
    DBUG_RETURN(1);
 | 
						|
  }
 | 
						|
  if (!new_field->pack_length)
 | 
						|
    new_field->pack_length=calc_pack_length(new_field->sql_type ==
 | 
						|
					    FIELD_TYPE_VAR_STRING ?
 | 
						|
					    FIELD_TYPE_STRING :
 | 
						|
					    new_field->sql_type,
 | 
						|
					    new_field->length);
 | 
						|
  lex->create_list.push_back(new_field);
 | 
						|
  lex->last_field=new_field;
 | 
						|
  DBUG_RETURN(0);
 | 
						|
}
 | 
						|
 | 
						|
/* Store position for column in ALTER TABLE .. ADD column */
 | 
						|
 | 
						|
void store_position_for_column(const char *name)
 | 
						|
{
 | 
						|
  current_lex->last_field->after=my_const_cast(char*) (name);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
add_proc_to_list(Item *item)
 | 
						|
{
 | 
						|
  ORDER *order;
 | 
						|
  Item	**item_ptr;
 | 
						|
 | 
						|
  if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
 | 
						|
    return 1;
 | 
						|
  item_ptr = (Item**) (order+1);
 | 
						|
  *item_ptr= item;
 | 
						|
  order->item=item_ptr;
 | 
						|
  order->free_me=0;
 | 
						|
  link_in_list(¤t_lex->proc_list,(byte*) order,(byte**) &order->next);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Fix escaping of _, % and \ in database and table names (for ODBC) */
 | 
						|
 | 
						|
static void remove_escape(char *name)
 | 
						|
{
 | 
						|
  char *to;
 | 
						|
#ifdef USE_MB
 | 
						|
  char *strend=name+(uint) strlen(name);
 | 
						|
#endif
 | 
						|
  for (to=name; *name ; 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)))
 | 
						|
    {
 | 
						|
	while (l--)
 | 
						|
	    *to++ = *name++;
 | 
						|
	name--;
 | 
						|
	continue;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    if (*name == '\\' && name[1])
 | 
						|
      name++;					// Skipp '\\'
 | 
						|
    *to++= *name;
 | 
						|
  }
 | 
						|
  *to=0;
 | 
						|
}
 | 
						|
 | 
						|
/****************************************************************************
 | 
						|
** save order by and tables in own lists
 | 
						|
****************************************************************************/
 | 
						|
 | 
						|
 | 
						|
bool add_to_list(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*))))
 | 
						|
    DBUG_RETURN(1);
 | 
						|
  item_ptr = (Item**) (order+1);
 | 
						|
  *item_ptr=item;
 | 
						|
  order->item= item_ptr;
 | 
						|
  order->asc = asc;
 | 
						|
  order->free_me=0;
 | 
						|
  order->used=0;
 | 
						|
  link_in_list(&list,(byte*) order,(byte**) &order->next);
 | 
						|
  DBUG_RETURN(0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
 | 
						|
			      bool updating,
 | 
						|
			      thr_lock_type flags,
 | 
						|
			      List<String> *use_index,
 | 
						|
			      List<String> *ignore_index
 | 
						|
			      )
 | 
						|
{
 | 
						|
  register TABLE_LIST *ptr;
 | 
						|
  THD	*thd=current_thd;
 | 
						|
  char *alias_str;
 | 
						|
  const char *current_db;
 | 
						|
  DBUG_ENTER("add_table_to_list");
 | 
						|
 | 
						|
  if (!table)
 | 
						|
    DBUG_RETURN(0);				// End of memory
 | 
						|
  alias_str= alias ? alias->str : table->table.str;
 | 
						|
  if (table->table.length > NAME_LEN ||
 | 
						|
      table->db.str && table->db.length > NAME_LEN ||
 | 
						|
      check_table_name(table->table.str,table->table.length))
 | 
						|
  {
 | 
						|
    net_printf(&thd->net,ER_WRONG_TABLE_NAME,table->table.str);
 | 
						|
    DBUG_RETURN(0);
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef FN_LOWER_CASE
 | 
						|
  if (!alias)					/* Alias is case sensitive */
 | 
						|
    if (!(alias_str=sql_strmake(alias_str,table->table.length)))
 | 
						|
      DBUG_RETURN(0);
 | 
						|
  if (lower_case_table_names)
 | 
						|
    casedn_str(table->table.str);
 | 
						|
#endif
 | 
						|
  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->name=alias_str;
 | 
						|
  ptr->lock_type=flags;
 | 
						|
  ptr->updating=updating;
 | 
						|
  if (use_index)
 | 
						|
    ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
 | 
						|
					       sizeof(*use_index));
 | 
						|
  if (ignore_index)
 | 
						|
    ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index,
 | 
						|
						   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 ;
 | 
						|
	 tables=tables->next)
 | 
						|
    {
 | 
						|
      if (!strcmp(alias_str,tables->name) &&
 | 
						|
	  !strcmp(ptr->db ? ptr->db : current_db,
 | 
						|
		  tables->db ? tables->db : current_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);
 | 
						|
  DBUG_RETURN(ptr);
 | 
						|
}
 | 
						|
 | 
						|
void add_join_on(TABLE_LIST *b,Item *expr)
 | 
						|
{
 | 
						|
  if (!b->on_expr)
 | 
						|
    b->on_expr=expr;
 | 
						|
  else
 | 
						|
  {
 | 
						|
    // This only happens if you have both a right and left join
 | 
						|
    b->on_expr=new Item_cond_and(b->on_expr,expr);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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(THD *thd,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))
 | 
						|
      return 1;
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
 | 
						|
{
 | 
						|
  bool result=0;
 | 
						|
 | 
						|
  select_errors=0;				/* Write if more errors */
 | 
						|
  // mysql_log.flush();				// Flush log
 | 
						|
  if (options & REFRESH_GRANT)
 | 
						|
  {
 | 
						|
    acl_reload();
 | 
						|
    grant_reload();
 | 
						|
  }
 | 
						|
  if (options & REFRESH_LOG)
 | 
						|
  {
 | 
						|
    mysql_log.new_file();
 | 
						|
    mysql_update_log.new_file();
 | 
						|
    mysql_bin_log.new_file();
 | 
						|
    mysql_slow_log.new_file();
 | 
						|
    if (ha_flush_logs())
 | 
						|
      result=1;
 | 
						|
  }
 | 
						|
  if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
 | 
						|
  {
 | 
						|
    if ((options & REFRESH_READ_LOCK) && thd && ! thd->global_read_lock)
 | 
						|
    {
 | 
						|
      thd->global_read_lock=1;
 | 
						|
      thread_safe_increment(global_read_lock,&LOCK_open);
 | 
						|
    }
 | 
						|
    result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
 | 
						|
  }
 | 
						|
  if (options & REFRESH_HOSTS)
 | 
						|
    hostname_cache_refresh();
 | 
						|
  if (options & REFRESH_STATUS)
 | 
						|
    refresh_status();
 | 
						|
  if (options & REFRESH_THREADS)
 | 
						|
    flush_thread_cache();
 | 
						|
  if (options & REFRESH_MASTER)
 | 
						|
    reset_master();
 | 
						|
  if (options & REFRESH_SLAVE)
 | 
						|
    reset_slave();
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void kill_one_thread(THD *thd, ulong id)
 | 
						|
{
 | 
						|
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
 | 
						|
  I_List_iterator<THD> it(threads);
 | 
						|
  THD *tmp;
 | 
						|
  uint error=ER_NO_SUCH_THREAD;
 | 
						|
  while ((tmp=it++))
 | 
						|
  {
 | 
						|
    if (tmp->thread_id == id)
 | 
						|
    {
 | 
						|
      if ((thd->master_access & PROCESS_ACL) ||
 | 
						|
	  !strcmp(thd->user,tmp->user))
 | 
						|
      {
 | 
						|
	thr_alarm_kill(tmp->real_id);
 | 
						|
	tmp->killed=1;
 | 
						|
	error=0;
 | 
						|
	if (tmp->mysys_var)
 | 
						|
	{
 | 
						|
	  pthread_mutex_lock(&tmp->mysys_var->mutex);
 | 
						|
	  if (!tmp->system_thread)		// Don't abort locks
 | 
						|
	    tmp->mysys_var->abort=1;
 | 
						|
	  if (tmp->mysys_var->current_mutex)
 | 
						|
	  {
 | 
						|
	    pthread_mutex_lock(tmp->mysys_var->current_mutex);
 | 
						|
	    pthread_cond_broadcast(tmp->mysys_var->current_cond);
 | 
						|
	    pthread_mutex_unlock(tmp->mysys_var->current_mutex);
 | 
						|
	  }
 | 
						|
	  pthread_mutex_unlock(&tmp->mysys_var->mutex);
 | 
						|
	}
 | 
						|
      }
 | 
						|
      else
 | 
						|
	error=ER_KILL_DENIED_ERROR;
 | 
						|
      break;					// Found thread
 | 
						|
    }
 | 
						|
  }
 | 
						|
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
 | 
						|
  if (!error)
 | 
						|
    send_ok(&thd->net);
 | 
						|
  else
 | 
						|
    net_printf(&thd->net,error,id);
 | 
						|
}
 | 
						|
 | 
						|
/* Clear most status variables */
 | 
						|
 | 
						|
static void refresh_status(void)
 | 
						|
{
 | 
						|
  pthread_mutex_lock(&THR_LOCK_keycache);
 | 
						|
  pthread_mutex_lock(&LOCK_status);
 | 
						|
  for (struct show_var_st *ptr=status_vars; ptr->name; ptr++)
 | 
						|
  {
 | 
						|
    if (ptr->type == SHOW_LONG)
 | 
						|
      *(ulong*) ptr->value=0;
 | 
						|
  }
 | 
						|
  pthread_mutex_unlock(&LOCK_status);
 | 
						|
  pthread_mutex_unlock(&THR_LOCK_keycache);
 | 
						|
}
 | 
						|
 |