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.cc3251
1 files changed, 1349 insertions, 1902 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 084bcfc3c76..ae347bebb47 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -16,41 +16,22 @@
#define MYSQL_LEX 1
#include "mysql_priv.h"
#include "sql_repl.h"
+#include "rpl_filter.h"
#include "repl_failsafe.h"
#include <m_ctype.h>
#include <myisam.h>
#include <my_dir.h>
-#ifdef HAVE_INNOBASE_DB
-#include "ha_innodb.h"
-#endif
-
-#ifdef HAVE_NDBCLUSTER_DB
-#include "ha_ndbcluster.h"
-#endif
-
#include "sp_head.h"
#include "sp.h"
#include "sp_cache.h"
+#include "events.h"
#include "sql_trigger.h"
-#ifdef HAVE_OPENSSL
-/*
- Without SSL the handshake consists of one packet. This packet
- has both client capabilites and scrambled password.
- With SSL the handshake might consist of two packets. If the first
- packet (client capabilities) has CLIENT_SSL flag set, we have to
- switch to SSL and read the second packet. The scrambled password
- is in the second packet and client_capabilites field will be ignored.
- Maybe it is better to accept flags other than CLIENT_SSL from the
- second packet?
+/**
+ @defgroup Runtime_Environment Runtime Environment
+ @{
*/
-#define SSL_HANDSHAKE_SIZE 2
-#define NORMAL_HANDSHAKE_SIZE 6
-#define MIN_HANDSHAKE_SIZE 2
-#else
-#define MIN_HANDSHAKE_SIZE 6
-#endif /* HAVE_OPENSSL */
/* Used in error handling only */
#define SP_TYPE_STRING(LP) \
@@ -62,55 +43,49 @@
(LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
"FUNCTION" : "PROCEDURE")
-#ifdef SOLARIS
-extern "C" int gethostname(char *name, int namelen);
-#endif
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-static void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
-static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
-static void decrease_user_connections(USER_CONN *uc);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-static bool check_db_used(THD *thd,TABLE_LIST *tables);
-static void remove_escape(char *name);
-static bool append_file_to_dir(THD *thd, const char **filename_ptr,
- const char *table_name);
+static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
static bool check_show_create_table_access(THD *thd, TABLE_LIST *table);
const char *any_db="*any*"; // Special symbol for check_access
-const char *command_name[]={
- "Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
- "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
- "Connect","Kill","Debug","Ping","Time","Delayed insert","Change user",
- "Binlog Dump","Table Dump", "Connect Out", "Register Slave",
- "Prepare", "Execute", "Long Data", "Close stmt",
- "Reset stmt", "Set option", "Fetch",
- "Error" // Last command number
+const LEX_STRING command_name[]={
+ { C_STRING_WITH_LEN("Sleep") },
+ { C_STRING_WITH_LEN("Quit") },
+ { C_STRING_WITH_LEN("Init DB") },
+ { C_STRING_WITH_LEN("Query") },
+ { C_STRING_WITH_LEN("Field List") },
+ { C_STRING_WITH_LEN("Create DB") },
+ { C_STRING_WITH_LEN("Drop DB") },
+ { C_STRING_WITH_LEN("Refresh") },
+ { C_STRING_WITH_LEN("Shutdown") },
+ { C_STRING_WITH_LEN("Statistics") },
+ { C_STRING_WITH_LEN("Processlist") },
+ { C_STRING_WITH_LEN("Connect") },
+ { C_STRING_WITH_LEN("Kill") },
+ { C_STRING_WITH_LEN("Debug") },
+ { C_STRING_WITH_LEN("Ping") },
+ { C_STRING_WITH_LEN("Time") },
+ { C_STRING_WITH_LEN("Delayed insert") },
+ { C_STRING_WITH_LEN("Change user") },
+ { C_STRING_WITH_LEN("Binlog Dump") },
+ { C_STRING_WITH_LEN("Table Dump") },
+ { C_STRING_WITH_LEN("Connect Out") },
+ { C_STRING_WITH_LEN("Register Slave") },
+ { C_STRING_WITH_LEN("Prepare") },
+ { C_STRING_WITH_LEN("Execute") },
+ { C_STRING_WITH_LEN("Long Data") },
+ { C_STRING_WITH_LEN("Close stmt") },
+ { C_STRING_WITH_LEN("Reset stmt") },
+ { C_STRING_WITH_LEN("Set option") },
+ { C_STRING_WITH_LEN("Fetch") },
+ { C_STRING_WITH_LEN("Daemon") },
+ { C_STRING_WITH_LEN("Error") } // Last command number
};
const char *xa_state_names[]={
"NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
};
-#ifdef __WIN__
-static void test_signal(int sig_ptr)
-{
-#if !defined( DBUG_OFF)
- MessageBox(NULL,"Test signal","DBUG",MB_OK);
-#endif
-#if defined(OS2)
- fprintf(stderr, "Test signal %d\n", sig_ptr);
- fflush(stderr);
-#endif
-}
-static void init_signals(void)
-{
- int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
- for (int i=0 ; i < 7 ; i++)
- signal( signals[i], test_signal) ;
-}
-#endif
static void unlock_locked_tables(THD *thd)
{
@@ -123,7 +98,7 @@ static void unlock_locked_tables(THD *thd)
}
-static bool end_active_trans(THD *thd)
+bool end_active_trans(THD *thd)
{
int error=0;
DBUG_ENTER("end_active_trans");
@@ -148,13 +123,14 @@ static bool end_active_trans(THD *thd)
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (ha_commit(thd))
error=1;
- thd->options&= ~(ulong) OPTION_BEGIN;
- thd->transaction.all.modified_non_trans_table= FALSE;
}
+ thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= FALSE;
DBUG_RETURN(error);
}
-static bool begin_trans(THD *thd)
+
+bool begin_trans(THD *thd)
{
int error=0;
if (unlikely(thd->in_sub_stmt))
@@ -173,8 +149,7 @@ static bool begin_trans(THD *thd)
else
{
LEX *lex= thd->lex;
- thd->transaction.all.modified_non_trans_table= FALSE;
- thd->options|= (ulong) OPTION_BEGIN;
+ thd->options|= 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);
@@ -188,7 +163,8 @@ static bool begin_trans(THD *thd)
*/
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
{
- return table_rules_on && tables && !tables_ok(thd,tables);
+ return rpl_filter->is_on() && tables && !thd->spcont &&
+ !rpl_filter->tables_ok(thd->db, tables);
}
#endif
@@ -205,410 +181,6 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables)
return 0;
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-static HASH hash_user_connections;
-
-static int get_or_create_user_conn(THD *thd, const char *user,
- const char *host,
- USER_RESOURCES *mqh)
-{
- int return_val= 0;
- uint temp_len, user_len;
- char temp_user[USER_HOST_BUFF_SIZE];
- struct user_conn *uc;
-
- DBUG_ASSERT(user != 0);
- DBUG_ASSERT(host != 0);
-
- user_len= strlen(user);
- temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
- (void) pthread_mutex_lock(&LOCK_user_conn);
- if (!(uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len)))
- {
- /* First connection for user; Create a user connection object */
- if (!(uc= ((struct user_conn*)
- my_malloc(sizeof(struct user_conn) + temp_len+1,
- MYF(MY_WME)))))
- {
- 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->host= uc->user + user_len + 1;
- uc->len= temp_len;
- uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
- uc->user_resources= *mqh;
- uc->intime= thd->thr_create_time;
- if (my_hash_insert(&hash_user_connections, (byte*) uc))
- {
- my_free((char*) uc,0);
- net_send_error(thd, 0, NullS); // Out of memory
- return_val= 1;
- goto end;
- }
- }
- thd->user_connect=uc;
- uc->connections++;
-end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- return return_val;
-
-}
-#endif /* !NO_EMBEDDED_ACCESS_CHECKS */
-
-
-/*
- Check if user exist and password supplied is correct.
-
- SYNOPSIS
- check_user()
- thd thread handle, thd->security_ctx->{host,user,ip} are used
- command originator of the check: now check_user is called
- during connect and change user procedures; used for
- logging.
- 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 depend on that, but future changes
- should be done with this in mind; 'thd' is INOUT, all other params
- are 'IN'.
-
- RETURN VALUE
- 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and
- thd->db are updated; OK is sent to client;
- -1 access denied or handshake error; error is sent to client;
- >0 error, not sent to client
-*/
-
-int check_user(THD *thd, enum enum_server_command command,
- const char *passwd, uint passwd_len, const char *db,
- bool check_count)
-{
- DBUG_ENTER("check_user");
- LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 };
-
-#ifdef NO_EMBEDDED_ACCESS_CHECKS
- thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights
- /* Change database if necessary */
- if (db && db[0])
- {
- /*
- thd->db is saved in caller and needs to be freed by caller if this
- function returns 0
- */
- thd->reset_db(NULL, 0);
- if (mysql_change_db(thd, &db_str, FALSE))
- {
- /* Send the error to the client */
- net_send_error(thd);
- DBUG_RETURN(-1);
- }
- }
- send_ok(thd);
- DBUG_RETURN(0);
-#else
-
- my_bool opt_secure_auth_local;
- pthread_mutex_lock(&LOCK_global_system_variables);
- opt_secure_auth_local= opt_secure_auth;
- pthread_mutex_unlock(&LOCK_global_system_variables);
-
- /*
- If the server is running in secure auth mode, short scrambles are
- forbidden.
- */
- if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
- {
- net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
- mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
- DBUG_RETURN(-1);
- }
- if (passwd_len != 0 &&
- passwd_len != SCRAMBLE_LENGTH &&
- passwd_len != SCRAMBLE_LENGTH_323)
- DBUG_RETURN(ER_HANDSHAKE_ERROR);
-
- /*
- Clear thd->db as it points to something, that will be freed when
- 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'.
- */
- thd->reset_db(NULL, 0);
-
- USER_RESOURCES ur;
- int res= acl_getroot(thd, &ur, passwd, passwd_len);
-#ifndef EMBEDDED_LIBRARY
- if (res == -1)
- {
- /*
- This happens when client (new) sends password scrambled with
- scramble(), but database holds old value (scrambled with
- scramble_323()). Here we please client to send scrambled_password
- in old format.
- */
- NET *net= &thd->net;
- if (opt_secure_auth_local)
- {
- net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip);
- mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
- thd->main_security_ctx.user,
- thd->main_security_ctx.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)
- {
- inc_host_errors(&thd->remote.sin_addr);
- DBUG_RETURN(ER_HANDSHAKE_ERROR);
- }
- /* Final attempt to check the user based on reply */
- /* So as passwd is short, errcode is always >= 0 */
- res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
- }
-#endif /*EMBEDDED_LIBRARY*/
- /* here res is always >= 0 */
- if (res == 0)
- {
- if (!(thd->main_security_ctx.master_access &
- NO_ACCESS)) // authentication is OK
- {
- DBUG_PRINT("info",
- ("Capabilities: %lu packet_length: %ld Host: '%s' "
- "Login user: '%s' Priv_user: '%s' Using password: %s "
- "Access: %lu db: '%s'",
- thd->client_capabilities,
- thd->max_client_packet_length,
- thd->main_security_ctx.host_or_ip,
- thd->main_security_ctx.user,
- thd->main_security_ctx.priv_user,
- passwd_len ? "yes": "no",
- thd->main_security_ctx.master_access,
- (thd->db ? thd->db : "*none*")));
-
- if (check_count)
- {
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- bool count_ok= thread_count <= max_connections + delayed_insert_threads
- || (thd->main_security_ctx.master_access & SUPER_ACL);
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- if (!count_ok)
- { // too many connections
- net_send_error(thd, ER_CON_COUNT_ERROR);
- DBUG_RETURN(-1);
- }
- }
-
- /* Why logging is performed before all checks've passed? */
- mysql_log.write(thd, command,
- (thd->main_security_ctx.priv_user ==
- thd->main_security_ctx.user ?
- (char*) "%s@%s on %s" :
- (char*) "%s@%s as anonymous on %s"),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- db ? db : (char*) "");
-
- /*
- This is the default access rights for the current database. It's
- set to 0 here because we don't have an active database yet (and we
- may not have an active database to set.
- */
- thd->main_security_ctx.db_access=0;
-
- /* Don't allow user to connect if he has done too many queries */
- if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
- max_user_connections) &&
- get_or_create_user_conn(thd,
- (opt_old_style_user_limits ? thd->main_security_ctx.user :
- thd->main_security_ctx.priv_user),
- (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
- thd->main_security_ctx.priv_host),
- &ur))
- DBUG_RETURN(-1);
- if (thd->user_connect &&
- (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 */
- if (db && db[0])
- {
- if (mysql_change_db(thd, &db_str, FALSE))
- {
- /* Send error to the client */
- net_send_error(thd);
- if (thd->user_connect)
- decrease_user_connections(thd->user_connect);
- DBUG_RETURN(-1);
- }
- }
- send_ok(thd);
- thd->password= test(passwd_len); // remember for error messages
- /* Ready to handle queries */
- DBUG_RETURN(0);
- }
- }
- else if (res == 2) // client gave short hash, server has long hash
- {
- 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_error(thd, ER_ACCESS_DENIED_ERROR,
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- passwd_len ? ER(ER_YES) : ER(ER_NO));
- mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- passwd_len ? ER(ER_YES) : ER(ER_NO));
- DBUG_RETURN(-1);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-/*
- Check for maximum allowable user connections, if the mysqld server is
- started with corresponding variable that is greater then 0.
-*/
-
-extern "C" byte *get_key_conn(user_conn *buff, uint *length,
- my_bool not_used __attribute__((unused)))
-{
- *length=buff->len;
- return (byte*) buff->user;
-}
-
-extern "C" void free_user(struct user_conn *uc)
-{
- my_free((char*) uc,MYF(0));
-}
-
-void init_max_user_conn(void)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
- 0,0,
- (hash_get_key) get_key_conn, (hash_free_key) free_user,
- 0);
-#endif
-}
-
-
-/*
- check if user has already too many connections
-
- SYNOPSIS
- check_for_max_user_connections()
- thd Thread handle
- uc User connect object
-
- NOTES
- If check fails, we decrease user connection count, which means one
- shouldn't call decrease_user_connections() after this function.
-
- RETURN
- 0 ok
- 1 error
-*/
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-
-static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
-{
- int error=0;
- DBUG_ENTER("check_for_max_user_connections");
-
- (void) pthread_mutex_lock(&LOCK_user_conn);
- if (max_user_connections && !uc->user_resources.user_conn &&
- max_user_connections < (uint) uc->connections)
- {
- 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.user_conn &&
- uc->user_resources.user_conn < uc->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;
- }
- uc->conn_per_hour++;
-
- end:
- if (error)
- uc->connections--; // no need for decrease_user_connections() here
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- DBUG_RETURN(error);
-}
-
-/*
- Decrease user connection count
-
- SYNOPSIS
- decrease_user_connections()
- uc User connection object
-
- NOTES
- If there is a n user connection object for a connection
- (which only happens if 'max_user_connections' is defined or
- if someone has created a resource grant for a user), then
- the connection count is always incremented on connect.
-
- The user connect object is not freed if some users has
- 'max connections per hour' defined as we need to be able to hold
- count over the lifetime of the connection.
-*/
-
-static void decrease_user_connections(USER_CONN *uc)
-{
- DBUG_ENTER("decrease_user_connections");
- (void) pthread_mutex_lock(&LOCK_user_conn);
- DBUG_ASSERT(uc->connections);
- if (!--uc->connections && !mqh_used)
- {
- /* Last connection for user; Delete it */
- (void) hash_delete(&hash_user_connections,(byte*) uc);
- }
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- DBUG_VOID_RETURN;
-}
-
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-
-
-void free_max_user_conn(void)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- hash_free(&hash_user_connections);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-
/*
Mark all commands that somehow changes a table
@@ -617,445 +189,125 @@ 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
+ See COMMAND_FLAG_xxx for different type of commands
2 - query that returns meaningful ROW_COUNT() -
a number of modified rows
*/
-char uc_update_queries[SQLCOM_END+1];
+uint sql_command_flags[SQLCOM_END+1];
void init_update_queries(void)
{
- bzero((gptr) &uc_update_queries, sizeof(uc_update_queries));
-
- 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]=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]=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_DROP_INDEX]=1;
- uc_update_queries[SQLCOM_CREATE_VIEW]=1;
- uc_update_queries[SQLCOM_DROP_VIEW]=1;
-}
-
-bool is_update_query(enum enum_sql_command command)
-{
- DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
- return uc_update_queries[command] != 0;
-}
-
-/*
- Reset per-hour user resource limits when it has been more than
- an hour since they were last checked
-
- SYNOPSIS:
- time_out_user_resource_limits()
- thd Thread handler
- uc User connection details
-
- NOTE:
- This assumes that the LOCK_user_conn mutex has been acquired, so it is
- safe to test and modify members of the USER_CONN structure.
-*/
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-
-static void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
-{
- time_t check_time = thd->start_time ? thd->start_time : time(NULL);
- DBUG_ENTER("time_out_user_resource_limits");
-
- /* If more than a hour since last check, reset resource checking */
- if (check_time - uc->intime >= 3600)
- {
- uc->questions=1;
- uc->updates=0;
- uc->conn_per_hour=0;
- uc->intime=check_time;
- }
-
- DBUG_VOID_RETURN;
-}
+ bzero((uchar*) &sql_command_flags, sizeof(sql_command_flags));
+
+ sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
+ sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
+ sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_BACKUP_TABLE]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_RESTORE_TABLE]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA;
+
+ sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
+ sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
+ sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
+ sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
+ sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
+ sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
+ sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
+ sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
+
+ sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_DATABASES]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_TRIGGERS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_EVENTS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_OPEN_TABLES]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_PLUGINS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_FIELDS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_KEYS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_VARIABLES]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_CHARSETS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_COLLATIONS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_NEW_MASTER]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_BINLOGS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_SLAVE_HOSTS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_BINLOG_EVENTS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_COLUMN_TYPES]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_STORAGE_ENGINES]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_AUTHORS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_CONTRIBUTORS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_PRIVILEGES]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_WARNS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_ERRORS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_ENGINE_STATUS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_ENGINE_MUTEX]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_ENGINE_LOGS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_PROCESSLIST]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_GRANTS]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_CREATE_DB]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_PROC_CODE]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_FUNC_CODE]= CF_STATUS_COMMAND;
+ sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]= CF_STATUS_COMMAND;
+
+ sql_command_flags[SQLCOM_SHOW_TABLES]= (CF_STATUS_COMMAND |
+ CF_SHOW_TABLE_COMMAND);
+ sql_command_flags[SQLCOM_SHOW_TABLE_STATUS]= (CF_STATUS_COMMAND |
+ CF_SHOW_TABLE_COMMAND);
-/*
- Check if maximum queries per hour limit has been reached
- returns 0 if OK.
-*/
-
-static bool check_mqh(THD *thd, uint check_command)
-{
- bool error= 0;
- USER_CONN *uc=thd->user_connect;
- DBUG_ENTER("check_mqh");
- DBUG_ASSERT(uc != 0);
-
- (void) pthread_mutex_lock(&LOCK_user_conn);
-
- time_out_user_resource_limits(thd, uc);
-
- /* Check that we have not done too many questions / hour */
- if (uc->user_resources.questions &&
- uc->questions++ >= 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;
- }
- if (check_command < (uint) SQLCOM_END)
- {
- /* Check that we have not done too many updates / hour */
- if (uc->user_resources.updates && uc_update_queries[check_command] &&
- uc->updates++ >= 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;
- }
- }
-end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- DBUG_RETURN(error);
-}
-
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-
-
-static void reset_mqh(LEX_USER *lu, bool get_them= 0)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- (void) pthread_mutex_lock(&LOCK_user_conn);
- if (lu) // for GRANT
- {
- USER_CONN *uc;
- uint temp_len=lu->user.length+lu->host.length+2;
- char temp_user[USER_HOST_BUFF_SIZE];
-
- memcpy(temp_user,lu->user.str,lu->user.length);
- memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
- temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
- if ((uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len)))
- {
- uc->questions=0;
- get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
- uc->updates=0;
- uc->conn_per_hour=0;
- }
- }
- 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,
- idx);
- if (get_them)
- get_mqh(uc->user,uc->host,uc);
- uc->questions=0;
- uc->updates=0;
- uc->conn_per_hour=0;
- }
- }
- (void) pthread_mutex_unlock(&LOCK_user_conn);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
+ /*
+ The following is used to preserver CF_ROW_COUNT during the
+ a CALL or EXECUTE statement, so the value generated by the
+ last called (or executed) statement is preserved.
+ See mysql_execute_command() for how CF_ROW_COUNT is used.
+ */
+ sql_command_flags[SQLCOM_CALL]= CF_HAS_ROW_COUNT;
+ sql_command_flags[SQLCOM_EXECUTE]= CF_HAS_ROW_COUNT;
-void thd_init_client_charset(THD *thd, uint cs_number)
-{
/*
- Use server character set and collation if
- - opt_character_set_client_handshake is not set
- - client has not specified a character set
- - client character set is the same as the servers
- - client character set doesn't exists in server
+ The following admin table operations are allowed
+ on log tables.
*/
- if (!opt_character_set_client_handshake ||
- !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
- !my_strcasecmp(&my_charset_latin1,
- global_system_variables.character_set_client->name,
- thd->variables.character_set_client->name))
- {
- thd->variables.character_set_client=
- global_system_variables.character_set_client;
- thd->variables.collation_connection=
- global_system_variables.collation_connection;
- thd->variables.character_set_results=
- global_system_variables.character_set_results;
- }
- else
- {
- thd->variables.character_set_results=
- thd->variables.collation_connection=
- thd->variables.character_set_client;
- }
+ sql_command_flags[SQLCOM_REPAIR]= CF_WRITE_LOGS_COMMAND;
+ sql_command_flags[SQLCOM_OPTIMIZE]= CF_WRITE_LOGS_COMMAND;
+ sql_command_flags[SQLCOM_ANALYZE]= CF_WRITE_LOGS_COMMAND;
}
-/*
- Perform handshake, authorize client and update thd ACL variables.
- SYNOPSIS
- check_connection()
- thd thread handle
+bool is_update_query(enum enum_sql_command command)
+{
+ DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
+ return (sql_command_flags[command] & CF_CHANGES_DATA) != 0;
+}
- RETURN
- 0 success, OK is sent to user, thd is updated.
- -1 error, which is sent to user
- > 0 error code (not sent to user)
+/**
+ Check if a sql command is allowed to write to log tables.
+ @param command The SQL command
+ @return true if writing is allowed
*/
-
-#ifndef EMBEDDED_LIBRARY
-static int check_connection(THD *thd)
+bool is_log_table_write_query(enum enum_sql_command command)
{
- uint connect_errors= 0;
- NET *net= &thd->net;
- ulong pkt_len= 0;
- char *end;
-
- DBUG_PRINT("info",
- ("New connection received on %s", vio_description(net->vio)));
-#ifdef SIGNAL_WITH_VIO_CLOSE
- thd->set_active_vio(net->vio);
-#endif
-
- if (!thd->main_security_ctx.host) // If TCP/IP connection
- {
- char ip[30];
-
- if (vio_peer_addr(net->vio, ip, &thd->peer_port))
- return (ER_BAD_HOST_ERROR);
- if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
- return (ER_OUT_OF_RESOURCES);
- thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
- vio_in_addr(net->vio,&thd->remote.sin_addr);
- if (!(specialflag & SPECIAL_NO_RESOLVE))
- {
- vio_in_addr(net->vio,&thd->remote.sin_addr);
- thd->main_security_ctx.host=
- ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
- /* Cut very long hostnames to avoid possible overflows */
- if (thd->main_security_ctx.host)
- {
- if (thd->main_security_ctx.host != my_localhost)
- thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
- HOSTNAME_LENGTH)]= 0;
- thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
- }
- if (connect_errors > max_connect_errors)
- return(ER_HOST_IS_BLOCKED);
- }
- DBUG_PRINT("info",("Host: %s ip: %s",
- (thd->main_security_ctx.host ?
- thd->main_security_ctx.host : "unknown host"),
- (thd->main_security_ctx.ip ?
- thd->main_security_ctx.ip : "unknown ip")));
- if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
- return(ER_HOST_NOT_PRIVILEGED);
- }
- else /* Hostname given means that the connection was on a socket */
- {
- DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
- thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
- thd->main_security_ctx.ip= 0;
- /* Reset sin_addr */
- bzero((char*) &thd->remote, sizeof(thd->remote));
- }
- vio_keepalive(net->vio, TRUE);
- {
- /* buff[] needs to big enough to hold the server_version variable */
- char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
- ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
- CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
-
- if (opt_using_transactions)
- client_flags|=CLIENT_TRANSACTIONS;
-#ifdef HAVE_COMPRESS
- client_flags |= CLIENT_COMPRESS;
-#endif /* HAVE_COMPRESS */
-#ifdef HAVE_OPENSSL
- if (ssl_acceptor_fd)
- client_flags |= CLIENT_SSL; /* Wow, SSL is available! */
-#endif /* HAVE_OPENSSL */
-
- end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
- int4store((uchar*) end, thd->thread_id);
- end+= 4;
- /*
- So as check_connection is the only entry point to authorization
- procedure, scramble is set here. This gives us new scramble for
- each handshake.
- */
- create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
- /*
- Old clients does not understand long scrambles, but can ignore packet
- tail: that's why first part of the scramble is placed here, and second
- part at the end of packet.
- */
- end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
-
- int2store(end, client_flags);
- /* write server characteristics: up to 16 bytes allowed */
- end[2]=(char) default_charset_info->number;
- int2store(end+3, thd->server_status);
- bzero(end+5, 13);
- end+= 18;
- /* write scramble tail */
- end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323,
- SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
-
- /* At this point we write connection message and read reply */
- if (net_write_command(net, (uchar) protocol_version, "", 0, buff,
- (uint) (end-buff)) ||
- (pkt_len= my_net_read(net)) == packet_error ||
- pkt_len < MIN_HANDSHAKE_SIZE)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
- }
-#ifdef _CUSTOMCONFIG_
-#include "_cust_sql_parse.h"
-#endif
- if (connect_errors)
- reset_host_errors(&thd->remote.sin_addr);
- if (thd->packet.alloc(thd->variables.net_buffer_length))
- return(ER_OUT_OF_RESOURCES);
-
- thd->client_capabilities=uint2korr(net->read_pos);
- if (thd->client_capabilities & CLIENT_PROTOCOL_41)
- {
- thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
- thd->max_client_packet_length= uint4korr(net->read_pos+4);
- DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
- thd_init_client_charset(thd, (uint) net->read_pos[8]);
- thd->update_charset();
- end= (char*) net->read_pos+32;
- }
- else
- {
- thd->max_client_packet_length= uint3korr(net->read_pos+2);
- end= (char*) net->read_pos+5;
- }
-
- if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
- thd->variables.sql_mode|= MODE_IGNORE_SPACE;
-#ifdef HAVE_OPENSSL
- DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
- if (thd->client_capabilities & CLIENT_SSL)
- {
- /* Do the SSL layering. */
- if (!ssl_acceptor_fd)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
- DBUG_PRINT("info", ("IO layer change in progress..."));
- if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout))
- {
- DBUG_PRINT("error", ("Failed to accept new SSL connection"));
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
- DBUG_PRINT("info", ("Reading user information over SSL layer"));
- if ((pkt_len= my_net_read(net)) == packet_error ||
- pkt_len < NORMAL_HANDSHAKE_SIZE)
- {
- DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
- pkt_len));
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
- }
-#endif
-
- if (end >= (char*) net->read_pos+ pkt_len +2)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
-
- if (thd->client_capabilities & CLIENT_INTERACTIVE)
- thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
- if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
- opt_using_transactions)
- net->return_status= &thd->server_status;
-
- char *user= end;
- char *passwd= strend(user)+1;
- uint user_len= passwd - user - 1;
- char *db= passwd;
- char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
- char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
- uint dummy_errors;
-
- /*
- Old clients send null-terminated string as password; new clients send
- the size (1 byte) + string (not null-terminated). Hence in case of empty
- password both send '\0'.
-
- Cast *passwd to an unsigned char, so that it doesn't extend the sign for
- *passwd > 127 and become 2**32-127 after casting to uint.
- */
- uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
- (uchar)(*passwd++) : strlen(passwd);
- db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
- db + passwd_len + 1 : 0;
- uint db_len= db ? strlen(db) : 0;
-
- if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return ER_HANDSHAKE_ERROR;
- }
-
- /* Since 4.1 all database names are stored in utf8 */
- if (db)
- {
- db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
- system_charset_info,
- db, db_len,
- thd->charset(), &dummy_errors)]= 0;
- db= db_buff;
- }
-
- user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
- system_charset_info, user, user_len,
- thd->charset(), &dummy_errors)]= '\0';
- user= user_buff;
-
- /* If username starts and ends in "'", chop them off */
- if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
- {
- user[user_len-1]= 0;
- user++;
- user_len-= 2;
- }
-
- if (thd->main_security_ctx.user)
- x_free(thd->main_security_ctx.user);
- if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0))))
- return (ER_OUT_OF_RESOURCES);
- return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
+ DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
+ return (sql_command_flags[command] & CF_WRITE_LOGS_COMMAND) != 0;
}
-
void execute_init_command(THD *thd, sys_var_str *init_command_var,
rw_lock_t *var_mutex)
{
@@ -1087,151 +339,6 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var,
}
-pthread_handler_t handle_one_connection(void *arg)
-{
- THD *thd=(THD*) arg;
- uint launch_time =
- (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
- if (launch_time >= slow_launch_time)
- statistic_increment(slow_launch_threads,&LOCK_status );
-
- pthread_detach_this_thread();
-
-#if !defined( __WIN__) && !defined(OS2) // Win32 calls this in pthread_create
- /* 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);
- statistic_increment(aborted_connects,&LOCK_status);
- end_thread(thd,0);
- return 0;
- }
-#endif
-
- /*
- handle_one_connection() is the only way a thread would start
- and would always be on top of the stack, therefore, the thread
- stack always starts at the address of the first local variable
- of handle_one_connection, which is thd. We need to know the
- start of the stack so that we could check for stack overruns.
- */
- DBUG_PRINT("info", ("handle_one_connection called by thread %lu\n",
- thd->thread_id));
- /* now that we've called my_thread_init(), it is safe to call DBUG_* */
-
-#if defined(__WIN__)
- init_signals();
-#elif !defined(OS2) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
- thd->thread_stack= (char*) &thd;
- if (thd->store_globals())
- {
- close_connection(thd, ER_OUT_OF_RESOURCES, 1);
- statistic_increment(aborted_connects,&LOCK_status);
- end_thread(thd,0);
- return 0;
- }
-
- do
- {
- int error;
- NET *net= &thd->net;
- Security_context *sctx= thd->security_ctx;
- net->no_send_error= 0;
-
- /* Use "connect_timeout" value during connection phase */
- my_net_set_read_timeout(net, connect_timeout);
- my_net_set_write_timeout(net, connect_timeout);
-
- if ((error=check_connection(thd)))
- { // Wrong permissions
- if (error > 0)
- net_printf_error(thd, error, sctx->host_or_ip);
-#ifdef __NT__
- if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
- my_sleep(1000); /* must wait after eof() */
-#endif
- statistic_increment(aborted_connects,&LOCK_status);
- goto end_thread;
- }
-#ifdef __NETWARE__
- netware_reg_user(sctx->ip, sctx->user, "MySQL");
-#endif
- if (thd->variables.max_join_size == HA_POS_ERROR)
- thd->options |= OPTION_BIG_SELECTS;
- if (thd->client_capabilities & CLIENT_COMPRESS)
- net->compress=1; // Use compression
-
- thd->version= refresh_version;
- thd->proc_info= 0;
- thd->command= COM_SLEEP;
- thd->init_for_queries();
-
- if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
- {
- execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
- if (thd->query_error)
- {
- thd->killed= THD::KILL_CONNECTION;
- sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
- thd->thread_id,(thd->db ? thd->db : "unconnected"),
- sctx->user ? sctx->user : "unauthenticated",
- sctx->host_or_ip, "init_connect command failed");
- sql_print_warning("%s", net->last_error);
- }
- thd->proc_info=0;
- thd->init_for_queries();
- }
-
- /* Connect completed, set read/write timeouts back to tdefault */
- my_net_set_read_timeout(net, thd->variables.net_read_timeout);
- my_net_set_write_timeout(net, thd->variables.net_write_timeout);
-
- 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);
- 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),
- thd->thread_id,(thd->db ? thd->db : "unconnected"),
- sctx->user ? sctx->user : "unauthenticated",
- sctx->host_or_ip,
- (net->last_errno ? ER(net->last_errno) :
- ER(ER_UNKNOWN_ERROR)));
- net_send_error(thd, net->last_errno, NullS);
- statistic_increment(aborted_threads,&LOCK_status);
- }
- else if (thd->killed)
- {
- statistic_increment(aborted_threads,&LOCK_status);
- }
-
-end_thread:
- close_connection(thd, 0, 1);
- end_thread(thd,1);
- /*
- If end_thread returns, we are either running with --one-thread
- or this thread has been schedule to handle the next query
- */
- thd= current_thd;
- thd->thread_stack= (char*) &thd;
- } while (!(test_flags & TEST_NO_THREADS));
- /* The following is only executed if we are not using --one-thread */
- return(0); /* purecov: deadcode */
-}
-
-#endif /* EMBEDDED_LIBRARY */
-
/*
Execute commands from bootstrap_file.
Used when creating the initial grant tables
@@ -1259,11 +366,6 @@ pthread_handler_t handle_bootstrap(void *arg)
#ifndef EMBEDDED_LIBRARY
pthread_detach_this_thread();
thd->thread_stack= (char*) &thd;
-#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
#endif /* EMBEDDED_LIBRARY */
if (thd->variables.max_join_size == HA_POS_ERROR)
@@ -1273,6 +375,7 @@ pthread_handler_t handle_bootstrap(void *arg)
thd->version=refresh_version;
thd->security_ctx->priv_user=
thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
+ thd->security_ctx->priv_host[0]=0;
/*
Make the "client" handle multiple results. This is necessary
to enable stored procedures with SELECTs and Dynamic SQL
@@ -1284,33 +387,42 @@ pthread_handler_t handle_bootstrap(void *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))
- {
- 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;
+ /* strlen() can't be deleted because fgets() doesn't return length */
+ 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.
+ */
+ /* purecov: begin tested */
+ 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);
+ /* purecov: end */
+ }
+ if (thd->is_fatal_error)
+ break; /* purecov: inspected */
while (length && (my_isspace(thd->charset(), buff[length-1]) ||
- buff[length-1] == ';'))
+ buff[length-1] == ';'))
length--;
buff[length]=0;
+
+ /* Skip lines starting with delimiter */
+ if (strncmp(buff, STRING_WITH_LEN("delimiter")) == 0)
+ continue;
+
thd->query_length=length;
- thd->query= thd->memdup_w_gap(buff, length+1,
- thd->db_length+1+QUERY_CACHE_FLAGS_SIZE);
+ thd->query= (char*) thd->memdup_w_gap(buff, length+1,
+ thd->db_length+1+
+ QUERY_CACHE_FLAGS_SIZE);
thd->query[length] = '\0';
DBUG_PRINT("query",("%-.4096s",thd->query));
/*
@@ -1359,7 +471,21 @@ end:
}
- /* This works because items are allocated with sql_alloc() */
+/* This works because items are allocated with sql_alloc() */
+
+void free_items(Item *item)
+{
+ 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)
{
@@ -1388,30 +514,35 @@ void cleanup_items(Item *item)
*/
static
-int mysql_table_dump(THD* thd, char* db, char* tbl_name)
+int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name)
{
TABLE* table;
TABLE_LIST* table_list;
int error = 0;
DBUG_ENTER("mysql_table_dump");
- db = (db && db[0]) ? db : thd->db;
+ if (db->length == 0)
+ {
+ db->str= thd->db; /* purecov: inspected */
+ db->length= thd->db_length; /* purecov: inspected */
+ }
if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(1); // out of memory
- table_list->db= db;
+ table_list->db= db->str;
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))
+ if (check_db_name(db))
{
- my_error(ER_WRONG_DB_NAME ,MYF(0), db ? db : "NULL");
+ /* purecov: begin inspected */
+ my_error(ER_WRONG_DB_NAME ,MYF(0), db->str ? db->str : "NULL");
goto err;
+ /* purecov: end */
}
if (lower_case_table_names)
my_casedn_str(files_charset_info, tbl_name);
- remove_escape(table_list->table_name);
- if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
+ if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT, 0)))
DBUG_RETURN(1);
if (check_one_table_access(thd, SELECT_ACL, table_list))
@@ -1470,7 +601,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
*/
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
res= ha_commit(thd);
- thd->options&= ~(ulong) OPTION_BEGIN;
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
break;
case COMMIT_RELEASE:
@@ -1488,7 +619,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (ha_rollback(thd))
res= -1;
- thd->options&= ~(ulong) OPTION_BEGIN;
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
if (!res && (completion == ROLLBACK_AND_CHAIN))
res= begin_trans(thd);
@@ -1568,7 +699,7 @@ bool do_command(THD *thd)
command= COM_END; // Wrong command
DBUG_PRINT("info",("Command on %s = %d (%s)",
vio_description(net->vio), command,
- command_name[command]));
+ command_name[command].str));
}
/* Restore read timeout value */
@@ -1640,13 +771,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_INIT_DB:
{
LEX_STRING tmp;
- statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB]);
thd->convert_string(&tmp, system_charset_info,
- packet, strlen(packet), thd->charset());
+ packet, packet_length-1, thd->charset());
if (!mysql_change_db(thd, &tmp, FALSE))
{
- mysql_log.write(thd,command,"%s",thd->db);
+ general_log_print(thd, command, "%s",thd->db);
send_ok(thd);
}
break;
@@ -1661,7 +791,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
case COM_TABLE_DUMP:
{
- char *db, *tbl_name;
+ char *tbl_name;
+ LEX_STRING db;
uint db_len= *(uchar*) packet;
if (db_len >= packet_length || db_len > NAME_LEN)
{
@@ -1675,27 +806,29 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
- statistic_increment(thd->status_var.com_other, &LOCK_status);
+ status_var_increment(thd->status_var.com_other);
thd->enable_slow_log= opt_log_slow_admin_statements;
- db= thd->alloc(db_len + tbl_len + 2);
- if (!db)
+ db.str= (char*) thd->alloc(db_len + tbl_len + 2);
+ if (!db.str)
{
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
break;
}
- tbl_name= strmake(db, packet + 1, db_len)+1;
+ db.length= db_len;
+ tbl_name= strmake(db.str, packet + 1, db_len)+1;
strmake(tbl_name, packet + db_len + 2, tbl_len);
- mysql_table_dump(thd, db, tbl_name);
+ mysql_table_dump(thd, &db, tbl_name);
break;
}
case COM_CHANGE_USER:
{
+ status_var_increment(thd->status_var.com_other);
+ char *user= (char*) packet, *packet_end= packet+ packet_length;
+ char *passwd= strend(user)+1;
+
thd->change_user();
thd->clear_error(); // if errors from rollback
- statistic_increment(thd->status_var.com_other, &LOCK_status);
- char *user= (char*) packet;
- char *passwd= strend(user)+1;
/*
Old clients send null-terminated string ('\0' for empty string) for
password. New clients send the size (1 byte) + string (not null
@@ -1704,10 +837,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
Cast *passwd to an unsigned char, so that it doesn't extend the sign
for *passwd > 127 and become 2**32-127 after casting to uint.
*/
- char db_buff[NAME_LEN+1]; // buffer to store db in utf8
+ char db_buff[NAME_LEN+1]; // buffer to store db in utf8
char *db= passwd;
- uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
- (uchar)(*passwd++) : strlen(passwd);
+ char *save_db;
+ uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
+ (uchar)(*passwd++) : strlen(passwd));
+ uint dummy_errors, save_db_length, db_length;
+ int res;
+ Security_context save_security_ctx= *thd->security_ctx;
+ USER_CONN *save_user_connect;
+
db+= passwd_len + 1;
#ifndef EMBEDDED_LIBRARY
/* Small check for incoming packet */
@@ -1718,17 +857,22 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
#endif
/* Convert database name to utf8 */
- uint dummy_errors;
+ /*
+ Handle problem with old bug in client protocol where db had an extra
+ \0
+ */
+ db_length= (packet_end - db);
+ if (db_length > 0 && db[db_length-1] == 0)
+ db_length--;
db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
- system_charset_info, db, strlen(db),
+ system_charset_info, db, db_length,
thd->charset(), &dummy_errors)]= 0;
db= db_buff;
/* Save user and privileges */
- uint save_db_length= thd->db_length;
- char *save_db= thd->db;
- Security_context save_security_ctx= *thd->security_ctx;
- USER_CONN *save_user_connect= thd->user_connect;
+ save_db_length= thd->db_length;
+ save_db= thd->db;
+ save_user_connect= thd->user_connect;
if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
{
@@ -1739,13 +883,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* Clear variables that are allocated */
thd->user_connect= 0;
- int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
+ res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
if (res)
{
/* authentication failure, we shall restore old user */
if (res > 0)
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
+ else
+ thd->clear_error(); // Error already sent to client
x_free(thd->security_ctx->user);
*thd->security_ctx= save_security_ctx;
thd->user_connect= save_user_connect;
@@ -1759,8 +905,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (save_user_connect)
decrease_user_connections(save_user_connect);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
- x_free((gptr) save_db);
- x_free((gptr) save_security_ctx.user);
+ x_free((uchar*) save_db);
+ x_free((uchar*) save_security_ctx.user);
}
break;
}
@@ -1803,7 +949,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
const char *format= "%.*b";
const char* found_semicolon= NULL;
- mysql_log.write(thd,command, format, thd->query_length, thd->query);
+ general_log_print(thd, command, format, thd->query_length, thd->query);
DBUG_PRINT("query",("%-.4096s",thd->query));
if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -1853,7 +999,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
#else
{
- char *fields, *pend;
+ char *fields, *packet_end= packet + packet_length - 1, *arg_end;
/* Locked closure of all tables */
TABLE_LIST table_list;
LEX_STRING conv_name;
@@ -1861,16 +1007,18 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* used as fields initializator */
lex_start(thd);
- statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]);
bzero((char*) &table_list,sizeof(table_list));
if (thd->copy_db_to(&table_list.db, &table_list.db_length))
break;
- pend= strend(packet);
+ /*
+ We have name + wildcard in packet, separated by endzero
+ */
+ arg_end= strend(packet);
thd->convert_string(&conv_name, system_charset_info,
- packet, (uint) (pend-packet), thd->charset());
+ packet, (uint) (arg_end - packet), thd->charset());
table_list.alias= table_list.table_name= conv_name.str;
- packet= pend+1;
+ packet= arg_end + 1;
if (!my_strcasecmp(system_charset_info, table_list.db,
INFORMATION_SCHEMA_NAME.str))
@@ -1880,19 +1028,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
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)))
+ thd->query_length= (uint) (packet_end - packet); // Don't count end \0
+ if (!(thd->query=fields= (char*) thd->memdup(packet,thd->query_length+1)))
break;
- mysql_log.write(thd,command,"%s %s",table_list.table_name, fields);
+ general_log_print(thd, command, "%s %s", table_list.table_name, fields);
if (lower_case_table_names)
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, test(table_list.schema_table)))
break;
- if (grant_option &&
- check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
+ if (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);
@@ -1901,8 +1047,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
mysql_reset_thd_for_next_command(thd);
thd->lex->
- select_lex.table_list.link_in_list((byte*) &table_list,
- (byte**) &table_list.next_local);
+ select_lex.table_list.link_in_list((uchar*) &table_list,
+ (uchar**) &table_list.next_local);
thd->lex->add_to_query_tables(&table_list);
/* switch on VIEW optimisation: do not fill temporary tables */
@@ -1915,44 +1061,46 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
case COM_QUIT:
/* We don't calculate statistics for this command */
- mysql_log.write(thd,command,NullS);
+ general_log_print(thd, command, NullS);
net->error=0; // Don't give 'abort' message
error=TRUE; // End server
break;
+#ifdef REMOVED
case COM_CREATE_DB: // QQ: To be removed
{
- char *db=thd->strdup(packet), *alias;
+ LEX_STRING db, alias;
HA_CREATE_INFO create_info;
- 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))
+ status_var_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB]);
+ if (thd->make_lex_string(&db, packet, packet_length - 1, FALSE) ||
+ thd->make_lex_string(&alias, db.str, db.length, FALSE) ||
+ check_db_name(&db))
{
- my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
+ my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
break;
}
- if (check_access(thd,CREATE_ACL,db,0,1,0,is_schema_db(db)))
+ if (check_access(thd, CREATE_ACL, db.str , 0, 1, 0,
+ is_schema_db(db.str)))
break;
- mysql_log.write(thd,command,packet);
+ general_log_print(thd, command, packet);
bzero(&create_info, sizeof(create_info));
- mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
+ mysql_create_db(thd, (lower_case_table_names == 2 ? alias.str : db.str),
&create_info, 0);
break;
}
case COM_DROP_DB: // QQ: To be removed
{
- 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))
+ status_var_increment(thd->status_var.com_stat[SQLCOM_DROP_DB]);
+ LEX_STRING db;
+
+ if (thd->make_lex_string(&db, packet, packet_length - 1, FALSE) ||
+ check_db_name(&db))
{
- my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
+ my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
break;
}
- if (check_access(thd,DROP_ACL,db,0,1,0,is_schema_db(db)))
+ if (check_access(thd, DROP_ACL, db.str, 0, 1, 0, is_schema_db(db.str)))
break;
if (thd->locked_tables || thd->active_transaction())
{
@@ -1960,10 +1108,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
break;
}
- mysql_log.write(thd,command,db);
- mysql_rm_db(thd, db, 0, 0);
+ general_log_print(thd, command, db.str);
+ mysql_rm_db(thd, db.str, 0, 0);
break;
}
+#endif
#ifndef EMBEDDED_LIBRARY
case COM_BINLOG_DUMP:
{
@@ -1971,7 +1120,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
ushort flags;
uint32 slave_server_id;
- statistic_increment(thd->status_var.com_other,&LOCK_status);
+ status_var_increment(thd->status_var.com_other);
thd->enable_slow_log= opt_log_slow_admin_statements;
if (check_global_access(thd, REPL_SLAVE_ACL))
break;
@@ -1984,7 +1133,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
kill_zombie_dump_threads(slave_server_id);
thd->server_id = slave_server_id;
- mysql_log.write(thd, command, "Log: '%s' Pos: %ld", packet+10,
+ general_log_print(thd, command, "Log: '%s' Pos: %ld", packet+10,
(long) pos);
mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unregister_slave(thd,1,1);
@@ -1997,12 +1146,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_REFRESH:
{
bool not_used;
- statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
ulong options= (ulong) (uchar) packet[0];
if (check_global_access(thd,RELOAD_ACL))
break;
- mysql_log.write(thd,command,NullS);
+ general_log_print(thd, command, NullS);
if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
send_ok(thd);
break;
@@ -2010,7 +1158,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#ifndef EMBEDDED_LIBRARY
case COM_SHUTDOWN:
{
- statistic_increment(thd->status_var.com_other, &LOCK_status);
+ status_var_increment(thd->status_var.com_other);
if (check_global_access(thd,SHUTDOWN_ACL))
break; /* purecov: inspected */
/*
@@ -2021,7 +1169,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
*/
enum mysql_enum_shutdown_level level=
(enum mysql_enum_shutdown_level) (uchar) packet[0];
- DBUG_PRINT("quit",("Got shutdown command for level %u", level));
if (level == SHUTDOWN_DEFAULT)
level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable
else if (level != SHUTDOWN_WAIT_ALL_BUFFERS)
@@ -2030,14 +1177,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
DBUG_PRINT("quit",("Got shutdown command for level %u", level));
- mysql_log.write(thd,command,NullS);
+ general_log_print(thd, command, NullS);
send_eof(thd);
#ifdef __WIN__
sleep(1); // must wait after eof()
#endif
-#ifndef OS2
- send_eof(thd); // This is for 'quit request'
-#endif
+ /*
+ The client is next going to send a COM_QUIT request (as part of
+ mysql_close()). Make the life simpler for the client by sending
+ the response for the coming COM_QUIT in advance
+ */
+ send_eof(thd);
close_connection(thd, 0, 1);
close_thread_tables(thd); // Free before kill
kill_mysql();
@@ -2047,65 +1197,78 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
case COM_STATISTICS:
{
- mysql_log.write(thd,command,NullS);
- statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS],
- &LOCK_status);
+ STATUS_VAR current_global_status_var;
+ ulong uptime;
+ uint length;
+ ulonglong queries_per_second1000;
#ifndef EMBEDDED_LIBRARY
- char buff[200];
+ char buff[250];
+ uint buff_len= sizeof(buff);
#else
char *buff= thd->net.last_error;
+ uint buff_len= sizeof(thd->net.last_error);
#endif
- STATUS_VAR current_global_status_var;
+ general_log_print(thd, command, NullS);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]);
calc_sum_of_all_status(&current_global_status_var);
-
- ulong uptime = (ulong) (thd->start_time - server_start_time);
- sprintf((char*) buff,
- "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, (ulong) thd->query_id,
- current_global_status_var.long_query_count,
- current_global_status_var.opened_tables, refresh_version, cached_tables(),
- (uptime ? (ulonglong2double(thd->query_id) / (double) uptime) :
- (double) 0));
+ if (!(uptime= (ulong) (thd->start_time - server_start_time)))
+ queries_per_second1000= 0;
+ else
+ queries_per_second1000= thd->query_id * LL(1000) / uptime;
+
+ length= my_snprintf((char*) buff, buff_len - 1,
+ "Uptime: %lu Threads: %d Questions: %lu "
+ "Slow queries: %lu Opens: %lu Flush tables: %lu "
+ "Open tables: %u Queries per second avg: %u.%u",
+ uptime,
+ (int) thread_count, (ulong) thd->query_id,
+ current_global_status_var.long_query_count,
+ current_global_status_var.opened_tables,
+ refresh_version,
+ cached_open_tables(),
+ (uint) (queries_per_second1000 / 1000),
+ (uint) (queries_per_second1000 % 1000));
#ifdef SAFEMALLOC
if (sf_malloc_cur_memory) // Using SAFEMALLOC
- sprintf(strend(buff), " Memory in use: %ldK Max memory used: %ldK",
- (sf_malloc_cur_memory+1023L)/1024L,
- (sf_malloc_max_memory+1023L)/1024L);
+ {
+ char *end= buff + length;
+ length+= my_snprintf(end, buff_len - length - 1,
+ end," Memory in use: %ldK Max memory used: %ldK",
+ (sf_malloc_cur_memory+1023L)/1024L,
+ (sf_malloc_max_memory+1023L)/1024L);
+ }
#endif
#ifndef EMBEDDED_LIBRARY
- VOID(my_net_write(net, buff,(uint) strlen(buff)));
- VOID(net_flush(net));
+ VOID(my_net_write(net, (uchar*) buff, length));
+ VOID(net_flush(net));
#endif
break;
}
case COM_PING:
- statistic_increment(thd->status_var.com_other, &LOCK_status);
+ status_var_increment(thd->status_var.com_other);
send_ok(thd); // Tell client we are alive
break;
case COM_PROCESS_INFO:
- statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]);
if (!thd->security_ctx->priv_user[0] &&
check_global_access(thd, PROCESS_ACL))
break;
- mysql_log.write(thd,command,NullS);
+ general_log_print(thd, command, NullS);
mysqld_list_processes(thd,
thd->security_ctx->master_access & PROCESS_ACL ?
NullS : thd->security_ctx->priv_user, 0);
break;
case COM_PROCESS_KILL:
{
- statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_KILL]);
ulong id=(ulong) uint4korr(packet);
- kill_one_thread(thd,id,false);
+ sql_kill(thd,id,false);
break;
}
case COM_SET_OPTION:
{
- statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION]);
uint opt_command= uint2korr(packet);
switch (opt_command) {
@@ -2124,11 +1287,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
case COM_DEBUG:
- statistic_increment(thd->status_var.com_other, &LOCK_status);
+ status_var_increment(thd->status_var.com_other);
if (check_global_access(thd, SUPER_ACL))
break; /* purecov: inspected */
mysql_print_status();
- mysql_log.write(thd,command,NullS);
+ general_log_print(thd, command, NullS);
send_eof(thd);
break;
case COM_SLEEP:
@@ -2182,7 +1345,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
void log_slow_statement(THD *thd)
{
- time_t start_of_query;
+ DBUG_ENTER("log_slow_statement");
/*
The following should never be true with our current code base,
@@ -2190,10 +1353,7 @@ void log_slow_statement(THD *thd)
statement in a trigger or stored function
*/
if (unlikely(thd->in_sub_stmt))
- return; // Don't set time for sub stmt
-
- start_of_query= thd->start_time;
- thd->end_time(); // Set start time
+ DBUG_VOID_RETURN; // Don't set time for sub stmt
/*
Do not log administrative statements unless the appropriate option is
@@ -2201,20 +1361,22 @@ void log_slow_statement(THD *thd)
*/
if (thd->enable_slow_log && !thd->user_time)
{
- thd->proc_info="logging slow query";
+ ulonglong end_utime_of_query= thd->current_utime();
- if ((ulong) (thd->start_time - thd->time_after_lock) >
- thd->variables.long_query_time ||
- (thd->server_status &
- (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
- opt_log_queries_not_using_indexes &&
- /* == SQLCOM_END unless this is a SHOW command */
- thd->lex->orig_sql_command == SQLCOM_END)
+ thd->proc_info="logging slow query";
+ if (((end_utime_of_query - thd->utime_after_lock) >
+ thd->variables.long_query_time ||
+ ((thd->server_status &
+ (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
+ opt_log_queries_not_using_indexes &&
+ !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) &&
+ thd->examined_row_count >= thd->variables.min_examined_row_limit)
{
thd->status_var.long_query_count++;
- mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
+ slow_log_print(thd, thd->query, thd->query_length, end_utime_of_query);
}
}
+ DBUG_VOID_RETURN;
}
@@ -2249,8 +1411,8 @@ void log_slow_statement(THD *thd)
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 *schema_select_lex= NULL;
+ DBUG_ENTER("prepare_schema_table");
switch (schema_table_idx) {
case SCH_SCHEMATA:
@@ -2266,63 +1428,59 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
case SCH_TABLES:
case SCH_VIEWS:
case SCH_TRIGGERS:
+ case SCH_EVENTS:
#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 (lex->select_lex.db == NULL &&
- lex->copy_db_to(&lex->select_lex.db, NULL))
{
- DBUG_RETURN(1);
- }
-
- schema_select_lex= new SELECT_LEX();
- schema_select_lex->db= lex->select_lex.db;
- schema_select_lex->table_list.first= NULL;
- remove_escape(schema_select_lex->db); // Fix escaped '_'
+ LEX_STRING db;
+ size_t dummy;
+ if (lex->select_lex.db == NULL &&
+ lex->copy_db_to(&lex->select_lex.db, &dummy))
+ {
+ DBUG_RETURN(1);
+ }
+ schema_select_lex= new SELECT_LEX();
+ db.str= schema_select_lex->db= lex->select_lex.db;
+ schema_select_lex->table_list.first= NULL;
+ db.length= strlen(db.str);
- if (check_db_name(schema_select_lex->db))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), schema_select_lex->db);
- DBUG_RETURN(1);
+ if (check_db_name(&db))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
+ DBUG_RETURN(1);
+ }
+ break;
}
-
-
- 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
- {
- DBUG_ASSERT(table_ident);
-
- TABLE_LIST **query_tables_last= lex->query_tables_last;
- schema_select_lex= new SELECT_LEX();
- /* 'parent_lex' is used in init_query() so it must be before it. */
- schema_select_lex->parent_lex= lex;
- schema_select_lex->init_query();
- if (!schema_select_lex->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 *dst_table= (TABLE_LIST*) schema_select_lex->table_list.first;
- remove_escape(dst_table->db); // Fix escaped '_'
- remove_escape(dst_table->table_name);
-
- break;
- }
+ DBUG_ASSERT(table_ident);
+ TABLE_LIST **query_tables_last= lex->query_tables_last;
+ schema_select_lex= new SELECT_LEX();
+ /* 'parent_lex' is used in init_query() so it must be before it. */
+ schema_select_lex->parent_lex= lex;
+ schema_select_lex->init_query();
+ if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
+ DBUG_RETURN(1);
+ lex->query_tables_last= query_tables_last;
+ break;
+ }
#endif
case SCH_OPEN_TABLES:
case SCH_VARIABLES:
case SCH_STATUS:
case SCH_PROCEDURES:
case SCH_CHARSETS:
+ case SCH_ENGINES:
case SCH_COLLATIONS:
case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
case SCH_USER_PRIVILEGES:
@@ -2343,8 +1501,6 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
table_list->schema_select_lex= schema_select_lex;
table_list->schema_table_reformed= 1;
- statistic_increment(thd->status_var.com_stat[lex->orig_sql_command],
- &LOCK_status);
DBUG_RETURN(0);
}
@@ -2381,7 +1537,7 @@ bool alloc_query(THD *thd, const char *packet, uint packet_length)
}
/* We must allocate some extra memory for query cache */
thd->query_length= 0; // Extra safety: Avoid races
- if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
+ if (!(thd->query= (char*) thd->memdup_w_gap((uchar*) (packet),
packet_length,
thd->db_length+ 1 +
QUERY_CACHE_FLAGS_SIZE)))
@@ -2414,6 +1570,91 @@ static void reset_one_shot_variables(THD *thd)
}
+static
+bool sp_process_definer(THD *thd)
+{
+ DBUG_ENTER("sp_process_definer");
+
+ LEX *lex= thd->lex;
+
+ /*
+ If the definer is not specified, this means that CREATE-statement missed
+ DEFINER-clause. DEFINER-clause can be missed in two cases:
+
+ - The user submitted a statement w/o the clause. This is a normal
+ case, we should assign CURRENT_USER as definer.
+
+ - Our slave received an updated from the master, that does not
+ replicate definer for stored rountines. We should also assign
+ CURRENT_USER as definer here, but also we should mark this routine
+ as NON-SUID. This is essential for the sake of backward
+ compatibility.
+
+ The problem is the slave thread is running under "special" user (@),
+ that actually does not exist. In the older versions we do not fail
+ execution of a stored routine if its definer does not exist and
+ continue the execution under the authorization of the invoker
+ (BUG#13198). And now if we try to switch to slave-current-user (@),
+ we will fail.
+
+ Actually, this leads to the inconsistent state of master and
+ slave (different definers, different SUID behaviour), but it seems,
+ this is the best we can do.
+ */
+
+ if (!lex->definer)
+ {
+ Query_arena original_arena;
+ Query_arena *ps_arena= thd->activate_stmt_arena_if_needed(&original_arena);
+
+ lex->definer= create_default_definer(thd);
+
+ if (ps_arena)
+ thd->restore_active_arena(ps_arena, &original_arena);
+
+ /* Error has been already reported. */
+ if (lex->definer == NULL)
+ DBUG_RETURN(TRUE);
+
+ if (thd->slave_thread && lex->sphead)
+ lex->sphead->m_chistics->suid= SP_IS_NOT_SUID;
+ }
+ else
+ {
+ /*
+ If the specified definer differs from the current user, we
+ should check that the current user has SUPER privilege (in order
+ to create a stored routine under another user one must have
+ SUPER privilege).
+ */
+ if ((strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
+ my_strcasecmp(system_charset_info, lex->definer->host.str,
+ thd->security_ctx->priv_host)) &&
+ check_global_access(thd, SUPER_ACL))
+ {
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
+ DBUG_RETURN(TRUE);
+ }
+ }
+
+ /* Check that the specified definer exists. Emit a warning if not. */
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (!is_acl_user(lex->definer->host.str, lex->definer->user.str))
+ {
+ push_warning_printf(thd,
+ MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_NO_SUCH_USER,
+ ER(ER_NO_SUCH_USER),
+ lex->definer->user.str,
+ lex->definer->host.str);
+ }
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+
+ DBUG_RETURN(FALSE);
+}
+
+
/*
Execute command saved in thd and lex->sql_command
@@ -2456,20 +1697,9 @@ mysql_execute_command(THD *thd)
/* Saved variable value */
DBUG_ENTER("mysql_execute_command");
thd->net.no_send_error= 0;
-
- /*
- Remember first generated insert id value of the previous
- statement. We remember it here at the beginning of the statement,
- and also in Item_func_last_insert_id::fix_fields() and
- sys_var_last_insert_id::value_ptr(). Last two places are required
- because LAST_INSERT_ID() and @@LAST_INSERT_ID may also be used in
- expression that is not executed with mysql_execute_command().
-
- And we remember it here because some statements read
- @@LAST_INSERT_ID indirectly, like "SELECT * FROM t1 WHERE id IS
- NULL", that may replace "id IS NULL" with "id = <LAST_INSERT_ID>".
- */
- thd->current_insert_id= thd->last_insert_id;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ thd->work_part_info= 0;
+#endif
/*
In many cases first table of main SELECT_LEX have special meaning =>
@@ -2501,9 +1731,7 @@ mysql_execute_command(THD *thd)
variables, but for now this is probably good enough.
Don't reset warnings when executing a stored routine.
*/
- if ((all_tables || &lex->select_lex != lex->all_selects_list ||
- lex->sroutines.records) && !thd->spcont ||
- lex->time_zone_tables_used)
+ if ((all_tables || !lex->is_single_level_stmt()) && !thd->spcont)
mysql_reset_errors(thd, 0);
#ifdef HAVE_REPLICATION
@@ -2582,8 +1810,8 @@ mysql_execute_command(THD *thd)
tables. Except for the replication thread and the 'super' users.
*/
if (opt_readonly &&
- !(thd->security_ctx->master_access & SUPER_ACL) &&
- uc_update_queries[lex->sql_command] &&
+ !(thd->security_ctx->master_access & SUPER_ACL) &&
+ (sql_command_flags[lex->sql_command] & CF_CHANGES_DATA) &&
!((lex->sql_command == SQLCOM_CREATE_TABLE) &&
(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) &&
!((lex->sql_command == SQLCOM_DROP_TABLE) && lex->drop_temporary) &&
@@ -2596,80 +1824,67 @@ mysql_execute_command(THD *thd)
#ifdef HAVE_REPLICATION
} /* endif unlikely slave */
#endif
- if(lex->orig_sql_command == SQLCOM_END)
- statistic_increment(thd->status_var.com_stat[lex->sql_command],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[lex->sql_command]);
DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE);
switch (lex->sql_command) {
+ case SQLCOM_SHOW_EVENTS:
+ if ((res= check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0,
+ is_schema_db(thd->lex->select_lex.db))))
+ break;
+ /* fall through */
+ case SQLCOM_SHOW_STATUS_PROC:
+ case SQLCOM_SHOW_STATUS_FUNC:
+ res= execute_sqlcom_select(thd, all_tables);
+ break;
+ case SQLCOM_SHOW_STATUS:
+ {
+ system_status_var old_status_var= thd->status_var;
+ thd->initial_status_var= &old_status_var;
+ res= execute_sqlcom_select(thd, all_tables);
+ /* Don't log SHOW STATUS commands to slow query log */
+ thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED |
+ SERVER_QUERY_NO_GOOD_INDEX_USED);
+ /*
+ restore status variables, as we don't want 'show status' to cause
+ changes
+ */
+ pthread_mutex_lock(&LOCK_status);
+ add_diff_to_status(&global_status_var, &thd->status_var,
+ &old_status_var);
+ thd->status_var= old_status_var;
+ pthread_mutex_unlock(&LOCK_status);
+ break;
+ }
+ case SQLCOM_SHOW_DATABASES:
+ case SQLCOM_SHOW_TABLES:
+ case SQLCOM_SHOW_TRIGGERS:
+ case SQLCOM_SHOW_TABLE_STATUS:
+ case SQLCOM_SHOW_OPEN_TABLES:
+ case SQLCOM_SHOW_PLUGINS:
+ case SQLCOM_SHOW_FIELDS:
+ case SQLCOM_SHOW_KEYS:
+ case SQLCOM_SHOW_VARIABLES:
+ case SQLCOM_SHOW_CHARSETS:
+ case SQLCOM_SHOW_COLLATIONS:
+ case SQLCOM_SHOW_STORAGE_ENGINES:
case SQLCOM_SELECT:
- {
- /* assign global limit variable if limit is not given */
- {
- SELECT_LEX *param= lex->unit.global_parameters;
- if (!param->explicit_limit)
- param->select_limit=
- new Item_int((ulonglong)thd->variables.select_limit);
- }
-
- select_result *sel_result=lex->result;
+ thd->status_var.last_query_cost= 0.0;
if (all_tables)
{
- if (lex->orig_sql_command != SQLCOM_SHOW_STATUS_PROC &&
- lex->orig_sql_command != SQLCOM_SHOW_STATUS_FUNC)
- res= check_table_access(thd,
- lex->exchange ? SELECT_ACL | FILE_ACL :
- SELECT_ACL,
- all_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, 0);
- if (res)
- goto error;
-
- if (!(res= open_and_lock_tables(thd, all_tables)))
- {
- if (lex->describe)
- {
- /*
- We always use select_send for EXPLAIN, even if it's an EXPLAIN
- for SELECT ... INTO OUTFILE: a user application should be able
- to prepend EXPLAIN to any query and receive output for it,
- even if the query itself redirects the output.
- */
- if (!(sel_result= new select_send()))
- goto error;
- else
- thd->send_explain_fields(sel_result);
- res= mysql_explain_union(thd, &thd->lex->unit, sel_result);
- if (lex->describe & DESCRIBE_EXTENDED)
- {
- char buff[1024];
- String str(buff,(uint32) sizeof(buff), system_charset_info);
- str.length(0);
- thd->lex->unit.print(&str);
- str.append('\0');
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_YES, str.ptr());
- }
- sel_result->send_eof();
- delete sel_result;
- }
- else
- {
- if (!sel_result && !(sel_result= new select_send()))
- goto error;
- query_cache_store_query(thd, all_tables);
- res= handle_select(thd, lex, sel_result, 0);
- if (sel_result != lex->result)
- delete sel_result;
- }
- }
+ lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
+ any_db, 0, 0, 0, 0);
+ if (!res)
+ res= execute_sqlcom_select(thd, all_tables);
break;
- }
case SQLCOM_PREPARE:
{
mysql_sql_stmt_prepare(thd);
@@ -2783,34 +1998,31 @@ mysql_execute_command(THD *thd)
case SQLCOM_BACKUP_TABLE:
{
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) ||
+ if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
check_global_access(thd, FILE_ACL))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_backup_table(thd, first_table);
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
break;
}
case SQLCOM_RESTORE_TABLE:
{
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) ||
+ if (check_table_access(thd, INSERT_ACL, all_tables, 0) ||
check_global_access(thd, FILE_ACL))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_restore_table(thd, first_table);
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
break;
}
case SQLCOM_ASSIGN_TO_KEYCACHE:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_db_used(thd, all_tables) ||
- check_access(thd, INDEX_ACL, first_table->db,
+ if (check_access(thd, INDEX_ACL, first_table->db,
&first_table->grant.privilege, 0, 0,
test(first_table->schema_table)))
goto error;
@@ -2820,8 +2032,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_PRELOAD_KEYS:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_db_used(thd, all_tables) ||
- check_access(thd, INDEX_ACL, first_table->db,
+ if (check_access(thd, INDEX_ACL, first_table->db,
&first_table->grant.privilege, 0, 0,
test(first_table->schema_table)))
goto error;
@@ -2862,33 +2073,23 @@ mysql_execute_command(THD *thd)
goto error;
if (end_active_trans(thd))
goto error;
- else
- res = load_master_data(thd);
+ res = load_master_data(thd);
break;
#endif /* HAVE_REPLICATION */
-#ifdef HAVE_NDBCLUSTER_DB
- case SQLCOM_SHOW_NDBCLUSTER_STATUS:
- {
- res = ndbcluster_show_status(thd);
- break;
- }
-#endif
-#ifdef HAVE_INNOBASE_DB
- case SQLCOM_SHOW_INNODB_STATUS:
+ case SQLCOM_SHOW_ENGINE_STATUS:
{
if (check_global_access(thd, SUPER_ACL))
- goto error;
- res = innodb_show_status(thd);
+ goto error;
+ res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_STATUS);
break;
}
- case SQLCOM_SHOW_MUTEX_STATUS:
+ case SQLCOM_SHOW_ENGINE_MUTEX:
{
if (check_global_access(thd, SUPER_ACL))
goto error;
- res = innodb_mutex_show_status(thd);
+ res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
break;
}
-#endif
#ifdef HAVE_REPLICATION
case SQLCOM_LOAD_MASTER_TABLE:
{
@@ -2899,17 +2100,10 @@ mysql_execute_command(THD *thd)
&first_table->grant.privilege, 0, 0,
test(first_table->schema_table)))
goto error; /* purecov: inspected */
- if (grant_option)
- {
- /* Check that the first table has CREATE privilege */
- if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
- goto error;
- }
- if (strlen(first_table->table_name) > NAME_LEN)
- {
- my_error(ER_WRONG_TABLE_NAME, MYF(0), first_table->table_name);
- break;
- }
+ /* Check that the first table has CREATE privilege */
+ if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
+ goto error;
+
pthread_mutex_lock(&LOCK_active_mi);
/*
fetch_master_table will send the error to the client on failure.
@@ -2936,11 +2130,6 @@ mysql_execute_command(THD *thd)
break;
}
}
- else
- {
- /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
- thd->transaction.all.modified_non_trans_table= TRUE;
- }
DBUG_ASSERT(first_table == all_tables && first_table != 0);
bool link_to_local;
// Skip first table, which is the table we are creating
@@ -2954,11 +2143,16 @@ mysql_execute_command(THD *thd)
referenced from this structure.
*/
HA_CREATE_INFO create_info(lex->create_info);
+ /*
+ We need to copy alter_info for the same reasons of re-execution
+ safety, only in case of Alter_info we have to do (almost) a deep
+ copy.
+ */
Alter_info alter_info(lex->alter_info, thd->mem_root);
if (thd->is_fatal_error)
{
- /* out of memory when creating a copy of alter_info */
+ /* If out of memory when creating a copy of alter_info. */
res= 1;
goto end_with_restore_list;
}
@@ -2966,6 +2160,7 @@ mysql_execute_command(THD *thd)
if ((res= create_table_precheck(thd, select_tables, create_table)))
goto end_with_restore_list;
+ /* Might have been updated in create_table_precheck */
create_info.alias= create_table->alias;
#ifndef HAVE_READLINK
@@ -3016,14 +2211,25 @@ mysql_execute_command(THD *thd)
res= 1;
goto end_with_restore_list;
}
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ {
+ partition_info *part_info= thd->lex->part_info;
+ if (part_info && !(part_info= thd->lex->part_info->get_clone()))
+ {
+ res= -1;
+ goto end_with_restore_list;
+ }
+ thd->work_part_info= part_info;
+ }
+#endif
if (select_lex->item_list.elements) // With select
{
- select_result *sel_result;
+ select_result *result;
select_lex->options|= SELECT_NO_UNLOCK;
unit->set_limit(select_lex);
- if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
{
lex->link_first_table_back(create_table, link_to_local);
create_table->create= TRUE;
@@ -3063,33 +2269,38 @@ mysql_execute_command(THD *thd)
}
}
}
+
/*
select_create is currently not re-execution friendly and
needs to be created for every execution of a PS/SP.
*/
- if ((sel_result= new select_create(create_table,
- &create_info,
- &alter_info,
- select_lex->item_list,
- lex->duplicates,
- lex->ignore)))
+ if ((result= new select_create(create_table,
+ &create_info,
+ &alter_info,
+ select_lex->item_list,
+ lex->duplicates,
+ lex->ignore,
+ select_tables)))
{
/*
CREATE from SELECT give its SELECT_LEX for SELECT,
and item_list belong to SELECT
*/
- res= handle_select(thd, lex, sel_result, 0);
- delete sel_result;
+ res= handle_select(thd, lex, result, 0);
+ delete result;
}
}
- else if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ else if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
create_table= lex->unlink_first_table(&link_to_local);
}
else
{
+ /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
+ if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
+ thd->options|= OPTION_KEEP_LOG;
/* regular create */
- if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
+ if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
res= mysql_create_like_table(thd, create_table, select_tables,
&create_info);
else
@@ -3112,25 +2323,22 @@ end_with_restore_list:
case SQLCOM_DROP_INDEX:
/*
CREATE INDEX and DROP INDEX are implemented by calling ALTER
- TABLE with proper arguments. This isn't very fast but it
- should work for most cases.
+ TABLE with proper arguments.
- In the future ALTER TABLE will notice that only added
- indexes and create these one by one for the existing table
- without having to do a full rebuild.
-
- One should normally create all indexes with CREATE TABLE or
- ALTER TABLE.
+ In the future ALTER TABLE will notice that the request is to
+ only add indexes and create these one by one for the existing
+ table without having to do a full rebuild.
*/
{
- Alter_info alter_info(lex->alter_info, thd->mem_root);
+ /* Prepare stack copies to be re-execution safe */
HA_CREATE_INFO create_info;
+ Alter_info alter_info(lex->alter_info, thd->mem_root);
- if (thd->is_fatal_error) /* out of memory creating a copy of alter_info*/
+ if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
goto error;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_one_table_access(thd, INDEX_ACL, first_table))
+ if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
if (end_active_trans(thd))
goto error;
@@ -3142,7 +2350,7 @@ end_with_restore_list:
thd->enable_slow_log= opt_log_slow_admin_statements;
bzero((char*) &create_info, sizeof(create_info));
- create_info.db_type= DB_TYPE_DEFAULT;
+ create_info.db_type= 0;
create_info.row_type= ROW_TYPE_NOT_USED;
create_info.default_table_charset= thd->variables.collation_database;
@@ -3191,6 +2399,7 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
{
ulong priv=0;
+ ulong priv_needed= ALTER_ACL;
/*
Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
so we have to use a copy of this structure to make execution
@@ -3202,14 +2411,16 @@ end_with_restore_list:
if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
goto error;
- if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
- {
- my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name);
- goto error;
- }
+ /*
+ We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
+ as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
+ */
+ if (alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME))
+ priv_needed|= DROP_ACL;
+
/* Must be set in the parser */
DBUG_ASSERT(select_lex->db);
- if (check_access(thd, ALTER_ACL, first_table->db,
+ if (check_access(thd, priv_needed, first_table->db,
&first_table->grant.privilege, 0, 0,
test(first_table->schema_table)) ||
check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0,
@@ -3218,22 +2429,20 @@ end_with_restore_list:
(TABLE_LIST *)
create_info.merge_list.first))
goto error; /* purecov: inspected */
- if (grant_option)
- {
- 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.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,
- UINT_MAX, 0))
- goto error;
- }
+ if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0))
+ goto error;
+ if (lex->name.str && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
+ { // Rename of table
+ TABLE_LIST tmp_table;
+ bzero((char*) &tmp_table,sizeof(tmp_table));
+ tmp_table.table_name= lex->name.str;
+ tmp_table.db=select_lex->db;
+ tmp_table.grant.privilege=priv;
+ if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
+ UINT_MAX, 0))
+ goto error;
}
+
/* Don't yet allow changing of symlinks with ALTER TABLE */
if (create_info.data_file_name)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
@@ -3245,32 +2454,28 @@ end_with_restore_list:
/* ALTER TABLE ends previous transaction */
if (end_active_trans(thd))
goto error;
- else
- {
- if (!thd->locked_tables &&
- !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
- {
- res= 1;
- break;
- }
- thd->enable_slow_log= opt_log_slow_admin_statements;
- res= mysql_alter_table(thd, select_lex->db, lex->name,
- &create_info,
- first_table,
- &alter_info,
- select_lex->order_list.elements,
- (ORDER *) select_lex->order_list.first,
- lex->ignore);
+ if (!thd->locked_tables &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ {
+ res= 1;
+ break;
}
+
+ thd->enable_slow_log= opt_log_slow_admin_statements;
+ res= mysql_alter_table(thd, select_lex->db, lex->name.str,
+ &create_info,
+ first_table,
+ &alter_info,
+ select_lex->order_list.elements,
+ (ORDER *) select_lex->order_list.first,
+ lex->ignore);
break;
}
case SQLCOM_RENAME_TABLE:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *table;
- if (check_db_used(thd, all_tables))
- goto error;
for (table= first_table; table; table= table->next_local->next_local)
{
if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
@@ -3279,24 +2484,21 @@ end_with_restore_list:
&table->next_local->grant.privilege, 0, 0,
test(table->next_local->schema_table)))
goto error;
- if (grant_option)
- {
- 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_local[0];
- if (check_grant(thd, ALTER_ACL | DROP_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, 1, 0)))
- goto error;
- }
+ 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_local[0];
+ if (check_grant(thd, ALTER_ACL | DROP_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, 1, 0)))
+ goto error;
}
- query_cache_invalidate3(thd, first_table, 0);
- if (end_active_trans(thd) || mysql_rename_tables(thd, first_table))
+
+ if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
goto error;
break;
}
@@ -3326,9 +2528,7 @@ end_with_restore_list:
/* 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_show_create_table_access(thd, first_table))
+ if (check_show_create_table_access(thd, first_table))
goto error;
res= mysqld_show_create(thd, first_table);
break;
@@ -3337,8 +2537,7 @@ end_with_restore_list:
case SQLCOM_CHECKSUM:
{
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))
+ if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, 0))
goto error; /* purecov: inspected */
res = mysql_checksum_table(thd, first_table, &lex->check_opt);
break;
@@ -3346,58 +2545,49 @@ end_with_restore_list:
case SQLCOM_REPAIR:
{
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))
+ if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res= mysql_repair_table(thd, first_table, &lex->check_opt);
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- /* Presumably, REPAIR and binlog writing doesn't require synchronization */
- if (mysql_bin_log.is_open())
- {
- thd->clear_error(); // No binlog error generated
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ /*
+ Presumably, REPAIR and binlog writing doesn't require synchronization
+ */
+ write_bin_log(thd, TRUE, thd->query, thd->query_length);
}
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
break;
}
case SQLCOM_CHECK:
{
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))
+ if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_check_table(thd, first_table, &lex->check_opt);
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
break;
}
case SQLCOM_ANALYZE:
{
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))
+ if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
- res = mysql_analyze_table(thd, first_table, &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)
{
- /* Presumably, ANALYZE and binlog writing doesn't require synchronization */
- if (mysql_bin_log.is_open())
- {
- thd->clear_error(); // No binlog error generated
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ /*
+ Presumably, ANALYZE and binlog writing doesn't require synchronization
+ */
+ write_bin_log(thd, TRUE, thd->query, thd->query_length);
}
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
break;
}
@@ -3405,8 +2595,7 @@ end_with_restore_list:
case SQLCOM_OPTIMIZE:
{
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))
+ if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
@@ -3415,15 +2604,12 @@ end_with_restore_list:
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- /* Presumably, OPTIMIZE and binlog writing doesn't require synchronization */
- if (mysql_bin_log.is_open())
- {
- thd->clear_error(); // No binlog error generated
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ /*
+ Presumably, OPTIMIZE and binlog writing doesn't require synchronization
+ */
+ write_bin_log(thd, TRUE, thd->query, thd->query_length);
}
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
break;
}
@@ -3502,6 +2688,36 @@ end_with_restore_list:
break;
}
case SQLCOM_REPLACE:
+#ifndef DBUG_OFF
+ if (mysql_bin_log.is_open())
+ {
+ /*
+ Generate an incident log event before writing the real event
+ to the binary log. We put this event is before the statement
+ since that makes it simpler to check that the statement was
+ not executed on the slave (since incidents usually stop the
+ slave).
+
+ Observe that any row events that are generated will be
+ generated before.
+
+ This is only for testing purposes and will not be present in a
+ release build.
+ */
+
+ Incident incident= INCIDENT_NONE;
+ DBUG_PRINT("debug", ("Just before generate_incident()"));
+ DBUG_EXECUTE_IF("incident_database_resync_on_replace",
+ incident= INCIDENT_LOST_EVENTS;);
+ if (incident)
+ {
+ Incident_log_event ev(thd, incident);
+ mysql_bin_log.write(&ev);
+ mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
+ }
+ DBUG_PRINT("debug", ("Just after generate_incident()"));
+ }
+#endif
case SQLCOM_INSERT:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
@@ -3526,7 +2742,8 @@ end_with_restore_list:
had before the statement.
*/
if (first_table->view && !first_table->contain_auto_increment)
- thd->last_insert_id= thd->current_insert_id;
+ thd->first_successful_insert_id_in_cur_stmt=
+ thd->first_successful_insert_id_in_prev_stmt;
break;
}
@@ -3558,7 +2775,7 @@ end_with_restore_list:
{
/* Skip first table, which is the table we are inserting in */
TABLE_LIST *second_table= first_table->next_local;
- select_lex->table_list.first= (byte*) second_table;
+ select_lex->table_list.first= (uchar*) second_table;
select_lex->context.table_list=
select_lex->context.first_name_resolution_table= second_table;
res= mysql_insert_select_prepare(thd);
@@ -3591,7 +2808,7 @@ end_with_restore_list:
delete sel_result;
}
/* revert changes for SP */
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
}
/*
@@ -3601,7 +2818,8 @@ end_with_restore_list:
had before the statement.
*/
if (first_table->view && !first_table->contain_auto_increment)
- thd->last_insert_id= thd->current_insert_id;
+ thd->first_successful_insert_id_in_cur_stmt=
+ thd->first_successful_insert_id_in_prev_stmt;
break;
}
@@ -3612,7 +2830,7 @@ end_with_restore_list:
break;
}
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_one_table_access(thd, DELETE_ACL, all_tables))
+ if (check_one_table_access(thd, DROP_ACL, all_tables))
goto error;
/*
Don't allow this within a transaction because we want to use
@@ -3722,7 +2940,7 @@ end_with_restore_list:
lex->drop_if_exists= 1;
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
- thd->transaction.all.modified_non_trans_table= TRUE;
+ thd->options|= OPTION_KEEP_LOG;
}
/* DDL and binlog write order protected by LOCK_open */
res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
@@ -3739,8 +2957,11 @@ end_with_restore_list:
thd->security_ctx->priv_user),
lex->verbose);
break;
- case SQLCOM_SHOW_STORAGE_ENGINES:
- res= mysqld_show_storage_engines(thd);
+ case SQLCOM_SHOW_AUTHORS:
+ res= mysqld_show_authors(thd);
+ break;
+ case SQLCOM_SHOW_CONTRIBUTORS:
+ res= mysqld_show_contributors(thd);
break;
case SQLCOM_SHOW_PRIVILEGES:
res= mysqld_show_privileges(thd);
@@ -3748,16 +2969,16 @@ end_with_restore_list:
case SQLCOM_SHOW_COLUMN_TYPES:
res= mysqld_show_column_types(thd);
break;
- case SQLCOM_SHOW_LOGS:
+ case SQLCOM_SHOW_ENGINE_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
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,0))
+ if (check_access(thd, FILE_ACL, any_db,0,0,0,0))
goto error;
- res= mysqld_show_logs(thd);
+ res= ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_LOGS);
break;
}
#endif
@@ -3842,8 +3063,6 @@ end_with_restore_list:
/* we must end the trasaction first, regardless of anything */
if (end_active_trans(thd))
goto error;
- if (check_db_used(thd, all_tables))
- goto error;
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
goto error;
thd->in_lock_tables=1;
@@ -3885,9 +3104,10 @@ end_with_restore_list:
break;
}
char *alias;
- if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
+ if (!(alias=thd->strmake(lex->name.str, lex->name.length)) ||
+ check_db_name(&lex->name))
{
- my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
break;
}
/*
@@ -3898,19 +3118,19 @@ end_with_restore_list:
above was not called. So we have to check rules again here.
*/
#ifdef HAVE_REPLICATION
- if (thd->slave_thread &&
- (!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
- !db_ok_with_wild_table(lex->name)))
+ if (thd->slave_thread &&
+ (!rpl_filter->db_ok(lex->name.str) ||
+ !rpl_filter->db_ok_with_wild_table(lex->name.str)))
{
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
break;
}
#endif
-
- if (check_access(thd,CREATE_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
+ if (check_access(thd,CREATE_ACL,lex->name.str, 0, 1, 0,
+ is_schema_db(lex->name.str)))
break;
- res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name),
- &create_info, 0);
+ res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
+ lex->name.str), &create_info, 0);
break;
}
case SQLCOM_DROP_DB:
@@ -3920,9 +3140,9 @@ end_with_restore_list:
res= -1;
break;
}
- if (check_db_name(lex->name))
+ if (check_db_name(&lex->name))
{
- my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
break;
}
/*
@@ -3934,31 +3154,79 @@ end_with_restore_list:
*/
#ifdef HAVE_REPLICATION
if (thd->slave_thread &&
- (!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
- !db_ok_with_wild_table(lex->name)))
+ (!rpl_filter->db_ok(lex->name.str) ||
+ !rpl_filter->db_ok_with_wild_table(lex->name.str)))
+ {
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
+ break;
+ }
+#endif
+ if (check_access(thd,DROP_ACL,lex->name.str,0,1,0,
+ is_schema_db(lex->name.str)))
+ break;
+ if (thd->locked_tables || thd->active_transaction())
+ {
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
+ goto error;
+ }
+ res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0);
+ break;
+ }
+ case SQLCOM_RENAME_DB:
+ {
+ LEX_STRING *olddb, *newdb;
+ List_iterator <LEX_STRING> db_list(lex->db_list);
+ olddb= db_list++;
+ newdb= db_list++;
+ if (end_active_trans(thd))
+ {
+ res= 1;
+ break;
+ }
+#ifdef HAVE_REPLICATION
+ if (thd->slave_thread &&
+ (!rpl_filter->db_ok(olddb->str) ||
+ !rpl_filter->db_ok(newdb->str) ||
+ !rpl_filter->db_ok_with_wild_table(olddb->str) ||
+ !rpl_filter->db_ok_with_wild_table(newdb->str)))
{
+ res= 1;
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
break;
}
#endif
- if (check_access(thd,DROP_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
+ if (check_db_name(newdb))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), newdb->str);
break;
+ }
+ if (check_access(thd,ALTER_ACL,olddb->str,0,1,0,is_schema_db(olddb->str)) ||
+ check_access(thd,DROP_ACL,olddb->str,0,1,0,is_schema_db(olddb->str)) ||
+ check_access(thd,CREATE_ACL,newdb->str,0,1,0,is_schema_db(newdb->str)))
+ {
+ res= 1;
+ break;
+ }
if (thd->locked_tables || thd->active_transaction())
{
+ res= 1;
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- res= mysql_rm_db(thd, lex->name, lex->drop_if_exists, 0);
+ res= mysql_rename_db(thd, olddb, newdb);
+ if (!res)
+ send_ok(thd);
break;
}
case SQLCOM_ALTER_DB:
{
- char *db= lex->name;
- DBUG_ASSERT(db); /* Must be set in the parser */
- if (!strip_sp(db) || check_db_name(db))
+ LEX_STRING *db= &lex->name;
+ HA_CREATE_INFO create_info(lex->create_info);
+ if (check_db_name(db))
{
- my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
+ my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
break;
}
/*
@@ -3970,14 +3238,14 @@ end_with_restore_list:
*/
#ifdef HAVE_REPLICATION
if (thd->slave_thread &&
- (!db_ok(db, replicate_do_db, replicate_ignore_db) ||
- !db_ok_with_wild_table(db)))
+ (!rpl_filter->db_ok(db->str) ||
+ !rpl_filter->db_ok_with_wild_table(db->str)))
{
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
break;
}
#endif
- if (check_access(thd, ALTER_ACL, db, 0, 1, 0, is_schema_db(db)))
+ if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0, is_schema_db(db->str)))
break;
if (thd->locked_tables || thd->active_transaction())
{
@@ -3985,23 +3253,76 @@ end_with_restore_list:
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- res= mysql_alter_db(thd, db, &lex->create_info);
+ res= mysql_alter_db(thd, db->str, &create_info);
break;
}
case SQLCOM_SHOW_CREATE_DB:
{
DBUG_EXECUTE_IF("4x_server_emul",
my_error(ER_UNKNOWN_ERROR, MYF(0)); goto error;);
- if (!strip_sp(lex->name) || check_db_name(lex->name))
+ if (check_db_name(&lex->name))
{
- my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
break;
}
- if (check_access(thd,SELECT_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
- break;
- res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
+ res= mysqld_show_create_db(thd, lex->name.str, &lex->create_info);
break;
}
+ case SQLCOM_CREATE_EVENT:
+ case SQLCOM_ALTER_EVENT:
+ do
+ {
+ DBUG_ASSERT(lex->event_parse_data);
+ if (lex->table_or_sp_used())
+ {
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored "
+ "function calls as part of this statement");
+ break;
+ }
+
+ res= sp_process_definer(thd);
+ if (res)
+ break;
+
+ switch (lex->sql_command) {
+ case SQLCOM_CREATE_EVENT:
+ {
+ bool if_not_exists= (lex->create_info.options &
+ HA_LEX_CREATE_IF_NOT_EXISTS);
+ res= Events::create_event(thd, lex->event_parse_data, if_not_exists);
+ break;
+ }
+ case SQLCOM_ALTER_EVENT:
+ res= Events::update_event(thd, lex->event_parse_data,
+ lex->spname ? &lex->spname->m_db : NULL,
+ lex->spname ? &lex->spname->m_name : NULL);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ DBUG_PRINT("info",("DDL error code=%d", res));
+ if (!res)
+ send_ok(thd);
+
+ } while (0);
+ /* Don't do it, if we are inside a SP */
+ if (!thd->spcont)
+ {
+ delete lex->sphead;
+ lex->sphead= NULL;
+ }
+ /* lex->unit.cleanup() is called outside, no need to call it here */
+ break;
+ case SQLCOM_SHOW_CREATE_EVENT:
+ res= Events::show_create_event(thd, lex->spname->m_db,
+ lex->spname->m_name);
+ break;
+ case SQLCOM_DROP_EVENT:
+ if (!(res= Events::drop_event(thd,
+ lex->spname->m_db, lex->spname->m_name,
+ lex->drop_if_exists)))
+ send_ok(thd);
+ break;
case SQLCOM_CREATE_FUNCTION: // UDF function
{
if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
@@ -4060,6 +3381,8 @@ end_with_restore_list:
}
case SQLCOM_REVOKE_ALL:
{
+ if (end_active_trans(thd))
+ goto error;
if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
check_global_access(thd,CREATE_USER_ACL))
break;
@@ -4071,6 +3394,9 @@ end_with_restore_list:
case SQLCOM_REVOKE:
case SQLCOM_GRANT:
{
+ if (end_active_trans(thd))
+ goto error;
+
if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
first_table ? first_table->db : select_lex->db,
first_table ? &first_table->grant.privilege : 0,
@@ -4120,8 +3446,7 @@ end_with_restore_list:
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,
+ if (check_grant_routine(thd, grants | GRANT_ACL, all_tables,
lex->type == TYPE_ENUM_PROCEDURE, 0))
goto error;
/* Conditionally writes to binlog */
@@ -4132,10 +3457,8 @@ end_with_restore_list:
}
else
{
- if (grant_option && check_grant(thd,
- (lex->grant | lex->grant_tot_col |
- GRANT_ACL),
- all_tables, 0, UINT_MAX, 0))
+ if (check_grant(thd,(lex->grant | lex->grant_tot_col | GRANT_ACL),
+ all_tables, 0, UINT_MAX, 0))
goto error;
/* Conditionally writes to binlog */
res= mysql_table_grant(thd, all_tables, lex->users_list,
@@ -4165,7 +3488,7 @@ end_with_restore_list:
{
if (!(user= get_current_user(thd, tmp_user)))
goto error;
- reset_mqh(user);
+ reset_mqh(user, 0);
}
}
}
@@ -4195,14 +3518,12 @@ end_with_restore_list:
We WANT to write and we CAN write.
! we write after unlocking the table.
*/
- /* Presumably, RESET and binlog writing doesn't require synchronization */
+ /*
+ Presumably, RESET and binlog writing doesn't require synchronization
+ */
if (!lex->no_write_to_binlog && write_to_binlog)
{
- if (mysql_bin_log.is_open())
- {
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ write_bin_log(thd, FALSE, thd->query, thd->query_length);
}
send_ok(thd);
}
@@ -4213,13 +3534,20 @@ end_with_restore_list:
{
Item *it= (Item *)lex->value_list.head();
+ if (lex->table_or_sp_used())
+ {
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored "
+ "function calls as part of this statement");
+ break;
+ }
+
if ((!it->fixed && it->fix_fields(lex->thd, &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);
+ sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
break;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -4239,15 +3567,12 @@ end_with_restore_list:
#endif
case SQLCOM_HA_OPEN:
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))
+ if (check_table_access(thd, SELECT_ACL, all_tables, 0))
goto error;
res= mysql_ha_open(thd, first_table, 0);
break;
case SQLCOM_HA_CLOSE:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_db_used(thd, all_tables))
- goto error;
res= mysql_ha_close(thd, first_table);
break;
case SQLCOM_HA_READ:
@@ -4257,8 +3582,6 @@ end_with_restore_list:
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, all_tables))
- goto error;
unit->set_limit(select_lex);
res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
lex->insert_list, lex->ha_rkey_mode, select_lex->where,
@@ -4326,7 +3649,8 @@ end_with_restore_list:
res= TRUE; // cannot happen
else
{
- if (thd->transaction.all.modified_non_trans_table &&
+ if (((thd->options & OPTION_KEEP_LOG) ||
+ thd->transaction.all.modified_non_trans_table) &&
!thd->slave_thread)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
@@ -4396,7 +3720,7 @@ end_with_restore_list:
Verify that the database name is allowed, optionally
lowercase it.
*/
- if (check_db_name(lex->sphead->m_db.str))
+ if (check_db_name(&lex->sphead->m_db))
{
my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str);
goto create_sp_error;
@@ -4434,83 +3758,8 @@ end_with_restore_list:
}
#endif
- /*
- If the definer is not specified, this means that CREATE-statement missed
- DEFINER-clause. DEFINER-clause can be missed in two cases:
-
- - The user submitted a statement w/o the clause. This is a normal
- case, we should assign CURRENT_USER as definer.
-
- - Our slave received an updated from the master, that does not
- replicate definer for stored rountines. We should also assign
- CURRENT_USER as definer here, but also we should mark this routine
- as NON-SUID. This is essential for the sake of backward
- compatibility.
-
- The problem is the slave thread is running under "special" user (@),
- that actually does not exist. In the older versions we do not fail
- execution of a stored routine if its definer does not exist and
- continue the execution under the authorization of the invoker
- (BUG#13198). And now if we try to switch to slave-current-user (@),
- we will fail.
-
- Actually, this leads to the inconsistent state of master and
- slave (different definers, different SUID behaviour), but it seems,
- this is the best we can do.
- */
-
- if (!lex->definer)
- {
- bool local_res= FALSE;
- Query_arena original_arena;
- Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
-
- if (!(lex->definer= create_default_definer(thd)))
- local_res= TRUE;
-
- if (ps_arena)
- thd->restore_active_arena(ps_arena, &original_arena);
-
- /* Error has been already reported. */
- if (local_res)
- goto create_sp_error;
-
- if (thd->slave_thread)
- lex->sphead->m_chistics->suid= SP_IS_NOT_SUID;
- }
-
- /*
- If the specified definer differs from the current user, we should check
- that the current user has SUPER privilege (in order to create a stored
- routine under another user one must have SUPER privilege).
- */
-
- else if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
- my_strcasecmp(system_charset_info,
- lex->definer->host.str,
- thd->security_ctx->priv_host))
- {
- if (check_global_access(thd, SUPER_ACL))
- {
- my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
- goto create_sp_error;
- }
- }
-
- /* Check that the specified definer exists. Emit a warning if not. */
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!is_acl_user(lex->definer->host.str,
- lex->definer->user.str))
- {
- push_warning_printf(thd,
- MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_NO_SUCH_USER,
- ER(ER_NO_SUCH_USER),
- lex->definer->user.str,
- lex->definer->host.str);
- }
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+ if (sp_process_definer(thd))
+ goto create_sp_error;
res= (sp_result= lex->sphead->create(thd));
switch (sp_result) {
@@ -4655,7 +3904,10 @@ create_sp_error:
send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
thd->row_count_func));
else
+ {
+ DBUG_ASSERT(thd->net.report_error == 1 || thd->killed);
goto error; // Substatement should already have sent error
+ }
}
break;
}
@@ -4713,11 +3965,15 @@ create_sp_error:
already puts on CREATE FUNCTION.
*/
/* Conditionally writes to binlog */
- if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
- sp_result= sp_update_procedure(thd, lex->spname,
- &lex->sp_chistics);
- else
- sp_result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
+
+ int type= lex->sql_command == SQLCOM_ALTER_PROCEDURE ?
+ TYPE_ENUM_PROCEDURE :
+ TYPE_ENUM_FUNCTION;
+
+ sp_result= sp_update_routine(thd,
+ type,
+ lex->spname,
+ &lex->sp_chistics);
}
}
switch (sp_result)
@@ -4766,11 +4022,13 @@ create_sp_error:
ER(ER_PROC_AUTO_REVOKE_FAIL));
}
#endif
- /* Conditionally writes to binlog */
- if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
- sp_result= sp_drop_procedure(thd, lex->spname);
- else
- sp_result= sp_drop_function(thd, lex->spname);
+ /* Conditionally writes to binlog */
+
+ int type= lex->sql_command == SQLCOM_DROP_PROCEDURE ?
+ TYPE_ENUM_PROCEDURE :
+ TYPE_ENUM_FUNCTION;
+
+ sp_result= sp_drop_routine(thd, type, lex->spname);
}
else
{
@@ -4784,7 +4042,6 @@ create_sp_error:
if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
goto error;
- /* Does NOT write to binlog */
if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
{
send_ok(thd);
@@ -4828,13 +4085,8 @@ create_sp_error:
}
case SQLCOM_SHOW_CREATE_PROC:
{
- if (lex->spname->m_name.length > NAME_LEN)
+ if (sp_show_create_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname))
{
- 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;
@@ -4843,42 +4095,34 @@ create_sp_error:
}
case SQLCOM_SHOW_CREATE_FUNC:
{
- if (lex->spname->m_name.length > NAME_LEN)
+ if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname))
{
- 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;
}
+#ifdef NOT_USED
case SQLCOM_SHOW_STATUS_PROC:
{
- res= sp_show_status_procedure(thd, (lex->wild ?
- lex->wild->ptr() : NullS));
+ res= sp_show_status_routine(thd, TYPE_ENUM_PROCEDURE,
+ (lex->wild ? lex->wild->ptr() : NullS));
break;
}
case SQLCOM_SHOW_STATUS_FUNC:
{
- res= sp_show_status_function(thd, (lex->wild ?
- lex->wild->ptr() : NullS));
+ res= sp_show_status_routine(thd, TYPE_ENUM_FUNCTION,
+ (lex->wild ? lex->wild->ptr() : NullS));
break;
}
+#endif
#ifndef DBUG_OFF
case SQLCOM_SHOW_PROC_CODE:
case SQLCOM_SHOW_FUNC_CODE:
{
sp_head *sp;
- if (lex->spname->m_name.length > NAME_LEN)
- {
- my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
- goto error;
- }
if (lex->sql_command == SQLCOM_SHOW_PROC_CODE)
sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
&thd->sp_proc_cache, FALSE);
@@ -4895,6 +4139,19 @@ create_sp_error:
break;
}
#endif // ifndef DBUG_OFF
+ case SQLCOM_SHOW_CREATE_TRIGGER:
+ {
+ if (lex->spname->m_name.length > NAME_LEN)
+ {
+ my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
+ goto error;
+ }
+
+ if (show_create_trigger(thd, lex->spname))
+ goto error; /* Error has been already logged. */
+
+ break;
+ }
case SQLCOM_CREATE_VIEW:
{
/*
@@ -4974,7 +4231,7 @@ create_sp_error:
thd->transaction.xid_state.xid.set(thd->lex->xid);
xid_cache_insert(&thd->transaction.xid_state);
thd->transaction.all.modified_non_trans_table= FALSE;
- thd->options|= (ulong) OPTION_BEGIN;
+ thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS;
send_ok(thd);
break;
@@ -5067,7 +4324,7 @@ create_sp_error:
xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
- thd->options&= ~(ulong) OPTION_BEGIN;
+ thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
xid_cache_delete(&thd->transaction.xid_state);
@@ -5098,7 +4355,7 @@ create_sp_error:
my_error(ER_XAER_RMERR, MYF(0));
else
send_ok(thd);
- thd->options&= ~(ulong) OPTION_BEGIN;
+ thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
xid_cache_delete(&thd->transaction.xid_state);
@@ -5107,6 +4364,94 @@ create_sp_error:
case SQLCOM_XA_RECOVER:
res= mysql_xa_recover(thd);
break;
+ case SQLCOM_ALTER_TABLESPACE:
+ if (check_access(thd, ALTER_ACL, thd->db, 0, 1, 0, thd->db ? is_schema_db(thd->db) : 0))
+ break;
+ if (!(res= mysql_alter_tablespace(thd, lex->alter_tablespace_info)))
+ send_ok(thd);
+ break;
+ case SQLCOM_INSTALL_PLUGIN:
+ if (! (res= mysql_install_plugin(thd, &thd->lex->comment,
+ &thd->lex->ident)))
+ send_ok(thd);
+ break;
+ case SQLCOM_UNINSTALL_PLUGIN:
+ if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment)))
+ send_ok(thd);
+ break;
+ case SQLCOM_BINLOG_BASE64_EVENT:
+ {
+#ifndef EMBEDDED_LIBRARY
+ mysql_client_binlog_statement(thd);
+#else /* EMBEDDED_LIBRARY */
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "embedded");
+#endif /* EMBEDDED_LIBRARY */
+ break;
+ }
+ case SQLCOM_CREATE_SERVER:
+ {
+ int error;
+ LEX *lex= thd->lex;
+ DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER"));
+
+ if (check_global_access(thd, SUPER_ACL))
+ break;
+
+ if ((error= create_server(thd, &lex->server_options)))
+ {
+ DBUG_PRINT("info", ("problem creating server <%s>",
+ lex->server_options.server_name));
+ my_error(error, MYF(0), lex->server_options.server_name);
+ break;
+ }
+ send_ok(thd, 1);
+ break;
+ }
+ case SQLCOM_ALTER_SERVER:
+ {
+ int error;
+ LEX *lex= thd->lex;
+ DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER"));
+
+ if (check_global_access(thd, SUPER_ACL))
+ break;
+
+ if ((error= alter_server(thd, &lex->server_options)))
+ {
+ DBUG_PRINT("info", ("problem altering server <%s>",
+ lex->server_options.server_name));
+ my_error(error, MYF(0), lex->server_options.server_name);
+ break;
+ }
+ send_ok(thd, 1);
+ break;
+ }
+ case SQLCOM_DROP_SERVER:
+ {
+ int err_code;
+ LEX *lex= thd->lex;
+ DBUG_PRINT("info", ("case SQLCOM_DROP_SERVER"));
+
+ if (check_global_access(thd, SUPER_ACL))
+ break;
+
+ if ((err_code= drop_server(thd, &lex->server_options)))
+ {
+ if (! lex->drop_if_exists && err_code == ER_FOREIGN_SERVER_DOESNT_EXIST)
+ {
+ DBUG_PRINT("info", ("problem dropping server %s",
+ lex->server_options.server_name));
+ my_error(err_code, MYF(0), lex->server_options.server_name);
+ }
+ else
+ {
+ send_ok(thd, 0);
+ }
+ break;
+ }
+ send_ok(thd, 1);
+ break;
+ }
default:
#ifndef EMBEDDED_LIBRARY
DBUG_ASSERT(0); /* Impossible */
@@ -5114,10 +4459,11 @@ create_sp_error:
send_ok(thd);
break;
}
+
thd->proc_info="query end";
- /* Two binlog-related cleanups: */
/*
+ Binlog-related cleanup:
Reset system variables temporarily modified by SET ONE SHOT.
Exception: If this is a SET, do nothing. This is to allow
@@ -5132,21 +4478,18 @@ create_sp_error:
/*
The return value for ROW_COUNT() is "implementation dependent" if the
statement is not DELETE, INSERT or UPDATE, but -1 is what JDBC and ODBC
- wants.
-
- We do not change the value for a CALL or EXECUTE statement, so the value
- generated by the last called (or executed) statement is preserved.
- */
- if (lex->sql_command != SQLCOM_CALL && lex->sql_command != SQLCOM_EXECUTE &&
- uc_update_queries[lex->sql_command]<2)
+ wants. We also keep the last value in case of SQLCOM_CALL or
+ SQLCOM_EXECUTE.
+ */
+ if (!(sql_command_flags[lex->sql_command] & CF_HAS_ROW_COUNT))
thd->row_count_func= -1;
- goto end;
+ goto finish;
error:
res= TRUE;
-end:
+finish:
if (need_start_waiting)
{
/*
@@ -5159,6 +4502,59 @@ end:
}
+static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
+{
+ LEX *lex= thd->lex;
+ select_result *result=lex->result;
+ bool res;
+ /* assign global limit variable if limit is not given */
+ {
+ SELECT_LEX *param= lex->unit.global_parameters;
+ if (!param->explicit_limit)
+ param->select_limit=
+ new Item_int((ulonglong) thd->variables.select_limit);
+ }
+ if (!(res= open_and_lock_tables(thd, all_tables)))
+ {
+ if (lex->describe)
+ {
+ /*
+ We always use select_send for EXPLAIN, even if it's an EXPLAIN
+ for SELECT ... INTO OUTFILE: a user application should be able
+ to prepend EXPLAIN to any query and receive output for it,
+ even if the query itself redirects the output.
+ */
+ if (!(result= new select_send()))
+ return 1; /* purecov: inspected */
+ thd->send_explain_fields(result);
+ res= mysql_explain_union(thd, &thd->lex->unit, result);
+ if (lex->describe & DESCRIBE_EXTENDED)
+ {
+ char buff[1024];
+ String str(buff,(uint32) sizeof(buff), system_charset_info);
+ str.length(0);
+ thd->lex->unit.print(&str);
+ str.append('\0');
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_YES, str.ptr());
+ }
+ result->send_eof();
+ delete result;
+ }
+ else
+ {
+ if (!result && !(result= new select_send()))
+ return 1; /* purecov: inspected */
+ query_cache_store_query(thd, all_tables);
+ res= handle_select(thd, lex, result, 0);
+ if (result != lex->result)
+ delete result;
+ }
+ }
+ return res;
+}
+
+
/*
Check grants for commands which work only with one table.
@@ -5167,6 +4563,8 @@ end:
thd Thread handler
privilege requested privilege
all_tables global table list of query
+ no_errors FALSE/TRUE - report/don't report error to
+ the client (using my_error() call).
RETURN
0 - OK
@@ -5174,7 +4572,7 @@ end:
*/
bool check_single_table_access(THD *thd, ulong privilege,
- TABLE_LIST *all_tables)
+ TABLE_LIST *all_tables, bool no_errors)
{
Security_context * backup_ctx= thd->security_ctx;
@@ -5190,15 +4588,14 @@ bool check_single_table_access(THD *thd, ulong privilege,
db_name= all_tables->db;
if (check_access(thd, privilege, db_name,
- &all_tables->grant.privilege, 0, 0,
+ &all_tables->grant.privilege, 0, no_errors,
test(all_tables->schema_table)))
goto deny;
/* Show only 1 table for check_grant */
- if (grant_option &&
- !(all_tables->belong_to_view &&
+ if (!(all_tables->belong_to_view &&
(thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
- check_grant(thd, privilege, all_tables, 0, 1, 0))
+ check_grant(thd, privilege, all_tables, 0, 1, no_errors))
goto deny;
thd->security_ctx= backup_ctx;
@@ -5226,7 +4623,7 @@ deny:
bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
{
- if (check_single_table_access (thd,privilege,all_tables))
+ if (check_single_table_access (thd,privilege,all_tables, FALSE))
return 1;
/* Check rights on tables of subselects and implictly opened tables */
@@ -5239,7 +4636,7 @@ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
*/
if (view && subselects_tables->belong_to_view == view)
{
- if (check_single_table_access (thd, privilege, subselects_tables))
+ if (check_single_table_access (thd, privilege, subselects_tables, FALSE))
return 1;
subselects_tables= subselects_tables->next_global;
}
@@ -5374,9 +4771,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
db_access, want_access));
db_access= ((*save_priv=(db_access | sctx->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 &&
+ (!dont_check_global_grants &&
!(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
DBUG_RETURN(FALSE); /* Ok */
@@ -5428,74 +4824,56 @@ bool check_global_access(THD *thd, ulong want_access)
static bool check_show_access(THD *thd, TABLE_LIST *table)
{
- switch (get_schema_table_idx(table->schema_table))
- {
+ switch (get_schema_table_idx(table->schema_table)) {
case SCH_SCHEMATA:
return (specialflag & SPECIAL_SKIP_SHOW_DB) &&
- check_global_access(thd, SHOW_DB_ACL);
+ check_global_access(thd, SHOW_DB_ACL);
case SCH_TABLE_NAMES:
case SCH_TABLES:
case SCH_VIEWS:
case SCH_TRIGGERS:
- {
- const char *dst_db_name= table->schema_select_lex->db;
-
- DBUG_ASSERT(dst_db_name);
+ case SCH_EVENTS:
+ {
+ const char *dst_db_name= table->schema_select_lex->db;
- if (check_access(thd, SELECT_ACL, dst_db_name,
- &thd->col_access, FALSE, FALSE,
- is_schema_db(dst_db_name)))
- {
- return TRUE;
- }
+ DBUG_ASSERT(dst_db_name);
- if (!thd->col_access && check_grant_db(thd, dst_db_name))
- {
- my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- thd->security_ctx->priv_user,
- thd->security_ctx->priv_host,
- dst_db_name);
- return TRUE;
- }
+ if (check_access(thd, SELECT_ACL, dst_db_name,
+ &thd->col_access, FALSE, FALSE,
+ is_schema_db(dst_db_name)))
+ return TRUE;
- return FALSE;
+ if (!thd->col_access && check_grant_db(thd, dst_db_name))
+ {
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ thd->security_ctx->priv_user,
+ thd->security_ctx->priv_host,
+ dst_db_name);
+ return TRUE;
}
+ return FALSE;
+ }
+
case SCH_COLUMNS:
case SCH_STATISTICS:
- {
- TABLE_LIST *dst_table=
- (TABLE_LIST *) table->schema_select_lex->table_list.first;
+ {
+ TABLE_LIST *dst_table;
+ dst_table= (TABLE_LIST *) table->schema_select_lex->table_list.first;
- DBUG_ASSERT(dst_table);
+ DBUG_ASSERT(dst_table);
- if (check_access(thd, SELECT_ACL | EXTRA_ACL,
- dst_table->db,
- &dst_table->grant.privilege,
- FALSE, FALSE,
- test(dst_table->schema_table)))
- {
- return FALSE;
- }
-
- return grant_option &&
- check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE);
- }
+ if (check_access(thd, SELECT_ACL | EXTRA_ACL,
+ dst_table->db,
+ &dst_table->grant.privilege,
+ FALSE, FALSE,
+ test(dst_table->schema_table)))
+ return FALSE;
- 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:
+ return (check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE));
+ }
+ default:
break;
}
@@ -5530,8 +4908,6 @@ bool
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
bool no_errors)
{
- uint found=0;
- ulong found_access=0;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
TABLE_LIST *org_tables= tables;
#endif
@@ -5573,9 +4949,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
}
if (tables->derived ||
- (tables->table && (int)tables->table->s->tmp_table) ||
- my_tz_check_n_skip_implicit_tables(&tables,
- thd->lex->time_zone_tables_used))
+ (tables->table && (int)tables->table->s->tmp_table))
continue;
thd->security_ctx= sctx;
if ((sctx->master_access & want_access) ==
@@ -5584,26 +4958,17 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
tables->grant.privilege= want_access;
else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
{
- if (found && !grant_option) // db already checked
- tables->grant.privilege=found_access;
- else
- {
- if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
+ if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
0, no_errors, test(tables->schema_table)))
- goto deny; // Access denied
- found_access=tables->grant.privilege;
- found=1;
- }
+ goto deny; // Access denied
}
else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
0, no_errors, test(tables->schema_table)))
goto deny;
}
thd->security_ctx= backup_ctx;
- if (grant_option)
- return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
+ return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
- return FALSE;
deny:
thd->security_ctx= backup_ctx;
return TRUE;
@@ -5633,11 +4998,10 @@ check_routine_access(THD *thd, ulong want_access,char *db, char *name,
return TRUE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (grant_option)
return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
-#endif
-
+#else
return FALSE;
+#endif
}
@@ -5699,7 +5063,7 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
if (!check_access(thd, access, table->db,
&table->grant.privilege, 0, 1,
test(table->schema_table)) &&
- !grant_option || !check_grant(thd, access, table, 0, 1, 1))
+ !check_grant(thd, access, table, 0, 1, 1))
DBUG_RETURN(0);
}
}
@@ -5728,31 +5092,12 @@ bool check_merge_table_access(THD *thd, char *db,
}
-static bool check_db_used(THD *thd,TABLE_LIST *tables)
-{
- char *current_db= NULL;
- for (; tables; tables= tables->next_global)
- {
- if (tables->db == NULL)
- {
- /*
- This code never works and should be removed in 5.1. All tables
- that are added to the list of tables should already have its
- database field initialized properly (see st_lex::add_table_to_list).
- */
- DBUG_ASSERT(0);
- if (thd->copy_db_to(&current_db, 0))
- return TRUE;
- tables->db= current_db;
- }
- }
- return FALSE;
-}
-
/****************************************************************************
Check stack size; Send error if there isn't enough stack to continue
****************************************************************************/
+#ifndef EMBEDDED_LIBRARY
+
#if STACK_DIRECTION < 0
#define used_stack(A,B) (long) (A - B)
#else
@@ -5763,7 +5108,6 @@ static bool check_db_used(THD *thd,TABLE_LIST *tables)
long max_stack_used;
#endif
-#ifndef EMBEDDED_LIBRARY
/*
Note: The 'buf' parameter is necessary, even if it is unused here.
- fix_fields functions has a "dummy" buffer large enough for the
@@ -5771,7 +5115,7 @@ long max_stack_used;
- Passing to check_stack_overrun() prevents the compiler from removing it.
*/
bool check_stack_overrun(THD *thd, long margin,
- char *buf __attribute__((unused)))
+ uchar *buf __attribute__((unused)))
{
long stack_used;
DBUG_ASSERT(thd == current_thd);
@@ -5803,19 +5147,19 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
if (!lex->yacc_yyvs)
old_info= *yystacksize;
*yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX);
- if (!(lex->yacc_yyvs= (char*)
- my_realloc((gptr) lex->yacc_yyvs,
+ if (!(lex->yacc_yyvs= (uchar*)
+ my_realloc(lex->yacc_yyvs,
*yystacksize*sizeof(**yyvs),
MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
- !(lex->yacc_yyss= (char*)
- my_realloc((gptr) lex->yacc_yyss,
+ !(lex->yacc_yyss= (uchar*)
+ my_realloc(lex->yacc_yyss,
*yystacksize*sizeof(**yyss),
MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
return 1;
if (old_info)
{ // Copy old info from stack
- memcpy(lex->yacc_yyss, (gptr) *yyss, old_info*sizeof(**yyss));
- memcpy(lex->yacc_yyvs, (gptr) *yyvs, old_info*sizeof(**yyvs));
+ memcpy(lex->yacc_yyss, (uchar*) *yyss, old_info*sizeof(**yyss));
+ memcpy(lex->yacc_yyvs, (uchar*) *yyvs, old_info*sizeof(**yyvs));
}
*yyss=(short*) lex->yacc_yyss;
*yyvs=(YYSTYPE*) lex->yacc_yyvs;
@@ -5829,6 +5173,7 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
DESCRIPTION
This needs to be called before execution of every statement
(prepared or conventional).
+ It is not called by substatements of routines.
TODO
Make it a method of THD and align its name with the rest of
@@ -5839,16 +5184,32 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
void mysql_reset_thd_for_next_command(THD *thd)
{
DBUG_ENTER("mysql_reset_thd_for_next_command");
+ DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
thd->free_list= 0;
thd->select_number= 1;
- thd->query_start_used= thd->insert_id_used=0;
- thd->last_insert_id_used_bin_log= FALSE;
+ /*
+ Those two lines below are theoretically unneeded as
+ THD::cleanup_after_query() should take care of this already.
+ */
+ thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty();
+ thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
+
+ thd->query_start_used= 0;
thd->is_fatal_error= thd->time_zone_used= 0;
thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
SERVER_QUERY_NO_INDEX_USED |
SERVER_QUERY_NO_GOOD_INDEX_USED);
+ /*
+ If in autocommit mode and not in a transaction, reset
+ OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG to not get warnings
+ in ha_rollback_trans() about some tables couldn't be rolled back.
+ */
+ if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+ {
+ thd->options&= ~OPTION_KEEP_LOG;
+ thd->transaction.all.modified_non_trans_table= FALSE;
+ }
DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
- thd->tmp_table_used= 0;
thd->thread_specific_used= FALSE;
if (!thd->in_sub_stmt)
{
@@ -5862,6 +5223,12 @@ void mysql_reset_thd_for_next_command(THD *thd)
thd->rand_used= 0;
thd->sent_row_count= thd->examined_row_count= 0;
}
+ /*
+ Because we come here only for start of top-statements, binlog format is
+ constant inside a complex statement (using stored functions) etc.
+ */
+ thd->reset_current_stmt_binlog_row_based();
+
DBUG_VOID_RETURN;
}
@@ -6010,6 +5377,7 @@ void mysql_init_multi_delete(LEX *lex)
lex->query_tables_last= &lex->query_tables;
}
+
/*
When you modify mysql_parse(), you may need to mofify
mysql_test_parse_for_slave() in this same file.
@@ -6017,11 +5385,12 @@ void mysql_init_multi_delete(LEX *lex)
/**
Parse a query.
- @param thd Current thread
- @param inBuf Begining of the query text
- @param length Length of the query text
- @param [out] semicolon For multi queries, position of the character of
- the next query in the query text.
+
+ @param thd Current thread
+ @param inBuf Begining of the query text
+ @param length Length of the query text
+ @param[out] found_semicolon For multi queries, position of the character of
+ the next query in the query text.
*/
void mysql_parse(THD *thd, const char *inBuf, uint length,
@@ -6058,12 +5427,11 @@ void mysql_parse(THD *thd, const char *inBuf, uint length,
sp_cache_flush_obsolete(&thd->sp_func_cache);
Lex_input_stream lip(thd, inBuf, length);
- thd->m_lip= &lip;
- int err= MYSQLparse(thd);
+ bool err= parse_sql(thd, &lip, NULL);
*found_semicolon= lip.found_semicolon;
- if (!err && ! thd->is_fatal_error)
+ if (!err)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (mqh_used && thd->user_connect &&
@@ -6086,8 +5454,8 @@ void mysql_parse(THD *thd, const char *inBuf, uint length,
PROCESSLIST.
Note that we don't need LOCK_thread_count to modify query_length.
*/
- if (lip.found_semicolon &&
- (thd->query_length= (ulong)(lip.found_semicolon - thd->query)))
+ if (*found_semicolon &&
+ (thd->query_length= (ulong)(*found_semicolon - thd->query)))
thd->query_length--;
/* Actually execute the query */
lex->set_trg_event_type_for_tables();
@@ -6142,12 +5510,10 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
DBUG_ENTER("mysql_test_parse_for_slave");
Lex_input_stream lip(thd, inBuf, length);
- thd->m_lip= &lip;
lex_start(thd);
mysql_reset_thd_for_next_command(thd);
- int err= MYSQLparse((void*) thd);
- if (!err && ! thd->is_fatal_error &&
+ if (!parse_sql(thd, &lip, NULL) &&
all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
error= 1; /* Ignore question */
thd->end_statement();
@@ -6163,7 +5529,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
** Return 0 if ok
******************************************************************************/
-bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
+bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
char *length, char *decimals,
uint type_modifier,
Item *default_value, Item *on_update_value,
@@ -6172,29 +5538,34 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
List<String> *interval_list, CHARSET_INFO *cs,
uint uint_geom_type)
{
- register create_field *new_field;
+ register Create_field *new_field;
LEX *lex= thd->lex;
DBUG_ENTER("add_field_to_list");
- if (strlen(field_name) > NAME_LEN)
+ if (check_string_char_length(field_name, "", NAME_CHAR_LEN,
+ system_charset_info, 1))
{
- my_error(ER_TOO_LONG_IDENT, MYF(0), field_name); /* purecov: inspected */
+ my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
if (type_modifier & PRI_KEY_FLAG)
{
- lex->col_list.push_back(new key_part_spec(field_name,0));
- lex->alter_info.key_list.push_back(new Key(Key::PRIMARY, NullS,
- HA_KEY_ALG_UNDEF, 0,
- lex->col_list));
+ Key *key;
+ lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
+ key= new Key(Key::PRIMARY, NullS,
+ &default_key_create_info,
+ 0, lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty();
}
if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
{
- lex->col_list.push_back(new key_part_spec(field_name,0));
- lex->alter_info.key_list.push_back(new Key(Key::UNIQUE, NullS,
- HA_KEY_ALG_UNDEF, 0,
- lex->col_list));
+ Key *key;
+ lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
+ key= new Key(Key::UNIQUE, NullS,
+ &default_key_create_info, 0,
+ lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty();
}
@@ -6209,9 +5580,9 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
*/
if (default_value->type() == Item::FUNC_ITEM &&
!(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
- type == FIELD_TYPE_TIMESTAMP))
+ type == MYSQL_TYPE_TIMESTAMP))
{
- my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
DBUG_RETURN(1);
}
else if (default_value->type() == Item::NULL_ITEM)
@@ -6220,24 +5591,24 @@ 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)
{
- my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
DBUG_RETURN(1);
}
}
else if (type_modifier & AUTO_INCREMENT_FLAG)
{
- my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
DBUG_RETURN(1);
}
}
- if (on_update_value && type != FIELD_TYPE_TIMESTAMP)
+ if (on_update_value && type != MYSQL_TYPE_TIMESTAMP)
{
- my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
+ my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
DBUG_RETURN(1);
}
- if (type == FIELD_TYPE_TIMESTAMP && length)
+ if (type == MYSQL_TYPE_TIMESTAMP && length)
{
/* Display widths are no longer supported for TIMSTAMP as of MySQL 4.1.
In other words, for declarations such as TIMESTAMP(2), TIMESTAMP(4),
@@ -6245,14 +5616,11 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
*/
char buf[32];
my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length);
- push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DEPRECATED_SYNTAX,
- ER(ER_WARN_DEPRECATED_SYNTAX),
- buf, "TIMESTAMP");
+ WARN_DEPRECATED(thd, "5.2", buf, "'TIMESTAMP'");
}
- if (!(new_field= new create_field()) ||
- new_field->init(thd, field_name, type, length, decimals, type_modifier,
+ if (!(new_field= new Create_field()) ||
+ new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
default_value, on_update_value, comment, change,
interval_list, cs, uint_geom_type))
DBUG_RETURN(1);
@@ -6282,41 +5650,11 @@ add_proc_to_list(THD* thd, Item *item)
*item_ptr= item;
order->item=item_ptr;
order->free_me=0;
- thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
+ thd->lex->proc_list.link_in_list((uchar*) order,(uchar**) &order->next);
return 0;
}
-/* Fix escaping of _, % and \ in database and table names (for ODBC) */
-
-static void remove_escape(char *name)
-{
- if (!*name) // For empty DB names
- return;
- char *to;
-#ifdef USE_MB
- char *strend=name+(uint) strlen(name);
-#endif
- for (to=name; *name ; name++)
- {
-#ifdef USE_MB
- int l;
- if (use_mb(system_charset_info) &&
- (l = my_ismbchar(system_charset_info, name, strend)))
- {
- while (l--)
- *to++ = *name++;
- name--;
- continue;
- }
-#endif
- if (*name == '\\' && name[1])
- name++; // Skip '\\'
- *to++= *name;
- }
- *to=0;
-}
-
/****************************************************************************
** save order by and tables in own lists
****************************************************************************/
@@ -6334,7 +5672,7 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
order->free_me=0;
order->used=0;
order->counter_used= 0;
- list.link_in_list((byte*) order,(byte**) &order->next);
+ list.link_in_list((uchar*) order,(uchar**) &order->next);
DBUG_RETURN(0);
}
@@ -6364,8 +5702,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
LEX_STRING *alias,
ulong table_options,
thr_lock_type lock_type,
- List<String> *use_index_arg,
- List<String> *ignore_index_arg,
+ List<Index_hint> *index_hints_arg,
LEX_STRING *option)
{
register TABLE_LIST *ptr;
@@ -6385,6 +5722,13 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
DBUG_RETURN(0);
}
+ if (table->is_derived_table() == FALSE && table->db.str &&
+ check_db_name(&table->db))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str);
+ DBUG_RETURN(0);
+ }
+
if (!alias) /* Alias is case sensitive */
{
if (table->sel)
@@ -6393,18 +5737,13 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
DBUG_RETURN(0);
}
- if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
+ if (!(alias_str= (char*) thd->memdup(alias_str,table->table.length+1)))
DBUG_RETURN(0);
}
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(0); /* purecov: inspected */
if (table->db.str)
{
- if (table->is_derived_table() == FALSE && check_db_name(table->db.str))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str);
- DBUG_RETURN(0);
- }
ptr->db= table->db.str;
ptr->db_length= table->db.length;
}
@@ -6427,7 +5766,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
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
+ (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0))
{
my_error(ER_UNKNOWN_TABLE, MYF(0),
ptr->table_name, INFORMATION_SCHEMA_NAME.str);
@@ -6438,12 +5777,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
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,
- sizeof(*use_index_arg));
- if (ignore_index_arg)
- ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index_arg,
- sizeof(*ignore_index_arg));
+ ptr->index_hints= index_hints_arg;
ptr->option= option ? option->str : 0;
/* check that used name is unique */
if (lock_type != TL_IGNORE)
@@ -6490,7 +5824,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
previous table reference to 'ptr'. Here we also add one element to the
list 'table_list'.
*/
- table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
+ table_list.link_in_list((uchar*) ptr, (uchar**) &ptr->next_local);
ptr->next_name_resolution_table= NULL;
/* Link table in global list (all used tables) */
lex->add_to_query_tables(ptr);
@@ -6529,11 +5863,12 @@ bool st_select_lex::init_nested_join(THD *thd)
sizeof(NESTED_JOIN))))
DBUG_RETURN(1);
nested_join= ptr->nested_join=
- ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
+ ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
join_list->push_front(ptr);
ptr->embedding= embedding;
ptr->join_list= join_list;
+ ptr->alias= (char*) "(nested_join)";
embedding= ptr;
join_list= &nested_join->join_list;
join_list->empty();
@@ -6614,10 +5949,11 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
sizeof(NESTED_JOIN))))
DBUG_RETURN(0);
nested_join= ptr->nested_join=
- ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
+ ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
ptr->embedding= embedding;
ptr->join_list= join_list;
+ ptr->alias= (char*) "(nest_last_join)";
embedded_list= &nested_join->join_list;
embedded_list->empty();
@@ -6792,7 +6128,7 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
fake_select_lex->context.resolve_in_select_list= TRUE;
fake_select_lex->context.select_lex= fake_select_lex;
- if (!first_sl->next_select())
+ if (!is_union())
{
/*
This works only for
@@ -6989,7 +6325,8 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
{
/*
Flush the normal query log, the update log, the binary log,
- the slow query log, and the relay log (if it exists).
+ the slow query log, the relay log (if it exists) and the log
+ tables.
*/
/*
@@ -6999,8 +6336,6 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
than it would help them)
*/
tmp_write_to_binlog= 0;
- mysql_log.new_file(1);
- mysql_slow_log.new_file(1);
if( mysql_bin_log.is_open() )
{
mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
@@ -7010,7 +6345,11 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
rotate_relay_log(active_mi);
pthread_mutex_unlock(&LOCK_active_mi);
#endif
- if (ha_flush_logs())
+
+ /* flush slow and general logs */
+ logger.flush_logs(thd);
+
+ if (ha_flush_logs(NULL))
result=1;
if (flush_error_log())
result=1;
@@ -7109,31 +6448,37 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
}
#endif
if (options & REFRESH_USER_RESOURCES)
- reset_mqh((LEX_USER *) NULL);
+ reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
*write_to_binlog= tmp_write_to_binlog;
return result;
}
+
/*
- kill on thread
+ kills a thread
SYNOPSIS
kill_one_thread()
thd Thread class
id Thread id
+ only_kill_query Should it kill the query or the connection
NOTES
This is written such that we have a short lock on LOCK_thread_count
*/
-void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
+uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
{
THD *tmp;
uint error=ER_NO_SUCH_THREAD;
+ DBUG_ENTER("kill_one_thread");
+ DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query));
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
I_List_iterator<THD> it(threads);
while ((tmp=it++))
{
+ if (tmp->command == COM_DAEMON)
+ continue;
if (tmp->thread_id == id)
{
pthread_mutex_lock(&tmp->LOCK_delete); // Lock from delete
@@ -7153,8 +6498,25 @@ void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
error=ER_KILL_DENIED_ERROR;
pthread_mutex_unlock(&tmp->LOCK_delete);
}
+ DBUG_PRINT("exit", ("%d", error));
+ DBUG_RETURN(error);
+}
- if (!error)
+
+/*
+ kills a thread and sends response
+
+ SYNOPSIS
+ sql_kill()
+ thd Thread class
+ id Thread id
+ only_kill_query Should it kill the query or the connection
+*/
+
+void sql_kill(THD *thd, ulong id, bool only_kill_query)
+{
+ uint error;
+ if (!(error= kill_one_thread(thd, id, only_kill_query)))
send_ok(thd);
else
my_error(error, MYF(0), id);
@@ -7163,8 +6525,8 @@ void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
/* If pointer is not a null pointer, append filename to it */
-static bool append_file_to_dir(THD *thd, const char **filename_ptr,
- const char *table_name)
+bool append_file_to_dir(THD *thd, const char **filename_ptr,
+ const char *table_name)
{
char buff[FN_REFLEN],*ptr, *end;
if (!*filename_ptr)
@@ -7180,7 +6542,7 @@ static bool append_file_to_dir(THD *thd, const char **filename_ptr,
/* Fix is using unix filename format on dos */
strmov(buff,*filename_ptr);
end=convert_dirname(buff, *filename_ptr, NullS);
- if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
+ if (!(ptr= (char*) thd->alloc((size_t) (end-buff) + strlen(table_name)+1)))
return 1; // End of memory
*filename_ptr=ptr;
strxmov(ptr,buff,table_name,NullS);
@@ -7322,12 +6684,11 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
else if ((check_access(thd, UPDATE_ACL, table->db,
&table->grant.privilege, 0, 1,
test(table->schema_table)) ||
- grant_option &&
check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
(check_access(thd, SELECT_ACL, table->db,
&table->grant.privilege, 0, 0,
test(table->schema_table)) ||
- grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
+ check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
DBUG_RETURN(TRUE);
table->table_in_first_from_clause= 1;
@@ -7335,19 +6696,17 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
/*
Is there tables of subqueries?
*/
- if (&lex->select_lex != lex->all_selects_list || lex->time_zone_tables_used)
+ if (&lex->select_lex != lex->all_selects_list)
{
DBUG_PRINT("info",("Checking sub query list"));
for (table= tables; table; table= table->next_global)
{
- if (!my_tz_check_n_skip_implicit_tables(&table,
- lex->time_zone_tables_used) &&
- !table->table_in_first_from_clause)
+ if (!table->table_in_first_from_clause)
{
if (check_access(thd, SELECT_ACL, table->db,
&table->grant.privilege, 0, 0,
test(table->schema_table)) ||
- grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
+ check_grant(thd, SELECT_ACL, table, 0, 1, 0))
DBUG_RETURN(TRUE);
}
}
@@ -7388,8 +6747,7 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
/* sql_yacc guarantees that tables and aux_tables are not zero */
DBUG_ASSERT(aux_tables != 0);
- if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
- check_table_access(thd, SELECT_ACL, tables, 0))
+ if (check_table_access(thd, SELECT_ACL, tables, 0))
DBUG_RETURN(TRUE);
/*
@@ -7489,8 +6847,7 @@ bool update_precheck(THD *thd, TABLE_LIST *tables)
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));
+ DBUG_RETURN(check_one_table_access(thd, UPDATE_ACL, tables));
}
@@ -7552,20 +6909,18 @@ bool insert_precheck(THD *thd, TABLE_LIST *tables)
my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
DBUG_RETURN(TRUE);
}
- if (check_db_used(thd, tables))
- DBUG_RETURN(TRUE);
DBUG_RETURN(FALSE);
}
/**
- @brief Check privileges for SHOW CREATE TABLE statement.
+ @brief Check privileges for SHOW CREATE TABLE statement.
- @param thd Thread context
- @param table Target table
+ @param thd Thread context
+ @param table Target table
- @retval TRUE Failure
- @retval FALSE Success
+ @retval TRUE Failure
+ @retval FALSE Success
*/
static bool check_show_create_table_access(THD *thd, TABLE_LIST *table)
@@ -7573,7 +6928,7 @@ static bool check_show_create_table_access(THD *thd, TABLE_LIST *table)
return check_access(thd, SELECT_ACL | EXTRA_ACL, table->db,
&table->grant.privilege, 0, 0,
test(table->schema_table)) ||
- grant_option && check_grant(thd, SELECT_ACL, table, 2, UINT_MAX, 0);
+ check_grant(thd, SELECT_ACL, table, 2, UINT_MAX, 0);
}
@@ -7609,7 +6964,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
(TABLE_LIST *)
lex->create_info.merge_list.first))
goto err;
- if (grant_option && want_priv != CREATE_TMP_ACL &&
+ if (want_priv != CREATE_TMP_ACL &&
check_grant(thd, want_priv, create_table, 0, 1, 0))
goto err;
@@ -7620,7 +6975,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
/* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
/*
- Only do the check for PS, becasue we on execute we have to check that
+ Only do the check for PS, because 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).
*/
@@ -7791,26 +7146,118 @@ LEX_USER *get_current_user(THD *thd, LEX_USER *user)
/*
- Check that length of a string does not exceed some limit.
+ Check that byte length of a string does not exceed some limit.
SYNOPSIS
- check_string_length()
- str string to be checked
- err_msg error message to be displayed if the string is too long
- max_length max length
+ check_string_byte_length()
+ str string to be checked
+ err_msg error message to be displayed if the string is too long
+ max_byte_length max length in bytes
RETURN
FALSE the passed string is not longer than max_length
TRUE the passed string is longer than max_length
+
+ NOTE
+ The function is not used in existing code but can be useful later?
*/
-bool check_string_length(LEX_STRING *str, const char *err_msg,
- uint max_length)
+bool check_string_byte_length(LEX_STRING *str, const char *err_msg,
+ uint max_byte_length)
{
- if (str->length <= max_length)
+ if (str->length <= max_byte_length)
return FALSE;
- my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_length);
+ my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_byte_length);
+
+ return TRUE;
+}
+
+
+/*
+ Check that char length of a string does not exceed some limit.
+
+ SYNOPSIS
+ check_string_char_length()
+ str string to be checked
+ err_msg error message to be displayed if the string is too long
+ max_char_length max length in symbols
+ cs string charset
+
+ RETURN
+ FALSE the passed string is not longer than max_char_length
+ TRUE the passed string is longer than max_char_length
+*/
+
+
+bool check_string_char_length(LEX_STRING *str, const char *err_msg,
+ uint max_char_length, CHARSET_INFO *cs,
+ bool no_error)
+{
+ int well_formed_error;
+ uint res= cs->cset->well_formed_len(cs, str->str, str->str + str->length,
+ max_char_length, &well_formed_error);
+
+ if (!well_formed_error && str->length == res)
+ return FALSE;
+ if (!no_error)
+ my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_char_length);
return TRUE;
}
+
+
+extern int MYSQLparse(void *thd); // from sql_yacc.cc
+
+
+/**
+ This is a wrapper of MYSQLparse(). All the code should call parse_sql()
+ instead of MYSQLparse().
+
+ @param thd Thread context.
+ @param lip Lexer context.
+ @param creation_ctx Object creation context.
+
+ @return Error status.
+ @retval FALSE on success.
+ @retval TRUE on parsing error.
+*/
+
+bool parse_sql(THD *thd,
+ Lex_input_stream *lip,
+ Object_creation_ctx *creation_ctx)
+{
+ DBUG_ASSERT(thd->m_lip == NULL);
+
+ /* Backup creation context. */
+
+ Object_creation_ctx *backup_ctx= NULL;
+
+ if (creation_ctx)
+ backup_ctx= creation_ctx->set_n_backup(thd);
+
+ /* Set Lex_input_stream. */
+
+ thd->m_lip= lip;
+
+ /* Parse the query. */
+
+ bool err_status= MYSQLparse(thd) != 0 || thd->is_fatal_error;
+
+ /* Reset Lex_input_stream. */
+
+ thd->m_lip= NULL;
+
+ /* Restore creation context. */
+
+ if (creation_ctx)
+ creation_ctx->restore_env(thd, backup_ctx);
+
+ /* That's it. */
+
+ return err_status;
+}
+
+/**
+ @} (end of group Runtime_Environment)
+*/