sql_parse.cc 233 KB
Newer Older
1
/* Copyright (C) 2000-2003 MySQL AB
2

unknown's avatar
unknown committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
7

unknown's avatar
unknown committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
12

unknown's avatar
unknown committed
13 14 15 16
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

17
#define MYSQL_LEX 1
unknown's avatar
unknown committed
18
#include "mysql_priv.h"
19
#include "sql_repl.h"
unknown's avatar
unknown committed
20
#include "rpl_filter.h"
21
#include "repl_failsafe.h"
unknown's avatar
unknown committed
22 23 24 25
#include <m_ctype.h>
#include <myisam.h>
#include <my_dir.h>

26
#include "sp_head.h"
27
#include "sp.h"
28
#include "sp_cache.h"
29
#include "events.h"
30
#include "event_data_objects.h"
31

unknown's avatar
unknown committed
32 33 34 35 36 37 38 39 40 41 42
#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?
*/
unknown's avatar
unknown committed
43 44 45
#define SSL_HANDSHAKE_SIZE      2
#define NORMAL_HANDSHAKE_SIZE   6
#define MIN_HANDSHAKE_SIZE      2
unknown's avatar
unknown committed
46
#else
unknown's avatar
unknown committed
47
#define MIN_HANDSHAKE_SIZE      6
unknown's avatar
unknown committed
48
#endif /* HAVE_OPENSSL */
unknown's avatar
unknown committed
49

50 51 52 53 54 55
/* Used in error handling only */
#define SP_TYPE_STRING(LP) \
  ((LP)->sphead->m_type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE")
#define SP_COM_STRING(LP) \
  ((LP)->sql_command == SQLCOM_CREATE_SPFUNCTION || \
   (LP)->sql_command == SQLCOM_ALTER_FUNCTION || \
56
   (LP)->sql_command == SQLCOM_SHOW_CREATE_FUNC || \
57 58 59
   (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
   "FUNCTION" : "PROCEDURE")

60
static void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
unknown's avatar
unknown committed
61
#ifndef NO_EMBEDDED_ACCESS_CHECKS
62
static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
63
static void decrease_user_connections(USER_CONN *uc);
64
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
65
static bool check_multi_update_lock(THD *thd);
66
static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
unknown's avatar
unknown committed
67

68
const char *any_db="*any*";	// Special symbol for check_access
unknown's avatar
unknown committed
69

unknown's avatar
unknown committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
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
unknown's avatar
unknown committed
102 103
};

unknown's avatar
unknown committed
104 105 106 107
const char *xa_state_names[]={
  "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
};

unknown's avatar
unknown committed
108 109 110
#ifdef __WIN__
static void  test_signal(int sig_ptr)
{
unknown's avatar
unknown committed
111
#if !defined( DBUG_OFF)
unknown's avatar
unknown committed
112 113 114 115 116 117
  MessageBox(NULL,"Test signal","DBUG",MB_OK);
#endif
}
static void init_signals(void)
{
  int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
118
  for (int i=0 ; i < 7 ; i++)
unknown's avatar
unknown committed
119 120 121 122
    signal( signals[i], test_signal) ;
}
#endif

unknown's avatar
unknown committed
123 124 125 126 127
static void unlock_locked_tables(THD *thd)
{
  if (thd->locked_tables)
  {
    thd->lock=thd->locked_tables;
128
    thd->locked_tables=0;			// Will be automatically closed
unknown's avatar
unknown committed
129 130 131 132
    close_thread_tables(thd);			// Free tables
  }
}

133

134
bool end_active_trans(THD *thd)
135
{
unknown's avatar
unknown committed
136
  int error=0;
137
  DBUG_ENTER("end_active_trans");
138
  if (unlikely(thd->in_sub_stmt))
139 140 141 142
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    DBUG_RETURN(1);
  }
143 144 145 146 147 148
  if (thd->transaction.xid_state.xa_state != XA_NOTR)
  {
    my_error(ER_XAER_RMFAIL, MYF(0),
             xa_state_names[thd->transaction.xid_state.xa_state]);
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
149
  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
unknown's avatar
unknown committed
150
		      OPTION_TABLE_LOCK))
151
  {
152 153 154 155
    DBUG_PRINT("info",("options: 0x%lx", (ulong) thd->options));
    /* Safety if one did "drop table" on locked tables */
    if (!thd->locked_tables)
      thd->options&= ~OPTION_TABLE_LOCK;
156
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
157
    if (ha_commit(thd))
unknown's avatar
unknown committed
158
      error=1;
159
  }
160 161
  thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
                   OPTION_KEEP_LOG);
162
  DBUG_RETURN(error);
163 164
}

unknown's avatar
unknown committed
165
bool begin_trans(THD *thd)
unknown's avatar
unknown committed
166 167
{
  int error=0;
168
  if (unlikely(thd->in_sub_stmt))
169 170 171 172
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    return 1;
  }
unknown's avatar
unknown committed
173 174 175 176 177 178 179 180 181 182
  if (thd->locked_tables)
  {
    thd->lock=thd->locked_tables;
    thd->locked_tables=0;			// Will be automatically closed
    close_thread_tables(thd);			// Free tables
  }
  if (end_active_trans(thd))
    error= -1;
  else
  {
183
    LEX *lex= thd->lex;
184
    thd->options|= OPTION_BEGIN;
unknown's avatar
unknown committed
185 186
    thd->server_status|= SERVER_STATUS_IN_TRANS;
    if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
unknown's avatar
unknown committed
187
      error= ha_start_consistent_snapshot(thd);
unknown's avatar
unknown committed
188 189 190
  }
  return error;
}
191

unknown's avatar
unknown committed
192
#ifdef HAVE_REPLICATION
193 194 195
/*
  Returns true if all tables should be ignored
*/
196 197
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
{
unknown's avatar
unknown committed
198 199
  return rpl_filter->is_on() && tables && !thd->spcont &&
         !rpl_filter->tables_ok(thd->db, tables);
200
}
unknown's avatar
unknown committed
201
#endif
202 203


204 205 206 207 208 209 210 211 212 213 214 215
static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables)
{
  for (TABLE_LIST *table= tables; table; table= table->next_global)
  {
    DBUG_ASSERT(table->db && table->table_name);
    if (table->updating &&
        !find_temporary_table(thd, table->db, table->table_name))
      return 1;
  }
  return 0;
}

216
#ifndef NO_EMBEDDED_ACCESS_CHECKS
217 218
static HASH hash_user_connections;

unknown's avatar
unknown committed
219 220
static int get_or_create_user_conn(THD *thd, const char *user,
				   const char *host,
unknown's avatar
unknown committed
221
				   USER_RESOURCES *mqh)
222
{
223
  int return_val= 0;
unknown's avatar
unknown committed
224
  uint temp_len, user_len;
225
  char temp_user[USER_HOST_BUFF_SIZE];
226 227 228 229 230
  struct  user_conn *uc;

  DBUG_ASSERT(user != 0);
  DBUG_ASSERT(host != 0);

231
  user_len= strlen(user);
232
  temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
233
  (void) pthread_mutex_lock(&LOCK_user_conn);
unknown's avatar
unknown committed
234 235
  if (!(uc = (struct  user_conn *) hash_search(&hash_user_connections,
					       (byte*) temp_user, temp_len)))
236
  {
unknown's avatar
unknown committed
237 238 239
    /* First connection for user; Create a user connection object */
    if (!(uc= ((struct user_conn*)
	       my_malloc(sizeof(struct user_conn) + temp_len+1,
unknown's avatar
unknown committed
240 241
			 MYF(MY_WME)))))
    {
242
      net_send_error(thd, 0, NullS);		// Out of memory
243
      return_val= 1;
244
      goto end;
unknown's avatar
unknown committed
245
    }
246 247
    uc->user=(char*) (uc+1);
    memcpy(uc->user,temp_user,temp_len+1);
248
    uc->host= uc->user + user_len +  1;
249
    uc->len= temp_len;
250
    uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
251 252
    uc->user_resources= *mqh;
    uc->intime= thd->thr_create_time;
unknown's avatar
SCRUM  
unknown committed
253
    if (my_hash_insert(&hash_user_connections, (byte*) uc))
254 255
    {
      my_free((char*) uc,0);
256
      net_send_error(thd, 0, NullS);		// Out of memory
257
      return_val= 1;
258 259 260 261
      goto end;
    }
  }
  thd->user_connect=uc;
262
  uc->connections++;
263 264 265
end:
  (void) pthread_mutex_unlock(&LOCK_user_conn);
  return return_val;
unknown's avatar
unknown committed
266

267
}
268
#endif /* !NO_EMBEDDED_ACCESS_CHECKS */
269 270 271


/*
272 273
  Check if user exist and password supplied is correct. 

274 275
  SYNOPSIS
    check_user()
276
    thd          thread handle, thd->security_ctx->{host,user,ip} are used
277 278 279
    command      originator of the check: now check_user is called
                 during connect and change user procedures; used for 
                 logging.
280
    passwd       scrambled password received from client
281 282 283 284
    passwd_len   length of scrambled password
    db           database name to connect to, may be NULL
    check_count  dont know exactly

285
    Note, that host, user and passwd may point to communication buffer.
286
    Current implementation does not depend on that, but future changes
287 288 289
    should be done with this in mind; 'thd' is INOUT, all other params
    are 'IN'.

290
  RETURN VALUE
291 292
    0  OK; thd->security_ctx->user/master_access/priv_user/db_access and
       thd->db are updated; OK is sent to client;
unknown's avatar
unknown committed
293 294
   -1  access denied or handshake error; error is sent to client;
   >0  error, not sent to client
unknown's avatar
unknown committed
295 296
*/

unknown's avatar
unknown committed
297 298 299
int check_user(THD *thd, enum enum_server_command command, 
	       const char *passwd, uint passwd_len, const char *db,
	       bool check_count)
unknown's avatar
unknown committed
300
{
301
  DBUG_ENTER("check_user");
unknown's avatar
unknown committed
302
  
unknown's avatar
unknown committed
303
#ifdef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
304
  thd->main_security_ctx.master_access= GLOBAL_ACLS;       // Full rights
305
  /* Change database if necessary */
306 307
  if (db && db[0])
  {
308 309 310 311
    /*
      thd->db is saved in caller and needs to be freed by caller if this
      function returns 0
    */
unknown's avatar
unknown committed
312
    thd->reset_db(NULL, 0);
313
    if (mysql_change_db(thd, db, FALSE))
314
    {
315 316
      /* Send the error to the client */
      net_send_error(thd);
317 318 319
      DBUG_RETURN(-1);
    }
  }
320
  send_ok(thd);
321
  DBUG_RETURN(0);
unknown's avatar
unknown committed
322 323
#else

324 325 326 327 328
  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);
  
329
  /*
330 331
    If the server is running in secure auth mode, short scrambles are 
    forbidden.
332
  */
333
  if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
unknown's avatar
unknown committed
334
  {
335
    net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
unknown's avatar
unknown committed
336
    general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
337
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
338
  }
unknown's avatar
unknown committed
339 340 341 342
  if (passwd_len != 0 &&
      passwd_len != SCRAMBLE_LENGTH &&
      passwd_len != SCRAMBLE_LENGTH_323)
    DBUG_RETURN(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
343

344
  /*
345
    Clear thd->db as it points to something, that will be freed when 
346
    connection is closed. We don't want to accidentally free a wrong pointer
347 348
    if connect failed. Also in case of 'CHANGE USER' failure, current
    database will be switched to 'no database selected'.
349
  */
unknown's avatar
unknown committed
350 351
  thd->reset_db(NULL, 0);

352
  USER_RESOURCES ur;
353
  int res= acl_getroot(thd, &ur, passwd, passwd_len);
unknown's avatar
unknown committed
354
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
355
  if (res == -1)
unknown's avatar
unknown committed
356
  {
unknown's avatar
unknown committed
357 358 359 360 361 362
    /*
      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.
    */
363
    NET *net= &thd->net;
364
    if (opt_secure_auth_local)
365
    {
366
      net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
367 368
                       thd->main_security_ctx.user,
                       thd->main_security_ctx.host_or_ip);
unknown's avatar
unknown committed
369 370 371
      general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
                        thd->main_security_ctx.user,
                        thd->main_security_ctx.host_or_ip);
372 373
      DBUG_RETURN(-1);
    }
unknown's avatar
unknown committed
374
    /* We have to read very specific packet size */
375
    if (send_old_password_request(thd) ||
unknown's avatar
unknown committed
376
        my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
377
    {
unknown's avatar
unknown committed
378 379 380 381 382
      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 */
383
    res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
unknown's avatar
unknown committed
384
  }
unknown's avatar
unknown committed
385
#endif /*EMBEDDED_LIBRARY*/
unknown's avatar
unknown committed
386 387
  /* here res is always >= 0 */
  if (res == 0)
unknown's avatar
unknown committed
388
  {
389 390
    if (!(thd->main_security_ctx.master_access &
          NO_ACCESS)) // authentication is OK
391
    {
unknown's avatar
unknown committed
392
      DBUG_PRINT("info",
unknown's avatar
unknown committed
393
                 ("Capabilities: %lu  packet_length: %ld  Host: '%s'  "
unknown's avatar
unknown committed
394
                  "Login user: '%s' Priv_user: '%s'  Using password: %s "
unknown's avatar
unknown committed
395
                  "Access: %lu  db: '%s'",
396 397 398 399 400
                  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,
unknown's avatar
unknown committed
401
                  passwd_len ? "yes": "no",
402 403
                  thd->main_security_ctx.master_access,
                  (thd->db ? thd->db : "*none*")));
unknown's avatar
unknown committed
404 405

      if (check_count)
406
      {
unknown's avatar
unknown committed
407
        VOID(pthread_mutex_lock(&LOCK_thread_count));
unknown's avatar
unknown committed
408
        bool count_ok= thread_count <= max_connections + delayed_insert_threads
409
                       || (thd->main_security_ctx.master_access & SUPER_ACL);
unknown's avatar
unknown committed
410 411
        VOID(pthread_mutex_unlock(&LOCK_thread_count));
        if (!count_ok)
unknown's avatar
unknown committed
412
        {                                         // too many connections
413
          net_send_error(thd, ER_CON_COUNT_ERROR);
unknown's avatar
unknown committed
414 415
          DBUG_RETURN(-1);
        }
416
      }
unknown's avatar
unknown committed
417

unknown's avatar
unknown committed
418
      /* Why logging is performed before all checks've passed? */
unknown's avatar
unknown committed
419 420 421 422 423 424 425 426
      general_log_print(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*) "");
unknown's avatar
unknown committed
427

428
      /*
429 430 431
        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.
432
      */
433
      thd->main_security_ctx.db_access=0;
unknown's avatar
unknown committed
434 435

      /* Don't allow user to connect if he has done too many queries */
436
      if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
unknown's avatar
unknown committed
437
	   max_user_connections) &&
438
	  get_or_create_user_conn(thd,
439 440 441 442
            (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),
443
            &ur))
unknown's avatar
unknown committed
444 445
	DBUG_RETURN(-1);
      if (thd->user_connect &&
446 447
	  (thd->user_connect->user_resources.conn_per_hour ||
	   thd->user_connect->user_resources.user_conn ||
unknown's avatar
unknown committed
448 449 450
	   max_user_connections) &&
	  check_for_max_user_connections(thd, thd->user_connect))
	DBUG_RETURN(-1);
unknown's avatar
unknown committed
451

452
      /* Change database if necessary */
unknown's avatar
unknown committed
453
      if (db && db[0])
454
      {
455
        if (mysql_change_db(thd, db, FALSE))
unknown's avatar
unknown committed
456
        {
457 458
          /* Send error to the client */
          net_send_error(thd);
unknown's avatar
unknown committed
459 460 461 462
          if (thd->user_connect)
            decrease_user_connections(thd->user_connect);
          DBUG_RETURN(-1);
        }
463
      }
464
      send_ok(thd);
unknown's avatar
unknown committed
465 466 467
      thd->password= test(passwd_len);          // remember for error messages 
      /* Ready to handle queries */
      DBUG_RETURN(0);
unknown's avatar
unknown committed
468 469
    }
  }
unknown's avatar
unknown committed
470
  else if (res == 2) // client gave short hash, server has long hash
unknown's avatar
unknown committed
471
  {
472
    net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
unknown's avatar
unknown committed
473
    general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
unknown's avatar
unknown committed
474
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
475
  }
476
  net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
477 478
                   thd->main_security_ctx.user,
                   thd->main_security_ctx.host_or_ip,
479
                   passwd_len ? ER(ER_YES) : ER(ER_NO));
unknown's avatar
unknown committed
480 481 482 483
  general_log_print(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));
unknown's avatar
unknown committed
484
  DBUG_RETURN(-1);
unknown's avatar
unknown committed
485
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
486 487
}

unknown's avatar
unknown committed
488
/*
unknown's avatar
unknown committed
489 490
  Check for maximum allowable user connections, if the mysqld server is
  started with corresponding variable that is greater then 0.
unknown's avatar
unknown committed
491 492
*/

493 494
extern "C" byte *get_key_conn(user_conn *buff, uint *length,
			      my_bool not_used __attribute__((unused)))
unknown's avatar
unknown committed
495 496 497 498 499
{
  *length=buff->len;
  return (byte*) buff->user;
}

500
extern "C" void free_user(struct user_conn *uc)
unknown's avatar
unknown committed
501 502 503 504
{
  my_free((char*) uc,MYF(0));
}

unknown's avatar
unknown committed
505
void init_max_user_conn(void)
unknown's avatar
unknown committed
506
{
507
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
508 509
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
		   0,0,
510
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
511
		   0);
512
#endif
unknown's avatar
unknown committed
513 514 515
}


unknown's avatar
unknown committed
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
/*
  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
*/

unknown's avatar
unknown committed
533 534
#ifndef NO_EMBEDDED_ACCESS_CHECKS

535
static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
unknown's avatar
unknown committed
536
{
537
  int error=0;
538
  DBUG_ENTER("check_for_max_user_connections");
unknown's avatar
unknown committed
539

540
  (void) pthread_mutex_lock(&LOCK_user_conn);
541
  if (max_user_connections && !uc->user_resources.user_conn &&
unknown's avatar
unknown committed
542
      max_user_connections < (uint) uc->connections)
unknown's avatar
unknown committed
543
  {
544
    net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
545 546
    error=1;
    goto end;
unknown's avatar
unknown committed
547
  }
548
  time_out_user_resource_limits(thd, uc);
549 550 551 552 553 554 555 556 557 558 559
  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)
560
  {
561
    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
unknown's avatar
unknown committed
562
                     "max_connections_per_hour",
563
                     (long) uc->user_resources.conn_per_hour);
564 565 566
    error=1;
    goto end;
  }
567
  uc->conn_per_hour++;
unknown's avatar
unknown committed
568 569

  end:
570 571
  if (error)
    uc->connections--; // no need for decrease_user_connections() here
572
  (void) pthread_mutex_unlock(&LOCK_user_conn);
573
  DBUG_RETURN(error);
unknown's avatar
unknown committed
574 575
}

unknown's avatar
unknown committed
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
/*
  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.
*/

594
static void decrease_user_connections(USER_CONN *uc)
unknown's avatar
unknown committed
595
{
596
  DBUG_ENTER("decrease_user_connections");
597 598 599
  (void) pthread_mutex_lock(&LOCK_user_conn);
  DBUG_ASSERT(uc->connections);
  if (!--uc->connections && !mqh_used)
unknown's avatar
unknown committed
600 601
  {
    /* Last connection for user; Delete it */
unknown's avatar
unknown committed
602
    (void) hash_delete(&hash_user_connections,(byte*) uc);
unknown's avatar
unknown committed
603
  }
604
  (void) pthread_mutex_unlock(&LOCK_user_conn);
605
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
606 607
}

608 609
#endif /* NO_EMBEDDED_ACCESS_CHECKS */

610

unknown's avatar
unknown committed
611 612
void free_max_user_conn(void)
{
613
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
614
  hash_free(&hash_user_connections);
615
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
616 617
}

unknown's avatar
unknown committed
618

619

620 621 622
/*
  Mark all commands that somehow changes a table
  This is used to check number of updates / hour
unknown's avatar
unknown committed
623 624 625

  sql_command is actually set to SQLCOM_END sometimes
  so we need the +1 to include it in the array.
unknown's avatar
unknown committed
626

627
  See COMMAND_FLAG_xxx for different type of commands
unknown's avatar
unknown committed
628 629
     2  - query that returns meaningful ROW_COUNT() -
          a number of modified rows
630 631
*/

632
uint sql_command_flags[SQLCOM_END+1];
633 634 635

void init_update_queries(void)
{
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
  bzero((gptr) &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;
  sql_command_flags[SQLCOM_TRUNCATE]=       CF_CHANGES_DATA;
  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_FUNC]= 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_STATUS_PROC]= 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);

  /*
    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;
693 694
}

695

unknown's avatar
unknown committed
696 697
bool is_update_query(enum enum_sql_command command)
{
unknown's avatar
unknown committed
698
  DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
699
  return (sql_command_flags[command] & CF_CHANGES_DATA) != 0;
unknown's avatar
unknown committed
700
}
701

unknown's avatar
unknown committed
702
/*
703 704
  Reset per-hour user resource limits when it has been more than
  an hour since they were last checked
unknown's avatar
unknown committed
705

706 707 708 709
  SYNOPSIS:
    time_out_user_resource_limits()
    thd			Thread handler
    uc			User connection details
unknown's avatar
unknown committed
710

711 712 713 714
  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.
*/
715

716
static void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
unknown's avatar
unknown committed
717
{
unknown's avatar
unknown committed
718
  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
719
  DBUG_ENTER("time_out_user_resource_limits");
unknown's avatar
unknown committed
720

unknown's avatar
unknown committed
721
  /* If more than a hour since last check, reset resource checking */
722 723 724 725 726 727 728
  if (check_time  - uc->intime >= 3600)
  {
    uc->questions=1;
    uc->updates=0;
    uc->conn_per_hour=0;
    uc->intime=check_time;
  }
729 730 731 732 733 734 735 736 737 738 739 740

  DBUG_VOID_RETURN;
}


/*
  Check if maximum queries per hour limit has been reached
  returns 0 if OK.
*/

static bool check_mqh(THD *thd, uint check_command)
{
741 742
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  bool error= 0;
743 744 745 746 747 748 749 750
  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);

unknown's avatar
unknown committed
751
  /* Check that we have not done too many questions / hour */
752 753 754
  if (uc->user_resources.questions &&
      uc->questions++ >= uc->user_resources.questions)
  {
755 756
    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
                     (long) uc->user_resources.questions);
757 758 759
    error=1;
    goto end;
  }
760
  if (check_command < (uint) SQLCOM_END)
unknown's avatar
unknown committed
761
  {
unknown's avatar
unknown committed
762
    /* Check that we have not done too many updates / hour */
763 764
    if (uc->user_resources.updates &&
        (sql_command_flags[check_command] & CF_CHANGES_DATA) &&
unknown's avatar
unknown committed
765 766
	uc->updates++ >= uc->user_resources.updates)
    {
767 768
      net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
                       (long) uc->user_resources.updates);
unknown's avatar
unknown committed
769 770 771
      error=1;
      goto end;
    }
unknown's avatar
unknown committed
772 773
  }
end:
774
  (void) pthread_mutex_unlock(&LOCK_user_conn);
775
  DBUG_RETURN(error);
776 777
#else
  return (0);
unknown's avatar
unknown committed
778
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
779 780
}

unknown's avatar
unknown committed
781

unknown's avatar
unknown committed
782
static void reset_mqh(LEX_USER *lu, bool get_them= 0)
783
{
unknown's avatar
unknown committed
784
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
785
  (void) pthread_mutex_lock(&LOCK_user_conn);
unknown's avatar
unknown committed
786
  if (lu)  // for GRANT
787
  {
788
    USER_CONN *uc;
789
    uint temp_len=lu->user.length+lu->host.length+2;
790
    char temp_user[USER_HOST_BUFF_SIZE];
791

unknown's avatar
unknown committed
792 793
    memcpy(temp_user,lu->user.str,lu->user.length);
    memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
794
    temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
unknown's avatar
unknown committed
795
    if ((uc = (struct  user_conn *) hash_search(&hash_user_connections,
796
						(byte*) temp_user, temp_len)))
797 798
    {
      uc->questions=0;
799
      get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
800 801
      uc->updates=0;
      uc->conn_per_hour=0;
802 803
    }
  }
unknown's avatar
unknown committed
804
  else
805
  {
unknown's avatar
unknown committed
806
    /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
unknown's avatar
unknown committed
807
    for (uint idx=0;idx < hash_user_connections.records; idx++)
808
    {
unknown's avatar
unknown committed
809 810
      USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
						      idx);
811 812 813 814 815
      if (get_them)
	get_mqh(uc->user,uc->host,uc);
      uc->questions=0;
      uc->updates=0;
      uc->conn_per_hour=0;
816 817
    }
  }
unknown's avatar
unknown committed
818
  (void) pthread_mutex_unlock(&LOCK_user_conn);
unknown's avatar
unknown committed
819
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
820
}
unknown's avatar
unknown committed
821

822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
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
  */
  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;
  }
}


unknown's avatar
unknown committed
853
/*
854
    Perform handshake, authorize client and update thd ACL variables.
855
  SYNOPSIS
856
    check_connection()
857
    thd  thread handle
858 859

  RETURN
860
     0  success, OK is sent to user, thd is updated.
861 862
    -1  error, which is sent to user
   > 0  error code (not sent to user)
unknown's avatar
unknown committed
863 864
*/

unknown's avatar
unknown committed
865 866
#ifndef EMBEDDED_LIBRARY
static int check_connection(THD *thd)
unknown's avatar
unknown committed
867
{
868
  uint connect_errors= 0;
unknown's avatar
unknown committed
869
  NET *net= &thd->net;
unknown's avatar
unknown committed
870 871
  ulong pkt_len= 0;
  char *end;
872

873 874
  DBUG_PRINT("info",
             ("New connection received on %s", vio_description(net->vio)));
unknown's avatar
unknown committed
875
#ifdef SIGNAL_WITH_VIO_CLOSE
876
  thd->set_active_vio(net->vio);
unknown's avatar
unknown committed
877
#endif
878

879
  if (!thd->main_security_ctx.host)         // If TCP/IP connection
unknown's avatar
unknown committed
880
  {
881
    char ip[30];
882

883
    if (vio_peer_addr(net->vio, ip, &thd->peer_port))
unknown's avatar
unknown committed
884
      return (ER_BAD_HOST_ERROR);
885
    if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
unknown's avatar
unknown committed
886
      return (ER_OUT_OF_RESOURCES);
887
    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
unknown's avatar
unknown committed
888
    vio_in_addr(net->vio,&thd->remote.sin_addr);
889
    if (!(specialflag & SPECIAL_NO_RESOLVE))
unknown's avatar
unknown committed
890
    {
891
      vio_in_addr(net->vio,&thd->remote.sin_addr);
892 893
      thd->main_security_ctx.host=
        ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
894
      /* Cut very long hostnames to avoid possible overflows */
895
      if (thd->main_security_ctx.host)
896
      {
897 898 899 900
        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;
901
      }
902 903
      if (connect_errors > max_connect_errors)
        return(ER_HOST_IS_BLOCKED);
unknown's avatar
unknown committed
904
    }
unknown's avatar
unknown committed
905
    DBUG_PRINT("info",("Host: %s  ip: %s",
906 907 908 909 910
		       (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))
unknown's avatar
unknown committed
911 912
      return(ER_HOST_NOT_PRIVILEGED);
  }
913
  else /* Hostname given means that the connection was on a socket */
unknown's avatar
unknown committed
914
  {
915 916 917
    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;
918 919
    /* Reset sin_addr */
    bzero((char*) &thd->remote, sizeof(thd->remote));
unknown's avatar
unknown committed
920 921 922
  }
  vio_keepalive(net->vio, TRUE);
  {
unknown's avatar
unknown committed
923
    /* buff[] needs to big enough to hold the server_version variable */
924
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
925 926
    ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
			  CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
unknown's avatar
unknown committed
927

928 929 930 931 932
    if (opt_using_transactions)
      client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
    client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
unknown's avatar
unknown committed
933 934
#ifdef HAVE_OPENSSL
    if (ssl_acceptor_fd)
935
      client_flags |= CLIENT_SSL;       /* Wow, SSL is available! */
unknown's avatar
unknown committed
936
#endif /* HAVE_OPENSSL */
unknown's avatar
unknown committed
937

938 939 940 941 942 943 944 945 946 947 948
    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
unknown's avatar
unknown committed
949
      tail: that's why first part of the scramble is placed here, and second
950 951
      part at the end of packet.
    */
952
    end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
953 954 955
   
    int2store(end, client_flags);
    /* write server characteristics: up to 16 bytes allowed */
956
    end[2]=(char) default_charset_info->number;
957 958 959 960 961 962 963 964 965
    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,
unknown's avatar
unknown committed
966
			  (uint) (end-buff)) ||
967
	(pkt_len= my_net_read(net)) == packet_error ||
unknown's avatar
unknown committed
968 969 970 971 972 973 974 975 976 977 978
	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);
unknown's avatar
unknown committed
979
  if (thd->packet.alloc(thd->variables.net_buffer_length))
unknown's avatar
unknown committed
980 981 982
    return(ER_OUT_OF_RESOURCES);

  thd->client_capabilities=uint2korr(net->read_pos);
983 984 985 986
  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);
unknown's avatar
unknown committed
987
    DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
988
    thd_init_client_charset(thd, (uint) net->read_pos[8]);
unknown's avatar
unknown committed
989
    thd->update_charset();
990
    end= (char*) net->read_pos+32;
991 992 993 994 995 996 997
  }
  else
  {
    thd->max_client_packet_length= uint3korr(net->read_pos+2);
    end= (char*) net->read_pos+5;
  }

998
  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
999
    thd->variables.sql_mode|= MODE_IGNORE_SPACE;
unknown's avatar
unknown committed
1000
#ifdef HAVE_OPENSSL
unknown's avatar
unknown committed
1001
  DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
unknown's avatar
unknown committed
1002 1003 1004
  if (thd->client_capabilities & CLIENT_SSL)
  {
    /* Do the SSL layering. */
1005 1006 1007 1008 1009
    if (!ssl_acceptor_fd)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
unknown's avatar
unknown committed
1010
    DBUG_PRINT("info", ("IO layer change in progress..."));
unknown's avatar
unknown committed
1011 1012
    if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
    {
1013
      DBUG_PRINT("error", ("Failed to accept new SSL connection"));
unknown's avatar
unknown committed
1014
      inc_host_errors(&thd->remote.sin_addr);
unknown's avatar
unknown committed
1015
      return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
1016
    }
unknown's avatar
unknown committed
1017
    DBUG_PRINT("info", ("Reading user information over SSL layer"));
1018
    if ((pkt_len= my_net_read(net)) == packet_error ||
unknown's avatar
unknown committed
1019 1020
	pkt_len < NORMAL_HANDSHAKE_SIZE)
    {
unknown's avatar
unknown committed
1021 1022
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
unknown's avatar
unknown committed
1023 1024 1025 1026
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
  }
1027 1028 1029
#endif

  if (end >= (char*) net->read_pos+ pkt_len +2)
unknown's avatar
unknown committed
1030
  {
1031 1032
    inc_host_errors(&thd->remote.sin_addr);
    return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
1033 1034 1035
  }

  if (thd->client_capabilities & CLIENT_INTERACTIVE)
1036
    thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
1037
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
1038 1039
      opt_using_transactions)
    net->return_status= &thd->server_status;
unknown's avatar
unknown committed
1040
  net->read_timeout=(uint) thd->variables.net_read_timeout;
unknown's avatar
unknown committed
1041

1042 1043
  char *user= end;
  char *passwd= strend(user)+1;
1044
  uint user_len= passwd - user - 1;
unknown's avatar
unknown committed
1045
  char *db= passwd;
unknown's avatar
unknown committed
1046 1047
  char db_buff[NAME_LEN + 1];           // buffer to store db in utf8
  char user_buff[USERNAME_LENGTH + 1];	// buffer to store user in utf8
1048 1049 1050
  uint dummy_errors;

  /*
unknown's avatar
unknown committed
1051 1052 1053
    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'.
1054 1055

    This strlen() can't be easily deleted without changing protocol.
unknown's avatar
unknown committed
1056
  */
1057
  uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
unknown's avatar
unknown committed
1058 1059 1060
    *passwd++ : strlen(passwd);
  db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
    db + passwd_len + 1 : 0;
1061
  /* strlen() can't be easily deleted without changing protocol */
unknown's avatar
unknown committed
1062 1063
  uint db_len= db ? strlen(db) : 0;

unknown's avatar
unknown committed
1064
  if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
unknown's avatar
unknown committed
1065 1066 1067 1068
  {
    inc_host_errors(&thd->remote.sin_addr);
    return ER_HANDSHAKE_ERROR;
  }
unknown's avatar
unknown committed
1069

unknown's avatar
unknown committed
1070 1071
  /* Since 4.1 all database names are stored in utf8 */
  if (db)
unknown's avatar
unknown committed
1072
  {
1073 1074
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
                             system_charset_info,
unknown's avatar
unknown committed
1075
                             db, db_len,
1076
                             thd->charset(), &dummy_errors)]= 0;
1077
    db= db_buff;
unknown's avatar
unknown committed
1078
  }
unknown's avatar
unknown committed
1079

1080 1081 1082
  user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
                                       system_charset_info, user, user_len,
                                       thd->charset(), &dummy_errors)]= '\0';
1083
  user= user_buff;
unknown's avatar
unknown committed
1084

1085 1086 1087 1088 1089 1090 1091 1092
  /* 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;
  }

1093 1094 1095
  if (thd->main_security_ctx.user)
    x_free(thd->main_security_ctx.user);
  if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0))))
1096
    return (ER_OUT_OF_RESOURCES);
unknown's avatar
unknown committed
1097
  return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
unknown's avatar
unknown committed
1098 1099
}

1100

1101 1102
void execute_init_command(THD *thd, sys_var_str *init_command_var,
			  rw_lock_t *var_mutex)
unknown's avatar
unknown committed
1103 1104 1105 1106
{
  Vio* save_vio;
  ulong save_client_capabilities;

1107 1108 1109 1110 1111 1112 1113 1114 1115
  thd->proc_info= "Execution of init_command";
  /*
    We need to lock init_command_var because
    during execution of init_command_var query
    values of init_command_var can't be changed
  */
  rw_rdlock(var_mutex);
  thd->query= init_command_var->value;
  thd->query_length= init_command_var->value_length;
