diff options
author | unknown <Sinisa@sinisa.nasamreza.org> | 2002-05-15 13:50:38 +0300 |
---|---|---|
committer | unknown <Sinisa@sinisa.nasamreza.org> | 2002-05-15 13:50:38 +0300 |
commit | c5bfcc9d7f3c77def9a8df65da11a6b55c2edea5 (patch) | |
tree | a860fbee06b7b609760f7c02085992e96887e9ce /sql/sql_parse.cc | |
parent | 2b0dd9c9666314f57f5f3aae6af7087b02d0b316 (diff) | |
download | mariadb-git-c5bfcc9d7f3c77def9a8df65da11a6b55c2edea5.tar.gz |
Features made for Schlund plus several bug fixes.
Read a manual for more detail
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 175 |
1 files changed, 111 insertions, 64 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index dc89888a1a5..af68c1bb9f3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -59,9 +59,9 @@ extern "C" pthread_mutex_t THR_LOCK_keycache; extern "C" int gethostname(char *name, int namelen); #endif -static int check_for_max_user_connections(UC *uc); +static int check_for_max_user_connections(USER_CONN *uc); static bool check_mqh(THD *thd); -static void decrease_user_connections(UC *uc); +static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables); static bool check_dup(const char *db, const char *name, TABLE_LIST *tables); @@ -126,18 +126,19 @@ extern pthread_mutex_t LOCK_user_conn; static int get_or_create_user_conn(THD *thd, const char *user, const char *host, - uint max_questions) + USER_RESOURCES *mqh) { int return_val=0; - uint temp_len; + uint temp_len, user_len, host_len; char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2]; struct user_conn *uc; DBUG_ASSERT(user != 0); DBUG_ASSERT(host != 0); - temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user)-1, user, "@", host, - NullS) - temp_user); + user_len=strlen(user); + host_len=strlen(host); + temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1; (void) pthread_mutex_lock(&LOCK_user_conn); if (!(uc = (struct user_conn *) hash_search(&hash_user_connections, (byte*) temp_user, temp_len))) @@ -153,10 +154,14 @@ static int get_or_create_user_conn(THD *thd, const char *user, } uc->user=(char*) (uc+1); memcpy(uc->user,temp_user,temp_len+1); + uc->user_len= user_len; + uc->host=uc->user + uc->user_len + 1; uc->len = temp_len; - uc->connections = 1; - uc->questions=0; - uc->max_questions=max_questions; + uc->connections = 1; + uc->questions=uc->updates=uc->conn_per_hour=0; + uc->user_resources=*mqh; + if (mqh->connections > max_user_connections) + uc->user_resources.connections = max_user_connections; uc->intime=thd->thr_create_time; if (hash_insert(&hash_user_connections, (byte*) uc)) { @@ -184,9 +189,9 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, const char *passwd, const char *db, bool check_count) { NET *net= &thd->net; - uint max_questions=0; thd->db=0; thd->db_length=0; + USER_RESOURCES ur; if (!(thd->user = my_strdup(user, MYF(0)))) { @@ -197,7 +202,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, passwd, thd->scramble, &thd->priv_user, protocol_version == 9 || !(thd->client_capabilities & - CLIENT_LONG_PASSWORD),&max_questions); + CLIENT_LONG_PASSWORD),&ur); DBUG_PRINT("info", ("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'", thd->client_capabilities, thd->max_packet_length, @@ -237,9 +242,9 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, db ? db : (char*) ""); thd->db_access=0; /* Don't allow user to connect if he has done too many queries */ - if ((max_questions || max_user_connections) && get_or_create_user_conn(thd,user,thd->host_or_ip,max_questions)) + if ((ur.questions || ur.updates || ur.connections) && get_or_create_user_conn(thd,user,thd->host_or_ip,&ur)) return -1; - if (max_user_connections && thd->user_connect && + if (thd->user_connect && thd->user_connect->user_resources.connections && check_for_max_user_connections(thd->user_connect)) return -1; if (db && db[0]) @@ -279,32 +284,43 @@ void init_max_user_conn(void) } -static int check_for_max_user_connections(UC *uc) +static int check_for_max_user_connections(USER_CONN *uc) { int error=0; DBUG_ENTER("check_for_max_user_connections"); - if (max_user_connections <= (uint) uc->connections) + if (max_user_connections && ( max_user_connections <= (uint) uc->connections)) { net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, uc->user); error=1; goto end; } uc->connections++; - +if (uc->user_resources.connections && uc->conn_per_hour++ >= uc->user_resources.connections) + { + net_printf(¤t_thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_connections", + (long) uc->user_resources.connections); + error=1; + goto end; + } end: DBUG_RETURN(error); } -static void decrease_user_connections(UC *uc) +static void decrease_user_connections(USER_CONN *uc) { - if (!max_user_connections) +/* if (!max_user_connections) return; +*/ DBUG_ENTER("decrease_user_connections"); - - if (!--uc->connections && !mqh_used) + if (mqh_used) + { + if (uc->conn_per_hour) + uc->conn_per_hour--; + } + else if (!--uc->connections) { /* Last connection for user; Delete it */ (void) pthread_mutex_lock(&LOCK_user_conn); @@ -325,70 +341,92 @@ void free_max_user_conn(void) Check if maximum queries per hour limit has been reached returns 0 if OK. - In theory we would need a mutex in the UC structure for this to be 100 % + In theory we would need a mutex in the USER_CONN structure for this to be 100 % safe, but as the worst scenario is that we would miss counting a couple of queries, this isn't critical. */ +char uc_update_queries[SQLCOM_END]; + static bool check_mqh(THD *thd) { bool error=0; DBUG_ENTER("check_mqh"); - UC *uc=thd->user_connect; + USER_CONN *uc=thd->user_connect; DBUG_ASSERT(uc != 0); + uint check_command = thd->lex.sql_command; + - bool my_start = thd->start_time != 0; - time_t check_time = (my_start) ? thd->start_time : time(NULL); - if (check_time - uc->intime >= 3600) + if (check_command < (uint) SQLCOM_END) { - (void) pthread_mutex_lock(&LOCK_user_conn); - uc->questions=1; - uc->intime=check_time; - (void) pthread_mutex_unlock(&LOCK_user_conn); + if (uc->user_resources.updates && uc_update_queries[check_command] && + ++(uc->updates) > uc->user_resources.updates) + { + net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_updates", + (long) uc->user_resources.updates); + error=1; + goto end; + } } - else if (uc->max_questions && ++(uc->questions) > uc->max_questions) + else { - net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_questions", - (long) uc->max_questions); - error=1; - goto end; + bool my_start = thd->start_time != 0; + time_t check_time = (my_start) ? thd->start_time : time(NULL); + + if (check_time - uc->intime >= 3600) + { + (void) pthread_mutex_lock(&LOCK_user_conn); + uc->questions=1; + uc->updates=0; + uc->conn_per_hour=0; + uc->intime=check_time; + (void) pthread_mutex_unlock(&LOCK_user_conn); + } + else if (uc->user_resources.questions && ++(uc->questions) > uc->user_resources.questions) + { + net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_questions", + (long) uc->user_resources.questions); + error=1; + goto end; + } } - end: DBUG_RETURN(error); } -static void reset_mqh(THD *thd, LEX_USER *lu, uint mq) +static void reset_mqh(THD *thd, LEX_USER *lu, USER_RESOURCES *mqh, bool get_them=false) { (void) pthread_mutex_lock(&LOCK_user_conn); if (lu) // for GRANT { - UC *uc; + USER_CONN *uc; uint temp_len=lu->user.length+lu->host.length+2; char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2]; memcpy(temp_user,lu->user.str,lu->user.length); memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length); - temp_user[lu->user.length]=temp_user[temp_len-1]=0; + temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0; if ((uc = (struct user_conn *) hash_search(&hash_user_connections, - (byte*) temp_user, temp_len))) + (byte*) temp_user, temp_len-1))) { uc->questions=0; - uc->max_questions=mq; + uc->user_resources=*mqh; + uc->updates=0; + uc->conn_per_hour=0; } } - else // for FLUSH PRIVILEGES + else // for FLUSH PRIVILEGES and FLUSH USER_RESOURCES { for (uint idx=0;idx < hash_user_connections.records; idx++) { - char user[USERNAME_LENGTH+1]; - char *where; - UC *uc=(struct user_conn *) hash_element(&hash_user_connections, idx); - where=strchr(uc->user,'@'); - strmake(user,uc->user,where - uc->user); - uc->max_questions=get_mqh(user,where+1); + USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections, idx); + if (get_them) + get_mqh(uc->user,uc->host,uc); + uc->questions=0; + uc->updates=0; + uc->conn_per_hour=0; } } (void) pthread_mutex_unlock(&LOCK_user_conn); @@ -708,7 +746,7 @@ pthread_handler_decl(handle_bootstrap,arg) thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1); thd->query[length] = '\0'; thd->query_id=query_id++; - if (thd->user_connect && check_mqh(thd)) + if (mqh_used && thd->user_connect && check_mqh(thd)) { thd->net.error = 0; close_thread_tables(thd); // Free tables @@ -895,7 +933,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, char *save_user= thd->user; char *save_priv_user= thd->priv_user; char *save_db= thd->db; - UC *save_uc= thd->user_connect; + USER_CONN *save_uc= thd->user_connect; if ((uint) ((uchar*) db - net->read_pos) > packet_length) { // Check if protocol is ok @@ -948,7 +986,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, my_pthread_setprio(pthread_self(),QUERY_PRIOR); mysql_log.write(thd,command,"%s",thd->query); DBUG_PRINT("query",("%s",thd->query)); - if (thd->user_connect && check_mqh(thd)) + if (mqh_used && thd->user_connect && check_mqh(thd)) { error = TRUE; // Abort client net->error = 0; // Don't give abort message @@ -1073,8 +1111,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, send_error(net,0); else send_eof(net); - if (mqh_used) - reset_mqh(thd,(LEX_USER *) NULL, 0); break; } case COM_SHUTDOWN: @@ -2316,12 +2352,12 @@ mysql_execute_command(void) Query_log_event qinfo(thd, thd->query); mysql_bin_log.write(&qinfo); } - if (mqh_used && lex->mqh) + if (mqh_used && (lex->mqh.questions || lex->mqh.updates || lex->mqh.connections) && lex->sql_command == SQLCOM_GRANT) { List_iterator <LEX_USER> str_list(lex->users_list); LEX_USER *user; while ((user=str_list++)) - reset_mqh(thd,user,lex->mqh); + reset_mqh(thd,user,&(lex->mqh)); } } } @@ -2727,8 +2763,15 @@ mysql_parse(THD *thd,char *inBuf,uint length) LEX *lex=lex_start(thd, (uchar*) inBuf, length); if (!yyparse() && ! thd->fatal_error) { - mysql_execute_command(); - query_cache_end_of_result(&thd->net); + if (mqh_used && thd->user_connect && check_mqh(thd)) + { + thd->net.error = 0; + } + else + { + mysql_execute_command(); + query_cache_end_of_result(&thd->net); + } } else query_cache_abort(&thd->net); @@ -3272,6 +3315,8 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables) { acl_reload(); grant_reload(); + if (mqh_used) + reset_mqh(thd,(LEX_USER *) NULL, 0, true); } if (options & REFRESH_LOG) { @@ -3318,14 +3363,16 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables) result=load_des_key_file(des_key_file); } #endif - if (options & REFRESH_SLAVE) - { - LOCK_ACTIVE_MI; - if (reset_slave(active_mi)) - result=1; - UNLOCK_ACTIVE_MI; - } - return result; + if (options & REFRESH_SLAVE) + { + LOCK_ACTIVE_MI; + if (reset_slave(active_mi)) + result=1; + UNLOCK_ACTIVE_MI; + } + if (options & REFRESH_USER_RESOURCES) + reset_mqh(thd,(LEX_USER *) NULL, 0); + return result; } |