1
0
mirror of https://github.com/MariaDB/server.git synced 2025-12-24 11:21:21 +03:00

This is a large push. Included are :

* multi-table updates
* new paid feature for limiting number of queries per hour for users
* optional syntax for multi-table deletes
* optimization for SQL_CALC_FOUND_ROWS
* a small addition for CREATE .. SELECT that will be of future use

I know that all this will require many additions to documentation, 
which I have not done, but I am at Arjen's disposal to help him document
all this.



libmysqld/lib_sql.cc:
  This is a small change required due to new paid feature of limiting 
  number of queries per hour for each user.
mysql-test/r/multi_update.result:
  Change of the result to accomodate multi-table updates
mysql-test/t/multi_update.test:
  Change in multi-table tests to accomodate multi-table updates
BitKeeper/etc/ignore:
  Added 50 sql/new.cc to the ignore list
scripts/mysql_install_db.sh:
  This is a small change required due to new paid feature of limiting 
  number of queries per hour for each user.
sql/item_timefunc.h:
  This is a small feature that will be of use later in the proper 
  creation of the tables out of CREATE ... SELECT...
  
  Further changes will come after this resolve/push/test passes ..
sql/lex.h:
  This is a small change required due to new paid feature of limiting 
  number of queries per hour for each user.
sql/mysql_priv.h:
  This is a small change required due to new paid feature of limiting 
  number of queries per hour for each user.
sql/mysqld.cc:
  This is a small change required due to new paid feature of limiting 
  number of queries per hour for each user.
sql/sql_acl.cc:
  This is a small change required due to new paid feature of limiting 
  number of queries per hour for each user.
sql/sql_acl.h:
  This is a small change required due to new paid feature of limiting 
  number of queries per hour for each user.
sql/sql_class.h:
  These are changes required for multi-table updates.
sql/sql_lex.h:
  Changes required for both multi-table updates and limiting number of 
  queries per hour (paid feature).
sql/sql_parse.cc:
  Ha ! So many changes. 
  
  * multi-table updates
  * limiting number of queries per hour for users
sql/sql_select.cc:
  Optimisation for SQL_CALC_FOUND_ROWS, when a query involves a single
  table, without WHERE or GROUP clause
sql/sql_update.cc:
  multi-table updates
sql/sql_yacc.yy:
  Many things :
  * multi-table updates
  * limiting number of queries per hour for users
  * new optional syntax for multi-table deletes. This one is different 
    from the one demanded by user. USING clause MUST include ALL tables, 
    not just the ones that are used and not deleted from.
This commit is contained in:
unknown
2001-12-26 16:49:10 +02:00
parent 1baa552749
commit 71ce58a3b1
18 changed files with 844 additions and 85 deletions

View File