unknown's avatar
unknown committed
1116 1117
  save_client_capabilities= thd->client_capabilities;
  thd->client_capabilities|= CLIENT_MULTI_QUERIES;
1118 1119 1120 1121
  /*
    We don't need return result of execution to client side.
    To forbid this we should set thd->net.vio to 0.
  */
unknown's avatar
unknown committed
1122 1123
  save_vio= thd->net.vio;
  thd->net.vio= 0;
1124
  thd->net.no_send_error= 0;
unknown's avatar
unknown committed
1125
  dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
1126
  rw_unlock(var_mutex);
unknown's avatar
unknown committed
1127 1128 1129 1130 1131
  thd->client_capabilities= save_client_capabilities;
  thd->net.vio= save_vio;
}


1132
pthread_handler_t handle_one_connection(void *arg)
unknown's avatar
unknown committed
1133 1134 1135
{
  THD *thd=(THD*) arg;
  uint launch_time  =
unknown's avatar
unknown committed
1136
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
unknown's avatar
unknown committed
1137 1138 1139 1140 1141
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status );

  pthread_detach_this_thread();

unknown's avatar
unknown committed
1142
#if !defined( __WIN__) // Win32 calls this in pthread_create
unknown's avatar
unknown committed
1143
  /* The following calls needs to be done before we call DBUG_ macros */
1144
  if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
unknown's avatar
unknown committed
1145
  {
1146
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
1147
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
1148 1149 1150 1151 1152
    end_thread(thd,0);
    return 0;
  }
#endif

1153 1154 1155 1156 1157 1158 1159
  /*
    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.
  */
unknown's avatar
unknown committed
1160
  DBUG_PRINT("info", ("handle_one_connection called by thread %lu\n",
unknown's avatar
unknown committed
1161
		      thd->thread_id));
unknown's avatar
unknown committed
1162
  /* now that we've called my_thread_init(), it is safe to call DBUG_* */
unknown's avatar
unknown committed
1163

unknown's avatar
unknown committed
1164
#if defined(__WIN__)
unknown's avatar
unknown committed
1165
  init_signals();
unknown's avatar
unknown committed
1166
#elif !defined(__NETWARE__)
unknown's avatar
unknown committed
1167 1168 1169 1170
  sigset_t set;
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
1171
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
1172 1173
  if (thd->store_globals())
  {
1174
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
1175
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
1176 1177 1178 1179 1180 1181 1182 1183
    end_thread(thd,0);
    return 0;
  }

  do
  {
    int error;
    NET *net= &thd->net;
1184
    Security_context *sctx= thd->security_ctx;
1185
    net->no_send_error= 0;
unknown's avatar
unknown committed
1186

1187
    if ((error=check_connection(thd)))
unknown's avatar
unknown committed
1188 1189
    {						// Wrong permissions
      if (error > 0)
1190
	net_printf_error(thd, error, sctx->host_or_ip);
unknown's avatar
unknown committed
1191 1192
#ifdef __NT__
      if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
1193
	my_sleep(1000);				/* must wait after eof() */
unknown's avatar
unknown committed
1194
#endif
1195
      statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
1196 1197
      goto end_thread;
    }
unknown's avatar
unknown committed
1198
#ifdef __NETWARE__
1199
    netware_reg_user(sctx->ip, sctx->user, "MySQL");
unknown's avatar
unknown committed
1200
#endif
1201
    if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
1202 1203 1204 1205
      thd->options |= OPTION_BIG_SELECTS;
    if (thd->client_capabilities & CLIENT_COMPRESS)
      net->compress=1;				// Use compression

unknown's avatar
unknown committed
1206
    thd->version= refresh_version;
1207
    thd->proc_info= 0;
1208
    thd->command= COM_SLEEP;
1209 1210
    thd->set_time();
    thd->init_for_queries();
unknown's avatar
unknown committed
1211

1212
    if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
unknown's avatar
unknown committed
1213
    {
1214 1215
      execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
      if (thd->query_error)
1216
      {
unknown's avatar
unknown committed
1217
	thd->killed= THD::KILL_CONNECTION;
1218 1219 1220 1221 1222 1223
        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);
      }
1224 1225 1226
      thd->proc_info=0;
      thd->set_time();
      thd->init_for_queries();
unknown's avatar
unknown committed
1227 1228
    }

1229 1230
    while (!net->error && net->vio != 0 &&
           !(thd->killed == THD::KILL_CONNECTION))
unknown's avatar
unknown committed
1231
    {
1232
      net->no_send_error= 0;
unknown's avatar
unknown committed
1233 1234 1235
      if (do_command(thd))
	break;
    }
1236 1237
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
unknown's avatar
unknown committed
1238
    if (net->error && net->vio != 0 && net->report_error)
unknown's avatar
unknown committed
1239
    {
1240
      if (!thd->killed && thd->variables.log_warnings > 1)
unknown's avatar
unknown committed
1241
	sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
unknown's avatar
unknown committed
1242
                          thd->thread_id,(thd->db ? thd->db : "unconnected"),
1243 1244
                          sctx->user ? sctx->user : "unauthenticated",
                          sctx->host_or_ip,
unknown's avatar
unknown committed
1245 1246
                          (net->last_errno ? ER(net->last_errno) :
                           ER(ER_UNKNOWN_ERROR)));
1247
      net_send_error(thd, net->last_errno, NullS);
unknown's avatar
unknown committed
1248
      statistic_increment(aborted_threads,&LOCK_status);
unknown's avatar
unknown committed
1249
    }
1250 1251 1252 1253
    else if (thd->killed)
    {
      statistic_increment(aborted_threads,&LOCK_status);
    }
1254
    
unknown's avatar
unknown committed
1255
end_thread:
1256
    close_connection(thd, 0, 1);
unknown's avatar
unknown committed
1257 1258 1259 1260 1261 1262
    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;
1263
    thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
1264 1265 1266 1267 1268
  } while (!(test_flags & TEST_NO_THREADS));
  /* The following is only executed if we are not using --one-thread */
  return(0);					/* purecov: deadcode */
}

unknown's avatar
unknown committed
1269 1270
#endif /* EMBEDDED_LIBRARY */

1271 1272 1273 1274
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
unknown's avatar
unknown committed
1275

1276
pthread_handler_t handle_bootstrap(void *arg)
unknown's avatar
unknown committed
1277
{
1278 1279 1280
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
unknown's avatar
unknown committed
1281

1282
  /* The following must be called before DBUG_ENTER */
1283
  thd->thread_stack= (char*) &thd;
1284
  if (my_thread_init() || thd->store_globals())
unknown's avatar
unknown committed
1285
  {
unknown's avatar
unknown committed
1286
#ifndef EMBEDDED_LIBRARY
1287
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
unknown's avatar
unknown committed
1288
#endif
1289
    thd->fatal_error();
1290
    goto end;
unknown's avatar
unknown committed
1291
  }
1292 1293
  DBUG_ENTER("handle_bootstrap");

unknown's avatar
unknown committed
1294
#ifndef EMBEDDED_LIBRARY
1295 1296
  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
1297
#if !defined(__WIN__) && !defined(__NETWARE__)
unknown's avatar
unknown committed
1298
  sigset_t set;
1299 1300
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
unknown's avatar
unknown committed
1301
#endif
unknown's avatar
unknown committed
1302
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
1303

1304
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
1305 1306 1307 1308
    thd->options |= OPTION_BIG_SELECTS;

  thd->proc_info=0;
  thd->version=refresh_version;
1309 1310
  thd->security_ctx->priv_user=
    thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
unknown's avatar
unknown committed
1311
  thd->security_ctx->priv_host[0]=0;
1312 1313 1314 1315 1316 1317
  /*
    Make the "client" handle multiple results. This is necessary
    to enable stored procedures with SELECTs and Dynamic SQL
    in init-file.
  */
  thd->client_capabilities|= CLIENT_MULTI_RESULTS;
unknown's avatar
unknown committed
1318

1319
  buff= (char*) thd->net.buff;
1320
  thd->init_for_queries();
unknown's avatar
unknown committed
1321 1322
  while (fgets(buff, thd->net.max_packet, file))
  {
1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
    /* 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 */
unknown's avatar
unknown committed
1345

unknown's avatar
unknown committed
1346
    while (length && (my_isspace(thd->charset(), buff[length-1]) ||
1347
                      buff[length-1] == ';'))
unknown's avatar
unknown committed
1348 1349
      length--;
    buff[length]=0;
1350
    thd->query_length=length;
unknown's avatar
unknown committed
1351 1352
    thd->query= thd->memdup_w_gap(buff, length+1, 
				  thd->db_length+1+QUERY_CACHE_FLAGS_SIZE);
unknown's avatar
unknown committed
1353
    thd->query[length] = '\0';
1354 1355 1356 1357
    /*
      We don't need to obtain LOCK_thread_count here because in bootstrap
      mode we have only one thread.
    */
1358
    thd->query_id=next_query_id();
unknown's avatar
unknown committed
1359 1360
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
1361
    if (thd->is_fatal_error)
1362
      break;
unknown's avatar
unknown committed
1363
    free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
1364
#ifdef USING_TRANSACTIONS
1365
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
1366
#endif
unknown's avatar
unknown committed
1367
  }
1368 1369 1370

  /* thd->fatal_error should be set in case something went wrong */
end:
1371 1372 1373 1374 1375 1376
  bootstrap_error= thd->is_fatal_error;

  net_end(&thd->net);
  thd->cleanup();
  delete thd;

unknown's avatar
unknown committed
1377
#ifndef EMBEDDED_LIBRARY
1378 1379 1380
  (void) pthread_mutex_lock(&LOCK_thread_count);
  thread_count--;
  (void) pthread_mutex_unlock(&LOCK_thread_count);
1381
  (void) pthread_cond_broadcast(&COND_thread_count);
1382 1383
  my_thread_end();
  pthread_exit(0);
unknown's avatar
unknown committed
1384
#endif
1385
  DBUG_RETURN(0);
unknown's avatar
unknown committed
1386 1387 1388
}


unknown's avatar
unknown committed
1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403
/* 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() */
1404 1405 1406

void cleanup_items(Item *item)
{
unknown's avatar
unknown committed
1407
  DBUG_ENTER("cleanup_items");  
1408 1409
  for (; item ; item=item->next)
    item->cleanup();
unknown's avatar
unknown committed
1410
  DBUG_VOID_RETURN;
1411 1412
}

unknown's avatar
unknown committed
1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431
/*
  Handle COM_TABLE_DUMP command

  SYNOPSIS
    mysql_table_dump
      thd           thread handle
      db            database name or an empty string. If empty,
                    the current database of the connection is used
      tbl_name      name of the table to dump

  NOTES
    This function is written to handle one specific command only.

  RETURN VALUE
    0               success
    1               error, the error message is set in THD
*/

static
1432
int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name)
unknown's avatar
unknown committed
1433 1434 1435 1436 1437
{
  TABLE* table;
  TABLE_LIST* table_list;
  int error = 0;
  DBUG_ENTER("mysql_table_dump");
1438 1439 1440 1441 1442
  if (db->length == 0)
  {
    db->str= thd->db;            /* purecov: inspected */
    db->length= thd->db_length;  /* purecov: inspected */
  }
1443
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
1444
    DBUG_RETURN(1); // out of memory
1445
  table_list->db= db->str;
1446
  table_list->table_name= table_list->alias= tbl_name;
unknown's avatar
VIEW  
unknown committed
1447 1448
  table_list->lock_type= TL_READ_NO_INSERT;
  table_list->prev_global= &table_list;	// can be removed after merge with 4.1
unknown's avatar
unknown committed
1449

1450
  if (check_db_name(db))
1451
  {
1452 1453
    /* purecov: begin inspected */
    my_error(ER_WRONG_DB_NAME ,MYF(0), db->str ? db->str : "NULL");
1454
    goto err;
1455
    /* purecov: end */
1456
  }
1457
  if (lower_case_table_names)
1458
    my_casedn_str(files_charset_info, tbl_name);
1459 1460 1461 1462

  if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
    DBUG_RETURN(1);

unknown's avatar
unknown committed
1463
  if (check_one_table_access(thd, SELECT_ACL, table_list))
unknown's avatar
unknown committed
1464 1465
    goto err;
  thd->free_list = 0;
unknown's avatar
unknown committed
1466
  thd->query_length=(uint) strlen(tbl_name);
unknown's avatar
unknown committed
1467
  thd->query = tbl_name;
unknown's avatar
unknown committed
1468
  if ((error = mysqld_dump_create_info(thd, table_list, -1)))
1469
  {
1470
    my_error(ER_GET_ERRNO, MYF(0), my_errno);
1471 1472
    goto err;
  }
unknown's avatar
unknown committed
1473
  net_flush(&thd->net);
unknown's avatar
unknown committed
1474
  if ((error= table->file->dump(thd,-1)))
1475
    my_error(ER_GET_ERRNO, MYF(0), error);
unknown's avatar
unknown committed
1476

unknown's avatar
unknown committed
1477
err:
unknown's avatar
unknown committed
1478
  DBUG_RETURN(error);
unknown's avatar
unknown committed
1479 1480
}

unknown's avatar
unknown committed
1481 1482 1483 1484
/*
  Ends the current transaction and (maybe) begin the next

  SYNOPSIS
1485
    end_trans()
unknown's avatar
unknown committed
1486 1487 1488 1489 1490 1491 1492
      thd            Current thread
      completion     Completion type

  RETURN
    0 - OK
*/

1493
int end_trans(THD *thd, enum enum_mysql_completiontype completion)
unknown's avatar
unknown committed
1494 1495 1496
{
  bool do_release= 0;
  int res= 0;
1497
  DBUG_ENTER("end_trans");
unknown's avatar
unknown committed
1498

1499
  if (unlikely(thd->in_sub_stmt))
1500 1501 1502 1503
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    DBUG_RETURN(1);
  }
1504 1505 1506 1507 1508 1509
  if (thd->transaction.xid_state.xa_state != XA_NOTR)
  {
    my_error(ER_XAER_RMFAIL, MYF(0),
             xa_state_names[thd->transaction.xid_state.xa_state]);
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
1510 1511 1512 1513 1514 1515 1516 1517
  switch (completion) {
  case COMMIT:
    /*
     We don't use end_active_trans() here to ensure that this works
     even if there is a problem with the OPTION_AUTO_COMMIT flag
     (Which of course should never happen...)
    */
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
1518
    res= ha_commit(thd);
1519 1520
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
                             OPTION_KEEP_LOG);
unknown's avatar
unknown committed
1521 1522
    break;
  case COMMIT_RELEASE:
unknown's avatar
unknown committed
1523
    do_release= 1; /* fall through */
unknown's avatar
unknown committed
1524 1525 1526 1527 1528 1529
  case COMMIT_AND_CHAIN:
    res= end_active_trans(thd);
    if (!res && completion == COMMIT_AND_CHAIN)
      res= begin_trans(thd);
    break;
  case ROLLBACK_RELEASE:
unknown's avatar
unknown committed
1530
    do_release= 1; /* fall through */
unknown's avatar
unknown committed
1531 1532 1533 1534
  case ROLLBACK:
  case ROLLBACK_AND_CHAIN:
  {
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
unknown's avatar
unknown committed
1535
    if (ha_rollback(thd))
unknown's avatar
unknown committed
1536
      res= -1;
1537 1538
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
                             OPTION_KEEP_LOG);
unknown's avatar
unknown committed
1539 1540 1541 1542 1543 1544 1545 1546 1547
    if (!res && (completion == ROLLBACK_AND_CHAIN))
      res= begin_trans(thd);
    break;
  }
  default:
    res= -1;
    my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
    DBUG_RETURN(-1);
  }
unknown's avatar
unknown committed
1548

unknown's avatar
unknown committed
1549 1550 1551
  if (res < 0)
    my_error(thd->killed_errno(), MYF(0));
  else if ((res == 0) && do_release)
unknown's avatar
unknown committed
1552 1553
    thd->killed= THD::KILL_CONNECTION;

unknown's avatar
unknown committed
1554 1555
  DBUG_RETURN(res);
}
unknown's avatar
unknown committed
1556

1557
#ifndef EMBEDDED_LIBRARY
1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568

/*
  Read one command from socket and execute it (query or simple command).
  This function is called in loop from thread function.
  SYNOPSIS
    do_command()
  RETURN VALUE
    0  success
    1  request of thread shutdown (see dispatch_command() description)
*/

unknown's avatar
unknown committed
1569 1570 1571
bool do_command(THD *thd)
{
  char *packet;
unknown's avatar
unknown committed
1572 1573
  uint old_timeout;
  ulong packet_length;
unknown's avatar
unknown committed
1574 1575 1576 1577 1578
  NET *net;
  enum enum_server_command command;
  DBUG_ENTER("do_command");

  net= &thd->net;
unknown's avatar
unknown committed
1579 1580 1581 1582
  /*
    indicator of uninitialized lex => normal flow of errors handling
    (see my_message_sql)
  */
1583
  thd->lex->current_select= 0;
unknown's avatar
unknown committed
1584 1585

  packet=0;
unknown's avatar
unknown committed
1586
  old_timeout=net->read_timeout;
unknown's avatar
unknown committed
1587
  /* Wait max for 8 hours */
unknown's avatar
unknown committed
1588
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
unknown's avatar
unknown committed
1589
  thd->clear_error();				// Clear error message
unknown's avatar
unknown committed
1590 1591 1592 1593

  net_new_transaction(net);
  if ((packet_length=my_net_read(net)) == packet_error)
  {
1594 1595 1596 1597 1598
    DBUG_PRINT("info",("Got error %d reading command from socket %s",
		       net->error,
		       vio_description(net->vio)));
    /* Check if we can continue without closing the connection */
    if (net->error != 3)
1599 1600
    {
      statistic_increment(aborted_threads,&LOCK_status);
1601
      DBUG_RETURN(TRUE);			// We have to close it.
1602
    }
1603
    net_send_error(thd, net->last_errno, NullS);
1604
    net->error= 0;
1605
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
1606 1607 1608 1609 1610
  }
  else
  {
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
1611 1612
    if (command >= COM_END)
      command= COM_END;				// Wrong command
unknown's avatar
unknown committed
1613 1614
    DBUG_PRINT("info",("Command on %s = %d (%s)",
		       vio_description(net->vio), command,
unknown's avatar
unknown committed
1615
		       command_name[command].str));
unknown's avatar
unknown committed
1616
  }
unknown's avatar
unknown committed
1617
  net->read_timeout=old_timeout;		// restore it
1618 1619 1620 1621 1622 1623 1624 1625 1626
  /*
    packet_length contains length of data, as it was stored in packet
    header. In case of malformed header, packet_length can be zero.
    If packet_length is not zero, my_net_read ensures that this number
    of bytes was actually read from network. Additionally my_net_read
    sets packet[packet_length]= 0 (thus if packet_length == 0,
    command == packet[0] == COM_SLEEP).
    In dispatch_command packet[packet_length] points beyond the end of packet.
  */
unknown's avatar
unknown committed
1627
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
1628
}
1629
#endif  /* EMBEDDED_LIBRARY */
1630

1631

1632 1633
/*
   Perform one connection-level (COM_XXXX) command.
1634

1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647
  SYNOPSIS
    dispatch_command()
    thd             connection handle
    command         type of command to perform 
    packet          data for the command, packet is always null-terminated
    packet_length   length of packet + 1 (to show that data is
                    null-terminated) except for COM_SLEEP, where it
                    can be zero.
  RETURN VALUE
    0   ok
    1   request of thread shutdown, i. e. if command is
        COM_QUIT/COM_SHUTDOWN
*/
1648

1649 1650 1651 1652
bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
1653
  bool error= 0;
1654 1655
  DBUG_ENTER("dispatch_command");

1656 1657 1658
  if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
    thd->killed= THD::NOT_KILLED;

1659
  thd->command=command;
unknown's avatar
unknown committed
1660
  /*
1661 1662
    Commands which always take a long time are logged into
    the slow log only if opt_log_slow_admin_statements is set.
unknown's avatar
unknown committed
1663
  */
1664
  thd->enable_slow_log= TRUE;
1665
  thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
unknown's avatar
unknown committed
1666
  thd->set_time();
unknown's avatar
unknown committed
1667 1668 1669
  VOID(pthread_mutex_lock(&LOCK_thread_count));
  thd->query_id=query_id;
  if (command != COM_STATISTICS && command != COM_PING)
1670
    next_query_id();
unknown's avatar
unknown committed
1671
  thread_running++;
1672
  /* TODO: set thd->lex->sql_command to SQLCOM_END here */
unknown's avatar
unknown committed
1673
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1674

1675 1676
  thd->server_status&=
           ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
1677
  switch (command) {
unknown's avatar
unknown committed
1678
  case COM_INIT_DB:
unknown's avatar
unknown committed
1679 1680
  {
    LEX_STRING tmp;
1681 1682
    statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB],
			&LOCK_status);
unknown's avatar
unknown committed
1683
    thd->convert_string(&tmp, system_charset_info,
1684
			packet, packet_length-1, thd->charset());
1685 1686
    if (!mysql_change_db(thd, tmp.str, FALSE))
    {
unknown's avatar
unknown committed
1687
      general_log_print(thd, command, "%s",thd->db);
1688 1689
      send_ok(thd);
    }
unknown's avatar
unknown committed
1690 1691
    break;
  }
unknown's avatar
unknown committed
1692
#ifdef HAVE_REPLICATION
1693 1694
  case COM_REGISTER_SLAVE:
  {
1695
    if (!register_slave(thd, (uchar*)packet, packet_length))
1696
      send_ok(thd);
1697 1698
    break;
  }
1699
#endif
unknown's avatar
unknown committed
1700
  case COM_TABLE_DUMP:
1701
  {
1702 1703
    char *tbl_name;
    LEX_STRING db;
1704
    uint db_len= *(uchar*) packet;
unknown's avatar
unknown committed
1705
    if (db_len >= packet_length || db_len > NAME_LEN)
unknown's avatar
unknown committed
1706
    {
unknown's avatar
unknown committed
1707
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
1708 1709
      break;
    }
1710
    uint tbl_len= *(uchar*) (packet + db_len + 1);
unknown's avatar
unknown committed
1711 1712
    if (db_len+tbl_len+2 > packet_length || tbl_len > NAME_LEN)
    {
unknown's avatar
unknown committed
1713
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
1714 1715
      break;
    }
1716

1717
    statistic_increment(thd->status_var.com_other, &LOCK_status);
1718
    thd->enable_slow_log= opt_log_slow_admin_statements;
1719 1720 1721
    db.str= thd->alloc(db_len + tbl_len + 2);
    db.length= db_len;
    if (!db.str)
1722 1723 1724 1725
    {
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
      break;
    }
1726
    tbl_name= strmake(db.str, packet + 1, db_len)+1;
1727
    strmake(tbl_name, packet + db_len + 2, tbl_len);
1728
    mysql_table_dump(thd, &db, tbl_name);
1729 1730
    break;
  }
unknown's avatar
unknown committed
1731 1732
  case COM_CHANGE_USER:
  {
1733 1734 1735 1736
    statistic_increment(thd->status_var.com_other, &LOCK_status);
    char *user= (char*) packet, *packet_end= packet+ packet_length;
    char *passwd= strend(user)+1;

unknown's avatar
unknown committed
1737
    thd->change_user();
1738
    thd->clear_error();                         // if errors from rollback
unknown's avatar
unknown committed
1739

1740
    /*
unknown's avatar
unknown committed
1741 1742 1743 1744
      Old clients send null-terminated string ('\0' for empty string) for
      password.  New clients send the size (1 byte) + string (not null
      terminated, so also '\0' for empty string).
    */
1745
    char db_buff[NAME_LEN+1];                 // buffer to store db in utf8
unknown's avatar
unknown committed
1746
    char *db= passwd;
1747 1748 1749 1750 1751 1752 1753
    char *save_db;
    uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
                      *passwd++ : strlen(passwd));
    uint dummy_errors, save_db_length, db_length, res;
    Security_context save_security_ctx= *thd->security_ctx;
    USER_CONN *save_user_connect;

unknown's avatar
unknown committed
1754
    db+= passwd_len + 1;
1755
#ifndef EMBEDDED_LIBRARY
1756
    /* Small check for incoming packet */
unknown's avatar
unknown committed
1757
    if ((uint) ((uchar*) db - net->read_pos) > packet_length)
1758
    {
unknown's avatar
unknown committed
1759
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1760 1761
      break;
    }
1762
#endif
1763
    /* Convert database name to utf8 */
1764 1765 1766 1767 1768 1769 1770
    /*
      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--;
1771
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
1772
                             system_charset_info, db, db_length,
1773
                             thd->charset(), &dummy_errors)]= 0;
1774
    db= db_buff;
unknown's avatar
unknown committed
1775

1776
    /* Save user and privileges */
1777 1778 1779
    save_db_length= thd->db_length;
    save_db= thd->db;
    save_user_connect= thd->user_connect;
1780 1781

    if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
1782
    {
1783
      thd->security_ctx->user= save_security_ctx.user;
unknown's avatar
unknown committed
1784
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
1785 1786
      break;
    }
unknown's avatar
unknown committed
1787

unknown's avatar
unknown committed
1788 1789
    /* Clear variables that are allocated */
    thd->user_connect= 0;
1790
    res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
unknown's avatar
unknown committed
1791

1792 1793
    if (res)
    {
1794
      /* authentication failure, we shall restore old user */
1795
      if (res > 0)
unknown's avatar
unknown committed
1796
        my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1797 1798
      x_free(thd->security_ctx->user);
      *thd->security_ctx= save_security_ctx;
unknown's avatar
unknown committed
1799
      thd->user_connect= save_user_connect;
1800 1801 1802 1803 1804
      thd->db= save_db;
      thd->db_length= save_db_length;
    }
    else
    {
1805
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1806
      /* we've authenticated new user */
unknown's avatar
unknown committed
1807 1808
      if (save_user_connect)
	decrease_user_connections(save_user_connect);
1809
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
1810
      x_free((gptr) save_db);
1811
      x_free((gptr)  save_security_ctx.user);
1812
    }
unknown's avatar
unknown committed
1813 1814
    break;
  }
1815
  case COM_STMT_EXECUTE:
unknown's avatar
unknown committed
1816
  {
1817
    mysql_stmt_execute(thd, packet, packet_length);
unknown's avatar
unknown committed
1818 1819
    break;
  }
1820
  case COM_STMT_FETCH:
1821 1822 1823 1824
  {
    mysql_stmt_fetch(thd, packet, packet_length);
    break;
  }
1825
  case COM_STMT_SEND_LONG_DATA:
unknown's avatar
unknown committed
1826
  {
1827
    mysql_stmt_get_longdata(thd, packet, packet_length);
unknown's avatar
unknown committed
1828 1829
    break;
  }
1830
  case COM_STMT_PREPARE:
unknown's avatar
unknown committed
1831
  {
1832
    mysql_stmt_prepare(thd, packet, packet_length);
unknown's avatar
unknown committed
1833 1834
    break;
  }
1835
  case COM_STMT_CLOSE:
unknown's avatar
unknown committed
1836
  {
1837
    mysql_stmt_close(thd, packet);
unknown's avatar
unknown committed
1838 1839
    break;
  }
1840
  case COM_STMT_RESET:
1841 1842 1843 1844
  {
    mysql_stmt_reset(thd, packet);
    break;
  }
unknown's avatar
unknown committed
1845 1846
  case COM_QUERY:
  {
1847 1848
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
1849
    char *packet_end= thd->query + thd->query_length;
unknown's avatar
unknown committed
1850 1851
    /* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */
    const char *format= "%.*b";
unknown's avatar
unknown committed
1852
    general_log_print(thd, command, format, thd->query_length, thd->query);
1853
    DBUG_PRINT("query",("%-.4096s",thd->query));
1854 1855 1856 1857

    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),QUERY_PRIOR);

1858
    mysql_parse(thd,thd->query, thd->query_length);
1859

1860
    while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error)
1861
    {
1862
      char *packet= thd->lex->found_semicolon;
1863
      net->no_send_error= 0;
1864
      /*
1865 1866
        Multiple queries exits, execute them individually
      */
1867 1868
      if (thd->lock || thd->open_tables || thd->derived_tables ||
          thd->prelocked_mode)
1869
        close_thread_tables(thd);
1870
      ulong length= (ulong)(packet_end-packet);
1871

1872
      log_slow_statement(thd);
1873

1874
      /* Remove garbage at start of query */
unknown's avatar
unknown committed
1875
      while (my_isspace(thd->charset(), *packet) && length > 0)
1876 1877 1878 1879
      {
        packet++;
        length--;
      }
unknown's avatar
unknown committed
1880
      VOID(pthread_mutex_lock(&LOCK_thread_count));
1881
      thd->query_length= length;
1882
      thd->query= packet;
1883
      thd->query_id= next_query_id();
1884
      thd->set_time(); /* Reset the query start time. */
1885
      /* TODO: set thd->lex->sql_command to SQLCOM_END here */
1886
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
1887 1888 1889
      mysql_parse(thd, packet, length);
    }

unknown's avatar
unknown committed
1890 1891 1892 1893 1894
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1895
  case COM_FIELD_LIST:				// This isn't actually needed
unknown's avatar
unknown committed
1896
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1897 1898
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
unknown's avatar
unknown committed
1899 1900 1901
    break;
#else
  {
1902
    char *fields, *packet_end= packet + packet_length - 1, *arg_end;
1903 1904
    /* Locked closure of all tables */
    TABLE_LIST *locked_tables= NULL;
unknown's avatar
unknown committed
1905
    TABLE_LIST table_list;
unknown's avatar
unknown committed
1906
    LEX_STRING conv_name;
1907
    /* Saved variable value */
unknown's avatar
unknown committed
1908
    my_bool old_innodb_table_locks=  thd->variables.innodb_table_locks;
1909
    uint dummy;
unknown's avatar
unknown committed
1910

unknown's avatar
unknown committed
1911 1912
    /* used as fields initializator */
    lex_start(thd, 0, 0);
1913

1914 1915
    statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
			&LOCK_status);
unknown's avatar
unknown committed
1916
    bzero((char*) &table_list,sizeof(table_list));
1917
    if (thd->copy_db_to(&table_list.db, &dummy))
unknown's avatar
unknown committed
1918
      break;
1919 1920 1921 1922
    /*
      We have name + wildcard in packet, separated by endzero
    */
    arg_end= strend(packet);
unknown's avatar
unknown committed
1923
    thd->convert_string(&conv_name, system_charset_info,
1924
			packet, (uint) (arg_end - packet), thd->charset());
1925
    table_list.alias= table_list.table_name= conv_name.str;
1926
    packet= arg_end + 1;
1927 1928 1929 1930 1931 1932 1933 1934 1935

    if (!my_strcasecmp(system_charset_info, table_list.db,
                       information_schema_name.str))
    {
      ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
      if (schema_table)
        table_list.schema_table= schema_table;
    }

1936
    thd->query_length= (uint) (packet_end - packet); // Don't count end \0
unknown's avatar
unknown committed
1937 1938
    if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
      break;
unknown's avatar
unknown committed
1939
    general_log_print(thd, command, "%s %s", table_list.table_name, fields);
1940
    if (lower_case_table_names)
1941
      my_casedn_str(files_charset_info, table_list.table_name);
unknown's avatar
unknown committed
1942

unknown's avatar
unknown committed
1943
    if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
1944
		     0, 0, test(table_list.schema_table)))
unknown's avatar
unknown committed
1945
      break;
unknown's avatar
unknown committed
1946 1947
    if (grant_option &&
	check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
1948
      break;
1949 1950 1951 1952 1953 1954
    /* init structures for VIEW processing */
    table_list.select_lex= &(thd->lex->select_lex);
    mysql_init_query(thd, (uchar*)"", 0);
    thd->lex->
      select_lex.table_list.link_in_list((byte*) &table_list,
                                         (byte**) &table_list.next_local);
unknown's avatar
unknown committed
1955
    thd->lex->add_to_query_tables(&table_list);
1956

1957 1958
    /* switch on VIEW optimisation: do not fill temporary tables */
    thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
unknown's avatar
unknown committed
1959
    mysqld_list_fields(thd,&table_list,fields);
1960
    thd->lex->unit.cleanup();
1961
    thd->cleanup_after_query();
unknown's avatar
unknown committed
1962 1963 1964 1965
    break;
  }
#endif
  case COM_QUIT:
1966
    /* We don't calculate statistics for this command */
unknown's avatar
unknown committed
1967
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1968 1969 1970 1971
    net->error=0;				// Don't give 'abort' message
    error=TRUE;					// End server
    break;

1972
#ifdef REMOVED
unknown's avatar
unknown committed
1973
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1974
    {
1975
      LEX_STRING db, alias;
1976
      HA_CREATE_INFO create_info;
unknown's avatar
unknown committed
1977

1978 1979
      statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB],
			  &LOCK_status);
1980 1981 1982
      if (thd->LEX_STRING_make(&db, packet, packet_length -1) ||
          thd->LEX_STRING_make(&alias, db.str, db.length) ||
          check_db_name(&db))
1983
      {
1984
	my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
1985 1986
	break;
      }
1987 1988
      if (check_access(thd, CREATE_ACL, db.str , 0, 1, 0,
                       is_schema_db(db.str)))
unknown's avatar
unknown committed
1989
	break;
unknown's avatar
unknown committed
1990
      general_log_print(thd, command, packet);
1991
      bzero(&create_info, sizeof(create_info));
1992
      mysql_create_db(thd, (lower_case_table_names == 2 ? alias.str : db.str),
1993
                      &create_info, 0);
unknown's avatar
unknown committed
1994 1995
      break;
    }
unknown's avatar
unknown committed
1996
  case COM_DROP_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1997
    {
1998 1999
      statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB],
			  &LOCK_status);
2000 2001 2002 2003
      LEX_STRING db;

      if (thd->LEX_STRING_make(&db, packet, packet_length - 1) ||
          check_db_name(&db))
2004
      {
2005
	my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
2006 2007
	break;
      }
2008
      if (check_access(thd, DROP_ACL, db.str, 0, 1, 0, is_schema_db(db.str)))
