summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc3551
1 files changed, 2438 insertions, 1113 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 8786304f893..5a06364cd22 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -25,6 +25,9 @@
#include "ha_innodb.h"
#endif
+#include "sp_head.h"
+#include "sp.h"
+
#ifdef HAVE_OPENSSL
/*
Without SSL the handshake consists of one packet. This packet
@@ -43,6 +46,16 @@
#define MIN_HANDSHAKE_SIZE 6
#endif /* HAVE_OPENSSL */
+/* Used in error handling only */
+#define SP_TYPE_STRING(LP) \
+ ((LP)->sphead->m_type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE")
+#define SP_COM_STRING(LP) \
+ ((LP)->sql_command == SQLCOM_CREATE_SPFUNCTION || \
+ (LP)->sql_command == SQLCOM_ALTER_FUNCTION || \
+ (LP)->sql_command == SQLCOM_SHOW_CREATE_FUNC || \
+ (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
+ "FUNCTION" : "PROCEDURE")
+
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#endif
@@ -53,8 +66,7 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
#endif
static void decrease_user_connections(USER_CONN *uc);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
-static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables,
- List<Item> *fields, SELECT_LEX *select_lex);
+static bool check_multi_update_lock(THD *thd);
static void remove_escape(char *name);
static void refresh_status(void);
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
@@ -69,10 +81,14 @@ const char *command_name[]={
"Connect","Kill","Debug","Ping","Time","Delayed insert","Change user",
"Binlog Dump","Table Dump", "Connect Out", "Register Slave",
"Prepare", "Execute", "Long Data", "Close stmt",
- "Reset stmt", "Set option",
+ "Reset stmt", "Set option", "Fetch",
"Error" // Last command number
};
+const char *xa_state_names[]={
+ "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
+};
+
static char empty_c_string[1]= {0}; // Used for not defined 'db'
#ifdef __WIN__
@@ -99,7 +115,7 @@ static void unlock_locked_tables(THD *thd)
if (thd->locked_tables)
{
thd->lock=thd->locked_tables;
- thd->locked_tables=0; // Will be automaticly closed
+ thd->locked_tables=0; // Will be automatically closed
close_thread_tables(thd); // Free tables
}
}
@@ -108,17 +124,44 @@ static void unlock_locked_tables(THD *thd)
static bool end_active_trans(THD *thd)
{
int error=0;
+ DBUG_ENTER("end_active_trans");
if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
OPTION_TABLE_LOCK))
{
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ DBUG_PRINT("info",("options: 0x%lx", (ulong) thd->options));
+ /* Safety if one did "drop table" on locked tables */
+ if (!thd->locked_tables)
+ thd->options&= ~OPTION_TABLE_LOCK;
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (ha_commit(thd))
error=1;
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
}
- return error;
+ DBUG_RETURN(error);
}
+static bool begin_trans(THD *thd)
+{
+ int error=0;
+ if (thd->locked_tables)
+ {
+ thd->lock=thd->locked_tables;
+ thd->locked_tables=0; // Will be automatically closed
+ close_thread_tables(thd); // Free tables
+ }
+ if (end_active_trans(thd))
+ error= -1;
+ else
+ {
+ LEX *lex= thd->lex;
+ thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
+ OPTION_BEGIN);
+ thd->server_status|= SERVER_STATUS_IN_TRANS;
+ if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
+ error= ha_start_consistent_snapshot(thd);
+ }
+ return error;
+}
#ifdef HAVE_REPLICATION
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
@@ -156,25 +199,21 @@ static int get_or_create_user_conn(THD *thd, const char *user,
my_malloc(sizeof(struct user_conn) + temp_len+1,
MYF(MY_WME)))))
{
- send_error(thd, 0, NullS); // Out of memory
+ net_send_error(thd, 0, NullS); // Out of memory
return_val=1;
goto end;
}
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->host= uc->user + user_len + 1;
uc->len = temp_len;
- uc->connections = 1;
- uc->questions=uc->updates=uc->conn_per_hour=0;
+ uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
uc->user_resources=*mqh;
- if (max_user_connections && mqh->connections > max_user_connections)
- uc->user_resources.connections = max_user_connections;
uc->intime=thd->thr_create_time;
if (my_hash_insert(&hash_user_connections, (byte*) uc))
{
my_free((char*) uc,0);
- send_error(thd, 0, NullS); // Out of memory
+ net_send_error(thd, 0, NullS); // Out of memory
return_val=1;
goto end;
}
@@ -196,13 +235,13 @@ end:
command originator of the check: now check_user is called
during connect and change user procedures; used for
logging.
- passwd scrambled password recieved from client
+ passwd scrambled password received from client
passwd_len length of scrambled password
db database name to connect to, may be NULL
check_count dont know exactly
Note, that host, user and passwd may point to communication buffer.
- Current implementation does not depened on that, but future changes
+ Current implementation does not depend on that, but future changes
should be done with this in mind; 'thd' is INOUT, all other params
are 'IN'.
@@ -221,13 +260,15 @@ int check_user(THD *thd, enum enum_server_command command,
#ifdef NO_EMBEDDED_ACCESS_CHECKS
thd->master_access= GLOBAL_ACLS; // Full rights
- /* Change database if necessary: OK or FAIL is sent in mysql_change_db */
+ /* Change database if necessary */
if (db && db[0])
{
thd->db= 0;
thd->db_length= 0;
if (mysql_change_db(thd, db))
{
+ /* Send the error to the client */
+ net_send_error(thd);
if (thd->user_connect)
decrease_user_connections(thd->user_connect);
DBUG_RETURN(-1);
@@ -249,7 +290,7 @@ int check_user(THD *thd, enum enum_server_command command,
*/
if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
{
- net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
DBUG_RETURN(-1);
}
@@ -260,7 +301,7 @@ int check_user(THD *thd, enum enum_server_command command,
/*
Clear thd->db as it points to something, that will be freed when
- connection is closed. We don't want to accidently free a wrong pointer
+ connection is closed. We don't want to accidentally free a wrong pointer
if connect failed. Also in case of 'CHANGE USER' failure, current
database will be switched to 'no database selected'.
*/
@@ -281,15 +322,16 @@ int check_user(THD *thd, enum enum_server_command command,
NET *net= &thd->net;
if (opt_secure_auth_local)
{
- net_printf(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
- thd->user, thd->host_or_ip);
+ net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
+ thd->user, thd->host_or_ip);
mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
thd->user, thd->host_or_ip);
DBUG_RETURN(-1);
}
+ /* We have to read very specific packet size */
if (send_old_password_request(thd) ||
- my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very
- { // specific packet size
+ my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
+ {
inc_host_errors(&thd->remote.sin_addr);
DBUG_RETURN(ER_HANDSHAKE_ERROR);
}
@@ -301,7 +343,7 @@ int check_user(THD *thd, enum enum_server_command command,
/* here res is always >= 0 */
if (res == 0)
{
- if (!(thd->master_access & NO_ACCESS)) // authentification is OK
+ if (!(thd->master_access & NO_ACCESS)) // authentication is OK
{
DBUG_PRINT("info",
("Capabilities: %d packet_length: %ld Host: '%s' "
@@ -315,12 +357,12 @@ int check_user(THD *thd, enum enum_server_command command,
if (check_count)
{
VOID(pthread_mutex_lock(&LOCK_thread_count));
- bool count_ok= thread_count < max_connections + delayed_insert_threads
+ bool count_ok= thread_count <= max_connections + delayed_insert_threads
|| (thd->master_access & SUPER_ACL);
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (!count_ok)
- { // too many connections
- send_error(thd, ER_CON_COUNT_ERROR);
+ { // too many connections
+ net_send_error(thd, ER_CON_COUNT_ERROR);
DBUG_RETURN(-1);
}
}
@@ -341,21 +383,27 @@ int check_user(THD *thd, enum enum_server_command command,
thd->db_access=0;
/* Don't allow user to connect if he has done too many queries */
- if ((ur.questions || ur.updates || ur.connections ||
+ if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
max_user_connections) &&
- get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur))
+ get_or_create_user_conn(thd,
+ opt_old_style_user_limits ? thd->user : thd->priv_user,
+ opt_old_style_user_limits ? thd->host_or_ip : thd->priv_host,
+ &ur))
DBUG_RETURN(-1);
if (thd->user_connect &&
- (thd->user_connect->user_resources.connections ||
+ (thd->user_connect->user_resources.conn_per_hour ||
+ thd->user_connect->user_resources.user_conn ||
max_user_connections) &&
check_for_max_user_connections(thd, thd->user_connect))
DBUG_RETURN(-1);
- /* Change database if necessary: OK or FAIL is sent in mysql_change_db */
+ /* Change database if necessary */
if (db && db[0])
{
if (mysql_change_db(thd, db))
{
+ /* Send error to the client */
+ net_send_error(thd);
if (thd->user_connect)
decrease_user_connections(thd->user_connect);
DBUG_RETURN(-1);
@@ -370,14 +418,14 @@ int check_user(THD *thd, enum enum_server_command command,
}
else if (res == 2) // client gave short hash, server has long hash
{
- net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
DBUG_RETURN(-1);
}
- net_printf(thd, ER_ACCESS_DENIED_ERROR,
- thd->user,
- thd->host_or_ip,
- passwd_len ? ER(ER_YES) : ER(ER_NO));
+ net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
+ thd->user,
+ thd->host_or_ip,
+ passwd_len ? ER(ER_YES) : ER(ER_NO));
mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
thd->user,
thd->host_or_ip,
@@ -437,20 +485,29 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
DBUG_ENTER("check_for_max_user_connections");
(void) pthread_mutex_lock(&LOCK_user_conn);
- if (max_user_connections &&
+ if (max_user_connections && !uc->user_resources.user_conn &&
max_user_connections < (uint) uc->connections)
{
- net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user);
+ net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
error=1;
goto end;
}
time_out_user_resource_limits(thd, uc);
- if (uc->user_resources.connections &&
- uc->user_resources.connections <= uc->conn_per_hour)
+ if (uc->user_resources.user_conn &&
+ uc->user_resources.user_conn < uc->connections)
{
- net_printf(thd, ER_USER_LIMIT_REACHED, uc->user,
- "max_connections_per_hour",
- (long) uc->user_resources.connections);
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
+ "max_user_connections",
+ (long) uc->user_resources.user_conn);
+ error= 1;
+ goto end;
+ }
+ if (uc->user_resources.conn_per_hour &&
+ uc->user_resources.conn_per_hour <= uc->conn_per_hour)
+ {
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
+ "max_connections_per_hour",
+ (long) uc->user_resources.conn_per_hour);
error=1;
goto end;
}
@@ -509,6 +566,12 @@ void free_max_user_conn(void)
sql_command is actually set to SQLCOM_END sometimes
so we need the +1 to include it in the array.
+
+ numbers are:
+ 0 - read-only query
+ != 0 - query that may change a table
+ 2 - query that returns meaningful ROW_COUNT() -
+ a number of modified rows
*/
char uc_update_queries[SQLCOM_END+1];
@@ -520,23 +583,25 @@ void init_update_queries(void)
uc_update_queries[SQLCOM_CREATE_TABLE]=1;
uc_update_queries[SQLCOM_CREATE_INDEX]=1;
uc_update_queries[SQLCOM_ALTER_TABLE]=1;
- uc_update_queries[SQLCOM_UPDATE]=1;
- uc_update_queries[SQLCOM_INSERT]=1;
- uc_update_queries[SQLCOM_INSERT_SELECT]=1;
- uc_update_queries[SQLCOM_DELETE]=1;
+ uc_update_queries[SQLCOM_UPDATE]=2;
+ uc_update_queries[SQLCOM_UPDATE_MULTI]=2;
+ uc_update_queries[SQLCOM_INSERT]=2;
+ uc_update_queries[SQLCOM_INSERT_SELECT]=2;
+ uc_update_queries[SQLCOM_DELETE]=2;
+ uc_update_queries[SQLCOM_DELETE_MULTI]=2;
uc_update_queries[SQLCOM_TRUNCATE]=1;
uc_update_queries[SQLCOM_DROP_TABLE]=1;
uc_update_queries[SQLCOM_LOAD]=1;
uc_update_queries[SQLCOM_CREATE_DB]=1;
uc_update_queries[SQLCOM_DROP_DB]=1;
- uc_update_queries[SQLCOM_REPLACE]=1;
- uc_update_queries[SQLCOM_REPLACE_SELECT]=1;
+ uc_update_queries[SQLCOM_REPLACE]=2;
+ uc_update_queries[SQLCOM_REPLACE_SELECT]=2;
uc_update_queries[SQLCOM_RENAME_TABLE]=1;
uc_update_queries[SQLCOM_BACKUP_TABLE]=1;
uc_update_queries[SQLCOM_RESTORE_TABLE]=1;
- uc_update_queries[SQLCOM_DELETE_MULTI]=1;
uc_update_queries[SQLCOM_DROP_INDEX]=1;
- uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
+ uc_update_queries[SQLCOM_CREATE_VIEW]=1;
+ uc_update_queries[SQLCOM_DROP_VIEW]=1;
}
bool is_update_query(enum enum_sql_command command)
@@ -561,7 +626,6 @@ bool is_update_query(enum enum_sql_command command)
static void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
{
- bool error= 0;
time_t check_time = thd->start_time ? thd->start_time : time(NULL);
DBUG_ENTER("time_out_user_resource_limits");
@@ -600,8 +664,8 @@ static bool check_mqh(THD *thd, uint check_command)
if (uc->user_resources.questions &&
uc->questions++ >= uc->user_resources.questions)
{
- net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
- (long) uc->user_resources.questions);
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
+ (long) uc->user_resources.questions);
error=1;
goto end;
}
@@ -611,8 +675,8 @@ static bool check_mqh(THD *thd, uint check_command)
if (uc->user_resources.updates && uc_update_queries[check_command] &&
uc->updates++ >= uc->user_resources.updates)
{
- net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
- (long) uc->user_resources.updates);
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
+ (long) uc->user_resources.updates);
error=1;
goto end;
}
@@ -626,7 +690,7 @@ end:
}
-static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
+static void reset_mqh(LEX_USER *lu, bool get_them= 0)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
(void) pthread_mutex_lock(&LOCK_user_conn);
@@ -648,8 +712,9 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
uc->conn_per_hour=0;
}
}
- else // for FLUSH PRIVILEGES and FLUSH USER_RESOURCES
+ else
{
+ /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
for (uint idx=0;idx < hash_user_connections.records; idx++)
{
USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
@@ -750,7 +815,7 @@ static int check_connection(THD *thd)
#endif /* HAVE_COMPRESS */
#ifdef HAVE_OPENSSL
if (ssl_acceptor_fd)
- client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */
+ client_flags |= CLIENT_SSL; /* Wow, SSL is available! */
#endif /* HAVE_OPENSSL */
end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
@@ -798,17 +863,6 @@ static int check_connection(THD *thd)
return(ER_OUT_OF_RESOURCES);
thd->client_capabilities=uint2korr(net->read_pos);
-#ifdef TO_BE_REMOVED_IN_4_1_RELEASE
- /*
- This is just a safety check against any client that would use the old
- CLIENT_CHANGE_USER flag
- */
- if ((thd->client_capabilities & CLIENT_PROTOCOL_41) &&
- !(thd->client_capabilities & (CLIENT_RESERVED |
- CLIENT_SECURE_CONNECTION |
- CLIENT_MULTI_RESULTS)))
- thd->client_capabilities&= ~CLIENT_PROTOCOL_41;
-#endif
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
@@ -956,6 +1010,7 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var,
*/
save_vio= thd->net.vio;
thd->net.vio= 0;
+ thd->net.no_send_error= 0;
dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
rw_unlock(var_mutex);
thd->client_capabilities= save_client_capabilities;
@@ -974,7 +1029,7 @@ pthread_handler_decl(handle_one_connection,arg)
pthread_detach_this_thread();
#if !defined( __WIN__) && !defined(OS2) // Win32 calls this in pthread_create
- // The following calls needs to be done before we call DBUG_ macros
+ /* The following calls needs to be done before we call DBUG_ macros */
if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
{
close_connection(thd, ER_OUT_OF_RESOURCES, 1);
@@ -993,10 +1048,10 @@ pthread_handler_decl(handle_one_connection,arg)
*/
DBUG_PRINT("info", ("handle_one_connection called by thread %d\n",
thd->thread_id));
- // now that we've called my_thread_init(), it is safe to call DBUG_*
+ /* now that we've called my_thread_init(), it is safe to call DBUG_* */
#if defined(__WIN__)
- init_signals(); // IRENA; testing ?
+ init_signals();
#elif !defined(OS2) && !defined(__NETWARE__)
sigset_t set;
VOID(sigemptyset(&set)); // Get mask in use
@@ -1015,11 +1070,12 @@ pthread_handler_decl(handle_one_connection,arg)
int error;
NET *net= &thd->net;
thd->thread_stack= (char*) &thd;
+ net->no_send_error= 0;
if ((error=check_connection(thd)))
{ // Wrong permissions
if (error > 0)
- net_printf(thd,error,thd->host_or_ip);
+ net_printf_error(thd, error, thd->host_or_ip);
#ifdef __NT__
if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
my_sleep(1000); /* must wait after eof() */
@@ -1037,32 +1093,39 @@ pthread_handler_decl(handle_one_connection,arg)
thd->version= refresh_version;
thd->proc_info= 0;
+ thd->command= COM_SLEEP;
thd->set_time();
thd->init_for_queries();
+
if (sys_init_connect.value_length && !(thd->master_access & SUPER_ACL))
{
execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
if (thd->query_error)
- thd->killed= 1;
+ thd->killed= THD::KILL_CONNECTION;
}
- while (!net->error && net->vio != 0 && !thd->killed)
+
+ thd->proc_info=0;
+ thd->set_time();
+ thd->init_for_queries();
+ while (!net->error && net->vio != 0 &&
+ !(thd->killed == THD::KILL_CONNECTION))
{
+ net->no_send_error= 0;
if (do_command(thd))
break;
}
if (thd->user_connect)
decrease_user_connections(thd->user_connect);
- free_root(thd->mem_root,MYF(0));
if (net->error && net->vio != 0 && net->report_error)
{
if (!thd->killed && thd->variables.log_warnings > 1)
- sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
+ sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
thd->thread_id,(thd->db ? thd->db : "unconnected"),
thd->user ? thd->user : "unauthenticated",
thd->host_or_ip,
(net->last_errno ? ER(net->last_errno) :
ER(ER_UNKNOWN_ERROR)));
- send_error(thd,net->last_errno,NullS);
+ net_send_error(thd, net->last_errno, NullS);
statistic_increment(aborted_threads,&LOCK_status);
}
else if (thd->killed)
@@ -1128,25 +1191,26 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->init_for_queries();
while (fgets(buff, thd->net.max_packet, file))
{
- ulong length= (ulong) strlen(buff);
- while (buff[length-1] != '\n' && !feof(file))
- {
- /*
- We got only a part of the current string. Will try to increase
- net buffer then read the rest of the current string.
- */
- if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
- {
- send_error(thd, thd->net.last_errno, NullS);
- thd->is_fatal_error= 1;
- break;
- }
- buff= (char*) thd->net.buff;
- fgets(buff + length, thd->net.max_packet - length, file);
- length+= (ulong) strlen(buff + length);
- }
- if (thd->is_fatal_error)
- break;
+ ulong length= (ulong) strlen(buff);
+ while (buff[length-1] != '\n' && !feof(file))
+ {
+ /*
+ We got only a part of the current string. Will try to increase
+ net buffer then read the rest of the current string.
+ */
+ if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
+ {
+ net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS);
+ thd->fatal_error();
+ break;
+ }
+ buff= (char*) thd->net.buff;
+ fgets(buff + length, thd->net.max_packet - length, file);
+ length+= (ulong) strlen(buff + length);
+ }
+ if (thd->is_fatal_error)
+ break;
+
while (length && (my_isspace(thd->charset(), buff[length-1]) ||
buff[length-1] == ';'))
length--;
@@ -1154,24 +1218,29 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->query_length=length;
thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
thd->query[length] = '\0';
- thd->query_id=query_id++;
- if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
- {
- thd->net.error = 0;
- close_thread_tables(thd); // Free tables
- free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- break;
- }
+ /*
+ We don't need to obtain LOCK_thread_count here because in bootstrap
+ mode we have only one thread.
+ */
+ thd->query_id=next_query_id();
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
if (thd->is_fatal_error)
break;
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+#ifdef USING_TRANSACTIONS
free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
+#endif
}
/* thd->fatal_error should be set in case something went wrong */
end:
+ bootstrap_error= thd->is_fatal_error;
+
+ net_end(&thd->net);
+ thd->cleanup();
+ delete thd;
+
#ifndef EMBEDDED_LIBRARY
(void) pthread_mutex_lock(&LOCK_thread_count);
thread_count--;
@@ -1180,23 +1249,31 @@ end:
my_thread_end();
pthread_exit(0);
#endif
- DBUG_RETURN(0); // Never reached
+ DBUG_RETURN(0);
}
/* This works because items are allocated with sql_alloc() */
void free_items(Item *item)
{
- for (; item ; item=item->next)
+ Item *next;
+ DBUG_ENTER("free_items");
+ for (; item ; item=next)
+ {
+ next=item->next;
item->delete_self();
+ }
+ DBUG_VOID_RETURN;
}
/* This works because items are allocated with sql_alloc() */
void cleanup_items(Item *item)
{
+ DBUG_ENTER("cleanup_items");
for (; item ; item=item->next)
item->cleanup();
+ DBUG_VOID_RETURN;
}
int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
@@ -1208,19 +1285,19 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
db = (db && db[0]) ? db : thd->db;
if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(1); // out of memory
- table_list->db = db;
- table_list->real_name = table_list->alias = tbl_name;
- table_list->lock_type = TL_READ_NO_INSERT;
- table_list->next = 0;
+ table_list->db= db;
+ table_list->table_name= table_list->alias= tbl_name;
+ table_list->lock_type= TL_READ_NO_INSERT;
+ table_list->prev_global= &table_list; // can be removed after merge with 4.1
if (!db || check_db_name(db))
{
- net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
+ my_error(ER_WRONG_DB_NAME ,MYF(0), db ? db : "NULL");
goto err;
}
if (lower_case_table_names)
my_casedn_str(files_charset_info, tbl_name);
- remove_escape(table_list->real_name);
+ remove_escape(table_list->table_name);
if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
DBUG_RETURN(1);
@@ -1230,7 +1307,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
thd->free_list = 0;
thd->query_length=(uint) strlen(tbl_name);
thd->query = tbl_name;
- if ((error = mysqld_dump_create_info(thd, table, -1)))
+ if ((error = mysqld_dump_create_info(thd, table_list, -1)))
{
my_error(ER_GET_ERRNO, MYF(0), my_errno);
goto err;
@@ -1240,10 +1317,71 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
my_error(ER_GET_ERRNO, MYF(0), error);
err:
- close_thread_tables(thd);
DBUG_RETURN(error);
}
+/*
+ Ends the current transaction and (maybe) begin the next
+
+ SYNOPSIS
+ end_trans()
+ thd Current thread
+ completion Completion type
+
+ RETURN
+ 0 - OK
+*/
+
+int end_trans(THD *thd, enum enum_mysql_completiontype completion)
+{
+ bool do_release= 0;
+ int res= 0;
+ DBUG_ENTER("end_trans");
+
+ switch (completion) {
+ case COMMIT:
+ /*
+ We don't use end_active_trans() here to ensure that this works
+ even if there is a problem with the OPTION_AUTO_COMMIT flag
+ (Which of course should never happen...)
+ */
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ res= ha_commit(thd);
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ break;
+ case COMMIT_RELEASE:
+ do_release= 1; /* fall through */
+ case COMMIT_AND_CHAIN:
+ res= end_active_trans(thd);
+ if (!res && completion == COMMIT_AND_CHAIN)
+ res= begin_trans(thd);
+ break;
+ case ROLLBACK_RELEASE:
+ do_release= 1; /* fall through */
+ case ROLLBACK:
+ case ROLLBACK_AND_CHAIN:
+ {
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ if (ha_rollback(thd))
+ res= -1;
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ if (!res && (completion == ROLLBACK_AND_CHAIN))
+ res= begin_trans(thd);
+ break;
+ }
+ default:
+ res= -1;
+ my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ if (res < 0)
+ my_error(thd->killed_errno(), MYF(0));
+ else if ((res == 0) && do_release)
+ thd->killed= THD::KILL_CONNECTION;
+
+ DBUG_RETURN(res);
+}
#ifndef EMBEDDED_LIBRARY
@@ -1275,7 +1413,7 @@ bool do_command(THD *thd)
packet=0;
old_timeout=net->read_timeout;
- // Wait max for 8 hours
+ /* Wait max for 8 hours */
net->read_timeout=(uint) thd->variables.net_wait_timeout;
thd->clear_error(); // Clear error message
@@ -1291,7 +1429,7 @@ bool do_command(THD *thd)
statistic_increment(aborted_threads,&LOCK_status);
DBUG_RETURN(TRUE); // We have to close it.
}
- send_error(thd,net->last_errno,NullS);
+ net_send_error(thd, net->last_errno, NullS);
net->error= 0;
DBUG_RETURN(FALSE);
}
@@ -1319,6 +1457,7 @@ bool do_command(THD *thd)
}
#endif /* EMBEDDED_LIBRARY */
+
/*
Perform one connection-level (COM_XXXX) command.
SYNOPSIS
@@ -1342,17 +1481,21 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
bool error= 0;
DBUG_ENTER("dispatch_command");
+ if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
+ thd->killed= THD::NOT_KILLED;
+
thd->command=command;
/*
Commands which will always take a long time should be marked with
this so that they will not get logged to the slow query log
*/
thd->slow_command=FALSE;
+ thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
thd->set_time();
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id=query_id;
if (command != COM_STATISTICS && command != COM_PING)
- query_id++;
+ next_query_id();
thread_running++;
/* TODO: set thd->lex->sql_command to SQLCOM_END here */
VOID(pthread_mutex_unlock(&LOCK_thread_count));
@@ -1363,7 +1506,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_INIT_DB:
{
LEX_STRING tmp;
- statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB],
+ &LOCK_status);
thd->convert_string(&tmp, system_charset_info,
packet, strlen(packet), thd->charset());
if (!mysql_change_db(thd, tmp.str))
@@ -1384,13 +1528,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
uint db_len= *(uchar*) packet;
uint tbl_len= *(uchar*) (packet + db_len + 1);
- statistic_increment(com_other, &LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
thd->slow_command= TRUE;
db= thd->alloc(db_len + tbl_len + 2);
tbl_name= strmake(db, packet + 1, db_len)+1;
strmake(tbl_name, packet + db_len + 2, tbl_len);
- if (mysql_table_dump(thd, db, tbl_name, -1))
- send_error(thd); // dump to NET
+ mysql_table_dump(thd, db, tbl_name, -1);
break;
}
case COM_CHANGE_USER:
@@ -1398,7 +1541,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->change_user();
thd->clear_error(); // if errors from rollback
- statistic_increment(com_other, &LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
char *user= (char*) packet;
char *passwd= strend(user)+1;
/*
@@ -1412,10 +1555,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
*passwd++ : strlen(passwd);
db+= passwd_len + 1;
#ifndef EMBEDDED_LIBRARY
- /* Small check for incomming packet */
+ /* Small check for incoming packet */
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
{
- send_error(thd, ER_UNKNOWN_COM_ERROR);
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
#endif
@@ -1438,7 +1581,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (!(thd->user= my_strdup(user, MYF(0))))
{
thd->user= save_user;
- send_error(thd, ER_OUT_OF_RESOURCES);
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
break;
}
@@ -1448,9 +1591,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (res)
{
- /* authentification failure, we shall restore old user */
+ /* authentication failure, we shall restore old user */
if (res > 0)
- send_error(thd, ER_UNKNOWN_COM_ERROR);
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
x_free(thd->user);
thd->user= save_user;
thd->priv_user= save_priv_user;
@@ -1475,6 +1618,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
mysql_stmt_execute(thd, packet, packet_length);
break;
}
+ case COM_FETCH:
+ {
+ mysql_stmt_fetch(thd, packet, packet_length);
+ break;
+ }
case COM_LONG_DATA:
{
mysql_stmt_get_longdata(thd, packet, packet_length);
@@ -1482,7 +1630,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_PREPARE:
{
- mysql_stmt_prepare(thd, packet, packet_length);
+ mysql_stmt_prepare(thd, packet, packet_length, 0);
break;
}
case COM_CLOSE_STMT:
@@ -1504,15 +1652,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_PRINT("query",("%-.4096s",thd->query));
mysql_parse(thd,thd->query, thd->query_length);
- while (!thd->killed && !thd->is_fatal_error && thd->lex->found_colon)
+ while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error)
{
- char *packet= thd->lex->found_colon;
+ char *packet= thd->lex->found_semicolon;
/*
Multiple queries exits, execute them individually
in embedded server - just store them to be executed later
*/
#ifndef EMBEDDED_LIBRARY
- if (thd->lock || thd->open_tables || thd->derived_tables)
+ if (thd->lock || thd->open_tables || thd->derived_tables ||
+ thd->prelocked_mode)
close_thread_tables(thd);
#endif
ulong length= (ulong)(packet_end-packet);
@@ -1528,7 +1677,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_length= length;
thd->query= packet;
- thd->query_id= query_id++;
+ thd->query_id= next_query_id();
thd->set_time(); /* Reset the query start time. */
/* TODO: set thd->lex->sql_command to SQLCOM_END here */
VOID(pthread_mutex_unlock(&LOCK_thread_count));
@@ -1560,34 +1709,50 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_FIELD_LIST: // This isn't actually needed
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
+ MYF(0)); /* purecov: inspected */
break;
#else
{
char *fields, *pend;
+ /* Locked closure of all tables */
+ TABLE_LIST *locked_tables= NULL;
TABLE_LIST table_list;
LEX_STRING conv_name;
+ /* Saved variable value */
+ my_bool old_innodb_table_locks=
+ IF_INNOBASE_DB(thd->variables.innodb_table_locks, FALSE);
+
- statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
+ &LOCK_status);
bzero((char*) &table_list,sizeof(table_list));
if (!(table_list.db=thd->db))
{
- send_error(thd,ER_NO_DB_ERROR);
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
break;
}
- thd->free_list=0;
pend= strend(packet);
thd->convert_string(&conv_name, system_charset_info,
packet, (uint) (pend-packet), thd->charset());
- table_list.alias= table_list.real_name= conv_name.str;
+ table_list.alias= table_list.table_name= conv_name.str;
packet= pend+1;
+
+ if (!my_strcasecmp(system_charset_info, table_list.db,
+ information_schema_name.str))
+ {
+ ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
+ if (schema_table)
+ table_list.schema_table= schema_table;
+ }
+
thd->query_length= strlen(packet); // for simplicity: don't optimize
if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
break;
- mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
+ mysql_log.write(thd,command,"%s %s",table_list.table_name, fields);
if (lower_case_table_names)
- my_casedn_str(files_charset_info, table_list.real_name);
- remove_escape(table_list.real_name); // This can't have wildcards
+ my_casedn_str(files_charset_info, table_list.table_name);
+ remove_escape(table_list.table_name); // This can't have wildcards
if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
0, 0))
@@ -1595,9 +1760,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (grant_option &&
check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
break;
+ /* init structures for VIEW processing */
+ table_list.select_lex= &(thd->lex->select_lex);
+ mysql_init_query(thd, (uchar*)"", 0);
+ thd->lex->
+ select_lex.table_list.link_in_list((byte*) &table_list,
+ (byte**) &table_list.next_local);
+ thd->lex->add_to_query_tables(&table_list);
+
+ /* switch on VIEW optimisation: do not fill temporary tables */
+ thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
mysqld_list_fields(thd,&table_list,fields);
- free_items(thd->free_list);
- thd->free_list= 0;
+ thd->lex->unit.cleanup();
+ thd->cleanup_after_query();
break;
}
#endif
@@ -1613,43 +1788,43 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
char *db=thd->strdup(packet), *alias;
HA_CREATE_INFO create_info;
- statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB],
+ &LOCK_status);
// null test to handle EOM
if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
{
- net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
+ my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
break;
}
if (check_access(thd,CREATE_ACL,db,0,1,0))
break;
mysql_log.write(thd,command,packet);
bzero(&create_info, sizeof(create_info));
- if (mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
- &create_info, 0) < 0)
- send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0);
+ mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
+ &create_info, 0);
break;
}
case COM_DROP_DB: // QQ: To be removed
{
- statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
- char *db=thd->strdup(packet), *alias;
- // null test to handle EOM
- if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
+ statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB],
+ &LOCK_status);
+ char *db=thd->strdup(packet);
+ /* null test to handle EOM */
+ if (!db || check_db_name(db))
{
- net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
+ my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
break;
}
if (check_access(thd,DROP_ACL,db,0,1,0))
break;
if (thd->locked_tables || thd->active_transaction())
{
- send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
break;
}
mysql_log.write(thd,command,db);
- if (mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : db),
- 0, 0) < 0)
- send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0);
+ mysql_rm_db(thd, db, 0, 0);
break;
}
#ifndef EMBEDDED_LIBRARY
@@ -1659,7 +1834,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
ushort flags;
uint32 slave_server_id;
- statistic_increment(com_other,&LOCK_status);
+ statistic_increment(thd->status_var.com_other,&LOCK_status);
thd->slow_command = TRUE;
if (check_global_access(thd, REPL_SLAVE_ACL))
break;
@@ -1676,7 +1851,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
(long) pos);
mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unregister_slave(thd,1,1);
- // fake COM_QUIT -- if we get here, the thread needs to terminate
+ /* fake COM_QUIT -- if we get here, the thread needs to terminate */
error = TRUE;
net->error = 0;
break;
@@ -1684,21 +1859,20 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
case COM_REFRESH:
{
- statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH],
+ &LOCK_status);
ulong options= (ulong) (uchar) packet[0];
if (check_global_access(thd,RELOAD_ACL))
break;
mysql_log.write(thd,command,NullS);
- if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, NULL))
- send_error(thd, 0);
- else
+ if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, NULL))
send_ok(thd);
break;
}
#ifndef EMBEDDED_LIBRARY
case COM_SHUTDOWN:
{
- statistic_increment(com_other,&LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
if (check_global_access(thd,SHUTDOWN_ACL))
break; /* purecov: inspected */
/*
@@ -1715,7 +1889,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
else if (level != SHUTDOWN_WAIT_ALL_BUFFERS)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "this shutdown level");
- send_error(thd);
break;
}
DBUG_PRINT("quit",("Got shutdown command for level %u", level));
@@ -1729,8 +1902,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
close_connection(thd, 0, 1);
close_thread_tables(thd); // Free before kill
- free_root(thd->mem_root,MYF(0));
- free_root(&thd->transaction.mem_root,MYF(0));
kill_mysql();
error=TRUE;
break;
@@ -1739,7 +1910,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_STATISTICS:
{
mysql_log.write(thd,command,NullS);
- statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS],
+ &LOCK_status);
#ifndef EMBEDDED_LIBRARY
char buff[200];
#else
@@ -1747,11 +1919,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
ulong uptime = (ulong) (thd->start_time - start_time);
sprintf((char*) buff,
- "Uptime: %ld Threads: %d Questions: %lu Slow queries: %ld Opens: %ld Flush tables: %ld Open tables: %u Queries per second avg: %.3f",
+ "Uptime: %lu Threads: %d Questions: %lu Slow queries: %lu Opens: %lu Flush tables: %lu Open tables: %u Queries per second avg: %.3f",
uptime,
- (int) thread_count,thd->query_id,long_query_count,
- opened_tables,refresh_version, cached_tables(),
- uptime ? (float)thd->query_id/(float)uptime : 0);
+ (int) thread_count, (ulong) thd->query_id,
+ (ulong) thd->status_var.long_query_count,
+ thd->status_var.opened_tables, refresh_version, cached_tables(),
+ (uptime ? (ulonglong2double(thd->query_id) / (double) uptime) :
+ (double) 0));
#ifdef SAFEMALLOC
if (sf_malloc_cur_memory) // Using SAFEMALLOC
sprintf(strend(buff), " Memory in use: %ldK Max memory used: %ldK",
@@ -1765,11 +1939,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
case COM_PING:
- statistic_increment(com_other,&LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
send_ok(thd); // Tell client we are alive
break;
case COM_PROCESS_INFO:
- statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
+ &LOCK_status);
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
break;
mysql_log.write(thd,command,NullS);
@@ -1779,14 +1954,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
case COM_PROCESS_KILL:
{
- statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
ulong id=(ulong) uint4korr(packet);
- kill_one_thread(thd,id);
+ kill_one_thread(thd,id,false);
break;
}
case COM_SET_OPTION:
{
- statistic_increment(com_stat[SQLCOM_SET_OPTION], &LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION],
+ &LOCK_status);
enum_mysql_set_option command= (enum_mysql_set_option) uint2korr(packet);
switch (command) {
case MYSQL_OPTION_MULTI_STATEMENTS_ON:
@@ -1798,16 +1974,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
send_eof(thd);
break;
default:
- send_error(thd, ER_UNKNOWN_COM_ERROR);
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
break;
}
case COM_DEBUG:
- statistic_increment(com_other,&LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
if (check_global_access(thd, SUPER_ACL))
break; /* purecov: inspected */
- mysql_print_status(thd);
+ mysql_print_status();
mysql_log.write(thd,command,NullS);
send_eof(thd);
break;
@@ -1817,17 +1993,32 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_DELAYED_INSERT:
case COM_END:
default:
- send_error(thd, ER_UNKNOWN_COM_ERROR);
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
- if (thd->lock || thd->open_tables || thd->derived_tables)
+ if (thd->lock || thd->open_tables || thd->derived_tables ||
+ thd->prelocked_mode)
{
thd->proc_info="closing tables";
close_thread_tables(thd); /* Free tables */
}
+ /*
+ assume handlers auto-commit (if some doesn't - transaction handling
+ in MySQL should be redesigned to support it; it's a big change,
+ and it's not worth it - better to commit explicitly only writing
+ transactions, read-only ones should better take care of themselves.
+ saves some work in 2pc too)
+ see also sql_base.cc - close_thread_tables()
+ */
+ bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
+ if (!thd->active_transaction())
+ thd->transaction.xid.null();
- if (thd->is_fatal_error)
- send_error(thd,0); // End of memory ?
+ /* report error issued during command execution */
+ if (thd->killed_errno() && !thd->net.report_error)
+ thd->send_kill_message();
+ if (thd->net.report_error)
+ net_send_error(thd);
log_slow_query(thd);
@@ -1861,13 +2052,126 @@ static void log_slow_query(THD *thd)
(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
(specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES)))
{
- long_query_count++;
+ thd->status_var.long_query_count++;
mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
}
}
}
+int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
+ enum enum_schema_tables schema_table_idx)
+{
+ DBUG_ENTER("prepare_schema_table");
+ SELECT_LEX *sel= 0;
+ switch (schema_table_idx) {
+ case SCH_SCHEMATA:
+#if defined(DONT_ALLOW_SHOW_COMMANDS)
+ my_message(ER_NOT_ALLOWED_COMMAND,
+ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(1);
+#else
+ if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
+ check_global_access(thd, SHOW_DB_ACL))
+ DBUG_RETURN(1);
+ break;
+#endif
+ case SCH_TABLE_NAMES:
+ case SCH_TABLES:
+ case SCH_VIEWS:
+#ifdef DONT_ALLOW_SHOW_COMMANDS
+ my_message(ER_NOT_ALLOWED_COMMAND,
+ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(1);
+#else
+ {
+ char *db= lex->select_lex.db ? lex->select_lex.db : thd->db;
+ if (!db)
+ {
+ my_message(ER_NO_DB_ERROR,
+ ER(ER_NO_DB_ERROR), MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+ remove_escape(db); // Fix escaped '_'
+ if (check_db_name(db))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), db);
+ DBUG_RETURN(1);
+ }
+ if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
+ DBUG_RETURN(1); /* purecov: inspected */
+ if (!thd->col_access && check_grant_db(thd,db))
+ {
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ thd->priv_user, thd->priv_host, db);
+ DBUG_RETURN(1);
+ }
+ /*
+ We need to do a copy to make this prepared statement safe if this
+ was thd->db
+ */
+ lex->select_lex.db= thd->strdup(db);
+ break;
+ }
+#endif
+ case SCH_COLUMNS:
+ case SCH_STATISTICS:
+#ifdef DONT_ALLOW_SHOW_COMMANDS
+ my_message(ER_NOT_ALLOWED_COMMAND,
+ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(1);
+#else
+ if (table_ident)
+ {
+ TABLE_LIST **query_tables_last= lex->query_tables_last;
+ sel= new SELECT_LEX();
+ sel->init_query();
+ if(!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
+ (List<String> *) 0, (List<String> *) 0))
+ DBUG_RETURN(1);
+ lex->query_tables_last= query_tables_last;
+ TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
+ char *db= table_list->db;
+ remove_escape(db); // Fix escaped '_'
+ remove_escape(table_list->table_name);
+ if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
+ &table_list->grant.privilege, 0, 0))
+ DBUG_RETURN(1); /* purecov: inspected */
+ if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2,
+ UINT_MAX, 0))
+ DBUG_RETURN(1);
+ break;
+ }
+#endif
+ case SCH_OPEN_TABLES:
+ case SCH_VARIABLES:
+ case SCH_STATUS:
+ case SCH_PROCEDURES:
+ case SCH_CHARSETS:
+ case SCH_COLLATIONS:
+ case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
+ case SCH_USER_PRIVILEGES:
+ case SCH_SCHEMA_PRIVILEGES:
+ case SCH_TABLE_PRIVILEGES:
+ case SCH_COLUMN_PRIVILEGES:
+ case SCH_TABLE_CONSTRAINTS:
+ case SCH_KEY_COLUMN_USAGE:
+ default:
+ break;
+ }
+
+ SELECT_LEX *select_lex= lex->current_select;
+ if (make_schema_select(thd, select_lex, schema_table_idx))
+ {
+ DBUG_RETURN(1);
+ }
+ TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
+ table_list->schema_select_lex= sel;
+ table_list->schema_table_reformed= 1;
+ DBUG_RETURN(0);
+}
+
+
/*
Read query from packet and store in thd->query
Used in COM_QUERY and COM_PREPARE
@@ -1878,8 +2182,8 @@ static void log_slow_query(THD *thd)
query_length
RETURN VALUES
- 0 ok
- 1 error; In this case thd->fatal_error is set
+ FALSE ok
+ TRUE error; In this case thd->fatal_error is set
*/
bool alloc_query(THD *thd, char *packet, ulong packet_length)
@@ -1904,7 +2208,7 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length)
packet_length,
thd->db_length+ 1 +
QUERY_CACHE_FLAGS_SIZE)))
- return 1;
+ return TRUE;
thd->query[packet_length]=0;
thd->query_length= packet_length;
@@ -1914,7 +2218,7 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length)
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
- return 0;
+ return FALSE;
}
/****************************************************************************
@@ -1922,26 +2226,56 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length)
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/
-void
+bool
mysql_execute_command(THD *thd)
{
- int res= 0;
+ bool res= FALSE;
+ int result= 0;
LEX *lex= thd->lex;
+ /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
+ SELECT_LEX *select_lex= &lex->select_lex;
bool slave_fake_lock= 0;
MYSQL_LOCK *fake_prev_lock= 0;
- SELECT_LEX *select_lex= &lex->select_lex;
- TABLE_LIST *tables= (TABLE_LIST*) select_lex->table_list.first;
+ /* first table of first SELECT_LEX */
+ TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
+ /* list of all tables in query */
+ TABLE_LIST *all_tables;
+ /* most outer SELECT_LEX_UNIT of query */
SELECT_LEX_UNIT *unit= &lex->unit;
+ /* Saved variable value */
DBUG_ENTER("mysql_execute_command");
+ thd->net.no_send_error= 0;
+
+ /*
+ In many cases first table of main SELECT_LEX have special meaning =>
+ check that it is first table in global list and relink it first in
+ queries_tables list if it is necessary (we need such relinking only
+ for queries with subqueries in select list, in this case tables of
+ subqueries will go to global list first)
+
+ all_tables will differ from first_table only if most upper SELECT_LEX
+ do not contain tables.
+
+ Because of above in place where should be at least one table in most
+ outer SELECT_LEX we have following check:
+ DBUG_ASSERT(first_table == all_tables);
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ */
+ lex->first_lists_tables_same();
+ /* should be assigned after making first tables same */
+ all_tables= lex->query_tables;
/*
Reset warning count for each query that uses tables
A better approach would be to reset this for any commands
that is not a SHOW command or a select that only access local
variables, but for now this is probably good enough.
+ Don't reset warnings when executing a stored routine.
*/
- if (tables || &lex->select_lex != lex->all_selects_list)
- mysql_reset_errors(thd);
+ if ((all_tables || &lex->select_lex != lex->all_selects_list ||
+ lex->spfuns.records || lex->spprocs.records) &&
+ !thd->spcont)
+ mysql_reset_errors(thd, 0);
#ifdef HAVE_REPLICATION
if (thd->slave_thread)
@@ -1950,8 +2284,7 @@ mysql_execute_command(THD *thd)
{
DBUG_PRINT("info",("need faked locked tables"));
- if (check_multi_update_lock(thd, tables, &select_lex->item_list,
- select_lex))
+ if (check_multi_update_lock(thd))
goto error;
/* Fix for replication, the tables are opened and locked,
@@ -1972,11 +2305,11 @@ mysql_execute_command(THD *thd)
*/
if (!(lex->sql_command == SQLCOM_DROP_TABLE &&
lex->drop_temporary && lex->drop_if_exists) &&
- all_tables_not_ok(thd,tables))
+ all_tables_not_ok(thd, all_tables))
{
/* we warn the slave SQL thread */
- my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
- DBUG_VOID_RETURN;
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
+ DBUG_RETURN(0);
}
#ifndef TO_BE_DELETED
/*
@@ -1993,13 +2326,9 @@ mysql_execute_command(THD *thd)
}
#endif /* !HAVE_REPLICATION */
- /* When subselects or time_zone info is used in a query
- * we create a new TABLE_LIST containing all referenced tables
- * and set local variable 'tables' to point to this list. */
- if ((&lex->select_lex != lex->all_selects_list ||
- lex->time_zone_tables_used) &&
- lex->unit.create_total_list(thd, lex, &tables))
- DBUG_VOID_RETURN;
+
+
+
/*
When option readonly is set deny operations which change tables.
@@ -2007,13 +2336,14 @@ mysql_execute_command(THD *thd)
*/
if (opt_readonly &&
!(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
- (uc_update_queries[lex->sql_command] > 0))
+ uc_update_queries[lex->sql_command])
{
- net_printf(thd, ER_OPTION_PREVENTS_STATEMENT, "--read-only");
- DBUG_VOID_RETURN;
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
+ DBUG_RETURN(-1);
}
- statistic_increment(com_stat[lex->sql_command],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[lex->sql_command],
+ &LOCK_status);
switch (lex->sql_command) {
case SQLCOM_SELECT:
{
@@ -2025,43 +2355,26 @@ mysql_execute_command(THD *thd)
}
select_result *result=lex->result;
- if (tables)
+ if (all_tables)
{
- res=check_table_access(thd,
- lex->exchange ? SELECT_ACL | FILE_ACL :
- SELECT_ACL,
- tables,0);
+ res= check_table_access(thd,
+ lex->exchange ? SELECT_ACL | FILE_ACL :
+ SELECT_ACL,
+ all_tables, 0);
}
else
- res=check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
- any_db,0,0,0);
+ res= check_access(thd,
+ lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
+ any_db, 0, 0, 0);
if (res)
- {
- res=0;
- break; // Error message is given
- }
- /*
- In case of single SELECT unit->global_parameters points on first SELECT
- TODO: move counters to SELECT_LEX
- */
- unit->offset_limit_cnt= (ha_rows) unit->global_parameters->offset_limit;
- unit->select_limit_cnt= (ha_rows) (unit->global_parameters->select_limit+
- unit->global_parameters->offset_limit);
- if (unit->select_limit_cnt <
- (ha_rows) unit->global_parameters->select_limit)
- unit->select_limit_cnt= HA_POS_ERROR; // no limit
- if (unit->select_limit_cnt == HA_POS_ERROR && !select_lex->next_select())
- select_lex->options&= ~OPTION_FOUND_ROWS;
+ goto error;
- if (!(res=open_and_lock_tables(thd,tables)))
+ if (!(res= open_and_lock_tables(thd, all_tables)))
{
if (lex->describe)
{
if (!(result= new select_send()))
- {
- send_error(thd, ER_OUT_OF_RESOURCES);
- DBUG_VOID_RETURN;
- }
+ goto error;
else
thd->send_explain_fields(result);
res= mysql_explain_union(thd, &thd->lex->unit, result);
@@ -2081,12 +2394,9 @@ mysql_execute_command(THD *thd)
else
{
if (!result && !(result= new select_send()))
- {
- res= -1;
- break;
- }
- query_cache_store_query(thd, tables);
- res= handle_select(thd, lex, result);
+ goto error;
+ query_cache_store_query(thd, all_tables);
+ res= handle_select(thd, lex, result, 0);
if (result != lex->result)
delete result;
}
@@ -2125,10 +2435,7 @@ mysql_execute_command(THD *thd)
*/
DBUG_ASSERT(!is_var_null);
if (!pstr)
- {
- res= -1;
- break; // EOM (error should be reported by allocator)
- }
+ goto error;
}
else
{
@@ -2146,11 +2453,8 @@ mysql_execute_command(THD *thd)
query_len= need_conversion? (pstr->length() * to_cs->mbmaxlen) :
pstr->length();
if (!(query_str= alloc_root(thd->mem_root, query_len+1)))
- {
- res= -1;
- break; // EOM (error should be reported by allocator)
- }
-
+ goto error;
+
if (need_conversion)
{
uint dummy_errors;
@@ -2172,8 +2476,8 @@ mysql_execute_command(THD *thd)
query_len, query_str));
}
thd->command= COM_PREPARE;
- if (!mysql_stmt_prepare(thd, query_str, query_len + 1,
- &lex->prepared_stmt_name))
+ if (!(res= mysql_stmt_prepare(thd, query_str, query_len + 1,
+ &lex->prepared_stmt_name)))
send_ok(thd, 0L, 0L, "Statement prepared");
break;
}
@@ -2199,21 +2503,20 @@ mysql_execute_command(THD *thd)
}
else
{
- res= -1;
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0),
- lex->prepared_stmt_name.length, lex->prepared_stmt_name.str,
+ lex->prepared_stmt_name.length,
+ lex->prepared_stmt_name.str,
"DEALLOCATE PREPARE");
+ goto error;
}
break;
}
case SQLCOM_DO:
- if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
- (res= open_and_lock_tables(thd,tables))))
- break;
+ if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
+ open_and_lock_tables(thd, all_tables))
+ goto error;
res= mysql_do(thd, *lex->insert_list);
- if (thd->net.report_error)
- res= -1;
break;
case SQLCOM_EMPTY_QUERY:
@@ -2229,16 +2532,31 @@ mysql_execute_command(THD *thd)
{
if (check_global_access(thd, SUPER_ACL))
goto error;
- // PURGE MASTER LOGS TO 'file'
+ /* PURGE MASTER LOGS TO 'file' */
res = purge_master_logs(thd, lex->to_log);
break;
}
case SQLCOM_PURGE_BEFORE:
{
+ Item *it;
+
if (check_global_access(thd, SUPER_ACL))
goto error;
- // PURGE MASTER LOGS BEFORE 'data'
- res = purge_master_logs_before_date(thd, lex->purge_time);
+ /* PURGE MASTER LOGS BEFORE 'data' */
+ it= (Item *)lex->value_list.head();
+ if ((!it->fixed &&it->fix_fields(lex->thd, 0, &it)) ||
+ it->check_cols(1))
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE");
+ goto error;
+ }
+ it= new Item_func_unix_timestamp(it);
+ /*
+ it is OK only emulate fix_fieds, because we need only
+ value of constant
+ */
+ it->quick_fix_field();
+ res = purge_master_logs_before_date(thd, (ulong)it->val_int());
break;
}
#endif
@@ -2263,12 +2581,12 @@ mysql_execute_command(THD *thd)
goto error;
/* This query don't work now. See comment in repl_failsafe.cc */
#ifndef WORKING_NEW_MASTER
- net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
- res= 1;
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
+ goto error;
#else
res = show_new_master(thd);
-#endif
break;
+#endif
}
#ifdef HAVE_REPLICATION
@@ -2283,48 +2601,52 @@ mysql_execute_command(THD *thd)
{
if (check_global_access(thd, REPL_SLAVE_ACL))
goto error;
- res = show_binlog_events(thd);
+ res = mysql_show_binlog_events(thd);
break;
}
#endif
case SQLCOM_BACKUP_TABLE:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL, tables,0) ||
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL, all_tables, 0) ||
check_global_access(thd, FILE_ACL))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
- res = mysql_backup_table(thd, tables);
+ res = mysql_backup_table(thd, first_table);
break;
}
case SQLCOM_RESTORE_TABLE:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd, INSERT_ACL, tables,0) ||
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, INSERT_ACL, all_tables, 0) ||
check_global_access(thd, FILE_ACL))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
- res = mysql_restore_table(thd, tables);
+ res = mysql_restore_table(thd, first_table);
break;
}
case SQLCOM_ASSIGN_TO_KEYCACHE:
{
- if (check_db_used(thd, tables) ||
- check_access(thd, INDEX_ACL, tables->db,
- &tables->grant.privilege, 0, 0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_access(thd, INDEX_ACL, first_table->db,
+ &first_table->grant.privilege, 0, 0))
goto error;
- res= mysql_assign_to_keycache(thd, tables, &lex->name_and_length);
+ res= mysql_assign_to_keycache(thd, first_table, &lex->ident);
break;
}
case SQLCOM_PRELOAD_KEYS:
{
- if (check_db_used(thd, tables) ||
- check_access(thd, INDEX_ACL, tables->db,
- &tables->grant.privilege, 0, 0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_access(thd, INDEX_ACL, first_table->db,
+ &first_table->grant.privilege, 0, 0))
goto error;
- res = mysql_preload_keys(thd, tables);
+ res = mysql_preload_keys(thd, first_table);
break;
}
#ifdef HAVE_REPLICATION
@@ -2360,7 +2682,7 @@ mysql_execute_command(THD *thd)
if (check_global_access(thd, SUPER_ACL))
goto error;
if (end_active_trans(thd))
- res= -1;
+ goto error;
else
res = load_master_data(thd);
break;
@@ -2373,23 +2695,32 @@ mysql_execute_command(THD *thd)
res = innodb_show_status(thd);
break;
}
+ case SQLCOM_SHOW_MUTEX_STATUS:
+ {
+ if (check_global_access(thd, SUPER_ACL))
+ goto error;
+ res = innodb_mutex_show_status(thd);
+ break;
+ }
#endif
#ifdef HAVE_REPLICATION
case SQLCOM_LOAD_MASTER_TABLE:
{
- if (!tables->db)
- tables->db=thd->db;
- if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege,0,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (!first_table->db)
+ first_table->db= thd->db;
+ if (check_access(thd, CREATE_ACL, first_table->db,
+ &first_table->grant.privilege, 0, 0))
goto error; /* purecov: inspected */
if (grant_option)
{
/* Check that the first table has CREATE privilege */
- if (check_grant(thd, CREATE_ACL, tables, 0, 1, 0))
+ if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
goto error;
}
- if (strlen(tables->real_name) > NAME_LEN)
+ if (strlen(first_table->table_name) > NAME_LEN)
{
- net_printf(thd,ER_WRONG_TABLE_NAME, tables->real_name);
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), first_table->table_name);
break;
}
pthread_mutex_lock(&LOCK_active_mi);
@@ -2397,7 +2728,7 @@ mysql_execute_command(THD *thd)
fetch_master_table will send the error to the client on failure.
Give error if the table already exists.
*/
- if (!fetch_master_table(thd, tables->db, tables->real_name,
+ if (!fetch_master_table(thd, first_table->db, first_table->table_name,
active_mi, 0, 0))
{
send_ok(thd);
@@ -2409,12 +2740,13 @@ mysql_execute_command(THD *thd)
case SQLCOM_CREATE_TABLE:
{
- /* Skip first table, which is the table we are creating */
- TABLE_LIST *create_table, *create_table_local;
- tables= lex->unlink_first_table(tables, &create_table,
- &create_table_local);
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ bool link_to_local;
+ // Skip first table, which is the table we are creating
+ TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
+ TABLE_LIST *select_tables= lex->query_tables;
- if ((res= create_table_precheck(thd, tables, create_table)))
+ if ((res= create_table_precheck(thd, select_tables, create_table)))
goto unsent_create_error;
#ifndef HAVE_READLINK
@@ -2422,16 +2754,13 @@ mysql_execute_command(THD *thd)
#else
/* Fix names if symlinked tables */
if (append_file_to_dir(thd, &lex->create_info.data_file_name,
- create_table->real_name) ||
- append_file_to_dir(thd,&lex->create_info.index_file_name,
- create_table->real_name))
- {
- res=-1;
+ create_table->table_name) ||
+ append_file_to_dir(thd, &lex->create_info.index_file_name,
+ create_table->table_name))
goto unsent_create_error;
- }
#endif
/*
- If we are using SET CHARSET without DEFAULT, add an implicite
+ If we are using SET CHARSET without DEFAULT, add an implicit
DEFAULT to not confuse old users. (This may change).
*/
if ((lex->create_info.used_fields &
@@ -2448,72 +2777,91 @@ mysql_execute_command(THD *thd)
select_result *result;
select_lex->options|= SELECT_NO_UNLOCK;
- unit->offset_limit_cnt= select_lex->offset_limit;
- unit->select_limit_cnt= select_lex->select_limit+
- select_lex->offset_limit;
- if (unit->select_limit_cnt < select_lex->select_limit)
- unit->select_limit_cnt= HA_POS_ERROR; // No limit
+ unit->set_limit(select_lex, select_lex);
- if (!(res=open_and_lock_tables(thd,tables)))
+ if (!(res= open_and_lock_tables(thd, select_tables)))
{
- res= -1; // If error
- if ((result=new select_create(create_table->db,
- create_table->real_name,
- &lex->create_info,
- lex->create_list,
- lex->key_list,
- select_lex->item_list, lex->duplicates,
- lex->ignore)))
+ /*
+ Is table which we are changing used somewhere in other parts
+ of query
+ */
+ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
+ unique_table(create_table, select_tables))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), create_table->table_name);
+ goto unsent_create_error;
+ }
+ /* If we create merge table, we have to test tables in merge, too */
+ if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
+ {
+ TABLE_LIST *tab;
+ for (tab= (TABLE_LIST*) lex->create_info.merge_list.first;
+ tab;
+ tab= tab->next_local)
+ {
+ if (unique_table(tab, select_tables))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), tab->table_name);
+ goto unsent_create_error;
+ }
+ }
+ }
+
+ if ((result= new select_create(create_table,
+ &lex->create_info,
+ lex->create_list,
+ lex->key_list,
+ select_lex->item_list,
+ lex->duplicates,
+ lex->ignore)))
{
/*
CREATE from SELECT give its SELECT_LEX for SELECT,
and item_list belong to SELECT
*/
select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
- res=handle_select(thd, lex, result);
+ res= handle_select(thd, lex, result, 0);
select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE;
+ delete result;
}
- //reset for PS
+ /* reset for PS */
lex->create_list.empty();
lex->key_list.empty();
}
}
- else // regular create
+ else
{
+ /* regular create */
if (lex->name)
res= mysql_create_like_table(thd, create_table, &lex->create_info,
(Table_ident *)lex->name);
else
{
- res= mysql_create_table(thd,create_table->db,
- create_table->real_name, &lex->create_info,
- lex->create_list,
- lex->key_list,0,0);
+ res= mysql_create_table(thd, create_table->db,
+ create_table->table_name, &lex->create_info,
+ lex->create_list,
+ lex->key_list, 0, 0);
}
if (!res)
send_ok(thd);
}
-
- // put tables back for PS rexecuting
- tables= lex->link_first_table_back(tables, create_table,
- create_table_local);
+ lex->link_first_table_back(create_table, link_to_local);
break;
- res= 1; //error reported
+ /* put tables back for PS rexecuting */
unsent_create_error:
- // put tables back for PS rexecuting
- tables= lex->link_first_table_back(tables, create_table,
- create_table_local);
- break;
+ lex->link_first_table_back(create_table, link_to_local);
+ goto error;
}
case SQLCOM_CREATE_INDEX:
- if (check_one_table_access(thd, INDEX_ACL, tables))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
if (end_active_trans(thd))
- res= -1;
+ goto error;
else
- res = mysql_create_index(thd, tables, lex->key_list);
+ res = mysql_create_index(thd, first_table, lex->key_list);
break;
#ifdef HAVE_REPLICATION
@@ -2540,8 +2888,9 @@ unsent_create_error:
*/
if (thd->locked_tables || thd->active_transaction())
{
- send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
- break;
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION),
+ MYF(0));
+ goto error;
}
{
pthread_mutex_lock(&LOCK_active_mi);
@@ -2552,35 +2901,37 @@ unsent_create_error:
#endif /* HAVE_REPLICATION */
case SQLCOM_ALTER_TABLE:
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
#if defined(DONT_ALLOW_SHOW_COMMANDS)
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- break;
+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
+ MYF(0)); /* purecov: inspected */
+ goto error;
#else
{
ulong priv=0;
if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
{
- net_printf(thd, ER_WRONG_TABLE_NAME, lex->name);
- res= 1;
- break;
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name);
+ goto error;
}
if (!select_lex->db)
- select_lex->db=tables->db;
- if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege,0,0) ||
+ select_lex->db= first_table->db;
+ if (check_access(thd, ALTER_ACL, first_table->db,
+ &first_table->grant.privilege, 0, 0) ||
check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0)||
- check_merge_table_access(thd, tables->db,
+ check_merge_table_access(thd, first_table->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
goto error; /* purecov: inspected */
if (grant_option)
{
- if (check_grant(thd, ALTER_ACL, tables, 0, UINT_MAX, 0))
+ if (check_grant(thd, ALTER_ACL, all_tables, 0, UINT_MAX, 0))
goto error;
if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
{ // Rename of table
TABLE_LIST tmp_table;
bzero((char*) &tmp_table,sizeof(tmp_table));
- tmp_table.real_name=lex->name;
+ tmp_table.table_name=lex->name;
tmp_table.db=select_lex->db;
tmp_table.grant.privilege=priv;
if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
@@ -2592,63 +2943,62 @@ unsent_create_error:
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
/* ALTER TABLE ends previous transaction */
if (end_active_trans(thd))
- res= -1;
+ goto error;
else
{
thd->slow_command=TRUE;
res= mysql_alter_table(thd, select_lex->db, lex->name,
&lex->create_info,
- tables, lex->create_list,
+ first_table, lex->create_list,
lex->key_list,
select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
- lex->duplicates, lex->ignore, &lex->alter_info);
+ lex->duplicates, lex->ignore, &lex->alter_info,
+ 1);
}
break;
}
#endif /*DONT_ALLOW_SHOW_COMMANDS*/
case SQLCOM_RENAME_TABLE:
{
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *table;
- if (check_db_used(thd,tables))
+ if (check_db_used(thd, all_tables))
goto error;
- for (table=tables ; table ; table=table->next->next)
+ for (table= first_table; table; table= table->next_local->next_local)
{
if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
&table->grant.privilege,0,0) ||
- check_access(thd, INSERT_ACL | CREATE_ACL, table->next->db,
- &table->next->grant.privilege,0,0))
+ check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
+ &table->next_local->grant.privilege, 0, 0))
goto error;
if (grant_option)
{
- TABLE_LIST old_list,new_list;
+ TABLE_LIST old_list, new_list;
/*
we do not need initialize old_list and new_list because we will
come table[0] and table->next[0] there
*/
- old_list=table[0];
- new_list=table->next[0];
- old_list.next=new_list.next=0;
- if (check_grant(thd, ALTER_ACL, &old_list, 0, UINT_MAX, 0) ||
- (!test_all_bits(table->next->grant.privilege,
+ old_list= table[0];
+ new_list= table->next_local[0];
+ if (check_grant(thd, ALTER_ACL, &old_list, 0, 1, 0) ||
+ (!test_all_bits(table->next_local->grant.privilege,
INSERT_ACL | CREATE_ACL) &&
- check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0,
- UINT_MAX, 0)))
+ check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
goto error;
}
}
- query_cache_invalidate3(thd, tables, 0);
- if (end_active_trans(thd))
- res= -1;
- else if (mysql_rename_tables(thd,tables))
- res= -1;
+ query_cache_invalidate3(thd, first_table, 0);
+ if (end_active_trans(thd) || mysql_rename_tables(thd, first_table))
+ goto error;
break;
}
#ifndef EMBEDDED_LIBRARY
case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
+ MYF(0)); /* purecov: inspected */
+ goto error;
#else
{
if (check_global_access(thd, SUPER_ACL))
@@ -2659,40 +3009,47 @@ unsent_create_error:
#endif
#endif /* EMBEDDED_LIBRARY */
case SQLCOM_SHOW_CREATE:
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
+ MYF(0)); /* purecov: inspected */
+ goto error;
#else
{
- if (check_db_used(thd, tables) ||
- check_access(thd, SELECT_ACL | EXTRA_ACL, tables->db,
- &tables->grant.privilege,0,0))
+ /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
+ if (lex->only_view)
+ first_table->skip_temporary= 1;
+
+ if (check_db_used(thd, all_tables) ||
+ check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db,
+ &first_table->grant.privilege, 0, 0))
goto error;
- if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
+ if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0))
goto error;
- res= mysqld_show_create(thd, tables);
+ res= mysqld_show_create(thd, first_table);
break;
}
#endif
case SQLCOM_CHECKSUM:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, 0))
goto error; /* purecov: inspected */
- res = mysql_checksum_table(thd, tables, &lex->check_opt);
+ res = mysql_checksum_table(thd, first_table, &lex->check_opt);
break;
}
case SQLCOM_REPAIR:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
- res = mysql_repair_table(thd, tables, &lex->check_opt);
+ res= mysql_repair_table(thd, first_table, &lex->check_opt);
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
@@ -2704,24 +3061,25 @@ unsent_create_error:
}
case SQLCOM_CHECK:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
- res = mysql_check_table(thd, tables, &lex->check_opt);
+ res = mysql_check_table(thd, first_table, &lex->check_opt);
break;
}
case SQLCOM_ANALYZE:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
- res = mysql_analyze_table(thd, tables, &lex->check_opt);
+ res = mysql_analyze_table(thd, first_table, &lex->check_opt);
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
@@ -2734,17 +3092,17 @@ unsent_create_error:
case SQLCOM_OPTIMIZE:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
- mysql_recreate_table(thd, tables, 1) :
- mysql_optimize_table(thd, tables, &lex->check_opt);
+ mysql_recreate_table(thd, first_table, 1) :
+ mysql_optimize_table(thd, first_table, &lex->check_opt);
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
@@ -2755,173 +3113,149 @@ unsent_create_error:
break;
}
case SQLCOM_UPDATE:
- if (update_precheck(thd, tables))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (update_precheck(thd, all_tables))
break;
- res= mysql_update(thd,tables,
- select_lex->item_list,
- lex->value_list,
- select_lex->where,
- select_lex->order_list.elements,
- (ORDER *) select_lex->order_list.first,
- select_lex->select_limit,
- lex->duplicates, lex->ignore);
- if (thd->net.report_error)
- res= -1;
- break;
- case SQLCOM_UPDATE_MULTI:
- {
- if ((res= multi_update_precheck(thd, tables)))
+ res= (result= mysql_update(thd, all_tables,
+ select_lex->item_list,
+ lex->value_list,
+ select_lex->where,
+ select_lex->order_list.elements,
+ (ORDER *) select_lex->order_list.first,
+ select_lex->select_limit,
+ lex->duplicates, lex->ignore));
+ /* mysql_update return 2 if we need to switch to multi-update */
+ if (result != 2)
break;
- res= mysql_multi_update(thd,tables,
- &select_lex->item_list,
- &lex->value_list,
- select_lex->where,
- select_lex->options,
- lex->duplicates, lex->ignore, unit, select_lex);
+ case SQLCOM_UPDATE_MULTI:
+ {
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ /* if we switched from normal update, rights are checked */
+ if (result != 2)
+ {
+ if ((res= multi_update_precheck(thd, all_tables)))
+ break;
+ }
+ else
+ res= 0;
+
+ res= mysql_multi_update(thd, all_tables,
+ &select_lex->item_list,
+ &lex->value_list,
+ select_lex->where,
+ select_lex->options,
+ lex->duplicates, lex->ignore, unit, select_lex);
break;
}
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
{
- if ((res= insert_precheck(thd, tables)))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if ((res= insert_precheck(thd, all_tables)))
break;
- res= mysql_insert(thd,tables,lex->field_list,lex->many_values,
- lex->update_list, lex->value_list,
+ res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
+ lex->update_list, lex->value_list,
lex->duplicates, lex->ignore);
- if (thd->net.report_error)
- res= -1;
+ if (first_table->view && !first_table->contain_auto_increment)
+ thd->last_insert_id= 0; // do not show last insert ID if VIEW have not it
break;
}
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
- TABLE_LIST *first_local_table= (TABLE_LIST *) select_lex->table_list.first;
- if ((res= insert_precheck(thd, tables)))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if ((res= insert_precheck(thd, all_tables)))
break;
/* Fix lock for first table */
- if (tables->lock_type == TL_WRITE_DELAYED)
- tables->lock_type= TL_WRITE;
+ if (first_table->lock_type == TL_WRITE_DELAYED)
+ first_table->lock_type= TL_WRITE;
/* Don't unlock tables until command is written to binary log */
select_lex->options|= SELECT_NO_UNLOCK;
select_result *result;
- unit->offset_limit_cnt= select_lex->offset_limit;
- unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit;
- if (unit->select_limit_cnt < select_lex->select_limit)
- unit->select_limit_cnt= HA_POS_ERROR; // No limit
+ unit->set_limit(select_lex, select_lex);
- if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
+ if (!(res= open_and_lock_tables(thd, all_tables)))
{
- /* Using same table for INSERT and SELECT */
- select_lex->options |= OPTION_BUFFER_RESULT;
- }
+ /* Skip first table, which is the table we are inserting in */
+ select_lex->table_list.first= (byte*)first_table->next_local;
- if ((res= open_and_lock_tables(thd, tables)))
- break;
-
- TABLE *table= tables->table;
- /* Skip first table, which is the table we are inserting in */
- select_lex->table_list.first= (byte*) first_local_table->next;
- tables= (TABLE_LIST *) select_lex->table_list.first;
- first_local_table->next= 0;
-
- if (!(res= mysql_prepare_insert(thd, tables, first_local_table,
- table, lex->field_list, 0,
- lex->update_list, lex->value_list,
- lex->duplicates)) &&
- (result= new select_insert(table, &lex->field_list,
- &lex->update_list, &lex->value_list,
- lex->duplicates, lex->ignore)))
- {
- /*
- insert/replace from SELECT give its SELECT_LEX for SELECT,
- and item_list belong to SELECT
- */
- lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
- res= handle_select(thd, lex, result);
+ res= mysql_insert_select_prepare(thd);
+ if (!res && (result= new select_insert(first_table, first_table->table,
+ &lex->field_list,
+ &lex->update_list, &lex->value_list,
+ lex->duplicates, lex->ignore)))
+ {
+ /*
+ insert/replace from SELECT give its SELECT_LEX for SELECT,
+ and item_list belong to SELECT
+ */
+ select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
+ res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
+ select_lex->resolve_mode= SELECT_LEX::INSERT_MODE;
+ delete result;
+ }
/* revert changes for SP */
- lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
- delete result;
- table->insert_values= 0;
- if (thd->net.report_error)
- res= -1;
+ select_lex->table_list.first= (byte*) first_table;
}
- else
- res= -1;
- first_local_table->next= tables;
- lex->select_lex.table_list.first= (byte*) first_local_table;
+
+ if (first_table->view && !first_table->contain_auto_increment)
+ thd->last_insert_id= 0; // do not show last insert ID if VIEW have not it
+
break;
}
case SQLCOM_TRUNCATE:
- if (check_one_table_access(thd, DELETE_ACL, tables))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_one_table_access(thd, DELETE_ACL, all_tables))
goto error;
/*
Don't allow this within a transaction because we want to use
re-generate table
*/
- if (thd->locked_tables || thd->active_transaction())
+ if ((thd->locked_tables && !lex->sphead) || thd->active_transaction())
{
- send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- res=mysql_truncate(thd, tables, 0);
+
+ res= mysql_truncate(thd, first_table, 0);
break;
case SQLCOM_DELETE:
{
- if ((res= delete_precheck(thd, tables)))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if ((res= delete_precheck(thd, all_tables)))
break;
- res = mysql_delete(thd,tables, select_lex->where,
+ res = mysql_delete(thd, all_tables, select_lex->where,
&select_lex->order_list,
select_lex->select_limit, select_lex->options);
- if (thd->net.report_error)
- res= -1;
break;
}
case SQLCOM_DELETE_MULTI:
{
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
- TABLE_LIST *target_tbl;
uint table_count;
multi_delete *result;
- if ((res= multi_delete_precheck(thd, tables, &table_count)))
+ if ((res= multi_delete_precheck(thd, all_tables, &table_count)))
break;
/* condition will be TRUE on SP re-excuting */
if (select_lex->item_list.elements != 0)
select_lex->item_list.empty();
if (add_item_to_list(thd, new Item_null()))
- {
- res= -1;
- break;
- }
+ goto error;
thd->proc_info="init";
- if ((res=open_and_lock_tables(thd,tables)))
+ if ((res= open_and_lock_tables(thd, all_tables)))
break;
- /* Fix tables-to-be-deleted-from list to point at opened tables */
- for (target_tbl= (TABLE_LIST*) aux_tables;
- target_tbl;
- target_tbl= target_tbl->next)
- {
- TABLE_LIST *orig= target_tbl->table_list;
- target_tbl->table= orig->table;
- /*
- Multi-delete can't be constructed over-union => we always have
- single SELECT on top and have to check underlying SELECTs of it
- */
- if (lex->select_lex.check_updateable_in_subqueries(orig->db,
- orig->real_name))
- {
- my_error(ER_UPDATE_TABLE_USED, MYF(0),
- orig->real_name);
- res= -1;
- break;
- }
- }
+
+ if ((res= mysql_multi_delete_prepare(thd)))
+ goto error;
if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
table_count)))
@@ -2934,28 +3268,24 @@ unsent_create_error:
0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
(ORDER *)NULL,
select_lex->options | thd->options |
- SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
+ SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
+ OPTION_SETUP_TABLES_DONE,
result, unit, select_lex);
- if (thd->net.report_error)
- res= -1;
delete result;
}
else
- res= -1; // Error is not sent
- close_thread_tables(thd);
+ res= TRUE; // Error
break;
}
case SQLCOM_DROP_TABLE:
{
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (!lex->drop_temporary)
{
- if (check_table_access(thd,DROP_ACL,tables,0))
+ if (check_table_access(thd, DROP_ACL, all_tables, 0))
goto error; /* purecov: inspected */
if (end_active_trans(thd))
- {
- res= -1;
- break;
- }
+ goto error;
}
else
{
@@ -2970,28 +3300,19 @@ unsent_create_error:
if (thd->slave_thread)
lex->drop_if_exists= 1;
}
- res= mysql_rm_table(thd,tables,lex->drop_if_exists, lex->drop_temporary);
+ res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
+ lex->drop_temporary);
}
break;
case SQLCOM_DROP_INDEX:
- if (check_one_table_access(thd, INDEX_ACL, tables))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
if (end_active_trans(thd))
- res= -1;
- else
- res = mysql_drop_index(thd, tables, &lex->alter_info);
- break;
- case SQLCOM_SHOW_DATABASES:
-#if defined(DONT_ALLOW_SHOW_COMMANDS)
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
-#else
- if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
- check_global_access(thd, SHOW_DB_ACL))
goto error;
- res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
+ else
+ res = mysql_drop_index(thd, first_table, &lex->alter_info);
break;
-#endif
case SQLCOM_SHOW_PROCESSLIST:
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
break;
@@ -3008,19 +3329,11 @@ unsent_create_error:
case SQLCOM_SHOW_COLUMN_TYPES:
res= mysqld_show_column_types(thd);
break;
- case SQLCOM_SHOW_STATUS:
- res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
- OPT_GLOBAL, &LOCK_status);
- break;
- case SQLCOM_SHOW_VARIABLES:
- res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
- init_vars, lex->option_type,
- &LOCK_global_system_variables);
- break;
case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
+ MYF(0)); /* purecov: inspected */
+ goto error;
#else
{
if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0))
@@ -3029,134 +3342,46 @@ unsent_create_error:
break;
}
#endif
- case SQLCOM_SHOW_TABLES:
- /* FALL THROUGH */
-#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
-#else
- {
- char *db=select_lex->db ? select_lex->db : thd->db;
- if (!db)
- {
- send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
- goto error; /* purecov: inspected */
- }
- remove_escape(db); // Fix escaped '_'
- if (check_db_name(db))
- {
- net_printf(thd,ER_WRONG_DB_NAME, db);
- goto error;
- }
- if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
- goto error; /* purecov: inspected */
- if (!thd->col_access && check_grant_db(thd,db))
- {
- net_printf(thd, ER_DBACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->priv_host,
- db);
- goto error;
- }
- /* grant is checked in mysqld_show_tables */
- if (lex->describe)
- res= mysqld_extend_show_tables(thd,db,
- (lex->wild ? lex->wild->ptr() : NullS));
- else
- res= mysqld_show_tables(thd,db,
- (lex->wild ? lex->wild->ptr() : NullS));
- break;
- }
-#endif
- case SQLCOM_SHOW_OPEN_TABLES:
- res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
- break;
- case SQLCOM_SHOW_CHARSETS:
- res= mysqld_show_charsets(thd,(lex->wild ? lex->wild->ptr() : NullS));
- break;
- case SQLCOM_SHOW_COLLATIONS:
- res= mysqld_show_collations(thd,(lex->wild ? lex->wild->ptr() : NullS));
- break;
- case SQLCOM_SHOW_FIELDS:
-#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
-#else
- {
- char *db=tables->db;
- remove_escape(db); // Fix escaped '_'
- remove_escape(tables->real_name);
- if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
- &tables->grant.privilege, 0, 0))
- goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
- goto error;
- res= mysqld_show_fields(thd,tables,
- (lex->wild ? lex->wild->ptr() : NullS),
- lex->verbose);
- break;
- }
-#endif
- case SQLCOM_SHOW_KEYS:
-#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
-#else
- {
- char *db=tables->db;
- remove_escape(db); // Fix escaped '_'
- remove_escape(tables->real_name);
- if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
- &tables->grant.privilege, 0, 0))
- goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
- goto error;
- res= mysqld_show_keys(thd,tables);
- break;
- }
-#endif
case SQLCOM_CHANGE_DB:
mysql_change_db(thd,select_lex->db);
break;
case SQLCOM_LOAD:
{
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
uint privilege= (lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | DELETE_ACL : INSERT_ACL);
+ INSERT_ACL | DELETE_ACL : INSERT_ACL) |
+ (lex->local_file ? 0 : FILE_ACL);
- if (!lex->local_file)
- {
- if (check_access(thd,privilege | FILE_ACL,tables->db,0,0,0))
- goto error;
- }
- else
+ if (lex->local_file)
{
if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
! opt_local_infile)
{
- send_error(thd,ER_NOT_ALLOWED_COMMAND);
+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0));
goto error;
}
- if (check_one_table_access(thd, privilege, tables))
- goto error;
}
- res=mysql_load(thd, lex->exchange, tables, lex->field_list,
- lex->duplicates, lex->ignore, (bool) lex->local_file, lex->lock_option);
+
+ if (check_one_table_access(thd, privilege, all_tables))
+ goto error;
+
+ res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
+ lex->update_list, lex->value_list, lex->duplicates,
+ lex->ignore, (bool) lex->local_file);
break;
}
case SQLCOM_SET_OPTION:
{
List<set_var_base> *lex_var_list= &lex->var_list;
- if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
- (res= open_and_lock_tables(thd,tables))))
- break;
+ if ((check_table_access(thd, SELECT_ACL, all_tables, 0) ||
+ open_and_lock_tables(thd, all_tables)))
+ goto error;
if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
{
- my_printf_error(0, "The SET ONE_SHOT syntax is reserved for \
-purposes internal to the MySQL server", MYF(0));
- res= -1;
- break;
+ my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
+ goto error;
}
if (!(res= sql_set_variables(thd, lex_var_list)))
{
@@ -3167,8 +3392,6 @@ purposes internal to the MySQL server", MYF(0));
thd->one_shot_set|= lex->one_shot_set;
send_ok(thd);
}
- if (thd->net.report_error)
- res= -1;
break;
}
@@ -3191,17 +3414,18 @@ purposes internal to the MySQL server", MYF(0));
break;
case SQLCOM_LOCK_TABLES:
unlock_locked_tables(thd);
- if (check_db_used(thd,tables) || end_active_trans(thd))
+ if (check_db_used(thd, all_tables) || end_active_trans(thd))
goto error;
- if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables,0))
+ if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
goto error;
thd->in_lock_tables=1;
thd->options|= OPTION_TABLE_LOCK;
- if (!(res= open_and_lock_tables(thd, tables)))
+
+ if (!(res= simple_open_n_lock_tables(thd, all_tables)))
{
#ifdef HAVE_QUERY_CACHE
if (thd->variables.query_cache_wlock_invalidate)
- query_cache.invalidate_locked_for_write(tables);
+ query_cache.invalidate_locked_for_write(first_table);
#endif /*HAVE_QUERY_CACHE*/
thd->locked_tables=thd->lock;
thd->lock=0;
@@ -3216,22 +3440,22 @@ purposes internal to the MySQL server", MYF(0));
char *alias;
if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
{
- net_printf(thd,ER_WRONG_DB_NAME, lex->name);
+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
break;
}
/*
If in a slave thread :
CREATE DATABASE DB was certainly not preceded by USE DB.
- For that reason, db_ok() in sql/slave.cc did not check the
+ For that reason, db_ok() in sql/slave.cc did not check the
do_db/ignore_db. And as this query involves no tables, tables_ok()
above was not called. So we have to check rules again here.
*/
#ifdef HAVE_REPLICATION
- if (thd->slave_thread &&
+ if (thd->slave_thread &&
(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
!db_ok_with_wild_table(lex->name)))
{
- my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
break;
}
#endif
@@ -3243,10 +3467,9 @@ purposes internal to the MySQL server", MYF(0));
}
case SQLCOM_DROP_DB:
{
- char *alias;
- if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
+ if (check_db_name(lex->name))
{
- net_printf(thd, ER_WRONG_DB_NAME, lex->name);
+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
break;
}
/*
@@ -3261,7 +3484,7 @@ purposes internal to the MySQL server", MYF(0));
(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
!db_ok_with_wild_table(lex->name)))
{
- my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
break;
}
#endif
@@ -3269,11 +3492,11 @@ purposes internal to the MySQL server", MYF(0));
break;
if (thd->locked_tables || thd->active_transaction())
{
- send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- res=mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : lex->name),
- lex->drop_if_exists, 0);
+ res= mysql_rm_db(thd, lex->name, lex->drop_if_exists, 0);
break;
}
case SQLCOM_ALTER_DB:
@@ -3281,12 +3504,12 @@ purposes internal to the MySQL server", MYF(0));
char *db= lex->name ? lex->name : thd->db;
if (!db)
{
- send_error(thd, ER_NO_DB_ERROR);
- goto error;
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ break;
}
if (!strip_sp(db) || check_db_name(db))
{
- net_printf(thd, ER_WRONG_DB_NAME, db);
+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
break;
}
/*
@@ -3301,7 +3524,7 @@ purposes internal to the MySQL server", MYF(0));
(!db_ok(db, replicate_do_db, replicate_ignore_db) ||
!db_ok_with_wild_table(db)))
{
- my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
break;
}
#endif
@@ -3309,7 +3532,8 @@ purposes internal to the MySQL server", MYF(0));
break;
if (thd->locked_tables || thd->active_transaction())
{
- send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
res= mysql_alter_db(thd, db, &lex->create_info);
@@ -3319,7 +3543,7 @@ purposes internal to the MySQL server", MYF(0));
{
if (!strip_sp(lex->name) || check_db_name(lex->name))
{
- net_printf(thd,ER_WRONG_DB_NAME, lex->name);
+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
break;
}
if (check_access(thd,SELECT_ACL,lex->name,0,1,0))
@@ -3327,38 +3551,67 @@ purposes internal to the MySQL server", MYF(0));
res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
break;
}
- case SQLCOM_CREATE_FUNCTION:
+ case SQLCOM_CREATE_FUNCTION: // UDF function
+ {
if (check_access(thd,INSERT_ACL,"mysql",0,1,0))
break;
#ifdef HAVE_DLOPEN
- if (!(res = mysql_create_function(thd,&lex->udf)))
+ if (sp_find_function(thd, lex->spname))
+ {
+ my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str);
+ goto error;
+ }
+ if (!(res = mysql_create_function(thd, &lex->udf)))
send_ok(thd);
#else
- res= -1;
+ res= TRUE;
#endif
break;
- case SQLCOM_DROP_FUNCTION:
- if (check_access(thd,DELETE_ACL,"mysql",0,1,0))
+ }
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ case SQLCOM_CREATE_USER:
+ {
+ if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1) &&
+ check_global_access(thd,CREATE_USER_ACL))
break;
-#ifdef HAVE_DLOPEN
- if (!(res = mysql_drop_function(thd,&lex->udf.name)))
+ if (!(res= mysql_create_user(thd, lex->users_list)))
+ {
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
send_ok(thd);
-#else
- res= -1;
-#endif
+ }
break;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ }
case SQLCOM_DROP_USER:
{
- if (check_access(thd, GRANT_ACL,"mysql",0,1,0))
+ if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1) &&
+ check_global_access(thd,CREATE_USER_ACL))
break;
if (!(res= mysql_drop_user(thd, lex->users_list)))
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
+ send_ok(thd);
+ }
+ break;
+ }
+ case SQLCOM_RENAME_USER:
+ {
+ if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1) &&
+ check_global_access(thd,CREATE_USER_ACL))
+ break;
+ if (!(res= mysql_rename_user(thd, lex->users_list)))
+ {
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
}
send_ok(thd);
}
@@ -3366,11 +3619,11 @@ purposes internal to the MySQL server", MYF(0));
}
case SQLCOM_REVOKE_ALL:
{
- if (check_access(thd, GRANT_ACL ,"mysql",0,1,0))
+ if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1) &&
+ check_global_access(thd,CREATE_USER_ACL))
break;
if (!(res = mysql_revoke_all(thd, lex->users_list)))
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
@@ -3384,95 +3637,102 @@ purposes internal to the MySQL server", MYF(0));
case SQLCOM_GRANT:
{
if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
- tables ? tables->db : select_lex->db,
- tables ? &tables->grant.privilege : 0,
- tables ? 0 : 1, 0))
+ first_table ? first_table->db : select_lex->db,
+ first_table ? &first_table->grant.privilege : 0,
+ first_table ? 0 : 1, 0))
goto error;
- /*
- Check that the user isn't trying to change a password for another
- user if he doesn't have UPDATE privilege to the MySQL database
- */
-
if (thd->user) // If not replication
{
LEX_USER *user;
+ uint counter;
+
List_iterator <LEX_USER> user_list(lex->users_list);
- while ((user=user_list++))
+ while ((user= user_list++))
{
- if (user->password.str &&
- (strcmp(thd->user,user->user.str) ||
- user->host.str &&
- my_strcasecmp(&my_charset_latin1,
- user->host.str, thd->host_or_ip)))
- {
- if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1))
- {
- send_error(thd, ER_PASSWORD_NOT_ALLOWED);
- goto error;
- }
- break; // We are allowed to do global changes
- }
+ if (specialflag & SPECIAL_NO_RESOLVE &&
+ hostname_requires_resolving(user->host.str))
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_HOSTNAME_WONT_WORK,
+ ER(ER_WARN_HOSTNAME_WONT_WORK),
+ user->host.str);
+ // Are we trying to change a password of another user
+ DBUG_ASSERT(user->host.str != 0);
+ if (strcmp(thd->user, user->user.str) ||
+ my_strcasecmp(system_charset_info,
+ user->host.str, thd->host_or_ip))
+ {
+ // TODO: use check_change_password()
+ if (check_acl_user(user, &counter) && user->password.str &&
+ check_access(thd, UPDATE_ACL,"mysql",0,1,1))
+ {
+ my_message(ER_PASSWORD_NOT_ALLOWED,
+ ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
+ goto error;
+ }
+ }
}
}
- if (specialflag & SPECIAL_NO_RESOLVE)
+ if (first_table)
{
- LEX_USER *user;
- List_iterator <LEX_USER> user_list(lex->users_list);
- while ((user=user_list++))
+ if (lex->type == TYPE_ENUM_PROCEDURE ||
+ lex->type == TYPE_ENUM_FUNCTION)
{
- if (hostname_requires_resolving(user->host.str))
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_HOSTNAME_WONT_WORK,
- ER(ER_WARN_HOSTNAME_WONT_WORK),
- user->host.str);
+ uint grants= lex->all_privileges
+ ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
+ : lex->grant;
+ if (grant_option &&
+ check_grant_routine(thd, grants | GRANT_ACL, all_tables,
+ lex->type == TYPE_ENUM_PROCEDURE, 0))
+ goto error;
+ res= mysql_routine_grant(thd, all_tables,
+ lex->type == TYPE_ENUM_PROCEDURE,
+ lex->users_list, grants,
+ lex->sql_command == SQLCOM_REVOKE, 0);
}
- }
- if (tables)
- {
- if (grant_option && check_grant(thd,
- (lex->grant | lex->grant_tot_col |
- GRANT_ACL),
- tables, 0, UINT_MAX, 0))
- goto error;
- if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
- lex->grant,
- lex->sql_command == SQLCOM_REVOKE)))
+ else
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
- if (mysql_bin_log.is_open())
- {
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ if (grant_option && check_grant(thd,
+ (lex->grant | lex->grant_tot_col |
+ GRANT_ACL),
+ all_tables, 0, UINT_MAX, 0))
+ goto error;
+ res= mysql_table_grant(thd, all_tables, lex->users_list,
+ lex->columns, lex->grant,
+ lex->sql_command == SQLCOM_REVOKE);
+ }
+ if (!res && mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
}
}
else
{
- if (lex->columns.elements)
+ if (lex->columns.elements || lex->type)
{
- send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE);
- res=1;
+ my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
+ MYF(0));
+ goto error;
}
else
res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
lex->sql_command == SQLCOM_REVOKE);
if (!res)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
- if (mqh_used && lex->sql_command == SQLCOM_GRANT)
+ if (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);
+ reset_mqh(user);
}
}
}
@@ -3480,23 +3740,21 @@ purposes internal to the MySQL server", MYF(0));
}
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
case SQLCOM_RESET:
- /*
- RESET commands are never written to the binary log, so we have to
- initialize this variable because RESET shares the same code as FLUSH
+ /*
+ RESET commands are never written to the binary log, so we have to
+ initialize this variable because RESET shares the same code as FLUSH
*/
lex->no_write_to_binlog= 1;
case SQLCOM_FLUSH:
{
- if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
+ if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, all_tables))
goto error;
/*
reload_acl_and_cache() will tell us if we are allowed to write to the
binlog or not.
*/
bool write_to_binlog;
- if (reload_acl_and_cache(thd, lex->type, tables, &write_to_binlog))
- send_error(thd, 0);
- else
+ if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
{
/*
We WANT to write and we CAN write.
@@ -3504,7 +3762,6 @@ purposes internal to the MySQL server", MYF(0));
*/
if (!lex->no_write_to_binlog && write_to_binlog)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
@@ -3516,11 +3773,20 @@ purposes internal to the MySQL server", MYF(0));
break;
}
case SQLCOM_KILL:
- kill_one_thread(thd,lex->thread_id);
+ {
+ Item *it= (Item *)lex->value_list.head();
+
+ if ((!it->fixed && it->fix_fields(lex->thd, 0, &it)) || it->check_cols(1))
+ {
+ my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
+ MYF(0));
+ goto error;
+ }
+ kill_one_thread(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
break;
+ }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
case SQLCOM_SHOW_GRANTS:
- res=0;
if ((thd->priv_user &&
!strcmp(thd->priv_user,lex->grant_user->user.str)) ||
!check_access(thd, SELECT_ACL, "mysql",0,1,0))
@@ -3530,111 +3796,780 @@ purposes internal to the MySQL server", MYF(0));
break;
#endif
case SQLCOM_HA_OPEN:
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL, tables,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL, all_tables, 0))
goto error;
- res = mysql_ha_open(thd, tables);
+ res= mysql_ha_open(thd, first_table, 0);
break;
case SQLCOM_HA_CLOSE:
- if (check_db_used(thd,tables))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables))
goto error;
- res = mysql_ha_close(thd, tables);
+ res= mysql_ha_close(thd, first_table);
break;
case SQLCOM_HA_READ:
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
/*
There is no need to check for table permissions here, because
if a user has no permissions to read a table, he won't be
able to open it (with SQLCOM_HA_OPEN) in the first place.
*/
- if (check_db_used(thd,tables))
+ if (check_db_used(thd, all_tables))
goto error;
- res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
- lex->insert_list, lex->ha_rkey_mode, select_lex->where,
- select_lex->select_limit, select_lex->offset_limit);
+ res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
+ lex->insert_list, lex->ha_rkey_mode, select_lex->where,
+ select_lex->select_limit, select_lex->offset_limit);
break;
case SQLCOM_BEGIN:
- if (thd->locked_tables)
+ if (begin_trans(thd))
+ goto error;
+ send_ok(thd);
+ break;
+ case SQLCOM_COMMIT:
+ if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
+ lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
+ goto error;
+ send_ok(thd);
+ break;
+ case SQLCOM_ROLLBACK:
+ if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
+ lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
+ goto error;
+ send_ok(thd);
+ break;
+ case SQLCOM_RELEASE_SAVEPOINT:
+ {
+ SAVEPOINT *sv;
+ for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
{
- thd->lock=thd->locked_tables;
- thd->locked_tables=0; // Will be automaticly closed
- close_thread_tables(thd); // Free tables
+ if (my_strnncoll(system_charset_info,
+ (uchar *)lex->ident.str, lex->ident.length,
+ (uchar *)sv->name, sv->length) == 0)
+ break;
}
- if (end_active_trans(thd))
+ if (sv)
{
- res= -1;
+ if (ha_release_savepoint(thd, sv))
+ res= TRUE; // cannot happen
+ else
+ send_ok(thd);
+ thd->transaction.savepoints=sv->prev;
}
else
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
+ break;
+ }
+ case SQLCOM_ROLLBACK_TO_SAVEPOINT:
+ {
+ SAVEPOINT *sv;
+ for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
+ {
+ if (my_strnncoll(system_charset_info,
+ (uchar *)lex->ident.str, lex->ident.length,
+ (uchar *)sv->name, sv->length) == 0)
+ break;
+ }
+ if (sv)
{
- thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
- OPTION_BEGIN);
- thd->server_status|= SERVER_STATUS_IN_TRANS;
- if (!(lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) ||
- !(res= ha_start_consistent_snapshot(thd)))
+ if (ha_rollback_to_savepoint(thd, sv))
+ res= TRUE; // cannot happen
+ else
+ {
+ if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
+ !thd->slave_thread)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARNING_NOT_COMPLETE_ROLLBACK,
+ ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
send_ok(thd);
+ }
+ thd->transaction.savepoints=sv;
}
+ else
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
break;
- case SQLCOM_COMMIT:
- /*
- We don't use end_active_trans() here to ensure that this works
- even if there is a problem with the OPTION_AUTO_COMMIT flag
- (Which of course should never happen...)
- */
+ }
+ case SQLCOM_SAVEPOINT:
+ if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) ||
+ !opt_using_transactions)
+ send_ok(thd);
+ else
+ {
+ SAVEPOINT **sv, *newsv;
+ for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
+ {
+ if (my_strnncoll(system_charset_info,
+ (uchar *)lex->ident.str, lex->ident.length,
+ (uchar *)(*sv)->name, (*sv)->length) == 0)
+ break;
+ }
+ if (*sv) /* old savepoint of the same name exists */
+ {
+ newsv=*sv;
+ ha_release_savepoint(thd, *sv); // it cannot fail
+ *sv=(*sv)->prev;
+ }
+ else if ((newsv=(SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
+ savepoint_alloc_size)) == 0)
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ break;
+ }
+ newsv->name=strmake_root(&thd->transaction.mem_root,
+ lex->ident.str, lex->ident.length);
+ newsv->length=lex->ident.length;
+ /*
+ if we'll get an error here, don't add new savepoint to the list.
+ we'll lose a little bit of memory in transaction mem_root, but it'll
+ be free'd when transaction ends anyway
+ */
+ if (ha_savepoint(thd, newsv))
+ res= TRUE;
+ else
+ {
+ newsv->prev=thd->transaction.savepoints;
+ thd->transaction.savepoints=newsv;
+ send_ok(thd);
+ }
+ }
+ break;
+ case SQLCOM_CREATE_PROCEDURE:
+ case SQLCOM_CREATE_SPFUNCTION:
{
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- if (!ha_commit(thd))
+ uint namelen;
+ char *name, *db;
+ int result;
+
+ DBUG_ASSERT(lex->sphead != 0);
+
+ if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0))
{
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ }
+
+ if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0])
+ {
+ lex->sphead->m_db.length= strlen(thd->db);
+ lex->sphead->m_db.str= strmake_root(thd->mem_root, thd->db,
+ lex->sphead->m_db.length);
+ }
+
+ name= lex->sphead->name(&namelen);
+#ifdef HAVE_DLOPEN
+ if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
+ {
+ udf_func *udf = find_udf(name, namelen);
+
+ if (udf)
+ {
+ my_error(ER_UDF_EXISTS, MYF(0), name);
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ }
+ }
+#endif
+ if (lex->sphead->m_type == TYPE_ENUM_FUNCTION &&
+ !lex->sphead->m_has_return)
+ {
+ my_error(ER_SP_NORETURN, MYF(0), name);
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ }
+
+ name= thd->strdup(name);
+ db= thd->strmake(lex->sphead->m_db.str, lex->sphead->m_db.length);
+ res= (result= lex->sphead->create(thd));
+ switch (result) {
+ case SP_OK:
+ lex->unit.cleanup();
+ delete lex->sphead;
+ lex->sphead= 0;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /* only add privileges if really neccessary */
+ if (sp_automatic_privileges &&
+ check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
+ db, name,
+ lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
+ {
+ close_thread_tables(thd);
+ if (sp_grant_privileges(thd, db, name,
+ lex->sql_command == SQLCOM_CREATE_PROCEDURE))
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_PROC_AUTO_GRANT_FAIL,
+ ER(ER_PROC_AUTO_GRANT_FAIL));
+ }
+#endif
send_ok(thd);
+ break;
+ case SP_WRITE_ROW_FAILED:
+ my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name);
+ lex->unit.cleanup();
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ case SP_NO_DB_ERROR:
+ my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
+ lex->unit.cleanup();
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ default:
+ my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name);
+ lex->unit.cleanup();
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
}
- else
- res= -1;
break;
}
- case SQLCOM_ROLLBACK:
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- if (!ha_rollback(thd))
+ case SQLCOM_CALL:
{
+ sp_head *sp;
+
/*
- If a non-transactional table was updated, warn; don't warn if this is a
- slave thread (because when a slave thread executes a ROLLBACK, it has
- been read from the binary log, so it's 100% sure and normal to produce
- error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
- slave SQL thread, it would not stop the thread but just be printed in
- the error log; but we don't want users to wonder why they have this
- message in the error log, so we don't send it.
+ This will cache all SP and SF and open and lock all tables
+ required for execution.
*/
- if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
- send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
+ if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
+ open_and_lock_tables(thd, all_tables))
+ goto error;
+
+ /*
+ By this moment all needed SPs should be in cache so no need
+ to look into DB. Moreover we may be unable to do it becuase
+ we may don't have read lock on mysql.proc
+ */
+ if (!(sp= sp_find_procedure(thd, lex->spname, TRUE)))
+ {
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
+ lex->spname->m_qname.str);
+ goto error;
+ }
+ else
+ {
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ st_sp_security_context save_ctx;
+#endif
+ ha_rows select_limit;
+ /* bits that should be cleared in thd->server_status */
+ uint bits_to_be_cleared= 0;
+
+#ifndef EMBEDDED_LIBRARY
+ my_bool nsok= thd->net.no_send_ok;
+ thd->net.no_send_ok= TRUE;
+#endif
+ if (sp->m_multi_results)
+ {
+ if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
+ {
+ my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
+ goto error;
+ }
+ /*
+ If SERVER_MORE_RESULTS_EXISTS is not set,
+ then remember that it should be cleared
+ */
+ bits_to_be_cleared= (~thd->server_status &
+ SERVER_MORE_RESULTS_EXISTS);
+ thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
+ }
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_routine_access(thd, EXECUTE_ACL,
+ sp->m_db.str, sp->m_name.str, TRUE, 0))
+ {
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
+ goto error;
+ }
+ sp_change_security_context(thd, sp, &save_ctx);
+ if (save_ctx.changed &&
+ check_routine_access(thd, EXECUTE_ACL,
+ sp->m_db.str, sp->m_name.str, TRUE, 0))
+ {
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
+ sp_restore_security_context(thd, sp, &save_ctx);
+ goto error;
+ }
+
+#endif
+ select_limit= thd->variables.select_limit;
+ thd->variables.select_limit= HA_POS_ERROR;
+
+ thd->row_count_func= 0;
+ tmp_disable_binlog(thd); /* don't binlog the substatements */
+ res= sp->execute_procedure(thd, &lex->value_list);
+ reenable_binlog(thd);
+
+ /*
+ We write CALL to binlog; on the opposite we didn't write the
+ substatements. That choice is necessary because the substatements
+ may use local vars.
+ Binlogging should happen when all tables are locked. They are locked
+ just above, and unlocked by close_thread_tables(). All tables which
+ are to be updated are locked like with a table-level write lock, and
+ this also applies to InnoDB (I tested - note that it reduces
+ InnoDB's concurrency as we don't use row-level locks). So binlogging
+ below is safe.
+ Note the limitation: if the SP returned an error, but still did some
+ updates, we do NOT binlog it. This is because otherwise "permission
+ denied", "table does not exist" etc would stop the slave quite
+ often. There is no easy way to know if the SP updated something
+ (even no_trans_update is not suitable, as it may be a transactional
+ autocommit update which happened, and no_trans_update covers only
+ INSERT/UPDATE/LOAD).
+ */
+ if (mysql_bin_log.is_open() &&
+ (sp->m_chistics->daccess == SP_CONTAINS_SQL ||
+ sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA))
+ {
+ if (res)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_FAILED_ROUTINE_BREAK_BINLOG,
+ ER(ER_FAILED_ROUTINE_BREAK_BINLOG));
+ else
+ {
+ thd->clear_error();
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
+ }
+
+ /*
+ If warnings have been cleared, we have to clear total_warn_count
+ too, otherwise the clients get confused.
+ */
+ if (thd->warn_list.is_empty())
+ thd->total_warn_count= 0;
+
+ thd->variables.select_limit= select_limit;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ sp_restore_security_context(thd, sp, &save_ctx);
+#endif
+
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
+ thd->server_status&= ~bits_to_be_cleared;
+
+ if (!res)
+ send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
+ thd->row_count_func));
+ else
+ goto error; // Substatement should already have sent error
+ }
+ break;
+ }
+ case SQLCOM_ALTER_PROCEDURE:
+ case SQLCOM_ALTER_FUNCTION:
+ {
+ int result;
+ sp_head *sp;
+ st_sp_chistics chistics;
+
+ memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
+ if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
+ sp= sp_find_procedure(thd, lex->spname);
+ else
+ sp= sp_find_function(thd, lex->spname);
+ mysql_reset_errors(thd, 0);
+ if (! sp)
+ {
+ if (lex->spname->m_db.str)
+ result= SP_KEY_NOT_FOUND;
+ else
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ goto error;
+ }
+ }
else
+ {
+ if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str,
+ sp->m_name.str,
+ lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
+ goto error;
+ memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
+ if (!trust_routine_creators && mysql_bin_log.is_open() &&
+ !sp->m_chistics->detistic &&
+ (chistics.daccess == SP_CONTAINS_SQL ||
+ chistics.daccess == SP_MODIFIES_SQL_DATA))
+ {
+ my_message(ER_BINLOG_UNSAFE_ROUTINE,
+ ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0));
+ result= SP_INTERNAL_ERROR;
+ }
+ else
+ {
+ if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
+ result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
+ else
+ result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
+ }
+ }
+ switch (result)
+ {
+ case SP_OK:
+ if (mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
send_ok(thd);
+ break;
+ case SP_KEY_NOT_FOUND:
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ SP_COM_STRING(lex), lex->spname->m_qname.str);
+ goto error;
+ default:
+ my_error(ER_SP_CANT_ALTER, MYF(0),
+ SP_COM_STRING(lex), lex->spname->m_qname.str);
+ goto error;
+ }
+ break;
+ }
+ case SQLCOM_DROP_PROCEDURE:
+ case SQLCOM_DROP_FUNCTION:
+ {
+ sp_head *sp;
+ int result;
+ char *db, *name;
+
+ if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
+ sp= sp_find_procedure(thd, lex->spname);
+ else
+ sp= sp_find_function(thd, lex->spname);
+ mysql_reset_errors(thd, 0);
+ if (sp)
+ {
+ db= thd->strdup(sp->m_db.str);
+ name= thd->strdup(sp->m_name.str);
+ if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
+ lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
+ goto error;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (sp_automatic_privileges &&
+ sp_revoke_privileges(thd, db, name,
+ lex->sql_command == SQLCOM_DROP_PROCEDURE))
+ {
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_PROC_AUTO_REVOKE_FAIL,
+ ER(ER_PROC_AUTO_REVOKE_FAIL));
+ }
+#endif
+ if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
+ result= sp_drop_procedure(thd, lex->spname);
+ else
+ result= sp_drop_function(thd, lex->spname);
+ }
+ else
+ {
+#ifdef HAVE_DLOPEN
+ if (lex->sql_command == SQLCOM_DROP_FUNCTION)
+ {
+ udf_func *udf = find_udf(lex->spname->m_name.str,
+ lex->spname->m_name.length);
+ if (udf)
+ {
+ if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0))
+ goto error;
+ if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
+ {
+ send_ok(thd);
+ break;
+ }
+ }
+ }
+#endif
+ if (lex->spname->m_db.str)
+ result= SP_KEY_NOT_FOUND;
+ else
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ goto error;
+ }
+ }
+ res= result;
+ switch (result)
+ {
+ case SP_OK:
+ if (mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
+ send_ok(thd);
+ break;
+ case SP_KEY_NOT_FOUND:
+ if (lex->drop_if_exists)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
+ SP_COM_STRING(lex), lex->spname->m_name.str);
+ res= FALSE;
+ send_ok(thd);
+ break;
+ }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ SP_COM_STRING(lex), lex->spname->m_qname.str);
+ goto error;
+ default:
+ my_error(ER_SP_DROP_FAILED, MYF(0),
+ SP_COM_STRING(lex), lex->spname->m_qname.str);
+ goto error;
+ }
+ break;
+ }
+ case SQLCOM_SHOW_CREATE_PROC:
+ {
+ if (lex->spname->m_name.length > NAME_LEN)
+ {
+ my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
+ goto error;
+ }
+ if (sp_show_create_procedure(thd, lex->spname) != SP_OK)
+ { /* We don't distinguish between errors for now */
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ SP_COM_STRING(lex), lex->spname->m_name.str);
+ goto error;
+ }
+ break;
+ }
+ case SQLCOM_SHOW_CREATE_FUNC:
+ {
+ if (lex->spname->m_name.length > NAME_LEN)
+ {
+ my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
+ goto error;
+ }
+ if (sp_show_create_function(thd, lex->spname) != SP_OK)
+ { /* We don't distinguish between errors for now */
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ SP_COM_STRING(lex), lex->spname->m_name.str);
+ goto error;
+ }
+ break;
+ }
+ case SQLCOM_SHOW_STATUS_PROC:
+ {
+ res= sp_show_status_procedure(thd, (lex->wild ?
+ lex->wild->ptr() : NullS));
+ break;
+ }
+ case SQLCOM_SHOW_STATUS_FUNC:
+ {
+ res= sp_show_status_function(thd, (lex->wild ?
+ lex->wild->ptr() : NullS));
+ break;
+ }
+ case SQLCOM_CREATE_VIEW:
+ {
+ if (!(res= mysql_create_view(thd, thd->lex->create_view_mode)) &&
+ mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
+ break;
+ }
+ case SQLCOM_DROP_VIEW:
+ {
+ if (check_table_access(thd, DROP_ACL, all_tables, 0) ||
+ end_active_trans(thd))
+ goto error;
+ if (!(res= mysql_drop_view(thd, first_table, thd->lex->drop_mode)) &&
+ mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
+ break;
+ }
+ case SQLCOM_CREATE_TRIGGER:
+ {
+ res= mysql_create_or_drop_trigger(thd, all_tables, 1);
+
+ /* We don't care about trigger body after this point */
+ delete lex->sphead;
+ lex->sphead= 0;
+ break;
+ }
+ case SQLCOM_DROP_TRIGGER:
+ {
+ res= mysql_create_or_drop_trigger(thd, all_tables, 0);
+ break;
+ }
+ case SQLCOM_XA_START:
+ if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME)
+ {
+ if (! thd->transaction.xid.eq(thd->lex->xid))
+ {
+ my_error(ER_XAER_NOTA, MYF(0));
+ break;
+ }
+ thd->transaction.xa_state=XA_ACTIVE;
+ send_ok(thd);
+ break;
+ }
+ if (thd->lex->xa_opt != XA_NONE)
+ { // JOIN is not supported yet. TODO
+ my_error(ER_XAER_INVAL, MYF(0));
+ break;
+ }
+ if (thd->transaction.xa_state != XA_NOTR)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xa_state]);
+ break;
+ }
+ if (thd->active_transaction() || thd->locked_tables)
+ {
+ my_error(ER_XAER_OUTSIDE, MYF(0));
+ break;
+ }
+ DBUG_ASSERT(thd->transaction.xid.is_null());
+ thd->transaction.xa_state=XA_ACTIVE;
+ thd->transaction.xid.set(thd->lex->xid);
+ thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
+ OPTION_BEGIN);
+ thd->server_status|= SERVER_STATUS_IN_TRANS;
+ send_ok(thd);
+ break;
+ case SQLCOM_XA_END:
+ /* fake it */
+ if (thd->lex->xa_opt != XA_NONE)
+ { // SUSPEND and FOR MIGRATE are not supported yet. TODO
+ my_error(ER_XAER_INVAL, MYF(0));
+ break;
+ }
+ if (thd->transaction.xa_state != XA_ACTIVE)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xa_state]);
+ break;
+ }
+ if (!thd->transaction.xid.eq(thd->lex->xid))
+ {
+ my_error(ER_XAER_NOTA, MYF(0));
+ break;
+ }
+ thd->transaction.xa_state=XA_IDLE;
+ send_ok(thd);
+ break;
+ case SQLCOM_XA_PREPARE:
+ if (thd->transaction.xa_state != XA_IDLE)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xa_state]);
+ break;
+ }
+ if (!thd->transaction.xid.eq(thd->lex->xid))
+ {
+ my_error(ER_XAER_NOTA, MYF(0));
+ break;
+ }
+ if (ha_prepare(thd))
+ {
+ my_error(ER_XA_RBROLLBACK, MYF(0));
+ thd->transaction.xa_state=XA_NOTR;
+ break;
+ }
+ thd->transaction.xa_state=XA_PREPARED;
+ send_ok(thd);
+ break;
+ case SQLCOM_XA_COMMIT:
+ if (!thd->transaction.xid.eq(thd->lex->xid))
+ {
+ if (!(res= !ha_commit_or_rollback_by_xid(thd->lex->xid, 1)))
+ my_error(ER_XAER_NOTA, MYF(0));
+ else
+ send_ok(thd);
+ break;
+ }
+ if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
+ {
+ int r;
+ if ((r= ha_commit(thd)))
+ my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
+ else
+ send_ok(thd);
}
else
- res= -1;
+ if (thd->transaction.xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE)
+ {
+ if (wait_if_global_read_lock(thd, 0, 0))
+ {
+ ha_rollback(thd);
+ my_error(ER_XAER_RMERR, MYF(0));
+ }
+ else
+ {
+ if (ha_commit_one_phase(thd, 1))
+ my_error(ER_XAER_RMERR, MYF(0));
+ else
+ send_ok(thd);
+ start_waiting_global_read_lock(thd);
+ }
+ }
+ else
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xa_state]);
+ break;
+ }
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ thd->transaction.xa_state=XA_NOTR;
break;
- case SQLCOM_ROLLBACK_TO_SAVEPOINT:
- if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
+ case SQLCOM_XA_ROLLBACK:
+ if (!thd->transaction.xid.eq(thd->lex->xid))
{
- if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
- send_warning(thd, ER_WARNING_NOT_COMPLETE_ROLLBACK, 0);
+ if (!(res= !ha_commit_or_rollback_by_xid(thd->lex->xid, 0)))
+ my_error(ER_XAER_NOTA, MYF(0));
else
- send_ok(thd);
+ send_ok(thd);
+ break;
}
+ if (thd->transaction.xa_state != XA_IDLE &&
+ thd->transaction.xa_state != XA_PREPARED)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xa_state]);
+ break;
+ }
+ if (ha_rollback(thd))
+ my_error(ER_XAER_RMERR, MYF(0));
else
- res= -1;
- break;
- case SQLCOM_SAVEPOINT:
- if (!ha_savepoint(thd, lex->savepoint_name))
send_ok(thd);
- else
- res= -1;
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ thd->transaction.xa_state=XA_NOTR;
break;
- default: /* Impossible */
+ case SQLCOM_XA_RECOVER:
+ res= mysql_xa_recover(thd);
+ break;
+ default:
+ DBUG_ASSERT(0); /* Impossible */
send_ok(thd);
break;
}
- thd->proc_info="query end"; // QQ
+ thd->proc_info="query end";
+ /* Two binlog-related cleanups: */
if (thd->one_shot_set)
{
/*
@@ -3659,10 +4594,20 @@ purposes internal to the MySQL server", MYF(0));
thd->one_shot_set= 0;
}
}
- if (res < 0)
- send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
+
+ /*
+ The return value for ROW_COUNT() is "implementation dependent" if
+ the statement is not DELETE, INSERT or UPDATE (or a CALL executing
+ such a statement), but -1 is what JDBC and ODBC wants.
+ */
+ if (lex->sql_command != SQLCOM_CALL && uc_update_queries[lex->sql_command]<2)
+ thd->row_count_func= -1;
+ goto cleanup;
error:
+ res= 1;
+
+cleanup:
if (unlikely(slave_fake_lock))
{
DBUG_PRINT("info",("undoing faked lock"));
@@ -3671,7 +4616,7 @@ error:
if (thd->lock == thd->locked_tables)
thd->lock= 0;
}
- DBUG_VOID_RETURN;
+ DBUG_RETURN(res || thd->net.report_error);
}
@@ -3682,28 +4627,29 @@ error:
SYNOPSIS
check_one_table_access()
thd Thread handler
- privilege requested privelage
- tables table list of command
+ privilege requested privilege
+ all_tables global table list of query
RETURN
0 - OK
1 - access denied, error is sent to client
*/
-int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables)
+bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
{
- if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
+ if (check_access(thd, privilege, all_tables->db,
+ &all_tables->grant.privilege, 0, 0))
return 1;
/* Show only 1 table for check_grant */
- if (grant_option && check_grant(thd, privilege, tables, 0, 1, 0))
+ if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0))
return 1;
/* Check rights on tables of subselects and implictly opened tables */
TABLE_LIST *subselects_tables;
- if ((subselects_tables= tables->next))
+ if ((subselects_tables= all_tables->next_global))
{
- if ((check_table_access(thd, SELECT_ACL, subselects_tables,0)))
+ if ((check_table_access(thd, SELECT_ACL, subselects_tables, 0)))
return 1;
}
return 0;
@@ -3733,14 +4679,14 @@ bool
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
bool dont_check_global_grants, bool no_errors)
{
- DBUG_ENTER("check_access");
- DBUG_PRINT("enter",("db: '%s' want_access: %lu master_access: %lu",
- db ? db : "", want_access, thd->master_access));
#ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong db_access;
bool db_is_pattern= test(want_access & GRANT_ACL);
#endif
ulong dummy;
+ DBUG_ENTER("check_access");
+ DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
+ db ? db : "", want_access, thd->master_access));
if (save_priv)
*save_priv=0;
else
@@ -3748,8 +4694,10 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
{
+ DBUG_PRINT("error",("No database"));
if (!no_errors)
- send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
+ MYF(0)); /* purecov: tested */
DBUG_RETURN(TRUE); /* purecov: tested */
}
@@ -3773,11 +4721,14 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
! db && dont_check_global_grants)
{ // We can never grant this
+ DBUG_PRINT("error",("No possible access"));
if (!no_errors)
- net_printf(thd,ER_ACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->priv_host,
- thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
+ my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
+ thd->priv_user,
+ thd->priv_host,
+ (thd->password ?
+ ER(ER_YES) :
+ ER(ER_NO))); /* purecov: tested */
DBUG_RETURN(TRUE); /* purecov: tested */
}
@@ -3791,18 +4742,24 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
DBUG_PRINT("info",("db_access: %lu", db_access));
/* Remove SHOW attribute and access rights we already have */
want_access &= ~(thd->master_access | EXTRA_ACL);
+ DBUG_PRINT("info",("db_access: %lu want_access: %lu",
+ db_access, want_access));
db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
/* grant_option is set if there exists a single table or column grant */
if (db_access == want_access ||
- ((grant_option && !dont_check_global_grants) &&
- !(want_access & ~(db_access | TABLE_ACLS))))
+ (grant_option && !dont_check_global_grants &&
+ !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
DBUG_RETURN(FALSE); /* Ok */
+
+ DBUG_PRINT("error",("Access denied"));
if (!no_errors)
- net_printf(thd,ER_DBACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->priv_host,
- db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ thd->priv_user,
+ thd->priv_host,
+ (db ? db : (thd->db ?
+ thd->db :
+ "unknown"))); /* purecov: tested */
DBUG_RETURN(TRUE); /* purecov: tested */
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
@@ -3817,7 +4774,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
want_access Use should have any of these global rights
WARNING
- One gets access rigth if one has ANY of the rights in want_access
+ One gets access right if one has ANY of the rights in want_access
This is useful as one in most cases only need one global right,
but in some case we want to check if the user has SUPER or
REPL_CLIENT_ACL rights.
@@ -3836,8 +4793,7 @@ bool check_global_access(THD *thd, ulong want_access)
if ((thd->master_access & want_access))
return 0;
get_privilege_desc(command, sizeof(command), want_access);
- net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
- command);
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
return 1;
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
@@ -3855,10 +4811,10 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
uint found=0;
ulong found_access=0;
TABLE_LIST *org_tables=tables;
- for (; tables ; tables=tables->next)
+ for (; tables; tables= tables->next_global)
{
- if (tables->derived ||
- (tables->table && (int)tables->table->tmp_table) ||
+ if (tables->derived || tables->schema_table || tables->belong_to_view ||
+ (tables->table && (int)tables->table->s->tmp_table) ||
my_tz_check_n_skip_implicit_tables(&tables,
thd->lex->time_zone_tables_used))
continue;
@@ -3888,6 +4844,94 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
return FALSE;
}
+
+bool
+check_routine_access(THD *thd, ulong want_access,char *db, char *name,
+ bool is_proc, bool no_errors)
+{
+ TABLE_LIST tables[1];
+
+ bzero((char *)tables, sizeof(TABLE_LIST));
+ tables->db= db;
+ tables->table_name= tables->alias= name;
+
+ if ((thd->master_access & want_access) == want_access && !thd->db)
+ tables->grant.privilege= want_access;
+ else if (check_access(thd,want_access,db,&tables->grant.privilege,
+ 0, no_errors))
+ return TRUE;
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (grant_option)
+ return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
+#endif
+
+ return FALSE;
+}
+
+
+/*
+ Check if the routine has any of the routine privileges
+
+ SYNOPSIS
+ check_some_routine_access()
+ thd Thread handler
+ db Database name
+ name Routine name
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool check_some_routine_access(THD *thd, const char *db, const char *name,
+ bool is_proc)
+{
+ ulong save_priv;
+ if (thd->master_access & SHOW_PROC_ACLS)
+ return FALSE;
+ if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1) ||
+ (save_priv & SHOW_PROC_ACLS))
+ return FALSE;
+ return check_routine_level_acl(thd, db, name, is_proc);
+}
+
+
+/*
+ Check if the given table has any of the asked privileges
+
+ SYNOPSIS
+ check_some_access()
+ thd Thread handler
+ want_access Bitmap of possible privileges to check for
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+
+bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
+{
+ ulong access;
+ DBUG_ENTER("check_some_access");
+
+ /* This loop will work as long as we have less than 32 privileges */
+ for (access= 1; access < want_access ; access<<= 1)
+ {
+ if (access & want_access)
+ {
+ if (!check_access(thd, access, table->db,
+ &table->grant.privilege, 0, 1) &&
+ !grant_option || !check_grant(thd, access, table, 0, 1, 1))
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_PRINT("exit",("no matching access rights"));
+ DBUG_RETURN(1);
+}
+
+
bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list)
{
@@ -3896,7 +4940,7 @@ bool check_merge_table_access(THD *thd, char *db,
{
/* Check that all tables use the current database */
TABLE_LIST *tmp;
- for (tmp=table_list; tmp ; tmp=tmp->next)
+ for (tmp= table_list; tmp; tmp= tmp->next_local)
{
if (!tmp->db || !tmp->db[0])
tmp->db=db;
@@ -3910,13 +4954,14 @@ bool check_merge_table_access(THD *thd, char *db,
static bool check_db_used(THD *thd,TABLE_LIST *tables)
{
- for (; tables ; tables=tables->next)
+ for (; tables; tables= tables->next_global)
{
if (!tables->db)
{
if (!(tables->db=thd->db))
{
- send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
+ MYF(0)); /* purecov: tested */
return TRUE; /* purecov: tested */
}
}
@@ -3924,6 +4969,7 @@ static bool check_db_used(THD *thd,TABLE_LIST *tables)
return FALSE;
}
+
/****************************************************************************
Check stack size; Send error if there isn't enough stack to continue
****************************************************************************/
@@ -3988,6 +5034,7 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
return 0;
}
+
/****************************************************************************
Initialize global thd variables needed for query
****************************************************************************/
@@ -4020,13 +5067,13 @@ void mysql_reset_thd_for_next_command(THD *thd)
DBUG_ENTER("mysql_reset_thd_for_next_command");
thd->free_list= 0;
thd->select_number= 1;
- thd->total_warn_count= 0; // Warnings for this query
+ thd->total_warn_count=0; // Warnings for this query
thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
thd->sent_row_count= thd->examined_row_count= 0;
thd->is_fatal_error= thd->rand_used= thd->time_zone_used= 0;
thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
- SERVER_QUERY_NO_INDEX_USED |
- SERVER_QUERY_NO_GOOD_INDEX_USED);
+ SERVER_QUERY_NO_INDEX_USED |
+ SERVER_QUERY_NO_GOOD_INDEX_USED);
thd->tmp_table_used= 0;
if (opt_bin_log)
reset_dynamic(&thd->user_var_events);
@@ -4041,6 +5088,8 @@ mysql_init_select(LEX *lex)
SELECT_LEX *select_lex= lex->current_select;
select_lex->init_select();
select_lex->select_limit= HA_POS_ERROR;
+ lex->orig_sql_command= SQLCOM_END;
+ lex->wild= 0;
if (select_lex == &lex->select_lex)
{
DBUG_ASSERT(lex->result == 0);
@@ -4053,18 +5102,21 @@ bool
mysql_new_select(LEX *lex, bool move_down)
{
SELECT_LEX *select_lex;
+ DBUG_ENTER("mysql_new_select");
+
if (!(select_lex= new(lex->thd->mem_root) SELECT_LEX()))
- return 1;
+ DBUG_RETURN(1);
select_lex->select_number= ++lex->thd->select_number;
select_lex->init_query();
select_lex->init_select();
+ select_lex->parent_lex= lex;
if (move_down)
{
+ SELECT_LEX_UNIT *unit;
lex->subqueries= TRUE;
/* first select_lex of subselect or derived table */
- SELECT_LEX_UNIT *unit;
if (!(unit= new(lex->thd->mem_root) SELECT_LEX_UNIT()))
- return 1;
+ DBUG_RETURN(1);
unit->init_query();
unit->init_select();
@@ -4074,10 +5126,15 @@ mysql_new_select(LEX *lex, bool move_down)
unit->link_prev= 0;
unit->return_to= lex->current_select;
select_lex->include_down(unit);
- // TODO: assign resolve_mode for fake subquery after merging with new tree
+ /* TODO: assign resolve_mode for fake subquery after merging with new tree */
}
else
{
+ if (lex->current_select->order_list.first && !lex->current_select->braces)
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
+ DBUG_RETURN(1);
+ }
select_lex->include_neighbour(lex->current_select);
SELECT_LEX_UNIT *unit= select_lex->master_unit();
SELECT_LEX *fake= unit->fake_select_lex;
@@ -4088,7 +5145,7 @@ mysql_new_select(LEX *lex, bool move_down)
fake SELECT_LEX for UNION processing
*/
if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX()))
- return 1;
+ DBUG_RETURN(1);
fake->include_standalone(unit,
(SELECT_LEX_NODE**)&unit->fake_select_lex);
fake->select_number= INT_MAX;
@@ -4102,7 +5159,7 @@ mysql_new_select(LEX *lex, bool move_down)
select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
lex->current_select= select_lex;
select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
- return 0;
+ DBUG_RETURN(0);
}
/*
@@ -4146,6 +5203,8 @@ void mysql_init_multi_delete(LEX *lex)
HA_POS_ERROR;
lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list);
lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
+ lex->query_tables= 0;
+ lex->query_tables_last= &lex->query_tables;
}
@@ -4174,7 +5233,13 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
#endif
{
if (thd->net.report_error)
- send_error(thd, 0, NullS);
+ {
+ if (thd->lex->sphead)
+ {
+ delete thd->lex->sphead;
+ thd->lex->sphead= NULL;
+ }
+ }
else
{
/*
@@ -4187,23 +5252,32 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
PROCESSLIST.
Note that we don't need LOCK_thread_count to modify query_length.
*/
- if (lex->found_colon &&
- (thd->query_length= (ulong)(lex->found_colon - thd->query)))
+ if (lex->found_semicolon &&
+ (thd->query_length= (ulong)(lex->found_semicolon - thd->query)))
thd->query_length--;
/* Actually execute the query */
mysql_execute_command(thd);
query_cache_end_of_result(thd);
}
}
+ lex->unit.cleanup();
}
else
{
DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
thd->is_fatal_error));
query_cache_abort(&thd->net);
+ lex->unit.cleanup();
+ if (thd->lex->sphead)
+ {
+ /* Clean up after failed stored procedure/function */
+ delete thd->lex->sphead;
+ thd->lex->sphead= NULL;
+ }
}
thd->proc_info="freeing items";
thd->end_statement();
+ thd->cleanup_after_query();
DBUG_ASSERT(thd->change_list.is_empty());
}
DBUG_VOID_RETURN;
@@ -4224,17 +5298,20 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
{
LEX *lex= thd->lex;
bool error= 0;
+ DBUG_ENTER("mysql_test_parse_for_slave");
mysql_init_query(thd, (uchar*) inBuf, length);
if (!yyparse((void*) thd) && ! thd->is_fatal_error &&
all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
- error= 1; /* Ignore question */
+ error= 1; /* Ignore question */
thd->end_statement();
- return error;
+ thd->cleanup_after_query();
+ DBUG_RETURN(error);
}
#endif
+
/*****************************************************************************
** Store field definition for create
** Return 0 if ok
@@ -4251,13 +5328,11 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
{
register create_field *new_field;
LEX *lex= thd->lex;
- uint allowed_type_modifier=0;
- char warn_buff[MYSQL_ERRMSG_SIZE];
DBUG_ENTER("add_field_to_list");
if (strlen(field_name) > NAME_LEN)
{
- net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
+ my_error(ER_TOO_LONG_IDENT, MYF(0), field_name); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
if (type_modifier & PRI_KEY_FLAG)
@@ -4288,7 +5363,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
!(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
type == FIELD_TYPE_TIMESTAMP))
{
- net_printf(thd, ER_INVALID_DEFAULT, field_name);
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
DBUG_RETURN(1);
}
else if (default_value->type() == Item::NULL_ITEM)
@@ -4297,25 +5372,54 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
NOT_NULL_FLAG)
{
- net_printf(thd,ER_INVALID_DEFAULT,field_name);
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
DBUG_RETURN(1);
}
}
else if (type_modifier & AUTO_INCREMENT_FLAG)
{
- net_printf(thd, ER_INVALID_DEFAULT, field_name);
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
DBUG_RETURN(1);
}
}
if (on_update_value && type != FIELD_TYPE_TIMESTAMP)
{
- net_printf(thd, ER_INVALID_ON_UPDATE, field_name);
+ my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
DBUG_RETURN(1);
}
-
- if (!(new_field=new create_field()))
+
+ if (!(new_field= new_create_field(thd, field_name, type, length, decimals,
+ type_modifier, default_value, on_update_value,
+ comment, change, interval_list, cs, uint_geom_type)))
DBUG_RETURN(1);
+
+ lex->create_list.push_back(new_field);
+ lex->last_field=new_field;
+ DBUG_RETURN(0);
+}
+
+/*****************************************************************************
+** Create field definition for create
+** Return 0 on failure, otherwise return create_field instance
+******************************************************************************/
+
+create_field *
+new_create_field(THD *thd, char *field_name, enum_field_types type,
+ char *length, char *decimals,
+ uint type_modifier,
+ Item *default_value, Item *on_update_value,
+ LEX_STRING *comment,
+ char *change, List<String> *interval_list, CHARSET_INFO *cs,
+ uint uint_geom_type)
+{
+ register create_field *new_field;
+ uint sign_len, allowed_type_modifier=0;
+ ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
+ DBUG_ENTER("new_create_field");
+
+ if (!(new_field=new create_field()))
+ DBUG_RETURN(NULL);
new_field->field=0;
new_field->field_name=field_name;
new_field->def= default_value;
@@ -4328,24 +5432,21 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
new_field->length=0;
new_field->change=change;
new_field->interval=0;
- new_field->pack_length=0;
+ new_field->pack_length= new_field->key_length= 0;
new_field->charset=cs;
new_field->geom_type= (Field::geometry_type) uint_geom_type;
- if (!comment)
- {
- new_field->comment.str=0;
- new_field->comment.length=0;
- }
- else
- {
- /* In this case comment is always of type Item_string */
- new_field->comment.str= (char*) comment->str;
- new_field->comment.length=comment->length;
- }
+ new_field->comment=*comment;
+ /*
+ Set flag if this field doesn't have a default value
+ */
+ if (!default_value && !(type_modifier & AUTO_INCREMENT_FLAG) &&
+ (type_modifier & NOT_NULL_FLAG) && type != FIELD_TYPE_TIMESTAMP)
+ new_field->flags|= NO_DEFAULT_VALUE_FLAG;
+
if (length && !(new_field->length= (uint) atoi(length)))
length=0; /* purecov: inspected */
- uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
+ sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
if (new_field->length && new_field->decimals &&
new_field->length < new_field->decimals+1 &&
@@ -4375,59 +5476,47 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
break;
case FIELD_TYPE_NULL:
break;
- case FIELD_TYPE_DECIMAL:
+ case FIELD_TYPE_NEWDECIMAL:
if (!length)
{
- if ((new_field->length= new_field->decimals))
- new_field->length++;
- else
+ if (!(new_field->length= new_field->decimals))
new_field->length= 10; // Default length for DECIMAL
}
- if (new_field->length < MAX_FIELD_WIDTH) // Skip wrong argument
+ new_field->pack_length=
+ my_decimal_get_binary_size(new_field->length, new_field->decimals);
+ if (new_field->length <= DECIMAL_MAX_PRECISION &&
+ new_field->length >= new_field->decimals)
{
- new_field->length+=sign_len;
- if (new_field->decimals)
- new_field->length++;
+ new_field->length=
+ my_decimal_precision_to_length(new_field->length, new_field->decimals,
+ type_modifier & UNSIGNED_FLAG);
+ break;
}
+ my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
+ DBUG_RETURN(NULL);
+ case MYSQL_TYPE_VARCHAR:
+ /*
+ Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
+ if they don't have a default value
+ */
+ max_field_charlength= MAX_FIELD_VARCHARLENGTH;
+ break;
+ case MYSQL_TYPE_STRING:
break;
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_VAR_STRING:
- if (new_field->length <= MAX_FIELD_CHARLENGTH || default_value)
- break;
- /* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */
- new_field->sql_type= FIELD_TYPE_BLOB;
- sprintf(warn_buff, ER(ER_AUTO_CONVERT), field_name, "CHAR",
- (cs == &my_charset_bin) ? "BLOB" : "TEXT");
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_AUTO_CONVERT,
- warn_buff);
- /* fall through */
case FIELD_TYPE_BLOB:
case FIELD_TYPE_TINY_BLOB:
case FIELD_TYPE_LONG_BLOB:
case FIELD_TYPE_MEDIUM_BLOB:
case FIELD_TYPE_GEOMETRY:
- if (new_field->length)
- {
- /* The user has given a length to the blob column */
- if (new_field->length < 256)
- type= FIELD_TYPE_TINY_BLOB;
- else if (new_field->length < 65536)
- type= FIELD_TYPE_BLOB;
- else if (new_field->length < 256L*256L*256L)
- type= FIELD_TYPE_MEDIUM_BLOB;
- else
- type= FIELD_TYPE_LONG_BLOB;
- new_field->length= 0;
- }
- new_field->sql_type= type;
if (default_value) // Allow empty as default value
{
String str,*res;
res=default_value->val_str(&str);
if (res->length())
{
- net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
- DBUG_RETURN(1); /* purecov: inspected */
+ my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
+ field_name); /* purecov: inspected */
+ DBUG_RETURN(NULL);
}
new_field->def=0;
}
@@ -4446,8 +5535,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
uint tmp_length=new_field->length;
if (tmp_length > PRECISION_FOR_DOUBLE)
{
- net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
- DBUG_RETURN(1);
+ my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
+ DBUG_RETURN(NULL);
}
else if (tmp_length > PRECISION_FOR_FLOAT)
{
@@ -4519,11 +5608,11 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
If we have TIMESTAMP NULL column without explicit DEFAULT value
we treat it as having DEFAULT NULL attribute.
*/
- new_field->unireg_check= on_update_value ?
- Field::TIMESTAMP_UN_FIELD :
- (new_field->flags & NOT_NULL_FLAG ?
- Field::TIMESTAMP_OLD_FIELD:
- Field::NONE);
+ new_field->unireg_check= (on_update_value ?
+ Field::TIMESTAMP_UN_FIELD :
+ (new_field->flags & NOT_NULL_FLAG ?
+ Field::TIMESTAMP_OLD_FIELD:
+ Field::NONE));
}
break;
case FIELD_TYPE_DATE: // Old date type
@@ -4543,8 +5632,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
{
if (interval_list->elements > sizeof(longlong)*8)
{
- net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
- DBUG_RETURN(1); /* purecov: inspected */
+ my_error(ER_TOO_BIG_SET, MYF(0), field_name); /* purecov: inspected */
+ DBUG_RETURN(NULL);
}
new_field->pack_length= get_set_pack_length(interval_list->elements);
@@ -4558,8 +5647,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
when we know the character set of the column
*/
new_field->length= 1;
+ break;
}
- break;
case FIELD_TYPE_ENUM:
{
// Should be safe
@@ -4570,37 +5659,50 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
while ((tmp= it++))
new_field->interval_list.push_back(tmp);
new_field->length= 1; // See comment for FIELD_TYPE_SET above.
- }
+ break;
+ }
+ case MYSQL_TYPE_VAR_STRING:
+ DBUG_ASSERT(0); // Impossible
break;
+ case MYSQL_TYPE_BIT:
+ {
+ if (!length)
+ new_field->length= 1;
+ if (new_field->length > MAX_BIT_FIELD_LENGTH)
+ {
+ my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name,
+ MAX_BIT_FIELD_LENGTH);
+ DBUG_RETURN(NULL);
+ }
+ new_field->pack_length= (new_field->length + 7) / 8;
+ break;
+ }
+ case FIELD_TYPE_DECIMAL:
+ DBUG_ASSERT(0); /* Was obsolete */
}
- if ((new_field->length > MAX_FIELD_CHARLENGTH && type != FIELD_TYPE_SET &&
- type != FIELD_TYPE_ENUM) ||
- (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
- type != FIELD_TYPE_STRING &&
- type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
+ if (!(new_field->flags & BLOB_FLAG) &&
+ ((new_field->length > max_field_charlength && type != FIELD_TYPE_SET &&
+ type != FIELD_TYPE_ENUM &&
+ (type != MYSQL_TYPE_VARCHAR || default_value)) ||
+ (!new_field->length &&
+ type != MYSQL_TYPE_STRING &&
+ type != MYSQL_TYPE_VARCHAR && type != FIELD_TYPE_GEOMETRY)))
{
- net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
- MAX_FIELD_CHARLENGTH); /* purecov: inspected */
- DBUG_RETURN(1); /* purecov: inspected */
+ my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0),
+ field_name, max_field_charlength); /* purecov: inspected */
+ DBUG_RETURN(NULL);
}
type_modifier&= AUTO_INCREMENT_FLAG;
if ((~allowed_type_modifier) & type_modifier)
{
- net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
- DBUG_RETURN(1);
+ my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
+ DBUG_RETURN(NULL);
}
- if (!new_field->pack_length)
- new_field->pack_length=calc_pack_length(new_field->sql_type ==
- FIELD_TYPE_VAR_STRING ?
- FIELD_TYPE_STRING :
- new_field->sql_type,
- new_field->length);
- lex->create_list.push_back(new_field);
- lex->last_field=new_field;
- DBUG_RETURN(0);
+ DBUG_RETURN(new_field);
}
+
/* Store position for column in ALTER TABLE .. ADD column */
void store_position_for_column(const char *name)
@@ -4639,7 +5741,6 @@ static void remove_escape(char *name)
{
#ifdef USE_MB
int l;
-/* if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
if (use_mb(system_charset_info) &&
(l = my_ismbchar(system_charset_info, name, strend)))
{
@@ -4672,6 +5773,7 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
order->asc = asc;
order->free_me=0;
order->used=0;
+ order->counter_used= 0;
list.link_in_list((byte*) order,(byte**) &order->next);
DBUG_RETURN(0);
}
@@ -4707,6 +5809,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
{
register TABLE_LIST *ptr;
char *alias_str;
+ LEX *lex= thd->lex;
DBUG_ENTER("add_table_to_list");
if (!table)
@@ -4715,7 +5818,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
if (check_table_name(table->table.str,table->table.length) ||
table->db.str && check_db_name(table->db.str))
{
- net_printf(thd, ER_WRONG_TABLE_NAME, table->table.str);
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
DBUG_RETURN(0);
}
@@ -4723,7 +5826,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
{
if (table->sel)
{
- net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
+ my_message(ER_DERIVED_MUST_HAVE_ALIAS,
+ ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
DBUG_RETURN(0);
}
if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
@@ -4753,13 +5857,29 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->alias= alias_str;
if (lower_case_table_names && table->table.length)
my_casedn_str(files_charset_info, table->table.str);
- ptr->real_name=table->table.str;
- ptr->real_name_length=table->table.length;
+ ptr->table_name=table->table.str;
+ ptr->table_name_length=table->table.length;
ptr->lock_type= lock_type;
ptr->updating= test(table_options & TL_OPTION_UPDATING);
ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
ptr->derived= table->sel;
+ if (!my_strcasecmp(system_charset_info, ptr->db,
+ information_schema_name.str))
+ {
+ ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
+ if (!schema_table ||
+ (schema_table->hidden &&
+ lex->orig_sql_command == SQLCOM_END)) // not a 'show' command
+ {
+ my_error(ER_UNKNOWN_TABLE, MYF(0),
+ ptr->table_name, information_schema_name.str);
+ DBUG_RETURN(0);
+ }
+ ptr->schema_table_name= ptr->table_name;
+ ptr->schema_table= schema_table;
+ }
+ ptr->select_lex= lex->current_select;
ptr->cacheable_table= 1;
if (use_index_arg)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index_arg,
@@ -4773,22 +5893,264 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
{
for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
tables ;
- tables=tables->next)
+ tables=tables->next_local)
{
if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
!strcmp(ptr->db, tables->db))
{
- net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
+ my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
DBUG_RETURN(0); /* purecov: tested */
}
}
}
- table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
+ /* Link table in local list (list for current select) */
+ table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
+ /* Link table in global list (all used tables) */
+ lex->add_to_query_tables(ptr);
DBUG_RETURN(ptr);
}
/*
+ Initialize a new table list for a nested join
+
+ SYNOPSIS
+ init_nested_join()
+ thd current thread
+
+ DESCRIPTION
+ The function initializes a structure of the TABLE_LIST type
+ for a nested join. It sets up its nested join list as empty.
+ The created structure is added to the front of the current
+ join list in the st_select_lex object. Then the function
+ changes the current nest level for joins to refer to the newly
+ created empty list after having saved the info on the old level
+ in the initialized structure.
+
+ RETURN VALUE
+ 0, if success
+ 1, otherwise
+*/
+
+bool st_select_lex::init_nested_join(THD *thd)
+{
+ TABLE_LIST *ptr;
+ NESTED_JOIN *nested_join;
+ DBUG_ENTER("init_nested_join");
+
+ if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
+ !(nested_join= ptr->nested_join=
+ (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
+ DBUG_RETURN(1);
+ join_list->push_front(ptr);
+ ptr->embedding= embedding;
+ ptr->join_list= join_list;
+ embedding= ptr;
+ join_list= &nested_join->join_list;
+ join_list->empty();
+ DBUG_RETURN(0);
+}
+
+
+/*
+ End a nested join table list
+
+ SYNOPSIS
+ end_nested_join()
+ thd current thread
+
+ DESCRIPTION
+ The function returns to the previous join nest level.
+ If the current level contains only one member, the function
+ moves it one level up, eliminating the nest.
+
+ RETURN VALUE
+ Pointer to TABLE_LIST element added to the total table list, if success
+ 0, otherwise
+*/
+
+TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
+{
+ TABLE_LIST *ptr;
+ NESTED_JOIN *nested_join;
+ DBUG_ENTER("end_nested_join");
+
+ DBUG_ASSERT(embedding);
+ ptr= embedding;
+ join_list= ptr->join_list;
+ embedding= ptr->embedding;
+ nested_join= ptr->nested_join;
+ if (nested_join->join_list.elements == 1)
+ {
+ TABLE_LIST *embedded= nested_join->join_list.head();
+ join_list->pop();
+ embedded->join_list= join_list;
+ embedded->embedding= embedding;
+ join_list->push_front(embedded);
+ ptr= embedded;
+ }
+ else if (nested_join->join_list.elements == 0)
+ {
+ join_list->pop();
+ ptr= 0; // return value
+ }
+ DBUG_RETURN(ptr);
+}
+
+
+/*
+ Nest last join operation
+
+ SYNOPSIS
+ nest_last_join()
+ thd current thread
+
+ DESCRIPTION
+ The function nest last join operation as if it was enclosed in braces.
+
+ RETURN VALUE
+ Pointer to TABLE_LIST element created for the new nested join, if success
+ 0, otherwise
+*/
+
+TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
+{
+ TABLE_LIST *ptr;
+ NESTED_JOIN *nested_join;
+ DBUG_ENTER("nest_last_join");
+
+ if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
+ !(nested_join= ptr->nested_join=
+ (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
+ DBUG_RETURN(0);
+ ptr->embedding= embedding;
+ ptr->join_list= join_list;
+ List<TABLE_LIST> *embedded_list= &nested_join->join_list;
+ embedded_list->empty();
+ for (int i=0; i < 2; i++)
+ {
+ TABLE_LIST *table= join_list->pop();
+ table->join_list= embedded_list;
+ table->embedding= ptr;
+ embedded_list->push_back(table);
+ }
+ join_list->push_front(ptr);
+ nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
+ DBUG_RETURN(ptr);
+}
+
+
+/*
+ Save names for a join with using clause
+
+ SYNOPSIS
+ save_names_for_using_list
+ tab1 left table in join
+ tab2 right table in join
+
+ DESCRIPTION
+ The function saves the full names of the tables in st_select_lex
+ to be able to build later an on expression to replace the using clause.
+
+ RETURN VALUE
+ None
+*/
+
+void st_select_lex::save_names_for_using_list(TABLE_LIST *tab1,
+ TABLE_LIST *tab2)
+{
+ while (tab1->nested_join)
+ {
+ tab1= tab1->nested_join->join_list.head();
+ }
+ db1= tab1->db;
+ table1= tab1->alias;
+ while (tab2->nested_join)
+ {
+ TABLE_LIST *next;
+ List_iterator_fast<TABLE_LIST> it(tab2->nested_join->join_list);
+ tab2= it++;
+ while ((next= it++))
+ tab2= next;
+ }
+ db2= tab2->db;
+ table2= tab2->alias;
+}
+
+
+/*
+ Add a table to the current join list
+
+ SYNOPSIS
+ add_joined_table()
+ table the table to add
+
+ DESCRIPTION
+ The function puts a table in front of the current join list
+ of st_select_lex object.
+ Thus, joined tables are put into this list in the reverse order
+ (the most outer join operation follows first).
+
+ RETURN VALUE
+ None
+*/
+
+void st_select_lex::add_joined_table(TABLE_LIST *table)
+{
+ DBUG_ENTER("add_joined_table");
+ join_list->push_front(table);
+ table->join_list= join_list;
+ table->embedding= embedding;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Convert a right join into equivalent left join
+
+ SYNOPSIS
+ convert_right_join()
+ thd current thread
+
+ DESCRIPTION
+ The function takes the current join list t[0],t[1] ... and
+ effectively converts it into the list t[1],t[0] ...
+ Although the outer_join flag for the new nested table contains
+ JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
+ operation.
+
+ EXAMPLES
+ SELECT * FROM t1 RIGHT JOIN t2 ON on_expr =>
+ SELECT * FROM t2 LEFT JOIN t1 ON on_expr
+
+ SELECT * FROM t1,t2 RIGHT JOIN t3 ON on_expr =>
+ SELECT * FROM t1,t3 LEFT JOIN t2 ON on_expr
+
+ SELECT * FROM t1,t2 RIGHT JOIN (t3,t4) ON on_expr =>
+ SELECT * FROM t1,(t3,t4) LEFT JOIN t2 ON on_expr
+
+ SELECT * FROM t1 LEFT JOIN t2 ON on_expr1 RIGHT JOIN t3 ON on_expr2 =>
+ SELECT * FROM t3 LEFT JOIN (t1 LEFT JOIN t2 ON on_expr2) ON on_expr1
+
+ RETURN
+ Pointer to the table representing the inner table, if success
+ 0, otherwise
+*/
+
+TABLE_LIST *st_select_lex::convert_right_join()
+{
+ TABLE_LIST *tab2= join_list->pop();
+ TABLE_LIST *tab1= join_list->pop();
+ DBUG_ENTER("convert_right_join");
+
+ join_list->push_front(tab2);
+ join_list->push_front(tab1);
+ tab1->outer_join|= JOIN_TYPE_RIGHT;
+
+ DBUG_RETURN(tab1);
+}
+
+/*
Set lock for all tables in current select level
SYNOPSIS:
@@ -4808,9 +6170,9 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
DBUG_PRINT("enter", ("lock_type: %d for_update: %d", lock_type,
for_update));
- for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
- tables ;
- tables=tables->next)
+ for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first;
+ tables;
+ tables= tables->next_local)
{
tables->lock_type= lock_type;
tables->updating= for_update;
@@ -4827,7 +6189,7 @@ void add_join_on(TABLE_LIST *b,Item *expr)
b->on_expr=expr;
else
{
- // This only happens if you have both a right and left join
+ /* This only happens if you have both a right and left join */
b->on_expr=new Item_cond_and(b->on_expr,expr);
}
b->on_expr->top_level_item();
@@ -4842,7 +6204,7 @@ void add_join_on(TABLE_LIST *b,Item *expr)
add_join_natural()
a Table to do normal join with
b Do normal join with this table
-
+
IMPLEMENTATION
This function just marks that table b should be joined with a.
The function setup_cond() will create in b->on_expr a list
@@ -4889,8 +6251,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
{
acl_reload(thd);
grant_reload(thd);
- if (mqh_used)
- reset_mqh(thd,(LEX_USER *) NULL,TRUE);
+ reset_mqh((LEX_USER *)NULL, TRUE);
}
#endif
if (options & REFRESH_LOG)
@@ -4900,23 +6261,16 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
the slow query log, and the relay log (if it exists).
*/
- /*
+ /*
Writing this command to the binlog may result in infinite loops when doing
mysqlbinlog|mysql, and anyway it does not really make sense to log it
automatically (would cause more trouble to users than it would help them)
*/
tmp_write_to_binlog= 0;
mysql_log.new_file(1);
- mysql_update_log.new_file(1);
- mysql_bin_log.new_file(1);
mysql_slow_log.new_file(1);
+ mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
#ifdef HAVE_REPLICATION
- if (mysql_bin_log.is_open() && expire_logs_days)
- {
- long purge_time= time(0) - expire_logs_days*24*60*60;
- if (purge_time >= 0)
- mysql_bin_log.purge_logs_before_date(purge_time);
- }
pthread_mutex_lock(&LOCK_active_mi);
rotate_relay_log(active_mi);
pthread_mutex_unlock(&LOCK_active_mi);
@@ -4930,7 +6284,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
if (options & REFRESH_QUERY_CACHE_FREE)
{
query_cache.pack(); // FLUSH QUERY CACHE
- options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
+ options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
}
if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
{
@@ -4954,7 +6308,12 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
return 1;
result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
tables);
- make_global_read_lock_block_commit(thd);
+ if (make_global_read_lock_block_commit(thd))
+ {
+ /* Don't leave things in a half-locked state */
+ unlock_global_read_lock(thd);
+ return 1;
+ }
}
else
result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
@@ -4962,7 +6321,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
}
if (options & REFRESH_HOSTS)
hostname_cache_refresh();
- if (options & REFRESH_STATUS)
+ if (thd && (options & REFRESH_STATUS))
refresh_status();
if (options & REFRESH_THREADS)
flush_thread_cache();
@@ -4992,7 +6351,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
}
#endif
if (options & REFRESH_USER_RESOURCES)
- reset_mqh(thd,(LEX_USER *) NULL);
+ reset_mqh((LEX_USER *) NULL);
if (write_to_binlog)
*write_to_binlog= tmp_write_to_binlog;
return result;
@@ -5010,7 +6369,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
This is written such that we have a short lock on LOCK_thread_count
*/
-void kill_one_thread(THD *thd, ulong id)
+void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
{
THD *tmp;
uint error=ER_NO_SUCH_THREAD;
@@ -5030,7 +6389,7 @@ void kill_one_thread(THD *thd, ulong id)
if ((thd->master_access & SUPER_ACL) ||
!strcmp(thd->user,tmp->user))
{
- tmp->awake(1 /*prepare to die*/);
+ tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
error=0;
}
else
@@ -5041,7 +6400,7 @@ void kill_one_thread(THD *thd, ulong id)
if (!error)
send_ok(thd);
else
- net_printf(thd,error,id);
+ my_error(error, MYF(0), id);
}
@@ -5054,6 +6413,13 @@ static void refresh_status(void)
{
if (ptr->type == SHOW_LONG)
*(ulong*) ptr->value= 0;
+ else if (ptr->type == SHOW_LONG_STATUS)
+ {
+ THD *thd= current_thd;
+ /* We must update the global status before cleaning up the thread */
+ add_to_status(&global_status_var, &thd->status_var);
+ bzero((char*) &thd->status_var, sizeof(thd->status_var));
+ }
}
/* Reset the counters of all key caches (default and named). */
process_key_caches(reset_key_cache_counters);
@@ -5102,12 +6468,13 @@ static bool append_file_to_dir(THD *thd, const char **filename_ptr,
bool check_simple_select()
{
THD *thd= current_thd;
- if (thd->lex->current_select != &thd->lex->select_lex)
+ LEX *lex= thd->lex;
+ if (lex->current_select != &lex->select_lex)
{
char command[80];
- strmake(command, thd->lex->yylval->symbol.str,
- min(thd->lex->yylval->symbol.length, sizeof(command)-1));
- net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
+ strmake(command, lex->yylval->symbol.str,
+ min(lex->yylval->symbol.length, sizeof(command)-1));
+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
return 1;
}
return 0;
@@ -5124,18 +6491,16 @@ bool check_simple_select()
SYNOPSIS
check_multi_update_lock()
thd Current thread
- tables List of user-supplied tables
- fields List of fields requiring update
RETURN VALUES
0 ok
1 error
*/
-static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables,
- List<Item> *fields, SELECT_LEX *select_lex)
+static bool check_multi_update_lock(THD *thd)
{
bool res= 1;
- TABLE_LIST *table;
+ LEX *lex= thd->lex;
+ TABLE_LIST *table, *tables= lex->query_tables;
DBUG_ENTER("check_multi_update_lock");
if (check_db_used(thd, tables))
@@ -5145,18 +6510,18 @@ static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables,
Ensure that we have UPDATE or SELECT privilege for each table
The exact privilege is checked in mysql_multi_update()
*/
- for (table= tables ; table ; table= table->next)
+ for (table= tables ; table ; table= table->next_local)
{
- TABLE_LIST *save= table->next;
- table->next= 0;
+ TABLE_LIST *save= table->next_local;
+ table->next_local= 0;
if ((check_access(thd, UPDATE_ACL, table->db, &table->grant.privilege,0,1) ||
(grant_option && check_grant(thd, UPDATE_ACL, table,0,1,1))) &&
check_one_table_access(thd, SELECT_ACL, table))
goto error;
- table->next= save;
+ table->next_local= save;
}
- if (mysql_multi_update_lock(thd, tables, fields, select_lex))
+ if (mysql_multi_update_prepare(thd))
goto error;
res= 0;
@@ -5247,25 +6612,24 @@ Item * all_any_subquery_creator(Item *left_expr,
One should normally create all indexes with CREATE TABLE or ALTER TABLE.
*/
-int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
+bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
{
List<create_field> fields;
ALTER_INFO alter_info;
alter_info.flags= ALTER_ADD_INDEX;
- alter_info.is_simple= 0;
HA_CREATE_INFO create_info;
DBUG_ENTER("mysql_create_index");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
create_info.default_table_charset= thd->variables.collation_database;
- DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
+ DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
&create_info, table_list,
fields, keys, 0, (ORDER*)0,
- DUP_ERROR, 0, &alter_info));
+ DUP_ERROR, 0, &alter_info, 1));
}
-int mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
+bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
{
List<create_field> fields;
List<Key> keys;
@@ -5276,11 +6640,10 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
create_info.default_table_charset= thd->variables.collation_database;
alter_info->clear();
alter_info->flags= ALTER_DROP_INDEX;
- alter_info->is_simple= 0;
- DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
+ DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
&create_info, table_list,
fields, keys, 0, (ORDER*)0,
- DUP_ERROR, 0, alter_info));
+ DUP_ERROR, 0, alter_info, 1));
}
@@ -5290,33 +6653,31 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
SYNOPSIS
multi_update_precheck()
thd Thread handler
- tables Global table list
+ tables Global/local table list (have to be the same)
RETURN VALUE
- 0 OK
- 1 Error (message is sent to user)
- -1 Error (message is not sent to user)
+ FALSE OK
+ TRUE Error
*/
-int multi_update_precheck(THD *thd, TABLE_LIST *tables)
+bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
{
- DBUG_ENTER("multi_update_precheck");
const char *msg= 0;
TABLE_LIST *table;
LEX *lex= thd->lex;
SELECT_LEX *select_lex= &lex->select_lex;
- TABLE_LIST *update_list= (TABLE_LIST*)select_lex->table_list.first;
+ DBUG_ENTER("multi_update_precheck");
if (select_lex->item_list.elements != lex->value_list.elements)
{
- my_error(ER_WRONG_VALUE_COUNT, MYF(0));
- DBUG_RETURN(-1);
+ my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
+ DBUG_RETURN(TRUE);
}
/*
Ensure that we have UPDATE or SELECT privilege for each table
The exact privilege is checked in mysql_multi_update()
*/
- for (table= update_list; table; table= table->next)
+ for (table= tables; table; table= table->next_local)
{
if (table->derived)
table->grant.privilege= SELECT_ACL;
@@ -5324,17 +6685,12 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables)
&table->grant.privilege, 0, 1) ||
grant_option &&
check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
- (check_access(thd, SELECT_ACL, table->db,
- &table->grant.privilege, 0, 0) ||
- grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
- DBUG_RETURN(1);
+ (check_access(thd, SELECT_ACL, table->db,
+ &table->grant.privilege, 0, 0) ||
+ grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
+ DBUG_RETURN(TRUE);
- /*
- We assign following flag only to copy of table, because it will
- be checked only if query contains subqueries i.e. only if copy exists
- */
- if (table->table_list)
- table->table_list->table_in_update_from_clause= 1;
+ table->table_in_first_from_clause= 1;
}
/*
Is there tables of subqueries?
@@ -5342,27 +6698,16 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables)
if (&lex->select_lex != lex->all_selects_list)
{
DBUG_PRINT("info",("Checking sub query list"));
- for (table= tables; table; table= table->next)
+ for (table= tables; table; table= table->next_global)
{
- if (my_tz_check_n_skip_implicit_tables(&table,
- lex->time_zone_tables_used))
- continue;
- else if (table->table_in_update_from_clause)
- {
- /*
- If we check table by local TABLE_LIST copy then we should copy
- grants to global table list, because it will be used for table
- opening.
- */
- if (table->table_list)
- table->grant= table->table_list->grant;
- }
- else if (!table->derived)
+ if (!my_tz_check_n_skip_implicit_tables(&table,
+ lex->time_zone_tables_used) &&
+ !table->table_in_first_from_clause)
{
if (check_access(thd, SELECT_ACL, table->db,
&table->grant.privilege, 0, 0) ||
grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
}
}
@@ -5375,9 +6720,9 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables)
if (msg)
{
my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
/*
@@ -5386,23 +6731,21 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables)
SYNOPSIS
multi_delete_precheck()
thd Thread handler
- tables Global table list
+ tables Global/local table list
table_count Pointer to table counter
RETURN VALUE
- 0 OK
- 1 error (message is sent to user)
- -1 error (message is not sent to user)
+ FALSE OK
+ TRUE error
*/
-int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
+bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
{
- DBUG_ENTER("multi_delete_precheck");
SELECT_LEX *select_lex= &thd->lex->select_lex;
TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
- TABLE_LIST *delete_tables= (TABLE_LIST *)select_lex->table_list.first;
TABLE_LIST *target_tbl;
+ DBUG_ENTER("multi_delete_precheck");
*table_count= 0;
@@ -5411,18 +6754,19 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
check_table_access(thd,SELECT_ACL, tables,0) ||
check_table_access(thd,DELETE_ACL, aux_tables,0))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
{
- my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, MYF(0));
- DBUG_RETURN(-1);
+ my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
+ ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
+ DBUG_RETURN(TRUE);
}
- for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next)
+ for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next_local)
{
(*table_count)++;
/* All tables in aux_tables must be found in FROM PART */
TABLE_LIST *walk;
- for (walk= delete_tables; walk; walk= walk->next)
+ for (walk= tables; walk; walk= walk->next_local)
{
if (!my_strcasecmp(table_alias_charset,
target_tbl->alias, walk->alias) &&
@@ -5431,28 +6775,22 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
}
if (!walk)
{
- my_error(ER_UNKNOWN_TABLE, MYF(0), target_tbl->real_name,
- "MULTI DELETE");
- DBUG_RETURN(-1);
- }
- if (walk->derived)
- {
- my_error(ER_NON_UPDATABLE_TABLE, MYF(0), target_tbl->real_name,
- "DELETE");
- DBUG_RETURN(-1);
+ my_error(ER_UNKNOWN_TABLE, MYF(0),
+ target_tbl->table_name, "MULTI DELETE");
+ DBUG_RETURN(TRUE);
}
walk->lock_type= target_tbl->lock_type;
- target_tbl->table_list= walk; // Remember corresponding table
+ target_tbl->correspondent_table= walk; // Remember corresponding table
/* in case of subselects, we need to set lock_type in
* corresponding table in list of all tables */
- if (walk->table_list)
+ if (walk->correspondent_table)
{
- target_tbl->table_list= walk->table_list;
- walk->table_list->lock_type= walk->lock_type;
+ target_tbl->correspondent_table= walk->correspondent_table;
+ walk->correspondent_table->lock_type= walk->lock_type;
}
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -5465,21 +6803,20 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
tables Global table list
RETURN VALUE
- 0 OK
- 1 Error (message is sent to user)
- -1 Error (message is not sent to user)
+ FALSE OK
+ TRUE Error
*/
-int update_precheck(THD *thd, TABLE_LIST *tables)
+bool update_precheck(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("update_precheck");
if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
{
- my_error(ER_WRONG_VALUE_COUNT, MYF(0));
- DBUG_RETURN(-1);
+ my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN((check_db_used(thd, tables) ||
- check_one_table_access(thd, UPDATE_ACL, tables)) ? 1 : 0);
+ DBUG_RETURN(check_db_used(thd, tables) ||
+ check_one_table_access(thd, UPDATE_ACL, tables));
}
@@ -5492,19 +6829,18 @@ int update_precheck(THD *thd, TABLE_LIST *tables)
tables Global table list
RETURN VALUE
- 0 OK
- 1 error (message is sent to user)
- -1 error (message is not sent to user)
+ FALSE OK
+ TRUE error
*/
-int delete_precheck(THD *thd, TABLE_LIST *tables)
+bool delete_precheck(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("delete_precheck");
if (check_one_table_access(thd, DELETE_ACL, tables))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
/* Set privilege for the WHERE clause */
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -5517,12 +6853,11 @@ int delete_precheck(THD *thd, TABLE_LIST *tables)
tables Global table list
RETURN VALUE
- 0 OK
- 1 error (message is sent to user)
- -1 error (message is not sent to user)
+ FALSE OK
+ TRUE error
*/
-int insert_precheck(THD *thd, TABLE_LIST *tables)
+bool insert_precheck(THD *thd, TABLE_LIST *tables)
{
LEX *lex= thd->lex;
DBUG_ENTER("insert_precheck");
@@ -5531,19 +6866,19 @@ int insert_precheck(THD *thd, TABLE_LIST *tables)
Check that we have modify privileges for the first table and
select privileges for the rest
*/
- ulong privilege= INSERT_ACL |
- (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
- (lex->duplicates == DUP_UPDATE ? UPDATE_ACL : 0);
+ ulong privilege= (INSERT_ACL |
+ (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
+ (lex->value_list.elements ? UPDATE_ACL : 0));
if (check_one_table_access(thd, privilege, tables))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
if (lex->update_list.elements != lex->value_list.elements)
{
- my_error(ER_WRONG_VALUE_COUNT, MYF(0));
- DBUG_RETURN(-1);
+ my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -5557,17 +6892,17 @@ int insert_precheck(THD *thd, TABLE_LIST *tables)
create_table Table which will be created
RETURN VALUE
- 0 OK
- 1 Error (message is sent to user)
+ FALSE OK
+ TRUE Error
*/
-int create_table_precheck(THD *thd, TABLE_LIST *tables,
- TABLE_LIST *create_table)
+bool create_table_precheck(THD *thd, TABLE_LIST *tables,
+ TABLE_LIST *create_table)
{
LEX *lex= thd->lex;
SELECT_LEX *select_lex= &lex->select_lex;
ulong want_priv;
- int error= 1; // Error message is given
+ bool error= TRUE; // Error message is given
DBUG_ENTER("create_table_precheck");
want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
@@ -5588,37 +6923,27 @@ int create_table_precheck(THD *thd, TABLE_LIST *tables,
/* Check permissions for used tables in CREATE TABLE ... SELECT */
/*
- For temporary tables or PREPARED STATEMETNS we don't have to check
- if the created table exists
+ Only do the check for PS, becasue we on execute we have to check that
+ against the opened tables to ensure we don't use a table that is part
+ of the view (which can only be done after the table has been opened).
*/
- if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
- ! thd->current_arena->is_stmt_prepare() &&
- find_real_table_in_list(tables, create_table->db,
- create_table->real_name))
- {
- net_printf(thd,ER_UPDATE_TABLE_USED, create_table->real_name);
-
- goto err;
- }
- if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
+ if (thd->current_arena->is_stmt_prepare())
{
- TABLE_LIST *tab;
- for (tab= tables; tab; tab= tab->next)
+ /*
+ For temporary tables we don't have to check if the created table exists
+ */
+ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
+ find_table_in_global_list(tables, create_table->db,
+ create_table->table_name))
{
- if (find_real_table_in_list((TABLE_LIST*) lex->create_info.
- merge_list.first,
- tables->db, tab->real_name))
- {
- net_printf(thd, ER_UPDATE_TABLE_USED, tab->real_name);
- goto err;
- }
- }
- }
-
+ error= FALSE;
+ goto err;
+ }
+ }
if (tables && check_table_access(thd, SELECT_ACL, tables,0))
goto err;
}
- error= 0;
+ error= FALSE;
err:
DBUG_RETURN(error);
@@ -5630,7 +6955,7 @@ err:
SYNOPSIS
negate_expression()
- thd therad handler
+ thd thread handler
expr expression for negation
RETURN