The world's most popular open source database
00001 /* Copyright (C) 2000-2003 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 #define MYSQL_LEX 1 00018 #include "mysql_priv.h" 00019 #include "sql_repl.h" 00020 #include "rpl_filter.h" 00021 #include "repl_failsafe.h" 00022 #include <m_ctype.h> 00023 #include <myisam.h> 00024 #include <my_dir.h> 00025 00026 #include "sp_head.h" 00027 #include "sp.h" 00028 #include "sp_cache.h" 00029 #include "events.h" 00030 #include "event_timed.h" 00031 00032 #ifdef HAVE_OPENSSL 00033 /* 00034 Without SSL the handshake consists of one packet. This packet 00035 has both client capabilites and scrambled password. 00036 With SSL the handshake might consist of two packets. If the first 00037 packet (client capabilities) has CLIENT_SSL flag set, we have to 00038 switch to SSL and read the second packet. The scrambled password 00039 is in the second packet and client_capabilites field will be ignored. 00040 Maybe it is better to accept flags other than CLIENT_SSL from the 00041 second packet? 00042 */ 00043 #define SSL_HANDSHAKE_SIZE 2 00044 #define NORMAL_HANDSHAKE_SIZE 6 00045 #define MIN_HANDSHAKE_SIZE 2 00046 #else 00047 #define MIN_HANDSHAKE_SIZE 6 00048 #endif /* HAVE_OPENSSL */ 00049 00050 /* Used in error handling only */ 00051 #define SP_TYPE_STRING(LP) \ 00052 ((LP)->sphead->m_type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE") 00053 #define SP_COM_STRING(LP) \ 00054 ((LP)->sql_command == SQLCOM_CREATE_SPFUNCTION || \ 00055 (LP)->sql_command == SQLCOM_ALTER_FUNCTION || \ 00056 (LP)->sql_command == SQLCOM_SHOW_CREATE_FUNC || \ 00057 (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \ 00058 "FUNCTION" : "PROCEDURE") 00059 00060 #ifdef SOLARIS 00061 extern "C" int gethostname(char *name, int namelen); 00062 #endif 00063 00064 static void time_out_user_resource_limits(THD *thd, USER_CONN *uc); 00065 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00066 static int check_for_max_user_connections(THD *thd, USER_CONN *uc); 00067 static void decrease_user_connections(USER_CONN *uc); 00068 #endif /* NO_EMBEDDED_ACCESS_CHECKS */ 00069 static bool check_multi_update_lock(THD *thd); 00070 static void remove_escape(char *name); 00071 static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); 00072 00073 const char *any_db="*any*"; // Special symbol for check_access 00074 00075 const LEX_STRING command_name[]={ 00076 C_STRING_WITH_LEN("Sleep"), 00077 C_STRING_WITH_LEN("Quit"), 00078 C_STRING_WITH_LEN("Init DB"), 00079 C_STRING_WITH_LEN("Query"), 00080 C_STRING_WITH_LEN("Field List"), 00081 C_STRING_WITH_LEN("Create DB"), 00082 C_STRING_WITH_LEN("Drop DB"), 00083 C_STRING_WITH_LEN("Refresh"), 00084 C_STRING_WITH_LEN("Shutdown"), 00085 C_STRING_WITH_LEN("Statistics"), 00086 C_STRING_WITH_LEN("Processlist"), 00087 C_STRING_WITH_LEN("Connect"), 00088 C_STRING_WITH_LEN("Kill"), 00089 C_STRING_WITH_LEN("Debug"), 00090 C_STRING_WITH_LEN("Ping"), 00091 C_STRING_WITH_LEN("Time"), 00092 C_STRING_WITH_LEN("Delayed insert"), 00093 C_STRING_WITH_LEN("Change user"), 00094 C_STRING_WITH_LEN("Binlog Dump"), 00095 C_STRING_WITH_LEN("Table Dump"), 00096 C_STRING_WITH_LEN("Connect Out"), 00097 C_STRING_WITH_LEN("Register Slave"), 00098 C_STRING_WITH_LEN("Prepare"), 00099 C_STRING_WITH_LEN("Execute"), 00100 C_STRING_WITH_LEN("Long Data"), 00101 C_STRING_WITH_LEN("Close stmt"), 00102 C_STRING_WITH_LEN("Reset stmt"), 00103 C_STRING_WITH_LEN("Set option"), 00104 C_STRING_WITH_LEN("Fetch"), 00105 C_STRING_WITH_LEN("Daemon"), 00106 C_STRING_WITH_LEN("Error") // Last command number 00107 }; 00108 00109 const char *xa_state_names[]={ 00110 "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED" 00111 }; 00112 00113 #ifdef __WIN__ 00114 static void test_signal(int sig_ptr) 00115 { 00116 #if !defined( DBUG_OFF) 00117 MessageBox(NULL,"Test signal","DBUG",MB_OK); 00118 #endif 00119 } 00120 static void init_signals(void) 00121 { 00122 int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ; 00123 for (int i=0 ; i < 7 ; i++) 00124 signal( signals[i], test_signal) ; 00125 } 00126 #endif 00127 00128 static void unlock_locked_tables(THD *thd) 00129 { 00130 if (thd->locked_tables) 00131 { 00132 thd->lock=thd->locked_tables; 00133 thd->locked_tables=0; // Will be automatically closed 00134 close_thread_tables(thd); // Free tables 00135 } 00136 } 00137 00138 00139 bool end_active_trans(THD *thd) 00140 { 00141 int error=0; 00142 DBUG_ENTER("end_active_trans"); 00143 if (unlikely(thd->in_sub_stmt)) 00144 { 00145 my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); 00146 DBUG_RETURN(1); 00147 } 00148 if (thd->transaction.xid_state.xa_state != XA_NOTR) 00149 { 00150 my_error(ER_XAER_RMFAIL, MYF(0), 00151 xa_state_names[thd->transaction.xid_state.xa_state]); 00152 DBUG_RETURN(1); 00153 } 00154 if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN | 00155 OPTION_TABLE_LOCK)) 00156 { 00157 DBUG_PRINT("info",("options: 0x%lx", (ulong) thd->options)); 00158 /* Safety if one did "drop table" on locked tables */ 00159 if (!thd->locked_tables) 00160 thd->options&= ~OPTION_TABLE_LOCK; 00161 thd->server_status&= ~SERVER_STATUS_IN_TRANS; 00162 if (ha_commit(thd)) 00163 error=1; 00164 } 00165 thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE | 00166 OPTION_KEEP_LOG); 00167 DBUG_RETURN(error); 00168 } 00169 00170 bool begin_trans(THD *thd) 00171 { 00172 int error=0; 00173 if (unlikely(thd->in_sub_stmt)) 00174 { 00175 my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); 00176 return 1; 00177 } 00178 if (thd->locked_tables) 00179 { 00180 thd->lock=thd->locked_tables; 00181 thd->locked_tables=0; // Will be automatically closed 00182 close_thread_tables(thd); // Free tables 00183 } 00184 if (end_active_trans(thd)) 00185 error= -1; 00186 else 00187 { 00188 LEX *lex= thd->lex; 00189 thd->options|= OPTION_BEGIN; 00190 thd->server_status|= SERVER_STATUS_IN_TRANS; 00191 if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) 00192 error= ha_start_consistent_snapshot(thd); 00193 } 00194 return error; 00195 } 00196 00197 #ifdef HAVE_REPLICATION 00198 /* 00199 Returns true if all tables should be ignored 00200 */ 00201 inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) 00202 { 00203 return rpl_filter->is_on() && tables && !thd->spcont && 00204 !rpl_filter->tables_ok(thd->db, tables); 00205 } 00206 #endif 00207 00208 00209 static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables) 00210 { 00211 for (TABLE_LIST *table= tables; table; table= table->next_global) 00212 { 00213 DBUG_ASSERT(table->db && table->table_name); 00214 if (table->updating && 00215 !find_temporary_table(thd, table->db, table->table_name)) 00216 return 1; 00217 } 00218 return 0; 00219 } 00220 00221 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00222 static HASH hash_user_connections; 00223 00224 static int get_or_create_user_conn(THD *thd, const char *user, 00225 const char *host, 00226 USER_RESOURCES *mqh) 00227 { 00228 int return_val= 0; 00229 uint temp_len, user_len; 00230 char temp_user[USER_HOST_BUFF_SIZE]; 00231 struct user_conn *uc; 00232 00233 DBUG_ASSERT(user != 0); 00234 DBUG_ASSERT(host != 0); 00235 00236 user_len= strlen(user); 00237 temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1; 00238 (void) pthread_mutex_lock(&LOCK_user_conn); 00239 if (!(uc = (struct user_conn *) hash_search(&hash_user_connections, 00240 (byte*) temp_user, temp_len))) 00241 { 00242 /* First connection for user; Create a user connection object */ 00243 if (!(uc= ((struct user_conn*) 00244 my_malloc(sizeof(struct user_conn) + temp_len+1, 00245 MYF(MY_WME))))) 00246 { 00247 net_send_error(thd, 0, NullS); // Out of memory 00248 return_val= 1; 00249 goto end; 00250 } 00251 uc->user=(char*) (uc+1); 00252 memcpy(uc->user,temp_user,temp_len+1); 00253 uc->host= uc->user + user_len + 1; 00254 uc->len= temp_len; 00255 uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0; 00256 uc->user_resources= *mqh; 00257 uc->intime= thd->thr_create_time; 00258 if (my_hash_insert(&hash_user_connections, (byte*) uc)) 00259 { 00260 my_free((char*) uc,0); 00261 net_send_error(thd, 0, NullS); // Out of memory 00262 return_val= 1; 00263 goto end; 00264 } 00265 } 00266 thd->user_connect=uc; 00267 uc->connections++; 00268 end: 00269 (void) pthread_mutex_unlock(&LOCK_user_conn); 00270 return return_val; 00271 00272 } 00273 #endif /* !NO_EMBEDDED_ACCESS_CHECKS */ 00274 00275 00276 /* 00277 Check if user exist and password supplied is correct. 00278 00279 SYNOPSIS 00280 check_user() 00281 thd thread handle, thd->security_ctx->{host,user,ip} are used 00282 command originator of the check: now check_user is called 00283 during connect and change user procedures; used for 00284 logging. 00285 passwd scrambled password received from client 00286 passwd_len length of scrambled password 00287 db database name to connect to, may be NULL 00288 check_count dont know exactly 00289 00290 Note, that host, user and passwd may point to communication buffer. 00291 Current implementation does not depend on that, but future changes 00292 should be done with this in mind; 'thd' is INOUT, all other params 00293 are 'IN'. 00294 00295 RETURN VALUE 00296 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and 00297 thd->db are updated; OK is sent to client; 00298 -1 access denied or handshake error; error is sent to client; 00299 >0 error, not sent to client 00300 */ 00301 00302 int check_user(THD *thd, enum enum_server_command command, 00303 const char *passwd, uint passwd_len, const char *db, 00304 bool check_count) 00305 { 00306 DBUG_ENTER("check_user"); 00307 00308 #ifdef NO_EMBEDDED_ACCESS_CHECKS 00309 thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights 00310 /* Change database if necessary */ 00311 if (db && db[0]) 00312 { 00313 /* 00314 thd->db is saved in caller and needs to be freed by caller if this 00315 function returns 0 00316 */ 00317 thd->reset_db(NULL, 0); 00318 if (mysql_change_db(thd, db, FALSE)) 00319 { 00320 /* Send the error to the client */ 00321 net_send_error(thd); 00322 DBUG_RETURN(-1); 00323 } 00324 } 00325 send_ok(thd); 00326 DBUG_RETURN(0); 00327 #else 00328 00329 my_bool opt_secure_auth_local; 00330 pthread_mutex_lock(&LOCK_global_system_variables); 00331 opt_secure_auth_local= opt_secure_auth; 00332 pthread_mutex_unlock(&LOCK_global_system_variables); 00333 00334 /* 00335 If the server is running in secure auth mode, short scrambles are 00336 forbidden. 00337 */ 00338 if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323) 00339 { 00340 net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE); 00341 general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); 00342 DBUG_RETURN(-1); 00343 } 00344 if (passwd_len != 0 && 00345 passwd_len != SCRAMBLE_LENGTH && 00346 passwd_len != SCRAMBLE_LENGTH_323) 00347 DBUG_RETURN(ER_HANDSHAKE_ERROR); 00348 00349 /* 00350 Clear thd->db as it points to something, that will be freed when 00351 connection is closed. We don't want to accidentally free a wrong pointer 00352 if connect failed. Also in case of 'CHANGE USER' failure, current 00353 database will be switched to 'no database selected'. 00354 */ 00355 thd->reset_db(NULL, 0); 00356 00357 USER_RESOURCES ur; 00358 int res= acl_getroot(thd, &ur, passwd, passwd_len); 00359 #ifndef EMBEDDED_LIBRARY 00360 if (res == -1) 00361 { 00362 /* 00363 This happens when client (new) sends password scrambled with 00364 scramble(), but database holds old value (scrambled with 00365 scramble_323()). Here we please client to send scrambled_password 00366 in old format. 00367 */ 00368 NET *net= &thd->net; 00369 if (opt_secure_auth_local) 00370 { 00371 net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE, 00372 thd->main_security_ctx.user, 00373 thd->main_security_ctx.host_or_ip); 00374 general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE), 00375 thd->main_security_ctx.user, 00376 thd->main_security_ctx.host_or_ip); 00377 DBUG_RETURN(-1); 00378 } 00379 /* We have to read very specific packet size */ 00380 if (send_old_password_request(thd) || 00381 my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) 00382 { 00383 inc_host_errors(&thd->remote.sin_addr); 00384 DBUG_RETURN(ER_HANDSHAKE_ERROR); 00385 } 00386 /* Final attempt to check the user based on reply */ 00387 /* So as passwd is short, errcode is always >= 0 */ 00388 res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323); 00389 } 00390 #endif /*EMBEDDED_LIBRARY*/ 00391 /* here res is always >= 0 */ 00392 if (res == 0) 00393 { 00394 if (!(thd->main_security_ctx.master_access & 00395 NO_ACCESS)) // authentication is OK 00396 { 00397 DBUG_PRINT("info", 00398 ("Capabilities: %lx packet_length: %ld Host: '%s' " 00399 "Login user: '%s' Priv_user: '%s' Using password: %s " 00400 "Access: %u db: '%s'", 00401 thd->client_capabilities, 00402 thd->max_client_packet_length, 00403 thd->main_security_ctx.host_or_ip, 00404 thd->main_security_ctx.user, 00405 thd->main_security_ctx.priv_user, 00406 passwd_len ? "yes": "no", 00407 thd->main_security_ctx.master_access, 00408 (thd->db ? thd->db : "*none*"))); 00409 00410 if (check_count) 00411 { 00412 VOID(pthread_mutex_lock(&LOCK_thread_count)); 00413 bool count_ok= thread_count <= max_connections + delayed_insert_threads 00414 || (thd->main_security_ctx.master_access & SUPER_ACL); 00415 VOID(pthread_mutex_unlock(&LOCK_thread_count)); 00416 if (!count_ok) 00417 { // too many connections 00418 net_send_error(thd, ER_CON_COUNT_ERROR); 00419 DBUG_RETURN(-1); 00420 } 00421 } 00422 00423 /* Why logging is performed before all checks've passed? */ 00424 general_log_print(thd, command, 00425 (thd->main_security_ctx.priv_user == 00426 thd->main_security_ctx.user ? 00427 (char*) "%s@%s on %s" : 00428 (char*) "%s@%s as anonymous on %s"), 00429 thd->main_security_ctx.user, 00430 thd->main_security_ctx.host_or_ip, 00431 db ? db : (char*) ""); 00432 00433 /* 00434 This is the default access rights for the current database. It's 00435 set to 0 here because we don't have an active database yet (and we 00436 may not have an active database to set. 00437 */ 00438 thd->main_security_ctx.db_access=0; 00439 00440 /* Don't allow user to connect if he has done too many queries */ 00441 if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn || 00442 max_user_connections) && 00443 get_or_create_user_conn(thd, 00444 (opt_old_style_user_limits ? thd->main_security_ctx.user : 00445 thd->main_security_ctx.priv_user), 00446 (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip : 00447 thd->main_security_ctx.priv_host), 00448 &ur)) 00449 DBUG_RETURN(-1); 00450 if (thd->user_connect && 00451 (thd->user_connect->user_resources.conn_per_hour || 00452 thd->user_connect->user_resources.user_conn || 00453 max_user_connections) && 00454 check_for_max_user_connections(thd, thd->user_connect)) 00455 DBUG_RETURN(-1); 00456 00457 /* Change database if necessary */ 00458 if (db && db[0]) 00459 { 00460 if (mysql_change_db(thd, db, FALSE)) 00461 { 00462 /* Send error to the client */ 00463 net_send_error(thd); 00464 if (thd->user_connect) 00465 decrease_user_connections(thd->user_connect); 00466 DBUG_RETURN(-1); 00467 } 00468 } 00469 send_ok(thd); 00470 thd->password= test(passwd_len); // remember for error messages 00471 /* Ready to handle queries */ 00472 DBUG_RETURN(0); 00473 } 00474 } 00475 else if (res == 2) // client gave short hash, server has long hash 00476 { 00477 net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE); 00478 general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); 00479 DBUG_RETURN(-1); 00480 } 00481 net_printf_error(thd, ER_ACCESS_DENIED_ERROR, 00482 thd->main_security_ctx.user, 00483 thd->main_security_ctx.host_or_ip, 00484 passwd_len ? ER(ER_YES) : ER(ER_NO)); 00485 general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), 00486 thd->main_security_ctx.user, 00487 thd->main_security_ctx.host_or_ip, 00488 passwd_len ? ER(ER_YES) : ER(ER_NO)); 00489 DBUG_RETURN(-1); 00490 #endif /* NO_EMBEDDED_ACCESS_CHECKS */ 00491 } 00492 00493 /* 00494 Check for maximum allowable user connections, if the mysqld server is 00495 started with corresponding variable that is greater then 0. 00496 */ 00497 00498 extern "C" byte *get_key_conn(user_conn *buff, uint *length, 00499 my_bool not_used __attribute__((unused))) 00500 { 00501 *length=buff->len; 00502 return (byte*) buff->user; 00503 } 00504 00505 extern "C" void free_user(struct user_conn *uc) 00506 { 00507 my_free((char*) uc,MYF(0)); 00508 } 00509 00510 void init_max_user_conn(void) 00511 { 00512 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00513 (void) hash_init(&hash_user_connections,system_charset_info,max_connections, 00514 0,0, 00515 (hash_get_key) get_key_conn, (hash_free_key) free_user, 00516 0); 00517 #endif 00518 } 00519 00520 00521 /* 00522 check if user has already too many connections 00523 00524 SYNOPSIS 00525 check_for_max_user_connections() 00526 thd Thread handle 00527 uc User connect object 00528 00529 NOTES 00530 If check fails, we decrease user connection count, which means one 00531 shouldn't call decrease_user_connections() after this function. 00532 00533 RETURN 00534 0 ok 00535 1 error 00536 */ 00537 00538 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00539 00540 static int check_for_max_user_connections(THD *thd, USER_CONN *uc) 00541 { 00542 int error=0; 00543 DBUG_ENTER("check_for_max_user_connections"); 00544 00545 (void) pthread_mutex_lock(&LOCK_user_conn); 00546 if (max_user_connections && !uc->user_resources.user_conn && 00547 max_user_connections < (uint) uc->connections) 00548 { 00549 net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user); 00550 error=1; 00551 goto end; 00552 } 00553 time_out_user_resource_limits(thd, uc); 00554 if (uc->user_resources.user_conn && 00555 uc->user_resources.user_conn < uc->connections) 00556 { 00557 net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, 00558 "max_user_connections", 00559 (long) uc->user_resources.user_conn); 00560 error= 1; 00561 goto end; 00562 } 00563 if (uc->user_resources.conn_per_hour && 00564 uc->user_resources.conn_per_hour <= uc->conn_per_hour) 00565 { 00566 net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, 00567 "max_connections_per_hour", 00568 (long) uc->user_resources.conn_per_hour); 00569 error=1; 00570 goto end; 00571 } 00572 uc->conn_per_hour++; 00573 00574 end: 00575 if (error) 00576 uc->connections--; // no need for decrease_user_connections() here 00577 (void) pthread_mutex_unlock(&LOCK_user_conn); 00578 DBUG_RETURN(error); 00579 } 00580 00581 /* 00582 Decrease user connection count 00583 00584 SYNOPSIS 00585 decrease_user_connections() 00586 uc User connection object 00587 00588 NOTES 00589 If there is a n user connection object for a connection 00590 (which only happens if 'max_user_connections' is defined or 00591 if someone has created a resource grant for a user), then 00592 the connection count is always incremented on connect. 00593 00594 The user connect object is not freed if some users has 00595 'max connections per hour' defined as we need to be able to hold 00596 count over the lifetime of the connection. 00597 */ 00598 00599 static void decrease_user_connections(USER_CONN *uc) 00600 { 00601 DBUG_ENTER("decrease_user_connections"); 00602 (void) pthread_mutex_lock(&LOCK_user_conn); 00603 DBUG_ASSERT(uc->connections); 00604 if (!--uc->connections && !mqh_used) 00605 { 00606 /* Last connection for user; Delete it */ 00607 (void) hash_delete(&hash_user_connections,(byte*) uc); 00608 } 00609 (void) pthread_mutex_unlock(&LOCK_user_conn); 00610 DBUG_VOID_RETURN; 00611 } 00612 00613 #endif /* NO_EMBEDDED_ACCESS_CHECKS */ 00614 00615 00616 void free_max_user_conn(void) 00617 { 00618 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00619 hash_free(&hash_user_connections); 00620 #endif /* NO_EMBEDDED_ACCESS_CHECKS */ 00621 } 00622 00623 00624 00625 /* 00626 Mark all commands that somehow changes a table 00627 This is used to check number of updates / hour 00628 00629 sql_command is actually set to SQLCOM_END sometimes 00630 so we need the +1 to include it in the array. 00631 00632 See COMMAND_FLAG_xxx for different type of commands 00633 2 - query that returns meaningful ROW_COUNT() - 00634 a number of modified rows 00635 */ 00636 00637 uint sql_command_flags[SQLCOM_END+1]; 00638 00639 void init_update_queries(void) 00640 { 00641 bzero((gptr) &sql_command_flags, sizeof(sql_command_flags)); 00642 00643 sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA; 00644 sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA; 00645 sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA; 00646 sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA; 00647 sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA; 00648 sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA; 00649 sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA; 00650 sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA; 00651 sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA; 00652 sql_command_flags[SQLCOM_BACKUP_TABLE]= CF_CHANGES_DATA; 00653 sql_command_flags[SQLCOM_RESTORE_TABLE]= CF_CHANGES_DATA; 00654 sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA; 00655 sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA; 00656 sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA; 00657 sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA; 00658 sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA; 00659 sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA; 00660 00661 sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; 00662 sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; 00663 sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; 00664 sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; 00665 sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; 00666 sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; 00667 sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; 00668 sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; 00669 00670 sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND; 00671 sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND; 00672 sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND; 00673 sql_command_flags[SQLCOM_SHOW_DATABASES]= CF_STATUS_COMMAND; 00674 sql_command_flags[SQLCOM_SHOW_TRIGGERS]= CF_STATUS_COMMAND; 00675 sql_command_flags[SQLCOM_SHOW_EVENTS]= CF_STATUS_COMMAND; 00676 sql_command_flags[SQLCOM_SHOW_OPEN_TABLES]= CF_STATUS_COMMAND; 00677 sql_command_flags[SQLCOM_SHOW_PLUGINS]= CF_STATUS_COMMAND; 00678 sql_command_flags[SQLCOM_SHOW_FIELDS]= CF_STATUS_COMMAND; 00679 sql_command_flags[SQLCOM_SHOW_KEYS]= CF_STATUS_COMMAND; 00680 sql_command_flags[SQLCOM_SHOW_VARIABLES]= CF_STATUS_COMMAND; 00681 sql_command_flags[SQLCOM_SHOW_CHARSETS]= CF_STATUS_COMMAND; 00682 sql_command_flags[SQLCOM_SHOW_COLLATIONS]= CF_STATUS_COMMAND; 00683 sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND; 00684 00685 sql_command_flags[SQLCOM_SHOW_TABLES]= (CF_STATUS_COMMAND | 00686 CF_SHOW_TABLE_COMMAND); 00687 sql_command_flags[SQLCOM_SHOW_TABLE_STATUS]= (CF_STATUS_COMMAND | 00688 CF_SHOW_TABLE_COMMAND); 00689 00690 /* 00691 The following is used to preserver CF_ROW_COUNT during the 00692 a CALL or EXECUTE statement, so the value generated by the 00693 last called (or executed) statement is preserved. 00694 See mysql_execute_command() for how CF_ROW_COUNT is used. 00695 */ 00696 sql_command_flags[SQLCOM_CALL]= CF_HAS_ROW_COUNT; 00697 sql_command_flags[SQLCOM_EXECUTE]= CF_HAS_ROW_COUNT; 00698 } 00699 00700 00701 bool is_update_query(enum enum_sql_command command) 00702 { 00703 DBUG_ASSERT(command >= 0 && command <= SQLCOM_END); 00704 return (sql_command_flags[command] & CF_CHANGES_DATA) != 0; 00705 } 00706 00707 /* 00708 Reset per-hour user resource limits when it has been more than 00709 an hour since they were last checked 00710 00711 SYNOPSIS: 00712 time_out_user_resource_limits() 00713 thd Thread handler 00714 uc User connection details 00715 00716 NOTE: 00717 This assumes that the LOCK_user_conn mutex has been acquired, so it is 00718 safe to test and modify members of the USER_CONN structure. 00719 */ 00720 00721 static void time_out_user_resource_limits(THD *thd, USER_CONN *uc) 00722 { 00723 time_t check_time = thd->start_time ? thd->start_time : time(NULL); 00724 DBUG_ENTER("time_out_user_resource_limits"); 00725 00726 /* If more than a hour since last check, reset resource checking */ 00727 if (check_time - uc->intime >= 3600) 00728 { 00729 uc->questions=1; 00730 uc->updates=0; 00731 uc->conn_per_hour=0; 00732 uc->intime=check_time; 00733 } 00734 00735 DBUG_VOID_RETURN; 00736 } 00737 00738 00739 /* 00740 Check if maximum queries per hour limit has been reached 00741 returns 0 if OK. 00742 */ 00743 00744 static bool check_mqh(THD *thd, uint check_command) 00745 { 00746 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00747 bool error= 0; 00748 USER_CONN *uc=thd->user_connect; 00749 DBUG_ENTER("check_mqh"); 00750 DBUG_ASSERT(uc != 0); 00751 00752 (void) pthread_mutex_lock(&LOCK_user_conn); 00753 00754 time_out_user_resource_limits(thd, uc); 00755 00756 /* Check that we have not done too many questions / hour */ 00757 if (uc->user_resources.questions && 00758 uc->questions++ >= uc->user_resources.questions) 00759 { 00760 net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions", 00761 (long) uc->user_resources.questions); 00762 error=1; 00763 goto end; 00764 } 00765 if (check_command < (uint) SQLCOM_END) 00766 { 00767 /* Check that we have not done too many updates / hour */ 00768 if (uc->user_resources.updates && 00769 (sql_command_flags[check_command] & CF_CHANGES_DATA) && 00770 uc->updates++ >= uc->user_resources.updates) 00771 { 00772 net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates", 00773 (long) uc->user_resources.updates); 00774 error=1; 00775 goto end; 00776 } 00777 } 00778 end: 00779 (void) pthread_mutex_unlock(&LOCK_user_conn); 00780 DBUG_RETURN(error); 00781 #else 00782 return (0); 00783 #endif /* NO_EMBEDDED_ACCESS_CHECKS */ 00784 } 00785 00786 00787 static void reset_mqh(LEX_USER *lu, bool get_them= 0) 00788 { 00789 #ifndef NO_EMBEDDED_ACCESS_CHECKS 00790 (void) pthread_mutex_lock(&LOCK_user_conn); 00791 if (lu) // for GRANT 00792 { 00793 USER_CONN *uc; 00794 uint temp_len=lu->user.length+lu->host.length+2; 00795 char temp_user[USER_HOST_BUFF_SIZE]; 00796 00797 memcpy(temp_user,lu->user.str,lu->user.length); 00798 memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length); 00799 temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0; 00800 if ((uc = (struct user_conn *) hash_search(&hash_user_connections, 00801 (byte*) temp_user, temp_len))) 00802 { 00803 uc->questions=0; 00804 get_mqh(temp_user,&temp_user[lu->user.length+1],uc); 00805 uc->updates=0; 00806 uc->conn_per_hour=0; 00807 } 00808 } 00809 else 00810 { 00811 /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */ 00812 for (uint idx=0;idx < hash_user_connections.records; idx++) 00813 { 00814 USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections, 00815 idx); 00816 if (get_them) 00817 get_mqh(uc->user,uc->host,uc); 00818 uc->questions=0; 00819 uc->updates=0; 00820 uc->conn_per_hour=0; 00821 } 00822 } 00823 (void) pthread_mutex_unlock(&LOCK_user_conn); 00824 #endif /* NO_EMBEDDED_ACCESS_CHECKS */ 00825 } 00826 00827 void thd_init_client_charset(THD *thd, uint cs_number) 00828 { 00829 /* 00830 Use server character set and collation if 00831 - opt_character_set_client_handshake is not set 00832 - client has not specified a character set 00833 - client character set is the same as the servers 00834 - client character set doesn't exists in server 00835 */ 00836 if (!opt_character_set_client_handshake || 00837 !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) || 00838 !my_strcasecmp(&my_charset_latin1, 00839 global_system_variables.character_set_client->name, 00840 thd->variables.character_set_client->name)) 00841 { 00842 thd->variables.character_set_client= 00843 global_system_variables.character_set_client; 00844 thd->variables.collation_connection= 00845 global_system_variables.collation_connection; 00846 thd->variables.character_set_results= 00847 global_system_variables.character_set_results; 00848 } 00849 else 00850 { 00851 thd->variables.character_set_results= 00852 thd->variables.collation_connection= 00853 thd->variables.character_set_client; 00854 } 00855 } 00856 00857 00858 /* 00859 Perform handshake, authorize client and update thd ACL variables. 00860 SYNOPSIS 00861 check_connection() 00862 thd thread handle 00863 00864 RETURN 00865 0 success, OK is sent to user, thd is updated. 00866 -1 error, which is sent to user 00867 > 0 error code (not sent to user) 00868 */ 00869 00870 #ifndef EMBEDDED_LIBRARY 00871 static int check_connection(THD *thd) 00872 { 00873 uint connect_errors= 0; 00874 NET *net= &thd->net; 00875 ulong pkt_len= 0; 00876 char *end; 00877 00878 DBUG_PRINT("info", 00879 ("New connection received on %s", vio_description(net->vio))); 00880 #ifdef SIGNAL_WITH_VIO_CLOSE 00881 thd->set_active_vio(net->vio); 00882 #endif 00883 00884 if (!thd->main_security_ctx.host) // If TCP/IP connection 00885 { 00886 char ip[30]; 00887 00888 if (vio_peer_addr(net->vio, ip, &thd->peer_port)) 00889 return (ER_BAD_HOST_ERROR); 00890 if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0)))) 00891 return (ER_OUT_OF_RESOURCES); 00892 thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; 00893 vio_in_addr(net->vio,&thd->remote.sin_addr); 00894 if (!(specialflag & SPECIAL_NO_RESOLVE)) 00895 { 00896 vio_in_addr(net->vio,&thd->remote.sin_addr); 00897 thd->main_security_ctx.host= 00898 ip_to_hostname(&thd->remote.sin_addr, &connect_errors); 00899 /* Cut very long hostnames to avoid possible overflows */ 00900 if (thd->main_security_ctx.host) 00901 { 00902 if (thd->main_security_ctx.host != my_localhost) 00903 thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host), 00904 HOSTNAME_LENGTH)]= 0; 00905 thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; 00906 } 00907 if (connect_errors > max_connect_errors) 00908 return(ER_HOST_IS_BLOCKED); 00909 } 00910 DBUG_PRINT("info",("Host: %s ip: %s", 00911 (thd->main_security_ctx.host ? 00912 thd->main_security_ctx.host : "unknown host"), 00913 (thd->main_security_ctx.ip ? 00914 thd->main_security_ctx.ip : "unknown ip"))); 00915 if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip)) 00916 return(ER_HOST_NOT_PRIVILEGED); 00917 } 00918 else /* Hostname given means that the connection was on a socket */ 00919 { 00920 DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host)); 00921 thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; 00922 thd->main_security_ctx.ip= 0; 00923 /* Reset sin_addr */ 00924 bzero((char*) &thd->remote, sizeof(thd->remote)); 00925 } 00926 vio_keepalive(net->vio, TRUE); 00927 { 00928 /* buff[] needs to big enough to hold the server_version variable */ 00929 char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64]; 00930 ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | 00931 CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); 00932 00933 if (opt_using_transactions) 00934 client_flags|=CLIENT_TRANSACTIONS; 00935 #ifdef HAVE_COMPRESS 00936 client_flags |= CLIENT_COMPRESS; 00937 #endif /* HAVE_COMPRESS */ 00938 #ifdef HAVE_OPENSSL 00939 if (ssl_acceptor_fd) 00940 client_flags |= CLIENT_SSL; /* Wow, SSL is available! */ 00941 #endif /* HAVE_OPENSSL */ 00942 00943 end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1; 00944 int4store((uchar*) end, thd->thread_id); 00945 end+= 4; 00946 /* 00947 So as check_connection is the only entry point to authorization 00948 procedure, scramble is set here. This gives us new scramble for 00949 each handshake. 00950 */ 00951 create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand); 00952 /* 00953 Old clients does not understand long scrambles, but can ignore packet 00954 tail: that's why first part of the scramble is placed here, and second 00955 part at the end of packet. 00956 */ 00957 end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1; 00958 00959 int2store(end, client_flags); 00960 /* write server characteristics: up to 16 bytes allowed */ 00961 end[2]=(char) default_charset_info->number; 00962 int2store(end+3, thd->server_status); 00963 bzero(end+5, 13); 00964 end+= 18; 00965 /* write scramble tail */ 00966 end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323, 00967 SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1; 00968 00969 /* At this point we write connection message and read reply */ 00970 if (net_write_command(net, (uchar) protocol_version, "", 0, buff, 00971 (uint) (end-buff)) || 00972 (pkt_len= my_net_read(net)) == packet_error || 00973 pkt_len < MIN_HANDSHAKE_SIZE) 00974 { 00975 inc_host_errors(&thd->remote.sin_addr); 00976 return(ER_HANDSHAKE_ERROR); 00977 } 00978 } 00979 #ifdef _CUSTOMCONFIG_ 00980 #include "_cust_sql_parse.h" 00981 #endif 00982 if (connect_errors) 00983 reset_host_errors(&thd->remote.sin_addr); 00984 if (thd->packet.alloc(thd->variables.net_buffer_length)) 00985 return(ER_OUT_OF_RESOURCES); 00986 00987 thd->client_capabilities=uint2korr(net->read_pos); 00988 if (thd->client_capabilities & CLIENT_PROTOCOL_41) 00989 { 00990 thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16; 00991 thd->max_client_packet_length= uint4korr(net->read_pos+4); 00992 DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); 00993 thd_init_client_charset(thd, (uint) net->read_pos[8]); 00994 thd->update_charset(); 00995 end= (char*) net->read_pos+32; 00996 } 00997 else 00998 { 00999 thd->max_client_packet_length= uint3korr(net->read_pos+2); 01000 end= (char*) net->read_pos+5; 01001 } 01002 01003 if (thd->client_capabilities & CLIENT_IGNORE_SPACE) 01004 thd->variables.sql_mode|= MODE_IGNORE_SPACE; 01005 #ifdef HAVE_OPENSSL 01006 DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities)); 01007 if (thd->client_capabilities & CLIENT_SSL) 01008 { 01009 /* Do the SSL layering. */ 01010 if (!ssl_acceptor_fd) 01011 { 01012 inc_host_errors(&thd->remote.sin_addr); 01013 return(ER_HANDSHAKE_ERROR); 01014 } 01015 DBUG_PRINT("info", ("IO layer change in progress...")); 01016 if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout)) 01017 { 01018 DBUG_PRINT("error", ("Failed to accept new SSL connection")); 01019 inc_host_errors(&thd->remote.sin_addr); 01020 return(ER_HANDSHAKE_ERROR); 01021 } 01022 DBUG_PRINT("info", ("Reading user information over SSL layer")); 01023 if ((pkt_len= my_net_read(net)) == packet_error || 01024 pkt_len < NORMAL_HANDSHAKE_SIZE) 01025 { 01026 DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)", 01027 pkt_len)); 01028 inc_host_errors(&thd->remote.sin_addr); 01029 return(ER_HANDSHAKE_ERROR); 01030 } 01031 } 01032 #endif 01033 01034 if (end >= (char*) net->read_pos+ pkt_len +2) 01035 { 01036 inc_host_errors(&thd->remote.sin_addr); 01037 return(ER_HANDSHAKE_ERROR); 01038 } 01039 01040 if (thd->client_capabilities & CLIENT_INTERACTIVE) 01041 thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout; 01042 if ((thd->client_capabilities & CLIENT_TRANSACTIONS) && 01043 opt_using_transactions) 01044 net->return_status= &thd->server_status; 01045 net->read_timeout=(uint) thd->variables.net_read_timeout; 01046 01047 char *user= end; 01048 char *passwd= strend(user)+1; 01049 uint user_len= passwd - user - 1; 01050 char *db= passwd; 01051 char db_buff[NAME_LEN+1]; // buffer to store db in utf8 01052 char user_buff[USERNAME_LENGTH+1]; // buffer to store user in utf8 01053 uint dummy_errors; 01054 01055 /* 01056 Old clients send null-terminated string as password; new clients send 01057 the size (1 byte) + string (not null-terminated). Hence in case of empty 01058 password both send '\0'. 01059 */ 01060 uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? 01061 *passwd++ : strlen(passwd); 01062 db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? 01063 db + passwd_len + 1 : 0; 01064 uint db_len= db ? strlen(db) : 0; 01065 01066 if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len) 01067 { 01068 inc_host_errors(&thd->remote.sin_addr); 01069 return ER_HANDSHAKE_ERROR; 01070 } 01071 01072 /* Since 4.1 all database names are stored in utf8 */ 01073 if (db) 01074 { 01075 db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1, 01076 system_charset_info, 01077 db, db_len, 01078 thd->charset(), &dummy_errors)]= 0; 01079 db= db_buff; 01080 } 01081 01082 user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1, 01083 system_charset_info, user, user_len, 01084 thd->charset(), &dummy_errors)]= '\0'; 01085 user= user_buff; 01086 01087 /* If username starts and ends in "'", chop them off */ 01088 if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'') 01089 { 01090 user[user_len-1]= 0; 01091 user++; 01092 user_len-= 2; 01093 } 01094 01095 if (thd->main_security_ctx.user) 01096 x_free(thd->main_security_ctx.user); 01097 if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0)))) 01098 return (ER_OUT_OF_RESOURCES); 01099 return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); 01100 } 01101 01102 01103 void execute_init_command(THD *thd, sys_var_str *init_command_var, 01104 rw_lock_t *var_mutex) 01105 { 01106 Vio* save_vio; 01107 ulong save_client_capabilities; 01108 01109 thd->proc_info= "Execution of init_command"; 01110 /* 01111 We need to lock init_command_var because 01112 during execution of init_command_var query 01113 values of init_command_var can't be changed 01114 */ 01115 rw_rdlock(var_mutex); 01116 thd->query= init_command_var->value; 01117 thd->query_length= init_command_var->value_length; 01118 save_client_capabilities= thd->client_capabilities; 01119 thd->client_capabilities|= CLIENT_MULTI_QUERIES; 01120 /* 01121 We don't need return result of execution to client side. 01122 To forbid this we should set thd->net.vio to 0. 01123 */ 01124 save_vio= thd->net.vio; 01125 thd->net.vio= 0; 01126 thd->net.no_send_error= 0; 01127 dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1); 01128 rw_unlock(var_mutex); 01129 thd->client_capabilities= save_client_capabilities; 01130 thd->net.vio= save_vio; 01131 } 01132 01133 01134 pthread_handler_t handle_one_connection(void *arg) 01135 { 01136 THD *thd=(THD*) arg; 01137 uint launch_time = 01138 (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time); 01139 if (launch_time >= slow_launch_time) 01140 statistic_increment(slow_launch_threads,&LOCK_status ); 01141 01142 pthread_detach_this_thread(); 01143 01144 #if !defined( __WIN__) // Win32 calls this in pthread_create 01145 /* The following calls needs to be done before we call DBUG_ macros */ 01146 if (!(test_flags & TEST_NO_THREADS) & my_thread_init()) 01147 { 01148 close_connection(thd, ER_OUT_OF_RESOURCES, 1); 01149 statistic_increment(aborted_connects,&LOCK_status); 01150 end_thread(thd,0); 01151 return 0; 01152 } 01153 #endif 01154 01155 /* 01156 handle_one_connection() is the only way a thread would start 01157 and would always be on top of the stack, therefore, the thread 01158 stack always starts at the address of the first local variable 01159 of handle_one_connection, which is thd. We need to know the 01160 start of the stack so that we could check for stack overruns. 01161 */ 01162 DBUG_PRINT("info", ("handle_one_connection called by thread %d\n", 01163 thd->thread_id)); 01164 /* now that we've called my_thread_init(), it is safe to call DBUG_* */ 01165 01166 #if defined(__WIN__) 01167 init_signals(); 01168 #elif !defined(__NETWARE__) 01169 sigset_t set; 01170 VOID(sigemptyset(&set)); // Get mask in use 01171 VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); 01172 #endif 01173 thd->thread_stack= (char*) &thd; 01174 if (thd->store_globals()) 01175 { 01176 close_connection(thd, ER_OUT_OF_RESOURCES, 1); 01177 statistic_increment(aborted_connects,&LOCK_status); 01178 end_thread(thd,0); 01179 return 0; 01180 } 01181 01182 do 01183 { 01184 int error; 01185 NET *net= &thd->net; 01186 Security_context *sctx= thd->security_ctx; 01187 net->no_send_error= 0; 01188 01189 if ((error=check_connection(thd))) 01190 { // Wrong permissions 01191 if (error > 0) 01192 net_printf_error(thd, error, sctx->host_or_ip); 01193 #ifdef __NT__ 01194 if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) 01195 my_sleep(1000); /* must wait after eof() */ 01196 #endif 01197 statistic_increment(aborted_connects,&LOCK_status); 01198 goto end_thread; 01199 } 01200 #ifdef __NETWARE__ 01201 netware_reg_user(sctx->ip, sctx->user, "MySQL"); 01202 #endif 01203 if (thd->variables.max_join_size == HA_POS_ERROR) 01204 thd->options |= OPTION_BIG_SELECTS; 01205 if (thd->client_capabilities & CLIENT_COMPRESS) 01206 net->compress=1; // Use compression 01207 01208 thd->version= refresh_version; 01209 thd->proc_info= 0; 01210 thd->command= COM_SLEEP; 01211 thd->set_time(); 01212 thd->init_for_queries(); 01213 01214 if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL)) 01215 { 01216 execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); 01217 if (thd->query_error) 01218 thd->killed= THD::KILL_CONNECTION; 01219 thd->proc_info=0; 01220 thd->set_time(); 01221 thd->init_for_queries(); 01222 } 01223 01224 while (!net->error && net->vio != 0 && 01225 !(thd->killed == THD::KILL_CONNECTION)) 01226 { 01227 net->no_send_error= 0; 01228 if (do_command(thd)) 01229 break; 01230 } 01231 if (thd->user_connect) 01232 decrease_user_connections(thd->user_connect); 01233 if (net->error && net->vio != 0 && net->report_error) 01234 { 01235 if (!thd->killed && thd->variables.log_warnings > 1) 01236 sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), 01237 thd->thread_id,(thd->db ? thd->db : "unconnected"), 01238 sctx->user ? sctx->user : "unauthenticated", 01239 sctx->host_or_ip, 01240 (net->last_errno ? ER(net->last_errno) : 01241 ER(ER_UNKNOWN_ERROR))); 01242 net_send_error(thd, net->last_errno, NullS); 01243 statistic_increment(aborted_threads,&LOCK_status); 01244 } 01245 else if (thd->killed) 01246 { 01247 statistic_increment(aborted_threads,&LOCK_status); 01248 } 01249 01250 end_thread: 01251 close_connection(thd, 0, 1); 01252 end_thread(thd,1); 01253 /* 01254 If end_thread returns, we are either running with --one-thread 01255 or this thread has been schedule to handle the next query 01256 */ 01257 thd= current_thd; 01258 thd->thread_stack= (char*) &thd; 01259 } while (!(test_flags & TEST_NO_THREADS)); 01260 /* The following is only executed if we are not using --one-thread */ 01261 return(0); /* purecov: deadcode */ 01262 } 01263 01264 #endif /* EMBEDDED_LIBRARY */ 01265 01266 /* 01267 Execute commands from bootstrap_file. 01268 Used when creating the initial grant tables 01269 */ 01270 01271 pthread_handler_t handle_bootstrap(void *arg) 01272 { 01273 THD *thd=(THD*) arg; 01274 FILE *file=bootstrap_file; 01275 char *buff; 01276 01277 /* The following must be called before DBUG_ENTER */ 01278 thd->thread_stack= (char*) &thd; 01279 if (my_thread_init() || thd->store_globals()) 01280 { 01281 #ifndef EMBEDDED_LIBRARY 01282 close_connection(thd, ER_OUT_OF_RESOURCES, 1); 01283 #endif 01284 thd->fatal_error(); 01285 goto end; 01286 } 01287 DBUG_ENTER("handle_bootstrap"); 01288 01289 #ifndef EMBEDDED_LIBRARY 01290 pthread_detach_this_thread(); 01291 thd->thread_stack= (char*) &thd; 01292 #if !defined(__WIN__) && !defined(__NETWARE__) 01293 sigset_t set; 01294 VOID(sigemptyset(&set)); // Get mask in use 01295 VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); 01296 #endif 01297 #endif /* EMBEDDED_LIBRARY */ 01298 01299 if (thd->variables.max_join_size == HA_POS_ERROR) 01300 thd->options |= OPTION_BIG_SELECTS; 01301 01302 thd->proc_info=0; 01303 thd->version=refresh_version; 01304 thd->security_ctx->priv_user= 01305 thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME)); 01306 thd->security_ctx->priv_host[0]=0; 01307 /* 01308 Make the "client" handle multiple results. This is necessary 01309 to enable stored procedures with SELECTs and Dynamic SQL 01310 in init-file. 01311 */ 01312 thd->client_capabilities|= CLIENT_MULTI_RESULTS; 01313 01314 buff= (char*) thd->net.buff; 01315 thd->init_for_queries(); 01316 while (fgets(buff, thd->net.max_packet, file)) 01317 { 01318 ulong length= (ulong) strlen(buff); 01319 while (buff[length-1] != '\n' && !feof(file)) 01320 { 01321 /* 01322 We got only a part of the current string. Will try to increase 01323 net buffer then read the rest of the current string. 01324 */ 01325 if (net_realloc(&(thd->net), 2 * thd->net.max_packet)) 01326 { 01327 net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS); 01328 thd->fatal_error(); 01329 break; 01330 } 01331 buff= (char*) thd->net.buff; 01332 fgets(buff + length, thd->net.max_packet - length, file); 01333 length+= (ulong) strlen(buff + length); 01334 } 01335 if (thd->is_fatal_error) 01336 break; 01337 01338 while (length && (my_isspace(thd->charset(), buff[length-1]) || 01339 buff[length-1] == ';')) 01340 length--; 01341 buff[length]=0; 01342 thd->query_length=length; 01343 thd->query= thd->memdup_w_gap(buff, length+1, 01344 thd->db_length+1+QUERY_CACHE_FLAGS_SIZE); 01345 thd->query[length] = '\0'; 01346 /* 01347 We don't need to obtain LOCK_thread_count here because in bootstrap 01348 mode we have only one thread. 01349 */ 01350 thd->query_id=next_query_id(); 01351 mysql_parse(thd,thd->query,length); 01352 close_thread_tables(thd); // Free tables 01353 if (thd->is_fatal_error) 01354 break; 01355 free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); 01356 #ifdef USING_TRANSACTIONS 01357 free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC)); 01358 #endif 01359 } 01360 01361 /* thd->fatal_error should be set in case something went wrong */ 01362 end: 01363 bootstrap_error= thd->is_fatal_error; 01364 01365 net_end(&thd->net); 01366 thd->cleanup(); 01367 delete thd; 01368 01369 #ifndef EMBEDDED_LIBRARY 01370 (void) pthread_mutex_lock(&LOCK_thread_count); 01371 thread_count--; 01372 (void) pthread_mutex_unlock(&LOCK_thread_count); 01373 (void) pthread_cond_broadcast(&COND_thread_count); 01374 my_thread_end(); 01375 pthread_exit(0); 01376 #endif 01377 DBUG_RETURN(0); 01378 } 01379 01380 01381 /* This works because items are allocated with sql_alloc() */ 01382 01383 void free_items(Item *item) 01384 { 01385 Item *next; 01386 DBUG_ENTER("free_items"); 01387 for (; item ; item=next) 01388 { 01389 next=item->next; 01390 item->delete_self(); 01391 } 01392 DBUG_VOID_RETURN; 01393 } 01394 01395 /* This works because items are allocated with sql_alloc() */ 01396 01397 void cleanup_items(Item *item) 01398 { 01399 DBUG_ENTER("cleanup_items"); 01400 for (; item ; item=item->next) 01401 item->cleanup(); 01402 DBUG_VOID_RETURN; 01403 } 01404 01405 /* 01406 Handle COM_TABLE_DUMP command 01407 01408 SYNOPSIS 01409 mysql_table_dump 01410 thd thread handle 01411 db database name or an empty string. If empty, 01412 the current database of the connection is used 01413 tbl_name name of the table to dump 01414 01415 NOTES 01416 This function is written to handle one specific command only. 01417 01418 RETURN VALUE 01419 0 success 01420 1 error, the error message is set in THD 01421 */ 01422 01423 static 01424 int mysql_table_dump(THD* thd, char* db, char* tbl_name) 01425 { 01426 TABLE* table; 01427 TABLE_LIST* table_list; 01428 int error = 0; 01429 DBUG_ENTER("mysql_table_dump"); 01430 db = (db && db[0]) ? db : thd->db; 01431 if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST)))) 01432 DBUG_RETURN(1); // out of memory 01433 table_list->db= db; 01434 table_list->table_name= table_list->alias= tbl_name; 01435 table_list->lock_type= TL_READ_NO_INSERT; 01436 table_list->prev_global= &table_list; // can be removed after merge with 4.1 01437 01438 if (!db || check_db_name(db)) 01439 { 01440 my_error(ER_WRONG_DB_NAME ,MYF(0), db ? db : "NULL"); 01441 goto err; 01442 } 01443 if (lower_case_table_names) 01444 my_casedn_str(files_charset_info, tbl_name); 01445 remove_escape(table_list->table_name); 01446 01447 if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT))) 01448 DBUG_RETURN(1); 01449 01450 if (check_one_table_access(thd, SELECT_ACL, table_list)) 01451 goto err; 01452 thd->free_list = 0; 01453 thd->query_length=(uint) strlen(tbl_name); 01454 thd->query = tbl_name; 01455 if ((error = mysqld_dump_create_info(thd, table_list, -1))) 01456 { 01457 my_error(ER_GET_ERRNO, MYF(0), my_errno); 01458 goto err; 01459 } 01460 net_flush(&thd->net); 01461 if ((error= table->file->dump(thd,-1))) 01462 my_error(ER_GET_ERRNO, MYF(0), error); 01463 01464 err: 01465 DBUG_RETURN(error); 01466 } 01467 01468 /* 01469 Ends the current transaction and (maybe) begin the next 01470 01471 SYNOPSIS 01472 end_trans() 01473 thd Current thread 01474 completion Completion type 01475 01476 RETURN 01477 0 - OK 01478 */ 01479 01480 int end_trans(THD *thd, enum enum_mysql_completiontype completion) 01481 { 01482 bool do_release= 0; 01483 int res= 0; 01484 DBUG_ENTER("end_trans"); 01485 01486 if (unlikely(thd->in_sub_stmt)) 01487 { 01488 my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); 01489 DBUG_RETURN(1); 01490 } 01491 if (thd->transaction.xid_state.xa_state != XA_NOTR) 01492 { 01493 my_error(ER_XAER_RMFAIL, MYF(0), 01494 xa_state_names[thd->transaction.xid_state.xa_state]); 01495 DBUG_RETURN(1); 01496 } 01497 switch (completion) { 01498 case COMMIT: 01499 /* 01500 We don't use end_active_trans() here to ensure that this works 01501 even if there is a problem with the OPTION_AUTO_COMMIT flag 01502 (Which of course should never happen...) 01503 */ 01504 thd->server_status&= ~SERVER_STATUS_IN_TRANS; 01505 res= ha_commit(thd); 01506 thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE | 01507 OPTION_KEEP_LOG); 01508 break; 01509 case COMMIT_RELEASE: 01510 do_release= 1; /* fall through */ 01511 case COMMIT_AND_CHAIN: 01512 res= end_active_trans(thd); 01513 if (!res && completion == COMMIT_AND_CHAIN) 01514 res= begin_trans(thd); 01515 break; 01516 case ROLLBACK_RELEASE: 01517 do_release= 1; /* fall through */ 01518 case ROLLBACK: 01519 case ROLLBACK_AND_CHAIN: 01520 { 01521 thd->server_status&= ~SERVER_STATUS_IN_TRANS; 01522 if (ha_rollback(thd)) 01523 res= -1; 01524 thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE | 01525 OPTION_KEEP_LOG); 01526 if (!res && (completion == ROLLBACK_AND_CHAIN)) 01527 res= begin_trans(thd); 01528 break; 01529 } 01530 default: 01531 res= -1; 01532 my_error(ER_UNKNOWN_COM_ERROR, MYF(0)); 01533 DBUG_RETURN(-1); 01534 } 01535 01536 if (res < 0) 01537 my_error(thd->killed_errno(), MYF(0)); 01538 else if ((res == 0) && do_release) 01539 thd->killed= THD::KILL_CONNECTION; 01540 01541 DBUG_RETURN(res); 01542 } 01543 01544 #ifndef EMBEDDED_LIBRARY 01545 01546 /* 01547 Read one command from socket and execute it (query or simple command). 01548 This function is called in loop from thread function. 01549 SYNOPSIS 01550 do_command() 01551 RETURN VALUE 01552 0 success 01553 1 request of thread shutdown (see dispatch_command() description) 01554 */ 01555 01556 bool do_command(THD *thd) 01557 { 01558 char *packet; 01559 uint old_timeout; 01560 ulong packet_length; 01561 NET *net; 01562 enum enum_server_command command; 01563 DBUG_ENTER("do_command"); 01564 01565 net= &thd->net; 01566 /* 01567 indicator of uninitialized lex => normal flow of errors handling 01568 (see my_message_sql) 01569 */ 01570 thd->lex->current_select= 0; 01571 01572 packet=0; 01573 old_timeout=net->read_timeout; 01574 /* Wait max for 8 hours */ 01575 net->read_timeout=(uint) thd->variables.net_wait_timeout; 01576 thd->clear_error(); // Clear error message 01577 01578 net_new_transaction(net); 01579 if ((packet_length=my_net_read(net)) == packet_error) 01580 { 01581 DBUG_PRINT("info",("Got error %d reading command from socket %s", 01582 net->error, 01583 vio_description(net->vio))); 01584 /* Check if we can continue without closing the connection */ 01585 if (net->error != 3) 01586 { 01587 statistic_increment(aborted_threads,&LOCK_status); 01588 DBUG_RETURN(TRUE); // We have to close it. 01589 } 01590 net_send_error(thd, net->last_errno, NullS); 01591 net->error= 0; 01592 DBUG_RETURN(FALSE); 01593 } 01594 else 01595 { 01596 packet=(char*) net->read_pos; 01597 command = (enum enum_server_command) (uchar) packet[0]; 01598 if (command >= COM_END) 01599 command= COM_END; // Wrong command 01600 DBUG_PRINT("info",("Command on %s = %d (%s)", 01601 vio_description(net->vio), command, 01602 command_name[command])); 01603 } 01604 net->read_timeout=old_timeout; // restore it 01605 /* 01606 packet_length contains length of data, as it was stored in packet 01607 header. In case of malformed header, packet_length can be zero. 01608 If packet_length is not zero, my_net_read ensures that this number 01609 of bytes was actually read from network. Additionally my_net_read 01610 sets packet[packet_length]= 0 (thus if packet_length == 0, 01611 command == packet[0] == COM_SLEEP). 01612 In dispatch_command packet[packet_length] points beyond the end of packet. 01613 */ 01614 DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length)); 01615 } 01616 #endif /* EMBEDDED_LIBRARY */ 01617 01618 01619 /* 01620 Perform one connection-level (COM_XXXX) command. 01621 01622 SYNOPSIS 01623 dispatch_command() 01624 thd connection handle 01625 command type of command to perform 01626 packet data for the command, packet is always null-terminated 01627 packet_length length of packet + 1 (to show that data is 01628 null-terminated) except for COM_SLEEP, where it 01629 can be zero. 01630 RETURN VALUE 01631 0 ok 01632 1 request of thread shutdown, i. e. if command is 01633 COM_QUIT/COM_SHUTDOWN 01634 */ 01635 01636 bool dispatch_command(enum enum_server_command command, THD *thd, 01637 char* packet, uint packet_length) 01638 { 01639 NET *net= &thd->net; 01640 bool error= 0; 01641 DBUG_ENTER("dispatch_command"); 01642 01643 if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) 01644 thd->killed= THD::NOT_KILLED; 01645 01646 thd->command=command; 01647 /* 01648 Commands which always take a long time are logged into 01649 the slow log only if opt_log_slow_admin_statements is set. 01650 */ 01651 thd->enable_slow_log= TRUE; 01652 thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ 01653 thd->set_time(); 01654 VOID(pthread_mutex_lock(&LOCK_thread_count)); 01655 thd->query_id=query_id; 01656 if (command != COM_STATISTICS && command != COM_PING) 01657 next_query_id(); 01658 thread_running++; 01659 /* TODO: set thd->lex->sql_command to SQLCOM_END here */ 01660 VOID(pthread_mutex_unlock(&LOCK_thread_count)); 01661 01662 thd->server_status&= 01663 ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); 01664 switch (command) { 01665 case COM_INIT_DB: 01666 { 01667 LEX_STRING tmp; 01668 statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB], 01669 &LOCK_status); 01670 thd->convert_string(&tmp, system_charset_info, 01671 packet, strlen(packet), thd->charset()); 01672 if (!mysql_change_db(thd, tmp.str, FALSE)) 01673 { 01674 general_log_print(thd, command, "%s",thd->db); 01675 send_ok(thd); 01676 } 01677 break; 01678 } 01679 #ifdef HAVE_REPLICATION 01680 case COM_REGISTER_SLAVE: 01681 { 01682 if (!register_slave(thd, (uchar*)packet, packet_length)) 01683 send_ok(thd); 01684 break; 01685 } 01686 #endif 01687 case COM_TABLE_DUMP: 01688 { 01689 char *db, *tbl_name; 01690 uint db_len= *(uchar*) packet; 01691 if (db_len >= packet_length || db_len > NAME_LEN) 01692 { 01693 my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); 01694 break; 01695 } 01696 uint tbl_len= *(uchar*) (packet + db_len + 1); 01697 if (db_len+tbl_len+2 > packet_length || tbl_len > NAME_LEN) 01698 { 01699 my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); 01700 break; 01701 } 01702 01703 statistic_increment(thd->status_var.com_other, &LOCK_status); 01704 thd->enable_slow_log= opt_log_slow_admin_statements; 01705 db= thd->alloc(db_len + tbl_len + 2); 01706 if (!db) 01707 { 01708 my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); 01709 break; 01710 } 01711 tbl_name= strmake(db, packet + 1, db_len)+1; 01712 strmake(tbl_name, packet + db_len + 2, tbl_len); 01713 mysql_table_dump(thd, db, tbl_name); 01714 break; 01715 } 01716 case COM_CHANGE_USER: 01717 { 01718 thd->change_user(); 01719 thd->clear_error(); // if errors from rollback 01720 01721 statistic_increment(thd->status_var.com_other, &LOCK_status); 01722 char *user= (char*) packet; 01723 char *passwd= strend(user)+1; 01724 /* 01725 Old clients send null-terminated string ('\0' for empty string) for 01726 password. New clients send the size (1 byte) + string (not null 01727 terminated, so also '\0' for empty string). 01728 */ 01729 char db_buff[NAME_LEN+1]; // buffer to store db in utf8 01730 char *db= passwd; 01731 uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? 01732 *passwd++ : strlen(passwd); 01733 db+= passwd_len + 1; 01734 #ifndef EMBEDDED_LIBRARY 01735 /* Small check for incoming packet */ 01736 if ((uint) ((uchar*) db - net->read_pos) > packet_length) 01737 { 01738 my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); 01739 break; 01740 } 01741 #endif 01742 /* Convert database name to utf8 */ 01743 uint dummy_errors; 01744 db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1, 01745 system_charset_info, db, strlen(db), 01746 thd->charset(), &dummy_errors)]= 0; 01747 db= db_buff; 01748 01749 /* Save user and privileges */ 01750 uint save_db_length= thd->db_length; 01751 char *save_db= thd->db; 01752 Security_context save_security_ctx= *thd->security_ctx; 01753 USER_CONN *save_user_connect= thd->user_connect; 01754 01755 if (!(thd->security_ctx->user= my_strdup(user, MYF(0)))) 01756 { 01757 thd->security_ctx->user= save_security_ctx.user; 01758 my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); 01759 break; 01760 } 01761 01762 /* Clear variables that are allocated */ 01763 thd->user_connect= 0; 01764 int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE); 01765 01766 if (res) 01767 { 01768 /* authentication failure, we shall restore old user */ 01769 if (res > 0) 01770 my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); 01771 x_free(thd->security_ctx->user); 01772 *thd->security_ctx= save_security_ctx; 01773 thd->user_connect= save_user_connect; 01774 thd->db= save_db; 01775 thd->db_length= save_db_length; 01776 } 01777 else 01778 { 01779 #ifndef NO_EMBEDDED_ACCESS_CHECKS 01780 /* we've authenticated new user */ 01781 if (save_user_connect) 01782 decrease_user_connections(save_user_connect); 01783 #endif /* NO_EMBEDDED_ACCESS_CHECKS */ 01784 x_free((gptr) save_db); 01785 x_free((gptr) save_security_ctx.user); 01786 } 01787 break; 01788 } 01789 case COM_STMT_EXECUTE: 01790 { 01791 mysql_stmt_execute(thd, packet, packet_length); 01792 break; 01793 } 01794 case COM_STMT_FETCH: 01795 { 01796 mysql_stmt_fetch(thd, packet, packet_length); 01797 break; 01798 } 01799 case COM_STMT_SEND_LONG_DATA: 01800 { 01801 mysql_stmt_get_longdata(thd, packet, packet_length); 01802 break; 01803 } 01804 case COM_STMT_PREPARE: 01805 { 01806 mysql_stmt_prepare(thd, packet, packet_length); 01807 break; 01808 } 01809 case COM_STMT_CLOSE: 01810 { 01811 mysql_stmt_close(thd, packet); 01812 break; 01813 } 01814 case COM_STMT_RESET: 01815 { 01816 mysql_stmt_reset(thd, packet); 01817 break; 01818 } 01819 case COM_QUERY: 01820 { 01821 if (alloc_query(thd, packet, packet_length)) 01822 break; // fatal error is set 01823 char *packet_end= thd->query + thd->query_length; 01824 general_log_print(thd, command, "%.*b", thd->query_length, thd->query); 01825 DBUG_PRINT("query",("%-.4096s",thd->query)); 01826 01827 if (!(specialflag & SPECIAL_NO_PRIOR)) 01828 my_pthread_setprio(pthread_self(),QUERY_PRIOR); 01829 01830 mysql_parse(thd,thd->query, thd->query_length); 01831 01832 while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error) 01833 { 01834 char *packet= thd->lex->found_semicolon; 01835 net->no_send_error= 0; 01836 /* 01837 Multiple queries exits, execute them individually 01838 */ 01839 if (thd->lock || thd->open_tables || thd->derived_tables || 01840 thd->prelocked_mode) 01841 close_thread_tables(thd); 01842 ulong length= (ulong)(packet_end-packet); 01843 01844 log_slow_statement(thd); 01845 01846 /* Remove garbage at start of query */ 01847 while (my_isspace(thd->charset(), *packet) && length > 0) 01848 { 01849 packet++; 01850 length--; 01851 } 01852 VOID(pthread_mutex_lock(&LOCK_thread_count)); 01853 thd->query_length= length; 01854 thd->query= packet; 01855 thd->query_id= next_query_id(); 01856 thd->set_time(); /* Reset the query start time. */ 01857 /* TODO: set thd->lex->sql_command to SQLCOM_END here */ 01858 VOID(pthread_mutex_unlock(&LOCK_thread_count)); 01859 mysql_parse(thd, packet, length); 01860 } 01861 01862 if (!(specialflag & SPECIAL_NO_PRIOR)) 01863 my_pthread_setprio(pthread_self(),WAIT_PRIOR); 01864 DBUG_PRINT("info",("query ready")); 01865 break; 01866 } 01867 case COM_FIELD_LIST: // This isn't actually needed 01868 #ifdef DONT_ALLOW_SHOW_COMMANDS 01869 my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), 01870 MYF(0)); /* purecov: inspected */ 01871 break; 01872 #else 01873 { 01874 char *fields, *pend; 01875 /* Locked closure of all tables */ 01876 TABLE_LIST *locked_tables= NULL; 01877 TABLE_LIST table_list; 01878 LEX_STRING conv_name; 01879 /* Saved variable value */ 01880 my_bool old_innodb_table_locks= thd->variables.innodb_table_locks; 01881 01882 01883 /* used as fields initializator */ 01884 lex_start(thd, 0, 0); 01885 01886 01887 statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS], 01888 &LOCK_status); 01889 bzero((char*) &table_list,sizeof(table_list)); 01890 if (thd->copy_db_to(&table_list.db, 0)) 01891 break; 01892 pend= strend(packet); 01893 thd->convert_string(&conv_name, system_charset_info, 01894 packet, (uint) (pend-packet), thd->charset()); 01895 table_list.alias= table_list.table_name= conv_name.str; 01896 packet= pend+1; 01897 01898 if (!my_strcasecmp(system_charset_info, table_list.db, 01899 information_schema_name.str)) 01900 { 01901 ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias); 01902 if (schema_table) 01903 table_list.schema_table= schema_table; 01904 } 01905 01906 thd->query_length= strlen(packet); // for simplicity: don't optimize 01907 if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1))) 01908 break; 01909 general_log_print(thd, command, "%s %s", table_list.table_name, fields); 01910 if (lower_case_table_names) 01911 my_casedn_str(files_charset_info, table_list.table_name); 01912 remove_escape(table_list.table_name); // This can't have wildcards 01913 01914 if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege, 01915 0, 0, test(table_list.schema_table))) 01916 break; 01917 if (grant_option && 01918 check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0)) 01919 break; 01920 /* init structures for VIEW processing */ 01921 table_list.select_lex= &(thd->lex->select_lex); 01922 mysql_init_query(thd, (uchar*)"", 0); 01923 thd->lex-> 01924 select_lex.table_list.link_in_list((byte*) &table_list, 01925 (byte**) &table_list.next_local); 01926 thd->lex->add_to_query_tables(&table_list); 01927 01928 /* switch on VIEW optimisation: do not fill temporary tables */ 01929 thd->lex->sql_command= SQLCOM_SHOW_FIELDS; 01930 mysqld_list_fields(thd,&table_list,fields); 01931 thd->lex->unit.cleanup(); 01932 thd->cleanup_after_query(); 01933 break; 01934 } 01935 #endif 01936 case COM_QUIT: 01937 /* We don't calculate statistics for this command */ 01938 general_log_print(thd, command, NullS); 01939 net->error=0; // Don't give 'abort' message 01940 error=TRUE; // End server 01941 break; 01942 01943 case COM_CREATE_DB: // QQ: To be removed 01944 { 01945 char *db=thd->strdup(packet), *alias; 01946 HA_CREATE_INFO create_info; 01947 01948 statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB], 01949 &LOCK_status); 01950 // null test to handle EOM 01951 if (!db || !(alias= thd->strdup(db)) || check_db_name(db)) 01952 { 01953 my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL"); 01954 break; 01955 } 01956 if (check_access(thd,CREATE_ACL,db,0,1,0,is_schema_db(db))) 01957 break; 01958 general_log_print(thd, command, packet); 01959 bzero(&create_info, sizeof(create_info)); 01960 mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db), 01961 &create_info, 0); 01962 break; 01963 } 01964 case COM_DROP_DB: // QQ: To be removed 01965 { 01966 statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB], 01967 &LOCK_status); 01968 char *db=thd->strdup(packet); 01969 /* null test to handle EOM */ 01970 if (!db || check_db_name(db)) 01971 { 01972 my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL"); 01973 break; 01974 } 01975 if (check_access(thd,DROP_ACL,db,0,1,0,is_schema_db(db))) 01976 break; 01977 if (thd->locked_tables || thd->active_transaction()) 01978 { 01979 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, 01980 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); 01981 break; 01982 } 01983 general_log_print(thd, command, db); 01984 mysql_rm_db(thd, db, 0, 0); 01985 break; 01986 } 01987 #ifndef EMBEDDED_LIBRARY 01988 case COM_BINLOG_DUMP: 01989 { 01990 ulong pos; 01991 ushort flags; 01992 uint32 slave_server_id; 01993 01994 statistic_increment(thd->status_var.com_other,&LOCK_status); 01995 thd->enable_slow_log= opt_log_slow_admin_statements; 01996 if (check_global_access(thd, REPL_SLAVE_ACL)) 01997 break; 01998 01999 /* TODO: The following has to be changed to an 8 byte integer */ 02000 pos = uint4korr(packet); 02001 flags = uint2korr(packet + 4); 02002 thd->server_id=0; /* avoid suicide */ 02003 if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0 02004 kill_zombie_dump_threads(slave_server_id); 02005 thd->server_id = slave_server_id; 02006 02007 general_log_print(thd, command, "Log: '%s' Pos: %ld", packet+10, 02008 (long) pos); 02009 mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags); 02010 unregister_slave(thd,1,1); 02011 /* fake COM_QUIT -- if we get here, the thread needs to terminate */ 02012 error = TRUE; 02013 net->error = 0; 02014 break; 02015 } 02016 #endif 02017 case COM_REFRESH: 02018 { 02019 bool not_used; 02020 statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH], 02021 &LOCK_status); 02022 ulong options= (ulong) (uchar) packet[0]; 02023 if (check_global_access(thd,RELOAD_ACL)) 02024 break; 02025 general_log_print(thd, command, NullS); 02026 if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used)) 02027 send_ok(thd); 02028 break; 02029 } 02030 #ifndef EMBEDDED_LIBRARY 02031 case COM_SHUTDOWN: 02032 { 02033 statistic_increment(thd->status_var.com_other, &LOCK_status); 02034 if (check_global_access(thd,SHUTDOWN_ACL)) 02035 break; /* purecov: inspected */ 02036 /* 02037 If the client is < 4.1.3, it is going to send us no argument; then 02038 packet_length is 1, packet[0] is the end 0 of the packet. Note that 02039 SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in 02040 packet[0]. 02041 */ 02042 enum mysql_enum_shutdown_level level= 02043 (enum mysql_enum_shutdown_level) (uchar) packet[0]; 02044 DBUG_PRINT("quit",("Got shutdown command for level %u", level)); 02045 if (level == SHUTDOWN_DEFAULT) 02046 level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable 02047 else if (level != SHUTDOWN_WAIT_ALL_BUFFERS) 02048 { 02049 my_error(ER_NOT_SUPPORTED_YET, MYF(0), "this shutdown level"); 02050 break; 02051 } 02052 DBUG_PRINT("quit",("Got shutdown command for level %u", level)); 02053 general_log_print(thd, command, NullS); 02054 send_eof(thd); 02055 #ifdef __WIN__ 02056 sleep(1); // must wait after eof() 02057 #endif 02058 send_eof(thd); // This is for 'quit request' 02059 close_connection(thd, 0, 1); 02060 close_thread_tables(thd); // Free before kill 02061 kill_mysql(); 02062 error=TRUE; 02063 break; 02064 } 02065 #endif 02066 case COM_STATISTICS: 02067 { 02068 general_log_print(thd, command, NullS); 02069 statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS], 02070 &LOCK_status); 02071 #ifndef EMBEDDED_LIBRARY 02072 char buff[200]; 02073 #else 02074 char *buff= thd->net.last_error; 02075 #endif 02076 02077 STATUS_VAR current_global_status_var; 02078 calc_sum_of_all_status(¤t_global_status_var); 02079 02080 ulong uptime = (ulong) (thd->start_time - start_time); 02081 sprintf((char*) buff, 02082 "Uptime: %lu Threads: %d Questions: %lu Slow queries: %lu Opens: %lu Flush tables: %lu Open tables: %u Queries per second avg: %.3f", 02083 uptime, 02084 (int) thread_count, (ulong) thd->query_id, 02085 current_global_status_var.long_query_count, 02086 current_global_status_var.opened_tables, refresh_version, 02087 cached_open_tables(), 02088 (uptime ? (ulonglong2double(thd->query_id) / (double) uptime) : 02089 (double) 0)); 02090 #ifdef SAFEMALLOC 02091 if (sf_malloc_cur_memory) // Using SAFEMALLOC 02092 sprintf(strend(buff), " Memory in use: %ldK Max memory used: %ldK", 02093 (sf_malloc_cur_memory+1023L)/1024L, 02094 (sf_malloc_max_memory+1023L)/1024L); 02095 #endif 02096 #ifndef EMBEDDED_LIBRARY 02097 VOID(my_net_write(net, buff,(uint) strlen(buff))); 02098 VOID(net_flush(net)); 02099 #endif 02100 break; 02101 } 02102 case COM_PING: 02103 statistic_increment(thd->status_var.com_other, &LOCK_status); 02104 send_ok(thd); // Tell client we are alive 02105 break; 02106 case COM_PROCESS_INFO: 02107 statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST], 02108 &LOCK_status); 02109 if (!thd->security_ctx->priv_user[0] && 02110 check_global_access(thd, PROCESS_ACL)) 02111 break; 02112 general_log_print(thd, command, NullS); 02113 mysqld_list_processes(thd, 02114 thd->security_ctx->master_access & PROCESS_ACL ? 02115 NullS : thd->security_ctx->priv_user, 0); 02116 break; 02117 case COM_PROCESS_KILL: 02118 { 02119 statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status); 02120 ulong id=(ulong) uint4korr(packet); 02121 sql_kill(thd,id,false); 02122 break; 02123 } 02124 case COM_SET_OPTION: 02125 { 02126 statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION], 02127 &LOCK_status); 02128 enum_mysql_set_option command= (enum_mysql_set_option) uint2korr(packet); 02129 switch (command) { 02130 case MYSQL_OPTION_MULTI_STATEMENTS_ON: 02131 thd->client_capabilities|= CLIENT_MULTI_STATEMENTS; 02132 send_eof(thd); 02133 break; 02134 case MYSQL_OPTION_MULTI_STATEMENTS_OFF: 02135 thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS; 02136 send_eof(thd); 02137 break; 02138 default: 02139 my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); 02140 break; 02141 } 02142 break; 02143 } 02144 case COM_DEBUG: 02145 statistic_increment(thd->status_var.com_other, &LOCK_status); 02146 if (check_global_access(thd, SUPER_ACL)) 02147 break; /* purecov: inspected */ 02148 mysql_print_status(); 02149 general_log_print(thd, command, NullS); 02150 send_eof(thd); 02151 break; 02152 case COM_SLEEP: 02153 case COM_CONNECT: // Impossible here 02154 case COM_TIME: // Impossible from client 02155 case COM_DELAYED_INSERT: 02156 case COM_END: 02157 default: 02158 my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); 02159 break; 02160 } 02161 if (thd->lock || thd->open_tables || thd->derived_tables || 02162 thd->prelocked_mode) 02163 { 02164 thd->proc_info="closing tables"; 02165 close_thread_tables(thd); /* Free tables */ 02166 } 02167 /* 02168 assume handlers auto-commit (if some doesn't - transaction handling 02169 in MySQL should be redesigned to support it; it's a big change, 02170 and it's not worth it - better to commit explicitly only writing 02171 transactions, read-only ones should better take care of themselves. 02172 saves some work in 2pc too) 02173 see also sql_base.cc - close_thread_tables() 02174 */ 02175 bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt)); 02176 if (!thd->active_transaction()) 02177 thd->transaction.xid_state.xid.null(); 02178 02179 /* report error issued during command execution */ 02180 if (thd->killed_errno() && !thd->net.report_error) 02181 thd->send_kill_message(); 02182 if (thd->net.report_error) 02183 net_send_error(thd); 02184 02185 log_slow_statement(thd); 02186 02187 thd->proc_info="cleaning up"; 02188 VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list 02189 thd->proc_info=0; 02190 thd->command=COM_SLEEP; 02191 thd->query=0; 02192 thd->query_length=0; 02193 thread_running--; 02194 VOID(pthread_mutex_unlock(&LOCK_thread_count)); 02195 thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory 02196 free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); 02197 DBUG_RETURN(error); 02198 } 02199 02200 02201 void log_slow_statement(THD *thd) 02202 { 02203 time_t start_of_query; 02204 DBUG_ENTER("log_slow_statement"); 02205 02206 /* 02207 The following should never be true with our current code base, 02208 but better to keep this here so we don't accidently try to log a 02209 statement in a trigger or stored function 02210 */ 02211 if (unlikely(thd->in_sub_stmt)) 02212 DBUG_VOID_RETURN; // Don't set time for sub stmt 02213 02214 start_of_query= thd->start_time; 02215 thd->end_time(); // Set start time 02216 02217 /* 02218 Do not log administrative statements unless the appropriate option is 02219 set; do not log into slow log if reading from backup. 02220 */ 02221 if (thd->enable_slow_log && !thd->user_time) 02222 { 02223 thd->proc_info="logging slow query"; 02224 02225 if ((ulong) (thd->start_time - thd->time_after_lock) > 02226 thd->variables.long_query_time || 02227 ((thd->server_status & 02228 (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && 02229 (specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES))) 02230 { 02231 thd->status_var.long_query_count++; 02232 slow_log_print(thd, thd->query, thd->query_length, start_of_query); 02233 } 02234 } 02235 DBUG_VOID_RETURN; 02236 } 02237 02238 02239 /* 02240 Create a TABLE_LIST object for an INFORMATION_SCHEMA table. 02241 02242 SYNOPSIS 02243 prepare_schema_table() 02244 thd thread handle 02245 lex current lex 02246 table_ident table alias if it's used 02247 schema_table_idx the type of the INFORMATION_SCHEMA table to be 02248 created 02249 02250 DESCRIPTION 02251 This function is used in the parser to convert a SHOW or DESCRIBE 02252 table_name command to a SELECT from INFORMATION_SCHEMA. 02253 It prepares a SELECT_LEX and a TABLE_LIST object to represent the 02254 given command as a SELECT parse tree. 02255 02256 NOTES 02257 Due to the way this function works with memory and LEX it cannot 02258 be used outside the parser (parse tree transformations outside 02259 the parser break PS and SP). 02260 02261 RETURN VALUE 02262 0 success 02263 1 out of memory or SHOW commands are not allowed 02264 in this version of the server. 02265 */ 02266 02267 int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, 02268 enum enum_schema_tables schema_table_idx) 02269 { 02270 DBUG_ENTER("prepare_schema_table"); 02271 SELECT_LEX *sel= 0; 02272 switch (schema_table_idx) { 02273 case SCH_SCHEMATA: 02274 #if defined(DONT_ALLOW_SHOW_COMMANDS) 02275 my_message(ER_NOT_ALLOWED_COMMAND, 02276 ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ 02277 DBUG_RETURN(1); 02278 #else 02279 if ((specialflag & SPECIAL_SKIP_SHOW_DB) && 02280 check_global_access(thd, SHOW_DB_ACL)) 02281 DBUG_RETURN(1); 02282 break; 02283 #endif 02284 case SCH_TABLE_NAMES: 02285 case SCH_TABLES: 02286 case SCH_VIEWS: 02287 case SCH_TRIGGERS: 02288 case SCH_EVENTS: 02289 #ifdef DONT_ALLOW_SHOW_COMMANDS 02290 my_message(ER_NOT_ALLOWED_COMMAND, 02291 ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ 02292 DBUG_RETURN(1); 02293 #else 02294 { 02295 char *db; 02296 if (lex->select_lex.db == NULL && 02297 thd->copy_db_to(&lex->select_lex.db, 0)) 02298 { 02299 DBUG_RETURN(1); 02300 } 02301 db= lex->select_lex.db; 02302 remove_escape(db); // Fix escaped '_' 02303 if (check_db_name(db)) 02304 { 02305 my_error(ER_WRONG_DB_NAME, MYF(0), db); 02306 DBUG_RETURN(1); 02307 } 02308 if (check_access(thd, SELECT_ACL, db, &thd->col_access, 0, 0, 02309 is_schema_db(db))) 02310 DBUG_RETURN(1); /* purecov: inspected */ 02311 if (!thd->col_access && check_grant_db(thd,db)) 02312 { 02313 my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), 02314 thd->security_ctx->priv_user, thd->security_ctx->priv_host, 02315 db); 02316 DBUG_RETURN(1); 02317 } 02318 break; 02319 } 02320 #endif 02321 case SCH_COLUMNS: 02322 case SCH_STATISTICS: 02323 #ifdef DONT_ALLOW_SHOW_COMMANDS 02324 my_message(ER_NOT_ALLOWED_COMMAND, 02325 ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ 02326 DBUG_RETURN(1); 02327 #else 02328 if (table_ident) 02329 { 02330 TABLE_LIST **query_tables_last= lex->query_tables_last; 02331 sel= new SELECT_LEX(); 02332 /* 'parent_lex' is used in init_query() so it must be before it. */ 02333 sel->parent_lex= lex; 02334 sel->init_query(); 02335 if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, 02336 (List<String> *) 0, (List<String> *) 0)) 02337 DBUG_RETURN(1); 02338 lex->query_tables_last= query_tables_last; 02339 TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first; 02340 char *db= table_list->db; 02341 remove_escape(db); // Fix escaped '_' 02342 remove_escape(table_list->table_name); 02343 if (check_access(thd,SELECT_ACL | EXTRA_ACL,db, 02344 &table_list->grant.privilege, 0, 0, 02345 test(table_list->schema_table))) 02346 DBUG_RETURN(1); /* purecov: inspected */ 02347 if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2, 02348 UINT_MAX, 0)) 02349 DBUG_RETURN(1); 02350 break; 02351 } 02352 #endif 02353 case SCH_OPEN_TABLES: 02354 case SCH_VARIABLES: 02355 case SCH_STATUS: 02356 case SCH_PROCEDURES: 02357 case SCH_CHARSETS: 02358 case SCH_ENGINES: 02359 case SCH_COLLATIONS: 02360 case SCH_COLLATION_CHARACTER_SET_APPLICABILITY: 02361 case SCH_USER_PRIVILEGES: 02362 case SCH_SCHEMA_PRIVILEGES: 02363 case SCH_TABLE_PRIVILEGES: 02364 case SCH_COLUMN_PRIVILEGES: 02365 case SCH_TABLE_CONSTRAINTS: 02366 case SCH_KEY_COLUMN_USAGE: 02367 default: 02368 break; 02369 } 02370 02371 SELECT_LEX *select_lex= lex->current_select; 02372 if (make_schema_select(thd, select_lex, schema_table_idx)) 02373 { 02374 DBUG_RETURN(1); 02375 } 02376 TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first; 02377 table_list->schema_select_lex= sel; 02378 table_list->schema_table_reformed= 1; 02379 DBUG_RETURN(0); 02380 } 02381 02382 02383 /* 02384 Read query from packet and store in thd->query 02385 Used in COM_QUERY and COM_STMT_PREPARE 02386 02387 DESCRIPTION 02388 Sets the following THD variables: 02389 query 02390 query_length 02391 02392 RETURN VALUES 02393 FALSE ok 02394 TRUE error; In this case thd->fatal_error is set 02395 */ 02396 02397 bool alloc_query(THD *thd, const char *packet, uint packet_length) 02398 { 02399 packet_length--; // Remove end null 02400 /* Remove garbage at start and end of query */ 02401 while (my_isspace(thd->charset(),packet[0]) && packet_length > 0) 02402 { 02403 packet++; 02404 packet_length--; 02405 } 02406 const char *pos= packet + packet_length; // Point at end null 02407 while (packet_length > 0 && 02408 (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1]))) 02409 { 02410 pos--; 02411 packet_length--; 02412 } 02413 /* We must allocate some extra memory for query cache */ 02414 thd->query_length= 0; // Extra safety: Avoid races 02415 if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet), 02416 packet_length, 02417 thd->db_length+ 1 + 02418 QUERY_CACHE_FLAGS_SIZE))) 02419 return TRUE; 02420 thd->query[packet_length]=0; 02421 thd->query_length= packet_length; 02422 02423 /* Reclaim some memory */ 02424 thd->packet.shrink(thd->variables.net_buffer_length); 02425 thd->convert_buffer.shrink(thd->variables.net_buffer_length); 02426 02427 return FALSE; 02428 } 02429 02430 static void reset_one_shot_variables(THD *thd) 02431 { 02432 thd->variables.character_set_client= 02433 global_system_variables.character_set_client; 02434 thd->variables.collation_connection= 02435 global_system_variables.collation_connection; 02436 thd->variables.collation_database= 02437 global_system_variables.collation_database; 02438 thd->variables.collation_server= 02439 global_system_variables.collation_server; 02440 thd->update_charset(); 02441 thd->variables.time_zone= 02442 global_system_variables.time_zone; 02443 thd->one_shot_set= 0; 02444 } 02445 02446 02447 /* 02448 Execute command saved in thd and lex->sql_command 02449 02450 SYNOPSIS 02451 mysql_execute_command() 02452 thd Thread handle 02453 02454 IMPLEMENTATION 02455 02456 Before every operation that can request a write lock for a table 02457 wait if a global read lock exists. However do not wait if this 02458 thread has locked tables already. No new locks can be requested 02459 until the other locks are released. The thread that requests the 02460 global read lock waits for write locked tables to become unlocked. 02461 02462 Note that wait_if_global_read_lock() sets a protection against a new 02463 global read lock when it succeeds. This needs to be released by 02464 start_waiting_global_read_lock() after the operation. 02465 02466 RETURN 02467 FALSE OK 02468 TRUE Error 02469 */ 02470 02471 bool 02472 mysql_execute_command(THD *thd) 02473 { 02474 bool res= FALSE; 02475 bool need_start_waiting= FALSE; // have protection against global read lock 02476 int result= 0; 02477 LEX *lex= thd->lex; 02478 /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ 02479 SELECT_LEX *select_lex= &lex->select_lex; 02480 /* first table of first SELECT_LEX */ 02481 TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first; 02482 /* list of all tables in query */ 02483 TABLE_LIST *all_tables; 02484 /* most outer SELECT_LEX_UNIT of query */ 02485 SELECT_LEX_UNIT *unit= &lex->unit; 02486 /* Saved variable value */ 02487 DBUG_ENTER("mysql_execute_command"); 02488 thd->net.no_send_error= 0; 02489 #ifdef WITH_PARTITION_STORAGE_ENGINE 02490 thd->work_part_info= 0; 02491 #endif 02492 02493 /* 02494 In many cases first table of main SELECT_LEX have special meaning => 02495 check that it is first table in global list and relink it first in 02496 queries_tables list if it is necessary (we need such relinking only 02497 for queries with subqueries in select list, in this case tables of 02498 subqueries will go to global list first) 02499 02500 all_tables will differ from first_table only if most upper SELECT_LEX 02501 do not contain tables. 02502 02503 Because of above in place where should be at least one table in most 02504 outer SELECT_LEX we have following check: 02505 DBUG_ASSERT(first_table == all_tables); 02506 DBUG_ASSERT(first_table == all_tables && first_table != 0); 02507 */ 02508 lex->first_lists_tables_same(); 02509 /* should be assigned after making first tables same */ 02510 all_tables= lex->query_tables; 02511 /* set context for commands which do not use setup_tables */ 02512 select_lex-> 02513 context.resolve_in_table_list_only((TABLE_LIST*)select_lex-> 02514 table_list.first); 02515 02516 /* 02517 Reset warning count for each query that uses tables 02518 A better approach would be to reset this for any commands 02519 that is not a SHOW command or a select that only access local 02520 variables, but for now this is probably good enough. 02521 Don't reset warnings when executing a stored routine. 02522 */ 02523 if ((all_tables || &lex->select_lex != lex->all_selects_list || 02524 lex->sroutines.records) && !thd->spcont || 02525 lex->time_zone_tables_used) 02526 mysql_reset_errors(thd, 0); 02527 02528 #ifdef HAVE_REPLICATION 02529 if (unlikely(thd->slave_thread)) 02530 { 02531 /* 02532 Check if statment should be skipped because of slave filtering 02533 rules 02534 02535 Exceptions are: 02536 - UPDATE MULTI: For this statement, we want to check the filtering 02537 rules later in the code 02538 - SET: we always execute it (Not that many SET commands exists in 02539 the binary log anyway -- only 4.1 masters write SET statements, 02540 in 5.0 there are no SET statements in the binary log) 02541 - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we 02542 have stale files on slave caused by exclusion of one tmp table). 02543 */ 02544 if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) && 02545 !(lex->sql_command == SQLCOM_SET_OPTION) && 02546 !(lex->sql_command == SQLCOM_DROP_TABLE && 02547 lex->drop_temporary && lex->drop_if_exists) && 02548 all_tables_not_ok(thd, all_tables)) 02549 { 02550 /* we warn the slave SQL thread */ 02551 my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); 02552 reset_one_shot_variables(thd); 02553 DBUG_RETURN(0); 02554 } 02555 } 02556 else 02557 { 02558 #endif /* HAVE_REPLICATION */ 02559 /* 02560 When option readonly is set deny operations which change non-temporary 02561 tables. Except for the replication thread and the 'super' users. 02562 */ 02563 if (opt_readonly && 02564 !(thd->security_ctx->master_access & SUPER_ACL) && 02565 (sql_command_flags[lex->sql_command] & CF_CHANGES_DATA) && 02566 !((lex->sql_command == SQLCOM_CREATE_TABLE) && 02567 (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) && 02568 ((lex->sql_command != SQLCOM_UPDATE_MULTI) && 02569 some_non_temp_table_to_be_updated(thd, all_tables))) 02570 { 02571 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); 02572 DBUG_RETURN(-1); 02573 } 02574 #ifdef HAVE_REPLICATION 02575 } /* endif unlikely slave */ 02576 #endif 02577 statistic_increment(thd->status_var.com_stat[lex->sql_command], 02578 &LOCK_status); 02579 02580 switch (lex->sql_command) { 02581 case SQLCOM_SHOW_EVENTS: 02582 if ((res= check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0, 02583 is_schema_db(thd->lex->select_lex.db)))) 02584 break; 02585 /* fall through */ 02586 case SQLCOM_SHOW_STATUS_PROC: 02587 case SQLCOM_SHOW_STATUS_FUNC: 02588 res= execute_sqlcom_select(thd, all_tables); 02589 break; 02590 case SQLCOM_SHOW_STATUS: 02591 { 02592 system_status_var old_status_var= thd->status_var; 02593 thd->initial_status_var= &old_status_var; 02594 res= execute_sqlcom_select(thd, all_tables); 02595 /* Don't log SHOW STATUS commands to slow query log */ 02596 thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | 02597 SERVER_QUERY_NO_GOOD_INDEX_USED); 02598 /* 02599 restore status variables, as we don't want 'show status' to cause 02600 changes 02601 */ 02602 pthread_mutex_lock(&LOCK_status); 02603 add_diff_to_status(&global_status_var, &thd->status_var, 02604 &old_status_var); 02605 thd->status_var= old_status_var; 02606 pthread_mutex_unlock(&LOCK_status); 02607 break; 02608 } 02609 case SQLCOM_SHOW_DATABASES: 02610 case SQLCOM_SHOW_TABLES: 02611 case SQLCOM_SHOW_TRIGGERS: 02612 case SQLCOM_SHOW_TABLE_STATUS: 02613 case SQLCOM_SHOW_OPEN_TABLES: 02614 case SQLCOM_SHOW_PLUGINS: 02615 case SQLCOM_SHOW_FIELDS: 02616 case SQLCOM_SHOW_KEYS: 02617 case SQLCOM_SHOW_VARIABLES: 02618 case SQLCOM_SHOW_CHARSETS: 02619 case SQLCOM_SHOW_COLLATIONS: 02620 case SQLCOM_SELECT: 02621 thd->status_var.last_query_cost= 0.0; 02622 if (all_tables) 02623 { 02624 res= check_table_access(thd, 02625 lex->exchange ? SELECT_ACL | FILE_ACL : 02626 SELECT_ACL, 02627 all_tables, 0); 02628 } 02629 else 02630 res= check_access(thd, 02631 lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL, 02632 any_db, 0, 0, 0, 0); 02633 if (!res) 02634 res= execute_sqlcom_select(thd, all_tables); 02635 break; 02636 case SQLCOM_PREPARE: 02637 { 02638 mysql_sql_stmt_prepare(thd); 02639 break; 02640 } 02641 case SQLCOM_EXECUTE: 02642 { 02643 mysql_sql_stmt_execute(thd); 02644 break; 02645 } 02646 case SQLCOM_DEALLOCATE_PREPARE: 02647 { 02648 mysql_sql_stmt_close(thd); 02649 break; 02650 } 02651 case SQLCOM_DO: 02652 if (check_table_access(thd, SELECT_ACL, all_tables, 0) || 02653 open_and_lock_tables(thd, all_tables)) 02654 goto error; 02655 02656 res= mysql_do(thd, *lex->insert_list); 02657 break; 02658 02659 case SQLCOM_EMPTY_QUERY: 02660 send_ok(thd); 02661 break; 02662 02663 case SQLCOM_HELP: 02664 res= mysqld_help(thd,lex->help_arg); 02665 break; 02666 02667 #ifndef EMBEDDED_LIBRARY 02668 case SQLCOM_PURGE: 02669 { 02670 if (check_global_access(thd, SUPER_ACL)) 02671 goto error; 02672 /* PURGE MASTER LOGS TO 'file' */ 02673 res = purge_master_logs(thd, lex->to_log); 02674 break; 02675 } 02676 case SQLCOM_PURGE_BEFORE: 02677 { 02678 Item *it; 02679 02680 if (check_global_access(thd, SUPER_ACL)) 02681 goto error; 02682 /* PURGE MASTER LOGS BEFORE 'data' */ 02683 it= (Item *)lex->value_list.head(); 02684 if ((!it->fixed && it->fix_fields(lex->thd, &it)) || 02685 it->check_cols(1)) 02686 { 02687 my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE"); 02688 goto error; 02689 } 02690 it= new Item_func_unix_timestamp(it); 02691 /* 02692 it is OK only emulate fix_fieds, because we need only 02693 value of constant 02694 */ 02695 it->quick_fix_field(); 02696 res = purge_master_logs_before_date(thd, (ulong)it->val_int()); 02697 break; 02698 } 02699 #endif 02700 case SQLCOM_SHOW_WARNS: 02701 { 02702 res= mysqld_show_warnings(thd, (ulong) 02703 ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) | 02704 (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) | 02705 (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR) 02706 )); 02707 break; 02708 } 02709 case SQLCOM_SHOW_ERRORS: 02710 { 02711 res= mysqld_show_warnings(thd, (ulong) 02712 (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)); 02713 break; 02714 } 02715 case SQLCOM_SHOW_NEW_MASTER: 02716 { 02717 if (check_global_access(thd, REPL_SLAVE_ACL)) 02718 goto error; 02719 /* This query don't work now. See comment in repl_failsafe.cc */ 02720 #ifndef WORKING_NEW_MASTER 02721 my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER"); 02722 goto error; 02723 #else 02724 res = show_new_master(thd); 02725 break; 02726 #endif 02727 } 02728 02729 #ifdef HAVE_REPLICATION 02730 case SQLCOM_SHOW_SLAVE_HOSTS: 02731 { 02732 if (check_global_access(thd, REPL_SLAVE_ACL)) 02733 goto error; 02734 res = show_slave_hosts(thd); 02735 break; 02736 } 02737 case SQLCOM_SHOW_BINLOG_EVENTS: 02738 { 02739 if (check_global_access(thd, REPL_SLAVE_ACL)) 02740 goto error; 02741 res = mysql_show_binlog_events(thd); 02742 break; 02743 } 02744 #endif 02745 02746 case SQLCOM_BACKUP_TABLE: 02747 { 02748 DBUG_ASSERT(first_table == all_tables && first_table != 0); 02749 if (check_table_access(thd, SELECT_ACL, all_tables, 0) || 02750 check_global_access(thd, FILE_ACL)) 02751 goto error; /* purecov: inspected */ 02752 thd->enable_slow_log= opt_log_slow_admin_statements; 02753 res = mysql_backup_table(thd, first_table); 02754 select_lex->table_list.first= (byte*) first_table; 02755 lex->query_tables=all_tables; 02756 break; 02757 } 02758 case SQLCOM_RESTORE_TABLE: 02759 { 02760 DBUG_ASSERT(first_table == all_tables && first_table != 0); 02761 if (check_table_access(thd, INSERT_ACL, all_tables, 0) || 02762 check_global_access(thd, FILE_ACL)) 02763 goto error; /* purecov: inspected */ 02764 thd->enable_slow_log= opt_log_slow_admin_statements; 02765 res = mysql_restore_table(thd, first_table); 02766 select_lex->table_list.first= (byte*) first_table; 02767 lex->query_tables=all_tables; 02768 break; 02769 } 02770 case SQLCOM_ASSIGN_TO_KEYCACHE: 02771 { 02772 DBUG_ASSERT(first_table == all_tables && first_table != 0); 02773 if (check_access(thd, INDEX_ACL, first_table->db, 02774 &first_table->grant.privilege, 0, 0, 02775 test(first_table->schema_table))) 02776 goto error; 02777 res= mysql_assign_to_keycache(thd, first_table, &lex->ident); 02778 break; 02779 } 02780 case SQLCOM_PRELOAD_KEYS: 02781 { 02782 DBUG_ASSERT(first_table == all_tables && first_table != 0); 02783 if (check_access(thd, INDEX_ACL, first_table->db, 02784 &first_table->grant.privilege, 0, 0, 02785 test(first_table->schema_table))) 02786 goto error; 02787 res = mysql_preload_keys(thd, first_table); 02788 break; 02789 } 02790 #ifdef HAVE_REPLICATION 02791 case SQLCOM_CHANGE_MASTER: 02792 { 02793 if (check_global_access(thd, SUPER_ACL)) 02794 goto error; 02795 pthread_mutex_lock(&LOCK_active_mi); 02796 res = change_master(thd,active_mi); 02797 pthread_mutex_unlock(&LOCK_active_mi); 02798 break; 02799 } 02800 case SQLCOM_SHOW_SLAVE_STAT: 02801 { 02802 /* Accept one of two privileges */ 02803 if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) 02804 goto error; 02805 pthread_mutex_lock(&LOCK_active_mi); 02806 res = show_master_info(thd,active_mi); 02807 pthread_mutex_unlock(&LOCK_active_mi); 02808 break; 02809 } 02810 case SQLCOM_SHOW_MASTER_STAT: 02811 { 02812 /* Accept one of two privileges */ 02813 if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) 02814 goto error; 02815 res = show_binlog_info(thd); 02816 break; 02817 } 02818 02819 case SQLCOM_LOAD_MASTER_DATA: // sync with master 02820 if (check_global_access(thd, SUPER_ACL)) 02821 goto error; 02822 if (end_active_trans(thd)) 02823 goto error; 02824 res = load_master_data(thd); 02825 break; 02826 #endif /* HAVE_REPLICATION */ 02827 case SQLCOM_SHOW_ENGINE_STATUS: 02828 { 02829 if (check_global_access(thd, SUPER_ACL)) 02830 goto error; 02831 res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_STATUS); 02832 break; 02833 } 02834 case SQLCOM_SHOW_ENGINE_MUTEX: 02835 { 02836 if (check_global_access(thd, SUPER_ACL)) 02837 goto error; 02838 res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX); 02839 break; 02840 } 02841 #ifdef HAVE_REPLICATION 02842 case SQLCOM_LOAD_MASTER_TABLE: 02843 { 02844 DBUG_ASSERT(first_table == all_tables && first_table != 0); 02845 DBUG_ASSERT(first_table->db); /* Must be set in the parser */ 02846 02847 if (check_access(thd, CREATE_ACL, first_table->db, 02848 &first_table->grant.privilege, 0, 0, 02849 test(first_table->schema_table))) 02850 goto error; /* purecov: inspected */ 02851 if (grant_option) 02852 { 02853 /* Check that the first table has CREATE privilege */ 02854 if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0)) 02855 goto error; 02856 } 02857 if (strlen(first_table->table_name) > NAME_LEN) 02858 { 02859 my_error(ER_WRONG_TABLE_NAME, MYF(0), first_table->table_name); 02860 break; 02861 } 02862 pthread_mutex_lock(&LOCK_active_mi); 02863 /* 02864 fetch_master_table will send the error to the client on failure. 02865 Give error if the table already exists. 02866 */ 02867 if (!fetch_master_table(thd, first_table->db, first_table->table_name, 02868 active_mi, 0, 0)) 02869 { 02870 send_ok(thd); 02871 } 02872 pthread_mutex_unlock(&LOCK_active_mi); 02873 break; 02874 } 02875 #endif /* HAVE_REPLICATION */ 02876 02877 case SQLCOM_CREATE_TABLE: 02878 { 02879 /* If CREATE TABLE of non-temporary table, do implicit commit */ 02880 if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) 02881 { 02882 if (end_active_trans(thd)) 02883 { 02884 res= -1; 02885 break; 02886 } 02887 } 02888 DBUG_ASSERT(first_table == all_tables && first_table != 0); 02889 bool link_to_local; 02890 // Skip first table, which is the table we are creating 02891 TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local); 02892 TABLE_LIST *select_tables= lex->query_tables; 02893 02894 if ((res= create_table_precheck(thd, select_tables, create_table))) 02895 goto end_with_restore_list; 02896 02897 #ifndef HAVE_READLINK 02898 lex->create_info.data_file_name=lex->create_info.index_file_name=0; 02899 #else 02900 /* Fix names if symlinked tables */ 02901 if (append_file_to_dir(thd, &lex->create_info.data_file_name, 02902 create_table->table_name) || 02903 append_file_to_dir(thd, &lex->create_info.index_file_name, 02904 create_table->table_name)) 02905 goto end_with_restore_list; 02906 #endif 02907 /* 02908 If we are using SET CHARSET without DEFAULT, add an implicit 02909 DEFAULT to not confuse old users. (This may change). 02910 */ 02911 if ((lex->create_info.used_fields & 02912 (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) == 02913 HA_CREATE_USED_CHARSET) 02914 { 02915 lex->create_info.used_fields&= ~HA_CREATE_USED_CHARSET; 02916 lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET; 02917 lex->create_info.default_table_charset= lex->create_info.table_charset; 02918 lex->create_info.table_charset= 0; 02919 } 02920 /* 02921 The create-select command will open and read-lock the select table 02922 and then create, open and write-lock the new table. If a global 02923 read lock steps in, we get a deadlock. The write lock waits for 02924 the global read lock, while the global read lock waits for the 02925 select table to be closed. So we wait until the global readlock is 02926 gone before starting both steps. Note that 02927 wait_if_global_read_lock() sets a protection against a new global 02928 read lock when it succeeds. This needs to be released by 02929 start_waiting_global_read_lock(). We protect the normal CREATE 02930 TABLE in the same way. That way we avoid that a new table is 02931 created during a gobal read lock. 02932 */ 02933 if (!thd->locked_tables && 02934 !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) 02935 { 02936 res= 1; 02937 goto end_with_restore_list; 02938 } 02939 #ifdef WITH_PARTITION_STORAGE_ENGINE 02940 { 02941 partition_info *part_info= thd->lex->part_info; 02942 if (part_info && !(part_info= thd->lex->part_info->get_clone())) 02943 { 02944 res= -1; 02945 goto end_with_restore_list; 02946 } 02947 thd->work_part_info= part_info; 02948 } 02949 #endif 02950 if (select_lex->item_list.elements) // With select 02951 { 02952 select_result *result; 02953 02954 select_lex->options|= SELECT_NO_UNLOCK; 02955 unit->set_limit(select_lex); 02956 02957 if (!(res= open_and_lock_tables(thd, select_tables))) 02958 { 02959 /* 02960 Is table which we are changing used somewhere in other parts 02961 of query 02962 */ 02963 if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) 02964 { 02965 TABLE_LIST *duplicate; 02966 if ((duplicate= unique_table(thd, create_table, select_tables))) 02967 { 02968 update_non_unique_table_error(create_table, "CREATE", duplicate); 02969 res= 1; 02970 goto end_with_restore_list; 02971 } 02972 } 02973 /* If we create merge table, we have to test tables in merge, too */ 02974 if (lex->create_info.used_fields & HA_CREATE_USED_UNION) 02975 { 02976 TABLE_LIST *tab; 02977 for (tab= (TABLE_LIST*) lex->create_info.merge_list.first; 02978 tab; 02979 tab= tab->next_local) 02980 { 02981 TABLE_LIST *duplicate; 02982 if ((duplicate= unique_table(thd, tab, select_tables))) 02983 { 02984 update_non_unique_table_error(tab, "CREATE", duplicate); 02985 res= 1; 02986 goto end_with_restore_list; 02987 } 02988 } 02989 } 02990 02991 if ((result= new select_create(create_table, 02992 &lex->create_info, 02993 lex->create_list, 02994 lex->key_list, 02995 select_lex->item_list, 02996 lex->duplicates, 02997 lex->ignore))) 02998 { 02999 /* 03000 CREATE from SELECT give its SELECT_LEX for SELECT, 03001 and item_list belong to SELECT 03002 */ 03003 res= handle_select(thd, lex, result, 0); 03004 delete result; 03005 } 03006 /* reset for PS */ 03007 lex->create_list.empty(); 03008 lex->key_list.empty(); 03009 } 03010 } 03011 else 03012 { 03013 /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ 03014 if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) 03015 thd->options|= OPTION_KEEP_LOG; 03016 /* regular create */ 03017 if (lex->like_name) 03018 res= mysql_create_like_table(thd, create_table, &lex->create_info, 03019 lex->like_name); 03020 else 03021 { 03022 res= mysql_create_table(thd, create_table->db, 03023 create_table->table_name, &lex->create_info, 03024 lex->create_list, 03025 lex->key_list, 0, 0, 1); 03026 } 03027 if (!res) 03028 send_ok(thd); 03029 } 03030 03031 /* put tables back for PS rexecuting */ 03032 end_with_restore_list: 03033 lex->link_first_table_back(create_table, link_to_local); 03034 break; 03035 } 03036 case SQLCOM_CREATE_INDEX: 03037 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03038 if (check_one_table_access(thd, INDEX_ACL, all_tables)) 03039 goto error; /* purecov: inspected */ 03040 thd->enable_slow_log= opt_log_slow_admin_statements; 03041 if (end_active_trans(thd)) 03042 goto error; 03043 res= mysql_create_index(thd, first_table, lex->key_list); 03044 break; 03045 03046 #ifdef HAVE_REPLICATION 03047 case SQLCOM_SLAVE_START: 03048 { 03049 pthread_mutex_lock(&LOCK_active_mi); 03050 start_slave(thd,active_mi,1 /* net report*/); 03051 pthread_mutex_unlock(&LOCK_active_mi); 03052 break; 03053 } 03054 case SQLCOM_SLAVE_STOP: 03055 /* 03056 If the client thread has locked tables, a deadlock is possible. 03057 Assume that 03058 - the client thread does LOCK TABLE t READ. 03059 - then the master updates t. 03060 - then the SQL slave thread wants to update t, 03061 so it waits for the client thread because t is locked by it. 03062 - then the client thread does SLAVE STOP. 03063 SLAVE STOP waits for the SQL slave thread to terminate its 03064 update t, which waits for the client thread because t is locked by it. 03065 To prevent that, refuse SLAVE STOP if the 03066 client thread has locked tables 03067 */ 03068 if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock) 03069 { 03070 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, 03071 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); 03072 goto error; 03073 } 03074 { 03075 pthread_mutex_lock(&LOCK_active_mi); 03076 stop_slave(thd,active_mi,1/* net report*/); 03077 pthread_mutex_unlock(&LOCK_active_mi); 03078 break; 03079 } 03080 #endif /* HAVE_REPLICATION */ 03081 03082 case SQLCOM_ALTER_TABLE: 03083 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03084 #if defined(DONT_ALLOW_SHOW_COMMANDS) 03085 my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), 03086 MYF(0)); /* purecov: inspected */ 03087 goto error; 03088 #else 03089 { 03090 ulong priv=0; 03091 ulong priv_needed= ALTER_ACL; 03092 /* We also require DROP priv for ALTER TABLE ... DROP PARTITION */ 03093 if (lex->alter_info.flags & ALTER_DROP_PARTITION) 03094 priv_needed|= DROP_ACL; 03095 03096 if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN)) 03097 { 03098 my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name); 03099 goto error; 03100 } 03101 /* Must be set in the parser */ 03102 DBUG_ASSERT(select_lex->db); 03103 if (check_access(thd, priv_needed, first_table->db, 03104 &first_table->grant.privilege, 0, 0, 03105 test(first_table->schema_table)) || 03106 check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0, 03107 is_schema_db(select_lex->db))|| 03108 check_merge_table_access(thd, first_table->db, 03109 (TABLE_LIST *) 03110 lex->create_info.merge_list.first)) 03111 goto error; /* purecov: inspected */ 03112 if (grant_option) 03113 { 03114 if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0)) 03115 goto error; 03116 if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL)) 03117 { // Rename of table 03118 TABLE_LIST tmp_table; 03119 bzero((char*) &tmp_table,sizeof(tmp_table)); 03120 tmp_table.table_name=lex->name; 03121 tmp_table.db=select_lex->db; 03122 tmp_table.grant.privilege=priv; 03123 if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0, 03124 UINT_MAX, 0)) 03125 goto error; 03126 } 03127 } 03128 /* Don't yet allow changing of symlinks with ALTER TABLE */ 03129 if (lex->create_info.data_file_name) 03130 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, 03131 "DATA DIRECTORY option ignored"); 03132 if (lex->create_info.index_file_name) 03133 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, 03134 "INDEX DIRECTORY option ignored"); 03135 lex->create_info.data_file_name=lex->create_info.index_file_name=0; 03136 /* ALTER TABLE ends previous transaction */ 03137 if (end_active_trans(thd)) 03138 goto error; 03139 03140 if (!thd->locked_tables && 03141 !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) 03142 { 03143 res= 1; 03144 break; 03145 } 03146 03147 thd->enable_slow_log= opt_log_slow_admin_statements; 03148 res= mysql_alter_table(thd, select_lex->db, lex->name, 03149 &lex->create_info, 03150 first_table, lex->create_list, 03151 lex->key_list, 03152 select_lex->order_list.elements, 03153 (ORDER *) select_lex->order_list.first, 03154 lex->ignore, &lex->alter_info, 1); 03155 break; 03156 } 03157 #endif /*DONT_ALLOW_SHOW_COMMANDS*/ 03158 case SQLCOM_RENAME_TABLE: 03159 { 03160 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03161 TABLE_LIST *table; 03162 for (table= first_table; table; table= table->next_local->next_local) 03163 { 03164 if (check_access(thd, ALTER_ACL | DROP_ACL, table->db, 03165 &table->grant.privilege,0,0, test(table->schema_table)) || 03166 check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db, 03167 &table->next_local->grant.privilege, 0, 0, 03168 test(table->next_local->schema_table))) 03169 goto error; 03170 if (grant_option) 03171 { 03172 TABLE_LIST old_list, new_list; 03173 /* 03174 we do not need initialize old_list and new_list because we will 03175 come table[0] and table->next[0] there 03176 */ 03177 old_list= table[0]; 03178 new_list= table->next_local[0]; 03179 if (check_grant(thd, ALTER_ACL, &old_list, 0, 1, 0) || 03180 (!test_all_bits(table->next_local->grant.privilege, 03181 INSERT_ACL | CREATE_ACL) && 03182 check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0))) 03183 goto error; 03184 } 03185 } 03186 query_cache_invalidate3(thd, first_table, 0); 03187 if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0)) 03188 goto error; 03189 break; 03190 } 03191 #ifndef EMBEDDED_LIBRARY 03192 case SQLCOM_SHOW_BINLOGS: 03193 #ifdef DONT_ALLOW_SHOW_COMMANDS 03194 my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), 03195 MYF(0)); /* purecov: inspected */ 03196 goto error; 03197 #else 03198 { 03199 if (check_global_access(thd, SUPER_ACL)) 03200 goto error; 03201 res = show_binlogs(thd); 03202 break; 03203 } 03204 #endif 03205 #endif /* EMBEDDED_LIBRARY */ 03206 case SQLCOM_SHOW_CREATE: 03207 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03208 #ifdef DONT_ALLOW_SHOW_COMMANDS 03209 my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), 03210 MYF(0)); /* purecov: inspected */ 03211 goto error; 03212 #else 03213 { 03214 /* Ignore temporary tables if this is "SHOW CREATE VIEW" */ 03215 if (lex->only_view) 03216 first_table->skip_temporary= 1; 03217 03218 if (check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db, 03219 &first_table->grant.privilege, 0, 0, 03220 test(first_table->schema_table))) 03221 goto error; 03222 if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0)) 03223 goto error; 03224 res= mysqld_show_create(thd, first_table); 03225 break; 03226 } 03227 #endif 03228 case SQLCOM_CHECKSUM: 03229 { 03230 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03231 if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, 0)) 03232 goto error; /* purecov: inspected */ 03233 res = mysql_checksum_table(thd, first_table, &lex->check_opt); 03234 break; 03235 } 03236 case SQLCOM_REPAIR: 03237 { 03238 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03239 if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0)) 03240 goto error; /* purecov: inspected */ 03241 thd->enable_slow_log= opt_log_slow_admin_statements; 03242 res= mysql_repair_table(thd, first_table, &lex->check_opt); 03243 /* ! we write after unlocking the table */ 03244 if (!res && !lex->no_write_to_binlog) 03245 { 03246 if (mysql_bin_log.is_open()) 03247 { 03248 thd->clear_error(); // No binlog error generated 03249 thd->binlog_query(THD::STMT_QUERY_TYPE, 03250 thd->query, thd->query_length, 0, FALSE); 03251 } 03252 } 03253 select_lex->table_list.first= (byte*) first_table; 03254 lex->query_tables=all_tables; 03255 break; 03256 } 03257 case SQLCOM_CHECK: 03258 { 03259 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03260 if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0)) 03261 goto error; /* purecov: inspected */ 03262 thd->enable_slow_log= opt_log_slow_admin_statements; 03263 res = mysql_check_table(thd, first_table, &lex->check_opt); 03264 select_lex->table_list.first= (byte*) first_table; 03265 lex->query_tables=all_tables; 03266 break; 03267 } 03268 case SQLCOM_ANALYZE: 03269 { 03270 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03271 if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0)) 03272 goto error; /* purecov: inspected */ 03273 thd->enable_slow_log= opt_log_slow_admin_statements; 03274 res= mysql_analyze_table(thd, first_table, &lex->check_opt); 03275 /* ! we write after unlocking the table */ 03276 if (!res && !lex->no_write_to_binlog) 03277 { 03278 if (mysql_bin_log.is_open()) 03279 { 03280 thd->clear_error(); // No binlog error generated 03281 thd->binlog_query(THD::STMT_QUERY_TYPE, 03282 thd->query, thd->query_length, 0, FALSE); 03283 } 03284 } 03285 select_lex->table_list.first= (byte*) first_table; 03286 lex->query_tables=all_tables; 03287 break; 03288 } 03289 03290 case SQLCOM_OPTIMIZE: 03291 { 03292 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03293 if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0)) 03294 goto error; /* purecov: inspected */ 03295 thd->enable_slow_log= opt_log_slow_admin_statements; 03296 res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ? 03297 mysql_recreate_table(thd, first_table, 1) : 03298 mysql_optimize_table(thd, first_table, &lex->check_opt); 03299 /* ! we write after unlocking the table */ 03300 if (!res && !lex->no_write_to_binlog) 03301 { 03302 if (mysql_bin_log.is_open()) 03303 { 03304 thd->clear_error(); // No binlog error generated 03305 thd->binlog_query(THD::STMT_QUERY_TYPE, 03306 thd->query, thd->query_length, 0, FALSE); 03307 } 03308 } 03309 select_lex->table_list.first= (byte*) first_table; 03310 lex->query_tables=all_tables; 03311 break; 03312 } 03313 case SQLCOM_UPDATE: 03314 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03315 if (update_precheck(thd, all_tables)) 03316 break; 03317 DBUG_ASSERT(select_lex->offset_limit == 0); 03318 unit->set_limit(select_lex); 03319 res= (result= mysql_update(thd, all_tables, 03320 select_lex->item_list, 03321 lex->value_list, 03322 select_lex->where, 03323 select_lex->order_list.elements, 03324 (ORDER *) select_lex->order_list.first, 03325 unit->select_limit_cnt, 03326 lex->duplicates, lex->ignore)); 03327 /* mysql_update return 2 if we need to switch to multi-update */ 03328 if (result != 2) 03329 break; 03330 case SQLCOM_UPDATE_MULTI: 03331 { 03332 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03333 /* if we switched from normal update, rights are checked */ 03334 if (result != 2) 03335 { 03336 if ((res= multi_update_precheck(thd, all_tables))) 03337 break; 03338 } 03339 else 03340 res= 0; 03341 03342 res= mysql_multi_update_prepare(thd); 03343 03344 #ifdef HAVE_REPLICATION 03345 /* Check slave filtering rules */ 03346 if (unlikely(thd->slave_thread)) 03347 { 03348 if (all_tables_not_ok(thd, all_tables)) 03349 { 03350 if (res!= 0) 03351 { 03352 res= 0; /* don't care of prev failure */ 03353 thd->clear_error(); /* filters are of highest prior */ 03354 } 03355 /* we warn the slave SQL thread */ 03356 my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); 03357 break; 03358 } 03359 if (res) 03360 break; 03361 } 03362 else 03363 { 03364 #endif /* HAVE_REPLICATION */ 03365 if (res) 03366 break; 03367 if (opt_readonly && 03368 !(thd->security_ctx->master_access & SUPER_ACL) && 03369 some_non_temp_table_to_be_updated(thd, all_tables)) 03370 { 03371 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); 03372 break; 03373 } 03374 #ifdef HAVE_REPLICATION 03375 } /* unlikely */ 03376 #endif 03377 03378 res= mysql_multi_update(thd, all_tables, 03379 &select_lex->item_list, 03380 &lex->value_list, 03381 select_lex->where, 03382 select_lex->options, 03383 lex->duplicates, lex->ignore, unit, select_lex); 03384 break; 03385 } 03386 case SQLCOM_REPLACE: 03387 case SQLCOM_INSERT: 03388 { 03389 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03390 if ((res= insert_precheck(thd, all_tables))) 03391 break; 03392 /* Skip first table, which is the table we are inserting in */ 03393 select_lex->context.table_list= first_table->next_local; 03394 03395 if (!thd->locked_tables && 03396 !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) 03397 { 03398 res= 1; 03399 break; 03400 } 03401 03402 res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values, 03403 lex->update_list, lex->value_list, 03404 lex->duplicates, lex->ignore); 03405 /* do not show last insert ID if VIEW does not have auto_inc */ 03406 if (first_table->view && !first_table->contain_auto_increment) 03407 thd->first_successful_insert_id_in_cur_stmt= 0; 03408 break; 03409 } 03410 case SQLCOM_REPLACE_SELECT: 03411 case SQLCOM_INSERT_SELECT: 03412 { 03413 select_result *result; 03414 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03415 if ((res= insert_precheck(thd, all_tables))) 03416 break; 03417 03418 /* Fix lock for first table */ 03419 if (first_table->lock_type == TL_WRITE_DELAYED) 03420 first_table->lock_type= TL_WRITE; 03421 03422 /* Don't unlock tables until command is written to binary log */ 03423 select_lex->options|= SELECT_NO_UNLOCK; 03424 03425 unit->set_limit(select_lex); 03426 03427 if (! thd->locked_tables && 03428 ! (need_start_waiting= ! wait_if_global_read_lock(thd, 0, 1))) 03429 { 03430 res= 1; 03431 break; 03432 } 03433 03434 if (!(res= open_and_lock_tables(thd, all_tables))) 03435 { 03436 /* Skip first table, which is the table we are inserting in */ 03437 TABLE_LIST *second_table= first_table->next_local; 03438 select_lex->table_list.first= (byte*) second_table; 03439 select_lex->context.table_list= 03440 select_lex->context.first_name_resolution_table= second_table; 03441 res= mysql_insert_select_prepare(thd); 03442 if (!res && (result= new select_insert(first_table, first_table->table, 03443 &lex->field_list, 03444 &lex->update_list, 03445 &lex->value_list, 03446 lex->duplicates, lex->ignore))) 03447 { 03448 res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE); 03449 /* 03450 Invalidate the table in the query cache if something changed 03451 after unlocking when changes become visible. 03452 TODO: this is workaround. right way will be move invalidating in 03453 the unlock procedure. 03454 */ 03455 if (first_table->lock_type == TL_WRITE_CONCURRENT_INSERT && 03456 thd->lock) 03457 { 03458 mysql_unlock_tables(thd, thd->lock); 03459 query_cache_invalidate3(thd, first_table, 1); 03460 thd->lock=0; 03461 } 03462 delete result; 03463 } 03464 /* revert changes for SP */ 03465 select_lex->table_list.first= (byte*) first_table; 03466 } 03467 /* do not show last insert ID if VIEW does not have auto_inc */ 03468 if (first_table->view && !first_table->contain_auto_increment) 03469 thd->first_successful_insert_id_in_cur_stmt= 0; 03470 break; 03471 } 03472 case SQLCOM_TRUNCATE: 03473 if (end_active_trans(thd)) 03474 { 03475 res= -1; 03476 break; 03477 } 03478 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03479 if (check_one_table_access(thd, DELETE_ACL, all_tables)) 03480 goto error; 03481 /* 03482 Don't allow this within a transaction because we want to use 03483 re-generate table 03484 */ 03485 if (thd->locked_tables || thd->active_transaction()) 03486 { 03487 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, 03488 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); 03489 goto error; 03490 } 03491 03492 res= mysql_truncate(thd, first_table, 0); 03493 break; 03494 case SQLCOM_DELETE: 03495 { 03496 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03497 if ((res= delete_precheck(thd, all_tables))) 03498 break; 03499 DBUG_ASSERT(select_lex->offset_limit == 0); 03500 unit->set_limit(select_lex); 03501 03502 if (!thd->locked_tables && 03503 !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) 03504 { 03505 res= 1; 03506 break; 03507 } 03508 03509 res = mysql_delete(thd, all_tables, select_lex->where, 03510 &select_lex->order_list, 03511 unit->select_limit_cnt, select_lex->options, 03512 FALSE); 03513 break; 03514 } 03515 case SQLCOM_DELETE_MULTI: 03516 { 03517 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03518 TABLE_LIST *aux_tables= 03519 (TABLE_LIST *)thd->lex->auxiliary_table_list.first; 03520 multi_delete *result; 03521 03522 if (!thd->locked_tables && 03523 !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) 03524 { 03525 res= 1; 03526 break; 03527 } 03528 03529 if ((res= multi_delete_precheck(thd, all_tables))) 03530 break; 03531 03532 /* condition will be TRUE on SP re-excuting */ 03533 if (select_lex->item_list.elements != 0) 03534 select_lex->item_list.empty(); 03535 if (add_item_to_list(thd, new Item_null())) 03536 goto error; 03537 03538 thd->proc_info="init"; 03539 if ((res= open_and_lock_tables(thd, all_tables))) 03540 break; 03541 03542 if ((res= mysql_multi_delete_prepare(thd))) 03543 goto error; 03544 03545 if (!thd->is_fatal_error && (result= new multi_delete(aux_tables, 03546 lex->table_count))) 03547 { 03548 res= mysql_select(thd, &select_lex->ref_pointer_array, 03549 select_lex->get_table_list(), 03550 select_lex->with_wild, 03551 select_lex->item_list, 03552 select_lex->where, 03553 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL, 03554 (ORDER *)NULL, 03555 select_lex->options | thd->options | 03556 SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | 03557 OPTION_SETUP_TABLES_DONE, 03558 result, unit, select_lex); 03559 delete result; 03560 } 03561 else 03562 res= TRUE; // Error 03563 break; 03564 } 03565 case SQLCOM_DROP_TABLE: 03566 { 03567 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03568 if (!lex->drop_temporary) 03569 { 03570 if (check_table_access(thd, DROP_ACL, all_tables, 0)) 03571 goto error; /* purecov: inspected */ 03572 if (end_active_trans(thd)) 03573 goto error; 03574 } 03575 else 03576 { 03577 /* 03578 If this is a slave thread, we may sometimes execute some 03579 DROP / * 40005 TEMPORARY * / TABLE 03580 that come from parts of binlogs (likely if we use RESET SLAVE or CHANGE 03581 MASTER TO), while the temporary table has already been dropped. 03582 To not generate such irrelevant "table does not exist errors", 03583 we silently add IF EXISTS if TEMPORARY was used. 03584 */ 03585 if (thd->slave_thread) 03586 lex->drop_if_exists= 1; 03587 03588 /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ 03589 thd->options|= OPTION_KEEP_LOG; 03590 } 03591 res= mysql_rm_table(thd, first_table, lex->drop_if_exists, 03592 lex->drop_temporary); 03593 } 03594 break; 03595 case SQLCOM_DROP_INDEX: 03596 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03597 if (check_one_table_access(thd, INDEX_ACL, all_tables)) 03598 goto error; /* purecov: inspected */ 03599 if (end_active_trans(thd)) 03600 goto error; 03601 res= mysql_drop_index(thd, first_table, &lex->alter_info); 03602 break; 03603 case SQLCOM_SHOW_PROCESSLIST: 03604 if (!thd->security_ctx->priv_user[0] && 03605 check_global_access(thd,PROCESS_ACL)) 03606 break; 03607 mysqld_list_processes(thd, 03608 (thd->security_ctx->master_access & PROCESS_ACL ? 03609 NullS : 03610 thd->security_ctx->priv_user), 03611 lex->verbose); 03612 break; 03613 case SQLCOM_SHOW_STORAGE_ENGINES: 03614 res= mysqld_show_storage_engines(thd); 03615 break; 03616 case SQLCOM_SHOW_AUTHORS: 03617 res= mysqld_show_authors(thd); 03618 break; 03619 case SQLCOM_SHOW_CONTRIBUTORS: 03620 res= mysqld_show_contributors(thd); 03621 break; 03622 case SQLCOM_SHOW_PRIVILEGES: 03623 res= mysqld_show_privileges(thd); 03624 break; 03625 case SQLCOM_SHOW_COLUMN_TYPES: 03626 res= mysqld_show_column_types(thd); 03627 break; 03628 case SQLCOM_SHOW_ENGINE_LOGS: 03629 #ifdef DONT_ALLOW_SHOW_COMMANDS 03630 my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), 03631 MYF(0)); /* purecov: inspected */ 03632 goto error; 03633 #else 03634 { 03635 if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0,0)) 03636 goto error; 03637 res= ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_LOGS); 03638 break; 03639 } 03640 #endif 03641 case SQLCOM_CHANGE_DB: 03642 if (!mysql_change_db(thd,select_lex->db,FALSE)) 03643 send_ok(thd); 03644 break; 03645 03646 case SQLCOM_LOAD: 03647 { 03648 DBUG_ASSERT(first_table == all_tables && first_table != 0); 03649 uint privilege= (lex->duplicates == DUP_REPLACE ? 03650 INSERT_ACL | DELETE_ACL : INSERT_ACL) | 03651 (lex->local_file ? 0 : FILE_ACL); 03652 03653 if (lex->local_file) 03654 { 03655 if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) || 03656 !opt_local_infile) 03657 { 03658 my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); 03659 goto error; 03660 } 03661 } 03662 03663 if (check_one_table_access(thd, privilege, all_tables)) 03664 goto error; 03665 03666 res= mysql_load(thd, lex->exchange, first_table, lex->field_list, 03667 lex->update_list, lex->value_list, lex->duplicates, 03668 lex->ignore, (bool) lex->local_file); 03669 break; 03670 } 03671 03672 case SQLCOM_SET_OPTION: 03673 { 03674 List<set_var_base> *lex_var_list= &lex->var_list; 03675 if ((check_table_access(thd, SELECT_ACL, all_tables, 0) || 03676 open_and_lock_tables(thd, all_tables))) 03677 goto error; 03678 if (lex->one_shot_set && not_all_support_one_shot(lex_var_list)) 03679 { 03680 my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT"); 03681 goto error; 03682 } 03683 if (!(res= sql_set_variables(thd, lex_var_list))) 03684 { 03685 /* 03686 If the previous command was a SET ONE_SHOT, we don't want to forget 03687 about the ONE_SHOT property of that SET. So we use a |= instead of = . 03688 */ 03689 thd->one_shot_set|= lex->one_shot_set; 03690 send_ok(thd); 03691 } 03692 break; 03693 } 03694 03695 case SQLCOM_UNLOCK_TABLES: 03696 /* 03697 It is critical for mysqldump --single-transaction --master-data that 03698 UNLOCK TABLES does not implicitely commit a connection which has only 03699 done FLUSH TABLES WITH READ LOCK + BEGIN. If this assumption becomes 03700 false, mysqldump will not work. 03701 */ 03702 unlock_locked_tables(thd); 03703 if (thd->options & OPTION_TABLE_LOCK) 03704 { 03705 end_active_trans(thd); 03706 thd->options&= ~(ulong) (OPTION_TABLE_LOCK); 03707 } 03708 if (thd->global_read_lock) 03709 unlock_global_read_lock(thd); 03710 send_ok(thd); 03711 break; 03712 case SQLCOM_LOCK_TABLES: 03713 unlock_locked_tables(thd); 03714 if (end_active_trans(thd)) 03715 goto error; 03716 if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0)) 03717 goto error; 03718 thd->in_lock_tables=1; 03719 thd->options|= OPTION_TABLE_LOCK; 03720 03721 if (!(res= simple_open_n_lock_tables(thd, all_tables))) 03722 { 03723 #ifdef HAVE_QUERY_CACHE 03724 if (thd->variables.query_cache_wlock_invalidate) 03725 query_cache.invalidate_locked_for_write(first_table); 03726 #endif /*HAVE_QUERY_CACHE*/ 03727 thd->locked_tables=thd->lock; 03728 thd->lock=0; 03729 send_ok(thd); 03730 } 03731 else 03732 thd->options&= ~(ulong) (OPTION_TABLE_LOCK); 03733 thd->in_lock_tables=0; 03734 break; 03735 case SQLCOM_CREATE_DB: 03736 { 03737 if (end_active_trans(thd)) 03738 { 03739 res= -1; 03740 break; 03741 } 03742 char *alias; 03743 if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name)) 03744 { 03745 my_error(ER_WRONG_DB_NAME, MYF(0), lex->name); 03746 break; 03747 } 03748 /* 03749 If in a slave thread : 03750 CREATE DATABASE DB was certainly not preceded by USE DB. 03751 For that reason, db_ok() in sql/slave.cc did not check the 03752 do_db/ignore_db. And as this query involves no tables, tables_ok() 03753 above was not called. So we have to check rules again here. 03754 */ 03755 #ifdef HAVE_REPLICATION 03756 if (thd->slave_thread && 03757 (!rpl_filter->db_ok(lex->name) || 03758 !rpl_filter->db_ok_with_wild_table(lex->name))) 03759 { 03760 my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); 03761 break; 03762 } 03763 #endif 03764 if (check_access(thd,CREATE_ACL,lex->name,0,1,0,is_schema_db(lex->name))) 03765 break; 03766 res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name), 03767 &lex->create_info, 0); 03768 break; 03769 } 03770 case SQLCOM_DROP_DB: 03771 { 03772 if (end_active_trans(thd)) 03773 { 03774 res= -1; 03775 break; 03776 } 03777 if (check_db_name(lex->name)) 03778 { 03779 my_error(ER_WRONG_DB_NAME, MYF(0), lex->name); 03780 break; 03781 } 03782 /* 03783 If in a slave thread : 03784 DROP DATABASE DB may not be preceded by USE DB. 03785 For that reason, maybe db_ok() in sql/slave.cc did not check the 03786 do_db/ignore_db. And as this query involves no tables, tables_ok() 03787 above was not called. So we have to check rules again here. 03788 */ 03789 #ifdef HAVE_REPLICATION 03790 if (thd->slave_thread && 03791 (!rpl_filter->db_ok(lex->name) || 03792 !rpl_filter->db_ok_with_wild_table(lex->name))) 03793 { 03794 my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); 03795 break; 03796 } 03797 #endif 03798 if (check_access(thd,DROP_ACL,lex->name,0,1,0,is_schema_db(lex->name))) 03799 break; 03800 if (thd->locked_tables || thd->active_transaction()) 03801 { 03802 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, 03803 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); 03804 goto error; 03805 } 03806 res= mysql_rm_db(thd, lex->name, lex->drop_if_exists, 0); 03807 break; 03808 } 03809 case SQLCOM_RENAME_DB: 03810 { 03811 LEX_STRING *olddb, *newdb; 03812 List_iterator <LEX_STRING> db_list(lex->db_list); 03813 olddb= db_list++; 03814 newdb= db_list++; 03815 if (end_active_trans(thd)) 03816 { 03817 res= 1; 03818 break; 03819 } 03820 #ifdef HAVE_REPLICATION 03821 if (thd->slave_thread && 03822 (!rpl_filter->db_ok(olddb->str) || 03823 !rpl_filter->db_ok(newdb->str) || 03824 !rpl_filter->db_ok_with_wild_table(olddb->str) || 03825 !rpl_filter->db_ok_with_wild_table(newdb->str))) 03826 { 03827 res= 1; 03828 my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); 03829 break; 03830 } 03831 #endif 03832 if (check_access(thd,ALTER_ACL,olddb->str,0,1,0,is_schema_db(olddb->str)) || 03833 check_access(thd,DROP_ACL,olddb->str,0,1,0,is_schema_db(olddb->str)) || 03834 check_access(thd,CREATE_ACL,newdb->str,0,1,0,is_schema_db(newdb->str))) 03835 { 03836 res= 1; 03837 break; 03838 } 03839 if (thd->locked_tables || thd->active_transaction()) 03840 { 03841 res= 1; 03842 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, 03843 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); 03844 goto error; 03845 } 03846 res= mysql_rename_db(thd, olddb, newdb); 03847 if (!res) 03848 send_ok(thd); 03849 break; 03850 } 03851 case SQLCOM_ALTER_DB: 03852 { 03853 char *db= lex->name; 03854 DBUG_ASSERT(db); /* Must be set in the parser */ 03855 if (!strip_sp(db) || check_db_name(db)) 03856 { 03857 my_error(ER_WRONG_DB_NAME, MYF(0), db); 03858 break; 03859 } 03860 /* 03861 If in a slave thread : 03862 ALTER DATABASE DB may not be preceded by USE DB. 03863 For that reason, maybe db_ok() in sql/slave.cc did not check the 03864 do_db/ignore_db. And as this query involves no tables, tables_ok() 03865 above was not called. So we have to check rules again here. 03866 */ 03867 #ifdef HAVE_REPLICATION 03868 if (thd->slave_thread && 03869 (!rpl_filter->db_ok(db) || 03870 !rpl_filter->db_ok_with_wild_table(db))) 03871 { 03872 my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); 03873 break; 03874 } 03875 #endif 03876 if (check_access(thd, ALTER_ACL, db, 0, 1, 0, is_schema_db(db))) 03877 break; 03878 if (thd->locked_tables || thd->active_transaction()) 03879 { 03880 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, 03881 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); 03882 goto error; 03883 } 03884 res= mysql_alter_db(thd, db, &lex->create_info); 03885 break; 03886 } 03887 case SQLCOM_SHOW_CREATE_DB: 03888 { 03889 if (!strip_sp(lex->name) || check_db_name(lex->name)) 03890 { 03891 my_error(ER_WRONG_DB_NAME, MYF(0), lex->name); 03892 break; 03893 } 03894 res=mysqld_show_create_db(thd,lex->name,&lex->create_info); 03895 break; 03896 } 03897 case SQLCOM_CREATE_EVENT: 03898 case SQLCOM_ALTER_EVENT: 03899 case SQLCOM_DROP_EVENT: 03900 { 03901 uint rows_affected= 1; 03902 DBUG_ASSERT(lex->et); 03903 do { 03904 if (! lex->et->dbname.str || 03905 (lex->sql_command == SQLCOM_ALTER_EVENT && lex->spname && 03906 !lex->spname->m_db.str)) 03907 { 03908 my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); 03909 res= true; 03910 break; 03911 } 03912 03913 if (check_access(thd, EVENT_ACL, lex->et->dbname.str, 0, 0, 0, 03914 is_schema_db(lex->et->dbname.str)) || 03915 (lex->sql_command == SQLCOM_ALTER_EVENT && lex->spname && 03916 (check_access(thd, EVENT_ACL, lex->spname->m_db.str, 0, 0, 0, 03917 is_schema_db(lex->spname->m_db.str))))) 03918 break; 03919 03920 if (end_active_trans(thd)) 03921 { 03922 res= -1; 03923 break; 03924 } 03925 03926 switch (lex->sql_command) { 03927 case SQLCOM_CREATE_EVENT: 03928 res= Events::create_event(thd, lex->et, 03929 (uint) lex->create_info.options, 03930 &rows_affected); 03931 break; 03932 case SQLCOM_ALTER_EVENT: 03933 res= Events::update_event(thd, lex->et, lex->spname, 03934 &rows_affected); 03935 break; 03936 case SQLCOM_DROP_EVENT: 03937 res= Events::drop_event(thd, lex->et, lex->drop_if_exists, 03938 &rows_affected); 03939 default:; 03940 } 03941 DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d", 03942 res, rows_affected)); 03943 if (!res) 03944 send_ok(thd, rows_affected); 03945 03946 /* lex->unit.cleanup() is called outside, no need to call it here */ 03947 } while (0); 03948 if (!thd->spcont) 03949 { 03950 lex->et->free_sphead_on_delete= true; 03951 lex->et->free_sp(); 03952 lex->et->deinit_mutexes(); 03953 } 03954 03955 break; 03956 } 03957 case SQLCOM_SHOW_CREATE_EVENT: 03958 { 03959 DBUG_ASSERT(lex->spname); 03960 DBUG_ASSERT(lex->et); 03961 if (! lex->spname->m_db.str) 03962 { 03963 my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); 03964 res= true; 03965 break; 03966 } 03967 if (check_access(thd, EVENT_ACL, lex->spname->m_db.str, 0, 0, 0, 03968 is_schema_db(lex->spname->m_db.str))) 03969 break; 03970 03971 if (lex->spname->m_name.length > NAME_LEN) 03972 { 03973 my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str); 03974 goto error; 03975 } 03976 res= Events::show_create_event(thd, lex->spname); 03977 break; 03978 } 03979 #ifndef DBUG_OFF 03980 case SQLCOM_SHOW_SCHEDULER_STATUS: 03981 { 03982 res= Events::dump_internal_status(thd); 03983 break; 03984 } 03985 #endif 03986 case SQLCOM_CREATE_FUNCTION: // UDF function 03987 { 03988 if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0)) 03989 break; 03990 #ifdef HAVE_DLOPEN 03991 if (sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname, 03992 &thd->sp_func_cache, FALSE)) 03993 { 03994 my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str); 03995 goto error; 03996 } 03997 if (!(res = mysql_create_function(thd, &lex->udf))) 03998 send_ok(thd); 03999 #else 04000 my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled"); 04001 res= TRUE; 04002 #endif 04003 break; 04004 } 04005 #ifndef NO_EMBEDDED_ACCESS_CHECKS 04006 case SQLCOM_CREATE_USER: 04007 { 04008 if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) && 04009 check_global_access(thd,CREATE_USER_ACL)) 04010 break; 04011 if (end_active_trans(thd)) 04012 goto error; 04013 if (!(res= mysql_create_user(thd, lex->users_list))) 04014 { 04015 if (mysql_bin_log.is_open()) 04016 thd->binlog_query(THD::MYSQL_QUERY_TYPE, 04017 thd->query, thd->query_length, FALSE, FALSE); 04018 send_ok(thd); 04019 } 04020 break; 04021 } 04022 case SQLCOM_DROP_USER: 04023 { 04024 if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) && 04025 check_global_access(thd,CREATE_USER_ACL)) 04026 break; 04027 if (end_active_trans(thd)) 04028 goto error; 04029 if (!(res= mysql_drop_user(thd, lex->users_list))) 04030 { 04031 if (mysql_bin_log.is_open()) 04032 { 04033 thd->binlog_query(THD::MYSQL_QUERY_TYPE, 04034 thd->query, thd->query_length, FALSE, FALSE); 04035 } 04036 send_ok(thd); 04037 } 04038 break; 04039 } 04040 case SQLCOM_RENAME_USER: 04041 { 04042 if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) && 04043 check_global_access(thd,CREATE_USER_ACL)) 04044 break; 04045 if (end_active_trans(thd)) 04046 goto error; 04047 if (!(res= mysql_rename_user(thd, lex->users_list))) 04048 { 04049 if (mysql_bin_log.is_open()) 04050 { 04051 thd->binlog_query(THD::MYSQL_QUERY_TYPE, 04052 thd->query, thd->query_length, FALSE, FALSE); 04053 } 04054 send_ok(thd); 04055 } 04056 break; 04057 } 04058 case