2009
	break;
unknown's avatar
unknown committed
2010 2011
      if (thd->locked_tables || thd->active_transaction())
      {
unknown's avatar
unknown committed
2012 2013
	my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                   ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
unknown's avatar
unknown committed
2014
	break;
unknown's avatar
unknown committed
2015
      }
2016 2017
      general_log_print(thd, command, db.str);
      mysql_rm_db(thd, db.str, 0, 0);
unknown's avatar
unknown committed
2018 2019
      break;
    }
2020
#endif
2021
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2022 2023
  case COM_BINLOG_DUMP:
    {
unknown's avatar
unknown committed
2024 2025 2026 2027
      ulong pos;
      ushort flags;
      uint32 slave_server_id;

2028
      statistic_increment(thd->status_var.com_other,&LOCK_status);
2029
      thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
unknown committed
2030
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2031
	break;
unknown's avatar
unknown committed
2032

2033
      /* TODO: The following has to be changed to an 8 byte integer */
2034 2035
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
2036
      thd->server_id=0; /* avoid suicide */
unknown's avatar
unknown committed
2037
      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
unknown's avatar
unknown committed
2038
	kill_zombie_dump_threads(slave_server_id);
2039
      thd->server_id = slave_server_id;
unknown's avatar
unknown committed
2040

unknown's avatar
unknown committed
2041
      general_log_print(thd, command, "Log: '%s'  Pos: %ld", packet+10,
unknown's avatar
unknown committed
2042
                      (long) pos);
2043
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
2044
      unregister_slave(thd,1,1);
unknown's avatar
unknown committed
2045
      /*  fake COM_QUIT -- if we get here, the thread needs to terminate */
2046 2047
      error = TRUE;
      net->error = 0;
unknown's avatar
unknown committed
2048 2049
      break;
    }
2050
#endif
unknown's avatar
unknown committed
2051
  case COM_REFRESH:
unknown's avatar
unknown committed
2052 2053 2054 2055 2056 2057
  {
    bool not_used;
    statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH],
                        &LOCK_status);
    ulong options= (ulong) (uchar) packet[0];
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
2058
      break;
unknown's avatar
unknown committed
2059
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
2060 2061 2062 2063
    if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
      send_ok(thd);
    break;
  }
2064
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2065
  case COM_SHUTDOWN:
2066
  {
2067
    statistic_increment(thd->status_var.com_other, &LOCK_status);
unknown's avatar
unknown committed
2068
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
2069
      break; /* purecov: inspected */
2070
    /*
2071 2072 2073 2074
      If the client is < 4.1.3, it is going to send us no argument; then
      packet_length is 1, packet[0] is the end 0 of the packet. Note that
      SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in
      packet[0].
2075
    */
2076 2077
    enum mysql_enum_shutdown_level level=
      (enum mysql_enum_shutdown_level) (uchar) packet[0];
2078
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
2079 2080 2081 2082 2083 2084 2085
    if (level == SHUTDOWN_DEFAULT)
      level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable
    else if (level != SHUTDOWN_WAIT_ALL_BUFFERS)
    {
      my_error(ER_NOT_SUPPORTED_YET, MYF(0), "this shutdown level");
      break;
    }
2086
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
unknown's avatar
unknown committed
2087
    general_log_print(thd, command, NullS);
2088
    send_eof(thd);
unknown's avatar
unknown committed
2089 2090 2091
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
2092 2093 2094 2095 2096 2097
    /*
      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);
2098
    close_connection(thd, 0, 1);
unknown's avatar
unknown committed
2099 2100 2101 2102
    close_thread_tables(thd);			// Free before kill
    kill_mysql();
    error=TRUE;
    break;
2103
  }
2104
#endif
unknown's avatar
unknown committed
2105 2106
  case COM_STATISTICS:
  {
2107 2108 2109
    STATUS_VAR current_global_status_var;
    ulong uptime;
    uint length;
unknown's avatar
unknown committed
2110
#ifndef EMBEDDED_LIBRARY
2111 2112
    char buff[250];
    uint buff_len= sizeof(buff);
unknown's avatar
unknown committed
2113 2114
#else
    char *buff= thd->net.last_error;
2115
    uint buff_len= sizeof(thd->net.last_error);
unknown's avatar
unknown committed
2116
#endif
2117

2118 2119 2120
    general_log_print(thd, command, NullS);
    statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS],
			&LOCK_status);
2121
    calc_sum_of_all_status(&current_global_status_var);
2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134
    uptime= (ulong) (thd->start_time - start_time);
    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: %.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_open_tables(),
                        (uptime ? (ulonglong2double(thd->query_id) /
                                   (double) uptime) : (double) 0));
unknown's avatar
unknown committed
2135
#ifdef SAFEMALLOC
2136
    if (sf_malloc_cur_memory)				// Using SAFEMALLOC
2137 2138 2139 2140 2141 2142 2143
    {
      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);
    }
unknown's avatar
unknown committed
2144 2145
#endif
#ifndef EMBEDDED_LIBRARY
2146 2147
    VOID(my_net_write(net, buff, length));
      VOID(net_flush(net));
unknown's avatar
unknown committed
2148
#endif
unknown's avatar
unknown committed
2149 2150 2151
    break;
  }
  case COM_PING:
2152
    statistic_increment(thd->status_var.com_other, &LOCK_status);
2153
    send_ok(thd);				// Tell client we are alive
unknown's avatar
unknown committed
2154 2155
    break;
  case COM_PROCESS_INFO:
2156 2157
    statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
			&LOCK_status);
2158 2159
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd, PROCESS_ACL))
unknown's avatar
unknown committed
2160
      break;
unknown's avatar
unknown committed
2161
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
2162
    mysqld_list_processes(thd,
2163 2164
			  thd->security_ctx->master_access & PROCESS_ACL ? 
			  NullS : thd->security_ctx->priv_user, 0);
unknown's avatar
unknown committed
2165 2166 2167
    break;
  case COM_PROCESS_KILL:
  {
2168
    statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
2169
    ulong id=(ulong) uint4korr(packet);
2170
    sql_kill(thd,id,false);
unknown's avatar
unknown committed
2171 2172
    break;
  }
2173 2174
  case COM_SET_OPTION:
  {
2175 2176
    statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION],
			&LOCK_status);
2177 2178 2179 2180
    enum_mysql_set_option command= (enum_mysql_set_option) uint2korr(packet);
    switch (command) {
    case MYSQL_OPTION_MULTI_STATEMENTS_ON:
      thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
unknown's avatar
unknown committed
2181
      send_eof(thd);
2182 2183 2184
      break;
    case MYSQL_OPTION_MULTI_STATEMENTS_OFF:
      thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
unknown's avatar
unknown committed
2185
      send_eof(thd);
2186 2187
      break;
    default:
unknown's avatar
unknown committed
2188
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
2189 2190 2191 2192
      break;
    }
    break;
  }
unknown's avatar
unknown committed
2193
  case COM_DEBUG:
2194
    statistic_increment(thd->status_var.com_other, &LOCK_status);
unknown's avatar
unknown committed
2195
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2196
      break;					/* purecov: inspected */
2197
    mysql_print_status();
unknown's avatar
unknown committed
2198
    general_log_print(thd, command, NullS);
2199
    send_eof(thd);
unknown's avatar
unknown committed
2200 2201 2202 2203 2204
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
2205
  case COM_END:
unknown's avatar
unknown committed
2206
  default:
unknown's avatar
unknown committed
2207
    my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
2208 2209
    break;
  }
2210 2211
  if (thd->lock || thd->open_tables || thd->derived_tables ||
      thd->prelocked_mode)
unknown's avatar
unknown committed
2212 2213 2214 2215
  {
    thd->proc_info="closing tables";
    close_thread_tables(thd);			/* Free tables */
  }
2216 2217 2218 2219 2220 2221 2222 2223 2224 2225
  /*
    assume handlers auto-commit (if some doesn't - transaction handling
    in MySQL should be redesigned to support it; it's a big change,
    and it's not worth it - better to commit explicitly only writing
    transactions, read-only ones should better take care of themselves.
    saves some work in 2pc too)
    see also sql_base.cc - close_thread_tables()
  */
  bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
  if (!thd->active_transaction())
2226
    thd->transaction.xid_state.xid.null();
unknown's avatar
unknown committed
2227

unknown's avatar
unknown committed
2228 2229 2230
  /* report error issued during command execution */
  if (thd->killed_errno() && !thd->net.report_error)
    thd->send_kill_message();
unknown's avatar
unknown committed
2231
  if (thd->net.report_error)
2232
    net_send_error(thd);
unknown's avatar
unknown committed
2233

2234
  log_slow_statement(thd);
2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249

  thd->proc_info="cleaning up";
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
  thd->proc_info=0;
  thd->command=COM_SLEEP;
  thd->query=0;
  thd->query_length=0;
  thread_running--;
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
  thd->packet.shrink(thd->variables.net_buffer_length);	// Reclaim some memory
  free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
  DBUG_RETURN(error);
}


2250
void log_slow_statement(THD *thd)
2251
{
2252
  time_t start_of_query;
unknown's avatar
unknown committed
2253
  DBUG_ENTER("log_slow_statement");
2254 2255 2256 2257 2258 2259 2260

  /*
    The following should never be true with our current code base,
    but better to keep this here so we don't accidently try to log a
    statement in a trigger or stored function
  */
  if (unlikely(thd->in_sub_stmt))
unknown's avatar
unknown committed
2261
    DBUG_VOID_RETURN;                           // Don't set time for sub stmt
2262 2263

  start_of_query= thd->start_time;
2264
  thd->end_time();				// Set start time
2265

2266 2267 2268 2269 2270
  /*
    Do not log administrative statements unless the appropriate option is
    set; do not log into slow log if reading from backup.
  */
  if (thd->enable_slow_log && !thd->user_time)
unknown's avatar
unknown committed
2271
  {
2272 2273
    thd->proc_info="logging slow query";

2274 2275
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
2276 2277
	((thd->server_status &
	  (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
2278
	 (specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES)))
2279
    {
2280
      thd->status_var.long_query_count++;
unknown's avatar
unknown committed
2281
      slow_log_print(thd, thd->query, thd->query_length, start_of_query);
2282
    }
unknown's avatar
unknown committed
2283
  }
unknown's avatar
unknown committed
2284
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2285 2286
}

2287

unknown's avatar
unknown committed
2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315
/*
  Create a TABLE_LIST object for an INFORMATION_SCHEMA table.

  SYNOPSIS
    prepare_schema_table()
      thd              thread handle
      lex              current lex
      table_ident      table alias if it's used
      schema_table_idx the type of the INFORMATION_SCHEMA table to be
                       created

  DESCRIPTION
    This function is used in the parser to convert a SHOW or DESCRIBE
    table_name command to a SELECT from INFORMATION_SCHEMA.
    It prepares a SELECT_LEX and a TABLE_LIST object to represent the
    given command as a SELECT parse tree.

  NOTES
    Due to the way this function works with memory and LEX it cannot
    be used outside the parser (parse tree transformations outside
    the parser break PS and SP).

  RETURN VALUE
    0                 success
    1                 out of memory or SHOW commands are not allowed
                      in this version of the server.
*/

2316 2317 2318 2319 2320
int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
                         enum enum_schema_tables schema_table_idx)
{
  DBUG_ENTER("prepare_schema_table");
  SELECT_LEX *sel= 0;
2321
  switch (schema_table_idx) {
2322 2323
  case SCH_SCHEMATA:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
unknown's avatar
unknown committed
2324 2325
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0));   /* purecov: inspected */
2326 2327 2328 2329 2330 2331 2332 2333 2334 2335
    DBUG_RETURN(1);
#else
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
	check_global_access(thd, SHOW_DB_ACL))
      DBUG_RETURN(1);
    break;
#endif
  case SCH_TABLE_NAMES:
  case SCH_TABLES:
  case SCH_VIEWS:
2336
  case SCH_TRIGGERS:
unknown's avatar
unknown committed
2337
  case SCH_EVENTS:
2338
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2339 2340
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
2341 2342 2343
    DBUG_RETURN(1);
#else
    {
2344 2345
      LEX_STRING db;
      uint dummy;
unknown's avatar
unknown committed
2346
      if (lex->select_lex.db == NULL &&
2347
          thd->copy_db_to(&lex->select_lex.db, &dummy))
2348
      {
unknown's avatar
unknown committed
2349
        DBUG_RETURN(1);
2350
      }
2351 2352 2353
      db.str= lex->select_lex.db;
      db.length= strlen(db.str);
      if (check_db_name(&db))
2354
      {
2355
        my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
2356 2357
        DBUG_RETURN(1);
      }
2358 2359
      if (check_access(thd, SELECT_ACL, db.str, &thd->col_access, 0, 0,
                       is_schema_db(db.str)))
2360
        DBUG_RETURN(1);			        /* purecov: inspected */
2361
      if (!thd->col_access && check_grant_db(thd, db.str))
2362
      {
unknown's avatar
unknown committed
2363
	my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
2364
                 thd->security_ctx->priv_user, thd->security_ctx->priv_host,
2365
                 db.str);
2366 2367 2368 2369 2370 2371 2372 2373
	DBUG_RETURN(1);
      }
      break;
    }
#endif
  case SCH_COLUMNS:
  case SCH_STATISTICS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2374 2375
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
2376 2377 2378 2379 2380 2381
    DBUG_RETURN(1);
#else
    if (table_ident)
    {
      TABLE_LIST **query_tables_last= lex->query_tables_last;
      sel= new SELECT_LEX();
unknown's avatar
unknown committed
2382 2383
      /* 'parent_lex' is used in init_query() so it must be before it. */
      sel->parent_lex= lex;
2384
      sel->init_query();
unknown's avatar
unknown committed
2385
      if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, 
2386 2387 2388 2389 2390 2391
                                 (List<String> *) 0, (List<String> *) 0))
        DBUG_RETURN(1);
      lex->query_tables_last= query_tables_last;
      TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
      char *db= table_list->db;
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
2392 2393
                       &table_list->grant.privilege, 0, 0,
                       test(table_list->schema_table)))
2394 2395 2396 2397 2398 2399 2400
        DBUG_RETURN(1);				/* purecov: inspected */
      if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2,
                                      UINT_MAX, 0))
        DBUG_RETURN(1);
      break;
    }
#endif
2401 2402 2403
  case SCH_OPEN_TABLES:
  case SCH_VARIABLES:
  case SCH_STATUS:
2404 2405
  case SCH_PROCEDURES:
  case SCH_CHARSETS:
unknown's avatar
unknown committed
2406
  case SCH_ENGINES:
2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425
  case SCH_COLLATIONS:
  case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
  case SCH_USER_PRIVILEGES:
  case SCH_SCHEMA_PRIVILEGES:
  case SCH_TABLE_PRIVILEGES:
  case SCH_COLUMN_PRIVILEGES:
  case SCH_TABLE_CONSTRAINTS:
  case SCH_KEY_COLUMN_USAGE:
  default:
    break;
  }
  
  SELECT_LEX *select_lex= lex->current_select;
  if (make_schema_select(thd, select_lex, schema_table_idx))
  {
    DBUG_RETURN(1);
  }
  TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
  table_list->schema_select_lex= sel;
2426
  table_list->schema_table_reformed= 1;
2427 2428 2429 2430
  DBUG_RETURN(0);
}


2431 2432
/*
  Read query from packet and store in thd->query
2433
  Used in COM_QUERY and COM_STMT_PREPARE
2434 2435 2436 2437 2438 2439 2440

  DESCRIPTION
    Sets the following THD variables:
      query
      query_length

  RETURN VALUES
unknown's avatar
unknown committed
2441 2442
    FALSE ok
    TRUE  error;  In this case thd->fatal_error is set
2443 2444
*/

2445
bool alloc_query(THD *thd, const char *packet, uint packet_length)
2446 2447
{
  packet_length--;				// Remove end null
2448
  /* Remove garbage at start and end of query */
unknown's avatar
unknown committed
2449
  while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
2450 2451 2452 2453
  {
    packet++;
    packet_length--;
  }
2454
  const char *pos= packet + packet_length;     // Point at end null
unknown's avatar
unknown committed
2455
  while (packet_length > 0 &&
unknown's avatar
unknown committed
2456
	 (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
2457 2458 2459 2460 2461
  {
    pos--;
    packet_length--;
  }
  /* We must allocate some extra memory for query cache */
unknown's avatar
unknown committed
2462
  thd->query_length= 0;                        // Extra safety: Avoid races
2463 2464
  if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
					      packet_length,
2465 2466
					      thd->db_length+ 1 +
					      QUERY_CACHE_FLAGS_SIZE)))
unknown's avatar
unknown committed
2467
    return TRUE;
2468 2469
  thd->query[packet_length]=0;
  thd->query_length= packet_length;
2470 2471 2472 2473

  /* Reclaim some memory */
  thd->packet.shrink(thd->variables.net_buffer_length);
  thd->convert_buffer.shrink(thd->variables.net_buffer_length);
2474

unknown's avatar
unknown committed
2475
  return FALSE;
2476 2477
}

2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493
static void reset_one_shot_variables(THD *thd) 
{
  thd->variables.character_set_client=
    global_system_variables.character_set_client;
  thd->variables.collation_connection=
    global_system_variables.collation_connection;
  thd->variables.collation_database=
    global_system_variables.collation_database;
  thd->variables.collation_server=
    global_system_variables.collation_server;
  thd->update_charset();
  thd->variables.time_zone=
    global_system_variables.time_zone;
  thd->one_shot_set= 0;
}

2494

2495
/*
2496
  Execute command saved in thd and lex->sql_command
2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517

  SYNOPSIS
    mysql_execute_command()
      thd                       Thread handle

  IMPLEMENTATION

    Before every operation that can request a write lock for a table
    wait if a global read lock exists. However do not wait if this
    thread has locked tables already. No new locks can be requested
    until the other locks are released. The thread that requests the
    global read lock waits for write locked tables to become unlocked.

    Note that wait_if_global_read_lock() sets a protection against a new
    global read lock when it succeeds. This needs to be released by
    start_waiting_global_read_lock() after the operation.

  RETURN
    FALSE       OK
    TRUE        Error
*/
unknown's avatar
unknown committed
2518

unknown's avatar
unknown committed
2519
bool
2520
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
2521
{
2522 2523 2524 2525
  bool res= FALSE;
  bool need_start_waiting= FALSE; // have protection against global read lock
  int  result= 0;
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
2526
  /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
unknown's avatar
unknown committed
2527
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
2528
  /* first table of first SELECT_LEX */
unknown's avatar
unknown committed
2529
  TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
unknown's avatar
VIEW  
unknown committed
2530 2531 2532
  /* list of all tables in query */
  TABLE_LIST *all_tables;
  /* most outer SELECT_LEX_UNIT of query */
2533
  SELECT_LEX_UNIT *unit= &lex->unit;
2534
  /* Saved variable value */
unknown's avatar
unknown committed
2535
  DBUG_ENTER("mysql_execute_command");
2536
  thd->net.no_send_error= 0;
unknown's avatar
unknown committed
2537 2538 2539
#ifdef WITH_PARTITION_STORAGE_ENGINE
  thd->work_part_info= 0;
#endif
unknown's avatar
unknown committed
2540

unknown's avatar
VIEW  
unknown committed
2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556
  /*
    In many cases first table of main SELECT_LEX have special meaning =>
    check that it is first table in global list and relink it first in 
    queries_tables list if it is necessary (we need such relinking only
    for queries with subqueries in select list, in this case tables of
    subqueries will go to global list first)

    all_tables will differ from first_table only if most upper SELECT_LEX
    do not contain tables.

    Because of above in place where should be at least one table in most
    outer SELECT_LEX we have following check:
    DBUG_ASSERT(first_table == all_tables);
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
  */
  lex->first_lists_tables_same();
2557
  /* should be assigned after making first tables same */
unknown's avatar
VIEW  
unknown committed
2558
  all_tables= lex->query_tables;
2559 2560 2561 2562
  /* set context for commands which do not use setup_tables */
  select_lex->
    context.resolve_in_table_list_only((TABLE_LIST*)select_lex->
                                       table_list.first);
unknown's avatar
VIEW  
unknown committed
2563

2564 2565 2566 2567 2568
  /*
    Reset warning count for each query that uses tables
    A better approach would be to reset this for any commands
    that is not a SHOW command or a select that only access local
    variables, but for now this is probably good enough.
2569
    Don't reset warnings when executing a stored routine.
2570
  */
2571
  if ((all_tables || &lex->select_lex != lex->all_selects_list ||
2572
       lex->sroutines.records) && !thd->spcont ||
2573
      lex->time_zone_tables_used)
unknown's avatar
unknown committed
2574
    mysql_reset_errors(thd, 0);
2575

unknown's avatar
SCRUM  
unknown committed
2576
#ifdef HAVE_REPLICATION
2577
  if (unlikely(thd->slave_thread))
2578
  {
unknown's avatar
unknown committed
2579
    /*
unknown's avatar
unknown committed
2580 2581
      Check if statment should be skipped because of slave filtering
      rules
2582 2583

      Exceptions are:
unknown's avatar
unknown committed
2584 2585
      - UPDATE MULTI: For this statement, we want to check the filtering
        rules later in the code
2586
      - SET: we always execute it (Not that many SET commands exists in
unknown's avatar
unknown committed
2587 2588
        the binary log anyway -- only 4.1 masters write SET statements,
	in 5.0 there are no SET statements in the binary log)
2589 2590
      - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we
        have stale files on slave caused by exclusion of one tmp table).
unknown's avatar
merge  
unknown committed
2591
    */
unknown's avatar
unknown committed
2592 2593
    if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
	!(lex->sql_command == SQLCOM_SET_OPTION) &&
2594
	!(lex->sql_command == SQLCOM_DROP_TABLE &&
2595
          lex->drop_temporary && lex->drop_if_exists) &&
unknown's avatar
Merge  
unknown committed
2596
        all_tables_not_ok(thd, all_tables))
unknown's avatar
unknown committed
2597 2598
    {
      /* we warn the slave SQL thread */
unknown's avatar
unknown committed
2599
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616
      if (thd->one_shot_set)
      {
        /*
          It's ok to check thd->one_shot_set here:

          The charsets in a MySQL 5.0 slave can change by both a binlogged
          SET ONE_SHOT statement and the event-internal charset setting, 
          and these two ways to change charsets do not seems to work
          together.

          At least there seems to be problems in the rli cache for
          charsets if we are using ONE_SHOT.  Note that this is normally no
          problem because either the >= 5.0 slave reads a 4.1 binlog (with
          ONE_SHOT) *or* or 5.0 binlog (without ONE_SHOT) but never both."
        */
        reset_one_shot_variables(thd);
      }
2617
      DBUG_RETURN(0);
unknown's avatar
unknown committed
2618
    }
2619
  }
2620
  else
2621
  {
2622
#endif /* HAVE_REPLICATION */
2623 2624 2625 2626 2627 2628
    /*
      When option readonly is set deny operations which change non-temporary
      tables. Except for the replication thread and the 'super' users.
    */
    if (opt_readonly &&
	!(thd->security_ctx->master_access & SUPER_ACL) &&
2629
	(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA) &&
2630 2631 2632 2633 2634
        !((lex->sql_command == SQLCOM_CREATE_TABLE) &&
          (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) &&
        !((lex->sql_command == SQLCOM_DROP_TABLE) && lex->drop_temporary) &&
        ((lex->sql_command != SQLCOM_UPDATE_MULTI) &&
          some_non_temp_table_to_be_updated(thd, all_tables)))
2635 2636 2637 2638 2639 2640 2641
    {
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
      DBUG_RETURN(-1);
    }
#ifdef HAVE_REPLICATION
  } /* endif unlikely slave */
#endif
2642 2643
  statistic_increment(thd->status_var.com_stat[lex->sql_command],
                      &LOCK_status);
2644

unknown's avatar
unknown committed
2645
  switch (lex->sql_command) {
2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684
  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:
unknown's avatar
unknown committed
2685
  case SQLCOM_SELECT:
2686
    thd->status_var.last_query_cost= 0.0;
unknown's avatar
VIEW  
unknown committed
2687
    if (all_tables)
unknown's avatar
unknown committed
2688
    {
2689 2690 2691 2692
      res= check_table_access(thd,
                              lex->exchange ? SELECT_ACL | FILE_ACL :
                              SELECT_ACL,
                              all_tables, 0);
unknown's avatar
unknown committed
2693 2694
    }
    else
unknown's avatar
VIEW  
unknown committed
2695
      res= check_access(thd,
2696 2697 2698 2699
                        lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
                        any_db, 0, 0, 0, 0);
    if (!res)
      res= execute_sqlcom_select(thd, all_tables);
unknown's avatar
unknown committed
2700
    break;
unknown's avatar
unknown committed
2701
  case SQLCOM_PREPARE:
2702
  {
2703
    mysql_sql_stmt_prepare(thd);
unknown's avatar
unknown committed
2704 2705 2706 2707
    break;
  }
  case SQLCOM_EXECUTE:
  {
2708
    mysql_sql_stmt_execute(thd);
unknown's avatar
unknown committed
2709 2710 2711 2712
    break;
  }
  case SQLCOM_DEALLOCATE_PREPARE:
  {
2713
    mysql_sql_stmt_close(thd);
unknown's avatar
unknown committed
2714 2715
    break;
  }
unknown's avatar
unknown committed
2716
  case SQLCOM_DO:
2717 2718
    if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
        open_and_lock_tables(thd, all_tables))
unknown's avatar
unknown committed
2719
      goto error;
unknown's avatar
unknown committed
2720 2721

    res= mysql_do(thd, *lex->insert_list);
unknown's avatar
unknown committed
2722 2723
    break;

2724
  case SQLCOM_EMPTY_QUERY:
2725
    send_ok(thd);
2726 2727
    break;

unknown's avatar
unknown committed
2728 2729 2730 2731
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

2732
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2733
  case SQLCOM_PURGE:
2734
  {
unknown's avatar
unknown committed
2735
    if (check_global_access(thd, SUPER_ACL))
2736
      goto error;
unknown's avatar
unknown committed
2737
    /* PURGE MASTER LOGS TO 'file' */
2738 2739 2740
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
2741 2742
  case SQLCOM_PURGE_BEFORE:
  {
2743 2744
    Item *it;

2745 2746
    if (check_global_access(thd, SUPER_ACL))
      goto error;
unknown's avatar
unknown committed
2747
    /* PURGE MASTER LOGS BEFORE 'data' */
2748
    it= (Item *)lex->value_list.head();
2749
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) ||
unknown's avatar
unknown committed
2750
        it->check_cols(1))
2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761
    {
      my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE");
      goto error;
    }
    it= new Item_func_unix_timestamp(it);
    /*
      it is OK only emulate fix_fieds, because we need only
      value of constant
    */
    it->quick_fix_field();
    res = purge_master_logs_before_date(thd, (ulong)it->val_int());
2762 2763
    break;
  }
2764
#endif
unknown's avatar
unknown committed
2765 2766
  case SQLCOM_SHOW_WARNS:
  {
2767 2768
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
2769 2770 2771
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
unknown's avatar
unknown committed
2772 2773 2774 2775
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
2776 2777
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
2778 2779
    break;
  }
unknown's avatar
unknown committed
2780 2781
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
2782
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2783
      goto error;
2784
    /* This query don't work now. See comment in repl_failsafe.cc */
unknown's avatar
unknown committed
2785
#ifndef WORKING_NEW_MASTER
unknown's avatar
unknown committed
2786 2787
    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
    goto error;
unknown's avatar
unknown committed
2788
#else
unknown's avatar
unknown committed
2789 2790
    res = show_new_master(thd);
    break;
unknown's avatar
unknown committed
2791
#endif
unknown's avatar
unknown committed
2792
  }
2793

unknown's avatar
unknown committed
2794
#ifdef HAVE_REPLICATION
2795 2796
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
2797
    if (check_global_access(thd, REPL_SLAVE_ACL))
2798 2799 2800 2801
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
2802 2803
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
2804
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2805
      goto error;
2806
    res = mysql_show_binlog_events(thd);
unknown's avatar
unknown committed
2807 2808
    break;
  }
2809 2810
#endif

unknown's avatar
unknown committed
2811
  case SQLCOM_BACKUP_TABLE:
2812
  {
unknown's avatar
VIEW  
unknown committed
2813
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2814
    if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
unknown's avatar
unknown committed
2815
	check_global_access(thd, FILE_ACL))
2816
      goto error; /* purecov: inspected */
2817
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2818
    res = mysql_backup_table(thd, first_table);
2819
    select_lex->table_list.first= (byte*) first_table;
2820
    lex->query_tables=all_tables;
2821 2822
    break;
  }
unknown's avatar
unknown committed
2823
  case SQLCOM_RESTORE_TABLE:
2824
  {
unknown's avatar
VIEW  
unknown committed
2825
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2826
    if (check_table_access(thd, INSERT_ACL, all_tables, 0) ||
unknown's avatar
unknown committed
2827
	check_global_access(thd, FILE_ACL))
2828
      goto error; /* purecov: inspected */
2829
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2830
    res = mysql_restore_table(thd, first_table);
2831
    select_lex->table_list.first= (byte*) first_table;
2832
    lex->query_tables=all_tables;
2833 2834
    break;
  }