@@ -37,7 +37,7 @@ extern "C" int gethostname(char *name, int namelen);
#endif
static int check_for_max_user_connections(const char *user, int u_length,
const char *host);
const char *host, uint max);
static void decrease_user_connections(const char *user, const char *host);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
@@ -98,6 +98,95 @@ inline bool end_active_trans(THD *thd)
}
static HASH hash_user_connections;
extern pthread_mutex_t LOCK_user_conn;
struct user_conn {
char *user;
uint len, connections, questions, max;
time_t intime;
};
static byte* get_key_conn(user_conn *buff, uint *length,
my_bool not_used __attribute__((unused)))
{
*length=buff->len;
return (byte*) buff->user;
}
#define DEF_USER_COUNT 50
static void free_user(struct user_conn *uc)
{
my_free((char*) uc,MYF(0));
}
/*
** Check if maximum queries per hour limit has been reached
** returns 0 if OK.
*/
static bool check_mqh(THD *thd, const char *user, const char *host,uint max)
{
uint temp_len;
char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
struct user_conn *uc;
if (!user)
user="";
if (!host)
host="";
temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
NullS) - temp_user);
//This would be MUCH faster if there was already temp_user made in THD !!! May I ??
(void) pthread_mutex_lock(&LOCK_user_conn);
uc = (struct user_conn *) hash_search(&hash_user_connections,
(byte*) temp_user, temp_len);
if (uc) /* user found ; check for no. of queries */
{
bool my_start = thd->start_time != 0;
time_t check_time = (my_start) ? thd->start_time : time(NULL);
if (check_time - uc->intime >= 3600)
{
uc->questions=(uint)my_start;
uc->intime=check_time;
}
else if (uc->max && ++(uc->questions) > uc->max)
{
(void) pthread_mutex_unlock(&LOCK_user_conn);
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); // change this to appropriate message
return 1;
}
}
else
{
struct user_conn *uc= ((struct user_conn*)
my_malloc(sizeof(struct user_conn) + temp_len+1,
MYF(MY_WME)));
if (!uc)
{
send_error(&current_thd->net, 0, NullS); // Out of memory
(void) pthread_mutex_unlock(&LOCK_user_conn);
return 1;
}
uc->user=(char*) (uc+1);
memcpy(uc->user,temp_user,temp_len+1);
uc->len = temp_len;
uc->connections = 1;
uc->questions=0;
uc->max=max;
uc->intime=current_thd->thr_create_time;
if (hash_insert(&hash_user_connections, (byte*) uc))
{
my_free((char*) uc,0);
send_error(&current_thd->net, 0, NullS); // Out of memory
(void) pthread_mutex_unlock(&LOCK_user_conn);
return 1;
}
}
(void) pthread_mutex_unlock(&LOCK_user_conn);
return 0;
}
/*
** Check if user is ok
** Updates:
@@ -108,6 +197,7 @@ 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=0;
thd->db=0;
if (!(thd->user = my_strdup(user, MYF(0))))
@@ -119,7 +209,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));
CLIENT_LONG_PASSWORD),&max);
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,
@@ -150,6 +240,8 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
return(1);
}
}
if (mqh_used && max && check_mqh(thd,user,thd->host,max))
return -1;
mysql_log.write(thd,command,
(thd->priv_user == thd->user ?
(char*) "%s@%s on %s" :
@@ -159,7 +251,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
db ? db : (char*) "");
thd->db_access=0;
if (max_user_connections &&
check_for_max_user_connections(user, strlen(user), thd->host))
check_for_max_user_connections(user, strlen(user), thd->host, max))
return -1;
if (db && db[0])
{
@@ -179,28 +271,6 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
** variable that is greater then 0
*/
static HASH hash_user_connections;
extern pthread_mutex_t LOCK_user_conn;
struct user_conn {
char *user;
uint len, connections;
};
static byte* get_key_conn(user_conn *buff, uint *length,
my_bool not_used __attribute__((unused)))
{
*length=buff->len;
return (byte*) buff->user;
}
#define DEF_USER_COUNT 50
static void free_user(struct user_conn *uc)
{
my_free((char*) uc,MYF(0));
}
void init_max_user_conn(void)
{
(void) hash_init(&hash_user_connections,DEF_USER_COUNT,0,0,
@@ -210,7 +280,7 @@ void init_max_user_conn(void)
static int check_for_max_user_connections(const char *user, int u_length,
const char *host)
const char *host, uint max)
{
int error=1;
uint temp_len;
@@ -251,7 +321,10 @@ static int check_for_max_user_connections(const char *user, int u_length,
uc->user=(char*) (uc+1);
memcpy(uc->user,temp_user,temp_len+1);
uc->len = temp_len;
uc->connections = 1;
uc->connections = 1;
uc->questions=0;
uc->max=max;
uc->intime=current_thd->thr_create_time;
if (hash_insert(&hash_user_connections, (byte*) uc))
{
my_free((char*) uc,0);
@@ -290,7 +363,7 @@ static void decrease_user_connections(const char *user, const char *host)
dbug_assert(uc != 0); // We should always find the user
if (!uc)
goto end; // Safety; Something went wrong
if (! --uc->connections)
if (! --uc->connections && !mqh_used)
{
/* Last connection for user; Delete it */
(void) hash_delete(&hash_user_connections,(byte*) uc);
@@ -306,7 +379,6 @@ void free_max_user_conn(void)
hash_free(&hash_user_connections);
}
/*
** check connnetion and get priviliges
** returns 0 on ok, -1 < if error is given > 0 on error.
@@ -849,6 +921,12 @@ 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 (mqh_used && check_mqh(thd,thd->user,thd->host,0))
{
error = TRUE;
net->error = 0;
break;
}
mysql_parse(thd,thd->query,packet_length-1);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
@@ -959,6 +1037,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
send_error(net,0);
else
send_eof(net);
if (mqh_used && hash_user_connections.array.buffer == 0)
init_max_user_conn();
break;
}
case COM_SHUTDOWN:
@@ -1092,6 +1172,8 @@ mysql_execute_command(void)
(table_rules_on && tables && thd->slave_thread &&
!tables_ok(thd,tables)))
DBUG_VOID_RETURN;
if (lex->sql_command==SQLCOM_UPDATE && select_lex->table_list.elements > 1)
lex->sql_command=SQLCOM_MULTI_UPDATE;
switch (lex->sql_command) {
case SQLCOM_SELECT:
@@ -1727,6 +1809,59 @@ mysql_execute_command(void)
close_thread_tables(thd);
break;
}
case SQLCOM_MULTI_UPDATE:
multi_update *result;
uint table_count;
TABLE_LIST *auxi;
if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege))
goto error;
if (grant_option && check_grant(thd,UPDATE_ACL,tables))
goto error;
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(&thd->net,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
{
table_count++;
auxi->lock_type=TL_WRITE;
}
if (select_lex->order_list.elements || (select_lex->select_limit && select_lex->select_limit < INT_MAX))
{
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /// will have to come up with something better eventually
DBUG_VOID_RETURN;
}
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
if ((res=open_and_lock_tables(thd,tables)))
break;
if (!setup_fields(thd,tables,select_lex->item_list,1,0,0) &&
!setup_fields(thd,tables,lex->value_list,0,0,0) && ! thd->fatal_error &&
(result=new multi_update(thd,tables,select_lex->item_list,lex->duplicates,
lex->lock_option, table_count)))
{
List <Item> total_list;
List_iterator <Item> field_list(select_lex->item_list);
List_iterator <Item> value_list(lex->value_list);
Item *item;
while ((item=field_list++))
total_list.push_back(item);
while ((item=value_list++))
total_list.push_back(item);
res=mysql_select(thd,tables,total_list,
select_lex->where,select_lex->ftfunc_list,
(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
(ORDER *)NULL,
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE,
result);
delete result;
}
else
res= -1; // Error is not sent
close_thread_tables(thd);
break;
case SQLCOM_DROP_TABLE:
{
if (check_table_access(thd,DROP_ACL,tables))
@@ -2080,6 +2215,8 @@ mysql_execute_command(void)
}
}
}
if (mqh_used && hash_user_connections.array.buffer == 0)
init_max_user_conn();
break;
}
case SQLCOM_FLUSH: