sql_parse.cc
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:79k
- /* 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>
- #include <assert.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 int check_for_max_user_connections(const char *user, int u_length,
- const char *host);
- static void decrease_user_connections(const char *user, const char *host);
- static 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
- inline bool end_active_trans(THD *thd)
- {
- int error=0;
- if (thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))
- {
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- if (ha_commit(thd))
- error=1;
- }
- return error;
- }
- /*
- ** 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 (max_user_connections &&
- check_for_max_user_connections(user, strlen(user), thd->host))
- return -1;
- if (db && db[0])
- {
- bool error=test(mysql_change_db(thd,db));
- if (error)
- decrease_user_connections(thd->user,thd->host);
- return error;
- }
- else
- send_ok(net); // Ready to handle questions
- return 0; // ok
- }
- /*
- ** check for maximum allowable user connections
- ** if mysql server is started with corresponding
- ** variable that is greater then 0
- */
- static HASH hash_user_connections;
- static DYNAMIC_ARRAY user_conn_array;
- extern pthread_mutex_t LOCK_user_conn;
- struct user_conn {
- char *user;
- uint len, connections;
- };
- static byte* get_key_conn(user_conn *buff, uint *length,
- my_bool not_used __attribute__((unused)))
- {
- *length=buff->len;
- return (byte*) buff->user;
- }
- #define DEF_USER_COUNT 50
- static void free_user(struct user_conn *uc)
- {
- my_free((char*) uc,MYF(0));
- }
- void init_max_user_conn(void)
- {
- (void) hash_init(&hash_user_connections,DEF_USER_COUNT,0,0,
- (hash_get_key) get_key_conn, (void (*)(void*)) free_user,
- 0);
- }
- static int check_for_max_user_connections(const char *user, int u_length,
- const char *host)
- {
- int error=1;
- uint temp_len;
- char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
- struct user_conn *uc;
- if (!user)
- user="";
- if (!host)
- host="";
- DBUG_ENTER("check_for_max_user_connections");
- DBUG_PRINT("enter",("user: '%s' host: '%s'", user, host));
- temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
- NullS) - temp_user);
- (void) pthread_mutex_lock(&LOCK_user_conn);
- uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len);
- if (uc) /* user found ; check for no. of connections */
- {
- if (max_user_connections == (uint) uc->connections)
- {
- net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, temp_user);
- goto end;
- }
- uc->connections++;
- }
- else
- {
- /* the user is not found in the cache; Insert it */
- struct user_conn *uc= ((struct user_conn*)
- my_malloc(sizeof(struct user_conn) + temp_len+1,
- MYF(MY_WME)));
- if (!uc)
- {
- send_error(¤t_thd->net, 0, NullS); // Out of memory
- goto end;
- }
- uc->user=(char*) (uc+1);
- memcpy(uc->user,temp_user,temp_len+1);
- uc->len = temp_len;
- uc->connections = 1;
- if (hash_insert(&hash_user_connections, (byte*) uc))
- {
- my_free((char*) uc,0);
- send_error(¤t_thd->net, 0, NullS); // Out of memory
- goto end;
- }
- }
- error=0;
- end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- DBUG_RETURN(error);
- }
- static void decrease_user_connections(const char *user, const char *host)
- {
- char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
- int temp_len;
- struct user_conn *uc;
- if (!max_user_connections)
- return;
- if (!user)
- user="";
- if (!host)
- host="";
- DBUG_ENTER("decrease_user_connections");
- DBUG_PRINT("enter",("user: '%s' host: '%s'", user, host));
- temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
- NullS) - temp_user);
- (void) pthread_mutex_lock(&LOCK_user_conn);
- uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len);
- dbug_assert(uc != 0); // We should always find the user
- if (!uc)
- goto end; // Safety; Something went wrong
- if (! --uc->connections)
- {
- /* Last connection for user; Delete it */
- (void) hash_delete(&hash_user_connections,(byte*) uc);
- }
- end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- DBUG_VOID_RETURN;
- }
- void free_max_user_conn(void)
- {
- hash_free(&hash_user_connections);
- }
- /*
- ** 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[30];
- 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;
- {
- /* buff[] needs to big enough to hold the server_version variable */
- char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+32],*end;
- int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB;
- if (opt_using_transactions)
- client_flags|=CLIENT_TRANSACTIONS;
- #ifdef HAVE_COMPRESS
- client_flags |= CLIENT_COMPRESS;
- #endif /* HAVE_COMPRESS */
- 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_OPENSSL
- if (ssl_acceptor_fd)
- client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */
- /*
- * Without SSL the handshake consists of one packet. This packet
- * has both client capabilites and scrambled password.
- * With SSL the handshake might consist of two packets. If the first
- * packet (client capabilities) has CLIENT_SSL flag set, we have to
- * switch to SSL and read the second packet. The scrambled password
- * is in the second packet and client_capabilites field will be ignored.
- * Maybe it is better to accept flags other than CLIENT_SSL from the
- * second packet?
- */
- #define SSL_HANDSHAKE_SIZE 2
- #define NORMAL_HANDSHAKE_SIZE 6
- #define MIN_HANDSHAKE_SIZE 2
- #else
- #define MIN_HANDSHAKE_SIZE 6
- #endif /* HAVE_OPENSSL */
- int2store(end,client_flags);
- end[2]=MY_CHARSET_CURRENT;
- 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 %dn",
- 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->user : "unauthenticated",
- (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);
- }
- decrease_user_connections(thd->user,thd->host);
- 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 */
- }
- /*
- Execute commands from bootstrap_file.
- Used when creating the initial grant tables
- */
- pthread_handler_decl(handle_bootstrap,arg)
- {
- THD *thd=(THD*) arg;
- FILE *file=bootstrap_file;
- char *buff;
- /* The following must be called before DBUG_ENTER */
- if (my_thread_init() || thd->store_globals())
- {
- close_connection(&thd->net,ER_OUT_OF_RESOURCES);
- thd->fatal_error=1;
- goto end;
- }
- DBUG_ENTER("handle_bootstrap");
- pthread_detach_this_thread();
- thd->thread_stack= (char*) &thd;
- 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;
- thd->priv_user=thd->user=(char*)"boot";
- 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)
- break;
- free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
- }
- thd->priv_user=thd->user=0;
- /* thd->fatal_error should be set in case something went wrong */
- end:
- (void) pthread_mutex_lock(&LOCK_thread_count);
- thread_count--;
- (void) pthread_cond_broadcast(&COND_thread_count);
- (void) pthread_mutex_unlock(&LOCK_thread_count);
- my_thread_end();
- pthread_exit(0);
- DBUG_RETURN(0); // Never reached
- }
- 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 (!db || check_db_name(db))
- {
- net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
- goto err;
- }
- 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;
- // commands which will always take a long time should be marked with
- // this so that they will not get logged to the slow query log
- bool slow_command=FALSE;
- DBUG_ENTER("do_command");
- net= &thd->net;
- 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();
- thd->lex.options=0; // We store status here
- 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:
- {
- slow_command = TRUE;
- char* data = packet + 1;
- uint db_len = *data;
- uint tbl_len = *(data + db_len + 1);
- char* db = sql_alloc(db_len + tbl_len + 2);
- memcpy(db, data + 1, db_len);
- 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;
- }
- decrease_user_connections (save_user, thd->host);
- 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);
- // null test to handle EOM
- if (!db || !stripp_sp(db) || check_db_name(db))
- {
- net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
- break;
- }
- if (check_access(thd,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);
- // null test to handle EOM
- if (!db || !stripp_sp(db) || check_db_name(db))
- {
- net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
- break;
- }
- if (check_access(thd,DROP_ACL,db,0,1) || end_active_trans(thd))
- break;
- mysql_log.write(thd,command,db);
- mysql_rm_db(thd,db,0);
- break;
- }
- case COM_BINLOG_DUMP:
- {
- slow_command = TRUE;
- 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, 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 */
- }
- 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 (!slow_command && !thd->user_time) // do not log 'slow_command' queries
- {
- thd->proc_info="logging slow query";
- if ((ulong) (thd->start_time - thd->time_after_lock) > long_query_time ||
- ((thd->lex.options &
- (QUERY_NO_INDEX_USED | QUERY_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 up";
- 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= &thd->lex;
- TABLE_LIST *tables=(TABLE_LIST*) lex->table_list.first;
- DBUG_ENTER("mysql_execute_command");
- if(table_rules_on && thd->slave_thread && 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;
- if (end_active_trans(thd))
- res= -1;
- else
- 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 (end_active_trans(thd))
- res= -1;
- else 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_TRUNCATE:
- lex->where=0;
- lex->select_limit=HA_POS_ERROR;
- /* Fall through */
- case SQLCOM_DELETE:
- {
- if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
- goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd,DELETE_ACL,tables))
- 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 */
- if (end_active_trans(thd))
- res= -1;
- else
- res = mysql_rm_table(thd,tables,lex->drop_if_exists);
- }
- break;
- case SQLCOM_DROP_INDEX:
- if (!tables->db)
- tables->db=thd->db;
- 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;
- if (end_active_trans(thd))
- res= -1;
- else
- 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_LOGS:
- #ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
- #else
- {
- if (grant_option && check_access(thd, FILE_ACL, any_db))
- goto error;
- res= mysqld_show_logs(thd);
- break;
- }
- #endif
- case SQLCOM_SHOW_TABLES:
- /* FALL THROUGH */
- case SQLCOM_SHOW_OPEN_TABLES:
- #ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
- #else
- {
- char *db=lex->db ? lex->db : thd->db;
- if (!db)
- {
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
- goto error; /* purecov: inspected */
- }
- remove_escape(db); // Fix escaped '_'
- if (check_db_name(db))
- {
- net_printf(&thd->net,ER_WRONG_DB_NAME, db);
- 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->sql_command == SQLCOM_SHOW_OPEN_TABLES)
- res= mysqld_show_open_tables(thd,db,
- (lex->wild ? lex->wild->ptr() : NullS));
- else if (lex->options & SELECT_DESCRIBE)
- 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),
- lex->verbose);
- 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_NOT_AUTO_COMMIT)
- {
- if ((org_options & OPTION_NOT_AUTO_COMMIT))
- {
- /* We changed to auto_commit mode */
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
- thd->server_status|= SERVER_STATUS_AUTOCOMMIT;
- if (ha_commit(thd))
- {
- res= -1;
- break;
- }
- }
- else
- {
- thd->options&= ~(ulong) (OPTION_STATUS_NO_TRANS_UPDATE);
- 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) || end_active_trans(thd))
- 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 (!stripp_sp(lex->name) || check_db_name(lex->name))
- {
- net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
- break;
- }
- if (check_access(thd,CREATE_ACL,lex->name,0,1))
- break;
- mysql_create_db(thd,lex->name,lex->create_info.options);
- break;
- }
- case SQLCOM_DROP_DB:
- {
- if (!stripp_sp(lex->name) || check_db_name(lex->name))
- {
- net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
- break;
- }
- if (check_access(thd,DROP_ACL,lex->name,0,1) ||
- end_active_trans(thd))
- break;
- mysql_rm_db(thd,lex->name,lex->drop_if_exists);
- 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->priv_user && !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
- !check_access(thd, SELECT_ACL, "mysql",0,1))
- {
- res = mysql_show_grants(thd,lex->grant_user);
- }
- break;
- case SQLCOM_BEGIN:
- if (end_active_trans(thd))
- {
- res= -1;
- }
- else
- {
- thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
- 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 | OPTION_STATUS_NO_TRANS_UPDATE);
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- if (!ha_commit(thd))
- send_ok(&thd->net);
- else
- res= -1;
- break;
- case SQLCOM_ROLLBACK:
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- if (!ha_rollback(thd))
- {
- if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
- send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
- else
- send_ok(&thd->net);
- }
- else
- res= -1;
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
- 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 dont_check_global_grants)
- {
- uint db_access,dummy;
- if (save_priv)
- *save_priv=0;
- else
- save_priv= &dummy;
- if (!db && !thd->db && !dont_check_global_grants)
- {
- 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 && dont_check_global_grants)
- { // We can never grant this
- net_printf(&thd->net,ER_ACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
- thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
- 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);
- /* grant_option is set if there exists a single table or column grant */
- if (db_access == want_access ||
- ((grant_option && !dont_check_global_grants) &&
- !(want_access & ~TABLE_ACLS)))
- return FALSE; /* Ok */
- net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->host ? thd->host : (thd->ip ? thd->ip : "unknown"),
- db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
- 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 ||
- check_table_name(table->table.str,table->table.length) ||
- table->db.str && check_db_name(table->db.str))
- {
- net_printf(&thd->net,ER_WRONG_TABLE_NAME,table->table.str);
- 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))
- {
- tmp->prepare_to_die();
- error=0;
- }
- 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);
- }