unknown's avatar
unknown committed
2835 2836
  case SQLCOM_ASSIGN_TO_KEYCACHE:
  {
unknown's avatar
VIEW  
unknown committed
2837
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2838
    if (check_access(thd, INDEX_ACL, first_table->db,
2839 2840
                     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
unknown's avatar
unknown committed
2841
      goto error;
2842
    res= mysql_assign_to_keycache(thd, first_table, &lex->ident);
unknown's avatar
unknown committed
2843 2844
    break;
  }
unknown's avatar
unknown committed
2845 2846
  case SQLCOM_PRELOAD_KEYS:
  {
unknown's avatar
VIEW  
unknown committed
2847
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2848
    if (check_access(thd, INDEX_ACL, first_table->db,
2849 2850
                     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
2851
      goto error;
unknown's avatar
VIEW  
unknown committed
2852
    res = mysql_preload_keys(thd, first_table);
unknown's avatar
unknown committed
2853 2854
    break;
  }
unknown's avatar
unknown committed
2855
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2856
  case SQLCOM_CHANGE_MASTER:
2857
  {
unknown's avatar
unknown committed
2858
    if (check_global_access(thd, SUPER_ACL))
2859
      goto error;
2860
    pthread_mutex_lock(&LOCK_active_mi);
2861
    res = change_master(thd,active_mi);
2862
    pthread_mutex_unlock(&LOCK_active_mi);
2863 2864
    break;
  }
unknown's avatar
unknown committed
2865
  case SQLCOM_SHOW_SLAVE_STAT:
2866
  {
2867 2868
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2869
      goto error;
2870
    pthread_mutex_lock(&LOCK_active_mi);
2871
    res = show_master_info(thd,active_mi);
2872
    pthread_mutex_unlock(&LOCK_active_mi);
2873 2874
    break;
  }
unknown's avatar
unknown committed
2875
  case SQLCOM_SHOW_MASTER_STAT:
2876
  {
2877 2878
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2879 2880 2881 2882
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
2883

2884
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
2885
    if (check_global_access(thd, SUPER_ACL))
2886
      goto error;
2887
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2888
      goto error;
2889
    res = load_master_data(thd);
2890
    break;
unknown's avatar
unknown committed
2891
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
2892
  case SQLCOM_SHOW_ENGINE_STATUS:
unknown's avatar
unknown committed
2893
    {
2894
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2895 2896
        goto error;
      res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_STATUS);
unknown's avatar
unknown committed
2897 2898
      break;
    }
unknown's avatar
unknown committed
2899
  case SQLCOM_SHOW_ENGINE_MUTEX:
unknown's avatar
unknown committed
2900 2901
    {
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2902
        goto error;
unknown's avatar
unknown committed
2903
      res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
unknown's avatar
unknown committed
2904 2905
      break;
    }
unknown's avatar
unknown committed
2906
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2907
  case SQLCOM_LOAD_MASTER_TABLE:
2908
  {
unknown's avatar
VIEW  
unknown committed
2909
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2910 2911
    DBUG_ASSERT(first_table->db); /* Must be set in the parser */

unknown's avatar
VIEW  
unknown committed
2912
    if (check_access(thd, CREATE_ACL, first_table->db,
2913 2914
		     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
unknown's avatar
unknown committed
2915 2916 2917 2918
      goto error;				/* purecov: inspected */
    if (grant_option)
    {
      /* Check that the first table has CREATE privilege */
unknown's avatar
VIEW  
unknown committed
2919
      if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
2920
	goto error;
unknown's avatar
unknown committed
2921
    }
2922
    pthread_mutex_lock(&LOCK_active_mi);
2923 2924 2925 2926
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
2927
    if (!fetch_master_table(thd, first_table->db, first_table->table_name,
2928
			    active_mi, 0, 0))
2929
    {
2930
      send_ok(thd);
2931
    }
2932
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2933
    break;
2934
  }
unknown's avatar
unknown committed
2935
#endif /* HAVE_REPLICATION */
2936

unknown's avatar
unknown committed
2937
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
2938
  {
2939
    /* If CREATE TABLE of non-temporary table, do implicit commit */
2940 2941 2942 2943 2944 2945 2946 2947
    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
    {
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
unknown's avatar
VIEW  
unknown committed
2948 2949 2950 2951 2952
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    bool link_to_local;
    // Skip first table, which is the table we are creating
    TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
    TABLE_LIST *select_tables= lex->query_tables;
unknown's avatar
unknown committed
2953

unknown's avatar
VIEW  
unknown committed
2954
    if ((res= create_table_precheck(thd, select_tables, create_table)))
unknown's avatar
unknown committed
2955
      goto end_with_restore_list;
unknown's avatar
unknown committed
2956

2957
#ifndef HAVE_READLINK
2958 2959 2960 2961 2962 2963
    if (lex->create_info.data_file_name)
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                   "DATA DIRECTORY option ignored");
    if (lex->create_info.index_file_name)
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                   "INDEX DIRECTORY option ignored");
2964 2965
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
2966
    /* Fix names if symlinked tables */
unknown's avatar
unknown committed
2967
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
2968
			   create_table->table_name) ||
unknown's avatar
VIEW  
unknown committed
2969
	append_file_to_dir(thd, &lex->create_info.index_file_name,
2970
			   create_table->table_name))
unknown's avatar
unknown committed
2971
      goto end_with_restore_list;
2972
#endif
2973
    /*
2974
      If we are using SET CHARSET without DEFAULT, add an implicit
2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985
      DEFAULT to not confuse old users. (This may change).
    */
    if ((lex->create_info.used_fields & 
	 (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
	HA_CREATE_USED_CHARSET)
    {
      lex->create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
      lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
      lex->create_info.default_table_charset= lex->create_info.table_charset;
      lex->create_info.table_charset= 0;
    }
2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998
    /*
      The create-select command will open and read-lock the select table
      and then create, open and write-lock the new table. If a global
      read lock steps in, we get a deadlock. The write lock waits for
      the global read lock, while the global read lock waits for the
      select table to be closed. So we wait until the global readlock is
      gone before starting both steps. Note that
      wait_if_global_read_lock() sets a protection against a new global
      read lock when it succeeds. This needs to be released by
      start_waiting_global_read_lock(). We protect the normal CREATE
      TABLE in the same way. That way we avoid that a new table is
      created during a gobal read lock.
    */
2999 3000
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
3001
    {
unknown's avatar
unknown committed
3002 3003
      res= 1;
      goto end_with_restore_list;
3004
    }
3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015
#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
3016
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
3017 3018
    {
      select_result *result;
3019

3020
      select_lex->options|= SELECT_NO_UNLOCK;
3021
      unit->set_limit(select_lex);
3022

unknown's avatar
VIEW  
unknown committed
3023
      if (!(res= open_and_lock_tables(thd, select_tables)))
3024
      {
3025 3026 3027 3028
        /*
          Is table which we are changing used somewhere in other parts
          of query
        */
3029
        if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
3030
        {
3031
          TABLE_LIST *duplicate;
3032
          if ((duplicate= unique_table(thd, create_table, select_tables)))
3033 3034 3035
          {
            update_non_unique_table_error(create_table, "CREATE", duplicate);
            res= 1;
3036
            goto end_with_restore_list;
3037
          }
3038
        }
unknown's avatar
unknown committed
3039 3040 3041 3042 3043 3044 3045 3046
        /* If we create merge table, we have to test tables in merge, too */
        if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
        {
          TABLE_LIST *tab;
          for (tab= (TABLE_LIST*) lex->create_info.merge_list.first;
               tab;
               tab= tab->next_local)
          {
3047
            TABLE_LIST *duplicate;
3048
            if ((duplicate= unique_table(thd, tab, select_tables)))
unknown's avatar
unknown committed
3049
            {
3050
              update_non_unique_table_error(tab, "CREATE", duplicate);
unknown's avatar
unknown committed
3051
              res= 1;
3052
              goto end_with_restore_list;
unknown's avatar
unknown committed
3053 3054 3055
            }
          }
        }
3056

unknown's avatar
VIEW  
unknown committed
3057 3058 3059 3060 3061
        if ((result= new select_create(create_table,
				       &lex->create_info,
				       lex->create_list,
				       lex->key_list,
				       select_lex->item_list,
3062 3063
				       lex->duplicates,
				       lex->ignore)))
3064 3065 3066 3067 3068
        {
          /*
            CREATE from SELECT give its SELECT_LEX for SELECT,
            and item_list belong to SELECT
          */
3069
          res= handle_select(thd, lex, result, 0);
3070
          delete result;
3071
        }
unknown's avatar
unknown committed
3072
	/* reset for PS */
3073 3074
	lex->create_list.empty();
	lex->key_list.empty();
3075 3076
      }
    }
unknown's avatar
unknown committed
3077
    else
unknown's avatar
unknown committed
3078
    {
3079 3080 3081
      /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
      if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
        thd->options|= OPTION_KEEP_LOG;
unknown's avatar
unknown committed
3082
      /* regular create */
unknown's avatar
unknown committed
3083
      if (lex->like_name)
unknown's avatar
unknown committed
3084
        res= mysql_create_like_table(thd, create_table, &lex->create_info, 
unknown's avatar
unknown committed
3085
                                     lex->like_name); 
unknown's avatar
unknown committed
3086
      else
3087
      {
unknown's avatar
VIEW  
unknown committed
3088
        res= mysql_create_table(thd, create_table->db,
3089
				create_table->table_name, &lex->create_info,
unknown's avatar
VIEW  
unknown committed
3090
				lex->create_list,
3091
				lex->key_list, 0, 0, 1);
3092
      }
unknown's avatar
unknown committed
3093
      if (!res)
3094
	send_ok(thd);
unknown's avatar
unknown committed
3095
    }
3096

unknown's avatar
unknown committed
3097
    /* put tables back for PS rexecuting */
unknown's avatar
unknown committed
3098
end_with_restore_list:
unknown's avatar
VIEW  
unknown committed
3099
    lex->link_first_table_back(create_table, link_to_local);
unknown's avatar
unknown committed
3100
    break;
unknown's avatar
unknown committed
3101
  }
unknown's avatar
unknown committed
3102
  case SQLCOM_CREATE_INDEX:
unknown's avatar
VIEW  
unknown committed
3103 3104
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, INDEX_ACL, all_tables))
unknown's avatar
unknown committed
3105
      goto error; /* purecov: inspected */
3106
    thd->enable_slow_log= opt_log_slow_admin_statements;
3107
    if (end_active_trans(thd))
unknown's avatar
unknown committed
3108
      goto error;
3109
    res= mysql_create_index(thd, first_table, lex->key_list);
unknown's avatar
unknown committed
3110 3111
    break;

unknown's avatar
unknown committed
3112
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
3113
  case SQLCOM_SLAVE_START:
3114
  {
3115
    pthread_mutex_lock(&LOCK_active_mi);
3116
    start_slave(thd,active_mi,1 /* net report*/);
3117
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
3118
    break;
3119
  }
unknown's avatar
unknown committed
3120
  case SQLCOM_SLAVE_STOP:
3121 3122 3123 3124 3125 3126
  /*
    If the client thread has locked tables, a deadlock is possible.
    Assume that
    - the client thread does LOCK TABLE t READ.
    - then the master updates t.
    - then the SQL slave thread wants to update t,
3127
      so it waits for the client thread because t is locked by it.
3128
    - then the client thread does SLAVE STOP.
3129 3130
      SLAVE STOP waits for the SQL slave thread to terminate its
      update t, which waits for the client thread because t is locked by it.
3131 3132 3133
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
3134
  if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock)
3135
  {
3136 3137
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3138
    goto error;
3139
  }
3140
  {
3141
    pthread_mutex_lock(&LOCK_active_mi);
3142
    stop_slave(thd,active_mi,1/* net report*/);
3143
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
3144
    break;
3145
  }
unknown's avatar
unknown committed
3146
#endif /* HAVE_REPLICATION */
3147

unknown's avatar
unknown committed
3148
  case SQLCOM_ALTER_TABLE:
unknown's avatar
VIEW  
unknown committed
3149
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3150
    {
unknown's avatar
unknown committed
3151
      ulong priv=0;
unknown's avatar
unknown committed
3152
      ulong priv_needed= ALTER_ACL;
3153 3154 3155 3156 3157
      /*
        We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
        as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
      */
      if (lex->alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME))
unknown's avatar
unknown committed
3158 3159
        priv_needed|= DROP_ACL;

unknown's avatar
unknown committed
3160 3161
      /* Must be set in the parser */
      DBUG_ASSERT(select_lex->db);
unknown's avatar
unknown committed
3162
      if (check_access(thd, priv_needed, first_table->db,
3163 3164 3165 3166
		       &first_table->grant.privilege, 0, 0,
                       test(first_table->schema_table)) ||
	  check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0,
                       is_schema_db(select_lex->db))||
unknown's avatar
VIEW  
unknown committed
3167
	  check_merge_table_access(thd, first_table->db,
3168 3169 3170
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
3171 3172
      if (grant_option)
      {
unknown's avatar
unknown committed
3173
	if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0))
unknown's avatar
unknown committed
3174
	  goto error;
3175
	if (lex->name.str && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
unknown's avatar
unknown committed
3176 3177 3178
	{					// Rename of table
	  TABLE_LIST tmp_table;
	  bzero((char*) &tmp_table,sizeof(tmp_table));
3179
	  tmp_table.table_name= lex->name.str;
3180
	  tmp_table.db=select_lex->db;
unknown's avatar
unknown committed
3181
	  tmp_table.grant.privilege=priv;
unknown's avatar
unknown committed
3182 3183
	  if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
			  UINT_MAX, 0))
unknown's avatar
unknown committed
3184 3185 3186
	    goto error;
	}
      }
3187
      /* Don't yet allow changing of symlinks with ALTER TABLE */
3188 3189 3190 3191 3192 3193
      if (lex->create_info.data_file_name)
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                     "DATA DIRECTORY option ignored");
      if (lex->create_info.index_file_name)
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                     "INDEX DIRECTORY option ignored");
3194
      lex->create_info.data_file_name=lex->create_info.index_file_name=0;
unknown's avatar
unknown committed
3195
      /* ALTER TABLE ends previous transaction */
3196
      if (end_active_trans(thd))
unknown's avatar
unknown committed
3197
	goto error;
3198

3199 3200 3201 3202 3203
      if (!thd->locked_tables &&
          !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
      {
        res= 1;
        break;
unknown's avatar
unknown committed
3204
      }
3205

3206
      thd->enable_slow_log= opt_log_slow_admin_statements;
3207
      res= mysql_alter_table(thd, select_lex->db, lex->name.str,
3208 3209 3210 3211 3212
                             &lex->create_info,
                             first_table, lex->create_list,
                             lex->key_list,
                             select_lex->order_list.elements,
                             (ORDER *) select_lex->order_list.first,
3213
                             lex->ignore, &lex->alter_info, 1);
unknown's avatar
unknown committed
3214 3215
      break;
    }
unknown's avatar
unknown committed
3216
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
3217
  {
unknown's avatar
VIEW  
unknown committed
3218
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3219
    TABLE_LIST *table;
unknown's avatar
VIEW  
unknown committed
3220
    for (table= first_table; table; table= table->next_local->next_local)
unknown's avatar
unknown committed
3221
    {
unknown's avatar
unknown committed
3222
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
3223
		       &table->grant.privilege,0,0, test(table->schema_table)) ||
unknown's avatar
VIEW  
unknown committed
3224
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
3225 3226
		       &table->next_local->grant.privilege, 0, 0,
                       test(table->next_local->schema_table)))
unknown's avatar
unknown committed
3227 3228 3229
	goto error;
      if (grant_option)
      {
unknown's avatar
VIEW  
unknown committed
3230
	TABLE_LIST old_list, new_list;
unknown's avatar
unknown committed
3231 3232 3233 3234
	/*
	  we do not need initialize old_list and new_list because we will
	  come table[0] and table->next[0] there
	*/
unknown's avatar
VIEW  
unknown committed
3235 3236 3237 3238
	old_list= table[0];
	new_list= table->next_local[0];
	if (check_grant(thd, ALTER_ACL, &old_list, 0, 1, 0) ||
	    (!test_all_bits(table->next_local->grant.privilege,
3239
			    INSERT_ACL | CREATE_ACL) &&
unknown's avatar
VIEW  
unknown committed
3240
	     check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
unknown's avatar
unknown committed
3241 3242 3243
	  goto error;
      }
    }
unknown's avatar
VIEW  
unknown committed
3244
    query_cache_invalidate3(thd, first_table, 0);
unknown's avatar
unknown committed
3245
    if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
unknown's avatar
unknown committed
3246
      goto error;
unknown's avatar
unknown committed
3247
    break;
unknown's avatar
unknown committed
3248
  }
3249
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
3250 3251
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
3252 3253
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
3254
    goto error;
unknown's avatar
unknown committed
3255 3256
#else
    {
unknown's avatar
unknown committed
3257
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
3258 3259 3260 3261
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
3262
#endif
3263
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
3264
  case SQLCOM_SHOW_CREATE:
unknown's avatar
VIEW  
unknown committed
3265
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3266
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
3267 3268
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
3269
    goto error;
unknown's avatar
unknown committed
3270
#else
unknown's avatar
unknown committed
3271
    {
3272 3273 3274 3275
      /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
      if (lex->only_view)
        first_table->skip_temporary= 1;

unknown's avatar
unknown committed
3276
      if (check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db,
3277 3278
		       &first_table->grant.privilege, 0, 0, 
                       test(first_table->schema_table)))
unknown's avatar
unknown committed
3279
	goto error;
unknown's avatar
unknown committed
3280
      if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0))
3281
	goto error;
unknown's avatar
unknown committed
3282
      res= mysqld_show_create(thd, first_table);
unknown's avatar
unknown committed
3283 3284
      break;
    }
unknown's avatar
unknown committed
3285
#endif
3286 3287
  case SQLCOM_CHECKSUM:
  {
unknown's avatar
VIEW  
unknown committed
3288
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3289
    if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, 0))
3290
      goto error; /* purecov: inspected */
unknown's avatar
VIEW  
unknown committed
3291
    res = mysql_checksum_table(thd, first_table, &lex->check_opt);
3292 3293
    break;
  }
unknown's avatar
unknown committed
3294
  case SQLCOM_REPAIR:
3295
  {
unknown's avatar
VIEW  
unknown committed
3296
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3297
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
3298
      goto error; /* purecov: inspected */
3299
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
3300
    res= mysql_repair_table(thd, first_table, &lex->check_opt);
3301 3302 3303
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
3304
      /* Presumably, REPAIR and binlog writing doesn't require synchronization */
3305 3306
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
3307
	thd->clear_error(); // No binlog error generated
unknown's avatar
unknown committed
3308 3309
        thd->binlog_query(THD::STMT_QUERY_TYPE,
                          thd->query, thd->query_length, 0, FALSE);
3310 3311
      }
    }
3312
    select_lex->table_list.first= (byte*) first_table;
3313
    lex->query_tables=all_tables;
3314 3315
    break;
  }
unknown's avatar
unknown committed
3316
  case SQLCOM_CHECK:
3317
  {
unknown's avatar
VIEW  
unknown committed
3318
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3319
    if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0))
3320
      goto error; /* purecov: inspected */
3321
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
3322
    res = mysql_check_table(thd, first_table, &lex->check_opt);
3323
    select_lex->table_list.first= (byte*) first_table;
3324
    lex->query_tables=all_tables;
3325 3326
    break;
  }
unknown's avatar
unknown committed
3327 3328
  case SQLCOM_ANALYZE:
  {
unknown's avatar
VIEW  
unknown committed
3329
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3330
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
unknown's avatar
unknown committed
3331
      goto error; /* purecov: inspected */
3332
    thd->enable_slow_log= opt_log_slow_admin_statements;
3333
    res= mysql_analyze_table(thd, first_table, &lex->check_opt);
3334 3335 3336
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
3337
      /* Presumably, ANALYZE and binlog writing doesn't require synchronization */
3338 3339
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
3340
	thd->clear_error(); // No binlog error generated
unknown's avatar
unknown committed
3341 3342
        thd->binlog_query(THD::STMT_QUERY_TYPE,
                          thd->query, thd->query_length, 0, FALSE);
3343 3344
      }
    }
3345
    select_lex->table_list.first= (byte*) first_table;
3346
    lex->query_tables=all_tables;
unknown's avatar
unknown committed
3347
    break;
unknown's avatar
unknown committed
3348
  }
3349

unknown's avatar
unknown committed
3350 3351
  case SQLCOM_OPTIMIZE:
  {
unknown's avatar
VIEW  
unknown committed
3352
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3353
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
unknown's avatar
unknown committed
3354
      goto error; /* purecov: inspected */
3355
    thd->enable_slow_log= opt_log_slow_admin_statements;
3356
    res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
unknown's avatar
VIEW  
unknown committed
3357 3358
      mysql_recreate_table(thd, first_table, 1) :
      mysql_optimize_table(thd, first_table, &lex->check_opt);
3359 3360 3361
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
3362
      /* Presumably, OPTIMIZE and binlog writing doesn't require synchronization */
3363 3364
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
3365
	thd->clear_error(); // No binlog error generated
unknown's avatar
unknown committed
3366 3367
        thd->binlog_query(THD::STMT_QUERY_TYPE,
                          thd->query, thd->query_length, 0, FALSE);
3368 3369
      }
    }
3370
    select_lex->table_list.first= (byte*) first_table;
3371
    lex->query_tables=all_tables;
unknown's avatar
unknown committed
3372 3373 3374
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
VIEW  
unknown committed
3375 3376
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (update_precheck(thd, all_tables))
unknown's avatar
unknown committed
3377
      break;
3378 3379
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
unknown's avatar
unknown committed
3380 3381 3382 3383 3384 3385
    res= (result= mysql_update(thd, all_tables,
                               select_lex->item_list,
                               lex->value_list,
                               select_lex->where,
                               select_lex->order_list.elements,
                               (ORDER *) select_lex->order_list.first,
3386
                               unit->select_limit_cnt,
3387
                               lex->duplicates, lex->ignore));
3388
    /* mysql_update return 2 if we need to switch to multi-update */
unknown's avatar
unknown committed
3389
    if (result != 2)
3390
      break;
3391
  case SQLCOM_UPDATE_MULTI:
unknown's avatar
unknown committed
3392 3393 3394 3395
  {
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    /* if we switched from normal update, rights are checked */
    if (result != 2)
3396
    {
unknown's avatar
unknown committed
3397 3398 3399 3400 3401
      if ((res= multi_update_precheck(thd, all_tables)))
        break;
    }
    else
      res= 0;
unknown's avatar
unknown committed
3402

3403
    res= mysql_multi_update_prepare(thd);
unknown's avatar
unknown committed
3404

3405
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
3406
    /* Check slave filtering rules */
3407
    if (unlikely(thd->slave_thread))
unknown's avatar
unknown committed
3408
    {
3409 3410
      if (all_tables_not_ok(thd, all_tables))
      {
3411 3412 3413 3414 3415
        if (res!= 0)
        {
          res= 0;             /* don't care of prev failure  */
          thd->clear_error(); /* filters are of highest prior */
        }
3416 3417 3418 3419
        /* we warn the slave SQL thread */
        my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
        break;
      }
3420 3421
      if (res)
        break;
unknown's avatar
unknown committed
3422
    }
3423 3424
    else
    {
3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437
#endif /* HAVE_REPLICATION */
      if (res)
        break;
      if (opt_readonly &&
	  !(thd->security_ctx->master_access & SUPER_ACL) &&
	  some_non_temp_table_to_be_updated(thd, all_tables))
      {
	my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
	break;
      }
#ifdef HAVE_REPLICATION
    }  /* unlikely */
#endif
unknown's avatar
unknown committed
3438

unknown's avatar
unknown committed
3439 3440 3441 3442 3443 3444
    res= mysql_multi_update(thd, all_tables,
                            &select_lex->item_list,
                            &lex->value_list,
                            select_lex->where,
                            select_lex->options,
                            lex->duplicates, lex->ignore, unit, select_lex);
unknown's avatar
unknown committed
3445
    break;
unknown's avatar
unknown committed
3446
  }
unknown's avatar
unknown committed
3447
  case SQLCOM_REPLACE:
3448 3449
  case SQLCOM_INSERT:
  {
unknown's avatar
VIEW  
unknown committed
3450
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3451
    if ((res= insert_precheck(thd, all_tables)))
unknown's avatar
unknown committed
3452
      break;
3453 3454 3455 3456 3457 3458 3459 3460

    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
    {
      res= 1;
      break;
    }

unknown's avatar
VIEW  
unknown committed
3461
    res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
unknown's avatar
unknown committed
3462
		      lex->update_list, lex->value_list,
3463
                      lex->duplicates, lex->ignore);
3464 3465 3466 3467 3468 3469 3470

    /*
      If we have inserted into a VIEW, and the base table has
      AUTO_INCREMENT column, but this column is not accessible through
      a view, then we should restore LAST_INSERT_ID to the value it
      had before the statement.
    */
unknown's avatar
VIEW  
unknown committed
3471
    if (first_table->view && !first_table->contain_auto_increment)
3472 3473
      thd->first_successful_insert_id_in_cur_stmt=
        thd->first_successful_insert_id_in_prev_stmt;
3474

unknown's avatar
unknown committed
3475
    break;
3476
  }
unknown's avatar
unknown committed
3477 3478 3479
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
unknown's avatar
unknown committed
3480
    select_result *result;
unknown's avatar
VIEW  
unknown committed
3481
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3482
    if ((res= insert_precheck(thd, all_tables)))
3483
      break;
unknown's avatar
unknown committed
3484

3485
    /* Fix lock for first table */
unknown's avatar
VIEW  
unknown committed
3486 3487
    if (first_table->lock_type == TL_WRITE_DELAYED)
      first_table->lock_type= TL_WRITE;
3488

3489 3490
    /* Don't unlock tables until command is written to binary log */
    select_lex->options|= SELECT_NO_UNLOCK;
unknown's avatar
unknown committed
3491

3492
    unit->set_limit(select_lex);
3493 3494 3495 3496 3497 3498 3499 3500

    if (! thd->locked_tables &&
        ! (need_start_waiting= ! wait_if_global_read_lock(thd, 0, 1)))
    {
      res= 1;
      break;
    }

unknown's avatar
VIEW  
unknown committed
3501
    if (!(res= open_and_lock_tables(thd, all_tables)))
3502
    {
3503
      /* Skip first table, which is the table we are inserting in */
unknown's avatar
unknown committed
3504 3505
      TABLE_LIST *second_table= first_table->next_local;
      select_lex->table_list.first= (byte*) second_table;
3506 3507
      select_lex->context.table_list= 
        select_lex->context.first_name_resolution_table= second_table;
3508 3509 3510
      res= mysql_insert_select_prepare(thd);
      if (!res && (result= new select_insert(first_table, first_table->table,
                                             &lex->field_list,
3511 3512
                                             &lex->update_list,
                                             &lex->value_list,
3513
                                             lex->duplicates, lex->ignore)))
3514
      {
3515
	res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
3516 3517 3518 3519 3520 3521 3522 3523 3524
        /*
          Invalidate the table in the query cache if something changed
          after unlocking when changes become visible.
          TODO: this is workaround. right way will be move invalidating in
          the unlock procedure.
        */
        if (first_table->lock_type ==  TL_WRITE_CONCURRENT_INSERT &&
            thd->lock)
        {
3525 3526 3527
          /* INSERT ... SELECT should invalidate only the very first table */
          TABLE_LIST *save_table= first_table->next_local;
          first_table->next_local= 0;
3528 3529
          mysql_unlock_tables(thd, thd->lock);
          query_cache_invalidate3(thd, first_table, 1);
3530
          first_table->next_local= save_table;
3531 3532
          thd->lock=0;
        }
3533 3534
        delete result;
      }
3535
      /* revert changes for SP */
unknown's avatar
unknown committed
3536
      select_lex->table_list.first= (byte*) first_table;
3537
    }
unknown's avatar
VIEW  
unknown committed
3538

3539 3540 3541 3542 3543 3544
    /*
      If we have inserted into a VIEW, and the base table has
      AUTO_INCREMENT column, but this column is not accessible through
      a view, then we should restore LAST_INSERT_ID to the value it
      had before the statement.
    */
unknown's avatar
VIEW  
unknown committed
3545
    if (first_table->view && !first_table->contain_auto_increment)
3546 3547
      thd->first_successful_insert_id_in_cur_stmt=
        thd->first_successful_insert_id_in_prev_stmt;
3548

unknown's avatar
unknown committed
3549 3550
    break;
  }
3551
  case SQLCOM_TRUNCATE:
3552 3553 3554 3555 3556
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
VIEW  
unknown committed
3557 3558
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, DELETE_ACL, all_tables))
unknown's avatar
unknown committed
3559
      goto error;
3560 3561 3562 3563
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
3564
    if (thd->locked_tables || thd->active_transaction())
3565
    {
unknown's avatar
unknown committed
3566 3567
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3568 3569
      goto error;
    }
unknown's avatar
VIEW  
unknown committed
3570

unknown's avatar
unknown committed
3571
    res= mysql_truncate(thd, first_table, 0);
3572
    break;
unknown's avatar
unknown committed
3573
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
3574
  {
unknown's avatar
VIEW  
unknown committed
3575 3576
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if ((res= delete_precheck(thd, all_tables)))
unknown's avatar
unknown committed
3577
      break;
3578 3579
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
3580 3581 3582 3583 3584 3585 3586 3587

    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
    {
      res= 1;
      break;
    }

unknown's avatar
VIEW  
unknown committed
3588
    res = mysql_delete(thd, all_tables, select_lex->where,
3589
                       &select_lex->order_list,
unknown's avatar
unknown committed
3590 3591
                       unit->select_limit_cnt, select_lex->options,
                       FALSE);
unknown's avatar
unknown committed
3592 3593
    break;
  }
3594
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
3595
  {
unknown's avatar
VIEW  
unknown committed
3596
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3597
    TABLE_LIST *aux_tables=
unknown's avatar
unknown committed
3598
      (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
unknown's avatar
unknown committed
3599
    multi_delete *result;
unknown's avatar
unknown committed
3600

3601 3602 3603 3604 3605 3606 3607
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
    {
      res= 1;
      break;
    }

3608
    if ((res= multi_delete_precheck(thd, all_tables)))
3609
      break;
unknown's avatar
unknown committed
3610

unknown's avatar
unknown committed
3611
    /* condition will be TRUE on SP re-excuting */
3612 3613
    if (select_lex->item_list.elements != 0)
      select_lex->item_list.empty();
unknown's avatar
unknown committed
3614
    if (add_item_to_list(thd, new Item_null()))
unknown's avatar
unknown committed
3615
      goto error;
3616

unknown's avatar
unknown committed
3617
    thd->proc_info="init";
unknown's avatar
VIEW  
unknown committed
3618 3619 3620 3621
    if ((res= open_and_lock_tables(thd, all_tables)))
      break;

    if ((res= mysql_multi_delete_prepare(thd)))
unknown's avatar
unknown committed
3622
      goto error;
3623

3624
    if (!thd->is_fatal_error && (result= new multi_delete(aux_tables,
3625
							  lex->table_count)))
unknown's avatar
unknown committed
3626
    {
3627 3628 3629
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
3630
			select_lex->item_list,
unknown's avatar
unknown committed
3631
			select_lex->where,
3632
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
unknown's avatar
unknown committed
3633 3634
			(ORDER *)NULL,
			select_lex->options | thd->options |
3635 3636
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
                        OPTION_SETUP_TABLES_DONE,
3637
			result, unit, select_lex);
3638
      delete result;
unknown's avatar
unknown committed
3639 3640
    }
    else
3641
      res= TRUE;                                // Error
unknown's avatar
unknown committed
3642 3643
    break;
  }
unknown's avatar
unknown committed
3644
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
3645
  {
unknown's avatar
VIEW  
unknown committed
3646
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3647 3648
    if (!lex->drop_temporary)
    {
unknown's avatar
VIEW  
unknown committed
3649
      if (check_table_access(thd, DROP_ACL, all_tables, 0))
3650 3651
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
unknown's avatar
unknown committed
3652
        goto error;
3653
    }
unknown's avatar
unknown committed
3654
    else
unknown's avatar
unknown committed
3655 3656 3657 3658 3659 3660
    {
      /*
	If this is a slave thread, we may sometimes execute some 
	DROP / * 40005 TEMPORARY * / TABLE
	that come from parts of binlogs (likely if we use RESET SLAVE or CHANGE
	MASTER TO), while the temporary table has already been dropped.
unknown's avatar
unknown committed
3661 3662
	To not generate such irrelevant "table does not exist errors",
	we silently add IF EXISTS if TEMPORARY was used.
unknown's avatar
unknown committed
3663 3664 3665
      */
      if (thd->slave_thread)
	lex->drop_if_exists= 1;
3666

unknown's avatar
unknown committed
3667
      /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
3668
      thd->options|= OPTION_KEEP_LOG;
unknown's avatar
unknown committed
3669
    }
3670
    /* DDL and binlog write order protected by LOCK_open */
unknown's avatar
VIEW  
unknown committed
3671 3672
    res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
			lex->drop_temporary);
unknown's avatar
unknown committed
3673 3674
  }
  break;
unknown's avatar
unknown committed
3675
  case SQLCOM_DROP_INDEX:
unknown's avatar
VIEW  
unknown committed
3676 3677
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, INDEX_ACL, all_tables))
unknown's avatar
unknown committed
3678
      goto error;				/* purecov: inspected */
3679
    if (end_active_trans(thd))
unknown's avatar
unknown committed
3680
      goto error;
3681
    res= mysql_drop_index(thd, first_table, &lex->alter_info);
unknown's avatar
unknown committed
3682 3683
    break;
  case SQLCOM_SHOW_PROCESSLIST:
3684 3685
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
3686
      break;
unknown's avatar
unknown committed
3687
    mysqld_list_processes(thd,
3688 3689 3690 3691
			  (thd->security_ctx->master_access & PROCESS_ACL ?
                           NullS :
                           thd->security_ctx->priv_user),
                          lex->verbose);
unknown's avatar
unknown committed
3692
    break;
unknown's avatar
unknown committed
3693 3694
  case SQLCOM_SHOW_STORAGE_ENGINES:
    res= mysqld_show_storage_engines(thd);
unknown's avatar
unknown committed
3695
    break;
unknown's avatar
unknown committed
3696 3697 3698
  case SQLCOM_SHOW_AUTHORS:
    res= mysqld_show_authors(thd);
    break;
3699 3700 3701
  case SQLCOM_SHOW_CONTRIBUTORS:
    res= mysqld_show_contributors(thd);
    break;
unknown's avatar
unknown committed
3702 3703 3704 3705 3706 3707
  case SQLCOM_SHOW_PRIVILEGES:
    res= mysqld_show_privileges(thd);
    break;
  case SQLCOM_SHOW_COLUMN_TYPES:
    res= mysqld_show_column_types(thd);
    break;
unknown's avatar
unknown committed
3708
  case SQLCOM_SHOW_ENGINE_LOGS:
unknown's avatar
unknown committed
3709
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
3710 3711
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
3712
    goto error;
unknown's avatar
unknown committed
3713 3714
#else
    {
3715
      if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0,0))
unknown's avatar
unknown committed
3716
	goto error;
unknown's avatar
unknown committed
3717
      res= ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_LOGS);
unknown's avatar
unknown committed
3718 3719
      break;
    }
unknown's avatar
unknown committed
3720 3721
#endif
  case SQLCOM_CHANGE_DB:
3722 3723
    if (!mysql_change_db(thd,select_lex->db,FALSE))
      send_ok(thd);
unknown's avatar
unknown committed
3724
    break;
3725

unknown's avatar
unknown committed
3726 3727
  case SQLCOM_LOAD:
  {
unknown's avatar
VIEW  
unknown committed
3728
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3729
    uint privilege= (lex->duplicates == DUP_REPLACE ?
unknown's avatar
unknown committed
3730 3731
		     INSERT_ACL | DELETE_ACL : INSERT_ACL) |
                    (lex->local_file ? 0 : FILE_ACL);
3732

unknown's avatar
unknown committed
3733
    if (lex->local_file)
unknown's avatar
unknown committed
3734
    {
3735
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
3736
          !opt_local_infile)
3737
      {
unknown's avatar
unknown committed
3738
	my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0));
3739 3740
	goto error;
      }
unknown's avatar
unknown committed
3741
    }
unknown's avatar
unknown committed
3742 3743 3744 3745

    if (check_one_table_access(thd, privilege, all_tables))
      goto error;

unknown's avatar
VIEW  
unknown committed
3746
    res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
unknown's avatar
unknown committed
3747
                    lex->update_list, lex->value_list, lex->duplicates,
3748
                    lex->ignore, (bool) lex->local_file);
unknown's avatar
unknown committed
3749 3750
    break;
  }
3751

unknown's avatar
unknown committed
3752
  case SQLCOM_SET_OPTION:
3753 3754
  {
    List<set_var_base> *lex_var_list= &lex->var_list;
3755
    if ((check_table_access(thd, SELECT_ACL, all_tables, 0) ||
unknown's avatar
unknown committed
3756 3757
	 open_and_lock_tables(thd, all_tables)))
      goto error;
3758 3759
    if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
    {
unknown's avatar
unknown committed
3760 3761
      my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
      goto error;
3762 3763 3764 3765 3766 3767 3768 3769
    }
    if (!(res= sql_set_variables(thd, lex_var_list)))
    {
      /*
        If the previous command was a SET ONE_SHOT, we don't want to forget
        about the ONE_SHOT property of that SET. So we use a |= instead of = .
      */
      thd->one_shot_set|= lex->one_shot_set;
3770
      send_ok(thd);
3771
    }
unknown's avatar
unknown committed
3772
    break;
3773
  }
unknown's avatar
unknown committed
3774

unknown's avatar
unknown committed
3775
  case SQLCOM_UNLOCK_TABLES:
3776 3777 3778 3779 3780 3781
    /*
      It is critical for mysqldump --single-transaction --master-data that
      UNLOCK TABLES does not implicitely commit a connection which has only
      done FLUSH TABLES WITH READ LOCK + BEGIN. If this assumption becomes
      false, mysqldump will not work.
    */
unknown's avatar
unknown committed
3782
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
3783 3784
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
3785
      end_active_trans(thd);
unknown's avatar
unknown committed
3786
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3787 3788
    }
    if (thd->global_read_lock)
3789
      unlock_global_read_lock(thd);
3790
    send_ok(thd);
unknown's avatar
unknown committed
3791 3792
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
3793
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
3794
    if (end_active_trans(thd))
unknown's avatar
unknown committed
3795
      goto error;
unknown's avatar
VIEW  
unknown committed
3796
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
3797
      goto error;
unknown's avatar
unknown committed
3798
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
3799
    thd->options|= OPTION_TABLE_LOCK;
unknown's avatar
VIEW  
unknown committed
3800

3801
    if (!(res= simple_open_n_lock_tables(thd, all_tables)))
unknown's avatar
unknown committed
3802
    {
3803 3804
#ifdef HAVE_QUERY_CACHE
      if (thd->variables.query_cache_wlock_invalidate)
unknown's avatar
VIEW  
unknown committed
3805
	query_cache.invalidate_locked_for_write(first_table);
3806
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
3807 3808
      thd->locked_tables=thd->lock;
      thd->lock=0;
3809
      send_ok(thd);
unknown's avatar
unknown committed
3810
    }
unknown's avatar
unknown committed
3811 3812
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3813 3814 3815
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
3816
  {
3817 3818 3819 3820 3821
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
unknown committed
3822
    char *alias;
3823 3824
    if (!(alias=thd->strmake(lex->name.str, lex->name.length)) ||
        check_db_name(&lex->name))
unknown's avatar
unknown committed
3825
    {
3826
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3827 3828
      break;
    }
3829 3830 3831
    /*
      If in a slave thread :
      CREATE DATABASE DB was certainly not preceded by USE DB.
3832
      For that reason, db_ok() in sql/slave.cc did not check the
3833 3834 3835
      do_db/ignore_db. And as this query involves no tables, tables_ok()
      above was not called. So we have to check rules again here.
    */
3836
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
3837
    if (thd->slave_thread && 
3838 3839
	(!rpl_filter->db_ok(lex->name.str) ||
	 !rpl_filter->db_ok_with_wild_table(lex->name.str)))
unknown's avatar
unknown committed
3840
    {
unknown's avatar
unknown committed
3841
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3842
      break;
unknown's avatar
unknown committed
3843
    }
3844
#endif
3845 3846
    if (check_access(thd,CREATE_ACL,lex->name.str, 0, 1, 0,
                     is_schema_db(lex->name.str)))
3847
      break;
3848 3849
    res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
                              lex->name.str), &lex->create_info, 0);
3850 3851
    break;
  }
unknown's avatar
unknown committed
3852
  case SQLCOM_DROP_DB:
3853
  {
3854 3855 3856 3857 3858
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
3859
    if (check_db_name(&lex->name))
unknown's avatar
unknown committed
3860
    {
3861
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3862 3863
      break;
    }
3864 3865 3866 3867 3868 3869 3870
    /*
      If in a slave thread :
      DROP DATABASE DB may not be preceded by USE DB.
      For that reason, maybe db_ok() in sql/slave.cc did not check the 
      do_db/ignore_db. And as this query involves no tables, tables_ok()
      above was not called. So we have to check rules again here.
    */
3871
#ifdef HAVE_REPLICATION
3872
    if (thd->slave_thread && 
3873 3874
	(!rpl_filter->db_ok(lex->name.str) ||
	 !rpl_filter->db_ok_with_wild_table(lex->name.str)))
unknown's avatar
unknown committed
3875
    {
unknown's avatar
unknown committed
3876
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3877
      break;
unknown's avatar
unknown committed
3878
    }
3879
#endif
3880 3881
    if (check_access(thd,DROP_ACL,lex->name.str,0,1,0,
                     is_schema_db(lex->name.str)))
3882
      break;
3883 3884
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3885 3886
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3887 3888
      goto error;
    }
3889
    res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0);
3890 3891
    break;
  }
unknown's avatar
unknown committed
3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914
  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
3915 3916 3917 3918 3919
    if (check_db_name(newdb))
    {
      my_error(ER_WRONG_DB_NAME, MYF(0), newdb->str);
      break;
    }
unknown's avatar
unknown committed
3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938
    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_rename_db(thd, olddb, newdb);
    if (!res)
      send_ok(thd);
    break;
  }
3939 3940
  case SQLCOM_ALTER_DB:
  {
3941 3942
    LEX_STRING *db= &lex->name;
    if (check_db_name(db))
3943
    {
3944
      my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
3945 3946
      break;
    }
unknown's avatar
unknown committed
3947 3948 3949
    /*
      If in a slave thread :
      ALTER DATABASE DB may not be preceded by USE DB.
3950
      For that reason, maybe db_ok() in sql/slave.cc did not check the
unknown's avatar
unknown committed
3951 3952 3953 3954
      do_db/ignore_db. And as this query involves no tables, tables_ok()
      above was not called. So we have to check rules again here.
    */
#ifdef HAVE_REPLICATION
3955
    if (thd->slave_thread &&
3956 3957
	(!rpl_filter->db_ok(db->str) ||
	 !rpl_filter->db_ok_with_wild_table(db->str)))
unknown's avatar
unknown committed
3958
    {
unknown's avatar
unknown committed
3959
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
unknown's avatar
unknown committed
3960 3961 3962
      break;
    }
#endif
3963
    if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0, is_schema_db(db->str)))
3964 3965 3966
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3967 3968
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3969 3970
      goto error;
    }
3971
    res= mysql_alter_db(thd, db->str, &lex->create_info);
3972 3973
    break;
  }
unknown's avatar
unknown committed
3974 3975
  case SQLCOM_SHOW_CREATE_DB:
  {
3976
    if (check_db_name(&lex->name))
unknown's avatar
unknown committed
3977
    {
3978
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3979 3980
      break;
    }
3981
    res= mysqld_show_create_db(thd, lex->name.str, &lex->create_info);
unknown's avatar
unknown committed
3982 3983
    break;
  }
unknown's avatar
unknown committed
3984 3985
  case SQLCOM_CREATE_EVENT:
  case SQLCOM_ALTER_EVENT:
3986
  do
unknown's avatar
unknown committed
3987
  {
unknown's avatar
unknown committed
3988
    DBUG_ASSERT(lex->event_parse_data);
unknown's avatar
unknown committed
3989 3990 3991 3992 3993 3994
    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;
    }
unknown's avatar
unknown committed
3995 3996
    switch (lex->sql_command) {
    case SQLCOM_CREATE_EVENT:
3997 3998
      res= Events::get_instance()->
            create_event(thd, lex->event_parse_data,
3999
                         lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS);
unknown's avatar
unknown committed
4000 4001
      break;
    case SQLCOM_ALTER_EVENT:
4002 4003
      res= Events::get_instance()->update_event(thd, lex->event_parse_data,
                                                lex->spname);
unknown's avatar
unknown committed
4004
      break;
4005 4006
    default:
      DBUG_ASSERT(0);
unknown's avatar
unknown committed
4007
    }
4008
    DBUG_PRINT("info",("DDL error code=%d", res));
unknown's avatar
unknown committed
4009
    if (!res)
4010
      send_ok(thd);
unknown's avatar
unknown committed
4011

4012 4013 4014 4015 4016 4017
  } while (0);
  /* Don't do it, if we are inside a SP */
  if (!thd->spcont)
  {
    delete lex->sphead;
    lex->sphead= NULL;
unknown's avatar
unknown committed
4018
  }
4019 4020
  /* lex->unit.cleanup() is called outside, no need to call it here */
  break;
4021
  case SQLCOM_DROP_EVENT:
unknown's avatar
unknown committed
4022 4023 4024 4025 4026 4027
  case SQLCOM_SHOW_CREATE_EVENT:
  {
    DBUG_ASSERT(lex->spname);
    if (! lex->spname->m_db.str)
    {
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
4028
      goto error;
unknown's avatar
unknown committed
4029 4030 4031 4032 4033 4034 4035 4036
    }
    if (check_access(thd, EVENT_ACL, lex->spname->m_db.str, 0, 0, 0,
                     is_schema_db(lex->spname->m_db.str)))
      break;

    if (lex->spname->m_name.length > NAME_LEN)
    {
      my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
4037
      /* this jumps to the end of the function and skips own messaging */
unknown's avatar
unknown committed
4038 4039
      goto error;
    }
4040 4041

    if (lex->sql_command == SQLCOM_SHOW_CREATE_EVENT)
4042 4043
      res= Events::get_instance()->show_create_event(thd, lex->spname->m_db,
                                                     lex->spname->m_name);
4044 4045
    else
    {
4046
      uint affected= 1;
4047 4048 4049 4050 4051
      if (!(res= Events::get_instance()->drop_event(thd,
                                                    lex->spname->m_db,
                                                    lex->spname->m_name,
                                                    lex->drop_if_exists,
                                                    FALSE)))
4052
        send_ok(thd);
4053
    }
4054 4055
    break;
  }
unknown's avatar
unknown committed
4056
  case SQLCOM_CREATE_FUNCTION:                  // UDF function
unknown's avatar
unknown committed
4057
  {
4058
    if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
unknown's avatar
unknown committed
4059
      break;
unknown's avatar
unknown committed
4060
#ifdef HAVE_DLOPEN
4061 4062
    if (sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                        &thd->sp_func_cache, FALSE))
unknown's avatar
unknown committed
4063
    {
4064
      my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str);
unknown's avatar
unknown committed
4065 4066
      goto error;
    }
4067
    if (!(res = mysql_create_function(thd, &lex->udf)))
unknown's avatar
unknown committed
4068
      send_ok(thd);
unknown's avatar
unknown committed
4069
#else
unknown's avatar
unknown committed
4070
    my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled");
unknown's avatar
unknown committed
4071
    res= TRUE;
unknown's avatar
unknown committed
4072 4073
#endif
    break;
unknown's avatar
unknown committed
4074
  }
unknown's avatar
unknown committed
4075
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4076 4077
  case SQLCOM_CREATE_USER:
  {
4078
    if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) &&
4079
        check_global_access(thd,CREATE_USER_ACL))
4080
      break;
4081 4082
    if (end_active_trans(thd))
      goto error;
4083
    /* Conditionally writes to binlog */
4084 4085 4086 4087
    if (!(res= mysql_create_user(thd, lex->users_list)))
      send_ok(thd);
    break;
  }
4088 4089
  case SQLCOM_DROP_USER:
  {
4090
    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) &&
4091
        check_global_access(thd,CREATE_USER_ACL))
4092
      break;
4093 4094
    if (end_active_trans(thd))
      goto error;
4095
    /* Conditionally writes to binlog */
4096
    if (!(res= mysql_drop_user(thd, lex->users_list)))
4097 4098 4099 4100 4101
      send_ok(thd);
    break;
  }
  case SQLCOM_RENAME_USER:
  {
4102
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
4103
        check_global_access(thd,CREATE_USER_ACL))
4104
      break;
4105 4106
    if (end_active_trans(thd))
      goto error;
4107
    /* Conditionally writes to binlog */
4108
    if (!(res= mysql_rename_user(thd, lex->users_list)))
4109 4110 4111 4112 4113
      send_ok(thd);
    break;
  }
  case SQLCOM_REVOKE_ALL:
  {
4114
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
4115
        check_global_access(thd,CREATE_USER_ACL))
4116
      break;
4117
    /* Conditionally writes to binlog */
4118 4119 4120 4121
    if (!(res = mysql_revoke_all(thd, lex->users_list)))
      send_ok(thd);
    break;
  }
4122 4123 4124 4125
  case SQLCOM_REVOKE:
  case SQLCOM_GRANT:
  {
    if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
unknown's avatar
unknown committed
4126
		     first_table ?  first_table->db : select_lex->db,
unknown's avatar
VIEW  
unknown committed
4127
		     first_table ? &first_table->grant.privilege : 0,
4128 4129 4130
		     first_table ? 0 : 1, 0,
                     first_table ? (bool) first_table->schema_table :
                     select_lex->db ? is_schema_db(select_lex->db) : 0))
4131 4132
      goto error;

4133
    if (thd->security_ctx->user)              // If not replication
unknown's avatar
unknown committed
4134
    {
4135
      LEX_USER *user, *tmp_user;
4136

unknown's avatar
unknown committed
4137
      List_iterator <LEX_USER> user_list(lex->users_list);
4138
      while ((tmp_user= user_list++))
unknown's avatar
unknown committed
4139
      {
4140 4141
        if (!(user= get_current_user(thd, tmp_user)))
          goto error;
4142 4143 4144 4145 4146 4147 4148 4149
        if (specialflag & SPECIAL_NO_RESOLVE &&
            hostname_requires_resolving(user->host.str))
          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                              ER_WARN_HOSTNAME_WONT_WORK,
                              ER(ER_WARN_HOSTNAME_WONT_WORK),
                              user->host.str);
        // Are we trying to change a password of another user
        DBUG_ASSERT(user->host.str != 0);
4150
        if (strcmp(thd->security_ctx->user, user->user.str) ||
4151
            my_strcasecmp(system_charset_info,
4152
                          user->host.str, thd->security_ctx->host_or_ip))
4153 4154
        {
          // TODO: use check_change_password()
4155 4156
          if (is_acl_user(user->host.str, user->user.str) &&
              user->password.str &&
4157
              check_access(thd, UPDATE_ACL,"mysql",0,1,1,0))
4158 4159 4160 4161 4162 4163
          {
            my_message(ER_PASSWORD_NOT_ALLOWED,
                       ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
            goto error;
          }
        }
unknown's avatar
SCRUM  
unknown committed
4164 4165
      }
    }
unknown's avatar
VIEW  
unknown committed
4166
    if (first_table)
4167
    {
4168 4169
      if (lex->type == TYPE_ENUM_PROCEDURE ||
          lex->type == TYPE_ENUM_FUNCTION)
4170 4171 4172 4173 4174
      {
        uint grants= lex->all_privileges 
		   ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
		   : lex->grant;
        if (grant_option && 
4175 4176
	    check_grant_routine(thd, grants | GRANT_ACL, all_tables,
                                lex->type == TYPE_ENUM_PROCEDURE, 0))
4177
	  goto error;
4178
        /* Conditionally writes to binlog */
4179 4180 4181 4182
        res= mysql_routine_grant(thd, all_tables,
                                 lex->type == TYPE_ENUM_PROCEDURE, 
                                 lex->users_list, grants,
                                 lex->sql_command == SQLCOM_REVOKE, 0);
4183 4184 4185 4186 4187 4188 4189 4190
      }
      else
      {
	if (grant_option && check_grant(thd,
					(lex->grant | lex->grant_tot_col |
					 GRANT_ACL),
					all_tables, 0, UINT_MAX, 0))
	  goto error;
4191
        /* Conditionally writes to binlog */
4192 4193 4194 4195
        res= mysql_table_grant(thd, all_tables, lex->users_list,
			       lex->columns, lex->grant,
			       lex->sql_command == SQLCOM_REVOKE);
      }
4196 4197 4198
    }
    else
    {
4199
      if (lex->columns.elements || lex->type)
4200
      {
unknown's avatar
unknown committed
4201 4202
	my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
                   MYF(0));
unknown's avatar
unknown committed
4203
        goto error;
4204 4205
      }
      else
4206
	/* Conditionally writes to binlog */
4207 4208 4209 4210
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
4211
	if (lex->sql_command == SQLCOM_GRANT)
4212
	{
unknown's avatar
unknown committed
4213
	  List_iterator <LEX_USER> str_list(lex->users_list);
4214 4215 4216 4217 4218
	  LEX_USER *user, *tmp_user;
	  while ((tmp_user=str_list++))
          {
            if (!(user= get_current_user(thd, tmp_user)))
              goto error;
unknown's avatar
unknown committed
4219
	    reset_mqh(user);
4220
          }
4221
	}
4222 4223 4224 4225
      }
    }
    break;
  }
unknown's avatar
SCRUM  
unknown committed
4226
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
unknown's avatar
unknown committed
4227
  case SQLCOM_RESET:
4228 4229 4230
    /*
      RESET commands are never written to the binary log, so we have to
      initialize this variable because RESET shares the same code as FLUSH
4231 4232 4233 4234
    */
    lex->no_write_to_binlog= 1;
  case SQLCOM_FLUSH:
  {
unknown's avatar
unknown committed
4235
    bool write_to_binlog;
unknown's avatar
unknown committed
4236
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
4237
      goto error;
4238

4239 4240 4241 4242
    /*
      reload_acl_and_cache() will tell us if we are allowed to write to the
      binlog or not.
    */
unknown's avatar
unknown committed
4243
    if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
4244 4245 4246 4247 4248
    {
      /*
        We WANT to write and we CAN write.
        ! we write after unlocking the table.
      */
4249
      /* Presumably, RESET and binlog writing doesn't require synchronization */
4250 4251 4252 4253
      if (!lex->no_write_to_binlog && write_to_binlog)
      {
        if (mysql_bin_log.is_open())
        {
unknown's avatar
unknown committed
4254 4255
          thd->binlog_query(THD::STMT_QUERY_TYPE,
                            thd->query, thd->query_length, 0, FALSE);
4256 4257 4258
        }
      }
      send_ok(thd);
4259 4260
    } 
    
unknown's avatar
unknown committed
4261
    break;
4262
  }
unknown's avatar
unknown committed
4263
  case SQLCOM_KILL:
4264 4265 4266
  {
    Item *it= (Item *)lex->value_list.head();

unknown's avatar
unknown committed
4267 4268 4269 4270 4271 4272 4273
    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;
    }

4274
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1))
4275 4276 4277 4278 4279
    {
      my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
		 MYF(0));
      goto error;
    }
4280
    sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
unknown's avatar
unknown committed
4281
    break;
4282
  }
unknown's avatar
unknown committed
4283
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
4284
  case SQLCOM_SHOW_GRANTS:
4285 4286 4287 4288
  {
    LEX_USER *grant_user= get_current_user(thd, lex->grant_user);
    if (!grant_user)
      goto error;
4289
    if ((thd->security_ctx->priv_user &&
4290
	 !strcmp(thd->security_ctx->priv_user, grant_user->user.str)) ||
4291
	!check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
unknown's avatar
unknown committed
4292
    {
4293
      res = mysql_show_grants(thd, grant_user);
unknown's avatar
unknown committed
4294 4295
    }
    break;
4296
  }
unknown's avatar
unknown committed
4297
#endif
4298
  case SQLCOM_HA_OPEN:
unknown's avatar
VIEW  
unknown committed
4299
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
4300
    if (check_table_access(thd, SELECT_ACL, all_tables, 0))
4301
      goto error;
unknown's avatar
unknown committed
4302
    res= mysql_ha_open(thd, first_table, 0);
4303 4304
    break;
  case SQLCOM_HA_CLOSE:
unknown's avatar
VIEW  
unknown committed
4305 4306
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    res= mysql_ha_close(thd, first_table);
4307 4308
    break;
  case SQLCOM_HA_READ:
unknown's avatar
VIEW  
unknown committed
4309
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
4310 4311 4312 4313 4314
    /*
      There is no need to check for table permissions here, because
      if a user has no permissions to read a table, he won't be
      able to open it (with SQLCOM_HA_OPEN) in the first place.
    */
4315
    unit->set_limit(select_lex);
4316
    res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
unknown's avatar
VIEW  
unknown committed
4317
                       lex->insert_list, lex->ha_rkey_mode, select_lex->where,
4318
                       unit->select_limit_cnt, unit->offset_limit_cnt);
4319 4320
    break;

unknown's avatar
unknown committed
4321
  case SQLCOM_BEGIN:
4322 4323 4324 4325 4326 4327
    if (thd->transaction.xid_state.xa_state != XA_NOTR)
    {
      my_error(ER_XAER_RMFAIL, MYF(0),
               xa_state_names[thd->transaction.xid_state.xa_state]);
      break;
    }
unknown's avatar
unknown committed
4328
    if (begin_trans(thd))
unknown's avatar
unknown committed
4329
      goto error;
unknown's avatar
unknown committed
4330
    send_ok(thd);
unknown's avatar
unknown committed
4331 4332
    break;
  case SQLCOM_COMMIT:
4333
    if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
unknown's avatar
unknown committed
4334
                              lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
unknown's avatar
unknown committed
4335
      goto error;
4336
    send_ok(thd);
unknown's avatar
unknown committed
4337 4338
    break;
  case SQLCOM_ROLLBACK:
4339
    if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
unknown's avatar
unknown committed
4340
                              lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
unknown's avatar
unknown committed
4341
      goto error;
4342
    send_ok(thd);
unknown's avatar
unknown committed
4343
    break;
unknown's avatar
unknown committed
4344
  case SQLCOM_RELEASE_SAVEPOINT:
unknown's avatar
unknown committed
4345
  {
4346 4347
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
unknown's avatar
unknown committed
4348 4349 4350
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
4351
                       (uchar *)sv->name, sv->length) == 0)
unknown's avatar
unknown committed
4352 4353
        break;
    }
4354
    if (sv)
unknown's avatar
unknown committed
4355
    {
4356
      if (ha_release_savepoint(thd, sv))
unknown's avatar
unknown committed
4357
        res= TRUE; // cannot happen
unknown's avatar
unknown committed
4358 4359
      else
        send_ok(thd);
4360
      thd->transaction.savepoints=sv->prev;
unknown's avatar
unknown committed
4361
    }
4362
    else
unknown's avatar
unknown committed
4363
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
4364
    break;
unknown's avatar
unknown committed
4365
  }
unknown's avatar
unknown committed
4366
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
unknown's avatar
unknown committed
4367
  {
4368 4369
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
4370 4371 4372
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
4373
                       (uchar *)sv->name, sv->length) == 0)
4374 4375
        break;
    }
4376
    if (sv)
4377
    {
4378
      if (ha_rollback_to_savepoint(thd, sv))
4379 4380
        res= TRUE; // cannot happen
      else
unknown's avatar
unknown committed
4381
      {
4382 4383
        if ((thd->options &
             (OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG)) &&
unknown's avatar
unknown committed
4384 4385 4386 4387 4388 4389
            !thd->slave_thread)
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_WARNING_NOT_COMPLETE_ROLLBACK,
                       ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
        send_ok(thd);
      }
4390
      thd->transaction.savepoints=sv;
unknown's avatar
unknown committed
4391 4392
    }
    else
4393
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
4394
    break;
4395
  }
4396
  case SQLCOM_SAVEPOINT:
4397 4398
    if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
          thd->in_sub_stmt) || !opt_using_transactions)
unknown's avatar
unknown committed
4399
      send_ok(thd);
unknown's avatar
unknown committed
4400
    else
4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438
    {
      SAVEPOINT **sv, *newsv;
      for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
      {
        if (my_strnncoll(system_charset_info,
                         (uchar *)lex->ident.str, lex->ident.length,
                         (uchar *)(*sv)->name, (*sv)->length) == 0)
          break;
      }
      if (*sv) /* old savepoint of the same name exists */
      {
        newsv=*sv;
        ha_release_savepoint(thd, *sv); // it cannot fail
        *sv=(*sv)->prev;
      }
      else if ((newsv=(SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
                                               savepoint_alloc_size)) == 0)
      {
        my_error(ER_OUT_OF_RESOURCES, MYF(0));
        break;
      }
      newsv->name=strmake_root(&thd->transaction.mem_root,
                               lex->ident.str, lex->ident.length);
      newsv->length=lex->ident.length;
      /*
        if we'll get an error here, don't add new savepoint to the list.
        we'll lose a little bit of memory in transaction mem_root, but it'll
        be free'd when transaction ends anyway
      */
      if (ha_savepoint(thd, newsv))
        res= TRUE;
      else
      {
        newsv->prev=thd->transaction.savepoints;
        thd->transaction.savepoints=newsv;
        send_ok(thd);
      }
    }
unknown's avatar
unknown committed
4439
    break;
4440 4441
  case SQLCOM_CREATE_PROCEDURE:
  case SQLCOM_CREATE_SPFUNCTION:
unknown's avatar
unknown committed
4442
  {
4443
    uint namelen;
unknown's avatar
unknown committed
4444
    char *name;
4445
    int result= SP_INTERNAL_ERROR;
4446

4447
    DBUG_ASSERT(lex->sphead != 0);
unknown's avatar
unknown committed
4448
    DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
4449 4450 4451 4452
    /*
      Verify that the database name is allowed, optionally
      lowercase it.
    */
4453
    if (check_db_name(&lex->sphead->m_db))
4454
    {
4455
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str);
4456
      goto create_sp_error;
4457 4458
    }

4459
    /*
4460 4461 4462
      Check that a database directory with this name
      exists. Design note: This won't work on virtual databases
      like information_schema.
4463 4464
    */
    if (check_db_dir_existence(lex->sphead->m_db.str))
4465
    {
4466
      my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
4467
      goto create_sp_error;
4468
    }
4469

4470 4471
    if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
                     is_schema_db(lex->sphead->m_db.str)))
4472
      goto create_sp_error;
4473

4474 4475
    if (end_active_trans(thd))
      goto create_sp_error;
4476 4477

    name= lex->sphead->name(&namelen);
4478
#ifdef HAVE_DLOPEN
unknown's avatar
unknown committed
4479 4480 4481
    if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
    {
      udf_func *udf = find_udf(name, namelen);
4482

unknown's avatar
unknown committed
4483
      if (udf)
4484
      {
4485 4486
        my_error(ER_UDF_EXISTS, MYF(0), name);
        goto create_sp_error;
4487
      }
unknown's avatar
unknown committed
4488 4489 4490
    }
#endif

4491 4492 4493
    /*
      If the definer is not specified, this means that CREATE-statement missed
      DEFINER-clause. DEFINER-clause can be missed in two cases:
4494

4495 4496 4497 4498 4499 4500 4501 4502
        - 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.
4503

4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527
          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 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)))
        res= TRUE;

      if (ps_arena)
        thd->restore_active_arena(ps_arena, &original_arena);

4528
      /* Error has been already reported. */
4529
      if (res)
4530
        goto create_sp_error;
4531 4532 4533 4534 4535 4536 4537 4538 4539 4540

      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).
    */
4541

4542 4543 4544 4545 4546 4547 4548 4549
    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");
4550
        goto create_sp_error;
4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568
      }
    }

    /* 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 */

unknown's avatar
unknown committed
4569
    res= (result= lex->sphead->create(thd));
4570 4571
    switch (result) {
    case SP_OK:
unknown's avatar
unknown committed
4572
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4573
      /* only add privileges if really neccessary */
4574
      if (sp_automatic_privileges && !opt_noacl &&
4575
          check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
4576
                               lex->sphead->m_db.str, name,
4577
                               lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
4578
      {
unknown's avatar
unknown committed
4579
        if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
4580
                                lex->sql_command == SQLCOM_CREATE_PROCEDURE))
4581 4582 4583
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_PROC_AUTO_GRANT_FAIL,
                       ER(ER_PROC_AUTO_GRANT_FAIL));
unknown's avatar
unknown committed
4584
        close_thread_tables(thd);
4585
      }
unknown's avatar
unknown committed
4586
#endif
unknown's avatar
unknown committed
4587
    break;
4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614
    case SP_WRITE_ROW_FAILED:
      my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name);
    break;
    case SP_BAD_IDENTIFIER:
      my_error(ER_TOO_LONG_IDENT, MYF(0), name);
    break;
    case SP_BODY_TOO_LONG:
      my_error(ER_TOO_LONG_BODY, MYF(0), name);
    break;
    default:
      my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name);
    break;
    } /* end switch */

    /*
      Capture all errors within this CASE and
      clean up the environment.
    */
create_sp_error:
    lex->unit.cleanup();
    delete lex->sphead;
    lex->sphead= 0;
    if (result != SP_OK )
      goto error;
    send_ok(thd);
    break; /* break super switch */
  } /* end case group bracket */
4615 4616 4617 4618
  case SQLCOM_CALL:
    {
      sp_head *sp;

4619 4620 4621 4622 4623 4624 4625 4626 4627
      /*
        This will cache all SP and SF and open and lock all tables
        required for execution.
      */
      if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
	  open_and_lock_tables(thd, all_tables))
       goto error;

      /*
4628 4629
        By this moment all needed SPs should be in cache so no need to look 
        into DB. 
4630
      */
4631 4632
      if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                                &thd->sp_proc_cache, TRUE)))
4633
      {
4634
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
unknown's avatar
unknown committed
4635
                 lex->spname->m_qname.str);
4636
	goto error;
4637 4638 4639
      }
      else
      {
unknown's avatar
unknown committed
4640
	ha_rows select_limit;
unknown's avatar
unknown committed
4641 4642
        /* bits that should be cleared in thd->server_status */
	uint bits_to_be_cleared= 0;
4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654
        /*
          Check that the stored procedure doesn't contain Dynamic SQL
          and doesn't return result sets: such stored procedures can't
          be called from a function or trigger.
        */
        if (thd->in_sub_stmt)
        {
          const char *where= (thd->in_sub_stmt & SUB_STMT_TRIGGER ?
                              "trigger" : "function");
          if (sp->is_not_allowed_in_function(where))
            goto error;
        }
4655

4656 4657
	my_bool nsok= thd->net.no_send_ok;
	thd->net.no_send_ok= TRUE;
4658
	if (sp->m_flags & sp_head::MULTI_RESULTS)
4659
	{
4660
	  if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
4661
	  {
4662 4663 4664 4665
            /*
              The client does not support multiple result sets being sent
              back
            */
4666
	    my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
4667 4668 4669
	    thd->net.no_send_ok= nsok;
	    goto error;
	  }
unknown's avatar
unknown committed
4670 4671 4672 4673 4674 4675 4676
          /*
            If SERVER_MORE_RESULTS_EXISTS is not set,
            then remember that it should be cleared
          */
	  bits_to_be_cleared= (~thd->server_status &
                               SERVER_MORE_RESULTS_EXISTS);
	  thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
4677 4678
	}

4679
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4680
	if (check_routine_access(thd, EXECUTE_ACL,
4681
				 sp->m_db.str, sp->m_name.str, TRUE, FALSE))
4682 4683 4684 4685
	{
	  thd->net.no_send_ok= nsok;
	  goto error;
	}
4686
#endif
unknown's avatar
unknown committed
4687 4688
	select_limit= thd->variables.select_limit;
	thd->variables.select_limit= HA_POS_ERROR;
4689

4690
        /* 
4691
          We never write CALL statements into binlog:
4692 4693 4694 4695 4696
           - If the mode is non-prelocked, each statement will be logged
             separately.
           - If the mode is prelocked, the invoking statement will care
             about writing into binlog.
          So just execute the statement.
4697
        */
4698
	res= sp->execute_procedure(thd, &lex->value_list);
4699 4700 4701
	/*
          If warnings have been cleared, we have to clear total_warn_count
          too, otherwise the clients get confused.
4702 4703 4704 4705
	 */
	if (thd->warn_list.is_empty())
	  thd->total_warn_count= 0;

unknown's avatar
unknown committed
4706
	thd->variables.select_limit= select_limit;
4707

4708
	thd->net.no_send_ok= nsok;
unknown's avatar
unknown committed
4709
        thd->server_status&= ~bits_to_be_cleared;
4710

unknown's avatar
unknown committed
4711
	if (!res)
unknown's avatar
unknown committed
4712 4713
	  send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
                                thd->row_count_func));
4714
	else
4715 4716
        {
          DBUG_ASSERT(thd->net.report_error == 1 || thd->killed);
4717
	  goto error;		// Substatement should already have sent error
4718
        }
4719
      }
4720
      break;
4721 4722
    }
  case SQLCOM_ALTER_PROCEDURE:
4723
  case SQLCOM_ALTER_FUNCTION:
4724
    {
unknown's avatar
unknown committed
4725
      int result;
4726 4727 4728 4729
      sp_head *sp;
      st_sp_chistics chistics;

      memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
unknown's avatar
unknown committed
4730
      if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
4731 4732
        sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                            &thd->sp_proc_cache, FALSE);
4733
      else
4734 4735
        sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                            &thd->sp_func_cache, FALSE);
unknown's avatar
unknown committed
4736
      mysql_reset_errors(thd, 0);
4737
      if (! sp)
4738 4739 4740 4741 4742 4743 4744 4745 4746
      {
	if (lex->spname->m_db.str)
	  result= SP_KEY_NOT_FOUND;
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
      }
4747 4748
      else
      {
4749 4750 4751
        if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str, 
				 sp->m_name.str,
                                 lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
4752
	  goto error;
4753 4754 4755

        if (end_active_trans(thd)) 
          goto error;
4756
	memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
4757 4758
        if ((sp->m_type == TYPE_ENUM_FUNCTION) &&
            !trust_function_creators &&  mysql_bin_log.is_open() &&
4759 4760 4761 4762 4763 4764 4765 4766 4767 4768
            !sp->m_chistics->detistic &&
            (chistics.daccess == SP_CONTAINS_SQL ||
             chistics.daccess == SP_MODIFIES_SQL_DATA))
        {
          my_message(ER_BINLOG_UNSAFE_ROUTINE,
		     ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0));
          result= SP_INTERNAL_ERROR;
        }
        else
        {
4769 4770 4771 4772 4773 4774
          /*
            Note that if you implement the capability of ALTER FUNCTION to
            alter the body of the function, this command should be made to
            follow the restrictions that log-bin-trust-function-creators=0
            already puts on CREATE FUNCTION.
          */
4775
          if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
4776
            /* Conditionally writes to binlog */
4777 4778
            result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
          else
4779
            /* Conditionally writes to binlog */
4780 4781
            result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
        }
4782
      }
unknown's avatar
unknown committed
4783
      switch (result)
4784
      {
unknown's avatar
unknown committed
4785
      case SP_OK:
4786
	send_ok(thd);
unknown's avatar
unknown committed
4787 4788
	break;
      case SP_KEY_NOT_FOUND:
4789 4790
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
4791 4792
	goto error;
      default:
4793 4794
	my_error(ER_SP_CANT_ALTER, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
4795
	goto error;
4796
      }
4797
      break;
4798 4799
    }
  case SQLCOM_DROP_PROCEDURE:
4800
  case SQLCOM_DROP_FUNCTION:
4801
    {
unknown's avatar
unknown committed
4802
      int result;
4803 4804
      int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
                 TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
4805

4806
      result= sp_routine_exists_in_table(thd, type, lex->spname);
unknown's avatar
unknown committed
4807
      mysql_reset_errors(thd, 0);
4808
      if (result == SP_OK)
4809
      {
4810 4811 4812
        char *db= lex->spname->m_db.str;
	char *name= lex->spname->m_name.str;

4813 4814
	if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
unknown's avatar
merge  
unknown committed
4815
          goto error;
4816 4817 4818

        if (end_active_trans(thd)) 
          goto error;
unknown's avatar
unknown committed
4819
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4820
	if (sp_automatic_privileges && !opt_noacl &&
4821 4822
	    sp_revoke_privileges(thd, db, name, 
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE))
4823 4824 4825 4826 4827
	{
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
		       ER_PROC_AUTO_REVOKE_FAIL,
		       ER(ER_PROC_AUTO_REVOKE_FAIL));
	}
unknown's avatar
unknown committed
4828
#endif
4829
	if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
4830 4831
          /* Conditionally writes to binlog */
	  result= sp_drop_procedure(thd, lex->spname); /* Conditionally writes to binlog */
4832
	else
4833 4834
          /* Conditionally writes to binlog */
	  result= sp_drop_function(thd, lex->spname); /* Conditionally writes to binlog */
4835 4836 4837
      }
      else
      {
4838
#ifdef HAVE_DLOPEN
4839 4840 4841 4842 4843 4844
	if (lex->sql_command == SQLCOM_DROP_FUNCTION)
	{
          udf_func *udf = find_udf(lex->spname->m_name.str,
                                   lex->spname->m_name.length);
          if (udf)
          {
4845
	    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
4846
	      goto error;
4847 4848

	    /* Does NOT write to binlog */
4849
	    if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
4850
	    {
4851 4852
	      send_ok(thd);
	      break;
4853 4854
	    }
	  }
4855
	}
4856
#endif
4857 4858 4859 4860 4861 4862 4863
	if (lex->spname->m_db.str)
	  result= SP_KEY_NOT_FOUND;
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
4864
      }
unknown's avatar
unknown committed
4865 4866
      res= result;
      switch (result)
4867 4868
      {
      case SP_OK:
4869
	send_ok(thd);
4870 4871
	break;
      case SP_KEY_NOT_FOUND:
4872 4873
	if (lex->drop_if_exists)
	{
4874
	  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
4875
			      ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
4876
			      SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4877
	  res= FALSE;
4878 4879 4880
	  send_ok(thd);
	  break;
	}
4881 4882
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4883 4884
	goto error;
      default:
4885 4886
	my_error(ER_SP_DROP_FAILED, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4887
	goto error;
4888
      }
4889
      break;
4890
    }
unknown's avatar
unknown committed
4891 4892
  case SQLCOM_SHOW_CREATE_PROC:
    {
4893
      if (lex->spname->m_name.length > NAME_LEN)
unknown's avatar
unknown committed
4894
      {
4895
	my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
unknown's avatar
unknown committed
4896 4897
	goto error;
      }
unknown's avatar
unknown committed
4898
      if (sp_show_create_procedure(thd, lex->spname) != SP_OK)
4899
      {			/* We don't distinguish between errors for now */
4900 4901
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4902 4903 4904 4905 4906 4907
	goto error;
      }
      break;
    }
  case SQLCOM_SHOW_CREATE_FUNC:
    {
4908
      if (lex->spname->m_name.length > NAME_LEN)
unknown's avatar
unknown committed
4909
      {
4910
	my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
unknown's avatar
unknown committed
4911 4912
	goto error;
      }
unknown's avatar
unknown committed
4913
      if (sp_show_create_function(thd, lex->spname) != SP_OK)
4914
      {			/* We don't distinguish between errors for now */
4915 4916
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4917 4918 4919 4920
	goto error;
      }
      break;
    }
4921
#ifdef NOT_USED
unknown's avatar
unknown committed
4922 4923
  case SQLCOM_SHOW_STATUS_PROC:
    {
4924
      res= sp_show_status_procedure(thd, (lex->wild ?
unknown's avatar
unknown committed
4925 4926 4927 4928 4929
					  lex->wild->ptr() : NullS));
      break;
    }
  case SQLCOM_SHOW_STATUS_FUNC:
    {
4930
      res= sp_show_status_function(thd, (lex->wild ? 
unknown's avatar
unknown committed
4931 4932 4933
					 lex->wild->ptr() : NullS));
      break;
    }
4934
#endif
unknown's avatar
unknown committed
4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946
#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)
unknown's avatar
unknown committed
4947 4948
        sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                            &thd->sp_proc_cache, FALSE);
unknown's avatar
unknown committed
4949
      else
unknown's avatar
unknown committed
4950 4951
        sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                            &thd->sp_func_cache, FALSE);
4952
      if (!sp || sp->show_routine_code(thd))
4953 4954
      {
        /* We don't distinguish between errors for now */
unknown's avatar
unknown committed
4955 4956 4957 4958 4959 4960 4961
        my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
        goto error;
      }
      break;
    }
#endif // ifndef DBUG_OFF
unknown's avatar
VIEW  
unknown committed
4962 4963
  case SQLCOM_CREATE_VIEW:
    {
4964 4965 4966
      if (end_active_trans(thd))
        goto error;

4967
      res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
unknown's avatar
VIEW  
unknown committed
4968 4969 4970 4971
      break;
    }
  case SQLCOM_DROP_VIEW:
    {
unknown's avatar
unknown committed
4972 4973 4974
      if (check_table_access(thd, DROP_ACL, all_tables, 0) ||
          end_active_trans(thd))
        goto error;
4975 4976
      /* Conditionally writes to binlog. */
      res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
unknown's avatar
VIEW  
unknown committed
4977 4978
      break;
    }
4979 4980
  case SQLCOM_CREATE_TRIGGER:
  {
4981 4982 4983
    if (end_active_trans(thd))
      goto error;

4984
    /* Conditionally writes to binlog. */
4985 4986 4987
    res= mysql_create_or_drop_trigger(thd, all_tables, 1);

    /* We don't care about trigger body after this point */
4988 4989 4990 4991 4992 4993
    delete lex->sphead;
    lex->sphead= 0;
    break;
  }
  case SQLCOM_DROP_TRIGGER:
  {
4994 4995 4996
    if (end_active_trans(thd))
      goto error;

4997
    /* Conditionally writes to binlog. */
4998 4999 5000
    res= mysql_create_or_drop_trigger(thd, all_tables, 0);
    break;
  }
5001
  case SQLCOM_XA_START:
5002 5003
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
        thd->lex->xa_opt == XA_RESUME)
5004
    {
5005
      if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
5006 5007 5008 5009
      {
        my_error(ER_XAER_NOTA, MYF(0));
        break;
      }
5010
      thd->transaction.xid_state.xa_state=XA_ACTIVE;
5011 5012 5013
      send_ok(thd);
      break;
    }
unknown's avatar
unknown committed
5014
    if (thd->lex->xa_opt != XA_NONE)
5015 5016 5017 5018
    { // JOIN is not supported yet. TODO
      my_error(ER_XAER_INVAL, MYF(0));
      break;
    }
5019
    if (thd->transaction.xid_state.xa_state != XA_NOTR)
5020
    {
unknown's avatar
unknown committed
5021
      my_error(ER_XAER_RMFAIL, MYF(0),
5022
               xa_state_names[thd->transaction.xid_state.xa_state]);
5023 5024 5025 5026 5027 5028 5029
      break;
    }
    if (thd->active_transaction() || thd->locked_tables)
    {
      my_error(ER_XAER_OUTSIDE, MYF(0));
      break;
    }
5030 5031 5032 5033 5034 5035 5036 5037 5038
    if (xid_cache_search(thd->lex->xid))
    {
      my_error(ER_XAER_DUPID, MYF(0));
      break;
    }
    DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
    thd->transaction.xid_state.xa_state=XA_ACTIVE;
    thd->transaction.xid_state.xid.set(thd->lex->xid);
    xid_cache_insert(&thd->transaction.xid_state);
5039 5040
    thd->options= ((thd->options & ~(OPTION_STATUS_NO_TRANS_UPDATE |
                                     OPTION_KEEP_LOG)) |
5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051
                   OPTION_BEGIN);
    thd->server_status|= SERVER_STATUS_IN_TRANS;
    send_ok(thd);
    break;
  case SQLCOM_XA_END:
    /* fake it */
    if (thd->lex->xa_opt != XA_NONE)
    { // SUSPEND and FOR MIGRATE are not supported yet. TODO
      my_error(ER_XAER_INVAL, MYF(0));
      break;
    }
5052
    if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
5053
    {
unknown's avatar
unknown committed
5054
      my_error(ER_XAER_RMFAIL, MYF(0),
5055
               xa_state_names[thd->transaction.xid_state.xa_state]);
5056 5057
      break;
    }
5058
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
5059 5060 5061 5062
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
5063
    thd->transaction.xid_state.xa_state=XA_IDLE;
5064 5065 5066
    send_ok(thd);
    break;
  case SQLCOM_XA_PREPARE:
5067
    if (thd->transaction.xid_state.xa_state != XA_IDLE)
5068
    {
unknown's avatar
unknown committed
5069
      my_error(ER_XAER_RMFAIL, MYF(0),
5070
               xa_state_names[thd->transaction.xid_state.xa_state]);
5071 5072
      break;
    }
5073
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
5074 5075 5076 5077 5078 5079 5080
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
    if (ha_prepare(thd))
    {
      my_error(ER_XA_RBROLLBACK, MYF(0));
5081 5082
      xid_cache_delete(&thd->transaction.xid_state);
      thd->transaction.xid_state.xa_state=XA_NOTR;
5083 5084
      break;
    }
5085
    thd->transaction.xid_state.xa_state=XA_PREPARED;
5086 5087 5088
    send_ok(thd);
    break;
  case SQLCOM_XA_COMMIT:
5089
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
5090
    {
5091 5092
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
5093
        my_error(ER_XAER_NOTA, MYF(0));
unknown's avatar
unknown committed
5094
      else
5095 5096 5097
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
        xid_cache_delete(xs);
unknown's avatar
unknown committed
5098
        send_ok(thd);
5099
      }
5100 5101
      break;
    }
5102
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
unknown's avatar
unknown committed
5103
        thd->lex->xa_opt == XA_ONE_PHASE)
5104
    {
unknown's avatar
unknown committed
5105 5106 5107
      int r;
      if ((r= ha_commit(thd)))
        my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
5108 5109 5110
      else
        send_ok(thd);
    }
5111
    else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
unknown's avatar
unknown committed
5112
             thd->lex->xa_opt == XA_NONE)
5113
    {
5114 5115 5116
      if (wait_if_global_read_lock(thd, 0, 0))
      {
        ha_rollback(thd);
5117
        my_error(ER_XAER_RMERR, MYF(0));
5118
      }
5119
      else
5120 5121 5122 5123 5124 5125 5126
      {
        if (ha_commit_one_phase(thd, 1))
          my_error(ER_XAER_RMERR, MYF(0));
        else
          send_ok(thd);
        start_waiting_global_read_lock(thd);
      }
5127 5128 5129
    }
    else
    {
unknown's avatar
unknown committed
5130
      my_error(ER_XAER_RMFAIL, MYF(0),
5131
               xa_state_names[thd->transaction.xid_state.xa_state]);
5132 5133
      break;
    }
5134 5135
    thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
                     OPTION_KEEP_LOG);
5136
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
5137 5138
    xid_cache_delete(&thd->transaction.xid_state);
    thd->transaction.xid_state.xa_state=XA_NOTR;
5139 5140
    break;
  case SQLCOM_XA_ROLLBACK:
5141
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
5142
    {
5143 5144
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
5145
        my_error(ER_XAER_NOTA, MYF(0));
unknown's avatar
unknown committed
5146
      else
5147 5148 5149
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
        xid_cache_delete(xs);
unknown's avatar
unknown committed
5150
        send_ok(thd);
5151
      }
5152 5153
      break;
    }
5154 5155
    if (thd->transaction.xid_state.xa_state != XA_IDLE &&
        thd->transaction.xid_state.xa_state != XA_PREPARED)
5156
    {
unknown's avatar
unknown committed
5157
      my_error(ER_XAER_RMFAIL, MYF(0),
5158
               xa_state_names[thd->transaction.xid_state.xa_state]);
5159 5160 5161 5162 5163 5164
      break;
    }
    if (ha_rollback(thd))
      my_error(ER_XAER_RMERR, MYF(0));
    else
      send_ok(thd);
5165 5166
    thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
                     OPTION_KEEP_LOG);
5167
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
5168 5169
    xid_cache_delete(&thd->transaction.xid_state);
    thd->transaction.xid_state.xa_state=XA_NOTR;
5170 5171
    break;
  case SQLCOM_XA_RECOVER:
5172
    res= mysql_xa_recover(thd);
5173
    break;
unknown's avatar
unknown committed
5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197
  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;
  }
5198
  default:
5199
#ifndef EMBEDDED_LIBRARY
5200
    DBUG_ASSERT(0);                             /* Impossible */
5201
#endif
5202
    send_ok(thd);
unknown's avatar
unknown committed
5203 5204
    break;
  }
unknown's avatar
unknown committed
5205

unknown's avatar
unknown committed
5206
  thd->proc_info="query end";
5207 5208

  /*
unknown's avatar
unknown committed
5209
    Binlog-related cleanup:
5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220
    Reset system variables temporarily modified by SET ONE SHOT.

    Exception: If this is a SET, do nothing. This is to allow
    mysqlbinlog to print many SET commands (in this case we want the
    charset temp setting to live until the real query). This is also
    needed so that SET CHARACTER_SET_CLIENT... does not cancel itself
    immediately.
  */
  if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION)
    reset_one_shot_variables(thd);

5221
  /*
5222 5223
    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
5224 5225 5226 5227
    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))
5228
    thd->row_count_func= -1;
5229

5230
  goto finish;
unknown's avatar
unknown committed
5231 5232

error:
5233 5234
  res= TRUE;

5235
finish:
5236 5237 5238 5239 5240 5241 5242 5243 5244
  if (need_start_waiting)
  {
    /*
      Release the protection against the global read lock and wake
      everyone, who might want to set a global read lock.
    */
    start_waiting_global_read_lock(thd);
  }
  DBUG_RETURN(res || thd->net.report_error);
unknown's avatar
unknown committed
5245 5246 5247
}


5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270
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()))
5271
        return 1;                               /* purecov: inspected */
5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289
      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()))
5290
        return 1;                               /* purecov: inspected */
5291 5292 5293 5294 5295 5296 5297 5298 5299 5300
      query_cache_store_query(thd, all_tables);
      res= handle_select(thd, lex, result, 0);
      if (result != lex->result)
        delete result;
    }
  }
  return res;
}


unknown's avatar
unknown committed
5301
/*
5302
  Check grants for commands which work only with one table.
unknown's avatar
unknown committed
5303

5304
  SYNOPSIS
5305
    check_single_table_access()
unknown's avatar
unknown committed
5306
    thd			Thread handler
5307
    privilege		requested privilege
unknown's avatar
VIEW  
unknown committed
5308
    all_tables		global table list of query
unknown's avatar
unknown committed
5309 5310 5311

  RETURN
    0 - OK
unknown's avatar
unknown committed
5312
    1 - access denied, error is sent to client
unknown's avatar
unknown committed
5313 5314
*/

5315 5316
bool check_single_table_access(THD *thd, ulong privilege, 
                               TABLE_LIST *all_tables)
unknown's avatar
unknown committed
5317
{
5318 5319 5320 5321 5322 5323
  Security_context * backup_ctx= thd->security_ctx;

  /* we need to switch to the saved context (if any) */
  if (all_tables->security_ctx)
    thd->security_ctx= all_tables->security_ctx;

5324 5325 5326 5327 5328 5329 5330 5331
  const char *db_name;
  if ((all_tables->view || all_tables->field_translation) &&
      !all_tables->schema_table)
    db_name= all_tables->view_db.str;
  else
    db_name= all_tables->db;

  if (check_access(thd, privilege, db_name,
5332 5333
		   &all_tables->grant.privilege, 0, 0,
                   test(all_tables->schema_table)))
5334
    goto deny;
unknown's avatar
unknown committed
5335

unknown's avatar
unknown committed
5336
  /* Show only 1 table for check_grant */
unknown's avatar
VIEW  
unknown committed
5337
  if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0))
5338 5339 5340
    goto deny;

  thd->security_ctx= backup_ctx;
5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366
  return 0;

deny:
  thd->security_ctx= backup_ctx;
  return 1;
}

/*
  Check grants for commands which work only with one table and all other
  tables belonging to subselects or implicitly opened tables.

  SYNOPSIS
    check_one_table_access()
    thd			Thread handler
    privilege		requested privilege
    all_tables		global table list of query

  RETURN
    0 - OK
    1 - access denied, error is sent to client
*/

bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
{
  if (check_single_table_access (thd,privilege,all_tables))
    return 1;
unknown's avatar
unknown committed
5367

5368
  /* Check rights on tables of subselects and implictly opened tables */
unknown's avatar
unknown committed
5369
  TABLE_LIST *subselects_tables, *view= all_tables->view ? all_tables : 0;
unknown's avatar
VIEW  
unknown committed
5370
  if ((subselects_tables= all_tables->next_global))
unknown's avatar
unknown committed
5371
  {
unknown's avatar
unknown committed
5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383
    /*
      Access rights asked for the first table of a view should be the same
      as for the view
    */
    if (view && subselects_tables->belong_to_view == view)
    {
      if (check_single_table_access (thd, privilege, subselects_tables))
        return 1;
      subselects_tables= subselects_tables->next_global;
    }
    if (subselects_tables &&
        (check_table_access(thd, SELECT_ACL, subselects_tables, 0)))
5384
      return 1;
unknown's avatar
unknown committed
5385 5386
  }
  return 0;
unknown's avatar
unknown committed
5387 5388 5389
}


unknown's avatar
unknown committed
5390
/****************************************************************************
unknown's avatar
unknown committed
5391
  Get the user (global) and database privileges for all used tables
unknown's avatar
unknown committed
5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404

  NOTES
    The idea of EXTRA_ACL is that one will be granted access to the table if
    one has the asked privilege on any column combination of the table; For
    example to be able to check a table one needs to have SELECT privilege on
    any column of the table.

  RETURN
    0  ok
    1  If we can't get the privileges and we don't use table/column grants.

    save_priv	In this we store global and db level grants for the table
		Note that we don't store db level grants if the global grants
unknown's avatar
unknown committed
5405 5406
                is enough to satisfy the request and the global grants contains
                a SELECT grant.
unknown's avatar
unknown committed
5407 5408 5409
****************************************************************************/

bool
unknown's avatar
unknown committed
5410
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
5411
	     bool dont_check_global_grants, bool no_errors, bool schema_db)
unknown's avatar
unknown committed
5412
{
5413
  Security_context *sctx= thd->security_ctx;
unknown's avatar
unknown committed
5414 5415
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  ulong db_access;
unknown's avatar
unknown committed
5416
  bool  db_is_pattern= test(want_access & GRANT_ACL);
unknown's avatar
unknown committed
5417 5418
#endif
  ulong dummy;
5419 5420
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("db: %s  want_access: %lu  master_access: %lu",
5421
                      db ? db : "", want_access, sctx->master_access));
unknown's avatar
unknown committed
5422 5423 5424 5425 5426
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

5427
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
5428
  {
5429
    DBUG_PRINT("error",("No database"));
5430
    if (!no_errors)
unknown's avatar
unknown committed
5431 5432
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
                 MYF(0));                       /* purecov: tested */
unknown's avatar
unknown committed
5433
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
5434 5435
  }

5436 5437 5438 5439 5440
  if (schema_db)
  {
    if (want_access & ~(SELECT_ACL | EXTRA_ACL))
    {
      if (!no_errors)
5441 5442
      {
        const char *db_name= db ? db : thd->db;
5443
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
5444 5445
                 sctx->priv_user, sctx->priv_host, db_name);
      }
5446 5447 5448 5449 5450 5451 5452 5453 5454
      DBUG_RETURN(TRUE);
    }
    else
    {
      *save_priv= SELECT_ACL;
      DBUG_RETURN(FALSE);
    }
  }

unknown's avatar
unknown committed
5455 5456 5457
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  DBUG_RETURN(0);
#else
5458
  if ((sctx->master_access & want_access) == want_access)
unknown's avatar
unknown committed
5459
  {
5460 5461 5462 5463 5464
    /*
      If we don't have a global SELECT privilege, we have to get the database
      specific access rights to be able to handle queries of type
      UPDATE t1 SET a=1 WHERE b > 0
    */
5465 5466
    db_access= sctx->db_access;
    if (!(sctx->master_access & SELECT_ACL) &&
unknown's avatar
unknown committed
5467
	(db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
5468 5469 5470
      db_access=acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
                        db_is_pattern);
    *save_priv=sctx->master_access | db_access;
unknown's avatar
unknown committed
5471
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
5472
  }
5473
  if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
5474
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
5475
  {						// We can never grant this
5476
    DBUG_PRINT("error",("No possible access"));
5477
    if (!no_errors)
5478
      my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
5479 5480
               sctx->priv_user,
               sctx->priv_host,
5481 5482 5483
               (thd->password ?
                ER(ER_YES) :
                ER(ER_NO)));                    /* purecov: tested */
unknown's avatar
unknown committed
5484
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
5485 5486 5487
  }

  if (db == any_db)
unknown's avatar
unknown committed
5488
    DBUG_RETURN(FALSE);				// Allow select on anything
unknown's avatar
unknown committed
5489

unknown's avatar
unknown committed
5490
  if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
5491 5492
    db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
                       db_is_pattern);
unknown's avatar
unknown committed
5493
  else
5494
    db_access= sctx->db_access;
5495
  DBUG_PRINT("info",("db_access: %lu", db_access));
unknown's avatar
unknown committed
5496
  /* Remove SHOW attribute and access rights we already have */
5497
  want_access &= ~(sctx->master_access | EXTRA_ACL);
5498 5499
  DBUG_PRINT("info",("db_access: %lu  want_access: %lu",
                     db_access, want_access));
5500
  db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
5501 5502

  /* grant_option is set if there exists a single table or column grant */
unknown's avatar
unknown committed
5503
  if (db_access == want_access ||
5504
      (grant_option && !dont_check_global_grants &&
5505
       !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
unknown's avatar
unknown committed
5506
    DBUG_RETURN(FALSE);				/* Ok */
5507 5508

  DBUG_PRINT("error",("Access denied"));
5509
  if (!no_errors)
5510
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
5511
             sctx->priv_user, sctx->priv_host,
5512 5513 5514
             (db ? db : (thd->db ?
                         thd->db :
                         "unknown")));          /* purecov: tested */
unknown's avatar
unknown committed
5515
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
5516
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
5517 5518 5519
}


5520 5521 5522 5523 5524 5525 5526 5527 5528
/*
  check for global access and give descriptive error message if it fails

  SYNOPSIS
    check_global_access()
    thd			Thread handler
    want_access		Use should have any of these global rights

  WARNING
5529
    One gets access right if one has ANY of the rights in want_access
5530 5531 5532 5533 5534 5535 5536 5537
    This is useful as one in most cases only need one global right,
    but in some case we want to check if the user has SUPER or
    REPL_CLIENT_ACL rights.

  RETURN
    0	ok
    1	Access denied.  In this case an error is sent to the client
*/
unknown's avatar
unknown committed
5538 5539

bool check_global_access(THD *thd, ulong want_access)
unknown's avatar
unknown committed
5540
{
unknown's avatar
unknown committed
5541 5542 5543
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  return 0;
#else
unknown's avatar
unknown committed
5544
  char command[128];
5545
  if ((thd->security_ctx->master_access & want_access))
unknown's avatar
unknown committed
5546 5547
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
5548
  my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
unknown's avatar
unknown committed
5549
  return 1;
unknown's avatar
unknown committed
5550
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
5551 5552 5553
}


unknown's avatar
unknown committed
5554
/*
5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574
  Check the privilege for all used tables.

  SYNOPSYS
    check_table_access()
      thd          Thread context
      want_access  Privileges requested
      tables       List of tables to be checked
      no_errors    FALSE/TRUE - report/don't report error to
                   the client (using my_error() call).

  NOTES
    Table privileges are cached in the table list for GRANT checking.
    This functions assumes that table list used and
    thd->lex->query_tables_own_last value correspond to each other
    (the latter should be either 0 or point to next_global member
    of one of elements of this table list).

  RETURN VALUE
    FALSE - OK
    TRUE  - Access denied
unknown's avatar
unknown committed
5575 5576
*/

5577
bool
unknown's avatar
unknown committed
5578
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
5579
		   bool no_errors)
unknown's avatar
unknown committed
5580
{
unknown's avatar
unknown committed
5581 5582
  uint found=0;
  ulong found_access=0;
5583 5584
  TABLE_LIST *org_tables= tables;
  TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
5585
  Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx;
5586
  /*
unknown's avatar
unknown committed
5587 5588 5589
    The check that first_not_own_table is not reached is for the case when
    the given table list refers to the list for prelocking (contains tables
    of other queries). For simple queries first_not_own_table is 0.
5590
  */
unknown's avatar
unknown committed
5591
  for (; tables != first_not_own_table; tables= tables->next_global)
unknown's avatar
unknown committed
5592
  {
5593 5594 5595 5596 5597
    if (tables->security_ctx)
      sctx= tables->security_ctx;
    else
      sctx= backup_ctx;

5598
    if (tables->schema_table && 
5599
        (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
5600 5601 5602
    {
      if (!no_errors)
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
5603
                 sctx->priv_user, sctx->priv_host,
5604 5605 5606
                 information_schema_name.str);
      return TRUE;
    }
5607 5608 5609 5610 5611
    /*
       Register access for view underlying table.
       Remove SHOW_VIEW_ACL, because it will be checked during making view
     */
    tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
5612
    if (tables->derived || tables->schema_table ||
5613
        (tables->table && (int)tables->table->s->tmp_table) ||
5614 5615
        my_tz_check_n_skip_implicit_tables(&tables,
                                           thd->lex->time_zone_tables_used))
unknown's avatar
unknown committed
5616
      continue;
5617 5618
    thd->security_ctx= sctx;
    if ((sctx->master_access & want_access) ==
5619
        (want_access & ~EXTRA_ACL) &&
unknown's avatar
unknown committed
5620
	thd->db)
unknown's avatar
unknown committed
5621
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
5622
    else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
unknown's avatar
unknown committed
5623 5624 5625 5626 5627
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
5628
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
5629
			 0, no_errors, test(tables->schema_table)))
5630
	  goto deny;                            // Access denied
unknown's avatar
unknown committed
5631
	found_access=tables->grant.privilege;
unknown's avatar
unknown committed
5632
	found=1;
unknown's avatar
unknown committed
5633 5634
      }
    }
5635
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
5636
			  0, no_errors, test(tables->schema_table)))
5637
      goto deny;
unknown's avatar
unknown committed
5638
  }
5639
  thd->security_ctx= backup_ctx;
unknown's avatar
unknown committed
5640
  if (grant_option)
5641
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
unknown's avatar
unknown committed
5642
		       test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
unknown's avatar
unknown committed
5643
  return FALSE;
5644 5645 5646
deny:
  thd->security_ctx= backup_ctx;
  return TRUE;
unknown's avatar
unknown committed
5647 5648
}

5649

5650
bool
5651 5652
check_routine_access(THD *thd, ulong want_access,char *db, char *name,
		     bool is_proc, bool no_errors)
5653 5654 5655 5656 5657
{
  TABLE_LIST tables[1];
  
  bzero((char *)tables, sizeof(TABLE_LIST));
  tables->db= db;
5658
  tables->table_name= tables->alias= name;
5659
  
unknown's avatar
unknown committed
5660 5661 5662 5663 5664 5665 5666
  /*
    The following test is just a shortcut for check_access() (to avoid
    calculating db_access) under the assumption that it's common to
    give persons global right to execute all stored SP (but not
    necessary to create them).
  */
  if ((thd->security_ctx->master_access & want_access) == want_access)
5667 5668
    tables->grant.privilege= want_access;
  else if (check_access(thd,want_access,db,&tables->grant.privilege,
unknown's avatar
unknown committed
5669
			0, no_errors, 0))
5670 5671
    return TRUE;
  
unknown's avatar
unknown committed
5672
#ifndef NO_EMBEDDED_ACCESS_CHECKS
5673
  if (grant_option)
5674
    return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
unknown's avatar
unknown committed
5675
#endif
5676 5677 5678 5679

  return FALSE;
}

5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694

/*
  Check if the routine has any of the routine privileges

  SYNOPSIS
    check_some_routine_access()
    thd		 Thread handler
    db           Database name
    name         Routine name

  RETURN
    0            ok
    1            error
*/

5695 5696
bool check_some_routine_access(THD *thd, const char *db, const char *name,
                               bool is_proc)
5697 5698
{
  ulong save_priv;
5699
  if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
5700
    return FALSE;
5701 5702 5703 5704 5705
  /*
    There are no routines in information_schema db. So we can safely
    pass zero to last paramter of check_access function
  */
  if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1, 0) ||
5706 5707
      (save_priv & SHOW_PROC_ACLS))
    return FALSE;
5708
  return check_routine_level_acl(thd, db, name, is_proc);
5709 5710 5711
}


5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736
/*
  Check if the given table has any of the asked privileges

  SYNOPSIS
    check_some_access()
    thd		 Thread handler
    want_access	 Bitmap of possible privileges to check for

  RETURN
    0  ok
    1  error
*/


bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
{
  ulong access;
  DBUG_ENTER("check_some_access");

  /* This loop will work as long as we have less than 32 privileges */
  for (access= 1; access < want_access ; access<<= 1)
  {
    if (access & want_access)
    {
      if (!check_access(thd, access, table->db,
5737 5738
                        &table->grant.privilege, 0, 1,
                        test(table->schema_table)) &&
5739 5740 5741 5742 5743 5744 5745 5746 5747
          !grant_option || !check_grant(thd, access, table, 0, 1, 1))
        DBUG_RETURN(0);
    }
  }
  DBUG_PRINT("exit",("no matching access rights"));
  DBUG_RETURN(1);
}


5748 5749
bool check_merge_table_access(THD *thd, char *db,
			      TABLE_LIST *table_list)
5750 5751 5752 5753
{
  int error=0;
  if (table_list)
  {
5754
    /* Check that all tables use the current database */
5755
    TABLE_LIST *tmp;
unknown's avatar
VIEW  
unknown committed
5756
    for (tmp= table_list; tmp; tmp= tmp->next_local)
5757 5758 5759 5760
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
    }
5761
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
unknown's avatar
unknown committed
5762
			     table_list,0);
5763 5764 5765 5766
  }
  return error;
}

unknown's avatar
unknown committed
5767

unknown's avatar
unknown committed
5768 5769 5770 5771 5772 5773 5774 5775 5776 5777
/****************************************************************************
	Check stack size; Send error if there isn't enough stack to continue
****************************************************************************/

#if STACK_DIRECTION < 0
#define used_stack(A,B) (long) (A - B)
#else
#define used_stack(A,B) (long) (B - A)
#endif

unknown's avatar
unknown committed
5778 5779 5780 5781
#ifndef DBUG_OFF
long max_stack_used;
#endif

5782
#ifndef EMBEDDED_LIBRARY
5783 5784 5785 5786 5787 5788 5789 5790
/*
  Note: The 'buf' parameter is necessary, even if it is unused here.
  - fix_fields functions has a "dummy" buffer large enough for the
    corresponding exec. (Thus we only have to check in fix_fields.)
  - Passing to check_stack_overrun() prevents the compiler from removing it.
 */
bool check_stack_overrun(THD *thd, long margin,
			 char *buf __attribute__((unused)))
unknown's avatar
unknown committed
5791 5792
{
  long stack_used;
5793
  DBUG_ASSERT(thd == current_thd);
unknown's avatar
unknown committed
5794
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
unknown's avatar
unknown committed
5795
      (long) (thread_stack - margin))
unknown's avatar
unknown committed
5796
  {
5797 5798 5799
    sprintf(errbuff[0],ER(ER_STACK_OVERRUN_NEED_MORE),
            stack_used,thread_stack,margin);
    my_message(ER_STACK_OVERRUN_NEED_MORE,errbuff[0],MYF(0));
5800
    thd->fatal_error();
unknown's avatar
unknown committed
5801 5802
    return 1;
  }
unknown's avatar
unknown committed
5803 5804 5805
#ifndef DBUG_OFF
  max_stack_used= max(max_stack_used, stack_used);
#endif
unknown's avatar
unknown committed
5806 5807
  return 0;
}
5808
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
5809 5810 5811 5812

#define MY_YACC_INIT 1000			// Start with big alloc
#define MY_YACC_MAX  32000			// Because of 'short'

5813
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
unknown's avatar
unknown committed
5814
{
5815
  LEX	*lex= current_thd->lex;
5816
  ulong old_info=0;
unknown's avatar
unknown committed
5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842
  if ((uint) *yystacksize >= MY_YACC_MAX)
    return 1;
  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,
		   *yystacksize*sizeof(**yyvs),
		   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
      !(lex->yacc_yyss= (char*)
	my_realloc((gptr) 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));
  }
  *yyss=(short*) lex->yacc_yyss;
  *yyvs=(YYSTYPE*) lex->yacc_yyvs;
  return 0;
}


/****************************************************************************
5843
  Initialize global thd variables needed for query
unknown's avatar
unknown committed
5844 5845
****************************************************************************/

5846
void
unknown's avatar
unknown committed
5847
mysql_init_query(THD *thd, uchar *buf, uint length)
unknown's avatar
unknown committed
5848 5849
{
  DBUG_ENTER("mysql_init_query");
unknown's avatar
unknown committed
5850
  lex_start(thd, buf, length);
5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861
  mysql_reset_thd_for_next_command(thd);
  DBUG_VOID_RETURN;
}


/*
 Reset THD part responsible for command processing state.

 DESCRIPTION
   This needs to be called before execution of every statement
   (prepared or conventional).
5862
   It is not called by substatements of routines.
5863 5864 5865 5866 5867 5868 5869 5870 5871 5872

 TODO
   Make it a method of THD and align its name with the rest of
   reset/end/start/init methods.
   Call it after we use THD for queries, not before.
*/

void mysql_reset_thd_for_next_command(THD *thd)
{
  DBUG_ENTER("mysql_reset_thd_for_next_command");
5873
  DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
5874
  thd->free_list= 0;
5875
  thd->select_number= 1;
5876 5877 5878 5879
  /*
    Those two lines below are theoretically unneeded as
    THD::cleanup_after_query() should take care of this already.
  */
5880
  thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty();
5881 5882 5883
  thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;

  thd->query_start_used= 0;
5884
  thd->is_fatal_error= thd->time_zone_used= 0;
unknown's avatar
unknown committed
5885
  thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | 
unknown's avatar
unknown committed
5886 5887
                          SERVER_QUERY_NO_INDEX_USED |
                          SERVER_QUERY_NO_GOOD_INDEX_USED);
5888 5889 5890 5891 5892 5893 5894 5895
  /*
    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_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG);

5896
  DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
unknown's avatar
unknown committed
5897
  thd->tmp_table_used= 0;
5898 5899
  if (!thd->in_sub_stmt)
  {
5900
    if (opt_bin_log)
5901
    {
5902
      reset_dynamic(&thd->user_var_events);
5903 5904
      thd->user_var_events_alloc= thd->mem_root;
    }
5905
    thd->clear_error();
5906 5907 5908 5909
    thd->total_warn_count=0;			// Warnings for this query
    thd->rand_used= 0;
    thd->sent_row_count= thd->examined_row_count= 0;
  }
5910 5911 5912 5913
  /*
    Because we come here only for start of top-statements, binlog format is
    constant inside a complex statement (using stored functions) etc.
  */
unknown's avatar
unknown committed
5914 5915
  thd->reset_current_stmt_binlog_row_based();

unknown's avatar
unknown committed
5916 5917 5918
  DBUG_VOID_RETURN;
}

5919

5920 5921 5922
void
mysql_init_select(LEX *lex)
{
unknown's avatar
unknown committed
5923
  SELECT_LEX *select_lex= lex->current_select;
unknown's avatar
unknown committed
5924
  select_lex->init_select();
5925
  lex->wild= 0;
5926 5927
  if (select_lex == &lex->select_lex)
  {
5928
    DBUG_ASSERT(lex->result == 0);
5929 5930
    lex->exchange= 0;
  }
5931 5932
}

5933

unknown's avatar
unknown committed
5934
bool
unknown's avatar
unknown committed
5935
mysql_new_select(LEX *lex, bool move_down)
5936
{
unknown's avatar
unknown committed
5937
  SELECT_LEX *select_lex;
5938
  THD *thd= lex->thd;
unknown's avatar
unknown committed
5939 5940
  DBUG_ENTER("mysql_new_select");

5941
  if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
5942
    DBUG_RETURN(1);
5943
  select_lex->select_number= ++thd->select_number;
unknown's avatar
unknown committed
5944
  select_lex->parent_lex= lex; /* Used in init_query. */
unknown's avatar
unknown committed
5945 5946
  select_lex->init_query();
  select_lex->init_select();
unknown's avatar
unknown committed
5947 5948
  lex->nest_level++;
  select_lex->nest_level= lex->nest_level;
5949 5950 5951 5952 5953
  /*
    Don't evaluate this subquery during statement prepare even if
    it's a constant one. The flag is switched off in the end of
    mysql_stmt_prepare.
  */
unknown's avatar
unknown committed
5954
  if (thd->stmt_arena->is_stmt_prepare())
5955
    select_lex->uncacheable|= UNCACHEABLE_PREPARE;
unknown's avatar
unknown committed
5956 5957
  if (move_down)
  {
unknown's avatar
unknown committed
5958
    SELECT_LEX_UNIT *unit;
5959
    lex->subqueries= TRUE;
unknown's avatar
unknown committed
5960
    /* first select_lex of subselect or derived table */
5961
    if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
unknown's avatar
unknown committed
5962
      DBUG_RETURN(1);
unknown's avatar
unknown committed
5963

unknown's avatar
unknown committed
5964 5965
    unit->init_query();
    unit->init_select();
5966
    unit->thd= thd;
unknown's avatar
unknown committed
5967
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
5968 5969
    unit->link_next= 0;
    unit->link_prev= 0;
5970
    unit->return_to= lex->current_select;
unknown's avatar
unknown committed
5971
    select_lex->include_down(unit);
5972 5973 5974 5975 5976
    /*
      By default we assume that it is usual subselect and we have outer name
      resolution context, if no we will assign it to 0 later
    */
    select_lex->context.outer_context= &select_lex->outer_select()->context;
unknown's avatar
unknown committed
5977 5978
  }
  else
unknown's avatar
unknown committed
5979
  {
unknown's avatar
VIEW  
unknown committed
5980 5981
    if (lex->current_select->order_list.first && !lex->current_select->braces)
    {
unknown's avatar
unknown committed
5982
      my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
unknown's avatar
unknown committed
5983
      DBUG_RETURN(1);
unknown's avatar
VIEW  
unknown committed
5984
    }
5985
    select_lex->include_neighbour(lex->current_select);
5986 5987 5988 5989 5990
    SELECT_LEX_UNIT *unit= select_lex->master_unit();                              
    if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->thd))
      DBUG_RETURN(1);
    select_lex->context.outer_context= 
                unit->first_select()->context.outer_context;
unknown's avatar
unknown committed
5991
  }
unknown's avatar
unknown committed
5992

5993
  select_lex->master_unit()->global_parameters= select_lex;
5994
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
5995
  lex->current_select= select_lex;
5996 5997 5998 5999 6000
  /*
    in subquery is SELECT query and we allow resolution of names in SELECT
    list
  */
  select_lex->context.resolve_in_select_list= TRUE;
unknown's avatar
unknown committed
6001
  DBUG_RETURN(0);
6002
}
unknown's avatar
unknown committed
6003

6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018
/*
  Create a select to return the same output as 'SELECT @@var_name'.

  SYNOPSIS
    create_select_for_variable()
    var_name		Variable name

  DESCRIPTION
    Used for SHOW COUNT(*) [ WARNINGS | ERROR]

    This will crash with a core dump if the variable doesn't exists
*/

void create_select_for_variable(const char *var_name)
{
6019
  THD *thd;
6020
  LEX *lex;
6021
  LEX_STRING tmp, null_lex_string;
6022 6023
  Item *var;
  char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end;
6024
  DBUG_ENTER("create_select_for_variable");
6025 6026

  thd= current_thd;
unknown's avatar
unknown committed
6027
  lex= thd->lex;
6028 6029 6030 6031
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
6032
  bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
6033 6034 6035 6036
  /*
    We set the name of Item to @@session.var_name because that then is used
    as the column name in the output.
  */
unknown's avatar
unknown committed
6037 6038 6039 6040 6041 6042
  if ((var= get_system_var(thd, OPT_SESSION, tmp, null_lex_string)))
  {
    end= strxmov(buff, "@@session.", var_name, NullS);
    var->set_name(buff, end-buff, system_charset_info);
    add_item_to_list(thd, var);
  }
6043 6044 6045
  DBUG_VOID_RETURN;
}

6046

unknown's avatar
unknown committed
6047 6048
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
6049
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
6050
  mysql_init_select(lex);
6051 6052
  lex->select_lex.select_limit= 0;
  lex->unit.select_limit_cnt= HA_POS_ERROR;
unknown's avatar
unknown committed
6053
  lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list);
6054
  lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
unknown's avatar
VIEW  
unknown committed
6055 6056
  lex->query_tables= 0;
  lex->query_tables_last= &lex->query_tables;
unknown's avatar
unknown committed
6057
}
unknown's avatar
unknown committed
6058

6059 6060 6061 6062
/*
  When you modify mysql_parse(), you may need to mofify
  mysql_test_parse_for_slave() in this same file.
*/
unknown's avatar
unknown committed
6063

6064
void mysql_parse(THD *thd, char *inBuf, uint length)
unknown's avatar
unknown committed
6065 6066
{
  DBUG_ENTER("mysql_parse");
6067 6068 6069

  DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););

unknown's avatar
unknown committed
6070
  mysql_init_query(thd, (uchar*) inBuf, length);
unknown's avatar
unknown committed
6071
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
unknown's avatar
unknown committed
6072
  {
unknown's avatar
unknown committed
6073
    LEX *lex= thd->lex;
6074
    
6075 6076
    sp_cache_flush_obsolete(&thd->sp_proc_cache);
    sp_cache_flush_obsolete(&thd->sp_func_cache);
6077
    
6078
    if (!MYSQLparse((void *)thd) && ! thd->is_fatal_error)
unknown's avatar
unknown committed
6079
    {
unknown's avatar
unknown committed
6080
#ifndef NO_EMBEDDED_ACCESS_CHECKS
6081
      if (mqh_used && thd->user_connect &&
6082
	  check_mqh(thd, lex->sql_command))
6083 6084 6085 6086
      {
	thd->net.error = 0;
      }
      else
unknown's avatar
unknown committed
6087
#endif
6088
      {
unknown's avatar
unknown committed
6089
	if (thd->net.report_error)
6090
	{
unknown's avatar
unknown committed
6091 6092
          delete lex->sphead;
          lex->sphead= NULL;
6093
	}
unknown's avatar
unknown committed
6094 6095
	else
	{
6096 6097 6098 6099 6100 6101 6102 6103 6104 6105
          /*
            Binlog logs a string starting from thd->query and having length
            thd->query_length; so we set thd->query_length correctly (to not
            log several statements in one event, when we executed only first).
            We set it to not see the ';' (otherwise it would get into binlog
            and Query_log_event::print() would give ';;' output).
            This also helps display only the current query in SHOW
            PROCESSLIST.
            Note that we don't need LOCK_thread_count to modify query_length.
          */
unknown's avatar
unknown committed
6106 6107
          if (lex->found_semicolon &&
              (thd->query_length= (ulong)(lex->found_semicolon - thd->query)))
6108 6109
            thd->query_length--;
          /* Actually execute the query */
unknown's avatar
unknown committed
6110
	  mysql_execute_command(thd);
unknown's avatar
SCRUM  
unknown committed
6111
	  query_cache_end_of_result(thd);
unknown's avatar
unknown committed
6112
	}
6113
      }
6114
      lex->unit.cleanup();
unknown's avatar
unknown committed
6115 6116
    }
    else
6117
    {
6118
      DBUG_ASSERT(thd->net.report_error);
6119
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
6120
			 thd->is_fatal_error));
6121 6122 6123 6124 6125

      /*
        The first thing we do after parse error is freeing sp_head to
        ensure that we have restored original memroot.
      */
unknown's avatar
unknown committed
6126
      if (lex->sphead)
6127
      {
unknown's avatar
unknown committed
6128
	/* Clean up after failed stored procedure/function */
unknown's avatar
unknown committed
6129 6130 6131
	delete lex->sphead;
	lex->sphead= NULL;
      }
6132 6133
      query_cache_abort(&thd->net);
      lex->unit.cleanup();
6134
    }
unknown's avatar
unknown committed
6135
    thd->proc_info="freeing items";
6136
    thd->end_statement();
6137
    thd->cleanup_after_query();
6138
    DBUG_ASSERT(thd->change_list.is_empty());
unknown's avatar
unknown committed
6139
  }
unknown's avatar
unknown committed
6140 6141 6142 6143
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
6144
#ifdef HAVE_REPLICATION
6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155
/*
  Usable by the replication SQL thread only: just parse a query to know if it
  can be ignored because of replicate-*-table rules.

  RETURN VALUES
    0	cannot be ignored
    1	can be ignored
*/

bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
{
unknown's avatar
unknown committed
6156
  LEX *lex= thd->lex;
6157
  bool error= 0;
unknown's avatar
unknown committed
6158
  DBUG_ENTER("mysql_test_parse_for_slave");
6159

unknown's avatar
unknown committed
6160
  mysql_init_query(thd, (uchar*) inBuf, length);
6161
  if (!MYSQLparse((void*) thd) && ! thd->is_fatal_error &&
6162
      all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
unknown's avatar
unknown committed
6163
    error= 1;                  /* Ignore question */
6164
  thd->end_statement();
6165
  thd->cleanup_after_query();
unknown's avatar
unknown committed
6166
  DBUG_RETURN(error);
6167
}
unknown's avatar
unknown committed
6168
#endif
unknown's avatar
unknown committed
6169

6170

unknown's avatar
unknown committed
6171

unknown's avatar
unknown committed
6172 6173 6174 6175 6176
/*****************************************************************************
** Store field definition for create
** Return 0 if ok
******************************************************************************/

unknown's avatar
unknown committed
6177
bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
unknown's avatar
unknown committed
6178
		       char *length, char *decimals,
6179
		       uint type_modifier,
6180 6181
		       Item *default_value, Item *on_update_value,
                       LEX_STRING *comment,
6182 6183
		       char *change,
                       List<String> *interval_list, CHARSET_INFO *cs,
unknown's avatar
unknown committed
6184
		       uint uint_geom_type)
unknown's avatar
unknown committed
6185 6186
{
  register create_field *new_field;
unknown's avatar
unknown committed
6187
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
6188 6189 6190 6191
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
6192
    my_error(ER_TOO_LONG_IDENT, MYF(0), field_name); /* purecov: inspected */
unknown's avatar
unknown committed
6193 6194 6195 6196 6197
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
6198 6199
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS,
                                    &default_key_create_info,
6200
				    0, lex->col_list));
unknown's avatar
unknown committed
6201 6202 6203 6204 6205
    lex->col_list.empty();
  }
  if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
6206 6207
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS,
                                    &default_key_create_info, 0,
unknown's avatar
unknown committed
6208 6209 6210 6211
				    lex->col_list));
    lex->col_list.empty();
  }

6212
  if (default_value)
unknown's avatar
unknown committed
6213
  {
6214
    /* 
unknown's avatar
unknown committed
6215 6216
      Default value should be literal => basic constants =>
      no need fix_fields()
6217 6218 6219
      
      We allow only one function as part of default value - 
      NOW() as default for TIMESTAMP type.
6220
    */
6221 6222 6223
    if (default_value->type() == Item::FUNC_ITEM && 
        !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
         type == FIELD_TYPE_TIMESTAMP))
6224
    {
6225
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
6226 6227 6228
      DBUG_RETURN(1);
    }
    else if (default_value->type() == Item::NULL_ITEM)
unknown's avatar
unknown committed
6229
    {
6230
      default_value= 0;
6231 6232 6233
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
6234
	my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
6235 6236 6237 6238 6239
	DBUG_RETURN(1);
      }
    }
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
6240
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
unknown's avatar
unknown committed
6241 6242 6243
      DBUG_RETURN(1);
    }
  }
6244 6245 6246

  if (on_update_value && type != FIELD_TYPE_TIMESTAMP)
  {
6247
    my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
6248 6249
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
6250

6251 6252 6253 6254 6255 6256
  if (type == FIELD_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),
       and so on, the display width is ignored.
    */
unknown's avatar
unknown committed
6257
    char buf[32];
6258
    my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length);
unknown's avatar
unknown committed
6259
    WARN_DEPRECATED(thd, "5.2", buf, "'TIMESTAMP'");
6260 6261
  }

6262 6263 6264 6265
  if (!(new_field= new create_field()) ||
      new_field->init(thd, field_name, type, length, decimals, type_modifier,
                      default_value, on_update_value, comment, change,
                      interval_list, cs, uint_geom_type))
unknown's avatar
unknown committed
6266
    DBUG_RETURN(1);
unknown's avatar
unknown committed
6267 6268 6269 6270 6271 6272

  lex->create_list.push_back(new_field);
  lex->last_field=new_field;
  DBUG_RETURN(0);
}

6273

unknown's avatar
unknown committed
6274 6275 6276 6277
/* Store position for column in ALTER TABLE .. ADD column */

void store_position_for_column(const char *name)
{
6278
  current_thd->lex->last_field->after=my_const_cast(char*) (name);
unknown's avatar
unknown committed
6279 6280 6281
}

bool
unknown's avatar
unknown committed
6282
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
6283 6284 6285 6286
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
6287
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
6288 6289 6290 6291 6292
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
unknown's avatar
unknown committed
6293
  thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
6294 6295 6296 6297 6298 6299 6300 6301 6302
  return 0;
}


/****************************************************************************
** save order by and tables in own lists
****************************************************************************/


unknown's avatar
unknown committed
6303
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
6304 6305 6306
{
  ORDER *order;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
6307
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER))))
unknown's avatar
unknown committed
6308
    DBUG_RETURN(1);
unknown's avatar
unknown committed
6309 6310
  order->item_ptr= item;
  order->item= &order->item_ptr;
unknown's avatar
unknown committed
6311 6312 6313
  order->asc = asc;
  order->free_me=0;
  order->used=0;
6314
  order->counter_used= 0;
unknown's avatar
unknown committed
6315
  list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
6316 6317 6318 6319
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
6320 6321 6322 6323 6324 6325 6326 6327 6328 6329
/*
  Add a table to list of used tables

  SYNOPSIS
    add_table_to_list()
    table		Table to add
    alias		alias for table (or null if no alias)
    table_options	A set of the following bits:
			TL_OPTION_UPDATING	Table will be updated
			TL_OPTION_FORCE_INDEX	Force usage of index
6330
			TL_OPTION_ALIAS	        an alias in multi table DELETE
unknown's avatar
unknown committed
6331 6332 6333 6334 6335 6336 6337 6338 6339
    lock_type		How table should be locked
    use_index		List of indexed used in USE INDEX
    ignore_index	List of indexed used in IGNORE INDEX

    RETURN
      0		Error
      #		Pointer to TABLE_LIST element added to the total table list
*/

unknown's avatar
unknown committed
6340 6341
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
6342
					     LEX_STRING *alias,
unknown's avatar
unknown committed
6343 6344
					     ulong table_options,
					     thr_lock_type lock_type,
6345 6346
					     List<String> *use_index_arg,
					     List<String> *ignore_index_arg,
unknown's avatar
unknown committed
6347
                                             LEX_STRING *option)
unknown's avatar
unknown committed
6348 6349
{
  register TABLE_LIST *ptr;
unknown's avatar
unknown committed
6350
  TABLE_LIST *previous_table_ref; /* The table preceding the current one. */
unknown's avatar
unknown committed
6351
  char *alias_str;
6352
  LEX *lex= thd->lex;
unknown's avatar
unknown committed
6353
  DBUG_ENTER("add_table_to_list");
6354
  LINT_INIT(previous_table_ref);
unknown's avatar
unknown committed
6355 6356 6357 6358

  if (!table)
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? alias->str : table->table.str;
6359 6360
  if (!test(table_options & TL_OPTION_ALIAS) && 
      check_table_name(table->table.str, table->table.length))
unknown's avatar
unknown committed
6361
  {
6362
    my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
unknown's avatar
unknown committed
6363 6364
    DBUG_RETURN(0);
  }
unknown's avatar
unknown committed
6365 6366

  if (table->is_derived_table() == FALSE && table->db.str &&
6367
      check_db_name(&table->db))
unknown's avatar
unknown committed
6368 6369 6370 6371
  {
    my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str);
    DBUG_RETURN(0);
  }
unknown's avatar
unknown committed
6372 6373

  if (!alias)					/* Alias is case sensitive */
6374 6375 6376
  {
    if (table->sel)
    {
unknown's avatar
unknown committed
6377 6378
      my_message(ER_DERIVED_MUST_HAVE_ALIAS,
                 ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
6379 6380
      DBUG_RETURN(0);
    }
6381
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
6382
      DBUG_RETURN(0);
6383
  }
unknown's avatar
unknown committed
6384
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
6385
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
6386
  if (table->db.str)
6387 6388 6389 6390
  {
    ptr->db= table->db.str;
    ptr->db_length= table->db.length;
  }
unknown's avatar
unknown committed
6391 6392
  else if (thd->copy_db_to(&ptr->db, &ptr->db_length))
    DBUG_RETURN(0);
unknown's avatar
unknown committed
6393

6394
  ptr->alias= alias_str;
6395
  if (lower_case_table_names && table->table.length)
6396
    table->table.length= my_casedn_str(files_charset_info, table->table.str);
6397 6398
  ptr->table_name=table->table.str;
  ptr->table_name_length=table->table.length;
6399
  ptr->lock_type=   lock_type;
unknown's avatar
unknown committed
6400 6401
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
6402
  ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
6403
  ptr->derived=	    table->sel;
6404 6405
  if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db,
                                      information_schema_name.str))
6406
  {
6407
    ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
6408 6409
    if (!schema_table ||
        (schema_table->hidden && 
6410
         (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0))
6411
    {
unknown's avatar
unknown committed
6412
      my_error(ER_UNKNOWN_TABLE, MYF(0),
6413
               ptr->table_name, information_schema_name.str);
6414 6415
      DBUG_RETURN(0);
    }
6416
    ptr->schema_table_name= ptr->table_name;
6417 6418
    ptr->schema_table= schema_table;
  }
6419
  ptr->select_lex=  lex->current_select;
unknown's avatar
unknown committed
6420
  ptr->cacheable_table= 1;
6421 6422 6423 6424 6425 6426
  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));
unknown's avatar
unknown committed
6427
  ptr->option= option ? option->str : 0;
unknown's avatar
unknown committed
6428
  /* check that used name is unique */
6429
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
6430
  {
unknown's avatar
unknown committed
6431 6432 6433 6434
    TABLE_LIST *first_table= (TABLE_LIST*) table_list.first;
    if (lex->sql_command == SQLCOM_CREATE_VIEW)
      first_table= first_table ? first_table->next_local : NULL;
    for (TABLE_LIST *tables= first_table ;
unknown's avatar
unknown committed
6435
	 tables ;
unknown's avatar
VIEW  
unknown committed
6436
	 tables=tables->next_local)
unknown's avatar
unknown committed
6437
    {
6438 6439
      if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
	  !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
6440
      {
6441
	my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
unknown's avatar
unknown committed
6442 6443
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
6444 6445
    }
  }
unknown's avatar
unknown committed
6446 6447 6448
  /* Store the table reference preceding the current one. */
  if (table_list.elements > 0)
  {
6449 6450 6451
    /*
      table_list.next points to the last inserted TABLE_LIST->next_local'
      element
6452
      We don't use the offsetof() macro here to avoid warnings from gcc
6453
    */
6454 6455 6456
    previous_table_ref= (TABLE_LIST*) ((char*) table_list.next -
                                       ((char*) &(ptr->next_local) -
                                        (char*) ptr));
6457 6458 6459 6460 6461 6462 6463 6464
    /*
      Set next_name_resolution_table of the previous table reference to point
      to the current table reference. In effect the list
      TABLE_LIST::next_name_resolution_table coincides with
      TABLE_LIST::next_local. Later this may be changed in
      store_top_level_join_columns() for NATURAL/USING joins.
    */
    previous_table_ref->next_name_resolution_table= ptr;
unknown's avatar
unknown committed
6465
  }
6466

unknown's avatar
unknown committed
6467 6468 6469 6470 6471 6472
  /*
    Link the current table reference in a local list (list for current select).
    Notice that as a side effect here we set the next_local field of the
    previous table reference to 'ptr'. Here we also add one element to the
    list 'table_list'.
  */
unknown's avatar
VIEW  
unknown committed
6473
  table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
unknown's avatar
unknown committed
6474
  ptr->next_name_resolution_table= NULL;
6475
  /* Link table in global list (all used tables) */
6476
  lex->add_to_query_tables(ptr);
unknown's avatar
unknown committed
6477 6478 6479
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
6480

6481 6482 6483 6484
/*
  Initialize a new table list for a nested join

  SYNOPSIS
unknown's avatar
unknown committed
6485
    init_nested_join()
6486
    thd         current thread
6487

6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506
  DESCRIPTION
    The function initializes a structure of the TABLE_LIST type
    for a nested join. It sets up its nested join list as empty.
    The created structure is added to the front of the current
    join list in the st_select_lex object. Then the function
    changes the current nest level for joins to refer to the newly
    created empty list after having saved the info on the old level
    in the initialized structure.

  RETURN VALUE
    0,  if success
    1,  otherwise
*/

bool st_select_lex::init_nested_join(THD *thd)
{
  TABLE_LIST *ptr;
  NESTED_JOIN *nested_join;
  DBUG_ENTER("init_nested_join");
6507

6508 6509
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
6510
    DBUG_RETURN(1);
6511 6512 6513
  nested_join= ptr->nested_join=
    ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));

6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533
  join_list->push_front(ptr);
  ptr->embedding= embedding;
  ptr->join_list= join_list;
  embedding= ptr;
  join_list= &nested_join->join_list;
  join_list->empty();
  DBUG_RETURN(0);
}


/*
  End a nested join table list

  SYNOPSIS
    end_nested_join()
    thd         current thread

  DESCRIPTION
    The function returns to the previous join nest level.
    If the current level contains only one member, the function
6534
    moves it one level up, eliminating the nest.
6535 6536 6537 6538 6539 6540 6541 6542 6543

  RETURN VALUE
    Pointer to TABLE_LIST element added to the total table list, if success
    0, otherwise
*/

TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
{
  TABLE_LIST *ptr;
6544
  NESTED_JOIN *nested_join;
6545
  DBUG_ENTER("end_nested_join");
6546

unknown's avatar
unknown committed
6547
  DBUG_ASSERT(embedding);
6548 6549 6550
  ptr= embedding;
  join_list= ptr->join_list;
  embedding= ptr->embedding;
6551
  nested_join= ptr->nested_join;
6552 6553 6554 6555 6556 6557 6558 6559 6560
  if (nested_join->join_list.elements == 1)
  {
    TABLE_LIST *embedded= nested_join->join_list.head();
    join_list->pop();
    embedded->join_list= join_list;
    embedded->embedding= embedding;
    join_list->push_front(embedded);
    ptr= embedded;
  }
6561
  else if (nested_join->join_list.elements == 0)
unknown's avatar
unknown committed
6562 6563
  {
    join_list->pop();
6564
    ptr= 0;                                     // return value
unknown's avatar
unknown committed
6565
  }
6566 6567 6568 6569 6570 6571 6572 6573
  DBUG_RETURN(ptr);
}


/*
  Nest last join operation

  SYNOPSIS
6574
    nest_last_join()
6575 6576 6577 6578 6579 6580
    thd         current thread

  DESCRIPTION
    The function nest last join operation as if it was enclosed in braces.

  RETURN VALUE
6581 6582 6583
    0  Error
    #  Pointer to TABLE_LIST element created for the new nested join

6584 6585 6586 6587 6588 6589
*/

TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
{
  TABLE_LIST *ptr;
  NESTED_JOIN *nested_join;
6590
  List<TABLE_LIST> *embedded_list;
6591
  DBUG_ENTER("nest_last_join");
6592

6593 6594
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
6595
    DBUG_RETURN(0);
6596 6597 6598
  nested_join= ptr->nested_join=
    ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));

6599 6600
  ptr->embedding= embedding;
  ptr->join_list= join_list;
6601
  embedded_list= &nested_join->join_list;
6602
  embedded_list->empty();
6603 6604

  for (uint i=0; i < 2; i++)
6605 6606 6607 6608 6609
  {
    TABLE_LIST *table= join_list->pop();
    table->join_list= embedded_list;
    table->embedding= ptr;
    embedded_list->push_back(table);
unknown's avatar
unknown committed
6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622
    if (table->natural_join)
    {
      ptr->is_natural_join= TRUE;
      /*
        If this is a JOIN ... USING, move the list of joined fields to the
        table reference that describes the join.
      */
      if (table->join_using_fields)
      {
        ptr->join_using_fields= table->join_using_fields;
        table->join_using_fields= NULL;
      }
    }
6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662
  }
  join_list->push_front(ptr);
  nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
  DBUG_RETURN(ptr);
}


/*
  Add a table to the current join list

  SYNOPSIS
    add_joined_table()
    table       the table to add

  DESCRIPTION
    The function puts a table in front of the current join list
    of st_select_lex object.
    Thus, joined tables are put into this list in the reverse order
    (the most outer join operation follows first).

  RETURN VALUE
    None
*/

void st_select_lex::add_joined_table(TABLE_LIST *table)
{
  DBUG_ENTER("add_joined_table");
  join_list->push_front(table);
  table->join_list= join_list;
  table->embedding= embedding;
  DBUG_VOID_RETURN;
}


/*
  Convert a right join into equivalent left join

  SYNOPSIS
    convert_right_join()
    thd         current thread
6663 6664 6665

  DESCRIPTION
    The function takes the current join list t[0],t[1] ... and
6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688
    effectively converts it into the list t[1],t[0] ...
    Although the outer_join flag for the new nested table contains
    JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
    operation.

  EXAMPLES
    SELECT * FROM t1 RIGHT JOIN t2 ON on_expr =>
      SELECT * FROM t2 LEFT JOIN t1 ON on_expr

    SELECT * FROM t1,t2 RIGHT JOIN t3 ON on_expr =>
      SELECT * FROM t1,t3 LEFT JOIN t2 ON on_expr

    SELECT * FROM t1,t2 RIGHT JOIN (t3,t4) ON on_expr =>
      SELECT * FROM t1,(t3,t4) LEFT JOIN t2 ON on_expr

    SELECT * FROM t1 LEFT JOIN t2 ON on_expr1 RIGHT JOIN t3  ON on_expr2 =>
      SELECT * FROM t3 LEFT JOIN (t1 LEFT JOIN t2 ON on_expr2) ON on_expr1

  RETURN
    Pointer to the table representing the inner table, if success
    0, otherwise
*/

6689
TABLE_LIST *st_select_lex::convert_right_join()
6690 6691
{
  TABLE_LIST *tab2= join_list->pop();
6692
  TABLE_LIST *tab1= join_list->pop();
6693 6694 6695 6696 6697 6698 6699 6700 6701
  DBUG_ENTER("convert_right_join");

  join_list->push_front(tab2);
  join_list->push_front(tab1);
  tab1->outer_join|= JOIN_TYPE_RIGHT;

  DBUG_RETURN(tab1);
}

unknown's avatar
unknown committed
6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714
/*
  Set lock for all tables in current select level

  SYNOPSIS:
    set_lock_for_tables()
    lock_type			Lock to set for tables

  NOTE:
    If lock is a write lock, then tables->updating is set 1
    This is to get tables_ok to know that the table is updated by the
    query
*/

unknown's avatar
unknown committed
6715
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
6716 6717 6718 6719 6720 6721
{
  bool for_update= lock_type >= TL_READ_NO_INSERT;
  DBUG_ENTER("set_lock_for_tables");
  DBUG_PRINT("enter", ("lock_type: %d  for_update: %d", lock_type,
		       for_update));

unknown's avatar
VIEW  
unknown committed
6722 6723 6724
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first;
       tables;
       tables= tables->next_local)
unknown's avatar
unknown committed
6725 6726 6727 6728 6729 6730 6731
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
6732

unknown's avatar
unknown committed
6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761
/*
  Create a fake SELECT_LEX for a unit

  SYNOPSIS:
    add_fake_select_lex()
    thd			   thread handle

  DESCRIPTION
    The method create a fake SELECT_LEX object for a unit.
    This object is created for any union construct containing a union
    operation and also for any single select union construct of the form
    (SELECT ... ORDER BY order_list [LIMIT n]) ORDER BY ... 
    or of the form
    (SELECT ... ORDER BY LIMIT n) ORDER BY ...
  
  NOTES
    The object is used to retrieve rows from the temporary table
    where the result on the union is obtained.

  RETURN VALUES
    1     on failure to create the object
    0     on success
*/

bool st_select_lex_unit::add_fake_select_lex(THD *thd)
{
  SELECT_LEX *first_sl= first_select();
  DBUG_ENTER("add_fake_select_lex");
  DBUG_ASSERT(!fake_select_lex);
unknown's avatar
unknown committed
6762

unknown's avatar
unknown committed
6763 6764 6765 6766 6767
  if (!(fake_select_lex= new (thd->mem_root) SELECT_LEX()))
      DBUG_RETURN(1);
  fake_select_lex->include_standalone(this, 
                                      (SELECT_LEX_NODE**)&fake_select_lex);
  fake_select_lex->select_number= INT_MAX;
unknown's avatar
unknown committed
6768
  fake_select_lex->parent_lex= thd->lex; /* Used in init_query. */
unknown's avatar
unknown committed
6769 6770
  fake_select_lex->make_empty_select();
  fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
6771 6772
  fake_select_lex->select_limit= 0;

unknown's avatar
unknown committed
6773
  fake_select_lex->context.outer_context=first_sl->context.outer_context;
6774 6775 6776
  /* allow item list resolving in fake select for ORDER BY */
  fake_select_lex->context.resolve_in_select_list= TRUE;
  fake_select_lex->context.select_lex= fake_select_lex;
unknown's avatar
unknown committed
6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789

  if (!first_sl->next_select())
  {
    /* 
      This works only for 
      (SELECT ... ORDER BY list [LIMIT n]) ORDER BY order_list [LIMIT m],
      (SELECT ... LIMIT n) ORDER BY order_list [LIMIT m]
      just before the parser starts processing order_list
    */ 
    global_parameters= fake_select_lex;
    fake_select_lex->no_table_names_allowed= 1;
    thd->lex->current_select= fake_select_lex;
  }
6790
  thd->lex->pop_context();
unknown's avatar
unknown committed
6791 6792 6793
  DBUG_RETURN(0);
}

6794

unknown's avatar
unknown committed
6795
/*
6796 6797
  Push a new name resolution context for a JOIN ... ON clause to the
  context stack of a query block.
unknown's avatar
unknown committed
6798 6799

  SYNOPSIS
6800
    push_new_name_resolution_context()
unknown's avatar
unknown committed
6801
    thd       pointer to current thread
unknown's avatar
unknown committed
6802
    left_op   left  operand of the JOIN
unknown's avatar
unknown committed
6803 6804 6805 6806
    right_op  rigth operand of the JOIN

  DESCRIPTION
    Create a new name resolution context for a JOIN ... ON clause,
6807 6808 6809
    set the first and last leaves of the list of table references
    to be used for name resolution, and push the newly created
    context to the stack of contexts of the query.
unknown's avatar
unknown committed
6810 6811

  RETURN
6812 6813
    FALSE  if all is OK
    TRUE   if a memory allocation error occured
unknown's avatar
unknown committed
6814 6815
*/

6816 6817 6818
bool
push_new_name_resolution_context(THD *thd,
                                 TABLE_LIST *left_op, TABLE_LIST *right_op)
unknown's avatar
unknown committed
6819 6820
{
  Name_resolution_context *on_context;
6821
  if (!(on_context= new (thd->mem_root) Name_resolution_context))
6822
    return TRUE;
unknown's avatar
unknown committed
6823 6824 6825 6826 6827
  on_context->init();
  on_context->first_name_resolution_table=
    left_op->first_leaf_for_name_resolution();
  on_context->last_name_resolution_table=
    right_op->last_leaf_for_name_resolution();
6828
  return thd->lex->push_context(on_context);
unknown's avatar
unknown committed
6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848
}


/*
  Add an ON condition to the second operand of a JOIN ... ON.

  SYNOPSIS
    add_join_on
    b     the second operand of a JOIN ... ON
    expr  the condition to be added to the ON clause

  DESCRIPTION
    Add an ON condition to the right operand of a JOIN ... ON clause.

  RETURN
    FALSE  if there was some error
    TRUE   if all is OK
*/

void add_join_on(TABLE_LIST *b, Item *expr)
unknown's avatar
unknown committed
6849
{
6850
  if (expr)
6851
  {
6852
    if (!b->on_expr)
unknown's avatar
unknown committed
6853
      b->on_expr= expr;
6854 6855
    else
    {
unknown's avatar
unknown committed
6856 6857 6858 6859 6860 6861
      /*
        If called from the parser, this happens if you have both a
        right and left join. If called later, it happens if we add more
        than one condition to the ON clause.
      */
      b->on_expr= new Item_cond_and(b->on_expr,expr);
6862 6863
    }
    b->on_expr->top_level_item();
6864
  }
unknown's avatar
unknown committed
6865 6866 6867
}


6868
/*
unknown's avatar
unknown committed
6869 6870
  Mark that there is a NATURAL JOIN or JOIN ... USING between two
  tables.
6871 6872 6873

  SYNOPSIS
    add_join_natural()
unknown's avatar
unknown committed
6874 6875 6876 6877
    a			Left join argument
    b			Right join argument
    using_fields        Field names from USING clause
  
6878
  IMPLEMENTATION
unknown's avatar
unknown committed
6879 6880 6881 6882 6883 6884 6885 6886 6887 6888
    This function marks that table b should be joined with a either via
    a NATURAL JOIN or via JOIN ... USING. Both join types are special
    cases of each other, so we treat them together. The function
    setup_conds() creates a list of equal condition between all fields
    of the same name for NATURAL JOIN or the fields in 'using_fields'
    for JOIN ... USING. The list of equality conditions is stored
    either in b->on_expr, or in JOIN::conds, depending on whether there
    was an outer join.

  EXAMPLE
6889 6890 6891
    SELECT * FROM t1 NATURAL LEFT JOIN t2
     <=>
    SELECT * FROM t1 LEFT JOIN t2 ON (t1.i=t2.i and t1.j=t2.j ... )
unknown's avatar
unknown committed
6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902

    SELECT * FROM t1 NATURAL JOIN t2 WHERE <some_cond>
     <=>
    SELECT * FROM t1, t2 WHERE (t1.i=t2.i and t1.j=t2.j and <some_cond>)

    SELECT * FROM t1 JOIN t2 USING(j) WHERE <some_cond>
     <=>
    SELECT * FROM t1, t2 WHERE (t1.j=t2.j and <some_cond>)

  RETURN
    None
6903 6904
*/

unknown's avatar
unknown committed
6905
void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields)
unknown's avatar
unknown committed
6906
{
unknown's avatar
unknown committed
6907 6908
  b->natural_join= a;
  b->join_using_fields= using_fields;
unknown's avatar
unknown committed
6909 6910
}

unknown's avatar
unknown committed
6911

6912
/*
6913 6914 6915 6916
  Reload/resets privileges and the different caches.

  SYNOPSIS
    reload_acl_and_cache()
6917
    thd			Thread handler (can be NULL!)
6918 6919 6920 6921 6922
    options             What should be reset/reloaded (tables, privileges,
    slave...)
    tables              Tables to flush (if any)
    write_to_binlog     Depending on 'options', it may be very bad to write the
                        query to the binlog (e.g. FLUSH SLAVE); this is a
unknown's avatar
unknown committed
6923 6924 6925
                        pointer where reload_acl_and_cache() will put 0 if
                        it thinks we really should not write to the binlog.
                        Otherwise it will put 1.
6926 6927 6928

  RETURN
    0	 ok
unknown's avatar
unknown committed
6929
    !=0  error.  thd->killed or thd->net.report_error is set
6930 6931
*/

6932 6933
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
                          bool *write_to_binlog)
unknown's avatar
unknown committed
6934 6935 6936
{
  bool result=0;
  select_errors=0;				/* Write if more errors */
6937
  bool tmp_write_to_binlog= 1;
6938

6939
  DBUG_ASSERT(!thd || !thd->in_sub_stmt);
6940

unknown's avatar
SCRUM  
unknown committed
6941
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
6942 6943
  if (options & REFRESH_GRANT)
  {
6944 6945 6946 6947 6948 6949
    THD *tmp_thd= 0;
    /*
      If reload_acl_and_cache() is called from SIGHUP handler we have to
      allocate temporary THD for execution of acl_reload()/grant_reload().
    */
    if (!thd && (thd= (tmp_thd= new THD)))
6950 6951
    {
      thd->thread_stack= (char*) &tmp_thd;
6952
      thd->store_globals();
6953
    }
6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965
    if (thd)
    {
      (void)acl_reload(thd);
      (void)grant_reload(thd);
    }
    if (tmp_thd)
    {
      delete tmp_thd;
      /* Remember that we don't have a THD */
      my_pthread_setspecific_ptr(THR_THD,  0);
      thd= 0;
    }
6966
    reset_mqh((LEX_USER *)NULL, TRUE);
unknown's avatar
unknown committed
6967
  }
unknown's avatar
SCRUM  
unknown committed
6968
#endif
unknown's avatar
unknown committed
6969 6970
  if (options & REFRESH_LOG)
  {
6971
    /*
unknown's avatar
unknown committed
6972
      Flush the normal query log, the update log, the binary log,
unknown's avatar
unknown committed
6973 6974
      the slow query log, the relay log (if it exists) and the log
      tables.
6975
    */
unknown's avatar
unknown committed
6976

6977
    /*
unknown's avatar
unknown committed
6978 6979 6980 6981
      Writing this command to the binlog may result in infinite loops
      when doing mysqlbinlog|mysql, and anyway it does not really make
      sense to log it automatically (would cause more trouble to users
      than it would help them)
6982 6983
    */
    tmp_write_to_binlog= 0;
6984 6985 6986 6987
    if( mysql_bin_log.is_open() )
    {
      mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
    }
unknown's avatar
unknown committed
6988
#ifdef HAVE_REPLICATION
6989
    pthread_mutex_lock(&LOCK_active_mi);
6990
    rotate_relay_log(active_mi);
6991
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
6992
#endif
unknown's avatar
unknown committed
6993 6994 6995 6996 6997

    /* flush slow and general logs */
    logger.flush_logs(thd);

    if (ha_flush_logs(NULL))
unknown's avatar
unknown committed
6998
      result=1;
unknown's avatar
unknown committed
6999 7000
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
7001
  }
unknown's avatar
unknown committed
7002
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
7003 7004
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
7005
    query_cache.pack();				// FLUSH QUERY CACHE
7006
    options &= ~REFRESH_QUERY_CACHE;    // Don't flush cache, just free memory
unknown's avatar
unknown committed
7007 7008 7009
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
7010
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
7011
  }
unknown's avatar
unknown committed
7012
#endif /*HAVE_QUERY_CACHE*/
7013 7014 7015 7016 7017
  /*
    Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
    (see sql_yacc.yy)
  */
  if (options & (REFRESH_TABLES | REFRESH_READ_LOCK)) 
unknown's avatar
unknown committed
7018
  {
7019
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
7020
    {
7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031
      /*
        We must not try to aspire a global read lock if we have a write
        locked table. This would lead to a deadlock when trying to
        reopen (and re-lock) the table after the flush.
      */
      if (thd->locked_tables)
      {
        THR_LOCK_DATA **lock_p= thd->locked_tables->locks;
        THR_LOCK_DATA **end_p= lock_p + thd->locked_tables->lock_count;

        for (; lock_p < end_p; lock_p++)
unknown's avatar
unknown committed
7032
        {
7033 7034 7035 7036 7037
          if ((*lock_p)->type == TL_WRITE)
          {
            my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
            return 1;
          }
unknown's avatar
unknown committed
7038
        }
7039
      }
unknown's avatar
unknown committed
7040 7041 7042 7043
      /*
	Writing to the binlog could cause deadlocks, as we don't log
	UNLOCK TABLES
      */
7044
      tmp_write_to_binlog= 0;
7045
      if (lock_global_read_lock(thd))
unknown's avatar
unknown committed
7046
	return 1;                               // Killed
7047 7048
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
                                 tables);
unknown's avatar
unknown committed
7049
      if (make_global_read_lock_block_commit(thd)) // Killed
7050 7051 7052 7053 7054
      {
        /* Don't leave things in a half-locked state */
        unlock_global_read_lock(thd);
        return 1;
      }
unknown's avatar
unknown committed
7055
    }
7056 7057
    else
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
unknown's avatar
unknown committed
7058
    my_dbopt_cleanup();
unknown's avatar
unknown committed
7059 7060 7061
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
unknown's avatar
unknown committed
7062
  if (thd && (options & REFRESH_STATUS))
unknown's avatar
unknown committed
7063
    refresh_status(thd);
unknown's avatar
unknown committed
7064 7065
  if (options & REFRESH_THREADS)
    flush_thread_cache();
unknown's avatar
unknown committed
7066
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
7067
  if (options & REFRESH_MASTER)
7068
  {
7069
    DBUG_ASSERT(thd);
7070
    tmp_write_to_binlog= 0;
7071
    if (reset_master(thd))
unknown's avatar
unknown committed
7072
    {
7073
      result=1;
unknown's avatar
unknown committed
7074 7075
      thd->fatal_error();                       // Ensure client get error
    }
7076
  }
7077
#endif
unknown's avatar
unknown committed
7078
#ifdef OPENSSL
7079 7080 7081 7082 7083 7084
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
unknown's avatar
unknown committed
7085
#ifdef HAVE_REPLICATION
7086 7087
 if (options & REFRESH_SLAVE)
 {
7088
   tmp_write_to_binlog= 0;
7089
   pthread_mutex_lock(&LOCK_active_mi);
7090
   if (reset_slave(thd, active_mi))
7091
     result=1;
7092
   pthread_mutex_unlock(&LOCK_active_mi);
7093
 }
7094
#endif
7095
 if (options & REFRESH_USER_RESOURCES)
unknown's avatar
unknown committed
7096
   reset_mqh((LEX_USER *) NULL);
unknown's avatar
unknown committed
7097
 *write_to_binlog= tmp_write_to_binlog;
7098
 return result;
unknown's avatar
unknown committed
7099 7100
}

7101

7102
/*
7103
  kills a thread
7104 7105 7106 7107 7108

  SYNOPSIS
    kill_one_thread()
    thd			Thread class
    id			Thread id
7109
    only_kill_query     Should it kill the query or the connection
7110 7111 7112 7113 7114

  NOTES
    This is written such that we have a short lock on LOCK_thread_count
*/

7115
uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
unknown's avatar
unknown committed
7116 7117 7118
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
7119 7120
  DBUG_ENTER("kill_one_thread");
  DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query));
7121 7122
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
7123 7124
  while ((tmp=it++))
  {
unknown's avatar
unknown committed
7125 7126
    if (tmp->command == COM_DAEMON)
      continue;
unknown's avatar
unknown committed
7127 7128
    if (tmp->thread_id == id)
    {
7129 7130
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
7131 7132 7133
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
7134 7135
  if (tmp)
  {
7136 7137
    if ((thd->security_ctx->master_access & SUPER_ACL) ||
	!strcmp(thd->security_ctx->user, tmp->security_ctx->user))
7138
    {
unknown's avatar
SCRUM  
unknown committed
7139
      tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
7140 7141 7142 7143 7144 7145
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }
7146 7147 7148 7149
  DBUG_PRINT("exit", ("%d", error));
  DBUG_RETURN(error);
}

7150

7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164
/*
  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)))
7165
    send_ok(thd);
unknown's avatar
unknown committed
7166
  else
unknown's avatar
unknown committed
7167
    my_error(error, MYF(0), id);
unknown's avatar
unknown committed
7168 7169
}

unknown's avatar
unknown committed
7170

7171 7172
	/* If pointer is not a null pointer, append filename to it */

unknown's avatar
unknown committed
7173 7174
bool append_file_to_dir(THD *thd, const char **filename_ptr,
                        const char *table_name)
7175
{
7176
  char buff[FN_REFLEN],*ptr, *end;
7177 7178 7179 7180 7181 7182 7183
  if (!*filename_ptr)
    return 0;					// nothing to do

  /* Check that the filename is not too long and it's a hard path */
  if (strlen(*filename_ptr)+strlen(table_name) >= FN_REFLEN-1 ||
      !test_if_hard_path(*filename_ptr))
  {
7184
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
7185 7186 7187 7188
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
7189
  end=convert_dirname(buff, *filename_ptr, NullS);
unknown's avatar
unknown committed
7190
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
7191 7192
    return 1;					// End of memory
  *filename_ptr=ptr;
7193
  strxmov(ptr,buff,table_name,NullS);
7194 7195
  return 0;
}
7196

7197

7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211
/*
  Check if the select is a simple select (not an union)

  SYNOPSIS
    check_simple_select()

  RETURN VALUES
    0	ok
    1	error	; In this case the error messege is sent to the client
*/

bool check_simple_select()
{
  THD *thd= current_thd;
7212 7213
  LEX *lex= thd->lex;
  if (lex->current_select != &lex->select_lex)
7214 7215
  {
    char command[80];
7216 7217
    strmake(command, lex->yylval->symbol.str,
	    min(lex->yylval->symbol.length, sizeof(command)-1));
7218
    my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
7219 7220 7221 7222
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
7223

unknown's avatar
unknown committed
7224

unknown's avatar
unknown committed
7225
Comp_creator *comp_eq_creator(bool invert)
unknown's avatar
unknown committed
7226
{
unknown's avatar
unknown committed
7227
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
unknown's avatar
unknown committed
7228 7229
}

unknown's avatar
unknown committed
7230

unknown's avatar
unknown committed
7231
Comp_creator *comp_ge_creator(bool invert)
unknown's avatar
unknown committed
7232
{
unknown's avatar
unknown committed
7233
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
unknown's avatar
unknown committed
7234 7235
}

unknown's avatar
unknown committed
7236

unknown's avatar
unknown committed
7237
Comp_creator *comp_gt_creator(bool invert)
unknown's avatar
unknown committed
7238
{
unknown's avatar
unknown committed
7239
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
unknown's avatar
unknown committed
7240 7241
}

unknown's avatar
unknown committed
7242

unknown's avatar
unknown committed
7243
Comp_creator *comp_le_creator(bool invert)
unknown's avatar
unknown committed
7244
{
unknown's avatar
unknown committed
7245
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
unknown's avatar
unknown committed
7246 7247
}

unknown's avatar
unknown committed
7248

unknown's avatar
unknown committed
7249
Comp_creator *comp_lt_creator(bool invert)
unknown's avatar
unknown committed
7250
{
unknown's avatar
unknown committed
7251
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
unknown's avatar
unknown committed
7252 7253
}

unknown's avatar
unknown committed
7254

unknown's avatar
unknown committed
7255
Comp_creator *comp_ne_creator(bool invert)
unknown's avatar
unknown committed
7256
{
unknown's avatar
unknown committed
7257
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
unknown's avatar
unknown committed
7258
}
unknown's avatar
unknown committed
7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278


/*
  Construct ALL/ANY/SOME subquery Item

  SYNOPSIS
    all_any_subquery_creator()
    left_expr - pointer to left expression
    cmp - compare function creator
    all - true if we create ALL subquery
    select_lex - pointer on parsed subquery structure

  RETURN VALUE
    constructed Item (or 0 if out of memory)
*/
Item * all_any_subquery_creator(Item *left_expr,
				chooser_compare_func_creator cmp,
				bool all,
				SELECT_LEX *select_lex)
{
unknown's avatar
unknown committed
7279
  if ((cmp == &comp_eq_creator) && !all)       //  = ANY <=> IN
unknown's avatar
unknown committed
7280
    return new Item_in_subselect(left_expr, select_lex);
unknown's avatar
unknown committed
7281 7282

  if ((cmp == &comp_ne_creator) && all)        // <> ALL <=> NOT IN
unknown's avatar
unknown committed
7283 7284 7285
    return new Item_func_not(new Item_in_subselect(left_expr, select_lex));

  Item_allany_subselect *it=
7286
    new Item_allany_subselect(left_expr, cmp, select_lex, all);
unknown's avatar
unknown committed
7287
  if (all)
7288
    return it->upper_item= new Item_func_not_all(it);	/* ALL */
unknown's avatar
unknown committed
7289

7290
  return it->upper_item= new Item_func_nop_all(it);      /* ANY/SOME */
unknown's avatar
unknown committed
7291
}
7292 7293


7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305
/*
  CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
  the proper arguments.  This isn't very fast but it should work for most
  cases.

  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.
*/

unknown's avatar
unknown committed
7306
bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
7307 7308
{
  List<create_field> fields;
7309 7310
  ALTER_INFO alter_info;
  alter_info.flags= ALTER_ADD_INDEX;
7311 7312 7313
  HA_CREATE_INFO create_info;
  DBUG_ENTER("mysql_create_index");
  bzero((char*) &create_info,sizeof(create_info));
unknown's avatar
unknown committed
7314
  create_info.db_type= 0;
7315
  create_info.default_table_charset= thd->variables.collation_database;
7316
  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
7317
				&create_info, table_list,
7318
				fields, keys, 0, (ORDER*)0,
7319
                                0, &alter_info, 1));
7320 7321 7322
}


unknown's avatar
unknown committed
7323
bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
7324 7325 7326 7327 7328 7329
{
  List<create_field> fields;
  List<Key> keys;
  HA_CREATE_INFO create_info;
  DBUG_ENTER("mysql_drop_index");
  bzero((char*) &create_info,sizeof(create_info));
unknown's avatar
unknown committed
7330
  create_info.db_type= 0;
7331
  create_info.default_table_charset= thd->variables.collation_database;
7332 7333
  alter_info->clear();
  alter_info->flags= ALTER_DROP_INDEX;
7334
  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
7335
				&create_info, table_list,
7336
				fields, keys, 0, (ORDER*)0,
7337
                                0, alter_info, 1));
7338
}
unknown's avatar
merge  
unknown committed
7339 7340


7341 7342 7343 7344 7345
/*
  Multi update query pre-check

  SYNOPSIS
    multi_update_precheck()
unknown's avatar
unknown committed
7346
    thd		Thread handler
unknown's avatar
VIEW  
unknown committed
7347
    tables	Global/local table list (have to be the same)
7348

unknown's avatar
unknown committed
7349
  RETURN VALUE
unknown's avatar
unknown committed
7350 7351
    FALSE OK
    TRUE  Error
7352
*/
unknown's avatar
unknown committed
7353

unknown's avatar
unknown committed
7354
bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
7355 7356 7357 7358 7359
{
  const char *msg= 0;
  TABLE_LIST *table;
  LEX *lex= thd->lex;
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
7360
  DBUG_ENTER("multi_update_precheck");
7361 7362 7363

  if (select_lex->item_list.elements != lex->value_list.elements)
  {
7364
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7365
    DBUG_RETURN(TRUE);
7366 7367 7368 7369 7370
  }
  /*
    Ensure that we have UPDATE or SELECT privilege for each table
    The exact privilege is checked in mysql_multi_update()
  */
unknown's avatar
VIEW  
unknown committed
7371
  for (table= tables; table; table= table->next_local)
7372
  {
7373 7374 7375
    if (table->derived)
      table->grant.privilege= SELECT_ACL;
    else if ((check_access(thd, UPDATE_ACL, table->db,
7376 7377
                           &table->grant.privilege, 0, 1,
                           test(table->schema_table)) ||
7378 7379
              grant_option &&
              check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
unknown's avatar
unknown committed
7380
             (check_access(thd, SELECT_ACL, table->db,
7381 7382
                           &table->grant.privilege, 0, 0,
                           test(table->schema_table)) ||
unknown's avatar
unknown committed
7383
              grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
unknown's avatar
unknown committed
7384
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7385

unknown's avatar
VIEW  
unknown committed
7386
    table->table_in_first_from_clause= 1;
7387
  }
unknown's avatar
unknown committed
7388 7389 7390
  /*
    Is there tables of subqueries?
  */
7391
  if (&lex->select_lex != lex->all_selects_list || lex->time_zone_tables_used)
7392
  {
7393
    DBUG_PRINT("info",("Checking sub query list"));
unknown's avatar
VIEW  
unknown committed
7394
    for (table= tables; table; table= table->next_global)
7395
    {
unknown's avatar
unknown committed
7396 7397 7398
      if (!my_tz_check_n_skip_implicit_tables(&table,
                                              lex->time_zone_tables_used) &&
          !table->table_in_first_from_clause)
7399 7400
      {
	if (check_access(thd, SELECT_ACL, table->db,
7401 7402
			 &table->grant.privilege, 0, 0,
                         test(table->schema_table)) ||
unknown's avatar
unknown committed
7403
	    grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
unknown's avatar
unknown committed
7404
	  DBUG_RETURN(TRUE);
7405 7406 7407 7408 7409 7410
      }
    }
  }

  if (select_lex->order_list.elements)
    msg= "ORDER BY";
7411
  else if (select_lex->select_limit)
7412 7413 7414 7415
    msg= "LIMIT";
  if (msg)
  {
    my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
unknown's avatar
unknown committed
7416
    DBUG_RETURN(TRUE);
7417
  }
unknown's avatar
unknown committed
7418
  DBUG_RETURN(FALSE);
7419 7420 7421 7422 7423 7424 7425
}

/*
  Multi delete query pre-check

  SYNOPSIS
    multi_delete_precheck()
unknown's avatar
unknown committed
7426
    thd			Thread handler
unknown's avatar
VIEW  
unknown committed
7427
    tables		Global/local table list
7428

unknown's avatar
unknown committed
7429
  RETURN VALUE
unknown's avatar
unknown committed
7430 7431
    FALSE OK
    TRUE  error
7432
*/
unknown's avatar
unknown committed
7433

7434
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
7435 7436 7437
{
  SELECT_LEX *select_lex= &thd->lex->select_lex;
  TABLE_LIST *aux_tables=
unknown's avatar
unknown committed
7438
    (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
7439
  TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
unknown's avatar
VIEW  
unknown committed
7440
  DBUG_ENTER("multi_delete_precheck");
unknown's avatar
unknown committed
7441

7442 7443
  /* sql_yacc guarantees that tables and aux_tables are not zero */
  DBUG_ASSERT(aux_tables != 0);
unknown's avatar
unknown committed
7444
  if (check_table_access(thd, SELECT_ACL, tables, 0))
7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455
    DBUG_RETURN(TRUE);

  /*
    Since aux_tables list is not part of LEX::query_tables list we
    have to juggle with LEX::query_tables_own_last value to be able
    call check_table_access() safely.
  */
  thd->lex->query_tables_own_last= 0;
  if (check_table_access(thd, DELETE_ACL, aux_tables, 0))
  {
    thd->lex->query_tables_own_last= save_query_tables_own_last;
unknown's avatar
unknown committed
7456
    DBUG_RETURN(TRUE);
7457 7458 7459
  }
  thd->lex->query_tables_own_last= save_query_tables_own_last;

7460 7461
  if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
  {
unknown's avatar
unknown committed
7462 7463
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
7464
    DBUG_RETURN(TRUE);
7465
  }
7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490
  DBUG_RETURN(FALSE);
}


/*
  Link tables in auxilary table list of multi-delete with corresponding
  elements in main table list, and set proper locks for them.

  SYNOPSIS
    multi_delete_set_locks_and_link_aux_tables()
      lex - pointer to LEX representing multi-delete

  RETURN VALUE
    FALSE - success
    TRUE  - error
*/

bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
{
  TABLE_LIST *tables= (TABLE_LIST*)lex->select_lex.table_list.first;
  TABLE_LIST *target_tbl;
  DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables");

  lex->table_count= 0;

unknown's avatar
unknown committed
7491
  for (target_tbl= (TABLE_LIST *)lex->auxiliary_table_list.first;
7492
       target_tbl; target_tbl= target_tbl->next_local)
7493
  {
7494
    lex->table_count++;
7495 7496
    /* All tables in aux_tables must be found in FROM PART */
    TABLE_LIST *walk;
unknown's avatar
VIEW  
unknown committed
7497
    for (walk= tables; walk; walk= walk->next_local)
7498
    {
unknown's avatar
unknown committed
7499 7500 7501
      if (!my_strcasecmp(table_alias_charset,
			 target_tbl->alias, walk->alias) &&
	  !strcmp(walk->db, target_tbl->db))
7502 7503 7504 7505
	break;
    }
    if (!walk)
    {
7506
      my_error(ER_UNKNOWN_TABLE, MYF(0),
7507
               target_tbl->table_name, "MULTI DELETE");
unknown's avatar
unknown committed
7508
      DBUG_RETURN(TRUE);
7509
    }
unknown's avatar
unknown committed
7510 7511 7512 7513 7514
    if (!walk->derived)
    {
      target_tbl->table_name= walk->table_name;
      target_tbl->table_name_length= walk->table_name_length;
    }
unknown's avatar
unknown committed
7515
    walk->updating= target_tbl->updating;
unknown's avatar
unknown committed
7516
    walk->lock_type= target_tbl->lock_type;
unknown's avatar
VIEW  
unknown committed
7517
    target_tbl->correspondent_table= walk;	// Remember corresponding table
7518
  }
unknown's avatar
unknown committed
7519
  DBUG_RETURN(FALSE);
7520 7521 7522
}


unknown's avatar
unknown committed
7523 7524 7525 7526 7527
/*
  simple UPDATE query pre-check

  SYNOPSIS
    update_precheck()
unknown's avatar
unknown committed
7528 7529
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
7530 7531

  RETURN VALUE
unknown's avatar
unknown committed
7532 7533
    FALSE OK
    TRUE  Error
unknown's avatar
unknown committed
7534
*/
unknown's avatar
unknown committed
7535

unknown's avatar
unknown committed
7536
bool update_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7537 7538 7539 7540
{
  DBUG_ENTER("update_precheck");
  if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
  {
unknown's avatar
unknown committed
7541
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7542
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7543
  }
unknown's avatar
unknown committed
7544
  DBUG_RETURN(check_one_table_access(thd, UPDATE_ACL, tables));
unknown's avatar
unknown committed
7545 7546 7547 7548 7549 7550 7551 7552
}


/*
  simple DELETE query pre-check

  SYNOPSIS
    delete_precheck()
unknown's avatar
unknown committed
7553 7554
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
7555 7556

  RETURN VALUE
unknown's avatar
unknown committed
7557 7558
    FALSE  OK
    TRUE   error
unknown's avatar
unknown committed
7559
*/
unknown's avatar
unknown committed
7560

unknown's avatar
unknown committed
7561
bool delete_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7562 7563 7564
{
  DBUG_ENTER("delete_precheck");
  if (check_one_table_access(thd, DELETE_ACL, tables))
unknown's avatar
unknown committed
7565
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7566
  /* Set privilege for the WHERE clause */
unknown's avatar
unknown committed
7567
  tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
7568
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
7569 7570 7571 7572 7573 7574 7575 7576
}


/*
  simple INSERT query pre-check

  SYNOPSIS
    insert_precheck()
unknown's avatar
unknown committed
7577 7578
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
7579 7580

  RETURN VALUE
unknown's avatar
unknown committed
7581 7582
    FALSE  OK
    TRUE   error
unknown's avatar
unknown committed
7583
*/
unknown's avatar
unknown committed
7584

unknown's avatar
merge  
unknown committed
7585
bool insert_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7586 7587 7588 7589
{
  LEX *lex= thd->lex;
  DBUG_ENTER("insert_precheck");

unknown's avatar
unknown committed
7590 7591 7592 7593
  /*
    Check that we have modify privileges for the first table and
    select privileges for the rest
  */
unknown's avatar
unknown committed
7594 7595 7596
  ulong privilege= (INSERT_ACL |
                    (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
                    (lex->value_list.elements ? UPDATE_ACL : 0));
unknown's avatar
unknown committed
7597 7598

  if (check_one_table_access(thd, privilege, tables))
unknown's avatar
unknown committed
7599
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7600

unknown's avatar
unknown committed
7601
  if (lex->update_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
7602
  {
unknown's avatar
unknown committed
7603
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7604
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7605
  }
unknown's avatar
unknown committed
7606
  DBUG_RETURN(FALSE);
7607
}
unknown's avatar
unknown committed
7608 7609 7610 7611 7612 7613 7614


/*
  CREATE TABLE query pre-check

  SYNOPSIS
    create_table_precheck()
unknown's avatar
unknown committed
7615 7616 7617
    thd			Thread handler
    tables		Global table list
    create_table	Table which will be created
unknown's avatar
unknown committed
7618 7619

  RETURN VALUE
unknown's avatar
unknown committed
7620 7621
    FALSE   OK
    TRUE   Error
unknown's avatar
unknown committed
7622
*/
unknown's avatar
unknown committed
7623

unknown's avatar
unknown committed
7624 7625
bool create_table_precheck(THD *thd, TABLE_LIST *tables,
                           TABLE_LIST *create_table)
unknown's avatar
unknown committed
7626 7627
{
  LEX *lex= thd->lex;
7628 7629
  SELECT_LEX *select_lex= &lex->select_lex;
  ulong want_priv;
unknown's avatar
merge  
unknown committed
7630
  bool error= TRUE;                                 // Error message is given
unknown's avatar
unknown committed
7631
  DBUG_ENTER("create_table_precheck");
7632 7633 7634

  want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
              CREATE_TMP_ACL : CREATE_ACL);
unknown's avatar
unknown committed
7635 7636
  lex->create_info.alias= create_table->alias;
  if (check_access(thd, want_priv, create_table->db,
7637 7638
		   &create_table->grant.privilege, 0, 0,
                   test(create_table->schema_table)) ||
unknown's avatar
unknown committed
7639 7640 7641
      check_merge_table_access(thd, create_table->db,
			       (TABLE_LIST *)
			       lex->create_info.merge_list.first))
7642 7643
    goto err;
  if (grant_option && want_priv != CREATE_TMP_ACL &&
7644
      check_grant(thd, want_priv, create_table, 0, 1, 0))
7645 7646 7647 7648 7649 7650
    goto err;

  if (select_lex->item_list.elements)
  {
    /* Check permissions for used tables in CREATE TABLE ... SELECT */

7651 7652
#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
    /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
7653
    /*
7654
      Only do the check for PS, because we on execute we have to check that
unknown's avatar
unknown committed
7655 7656
      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).
7657
    */
unknown's avatar
unknown committed
7658
    if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
7659
    {
unknown's avatar
unknown committed
7660 7661 7662 7663
      /*
        For temporary tables we don't have to check if the created table exists
      */
      if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
unknown's avatar
unknown committed
7664
          find_table_in_global_list(tables, create_table->db,
7665
                                    create_table->table_name))
unknown's avatar
unknown committed
7666
      {
7667
	error= FALSE;
unknown's avatar
unknown committed
7668 7669 7670
        goto err;
      }
    }
7671
#endif
7672 7673 7674
    if (tables && check_table_access(thd, SELECT_ACL, tables,0))
      goto err;
  }
unknown's avatar
merge  
unknown committed
7675
  error= FALSE;
7676 7677 7678

err:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
7679
}
unknown's avatar
unknown committed
7680 7681 7682 7683 7684 7685 7686


/*
  negate given expression

  SYNOPSIS
    negate_expression()
7687
    thd  thread handler
unknown's avatar
unknown committed
7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715
    expr expression for negation

  RETURN
    negated expression
*/

Item *negate_expression(THD *thd, Item *expr)
{
  Item *negated;
  if (expr->type() == Item::FUNC_ITEM &&
      ((Item_func *) expr)->functype() == Item_func::NOT_FUNC)
  {
    /* it is NOT(NOT( ... )) */
    Item *arg= ((Item_func *) expr)->arguments()[0];
    enum_parsing_place place= thd->lex->current_select->parsing_place;
    if (arg->is_bool_func() || place == IN_WHERE || place == IN_HAVING)
      return arg;
    /*
      if it is not boolean function then we have to emulate value of
      not(not(a)), it will be a != 0
    */
    return new Item_func_ne(arg, new Item_int((char*) "0", 0, 1));
  }

  if ((negated= expr->neg_transformer(thd)) != 0)
    return negated;
  return new Item_func_not(expr);
}
7716

7717 7718
/*
  Set the specified definer to the default value, which is the current user in
7719
  the thread.
7720 7721 7722 7723 7724 7725 7726
 
  SYNOPSIS
    get_default_definer()
    thd       [in] thread handler
    definer   [out] definer
*/
 
7727
void get_default_definer(THD *thd, LEX_USER *definer)
7728 7729 7730 7731 7732 7733 7734 7735 7736 7737
{
  const Security_context *sctx= thd->security_ctx;

  definer->user.str= (char *) sctx->priv_user;
  definer->user.length= strlen(definer->user.str);

  definer->host.str= (char *) sctx->priv_host;
  definer->host.length= strlen(definer->host.str);
}

7738

7739
/*
7740
  Create default definer for the specified THD.
7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758

  SYNOPSIS
    create_default_definer()
    thd         [in] thread handler

  RETURN
    On success, return a valid pointer to the created and initialized
    LEX_USER, which contains definer information.
    On error, return 0.
*/

LEX_USER *create_default_definer(THD *thd)
{
  LEX_USER *definer;

  if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
    return 0;

7759
  get_default_definer(thd, definer);
7760 7761 7762 7763 7764

  return definer;
}


7765
/*
7766
  Create definer with the given user and host names.
7767 7768

  SYNOPSIS
7769 7770 7771 7772
    create_definer()
    thd         [in] thread handler
    user_name   [in] user name
    host_name   [in] host name
7773 7774

  RETURN
7775
    On success, return a valid pointer to the created and initialized
7776
    LEX_USER, which contains definer information.
7777
    On error, return 0.
7778 7779
*/

7780
LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
7781
{
7782 7783 7784 7785
  LEX_USER *definer;

  /* Create and initialize. */

unknown's avatar
unknown committed
7786
  if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
7787 7788 7789 7790 7791 7792
    return 0;

  definer->user= *user_name;
  definer->host= *host_name;

  return definer;
7793
}
7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812


/*
  Retuns information about user or current user.

  SYNOPSIS
    get_current_user()
    thd         [in] thread handler
    user        [in] user

  RETURN
    On success, return a valid pointer to initialized
    LEX_USER, which contains user information.
    On error, return 0.
*/

LEX_USER *get_current_user(THD *thd, LEX_USER *user)
{
  if (!user->user.str)  // current_user
7813 7814
    return create_default_definer(thd);

7815 7816
  return user;
}
7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832


/*
  Check that 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

  RETURN
    FALSE   the passed string is not longer than max_length
    TRUE    the passed string is longer than max_length
*/

unknown's avatar
unknown committed
7833 7834
bool check_string_length(LEX_STRING *str, const char *err_msg,
                         uint max_length)
7835
{
unknown's avatar
unknown committed
7836 7837
  if (str->length <= max_length)
    return FALSE;
7838 7839

  my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_length);
unknown's avatar
unknown committed
7840

7841 7842
  return TRUE;
}