You need to sign in or sign up before continuing.
sql_parse.cc 184 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 17
   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 */

#include "mysql_priv.h"
18
#include "sql_repl.h"
19
#include "repl_failsafe.h"
unknown's avatar
unknown committed
20 21 22 23
#include <m_ctype.h>
#include <myisam.h>
#include <my_dir.h>

unknown's avatar
unknown committed
24
#ifdef HAVE_INNOBASE_DB
25
#include "ha_innodb.h"
unknown's avatar
unknown committed
26 27
#endif

28
#include "sp_head.h"
29
#include "sp.h"
30

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

49 50 51 52 53 54
/* 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 || \
55
   (LP)->sql_command == SQLCOM_SHOW_CREATE_FUNC || \
56 57 58
   (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
   "FUNCTION" : "PROCEDURE")

59 60 61
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#endif
unknown's avatar
unknown committed
62

unknown's avatar
unknown committed
63
#ifndef NO_EMBEDDED_ACCESS_CHECKS
64
static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
unknown's avatar
unknown committed
65
#endif
66
static void decrease_user_connections(USER_CONN *uc);
unknown's avatar
unknown committed
67
static bool check_db_used(THD *thd,TABLE_LIST *tables);
unknown's avatar
unknown committed
68 69
static void remove_escape(char *name);
static void refresh_status(void);
unknown's avatar
unknown committed
70 71
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
			       const char *table_name);
unknown's avatar
unknown committed
72

73
const char *any_db="*any*";	// Special symbol for check_access
unknown's avatar
unknown committed
74 75 76 77

const char *command_name[]={
  "Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
  "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
78
  "Connect","Kill","Debug","Ping","Time","Delayed insert","Change user",
unknown's avatar
unknown committed
79
  "Binlog Dump","Table Dump",  "Connect Out", "Register Slave",
80
  "Prepare", "Execute", "Long Data", "Close stmt",
81
  "Reset stmt", "Set option", "Fetch",
82
  "Error"					// Last command number
unknown's avatar
unknown committed
83 84
};

85
static char empty_c_string[1]= {0};		// Used for not defined 'db'
unknown's avatar
unknown committed
86 87 88 89

#ifdef __WIN__
static void  test_signal(int sig_ptr)
{
unknown's avatar
unknown committed
90
#if !defined( DBUG_OFF)
unknown's avatar
unknown committed
91 92
  MessageBox(NULL,"Test signal","DBUG",MB_OK);
#endif
unknown's avatar
unknown committed
93
#if defined(OS2)
94 95
  fprintf(stderr, "Test signal %d\n", sig_ptr);
  fflush(stderr);
unknown's avatar
unknown committed
96
#endif
unknown's avatar
unknown committed
97 98 99 100
}
static void init_signals(void)
{
  int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
101
  for (int i=0 ; i < 7 ; i++)
unknown's avatar
unknown committed
102 103 104 105
    signal( signals[i], test_signal) ;
}
#endif

unknown's avatar
unknown committed
106 107 108 109 110
static void unlock_locked_tables(THD *thd)
{
  if (thd->locked_tables)
  {
    thd->lock=thd->locked_tables;
111
    thd->locked_tables=0;			// Will be automatically closed
unknown's avatar
unknown committed
112 113 114 115
    close_thread_tables(thd);			// Free tables
  }
}

116

unknown's avatar
unknown committed
117
static bool end_active_trans(THD *thd)
118
{
unknown's avatar
unknown committed
119
  int error=0;
120
  DBUG_ENTER("end_active_trans");
unknown's avatar
unknown committed
121
  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
unknown's avatar
unknown committed
122
		      OPTION_TABLE_LOCK))
123
  {
124
    DBUG_PRINT("info",("options: 0x%lx", (ulong) thd->options));
125
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
126 127 128
    /* Safety if one did "drop table" on locked tables */
    if (!thd->locked_tables)
      thd->options&= ~OPTION_TABLE_LOCK;
129
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
130
    if (ha_commit(thd))
unknown's avatar
unknown committed
131
      error=1;
132
  }
133
  DBUG_RETURN(error);
134 135 136
}


unknown's avatar
unknown committed
137
#ifdef HAVE_REPLICATION
138 139 140
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
{
  return (table_rules_on && tables && !tables_ok(thd,tables) &&
unknown's avatar
unknown committed
141
          ((thd->lex->sql_command != SQLCOM_DELETE_MULTI) ||
unknown's avatar
unknown committed
142 143
           !tables_ok(thd,
		      (TABLE_LIST *)thd->lex->auxilliary_table_list.first)));
144
}
unknown's avatar
unknown committed
145
#endif
146 147


unknown's avatar
unknown committed
148 149
static HASH hash_user_connections;

unknown's avatar
unknown committed
150 151
static int get_or_create_user_conn(THD *thd, const char *user,
				   const char *host,
unknown's avatar
unknown committed
152
				   USER_RESOURCES *mqh)
unknown's avatar
unknown committed
153 154
{
  int return_val=0;
unknown's avatar
unknown committed
155
  uint temp_len, user_len;
unknown's avatar
unknown committed
156 157 158 159 160 161
  char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
  struct  user_conn *uc;

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

162 163
  user_len=strlen(user);
  temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
unknown's avatar
unknown committed
164
  (void) pthread_mutex_lock(&LOCK_user_conn);
unknown's avatar
unknown committed
165 166
  if (!(uc = (struct  user_conn *) hash_search(&hash_user_connections,
					       (byte*) temp_user, temp_len)))
unknown's avatar
unknown committed
167
  {
unknown's avatar
unknown committed
168 169 170
    /* 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
171 172
			 MYF(MY_WME)))))
    {
173
      net_send_error(thd, 0, NullS);		// Out of memory
unknown's avatar
unknown committed
174 175
      return_val=1;
      goto end;
unknown's avatar
unknown committed
176
    }
unknown's avatar
unknown committed
177 178
    uc->user=(char*) (uc+1);
    memcpy(uc->user,temp_user,temp_len+1);
179
    uc->host= uc->user + user_len +  1;
unknown's avatar
unknown committed
180
    uc->len = temp_len;
181
    uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
182
    uc->user_resources=*mqh;
unknown's avatar
unknown committed
183
    uc->intime=thd->thr_create_time;
unknown's avatar
SCRUM  
unknown committed
184
    if (my_hash_insert(&hash_user_connections, (byte*) uc))
unknown's avatar
unknown committed
185 186
    {
      my_free((char*) uc,0);
187
      net_send_error(thd, 0, NullS);		// Out of memory
unknown's avatar
unknown committed
188 189 190 191 192
      return_val=1;
      goto end;
    }
  }
  thd->user_connect=uc;
193
  uc->connections++;
unknown's avatar
unknown committed
194 195 196
end:
  (void) pthread_mutex_unlock(&LOCK_user_conn);
  return return_val;
unknown's avatar
unknown committed
197

unknown's avatar
unknown committed
198
}
unknown's avatar
unknown committed
199 200 201


/*
202
    Check if user exist and password supplied is correct. 
203 204
  SYNOPSIS
    check_user()
205 206 207 208
    thd          thread handle, thd->{host,user,ip} are used
    command      originator of the check: now check_user is called
                 during connect and change user procedures; used for 
                 logging.
209
    passwd       scrambled password received from client
210 211 212 213
    passwd_len   length of scrambled password
    db           database name to connect to, may be NULL
    check_count  dont know exactly

214
    Note, that host, user and passwd may point to communication buffer.
215
    Current implementation does not depend on that, but future changes
216 217 218
    should be done with this in mind; 'thd' is INOUT, all other params
    are 'IN'.

219 220 221
  RETURN VALUE
    0  OK; thd->user, thd->master_access, thd->priv_user, thd->db and
       thd->db_access are updated; OK is sent to client;
unknown's avatar
unknown committed
222 223
   -1  access denied or handshake error; error is sent to client;
   >0  error, not sent to client
unknown's avatar
unknown committed
224 225
*/

unknown's avatar
SCRUM:  
unknown committed
226 227 228
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
229
{
230
  DBUG_ENTER("check_user");
unknown's avatar
unknown committed
231
  
unknown's avatar
unknown committed
232 233
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  thd->master_access= GLOBAL_ACLS;			// Full rights
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
  /* Change database if necessary: OK or FAIL is sent in mysql_change_db */
  if (db && db[0])
  {
    thd->db= 0;
    thd->db_length= 0;
    if (mysql_change_db(thd, db))
    {
      if (thd->user_connect)
	decrease_user_connections(thd->user_connect);
      DBUG_RETURN(-1);
    }
  }
  else
    send_ok(thd);
  DBUG_RETURN(0);
unknown's avatar
unknown committed
249 250
#else

251 252 253 254 255
  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);
  
256
  /*
257 258
    If the server is running in secure auth mode, short scrambles are 
    forbidden.
259
  */
260
  if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
unknown's avatar
unknown committed
261
  {
262
    net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
263 264
    mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
265
  }
unknown's avatar
unknown committed
266 267 268 269
  if (passwd_len != 0 &&
      passwd_len != SCRAMBLE_LENGTH &&
      passwd_len != SCRAMBLE_LENGTH_323)
    DBUG_RETURN(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
270

271
  /*
272
    Clear thd->db as it points to something, that will be freed when 
273
    connection is closed. We don't want to accidentally free a wrong pointer
274 275
    if connect failed. Also in case of 'CHANGE USER' failure, current
    database will be switched to 'no database selected'.
276
  */
277 278
  thd->db= 0;
  thd->db_length= 0;
unknown's avatar
unknown committed
279
  
280
  USER_RESOURCES ur;
281
  int res= acl_getroot(thd, &ur, passwd, passwd_len);
unknown's avatar
SCRUM:  
unknown committed
282
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
283
  if (res == -1)
unknown's avatar
unknown committed
284
  {
unknown's avatar
unknown committed
285 286 287 288 289 290
    /*
      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.
    */
291
    NET *net= &thd->net;
292
    if (opt_secure_auth_local)
293
    {
294 295
      net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
                       thd->user, thd->host_or_ip);
296 297 298 299
      mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
                      thd->user, thd->host_or_ip);
      DBUG_RETURN(-1);
    }
unknown's avatar
unknown committed
300
    /* We have to read very specific packet size */
301
    if (send_old_password_request(thd) ||
unknown's avatar
unknown committed
302 303
        my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
    {                                               
unknown's avatar
unknown committed
304 305 306 307 308
      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 */
309
    res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
unknown's avatar
unknown committed
310
  }
unknown's avatar
SCRUM:  
unknown committed
311
#endif /*EMBEDDED_LIBRARY*/
unknown's avatar
unknown committed
312 313
  /* here res is always >= 0 */
  if (res == 0)
unknown's avatar
unknown committed
314
  {
315
    if (!(thd->master_access & NO_ACCESS)) // authentication is OK 
316
    {
unknown's avatar
unknown committed
317 318 319 320 321 322 323 324 325 326
      DBUG_PRINT("info",
                 ("Capabilities: %d  packet_length: %ld  Host: '%s'  "
                  "Login user: '%s' Priv_user: '%s'  Using password: %s "
                  "Access: %u  db: '%s'",
                  thd->client_capabilities, thd->max_client_packet_length,
                  thd->host_or_ip, thd->user, thd->priv_user,
                  passwd_len ? "yes": "no",
                  thd->master_access, thd->db ? thd->db : "*none*"));

      if (check_count)
327
      {
unknown's avatar
unknown committed
328 329
        VOID(pthread_mutex_lock(&LOCK_thread_count));
        bool count_ok= thread_count < max_connections + delayed_insert_threads
330
                       || (thd->master_access & SUPER_ACL);
unknown's avatar
unknown committed
331 332 333
        VOID(pthread_mutex_unlock(&LOCK_thread_count));
        if (!count_ok)
        {                                         // too many connections 
334
          net_send_error(thd, ER_CON_COUNT_ERROR);
unknown's avatar
unknown committed
335 336
          DBUG_RETURN(-1);
        }
337
      }
unknown's avatar
unknown committed
338

unknown's avatar
unknown committed
339 340 341 342 343 344 345 346
      /* Why logging is performed before all checks've passed? */
      mysql_log.write(thd,command,
                      (thd->priv_user == thd->user ?
                       (char*) "%s@%s on %s" :
                       (char*) "%s@%s as anonymous on %s"),
                      thd->user, thd->host_or_ip,
                      db ? db : (char*) "");

347
      /*
348 349 350
        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.
351
      */
unknown's avatar
unknown committed
352 353 354
      thd->db_access=0;

      /* Don't allow user to connect if he has done too many queries */
355
      if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
unknown's avatar
unknown committed
356
	   max_user_connections) &&
357 358 359 360
	  get_or_create_user_conn(thd,
            opt_old_style_user_limits ? thd->user : thd->priv_user,
            opt_old_style_user_limits ? thd->host_or_ip : thd->priv_host,
            &ur))
unknown's avatar
unknown committed
361 362
	DBUG_RETURN(-1);
      if (thd->user_connect &&
363 364
	  (thd->user_connect->user_resources.conn_per_hour ||
	   thd->user_connect->user_resources.user_conn ||
unknown's avatar
unknown committed
365 366 367
	   max_user_connections) &&
	  check_for_max_user_connections(thd, thd->user_connect))
	DBUG_RETURN(-1);
unknown's avatar
unknown committed
368 369 370

      /* Change database if necessary: OK or FAIL is sent in mysql_change_db */
      if (db && db[0])
371
      {
unknown's avatar
unknown committed
372 373 374 375 376 377
        if (mysql_change_db(thd, db))
        {
          if (thd->user_connect)
            decrease_user_connections(thd->user_connect);
          DBUG_RETURN(-1);
        }
378 379
      }
      else
unknown's avatar
unknown committed
380
	send_ok(thd);
unknown's avatar
unknown committed
381 382 383
      thd->password= test(passwd_len);          // remember for error messages 
      /* Ready to handle queries */
      DBUG_RETURN(0);
unknown's avatar
unknown committed
384 385
    }
  }
unknown's avatar
unknown committed
386
  else if (res == 2) // client gave short hash, server has long hash
unknown's avatar
unknown committed
387
  {
388
    net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
unknown's avatar
unknown committed
389 390
    mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
391
  }
392 393 394 395
  net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
                   thd->user,
                   thd->host_or_ip,
                   passwd_len ? ER(ER_YES) : ER(ER_NO));
unknown's avatar
unknown committed
396 397 398 399 400
  mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
                  thd->user,
                  thd->host_or_ip,
                  passwd_len ? ER(ER_YES) : ER(ER_NO));
  DBUG_RETURN(-1);
unknown's avatar
unknown committed
401
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
402 403
}

unknown's avatar
unknown committed
404
/*
unknown's avatar
unknown committed
405 406
  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
407 408
*/

409 410
extern "C" byte *get_key_conn(user_conn *buff, uint *length,
			      my_bool not_used __attribute__((unused)))
unknown's avatar
unknown committed
411 412 413 414 415
{
  *length=buff->len;
  return (byte*) buff->user;
}

416
extern "C" void free_user(struct user_conn *uc)
unknown's avatar
unknown committed
417 418 419 420
{
  my_free((char*) uc,MYF(0));
}

unknown's avatar
unknown committed
421
void init_max_user_conn(void)
unknown's avatar
unknown committed
422
{
unknown's avatar
unknown committed
423 424
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
		   0,0,
425
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
426
		   0);
unknown's avatar
unknown committed
427 428 429
}


unknown's avatar
unknown committed
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
/*
  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
447 448
#ifndef NO_EMBEDDED_ACCESS_CHECKS

449
static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
unknown's avatar
unknown committed
450
{
unknown's avatar
unknown committed
451
  int error=0;
452
  DBUG_ENTER("check_for_max_user_connections");
unknown's avatar
unknown committed
453

454
  (void) pthread_mutex_lock(&LOCK_user_conn);
455
  if (max_user_connections && !uc->user_resources.user_conn &&
unknown's avatar
unknown committed
456
      max_user_connections < (uint) uc->connections)
unknown's avatar
unknown committed
457
  {
458
    net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
unknown's avatar
unknown committed
459 460
    error=1;
    goto end;
unknown's avatar
unknown committed
461
  }
462 463 464 465 466 467 468 469 470 471 472
  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)
473
  {
474 475
    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
                     "max_connections",
476
                     (long) uc->user_resources.conn_per_hour);
477 478 479
    error=1;
    goto end;
  }
480
  uc->conn_per_hour++;
unknown's avatar
unknown committed
481 482

  end:
483 484
  if (error)
    uc->connections--; // no need for decrease_user_connections() here
485
  (void) pthread_mutex_unlock(&LOCK_user_conn);
486
  DBUG_RETURN(error);
unknown's avatar
unknown committed
487
}
unknown's avatar
unknown committed
488
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
489

unknown's avatar
unknown committed
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
/*
  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.
*/

508
static void decrease_user_connections(USER_CONN *uc)
unknown's avatar
unknown committed
509
{
unknown's avatar
unknown committed
510
  DBUG_ENTER("decrease_user_connections");
511 512 513
  (void) pthread_mutex_lock(&LOCK_user_conn);
  DBUG_ASSERT(uc->connections);
  if (!--uc->connections && !mqh_used)
unknown's avatar
unknown committed
514 515
  {
    /* Last connection for user; Delete it */
unknown's avatar
unknown committed
516
    (void) hash_delete(&hash_user_connections,(byte*) uc);
unknown's avatar
unknown committed
517
  }
518
  (void) pthread_mutex_unlock(&LOCK_user_conn);
519
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
520 521
}

522

unknown's avatar
unknown committed
523 524 525 526 527
void free_max_user_conn(void)
{
  hash_free(&hash_user_connections);
}

unknown's avatar
unknown committed
528

529 530 531
/*
  Mark all commands that somehow changes a table
  This is used to check number of updates / hour
unknown's avatar
unknown committed
532 533 534

  sql_command is actually set to SQLCOM_END sometimes
  so we need the +1 to include it in the array.
535 536
*/

unknown's avatar
unknown committed
537
char  uc_update_queries[SQLCOM_END+1];
538 539 540

void init_update_queries(void)
{
unknown's avatar
unknown committed
541 542
  bzero((gptr) &uc_update_queries, sizeof(uc_update_queries));

543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
  uc_update_queries[SQLCOM_CREATE_TABLE]=1;
  uc_update_queries[SQLCOM_CREATE_INDEX]=1;
  uc_update_queries[SQLCOM_ALTER_TABLE]=1;
  uc_update_queries[SQLCOM_UPDATE]=1;
  uc_update_queries[SQLCOM_INSERT]=1;
  uc_update_queries[SQLCOM_INSERT_SELECT]=1;
  uc_update_queries[SQLCOM_DELETE]=1;
  uc_update_queries[SQLCOM_TRUNCATE]=1;
  uc_update_queries[SQLCOM_DROP_TABLE]=1;
  uc_update_queries[SQLCOM_LOAD]=1;
  uc_update_queries[SQLCOM_CREATE_DB]=1;
  uc_update_queries[SQLCOM_DROP_DB]=1;
  uc_update_queries[SQLCOM_REPLACE]=1;
  uc_update_queries[SQLCOM_REPLACE_SELECT]=1;
  uc_update_queries[SQLCOM_RENAME_TABLE]=1;
  uc_update_queries[SQLCOM_BACKUP_TABLE]=1;
  uc_update_queries[SQLCOM_RESTORE_TABLE]=1;
  uc_update_queries[SQLCOM_DELETE_MULTI]=1;
  uc_update_queries[SQLCOM_DROP_INDEX]=1;
562
  uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
unknown's avatar
VIEW  
unknown committed
563 564
  uc_update_queries[SQLCOM_CREATE_VIEW]=1;
  uc_update_queries[SQLCOM_DROP_VIEW]=1;
565 566
}

unknown's avatar
unknown committed
567 568
bool is_update_query(enum enum_sql_command command)
{
unknown's avatar
unknown committed
569
  DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
unknown's avatar
unknown committed
570 571
  return uc_update_queries[command];
}
572

unknown's avatar
unknown committed
573 574 575
/*
  Check if maximum queries per hour limit has been reached
  returns 0 if OK.
unknown's avatar
unknown committed
576

577 578 579
  In theory we would need a mutex in the USER_CONN structure for this to
  be 100 % safe, but as the worst scenario is that we would miss counting
  a couple of queries, this isn't critical.
unknown's avatar
unknown committed
580 581
*/

582

583
static bool check_mqh(THD *thd, uint check_command)
unknown's avatar
unknown committed
584
{
unknown's avatar
unknown committed
585 586 587
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  return(0);
#else
unknown's avatar
unknown committed
588
  bool error=0;
unknown's avatar
unknown committed
589
  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
590
  USER_CONN *uc=thd->user_connect;
unknown's avatar
unknown committed
591
  DBUG_ENTER("check_mqh");
unknown's avatar
unknown committed
592
  DBUG_ASSERT(uc != 0);
unknown's avatar
unknown committed
593

unknown's avatar
unknown committed
594
  /* If more than a hour since last check, reset resource checking */
595 596 597 598 599 600 601 602 603
  if (check_time  - uc->intime >= 3600)
  {
    (void) pthread_mutex_lock(&LOCK_user_conn);
    uc->questions=1;
    uc->updates=0;
    uc->conn_per_hour=0;
    uc->intime=check_time;
    (void) pthread_mutex_unlock(&LOCK_user_conn);
  }
unknown's avatar
unknown committed
604
  /* Check that we have not done too many questions / hour */
605 606 607
  if (uc->user_resources.questions &&
      uc->questions++ >= uc->user_resources.questions)
  {
608 609
    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
                     (long) uc->user_resources.questions);
610 611 612
    error=1;
    goto end;
  }
613
  if (check_command < (uint) SQLCOM_END)
unknown's avatar
unknown committed
614
  {
unknown's avatar
unknown committed
615 616 617 618
    /* Check that we have not done too many updates / hour */
    if (uc->user_resources.updates && uc_update_queries[check_command] &&
	uc->updates++ >= uc->user_resources.updates)
    {
619 620
      net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
                       (long) uc->user_resources.updates);
unknown's avatar
unknown committed
621 622 623
      error=1;
      goto end;
    }
unknown's avatar
unknown committed
624 625
  }
end:
unknown's avatar
unknown committed
626
  DBUG_RETURN(error);
unknown's avatar
unknown committed
627
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
628 629
}

unknown's avatar
unknown committed
630

unknown's avatar
unknown committed
631
static void reset_mqh(LEX_USER *lu, bool get_them= 0)
unknown's avatar
unknown committed
632
{
unknown's avatar
unknown committed
633
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
634
  (void) pthread_mutex_lock(&LOCK_user_conn);
unknown's avatar
unknown committed
635
  if (lu)  // for GRANT
unknown's avatar
unknown committed
636
  {
637
    USER_CONN *uc;
638
    uint temp_len=lu->user.length+lu->host.length+2;
unknown's avatar
unknown committed
639 640
    char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];

unknown's avatar
unknown committed
641 642
    memcpy(temp_user,lu->user.str,lu->user.length);
    memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
643
    temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
unknown's avatar
unknown committed
644
    if ((uc = (struct  user_conn *) hash_search(&hash_user_connections,
645
						(byte*) temp_user, temp_len)))
unknown's avatar
unknown committed
646 647
    {
      uc->questions=0;
648
      get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
649 650
      uc->updates=0;
      uc->conn_per_hour=0;
unknown's avatar
unknown committed
651 652
    }
  }
unknown's avatar
unknown committed
653
  else
unknown's avatar
unknown committed
654
  {
unknown's avatar
unknown committed
655
    /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
unknown's avatar
unknown committed
656
    for (uint idx=0;idx < hash_user_connections.records; idx++)
unknown's avatar
unknown committed
657
    {
unknown's avatar
unknown committed
658 659
      USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
						      idx);
660 661 662 663 664
      if (get_them)
	get_mqh(uc->user,uc->host,uc);
      uc->questions=0;
      uc->updates=0;
      uc->conn_per_hour=0;
unknown's avatar
unknown committed
665 666
    }
  }
unknown's avatar
unknown committed
667
  (void) pthread_mutex_unlock(&LOCK_user_conn);
unknown's avatar
unknown committed
668
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
669
}
unknown's avatar
unknown committed
670

unknown's avatar
unknown committed
671
/*
672
    Perform handshake, authorize client and update thd ACL variables.
673
  SYNOPSIS
674
    check_connection()
675
    thd  thread handle
676 677

  RETURN
678
     0  success, OK is sent to user, thd is updated.
679 680
    -1  error, which is sent to user
   > 0  error code (not sent to user)
unknown's avatar
unknown committed
681 682
*/

unknown's avatar
SCRUM:  
unknown committed
683 684
#ifndef EMBEDDED_LIBRARY
static int check_connection(THD *thd)
unknown's avatar
unknown committed
685
{
686
  uint connect_errors= 0;
unknown's avatar
unknown committed
687
  NET *net= &thd->net;
688

689 690 691
  DBUG_PRINT("info",
             ("New connection received on %s", vio_description(net->vio)));

unknown's avatar
unknown committed
692 693
  if (!thd->host)                           // If TCP/IP connection
  {
694
    char ip[30];
695

696
    if (vio_peer_addr(net->vio, ip, &thd->peer_port))
unknown's avatar
unknown committed
697
      return (ER_BAD_HOST_ERROR);
698
    if (!(thd->ip= my_strdup(ip,MYF(0))))
unknown's avatar
unknown committed
699
      return (ER_OUT_OF_RESOURCES);
700
    thd->host_or_ip= thd->ip;
unknown's avatar
unknown committed
701 702 703
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
    /* Fast local hostname resolve for Win32 */
    if (!strcmp(thd->ip,"127.0.0.1"))
unknown's avatar
unknown committed
704
    {
unknown's avatar
SCRUM:  
unknown committed
705 706
      thd->host= (char*) my_localhost;
      thd->host_or_ip= my_localhost;
unknown's avatar
unknown committed
707
    }
unknown's avatar
unknown committed
708 709 710
    else
#endif
    {
711 712 713 714 715 716
      if (!(specialflag & SPECIAL_NO_RESOLVE))
      {
	vio_in_addr(net->vio,&thd->remote.sin_addr);
	thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
	/* Cut very long hostnames to avoid possible overflows */
	if (thd->host)
unknown's avatar
unknown committed
717
	{
718
	  thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
unknown's avatar
unknown committed
719 720
	  thd->host_or_ip= thd->host;
	}
721 722 723
	if (connect_errors > max_connect_errors)
	  return(ER_HOST_IS_BLOCKED);
      }
unknown's avatar
unknown committed
724
    }
unknown's avatar
unknown committed
725 726 727
    DBUG_PRINT("info",("Host: %s  ip: %s",
		       thd->host ? thd->host : "unknown host",
		       thd->ip ? thd->ip : "unknown ip"));
unknown's avatar
unknown committed
728 729 730
    if (acl_check_host(thd->host,thd->ip))
      return(ER_HOST_NOT_PRIVILEGED);
  }
731
  else /* Hostname given means that the connection was on a socket */
unknown's avatar
unknown committed
732
  {
unknown's avatar
unknown committed
733
    DBUG_PRINT("info",("Host: %s",thd->host));
734 735
    thd->host_or_ip= thd->host;
    thd->ip= 0;
736
    bzero((char*) &thd->remote, sizeof(struct sockaddr));
unknown's avatar
unknown committed
737 738
  }
  vio_keepalive(net->vio, TRUE);
739 740
  ulong pkt_len= 0;
  char *end;
unknown's avatar
unknown committed
741
  {
unknown's avatar
unknown committed
742
    /* buff[] needs to big enough to hold the server_version variable */
743
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
744 745
    ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
			  CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
unknown's avatar
unknown committed
746

747 748 749 750 751
    if (opt_using_transactions)
      client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
    client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
unknown's avatar
unknown committed
752 753
#ifdef HAVE_OPENSSL
    if (ssl_acceptor_fd)
754
      client_flags |= CLIENT_SSL;       /* Wow, SSL is available! */
unknown's avatar
unknown committed
755
#endif /* HAVE_OPENSSL */
unknown's avatar
unknown committed
756

757 758 759 760 761 762 763 764 765 766 767
    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
768
      tail: that's why first part of the scramble is placed here, and second
769 770
      part at the end of packet.
    */
771
    end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
772 773 774
   
    int2store(end, client_flags);
    /* write server characteristics: up to 16 bytes allowed */
775
    end[2]=(char) default_charset_info->number;
776 777 778 779 780 781 782 783 784
    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
785
			  (uint) (end-buff)) ||
786
	(pkt_len= my_net_read(net)) == packet_error ||
unknown's avatar
unknown committed
787 788 789 790 791 792 793 794 795 796 797
	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
798
  if (thd->packet.alloc(thd->variables.net_buffer_length))
unknown's avatar
unknown committed
799 800 801
    return(ER_OUT_OF_RESOURCES);

  thd->client_capabilities=uint2korr(net->read_pos);
802 803 804 805 806 807 808 809 810 811 812
#ifdef TO_BE_REMOVED_IN_4_1_RELEASE
  /*
    This is just a safety check against any client that would use the old
    CLIENT_CHANGE_USER flag
  */
  if ((thd->client_capabilities & CLIENT_PROTOCOL_41) &&
      !(thd->client_capabilities & (CLIENT_RESERVED |
				    CLIENT_SECURE_CONNECTION |
				    CLIENT_MULTI_RESULTS)))
    thd->client_capabilities&= ~CLIENT_PROTOCOL_41;
#endif
813 814 815 816
  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
817 818 819 820 821 822 823
    DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
    /*
      Use server character set and collation if
      - client has not specified a character set
      - client character set is the same as the servers
      - client character set doesn't exists in server
    */
824
    if (!(thd->variables.character_set_client=
unknown's avatar
unknown committed
825 826 827 828
	  get_charset((uint) net->read_pos[8], MYF(0))) ||
	!my_strcasecmp(&my_charset_latin1,
		       global_system_variables.character_set_client->name,
		       thd->variables.character_set_client->name))
829
    {
830 831
      thd->variables.character_set_client=
	global_system_variables.character_set_client;
832 833
      thd->variables.collation_connection=
	global_system_variables.collation_connection;
834 835
      thd->variables.character_set_results=
	global_system_variables.character_set_results;
836 837 838
    }
    else
    {
839
      thd->variables.character_set_results=
840 841 842
      thd->variables.collation_connection= 
	thd->variables.character_set_client;
    }
unknown's avatar
unknown committed
843
    thd->update_charset();
844
    end= (char*) net->read_pos+32;
845 846 847 848 849 850 851
  }
  else
  {
    thd->max_client_packet_length= uint3korr(net->read_pos+2);
    end= (char*) net->read_pos+5;
  }

852
  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
853
    thd->variables.sql_mode|= MODE_IGNORE_SPACE;
unknown's avatar
unknown committed
854
#ifdef HAVE_OPENSSL
unknown's avatar
unknown committed
855
  DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
unknown's avatar
unknown committed
856 857 858
  if (thd->client_capabilities & CLIENT_SSL)
  {
    /* Do the SSL layering. */
859 860 861 862 863
    if (!ssl_acceptor_fd)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
unknown's avatar
unknown committed
864
    DBUG_PRINT("info", ("IO layer change in progress..."));
unknown's avatar
unknown committed
865 866 867 868 869
    if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
    {
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
      inc_host_errors(&thd->remote.sin_addr);
unknown's avatar
unknown committed
870
      return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
871
    }
unknown's avatar
unknown committed
872
    DBUG_PRINT("info", ("Reading user information over SSL layer"));
873
    if ((pkt_len= my_net_read(net)) == packet_error ||
unknown's avatar
unknown committed
874 875
	pkt_len < NORMAL_HANDSHAKE_SIZE)
    {
unknown's avatar
unknown committed
876 877
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
unknown's avatar
unknown committed
878 879 880 881
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
  }
882 883 884
#endif

  if (end >= (char*) net->read_pos+ pkt_len +2)
unknown's avatar
unknown committed
885
  {
886 887
    inc_host_errors(&thd->remote.sin_addr);
    return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
888 889 890
  }

  if (thd->client_capabilities & CLIENT_INTERACTIVE)
891
    thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
892
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
893 894
      opt_using_transactions)
    net->return_status= &thd->server_status;
unknown's avatar
unknown committed
895
  net->read_timeout=(uint) thd->variables.net_read_timeout;
unknown's avatar
unknown committed
896

897 898
  char *user= end;
  char *passwd= strend(user)+1;
unknown's avatar
unknown committed
899
  char *db= passwd;
900
  char db_buff[NAME_LEN+1];                     // buffer to store db in utf8
unknown's avatar
unknown committed
901
  char user_buff[USERNAME_LENGTH+1];		// buffer to store user in utf8
902 903 904
  uint dummy_errors;

  /*
unknown's avatar
unknown committed
905 906 907 908
    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'.
  */
909
  uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
unknown's avatar
unknown committed
910 911 912
    *passwd++ : strlen(passwd);
  db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
    db + passwd_len + 1 : 0;
unknown's avatar
unknown committed
913

unknown's avatar
unknown committed
914 915
  /* Since 4.1 all database names are stored in utf8 */
  if (db)
unknown's avatar
unknown committed
916
  {
unknown's avatar
unknown committed
917 918 919
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
                             system_charset_info,
                             db, strlen(db),
unknown's avatar
unknown committed
920
                             thd->charset(), &dummy_errors)]= 0;
921
    db= db_buff;
unknown's avatar
unknown committed
922
  }
unknown's avatar
unknown committed
923

924 925 926 927
  user_buff[copy_and_convert(user_buff, sizeof(user_buff)-1,
                             system_charset_info, user, strlen(user),
                             thd->charset(), &dummy_errors)]= '\0';
  user= user_buff;
unknown's avatar
unknown committed
928

929 930
  if (thd->user)
    x_free(thd->user);
931 932
  if (!(thd->user= my_strdup(user, MYF(0))))
    return (ER_OUT_OF_RESOURCES);
unknown's avatar
unknown committed
933
  return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
unknown's avatar
unknown committed
934 935
}

936

937 938
void execute_init_command(THD *thd, sys_var_str *init_command_var,
			  rw_lock_t *var_mutex)
unknown's avatar
SCRUM:  
unknown committed
939 940 941 942
{
  Vio* save_vio;
  ulong save_client_capabilities;

943 944 945 946 947 948 949 950 951
  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
SCRUM:  
unknown committed
952 953
  save_client_capabilities= thd->client_capabilities;
  thd->client_capabilities|= CLIENT_MULTI_QUERIES;
954 955 956 957
  /*
    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
SCRUM:  
unknown committed
958 959 960
  save_vio= thd->net.vio;
  thd->net.vio= 0;
  dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
961
  rw_unlock(var_mutex);
unknown's avatar
SCRUM:  
unknown committed
962 963 964 965 966
  thd->client_capabilities= save_client_capabilities;
  thd->net.vio= save_vio;
}


unknown's avatar
unknown committed
967 968 969 970
pthread_handler_decl(handle_one_connection,arg)
{
  THD *thd=(THD*) arg;
  uint launch_time  =
unknown's avatar
unknown committed
971
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
unknown's avatar
unknown committed
972 973 974 975 976
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status );

  pthread_detach_this_thread();

977
#if !defined( __WIN__) && !defined(OS2)	// Win32 calls this in pthread_create
unknown's avatar
unknown committed
978
  /* The following calls needs to be done before we call DBUG_ macros */
979
  if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
unknown's avatar
unknown committed
980
  {
981
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
982
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
983 984 985 986 987
    end_thread(thd,0);
    return 0;
  }
#endif

988 989 990 991 992 993 994
  /*
    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
995 996
  DBUG_PRINT("info", ("handle_one_connection called by thread %d\n",
		      thd->thread_id));
unknown's avatar
unknown committed
997
  /* now that we've called my_thread_init(), it is safe to call DBUG_* */
unknown's avatar
unknown committed
998

unknown's avatar
unknown committed
999
#if defined(__WIN__)
unknown's avatar
unknown committed
1000
  init_signals();				// IRENA; testing ?
unknown's avatar
unknown committed
1001
#elif !defined(OS2) && !defined(__NETWARE__)
unknown's avatar
unknown committed
1002 1003 1004 1005 1006 1007
  sigset_t set;
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
  if (thd->store_globals())
  {
1008
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
1009
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
    end_thread(thd,0);
    return 0;
  }

  do
  {
    int error;
    NET *net= &thd->net;
    thd->thread_stack= (char*) &thd;

1020
    if ((error=check_connection(thd)))
unknown's avatar
unknown committed
1021 1022
    {						// Wrong permissions
      if (error > 0)
1023
	net_printf_error(thd, error, thd->host_or_ip);
unknown's avatar
unknown committed
1024 1025
#ifdef __NT__
      if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
1026
	my_sleep(1000);				/* must wait after eof() */
unknown's avatar
unknown committed
1027
#endif
1028
      statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
1029 1030
      goto end_thread;
    }
unknown's avatar
unknown committed
1031 1032 1033
#ifdef __NETWARE__
    netware_reg_user(thd->ip, thd->user, "MySQL");
#endif
1034
    if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
1035 1036 1037 1038
      thd->options |= OPTION_BIG_SELECTS;
    if (thd->client_capabilities & CLIENT_COMPRESS)
      net->compress=1;				// Use compression

unknown's avatar
SCRUM:  
unknown committed
1039
    thd->version= refresh_version;
1040
    thd->proc_info= 0;
1041
    thd->command= COM_SLEEP;
1042 1043
    thd->set_time();
    thd->init_for_queries();
unknown's avatar
unknown committed
1044

unknown's avatar
unknown committed
1045
    if (sys_init_connect.value_length && !(thd->master_access & SUPER_ACL))
unknown's avatar
SCRUM:  
unknown committed
1046
    {
1047 1048
      execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
      if (thd->query_error)
unknown's avatar
unknown committed
1049
	thd->killed= THD::KILL_CONNECTION;
unknown's avatar
SCRUM:  
unknown committed
1050 1051 1052
    }

    thd->proc_info=0;
unknown's avatar
unknown committed
1053
    thd->set_time();
unknown's avatar
unknown committed
1054
    thd->init_for_queries();
unknown's avatar
SCRUM  
unknown committed
1055
    while (!net->error && net->vio != 0 && !(thd->killed == THD::KILL_CONNECTION))
unknown's avatar
unknown committed
1056 1057 1058 1059
    {
      if (do_command(thd))
	break;
    }
unknown's avatar
unknown committed
1060 1061
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
unknown's avatar
unknown committed
1062
    if (net->error && net->vio != 0 && net->report_error)
unknown's avatar
unknown committed
1063
    {
1064
      if (!thd->killed && thd->variables.log_warnings > 1)
unknown's avatar
unknown committed
1065
	sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
unknown's avatar
unknown committed
1066 1067 1068 1069 1070
                          thd->thread_id,(thd->db ? thd->db : "unconnected"),
                          thd->user ? thd->user : "unauthenticated",
                          thd->host_or_ip,
                          (net->last_errno ? ER(net->last_errno) :
                           ER(ER_UNKNOWN_ERROR)));
1071
      net_send_error(thd, net->last_errno, NullS);
unknown's avatar
unknown committed
1072
      statistic_increment(aborted_threads,&LOCK_status);
unknown's avatar
unknown committed
1073
    }
1074 1075 1076 1077
    else if (thd->killed)
    {
      statistic_increment(aborted_threads,&LOCK_status);
    }
unknown's avatar
unknown committed
1078
    
unknown's avatar
unknown committed
1079
end_thread:
1080
    close_connection(thd, 0, 1);
unknown's avatar
unknown committed
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
    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;
  } 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
1092 1093
#endif /* EMBEDDED_LIBRARY */

1094 1095 1096 1097
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
unknown's avatar
unknown committed
1098

1099
extern "C" pthread_handler_decl(handle_bootstrap,arg)
unknown's avatar
unknown committed
1100
{
1101 1102 1103
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
unknown's avatar
unknown committed
1104

1105
  /* The following must be called before DBUG_ENTER */
1106
  if (my_thread_init() || thd->store_globals())
unknown's avatar
unknown committed
1107
  {
unknown's avatar
unknown committed
1108
#ifndef EMBEDDED_LIBRARY
1109
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
unknown's avatar
unknown committed
1110
#endif
1111
    thd->fatal_error();
1112
    goto end;
unknown's avatar
unknown committed
1113
  }
1114 1115
  DBUG_ENTER("handle_bootstrap");

unknown's avatar
unknown committed
1116
#ifndef EMBEDDED_LIBRARY
1117 1118
  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
1119
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
unknown's avatar
unknown committed
1120
  sigset_t set;
1121 1122
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
unknown's avatar
unknown committed
1123
#endif
unknown's avatar
unknown committed
1124
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
1125

1126
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
1127 1128 1129 1130
    thd->options |= OPTION_BIG_SELECTS;

  thd->proc_info=0;
  thd->version=refresh_version;
1131
  thd->priv_user=thd->user=(char*) my_strdup("boot", MYF(MY_WME));
unknown's avatar
unknown committed
1132

1133
  buff= (char*) thd->net.buff;
unknown's avatar
unknown committed
1134
  thd->init_for_queries();
unknown's avatar
unknown committed
1135 1136
  while (fgets(buff, thd->net.max_packet, file))
  {
unknown's avatar
unknown committed
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
   ulong length= (ulong) strlen(buff);
   while (buff[length-1] != '\n' && !feof(file))
   {
     /*
       We got only a part of the current string. Will try to increase
       net buffer then read the rest of the current string.
     */
     if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
     {
       net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS);
       thd->fatal_error();
       break;
     }
     buff= (char*) thd->net.buff;
     fgets(buff + length, thd->net.max_packet - length, file);
     length+= (ulong) strlen(buff + length);
   }
   if (thd->is_fatal_error)
     break;

unknown's avatar
unknown committed
1157
    while (length && (my_isspace(thd->charset(), buff[length-1]) ||
1158
           buff[length-1] == ';'))
unknown's avatar
unknown committed
1159 1160
      length--;
    buff[length]=0;
1161
    thd->query_length=length;
unknown's avatar
unknown committed
1162 1163
    thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
    thd->query[length] = '\0';
1164 1165 1166 1167
    /*
      We don't need to obtain LOCK_thread_count here because in bootstrap
      mode we have only one thread.
    */
unknown's avatar
unknown committed
1168
    thd->query_id=query_id++;
1169
    if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
unknown's avatar
unknown committed
1170 1171 1172
    {
      thd->net.error = 0;
      close_thread_tables(thd);			// Free tables
unknown's avatar
unknown committed
1173
      free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1174 1175
      break;
    }
unknown's avatar
unknown committed
1176 1177
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
1178
    if (thd->is_fatal_error)
1179
      break;
unknown's avatar
unknown committed
1180
    free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
1181
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1182
  }
1183 1184 1185

  /* thd->fatal_error should be set in case something went wrong */
end:
unknown's avatar
unknown committed
1186
#ifndef EMBEDDED_LIBRARY
1187 1188 1189
  (void) pthread_mutex_lock(&LOCK_thread_count);
  thread_count--;
  (void) pthread_mutex_unlock(&LOCK_thread_count);
1190
  (void) pthread_cond_broadcast(&COND_thread_count);
1191 1192
  my_thread_end();
  pthread_exit(0);
unknown's avatar
unknown committed
1193
#endif
1194
  DBUG_RETURN(0);				// Never reached
unknown's avatar
unknown committed
1195 1196
}

1197
    /* This works because items are allocated with sql_alloc() */
unknown's avatar
unknown committed
1198

1199
void free_items(Item *item)
unknown's avatar
unknown committed
1200
{
unknown's avatar
unknown committed
1201
  Item *next;
unknown's avatar
unknown committed
1202
  DBUG_ENTER("free_items");
unknown's avatar
unknown committed
1203 1204 1205
  for (; item ; item=next)
  {
    next=item->next;
unknown's avatar
unknown committed
1206
    item->delete_self();
unknown's avatar
unknown committed
1207
  }
unknown's avatar
unknown committed
1208
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
1209 1210
}

1211 1212 1213 1214 1215 1216 1217 1218
    /* This works because items are allocated with sql_alloc() */

void cleanup_items(Item *item)
{
  for (; item ; item=item->next)
    item->cleanup();
}

unknown's avatar
unknown committed
1219 1220 1221 1222 1223 1224 1225
int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
{
  TABLE* table;
  TABLE_LIST* table_list;
  int error = 0;
  DBUG_ENTER("mysql_table_dump");
  db = (db && db[0]) ? db : thd->db;
1226
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
1227
    DBUG_RETURN(1); // out of memory
unknown's avatar
VIEW  
unknown committed
1228
  table_list->db= db;
1229
  table_list->table_name= table_list->alias= tbl_name;
unknown's avatar
VIEW  
unknown committed
1230 1231
  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
1232

unknown's avatar
unknown committed
1233 1234
  if (!db || check_db_name(db))
  {
1235
    my_error(ER_WRONG_DB_NAME ,MYF(0), db ? db : "NULL");
unknown's avatar
unknown committed
1236 1237
    goto err;
  }
1238
  if (lower_case_table_names)
1239
    my_casedn_str(files_charset_info, tbl_name);
1240
  remove_escape(table_list->table_name);
1241 1242 1243 1244

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

unknown's avatar
unknown committed
1245
  if (check_one_table_access(thd, SELECT_ACL, table_list))
unknown's avatar
unknown committed
1246 1247
    goto err;
  thd->free_list = 0;
unknown's avatar
unknown committed
1248
  thd->query_length=(uint) strlen(tbl_name);
unknown's avatar
unknown committed
1249
  thd->query = tbl_name;
unknown's avatar
unknown committed
1250
  if ((error = mysqld_dump_create_info(thd, table_list, -1)))
1251
  {
1252
    my_error(ER_GET_ERRNO, MYF(0), my_errno);
1253 1254
    goto err;
  }
unknown's avatar
unknown committed
1255
  net_flush(&thd->net);
1256
  if ((error= table->file->dump(thd,fd)))
1257
    my_error(ER_GET_ERRNO, MYF(0), error);
unknown's avatar
unknown committed
1258

unknown's avatar
unknown committed
1259 1260
err:
  close_thread_tables(thd);
unknown's avatar
unknown committed
1261
  DBUG_RETURN(error);
unknown's avatar
unknown committed
1262 1263 1264
}


1265
#ifndef EMBEDDED_LIBRARY
1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276

/*
  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
1277 1278 1279
bool do_command(THD *thd)
{
  char *packet;
unknown's avatar
unknown committed
1280 1281
  uint old_timeout;
  ulong packet_length;
unknown's avatar
unknown committed
1282 1283 1284 1285 1286
  NET *net;
  enum enum_server_command command;
  DBUG_ENTER("do_command");

  net= &thd->net;
unknown's avatar
unknown committed
1287 1288 1289 1290
  /*
    indicator of uninitialized lex => normal flow of errors handling
    (see my_message_sql)
  */
1291
  thd->lex->current_select= 0;
unknown's avatar
unknown committed
1292 1293

  packet=0;
unknown's avatar
unknown committed
1294
  old_timeout=net->read_timeout;
unknown's avatar
unknown committed
1295
  /* Wait max for 8 hours */
unknown's avatar
unknown committed
1296
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
unknown's avatar
unknown committed
1297
  thd->clear_error();				// Clear error message
unknown's avatar
unknown committed
1298 1299 1300 1301

  net_new_transaction(net);
  if ((packet_length=my_net_read(net)) == packet_error)
  {
1302 1303 1304 1305 1306
    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)
1307 1308
    {
      statistic_increment(aborted_threads,&LOCK_status);
1309
      DBUG_RETURN(TRUE);			// We have to close it.
1310
    }
1311
    net_send_error(thd, net->last_errno, NullS);
1312
    net->error= 0;
1313
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
1314 1315 1316
  }
  else
  {
unknown's avatar
unknown committed
1317
    if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
unknown's avatar
SCRUM  
unknown committed
1318
      thd->killed= THD::NOT_KILLED;
unknown's avatar
SCRUM  
unknown committed
1319

unknown's avatar
unknown committed
1320 1321
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
1322 1323
    if (command >= COM_END)
      command= COM_END;				// Wrong command
unknown's avatar
unknown committed
1324 1325 1326
    DBUG_PRINT("info",("Command on %s = %d (%s)",
		       vio_description(net->vio), command,
		       command_name[command]));
unknown's avatar
unknown committed
1327
  }
unknown's avatar
unknown committed
1328
  net->read_timeout=old_timeout;		// restore it
1329 1330 1331 1332 1333 1334 1335 1336 1337
  /*
    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
1338
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
1339
}
1340
#endif  /* EMBEDDED_LIBRARY */
1341

1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356
/*
   Perform one connection-level (COM_XXXX) command.
  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
*/
1357

1358 1359 1360 1361
bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
1362
  bool error= 0;
1363 1364 1365
  DBUG_ENTER("dispatch_command");

  thd->command=command;
unknown's avatar
unknown committed
1366 1367 1368 1369
  /*
    Commands which will always take a long time should be marked with
    this so that they will not get logged to the slow query log
  */
1370
  thd->slow_command=FALSE;
1371
  thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
unknown's avatar
unknown committed
1372
  thd->set_time();
unknown's avatar
unknown committed
1373 1374 1375 1376 1377
  VOID(pthread_mutex_lock(&LOCK_thread_count));
  thd->query_id=query_id;
  if (command != COM_STATISTICS && command != COM_PING)
    query_id++;
  thread_running++;
1378
  /* TODO: set thd->lex->sql_command to SQLCOM_END here */
unknown's avatar
unknown committed
1379
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1380

1381 1382
  thd->server_status&=
           ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
1383
  switch (command) {
unknown's avatar
unknown committed
1384
  case COM_INIT_DB:
unknown's avatar
unknown committed
1385 1386
  {
    LEX_STRING tmp;
1387 1388
    statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB],
			&LOCK_status);
unknown's avatar
unknown committed
1389 1390 1391 1392 1393 1394
    thd->convert_string(&tmp, system_charset_info,
			packet, strlen(packet), thd->charset());
    if (!mysql_change_db(thd, tmp.str))
      mysql_log.write(thd,command,"%s",thd->db);
    break;
  }
unknown's avatar
unknown committed
1395
#ifdef HAVE_REPLICATION
1396 1397
  case COM_REGISTER_SLAVE:
  {
1398
    if (!register_slave(thd, (uchar*)packet, packet_length))
1399
      send_ok(thd);
1400 1401
    break;
  }
1402
#endif
unknown's avatar
unknown committed
1403
  case COM_TABLE_DUMP:
1404 1405 1406 1407 1408
  {
    char *db, *tbl_name;
    uint db_len= *(uchar*) packet;
    uint tbl_len= *(uchar*) (packet + db_len + 1);

1409
    statistic_increment(thd->status_var.com_other, &LOCK_status);
1410
    thd->slow_command= TRUE;
1411 1412 1413
    db= thd->alloc(db_len + tbl_len + 2);
    tbl_name= strmake(db, packet + 1, db_len)+1;
    strmake(tbl_name, packet + db_len + 2, tbl_len);
unknown's avatar
unknown committed
1414
    mysql_table_dump(thd, db, tbl_name, -1);
1415 1416
    break;
  }
unknown's avatar
unknown committed
1417 1418
  case COM_CHANGE_USER:
  {
unknown's avatar
unknown committed
1419
    thd->change_user();
1420
    thd->clear_error();                         // if errors from rollback
unknown's avatar
unknown committed
1421

1422
    statistic_increment(thd->status_var.com_other, &LOCK_status);
1423
    char *user= (char*) packet;
unknown's avatar
unknown committed
1424
    char *passwd= strend(user)+1;
unknown's avatar
unknown committed
1425 1426 1427 1428 1429
    /* 
      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).
    */
unknown's avatar
unknown committed
1430
    char db_buff[NAME_LEN+1];                 // buffer to store db in utf8 
unknown's avatar
unknown committed
1431 1432 1433 1434
    char *db= passwd;
    uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? 
      *passwd++ : strlen(passwd);
    db+= passwd_len + 1;
1435
#ifndef EMBEDDED_LIBRARY
1436
    /* Small check for incoming packet */
unknown's avatar
unknown committed
1437
    if ((uint) ((uchar*) db - net->read_pos) > packet_length)
1438
    {
unknown's avatar
unknown committed
1439
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1440 1441
      break;
    }
1442
#endif
1443
    /* Convert database name to utf8 */
unknown's avatar
unknown committed
1444
    uint dummy_errors;
unknown's avatar
unknown committed
1445 1446
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
                             system_charset_info, db, strlen(db),
unknown's avatar
unknown committed
1447
                             thd->charset(), &dummy_errors)]= 0;
unknown's avatar
unknown committed
1448
    db= db_buff;
unknown's avatar
unknown committed
1449

1450 1451 1452 1453 1454 1455 1456
    /* Save user and privileges */
    uint save_master_access= thd->master_access;
    uint save_db_access= thd->db_access;
    uint save_db_length= thd->db_length;
    char *save_user= thd->user;
    char *save_priv_user= thd->priv_user;
    char *save_db= thd->db;
unknown's avatar
unknown committed
1457
    USER_CONN *save_user_connect= thd->user_connect;
unknown's avatar
unknown committed
1458 1459
    
    if (!(thd->user= my_strdup(user, MYF(0))))
1460 1461
    {
      thd->user= save_user;
unknown's avatar
unknown committed
1462
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
1463 1464
      break;
    }
unknown's avatar
unknown committed
1465

unknown's avatar
unknown committed
1466 1467
    /* Clear variables that are allocated */
    thd->user_connect= 0;
unknown's avatar
unknown committed
1468
    int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
unknown's avatar
unknown committed
1469

1470 1471
    if (res)
    {
1472
      /* authentication failure, we shall restore old user */
1473
      if (res > 0)
unknown's avatar
unknown committed
1474
        my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1475 1476 1477
      x_free(thd->user);
      thd->user= save_user;
      thd->priv_user= save_priv_user;
unknown's avatar
unknown committed
1478
      thd->user_connect= save_user_connect;
1479 1480 1481 1482 1483 1484 1485 1486
      thd->master_access= save_master_access;
      thd->db_access= save_db_access;
      thd->db= save_db;
      thd->db_length= save_db_length;
    }
    else
    {
      /* we've authenticated new user */
unknown's avatar
unknown committed
1487 1488
      if (save_user_connect)
	decrease_user_connections(save_user_connect);
1489 1490 1491
      x_free((gptr) save_db);
      x_free((gptr) save_user);
    }
unknown's avatar
unknown committed
1492 1493
    break;
  }
unknown's avatar
unknown committed
1494 1495
  case COM_EXECUTE:
  {
1496
    mysql_stmt_execute(thd, packet, packet_length);
unknown's avatar
unknown committed
1497 1498
    break;
  }
1499 1500 1501 1502 1503
  case COM_FETCH:
  {
    mysql_stmt_fetch(thd, packet, packet_length);
    break;
  }
unknown's avatar
unknown committed
1504 1505
  case COM_LONG_DATA:
  {
1506
    mysql_stmt_get_longdata(thd, packet, packet_length);
unknown's avatar
unknown committed
1507 1508 1509 1510
    break;
  }
  case COM_PREPARE:
  {
1511
    mysql_stmt_prepare(thd, packet, packet_length);
unknown's avatar
unknown committed
1512 1513
    break;
  }
unknown's avatar
unknown committed
1514 1515 1516 1517 1518
  case COM_CLOSE_STMT:
  {
    mysql_stmt_free(thd, packet);
    break;
  }
1519 1520 1521 1522 1523
  case COM_RESET_STMT:
  {
    mysql_stmt_reset(thd, packet);
    break;
  }
unknown's avatar
unknown committed
1524 1525
  case COM_QUERY:
  {
1526 1527
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
1528
    mysql_log.write(thd,command,"%s",thd->query);
1529
    DBUG_PRINT("query",("%-.4096s",thd->query));
1530
    mysql_parse(thd,thd->query, thd->query_length);
1531

1532
    while (!thd->killed && thd->lex->found_colon && !thd->net.report_error)
1533
    {
unknown's avatar
unknown committed
1534
      char *packet= thd->lex->found_colon;
1535
      /*
1536
        Multiple queries exits, execute them individually
1537
	in embedded server - just store them to be executed later 
1538
      */
1539
#ifndef EMBEDDED_LIBRARY
1540
      if (thd->lock || thd->open_tables || thd->derived_tables)
1541
        close_thread_tables(thd);
1542 1543
#endif
      ulong length= thd->query_length-(ulong)(packet-thd->query);
1544

1545
      /* Remove garbage at start of query */
unknown's avatar
unknown committed
1546
      while (my_isspace(thd->charset(), *packet) && length > 0)
1547 1548 1549 1550
      {
        packet++;
        length--;
      }
unknown's avatar
unknown committed
1551
      VOID(pthread_mutex_lock(&LOCK_thread_count));
1552
      thd->query_length= length;
1553 1554
      thd->query= packet;
      thd->query_id= query_id++;
1555
      /* TODO: set thd->lex->sql_command to SQLCOM_END here */
1556
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
1557
#ifndef EMBEDDED_LIBRARY
1558
      mysql_parse(thd, packet, length);
1559
#else
unknown's avatar
unknown committed
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569
      /*
	'packet' can point inside the query_rest's buffer
	so we have to do memmove here
       */
      if (thd->query_rest.length() > length)
      {
	memmove(thd->query_rest.c_ptr(), packet, length);
	thd->query_rest.length(length);
      }
      else
1570
	thd->query_rest.copy(packet, length, thd->query_rest.charset());
1571 1572
      break;
#endif /*EMBEDDED_LIBRARY*/
1573 1574
    }

unknown's avatar
unknown committed
1575 1576 1577 1578 1579
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1580
  case COM_FIELD_LIST:				// This isn't actually needed
unknown's avatar
unknown committed
1581
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1582 1583
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
unknown's avatar
unknown committed
1584 1585 1586
    break;
#else
  {
1587
    char *fields, *pend;
unknown's avatar
unknown committed
1588
    TABLE_LIST table_list;
unknown's avatar
unknown committed
1589 1590
    LEX_STRING conv_name;

1591 1592
    statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
			&LOCK_status);
unknown's avatar
unknown committed
1593 1594 1595
    bzero((char*) &table_list,sizeof(table_list));
    if (!(table_list.db=thd->db))
    {
unknown's avatar
unknown committed
1596
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
unknown's avatar
unknown committed
1597 1598
      break;
    }
1599
    pend= strend(packet);
unknown's avatar
unknown committed
1600 1601
    thd->convert_string(&conv_name, system_charset_info,
			packet, (uint) (pend-packet), thd->charset());
1602
    table_list.alias= table_list.table_name= conv_name.str;
1603
    packet= pend+1;
1604 1605 1606 1607 1608 1609 1610 1611 1612

    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;
    }

1613
    thd->query_length= strlen(packet);       // for simplicity: don't optimize
unknown's avatar
unknown committed
1614 1615
    if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
      break;
1616
    mysql_log.write(thd,command,"%s %s",table_list.table_name, fields);
1617
    if (lower_case_table_names)
1618 1619
      my_casedn_str(files_charset_info, table_list.table_name);
    remove_escape(table_list.table_name);	// This can't have wildcards
unknown's avatar
unknown committed
1620

unknown's avatar
unknown committed
1621 1622
    if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
		     0, 0))
unknown's avatar
unknown committed
1623
      break;
unknown's avatar
unknown committed
1624 1625
    if (grant_option &&
	check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
1626
      break;
1627 1628 1629 1630 1631 1632 1633
    /* 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);

1634 1635
    /* switch on VIEW optimisation: do not fill temporary tables */
    thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
unknown's avatar
unknown committed
1636
    mysqld_list_fields(thd,&table_list,fields);
1637
    thd->lex->unit.cleanup();
1638
    thd->cleanup_after_query();
unknown's avatar
unknown committed
1639 1640 1641 1642
    break;
  }
#endif
  case COM_QUIT:
1643
    /* We don't calculate statistics for this command */
1644
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1645 1646 1647 1648
    net->error=0;				// Don't give 'abort' message
    error=TRUE;					// End server
    break;

unknown's avatar
unknown committed
1649
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1650
    {
unknown's avatar
unknown committed
1651
      char *db=thd->strdup(packet), *alias;
1652
      HA_CREATE_INFO create_info;
unknown's avatar
unknown committed
1653

1654 1655
      statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB],
			  &LOCK_status);
unknown's avatar
unknown committed
1656
      // null test to handle EOM
unknown's avatar
unknown committed
1657
      if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
unknown's avatar
unknown committed
1658
      {
1659
	my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
unknown's avatar
unknown committed
1660 1661
	break;
      }
unknown's avatar
SCRUM:  
unknown committed
1662
      if (check_access(thd,CREATE_ACL,db,0,1,0))
unknown's avatar
unknown committed
1663
	break;
1664
      mysql_log.write(thd,command,packet);
1665
      bzero(&create_info, sizeof(create_info));
1666 1667
      mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
                      &create_info, 0);
unknown's avatar
unknown committed
1668 1669
      break;
    }
unknown's avatar
unknown committed
1670
  case COM_DROP_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1671
    {
1672 1673
      statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB],
			  &LOCK_status);
unknown's avatar
unknown committed
1674
      char *db=thd->strdup(packet), *alias;
unknown's avatar
unknown committed
1675
      /*  null test to handle EOM */
unknown's avatar
unknown committed
1676
      if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
unknown's avatar
unknown committed
1677
      {
1678
	my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
unknown's avatar
unknown committed
1679 1680
	break;
      }
unknown's avatar
SCRUM:  
unknown committed
1681
      if (check_access(thd,DROP_ACL,db,0,1,0))
1682
	break;
unknown's avatar
unknown committed
1683 1684
      if (thd->locked_tables || thd->active_transaction())
      {
unknown's avatar
unknown committed
1685 1686
	my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                   ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
unknown's avatar
unknown committed
1687
	break;
unknown's avatar
unknown committed
1688
      }
1689
      mysql_log.write(thd,command,db);
1690 1691
      mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : db),
                       0, 0);
unknown's avatar
unknown committed
1692 1693
      break;
    }
1694
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1695 1696
  case COM_BINLOG_DUMP:
    {
unknown's avatar
unknown committed
1697 1698 1699 1700
      ulong pos;
      ushort flags;
      uint32 slave_server_id;

1701
      statistic_increment(thd->status_var.com_other,&LOCK_status);
1702
      thd->slow_command = TRUE;
unknown's avatar
unknown committed
1703
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1704
	break;
unknown's avatar
unknown committed
1705

1706
      /* TODO: The following has to be changed to an 8 byte integer */
1707 1708
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
1709
      thd->server_id=0; /* avoid suicide */
unknown's avatar
unknown committed
1710
      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
unknown's avatar
unknown committed
1711
	kill_zombie_dump_threads(slave_server_id);
1712
      thd->server_id = slave_server_id;
unknown's avatar
unknown committed
1713 1714 1715

      mysql_log.write(thd, command, "Log: '%s'  Pos: %ld", packet+10,
                      (long) pos);
1716
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1717
      unregister_slave(thd,1,1);
unknown's avatar
unknown committed
1718
      /*  fake COM_QUIT -- if we get here, the thread needs to terminate */
1719 1720
      error = TRUE;
      net->error = 0;
unknown's avatar
unknown committed
1721 1722
      break;
    }
1723
#endif
unknown's avatar
unknown committed
1724 1725
  case COM_REFRESH:
    {
1726 1727
      statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH],
			  &LOCK_status);
unknown's avatar
unknown committed
1728
      ulong options= (ulong) (uchar) packet[0];
unknown's avatar
unknown committed
1729
      if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1730
	break;
1731
      mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1732
      if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, NULL))
1733
        send_ok(thd);
unknown's avatar
unknown committed
1734 1735
      break;
    }
1736
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1737
  case COM_SHUTDOWN:
1738
  {
1739
    statistic_increment(thd->status_var.com_other, &LOCK_status);
unknown's avatar
unknown committed
1740
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1741
      break; /* purecov: inspected */
1742
    /*
1743 1744 1745 1746
      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].
1747
    */
1748 1749
    enum mysql_enum_shutdown_level level=
      (enum mysql_enum_shutdown_level) (uchar) packet[0];
1750
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
1751 1752 1753 1754 1755 1756 1757
    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;
    }
1758
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
1759
    mysql_log.write(thd,command,NullS);
1760
    send_eof(thd);
unknown's avatar
unknown committed
1761 1762 1763
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
unknown's avatar
unknown committed
1764
#ifndef OS2
1765
    send_eof(thd);				// This is for 'quit request'
unknown's avatar
unknown committed
1766
#endif
1767
    close_connection(thd, 0, 1);
unknown's avatar
unknown committed
1768 1769 1770 1771
    close_thread_tables(thd);			// Free before kill
    kill_mysql();
    error=TRUE;
    break;
1772
  }
1773
#endif
unknown's avatar
unknown committed
1774 1775
  case COM_STATISTICS:
  {
1776
    mysql_log.write(thd,command,NullS);
1777 1778
    statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS],
			&LOCK_status);
unknown's avatar
unknown committed
1779
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1780
    char buff[200];
unknown's avatar
unknown committed
1781 1782 1783
#else
    char *buff= thd->net.last_error;
#endif
1784
    ulong uptime = (ulong) (thd->start_time - start_time);
unknown's avatar
unknown committed
1785
    sprintf((char*) buff,
1786
	    "Uptime: %ld  Threads: %d  Questions: %lu  Slow queries: %ld  Opens: %ld  Flush tables: %ld  Open tables: %u  Queries per second avg: %.3f",
unknown's avatar
unknown committed
1787
	    uptime,
1788 1789
	    (int) thread_count,thd->query_id,thd->status_var.long_query_count,
	    thd->status_var.opened_tables,refresh_version, cached_tables(),
unknown's avatar
unknown committed
1790 1791
	    uptime ? (float)thd->query_id/(float)uptime : 0);
#ifdef SAFEMALLOC
1792
    if (sf_malloc_cur_memory)				// Using SAFEMALLOC
unknown's avatar
unknown committed
1793
      sprintf(strend(buff), "  Memory in use: %ldK  Max memory used: %ldK",
1794 1795
	      (sf_malloc_cur_memory+1023L)/1024L,
	      (sf_malloc_max_memory+1023L)/1024L);
unknown's avatar
unknown committed
1796 1797
#endif
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1798
    VOID(my_net_write(net, buff,(uint) strlen(buff)));
unknown's avatar
unknown committed
1799
    VOID(net_flush(net));
unknown's avatar
unknown committed
1800
#endif
unknown's avatar
unknown committed
1801 1802 1803
    break;
  }
  case COM_PING:
1804
    statistic_increment(thd->status_var.com_other, &LOCK_status);
1805
    send_ok(thd);				// Tell client we are alive
unknown's avatar
unknown committed
1806 1807
    break;
  case COM_PROCESS_INFO:
1808 1809
    statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
			&LOCK_status);
unknown's avatar
unknown committed
1810
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
1811
      break;
1812
    mysql_log.write(thd,command,NullS);
unknown's avatar
SCRUM:  
unknown committed
1813 1814
    mysqld_list_processes(thd,
			  thd->master_access & PROCESS_ACL ? 
unknown's avatar
unknown committed
1815
			  NullS : thd->priv_user, 0);
unknown's avatar
unknown committed
1816 1817 1818
    break;
  case COM_PROCESS_KILL:
  {
1819
    statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
1820
    ulong id=(ulong) uint4korr(packet);
unknown's avatar
SCRUM  
unknown committed
1821
    kill_one_thread(thd,id,false);
unknown's avatar
unknown committed
1822 1823
    break;
  }
1824 1825
  case COM_SET_OPTION:
  {
1826 1827
    statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION],
			&LOCK_status);
1828 1829 1830 1831
    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
1832
      send_eof(thd);
1833 1834 1835
      break;
    case MYSQL_OPTION_MULTI_STATEMENTS_OFF:
      thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
unknown's avatar
unknown committed
1836
      send_eof(thd);
1837 1838
      break;
    default:
unknown's avatar
unknown committed
1839
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1840 1841 1842 1843
      break;
    }
    break;
  }
unknown's avatar
unknown committed
1844
  case COM_DEBUG:
1845
    statistic_increment(thd->status_var.com_other, &LOCK_status);
unknown's avatar
unknown committed
1846
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1847 1848
      break;					/* purecov: inspected */
    mysql_print_status(thd);
1849
    mysql_log.write(thd,command,NullS);
1850
    send_eof(thd);
unknown's avatar
unknown committed
1851 1852 1853 1854 1855
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
1856
  case COM_END:
unknown's avatar
unknown committed
1857
  default:
unknown's avatar
unknown committed
1858
    my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
1859 1860
    break;
  }
1861
  if (thd->lock || thd->open_tables || thd->derived_tables)
unknown's avatar
unknown committed
1862 1863 1864 1865 1866
  {
    thd->proc_info="closing tables";
    close_thread_tables(thd);			/* Free tables */
  }

unknown's avatar
unknown committed
1867 1868 1869
  /* report error issued during command execution */
  if (thd->killed_errno() && !thd->net.report_error)
    thd->send_kill_message();
unknown's avatar
unknown committed
1870
  if (thd->net.report_error)
1871
    net_send_error(thd);
unknown's avatar
unknown committed
1872 1873

  time_t start_of_query=thd->start_time;
1874
  thd->end_time();				// Set start time
1875

1876
  /* If not reading from backup and if the query took too long */
1877
  if (!thd->slow_command && !thd->user_time) // do not log 'slow_command' queries
unknown's avatar
unknown committed
1878
  {
1879 1880
    thd->proc_info="logging slow query";

1881 1882
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
1883 1884
	((thd->server_status &
	  (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
1885
	 (specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES)))
1886
    {
1887
      thd->status_var.long_query_count++;
1888 1889
      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
    }
unknown's avatar
unknown committed
1890
  }
1891
  thd->proc_info="cleaning up";
unknown's avatar
unknown committed
1892 1893 1894 1895
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
  thd->proc_info=0;
  thd->command=COM_SLEEP;
  thd->query=0;
unknown's avatar
unknown committed
1896
  thd->query_length=0;
unknown's avatar
unknown committed
1897 1898
  thread_running--;
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1899
  thd->packet.shrink(thd->variables.net_buffer_length);	// Reclaim some memory
1900

unknown's avatar
unknown committed
1901
  free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1902 1903 1904
  DBUG_RETURN(error);
}

1905

1906 1907 1908 1909 1910
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;
1911
  switch (schema_table_idx) {
1912 1913
  case SCH_SCHEMATA:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
unknown's avatar
unknown committed
1914 1915
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0));   /* purecov: inspected */
1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926
    DBUG_RETURN(1);
#else
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
	check_global_access(thd, SHOW_DB_ACL))
      DBUG_RETURN(1);
    break;
#endif
  case SCH_TABLE_NAMES:
  case SCH_TABLES:
  case SCH_VIEWS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1927 1928
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1929 1930 1931 1932 1933 1934
    DBUG_RETURN(1);
#else
    {
      char *db= lex->select_lex.db ? lex->select_lex.db : thd->db;
      if (!db)
      {
unknown's avatar
unknown committed
1935 1936
	my_message(ER_NO_DB_ERROR,
                   ER(ER_NO_DB_ERROR), MYF(0)); /* purecov: inspected */
1937 1938 1939 1940 1941
        DBUG_RETURN(1);				/* purecov: inspected */
      }
      remove_escape(db);				// Fix escaped '_'
      if (check_db_name(db))
      {
unknown's avatar
unknown committed
1942
        my_error(ER_WRONG_DB_NAME, MYF(0), db);
1943 1944 1945 1946 1947 1948
        DBUG_RETURN(1);
      }
      if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
        DBUG_RETURN(1);			        /* purecov: inspected */
      if (!thd->col_access && check_grant_db(thd,db))
      {
unknown's avatar
unknown committed
1949 1950
	my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
                 thd->priv_user, thd->priv_host, db);
1951 1952
	DBUG_RETURN(1);
      }
1953 1954 1955 1956 1957
      /*
        We need to do a copy to make this prepared statement safe if this
        was thd->db
      */
      lex->select_lex.db= thd->strdup(db);
1958 1959 1960 1961 1962 1963
      break;
    }
#endif
  case SCH_COLUMNS:
  case SCH_STATISTICS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1964 1965
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979
    DBUG_RETURN(1);
#else
    if (table_ident)
    {
      TABLE_LIST **query_tables_last= lex->query_tables_last;
      sel= new SELECT_LEX();
      sel->init_query();
      if(!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, 
                                 (List<String> *) 0, (List<String> *) 0))
        DBUG_RETURN(1);
      lex->query_tables_last= query_tables_last;
      TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
      char *db= table_list->db;
      remove_escape(db);			// Fix escaped '_'
1980
      remove_escape(table_list->table_name);
1981 1982 1983 1984 1985 1986 1987 1988 1989
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
                       &table_list->grant.privilege, 0, 0))
        DBUG_RETURN(1);				/* purecov: inspected */
      if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2,
                                      UINT_MAX, 0))
        DBUG_RETURN(1);
      break;
    }
#endif
1990 1991 1992
  case SCH_OPEN_TABLES:
  case SCH_VARIABLES:
  case SCH_STATUS:
1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017
  case SCH_PROCEDURES:
  case SCH_CHARSETS:
  case SCH_COLLATIONS:
  case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
  case SCH_USER_PRIVILEGES:
  case SCH_SCHEMA_PRIVILEGES:
  case SCH_TABLE_PRIVILEGES:
  case SCH_COLUMN_PRIVILEGES:
  case SCH_TABLE_CONSTRAINTS:
  case SCH_KEY_COLUMN_USAGE:
  default:
    break;
  }
  
  SELECT_LEX *select_lex= lex->current_select;
  if (make_schema_select(thd, select_lex, schema_table_idx))
  {
    DBUG_RETURN(1);
  }
  TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
  table_list->schema_select_lex= sel;
  DBUG_RETURN(0);
}


2018 2019 2020 2021 2022 2023 2024 2025 2026 2027
/*
  Read query from packet and store in thd->query
  Used in COM_QUERY and COM_PREPARE

  DESCRIPTION
    Sets the following THD variables:
      query
      query_length

  RETURN VALUES
unknown's avatar
unknown committed
2028 2029
    FALSE ok
    TRUE  error;  In this case thd->fatal_error is set
2030 2031 2032 2033 2034
*/

bool alloc_query(THD *thd, char *packet, ulong packet_length)
{
  packet_length--;				// Remove end null
2035
  /* Remove garbage at start and end of query */
unknown's avatar
unknown committed
2036
  while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
2037 2038 2039 2040 2041
  {
    packet++;
    packet_length--;
  }
  char *pos=packet+packet_length;		// Point at end null
unknown's avatar
unknown committed
2042
  while (packet_length > 0 &&
unknown's avatar
unknown committed
2043
	 (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
2044 2045 2046 2047 2048
  {
    pos--;
    packet_length--;
  }
  /* We must allocate some extra memory for query cache */
unknown's avatar
unknown committed
2049
  thd->query_length= 0;                        // Extra safety: Avoid races
2050 2051
  if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
					      packet_length,
2052 2053
					      thd->db_length+ 1 +
					      QUERY_CACHE_FLAGS_SIZE)))
unknown's avatar
unknown committed
2054
    return TRUE;
2055 2056
  thd->query[packet_length]=0;
  thd->query_length= packet_length;
2057 2058 2059 2060

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

  if (!(specialflag & SPECIAL_NO_PRIOR))
    my_pthread_setprio(pthread_self(),QUERY_PRIOR);
unknown's avatar
unknown committed
2064
  return FALSE;
2065 2066
}

unknown's avatar
unknown committed
2067 2068 2069 2070 2071
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/

unknown's avatar
unknown committed
2072
bool
2073
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
2074
{
unknown's avatar
unknown committed
2075
  bool	res= FALSE;
unknown's avatar
unknown committed
2076
  int result= 0;
unknown's avatar
unknown committed
2077
  LEX	*lex= thd->lex;
unknown's avatar
unknown committed
2078
  /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
unknown's avatar
unknown committed
2079
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
2080
  /* first table of first SELECT_LEX */
unknown's avatar
unknown committed
2081
  TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
unknown's avatar
VIEW  
unknown committed
2082 2083 2084
  /* list of all tables in query */
  TABLE_LIST *all_tables;
  /* most outer SELECT_LEX_UNIT of query */
2085
  SELECT_LEX_UNIT *unit= &lex->unit;
unknown's avatar
unknown committed
2086 2087
  DBUG_ENTER("mysql_execute_command");

unknown's avatar
VIEW  
unknown committed
2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103
  /*
    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();
2104
  /* should be assigned after making first tables same */
unknown's avatar
VIEW  
unknown committed
2105 2106
  all_tables= lex->query_tables;

2107
  if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
2108
      lex->sql_command != SQLCOM_CREATE_SPFUNCTION)
2109 2110 2111 2112 2113
  {
    if (sp_cache_functions(thd, lex))
      DBUG_RETURN(-1);
  }

2114 2115 2116 2117 2118 2119
  /*
    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.
  */
unknown's avatar
VIEW  
unknown committed
2120
  if (all_tables || &lex->select_lex != lex->all_selects_list)
2121 2122
    mysql_reset_errors(thd);

unknown's avatar
SCRUM  
unknown committed
2123
#ifdef HAVE_REPLICATION
2124 2125
  if (thd->slave_thread)
  {
unknown's avatar
unknown committed
2126
    /*
unknown's avatar
merge  
unknown committed
2127 2128 2129
      Skip if we are in the slave thread, some table rules have been
      given and the table list says the query should not be replicated
    */
unknown's avatar
VIEW  
unknown committed
2130
    if (all_tables_not_ok(thd, all_tables))
unknown's avatar
Fix for  
unknown committed
2131 2132
    {
      /* we warn the slave SQL thread */
unknown's avatar
unknown committed
2133
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
2134
      DBUG_RETURN(0);
unknown's avatar
Fix for  
unknown committed
2135
    }
unknown's avatar
merge  
unknown committed
2136 2137
#ifndef TO_BE_DELETED
    /*
2138 2139 2140
      This is a workaround to deal with the shortcoming in 3.23.44-3.23.46
      masters in RELEASE_LOCK() logging. We re-write SELECT RELEASE_LOCK()
      as DO RELEASE_LOCK()
unknown's avatar
merge  
unknown committed
2141
    */
2142 2143 2144
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
unknown's avatar
unknown committed
2145
      lex->insert_list = &select_lex->item_list;
2146
    }
unknown's avatar
merge  
unknown committed
2147
#endif
2148
  }
unknown's avatar
SCRUM:  
unknown committed
2149
#endif /* !HAVE_REPLICATION */
2150

2151 2152 2153 2154 2155
  /*
    When option readonly is set deny operations which change tables.
    Except for the replication thread and the 'super' users.
  */
  if (opt_readonly &&
unknown's avatar
unknown committed
2156
      !(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
2157 2158
      (uc_update_queries[lex->sql_command] > 0))
  {
unknown's avatar
unknown committed
2159
    my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
unknown's avatar
unknown committed
2160
    DBUG_RETURN(-1);
2161
  }
2162

2163 2164
  statistic_increment(thd->status_var.com_stat[lex->sql_command],
		      &LOCK_status);
unknown's avatar
unknown committed
2165 2166 2167
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
2168 2169 2170 2171 2172 2173 2174
    /* assign global limit variable if limit is not given */
    {
      SELECT_LEX *param= lex->unit.global_parameters;
      if (!param->explicit_limit)
	param->select_limit= thd->variables.select_limit;
    }

unknown's avatar
unknown committed
2175
    select_result *result=lex->result;
unknown's avatar
VIEW  
unknown committed
2176
    if (all_tables)
unknown's avatar
unknown committed
2177
    {
unknown's avatar
VIEW  
unknown committed
2178 2179 2180 2181
      res= check_table_access(thd,
			      lex->exchange ? SELECT_ACL | FILE_ACL :
			      SELECT_ACL,
			      all_tables, 0);
unknown's avatar
unknown committed
2182 2183
    }
    else
unknown's avatar
VIEW  
unknown committed
2184 2185 2186
      res= check_access(thd,
			lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
			any_db, 0, 0, 0);
unknown's avatar
unknown committed
2187
    if (res)
unknown's avatar
unknown committed
2188
      goto error;
unknown's avatar
unknown committed
2189

unknown's avatar
VIEW  
unknown committed
2190
    if (!(res= open_and_lock_tables(thd, all_tables)))
unknown's avatar
unknown committed
2191
    {
unknown's avatar
unknown committed
2192
      if (lex->describe)
unknown's avatar
unknown committed
2193
      {
2194
	if (!(result= new select_send()))
2195
	  goto error;
2196 2197
	else
	  thd->send_explain_fields(result);
unknown's avatar
unknown committed
2198
	res= mysql_explain_union(thd, &thd->lex->unit, result);
unknown's avatar
unknown committed
2199 2200 2201 2202 2203
	if (lex->describe & DESCRIBE_EXTENDED)
	{
	  char buff[1024];
	  String str(buff,(uint32) sizeof(buff), system_charset_info);
	  str.length(0);
unknown's avatar
unknown committed
2204
	  thd->lex->unit.print(&str);
unknown's avatar
unknown committed
2205 2206 2207 2208
	  str.append('\0');
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
		       ER_YES, str.ptr());
	}
2209
	result->send_eof();
2210
        delete result;
unknown's avatar
unknown committed
2211 2212 2213
      }
      else
      {
2214
	if (!result && !(result= new select_send()))
unknown's avatar
unknown committed
2215
          goto error;
unknown's avatar
VIEW  
unknown committed
2216
	query_cache_store_query(thd, all_tables);
2217
	res= handle_select(thd, lex, result, 0);
2218 2219
        if (result != lex->result)
          delete result;
unknown's avatar
unknown committed
2220
      }
unknown's avatar
unknown committed
2221
    }
unknown's avatar
unknown committed
2222 2223
    break;
  }
unknown's avatar
unknown committed
2224
  case SQLCOM_PREPARE:
2225
  {
2226 2227 2228 2229
    char *query_str;
    uint query_len;
    if (lex->prepared_stmt_code_is_varref)
    {
2230
      /* This is PREPARE stmt FROM @var. */
2231 2232 2233 2234
      String str;
      CHARSET_INFO *to_cs= thd->variables.collation_connection;
      bool need_conversion;
      user_var_entry *entry;
2235
      String *pstr= &str;
2236
      uint32 unused;
2237
      /*
2238 2239 2240
        Convert @var contents to string in connection character set. Although
        it is known that int/real/NULL value cannot be a valid query we still
        convert it for error messages to uniform.
2241
      */
2242 2243
      if ((entry=
             (user_var_entry*)hash_search(&thd->user_vars,
2244 2245 2246 2247
                                          (byte*)lex->prepared_stmt_code.str,
                                          lex->prepared_stmt_code.length))
          && entry->value)
      {
2248 2249
        my_bool is_var_null;
        pstr= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC);
2250 2251 2252 2253
        /*
          NULL value of variable checked early as entry->value so here
          we can't get NULL in normal conditions
        */
2254 2255
        DBUG_ASSERT(!is_var_null);
        if (!pstr)
unknown's avatar
unknown committed
2256
          goto error;
2257 2258
      }
      else
2259 2260 2261 2262 2263
      {
        /*
          variable absent or equal to NULL, so we need to set variable to
          something reasonable to get readable error message during parsing
        */
2264
        str.set("NULL", 4, &my_charset_latin1);
2265 2266
      }

2267
      need_conversion=
2268 2269
        String::needs_conversion(pstr->length(), pstr->charset(),
                                 to_cs, &unused);
2270

2271 2272
      query_len= need_conversion? (pstr->length() * to_cs->mbmaxlen) :
                                  pstr->length();
unknown's avatar
unknown committed
2273
      if (!(query_str= alloc_root(thd->mem_root, query_len+1)))
unknown's avatar
unknown committed
2274
        goto error;
unknown's avatar
merge  
unknown committed
2275
 
2276
      if (need_conversion)
unknown's avatar
unknown committed
2277 2278 2279 2280 2281 2282
      {
        uint dummy_errors;
        query_len= copy_and_convert(query_str, query_len, to_cs,
                                    pstr->ptr(), pstr->length(),
                                    pstr->charset(), &dummy_errors);
      }
2283
      else
2284
        memcpy(query_str, pstr->ptr(), pstr->length());
2285
      query_str[query_len]= 0;
2286 2287 2288
    }
    else
    {
2289 2290
      query_str= lex->prepared_stmt_code.str;
      query_len= lex->prepared_stmt_code.length;
2291
      DBUG_PRINT("info", ("PREPARE: %.*s FROM '%.*s' \n",
2292 2293
                          lex->prepared_stmt_name.length,
                          lex->prepared_stmt_name.str,
2294
                          query_len, query_str));
2295
    }
unknown's avatar
unknown committed
2296
    thd->command= COM_PREPARE;
unknown's avatar
unknown committed
2297 2298
    if (!(res= mysql_stmt_prepare(thd, query_str, query_len + 1,
                                  &lex->prepared_stmt_name)))
unknown's avatar
unknown committed
2299 2300 2301 2302 2303
      send_ok(thd, 0L, 0L, "Statement prepared");
    break;
  }
  case SQLCOM_EXECUTE:
  {
2304
    DBUG_PRINT("info", ("EXECUTE: %.*s\n",
2305 2306 2307
                        lex->prepared_stmt_name.length,
                        lex->prepared_stmt_name.str));
    mysql_sql_stmt_execute(thd, &lex->prepared_stmt_name);
unknown's avatar
unknown committed
2308 2309 2310 2311 2312
    lex->prepared_stmt_params.empty();
    break;
  }
  case SQLCOM_DEALLOCATE_PREPARE:
  {
2313 2314 2315 2316 2317
    Statement* stmt;
    DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", 
                        lex->prepared_stmt_name.length,
                        lex->prepared_stmt_name.str));
    if ((stmt= thd->stmt_map.find_by_name(&lex->prepared_stmt_name)))
unknown's avatar
unknown committed
2318
    {
2319 2320
      thd->stmt_map.erase(stmt);
      send_ok(thd);
unknown's avatar
unknown committed
2321
    }
2322
    else
2323 2324
    {
      my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0),
2325 2326
               lex->prepared_stmt_name.length,
               lex->prepared_stmt_name.str,
2327
               "DEALLOCATE PREPARE");
unknown's avatar
unknown committed
2328
      goto error;
2329
    }
unknown's avatar
unknown committed
2330 2331
    break;
  }
unknown's avatar
unknown committed
2332
  case SQLCOM_DO:
unknown's avatar
VIEW  
unknown committed
2333
    if (all_tables &&
unknown's avatar
unknown committed
2334 2335 2336
	(check_table_access(thd, SELECT_ACL, all_tables, 0) ||
         open_and_lock_tables(thd, all_tables)))
      goto error;
unknown's avatar
unknown committed
2337 2338

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

2341
  case SQLCOM_EMPTY_QUERY:
2342
    send_ok(thd);
2343 2344
    break;

unknown's avatar
unknown committed
2345 2346 2347 2348
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

2349
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2350
  case SQLCOM_PURGE:
2351
  {
unknown's avatar
unknown committed
2352
    if (check_global_access(thd, SUPER_ACL))
2353
      goto error;
unknown's avatar
unknown committed
2354
    /* PURGE MASTER LOGS TO 'file' */
2355 2356 2357
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
2358 2359
  case SQLCOM_PURGE_BEFORE:
  {
2360 2361
    Item *it;

2362 2363
    if (check_global_access(thd, SUPER_ACL))
      goto error;
unknown's avatar
unknown committed
2364
    /* PURGE MASTER LOGS BEFORE 'data' */
2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377
    it= (Item *)lex->value_list.head();
    if (it->check_cols(1) || it->fix_fields(lex->thd, 0, &it))
    {
      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());
2378 2379
    break;
  }
2380
#endif
unknown's avatar
unknown committed
2381 2382
  case SQLCOM_SHOW_WARNS:
  {
2383 2384
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
2385 2386 2387
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
unknown's avatar
unknown committed
2388 2389 2390 2391
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
2392 2393
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
2394 2395
    break;
  }
unknown's avatar
unknown committed
2396 2397
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
2398
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2399
      goto error;
2400
    /* This query don't work now. See comment in repl_failsafe.cc */
unknown's avatar
unknown committed
2401
#ifndef WORKING_NEW_MASTER
unknown's avatar
unknown committed
2402 2403
    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
    goto error;
unknown's avatar
unknown committed
2404
#else
unknown's avatar
unknown committed
2405 2406
    res = show_new_master(thd);
    break;
unknown's avatar
unknown committed
2407
#endif
unknown's avatar
unknown committed
2408
  }
2409

unknown's avatar
unknown committed
2410
#ifdef HAVE_REPLICATION
2411 2412
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
2413
    if (check_global_access(thd, REPL_SLAVE_ACL))
2414 2415 2416 2417
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
2418 2419
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
2420
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2421 2422 2423 2424
      goto error;
    res = show_binlog_events(thd);
    break;
  }
2425 2426
#endif

unknown's avatar
unknown committed
2427
  case SQLCOM_BACKUP_TABLE:
2428
  {
unknown's avatar
VIEW  
unknown committed
2429 2430 2431
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL, all_tables, 0) ||
unknown's avatar
unknown committed
2432
	check_global_access(thd, FILE_ACL))
2433
      goto error; /* purecov: inspected */
2434
    thd->slow_command=TRUE;
unknown's avatar
VIEW  
unknown committed
2435
    res = mysql_backup_table(thd, first_table);
unknown's avatar
unknown committed
2436

2437 2438
    break;
  }
unknown's avatar
unknown committed
2439
  case SQLCOM_RESTORE_TABLE:
2440
  {
unknown's avatar
VIEW  
unknown committed
2441 2442 2443
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, INSERT_ACL, all_tables, 0) ||
unknown's avatar
unknown committed
2444
	check_global_access(thd, FILE_ACL))
2445
      goto error; /* purecov: inspected */
2446
    thd->slow_command=TRUE;
unknown's avatar
VIEW  
unknown committed
2447
    res = mysql_restore_table(thd, first_table);
2448 2449
    break;
  }
unknown's avatar
unknown committed
2450 2451
  case SQLCOM_ASSIGN_TO_KEYCACHE:
  {
unknown's avatar
VIEW  
unknown committed
2452 2453 2454 2455
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
        check_access(thd, INDEX_ACL, first_table->db,
                     &first_table->grant.privilege, 0, 0))
unknown's avatar
unknown committed
2456
      goto error;
unknown's avatar
VIEW  
unknown committed
2457
    res= mysql_assign_to_keycache(thd, first_table, &lex->name_and_length);
unknown's avatar
unknown committed
2458 2459
    break;
  }
unknown's avatar
unknown committed
2460 2461
  case SQLCOM_PRELOAD_KEYS:
  {
unknown's avatar
VIEW  
unknown committed
2462 2463 2464 2465
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_access(thd, INDEX_ACL, first_table->db,
                     &first_table->grant.privilege, 0, 0))
2466
      goto error;
unknown's avatar
VIEW  
unknown committed
2467
    res = mysql_preload_keys(thd, first_table);
unknown's avatar
unknown committed
2468 2469
    break;
  }
unknown's avatar
unknown committed
2470
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2471
  case SQLCOM_CHANGE_MASTER:
2472
  {
unknown's avatar
unknown committed
2473
    if (check_global_access(thd, SUPER_ACL))
2474
      goto error;
2475
    pthread_mutex_lock(&LOCK_active_mi);
2476
    res = change_master(thd,active_mi);
2477
    pthread_mutex_unlock(&LOCK_active_mi);
2478 2479
    break;
  }
unknown's avatar
unknown committed
2480
  case SQLCOM_SHOW_SLAVE_STAT:
2481
  {
2482 2483
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2484
      goto error;
2485
    pthread_mutex_lock(&LOCK_active_mi);
2486
    res = show_master_info(thd,active_mi);
2487
    pthread_mutex_unlock(&LOCK_active_mi);
2488 2489
    break;
  }
unknown's avatar
unknown committed
2490
  case SQLCOM_SHOW_MASTER_STAT:
2491
  {
2492 2493
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2494 2495 2496 2497
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
2498

2499
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
2500
    if (check_global_access(thd, SUPER_ACL))
2501
      goto error;
2502
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2503
      goto error;
2504 2505
    else
      res = load_master_data(thd);
2506
    break;
unknown's avatar
unknown committed
2507
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
2508 2509 2510
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
2511
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2512 2513 2514 2515
	goto error;
      res = innodb_show_status(thd);
      break;
    }
unknown's avatar
unknown committed
2516 2517 2518
  case SQLCOM_SHOW_MUTEX_STATUS:
    {
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2519
        goto error;
unknown's avatar
unknown committed
2520 2521 2522
      res = innodb_mutex_show_status(thd);
      break;
    }
unknown's avatar
unknown committed
2523
#endif
unknown's avatar
unknown committed
2524
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2525
  case SQLCOM_LOAD_MASTER_TABLE:
2526
  {
unknown's avatar
VIEW  
unknown committed
2527 2528 2529 2530 2531
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (!first_table->db)
      first_table->db= thd->db;
    if (check_access(thd, CREATE_ACL, first_table->db,
		     &first_table->grant.privilege, 0, 0))
unknown's avatar
unknown committed
2532 2533 2534 2535
      goto error;				/* purecov: inspected */
    if (grant_option)
    {
      /* Check that the first table has CREATE privilege */
unknown's avatar
VIEW  
unknown committed
2536
      if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
2537
	goto error;
unknown's avatar
unknown committed
2538
    }
2539
    if (strlen(first_table->table_name) > NAME_LEN)
unknown's avatar
unknown committed
2540
    {
2541
      my_error(ER_WRONG_TABLE_NAME, MYF(0), first_table->table_name);
unknown's avatar
unknown committed
2542 2543
      break;
    }
2544
    pthread_mutex_lock(&LOCK_active_mi);
2545 2546 2547 2548
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
2549
    if (!fetch_master_table(thd, first_table->db, first_table->table_name,
2550
			    active_mi, 0, 0))
2551
    {
2552
      send_ok(thd);
2553
    }
2554
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2555
    break;
2556
  }
unknown's avatar
unknown committed
2557
#endif /* HAVE_REPLICATION */
2558

unknown's avatar
unknown committed
2559
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
2560
  {
unknown's avatar
VIEW  
unknown committed
2561 2562 2563 2564 2565
    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
2566

unknown's avatar
VIEW  
unknown committed
2567
    if ((res= create_table_precheck(thd, select_tables, create_table)))
unknown's avatar
unknown committed
2568
      goto unsent_create_error;
unknown's avatar
unknown committed
2569

2570 2571 2572
#ifndef HAVE_READLINK
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
unknown's avatar
unknown committed
2573
    /* Fix names if symlinked tables */
unknown's avatar
unknown committed
2574
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
2575
			   create_table->table_name) ||
unknown's avatar
VIEW  
unknown committed
2576
	append_file_to_dir(thd, &lex->create_info.index_file_name,
2577
			   create_table->table_name))
unknown's avatar
unknown committed
2578
      goto unsent_create_error;
2579
#endif
2580
    /*
2581
      If we are using SET CHARSET without DEFAULT, add an implicit
2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592
      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;
    }
2593
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
2594 2595
    {
      select_result *result;
2596

2597
      select_lex->options|= SELECT_NO_UNLOCK;
unknown's avatar
unknown committed
2598
      unit->set_limit(select_lex, select_lex);
2599

unknown's avatar
VIEW  
unknown committed
2600
      if (!(res= open_and_lock_tables(thd, select_tables)))
2601
      {
2602 2603 2604 2605 2606 2607 2608
        /*
          Is table which we are changing used somewhere in other parts
          of query
        */
        if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
            unique_table(create_table, select_tables))
        {
2609
          my_error(ER_UPDATE_TABLE_USED, MYF(0), create_table->table_name);
unknown's avatar
unknown committed
2610
          goto unsent_create_error;
2611
        }
unknown's avatar
unknown committed
2612 2613 2614 2615 2616 2617 2618 2619 2620 2621
        /* If we create merge table, we have to test tables in merge, too */
        if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
        {
          TABLE_LIST *tab;
          for (tab= (TABLE_LIST*) lex->create_info.merge_list.first;
               tab;
               tab= tab->next_local)
          {
            if (unique_table(tab, select_tables))
            {
2622
              my_error(ER_UPDATE_TABLE_USED, MYF(0), tab->table_name);
unknown's avatar
unknown committed
2623
              goto unsent_create_error;
unknown's avatar
unknown committed
2624 2625 2626
            }
          }
        }
2627

unknown's avatar
VIEW  
unknown committed
2628 2629 2630 2631 2632
        if ((result= new select_create(create_table,
				       &lex->create_info,
				       lex->create_list,
				       lex->key_list,
				       select_lex->item_list,
2633 2634
				       lex->duplicates,
				       lex->ignore)))
2635 2636 2637 2638 2639 2640
        {
          /*
            CREATE from SELECT give its SELECT_LEX for SELECT,
            and item_list belong to SELECT
          */
          select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
2641
          res= handle_select(thd, lex, result, 0);
2642
          select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE;
2643
          delete result;
2644
        }
unknown's avatar
unknown committed
2645
	/* reset for PS */
2646 2647
	lex->create_list.empty();
	lex->key_list.empty();
2648 2649
      }
    }
unknown's avatar
unknown committed
2650
    else
unknown's avatar
unknown committed
2651
    {
unknown's avatar
unknown committed
2652
      /* regular create */
unknown's avatar
unknown committed
2653
      if (lex->name)
unknown's avatar
unknown committed
2654
        res= mysql_create_like_table(thd, create_table, &lex->create_info, 
unknown's avatar
unknown committed
2655 2656
                                     (Table_ident *)lex->name); 
      else
2657
      {
unknown's avatar
VIEW  
unknown committed
2658
        res= mysql_create_table(thd, create_table->db,
2659
				create_table->table_name, &lex->create_info,
unknown's avatar
VIEW  
unknown committed
2660
				lex->create_list,
unknown's avatar
unknown committed
2661
				lex->key_list, 0, 0);
2662
      }
unknown's avatar
unknown committed
2663
      if (!res)
2664
	send_ok(thd);
unknown's avatar
unknown committed
2665
    }
unknown's avatar
VIEW  
unknown committed
2666
    lex->link_first_table_back(create_table, link_to_local);
2667 2668
    break;

unknown's avatar
unknown committed
2669
    /* put tables back for PS rexecuting */
unknown's avatar
unknown committed
2670
unsent_create_error:
unknown's avatar
VIEW  
unknown committed
2671
    lex->link_first_table_back(create_table, link_to_local);
unknown's avatar
unknown committed
2672
    goto error;
unknown's avatar
unknown committed
2673
  }
unknown's avatar
unknown committed
2674
  case SQLCOM_CREATE_INDEX:
unknown's avatar
VIEW  
unknown committed
2675 2676
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, INDEX_ACL, all_tables))
unknown's avatar
unknown committed
2677
      goto error; /* purecov: inspected */
2678
    thd->slow_command=TRUE;
2679
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2680
      goto error;
2681
    else
unknown's avatar
VIEW  
unknown committed
2682
      res = mysql_create_index(thd, first_table, lex->key_list);
unknown's avatar
unknown committed
2683 2684
    break;

unknown's avatar
unknown committed
2685
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2686
  case SQLCOM_SLAVE_START:
2687
  {
2688
    pthread_mutex_lock(&LOCK_active_mi);
2689
    start_slave(thd,active_mi,1 /* net report*/);
2690
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2691
    break;
2692
  }
unknown's avatar
unknown committed
2693
  case SQLCOM_SLAVE_STOP:
2694 2695 2696 2697 2698 2699
  /*
    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,
2700
      so it waits for the client thread because t is locked by it.
2701
    - then the client thread does SLAVE STOP.
2702 2703
      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.
2704 2705 2706 2707 2708
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
  if (thd->locked_tables || thd->active_transaction())
  {
unknown's avatar
unknown committed
2709 2710
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION),
               MYF(0));
2711
    goto error;
2712
  }
2713
  {
2714
    pthread_mutex_lock(&LOCK_active_mi);
2715
    stop_slave(thd,active_mi,1/* net report*/);
2716
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2717
    break;
2718
  }
unknown's avatar
unknown committed
2719
#endif /* HAVE_REPLICATION */
2720

unknown's avatar
unknown committed
2721
  case SQLCOM_ALTER_TABLE:
unknown's avatar
VIEW  
unknown committed
2722
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2723
#if defined(DONT_ALLOW_SHOW_COMMANDS)
unknown's avatar
unknown committed
2724 2725
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2726
    goto error;
unknown's avatar
unknown committed
2727 2728
#else
    {
unknown's avatar
unknown committed
2729
      ulong priv=0;
unknown's avatar
unknown committed
2730
      if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
unknown's avatar
unknown committed
2731
      {
2732
	my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name);
unknown's avatar
unknown committed
2733
        goto error;
unknown's avatar
unknown committed
2734
      }
2735
      if (!select_lex->db)
unknown's avatar
VIEW  
unknown committed
2736 2737 2738
	select_lex->db= first_table->db;
      if (check_access(thd, ALTER_ACL, first_table->db,
		       &first_table->grant.privilege, 0, 0) ||
unknown's avatar
SCRUM:  
unknown committed
2739
	  check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0)||
unknown's avatar
VIEW  
unknown committed
2740
	  check_merge_table_access(thd, first_table->db,
2741 2742 2743
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
2744 2745
      if (grant_option)
      {
unknown's avatar
VIEW  
unknown committed
2746
	if (check_grant(thd, ALTER_ACL, all_tables, 0, UINT_MAX, 0))
unknown's avatar
unknown committed
2747 2748 2749 2750 2751
	  goto error;
	if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
	{					// Rename of table
	  TABLE_LIST tmp_table;
	  bzero((char*) &tmp_table,sizeof(tmp_table));
2752
	  tmp_table.table_name=lex->name;
2753
	  tmp_table.db=select_lex->db;
unknown's avatar
unknown committed
2754
	  tmp_table.grant.privilege=priv;
unknown's avatar
unknown committed
2755 2756
	  if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
			  UINT_MAX, 0))
unknown's avatar
unknown committed
2757 2758 2759
	    goto error;
	}
      }
unknown's avatar
unknown committed
2760 2761
      /* Don't yet allow changing of symlinks with ALTER TABLE */
      lex->create_info.data_file_name=lex->create_info.index_file_name=0;
unknown's avatar
unknown committed
2762
      /* ALTER TABLE ends previous transaction */
2763
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2764
	goto error;
unknown's avatar
unknown committed
2765
      else
unknown's avatar
unknown committed
2766
      {
2767
        thd->slow_command=TRUE;
2768
	res= mysql_alter_table(thd, select_lex->db, lex->name,
unknown's avatar
unknown committed
2769
			       &lex->create_info,
unknown's avatar
VIEW  
unknown committed
2770
			       first_table, lex->create_list,
2771
			       lex->key_list,
2772
			       select_lex->order_list.elements,
2773
                               (ORDER *) select_lex->order_list.first,
2774
			       lex->duplicates, lex->ignore, &lex->alter_info);
unknown's avatar
unknown committed
2775
      }
unknown's avatar
unknown committed
2776 2777
      break;
    }
unknown's avatar
SCRUM:  
unknown committed
2778
#endif /*DONT_ALLOW_SHOW_COMMANDS*/
unknown's avatar
unknown committed
2779
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
2780
  {
unknown's avatar
VIEW  
unknown committed
2781
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2782
    TABLE_LIST *table;
unknown's avatar
VIEW  
unknown committed
2783
    if (check_db_used(thd, all_tables))
unknown's avatar
unknown committed
2784
      goto error;
unknown's avatar
VIEW  
unknown committed
2785
    for (table= first_table; table; table= table->next_local->next_local)
unknown's avatar
unknown committed
2786
    {
unknown's avatar
unknown committed
2787
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
unknown's avatar
SCRUM:  
unknown committed
2788
		       &table->grant.privilege,0,0) ||
unknown's avatar
VIEW  
unknown committed
2789 2790
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
		       &table->next_local->grant.privilege, 0, 0))
unknown's avatar
unknown committed
2791 2792 2793
	goto error;
      if (grant_option)
      {
unknown's avatar
VIEW  
unknown committed
2794
	TABLE_LIST old_list, new_list;
unknown's avatar
unknown committed
2795 2796 2797 2798
	/*
	  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
2799 2800 2801 2802
	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,
2803
			    INSERT_ACL | CREATE_ACL) &&
unknown's avatar
VIEW  
unknown committed
2804
	     check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
unknown's avatar
unknown committed
2805 2806 2807
	  goto error;
      }
    }
unknown's avatar
VIEW  
unknown committed
2808
    query_cache_invalidate3(thd, first_table, 0);
unknown's avatar
unknown committed
2809 2810
    if (end_active_trans(thd) || mysql_rename_tables(thd, first_table))
      goto error;
unknown's avatar
unknown committed
2811
    break;
unknown's avatar
unknown committed
2812
  }
2813
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2814 2815
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2816 2817
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2818
    goto error;
unknown's avatar
unknown committed
2819 2820
#else
    {
unknown's avatar
unknown committed
2821
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2822 2823 2824 2825
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
2826
#endif
2827
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2828
  case SQLCOM_SHOW_CREATE:
unknown's avatar
VIEW  
unknown committed
2829
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2830
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2831 2832
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2833
    goto error;
unknown's avatar
unknown committed
2834
#else
unknown's avatar
unknown committed
2835
    {
unknown's avatar
VIEW  
unknown committed
2836 2837 2838
      if (check_db_used(thd, all_tables) ||
	  check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db,
		       &first_table->grant.privilege, 0, 0))
unknown's avatar
unknown committed
2839
	goto error;
unknown's avatar
unknown committed
2840
      if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0))
2841
	goto error;
unknown's avatar
unknown committed
2842
      res= mysqld_show_create(thd, first_table);
unknown's avatar
unknown committed
2843 2844
      break;
    }
unknown's avatar
unknown committed
2845
#endif
2846 2847
  case SQLCOM_CHECKSUM:
  {
unknown's avatar
VIEW  
unknown committed
2848 2849 2850
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, 0))
2851
      goto error; /* purecov: inspected */
unknown's avatar
VIEW  
unknown committed
2852
    res = mysql_checksum_table(thd, first_table, &lex->check_opt);
2853 2854
    break;
  }
unknown's avatar
unknown committed
2855
  case SQLCOM_REPAIR:
2856
  {
unknown's avatar
VIEW  
unknown committed
2857 2858 2859
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
2860
      goto error; /* purecov: inspected */
2861
    thd->slow_command=TRUE;
unknown's avatar
VIEW  
unknown committed
2862
    res= mysql_repair_table(thd, first_table, &lex->check_opt);
2863 2864 2865 2866 2867
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
2868
	thd->clear_error(); // No binlog error generated
2869
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
2870 2871 2872
        mysql_bin_log.write(&qinfo);
      }
    }
2873 2874
    break;
  }
unknown's avatar
unknown committed
2875
  case SQLCOM_CHECK:
2876
  {
unknown's avatar
VIEW  
unknown committed
2877 2878 2879
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0))
2880
      goto error; /* purecov: inspected */
2881
    thd->slow_command=TRUE;
unknown's avatar
VIEW  
unknown committed
2882
    res = mysql_check_table(thd, first_table, &lex->check_opt);
2883 2884
    break;
  }
unknown's avatar
unknown committed
2885 2886
  case SQLCOM_ANALYZE:
  {
unknown's avatar
VIEW  
unknown committed
2887 2888 2889
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
unknown's avatar
unknown committed
2890
      goto error; /* purecov: inspected */
2891
    thd->slow_command=TRUE;
unknown's avatar
VIEW  
unknown committed
2892
    res = mysql_analyze_table(thd, first_table, &lex->check_opt);
2893 2894 2895 2896 2897
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
2898
	thd->clear_error(); // No binlog error generated
2899
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
2900 2901 2902
        mysql_bin_log.write(&qinfo);
      }
    }
unknown's avatar
unknown committed
2903
    break;
unknown's avatar
unknown committed
2904
  }
2905

unknown's avatar
unknown committed
2906 2907
  case SQLCOM_OPTIMIZE:
  {
unknown's avatar
VIEW  
unknown committed
2908 2909 2910
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
unknown's avatar
unknown committed
2911
      goto error; /* purecov: inspected */
2912
    thd->slow_command=TRUE;
2913
    res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
unknown's avatar
VIEW  
unknown committed
2914 2915
      mysql_recreate_table(thd, first_table, 1) :
      mysql_optimize_table(thd, first_table, &lex->check_opt);
2916 2917 2918 2919 2920
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
2921
	thd->clear_error(); // No binlog error generated
2922
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
2923 2924 2925
        mysql_bin_log.write(&qinfo);
      }
    }
unknown's avatar
unknown committed
2926 2927 2928
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
VIEW  
unknown committed
2929 2930
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (update_precheck(thd, all_tables))
unknown's avatar
unknown committed
2931
      break;
unknown's avatar
unknown committed
2932 2933 2934 2935 2936 2937 2938
    res= (result= mysql_update(thd, all_tables,
                               select_lex->item_list,
                               lex->value_list,
                               select_lex->where,
                               select_lex->order_list.elements,
                               (ORDER *) select_lex->order_list.first,
                               select_lex->select_limit,
2939
                               lex->duplicates, lex->ignore));
2940
    /* mysql_update return 2 if we need to switch to multi-update */
unknown's avatar
unknown committed
2941
    if (result != 2)
2942
      break;
2943
  case SQLCOM_UPDATE_MULTI:
2944
    {
unknown's avatar
unknown committed
2945
      DBUG_ASSERT(first_table == all_tables && first_table != 0);
2946
      /* if we switched from normal update, rights are checked */
unknown's avatar
unknown committed
2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959
      if (result != 2)
      {
        if ((res= multi_update_precheck(thd, all_tables)))
          break;
      }
      else
        res= 0;

      res= mysql_multi_update(thd, all_tables,
                              &select_lex->item_list,
                              &lex->value_list,
                              select_lex->where,
                              select_lex->options,
2960
                              lex->duplicates, lex->ignore, unit, select_lex);
unknown's avatar
unknown committed
2961
    break;
unknown's avatar
unknown committed
2962
  }
unknown's avatar
unknown committed
2963
  case SQLCOM_REPLACE:
2964 2965
  case SQLCOM_INSERT:
  {
unknown's avatar
VIEW  
unknown committed
2966
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2967
    if ((res= insert_precheck(thd, all_tables)))
unknown's avatar
unknown committed
2968
      break;
unknown's avatar
VIEW  
unknown committed
2969
    res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
unknown's avatar
unknown committed
2970
		      lex->update_list, lex->value_list,
2971
                      lex->duplicates, lex->ignore);
unknown's avatar
VIEW  
unknown committed
2972 2973
    if (first_table->view && !first_table->contain_auto_increment)
      thd->last_insert_id= 0; // do not show last insert ID if VIEW have not it
unknown's avatar
unknown committed
2974
    break;
2975
  }
unknown's avatar
unknown committed
2976 2977 2978
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
unknown's avatar
VIEW  
unknown committed
2979
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2980
    if ((res= insert_precheck(thd, all_tables)))
2981
      break;
unknown's avatar
unknown committed
2982

2983
    /* Fix lock for first table */
unknown's avatar
VIEW  
unknown committed
2984 2985
    if (first_table->lock_type == TL_WRITE_DELAYED)
      first_table->lock_type= TL_WRITE;
2986

2987 2988
    /* Don't unlock tables until command is written to binary log */
    select_lex->options|= SELECT_NO_UNLOCK;
unknown's avatar
unknown committed
2989 2990

    select_result *result;
unknown's avatar
unknown committed
2991
    unit->set_limit(select_lex, select_lex);
unknown's avatar
unknown committed
2992

unknown's avatar
VIEW  
unknown committed
2993
    if (!(res= open_and_lock_tables(thd, all_tables)))
2994
    {
2995 2996
      /* Skip first table, which is the table we are inserting in */
      lex->select_lex.table_list.first= (byte*)first_table->next_local;
2997

2998 2999 3000
      res= mysql_insert_select_prepare(thd);
      if (!res && (result= new select_insert(first_table, first_table->table,
                                             &lex->field_list,
unknown's avatar
unknown committed
3001
                                             &lex->update_list, &lex->value_list,
3002
                                             lex->duplicates, lex->ignore)))
3003
      {
3004 3005 3006 3007 3008
        /*
          insert/replace from SELECT give its SELECT_LEX for SELECT,
          and item_list belong to SELECT
        */
	lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
3009
	res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
3010
	lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
3011 3012
        delete result;
      }
3013 3014
      /* revert changes for SP */
      lex->select_lex.table_list.first= (byte*) first_table;
3015 3016
    }
    else
unknown's avatar
unknown committed
3017
      res= TRUE;
unknown's avatar
VIEW  
unknown committed
3018 3019 3020 3021

    if (first_table->view && !first_table->contain_auto_increment)
      thd->last_insert_id= 0; // do not show last insert ID if VIEW have not it

unknown's avatar
unknown committed
3022 3023
    break;
  }
3024
  case SQLCOM_TRUNCATE:
unknown's avatar
VIEW  
unknown committed
3025 3026
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, DELETE_ACL, all_tables))
unknown's avatar
unknown committed
3027
      goto error;
3028 3029 3030 3031 3032 3033
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3034 3035
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3036 3037
      goto error;
    }
unknown's avatar
VIEW  
unknown committed
3038

unknown's avatar
unknown committed
3039
    res= mysql_truncate(thd, first_table, 0);
3040
    break;
unknown's avatar
unknown committed
3041
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
3042
  {
unknown's avatar
VIEW  
unknown committed
3043 3044
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if ((res= delete_precheck(thd, all_tables)))
unknown's avatar
unknown committed
3045
      break;
unknown's avatar
VIEW  
unknown committed
3046
    res = mysql_delete(thd, all_tables, select_lex->where,
3047
                       &select_lex->order_list,
unknown's avatar
unknown committed
3048
                       select_lex->select_limit, select_lex->options);
unknown's avatar
unknown committed
3049 3050
    break;
  }
unknown's avatar
unknown committed
3051
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
3052
  {
unknown's avatar
VIEW  
unknown committed
3053
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3054 3055
    TABLE_LIST *aux_tables=
      (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
unknown's avatar
unknown committed
3056
    uint table_count;
unknown's avatar
unknown committed
3057
    multi_delete *result;
unknown's avatar
unknown committed
3058

unknown's avatar
VIEW  
unknown committed
3059
    if ((res= multi_delete_precheck(thd, all_tables, &table_count)))
3060
      break;
unknown's avatar
unknown committed
3061

unknown's avatar
unknown committed
3062
    /* condition will be TRUE on SP re-excuting */
3063 3064
    if (select_lex->item_list.elements != 0)
      select_lex->item_list.empty();
unknown's avatar
unknown committed
3065
    if (add_item_to_list(thd, new Item_null()))
unknown's avatar
unknown committed
3066
      goto error;
3067

unknown's avatar
unknown committed
3068
    thd->proc_info="init";
unknown's avatar
VIEW  
unknown committed
3069 3070 3071
    if ((res= open_and_lock_tables(thd, all_tables)))
      break;

3072 3073 3074 3075 3076 3077 3078 3079 3080 3081
    if (!first_table->table)
    {
      DBUG_ASSERT(first_table->view &&
                  first_table->ancestor && first_table->ancestor->next_local);
      my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
               first_table->view_db.str, first_table->view_name.str);
      res= -1;
      break;
    }

unknown's avatar
VIEW  
unknown committed
3082
    if ((res= mysql_multi_delete_prepare(thd)))
unknown's avatar
unknown committed
3083
      goto error;
3084

3085 3086
    if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
							  table_count)))
unknown's avatar
unknown committed
3087
    {
3088 3089 3090
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
unknown's avatar
unknown committed
3091
			select_lex->item_list,
unknown's avatar
unknown committed
3092
			select_lex->where,
3093
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
unknown's avatar
unknown committed
3094 3095
			(ORDER *)NULL,
			select_lex->options | thd->options |
3096 3097
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
                        OPTION_SETUP_TABLES_DONE,
3098
			result, unit, select_lex);
3099
      delete result;
unknown's avatar
unknown committed
3100 3101
    }
    else
unknown's avatar
unknown committed
3102
      res= TRUE;
unknown's avatar
unknown committed
3103 3104 3105
    close_thread_tables(thd);
    break;
  }
unknown's avatar
unknown committed
3106
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
3107
  {
unknown's avatar
VIEW  
unknown committed
3108
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3109 3110
    if (!lex->drop_temporary)
    {
unknown's avatar
VIEW  
unknown committed
3111
      if (check_table_access(thd, DROP_ACL, all_tables, 0))
3112 3113
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
unknown's avatar
unknown committed
3114
        goto error;
3115
    }
unknown's avatar
unknown committed
3116
    else
unknown's avatar
unknown committed
3117 3118 3119 3120 3121 3122
    {
      /*
	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
3123 3124
	To not generate such irrelevant "table does not exist errors",
	we silently add IF EXISTS if TEMPORARY was used.
unknown's avatar
unknown committed
3125 3126 3127 3128
      */
      if (thd->slave_thread)
	lex->drop_if_exists= 1;
    }
unknown's avatar
VIEW  
unknown committed
3129 3130
    res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
			lex->drop_temporary);
unknown's avatar
unknown committed
3131 3132
  }
  break;
unknown's avatar
unknown committed
3133
  case SQLCOM_DROP_INDEX:
unknown's avatar
VIEW  
unknown committed
3134 3135
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, INDEX_ACL, all_tables))
unknown's avatar
unknown committed
3136
      goto error;				/* purecov: inspected */
3137
    if (end_active_trans(thd))
unknown's avatar
unknown committed
3138
      goto error;
3139
    else
unknown's avatar
VIEW  
unknown committed
3140
      res = mysql_drop_index(thd, first_table, &lex->alter_info);
unknown's avatar
unknown committed
3141 3142
    break;
  case SQLCOM_SHOW_PROCESSLIST:
unknown's avatar
unknown committed
3143
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
3144
      break;
unknown's avatar
SCRUM:  
unknown committed
3145 3146
    mysqld_list_processes(thd,
			  thd->master_access & PROCESS_ACL ? NullS :
unknown's avatar
unknown committed
3147
			  thd->priv_user,lex->verbose);
unknown's avatar
unknown committed
3148
    break;
unknown's avatar
unknown committed
3149 3150
  case SQLCOM_SHOW_STORAGE_ENGINES:
    res= mysqld_show_storage_engines(thd);
unknown's avatar
unknown committed
3151 3152 3153 3154 3155 3156 3157
    break;
  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
3158 3159
  case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
3160 3161
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
3162
    goto error;
unknown's avatar
unknown committed
3163 3164
#else
    {
unknown's avatar
SCRUM:  
unknown committed
3165
      if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0))
unknown's avatar
unknown committed
3166 3167 3168 3169
	goto error;
      res= mysqld_show_logs(thd);
      break;
    }
unknown's avatar
unknown committed
3170 3171
#endif
  case SQLCOM_CHANGE_DB:
3172
    mysql_change_db(thd,select_lex->db);
unknown's avatar
unknown committed
3173
    break;
3174

unknown's avatar
unknown committed
3175 3176
  case SQLCOM_LOAD:
  {
unknown's avatar
VIEW  
unknown committed
3177
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3178
    uint privilege= (lex->duplicates == DUP_REPLACE ?
3179
		     INSERT_ACL | DELETE_ACL : INSERT_ACL);
3180 3181

    if (!lex->local_file)
unknown's avatar
unknown committed
3182
    {
unknown's avatar
VIEW  
unknown committed
3183
      if (check_access(thd, privilege | FILE_ACL, first_table->db, 0, 0, 0))
unknown's avatar
unknown committed
3184 3185 3186 3187
	goto error;
    }
    else
    {
3188
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
unknown's avatar
unknown committed
3189
	  ! opt_local_infile)
3190
      {
unknown's avatar
unknown committed
3191
	my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0));
3192 3193
	goto error;
      }
unknown's avatar
VIEW  
unknown committed
3194
      if (check_one_table_access(thd, privilege, all_tables))
unknown's avatar
unknown committed
3195 3196
	goto error;
    }
unknown's avatar
VIEW  
unknown committed
3197
    res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
3198 3199
                    lex->duplicates, lex->ignore, (bool) lex->local_file,
		    lex->lock_option);
unknown's avatar
unknown committed
3200 3201
    break;
  }
3202

unknown's avatar
unknown committed
3203
  case SQLCOM_SET_OPTION:
3204 3205
  {
    List<set_var_base> *lex_var_list= &lex->var_list;
unknown's avatar
VIEW  
unknown committed
3206
    if (all_tables &&
unknown's avatar
unknown committed
3207 3208 3209
	(check_table_access(thd, SELECT_ACL, all_tables, 0) ||
	 open_and_lock_tables(thd, all_tables)))
      goto error;
3210 3211
    if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
    {
unknown's avatar
unknown committed
3212 3213
      my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
      goto error;
3214 3215 3216 3217 3218 3219 3220 3221
    }
    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;
3222
      send_ok(thd);
3223
    }
unknown's avatar
unknown committed
3224
    break;
3225
  }
unknown's avatar
unknown committed
3226

unknown's avatar
unknown committed
3227
  case SQLCOM_UNLOCK_TABLES:
3228 3229 3230 3231 3232 3233
    /*
      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
3234
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
3235 3236
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
3237
      end_active_trans(thd);
unknown's avatar
unknown committed
3238
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3239 3240
    }
    if (thd->global_read_lock)
3241
      unlock_global_read_lock(thd);
3242
    send_ok(thd);
unknown's avatar
unknown committed
3243 3244
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
3245
    unlock_locked_tables(thd);
unknown's avatar
VIEW  
unknown committed
3246
    if (check_db_used(thd, all_tables) || end_active_trans(thd))
unknown's avatar
unknown committed
3247
      goto error;
unknown's avatar
VIEW  
unknown committed
3248
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
3249
      goto error;
unknown's avatar
unknown committed
3250
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
3251
    thd->options|= OPTION_TABLE_LOCK;
unknown's avatar
VIEW  
unknown committed
3252 3253

    if (!(res= open_and_lock_tables(thd, all_tables)))
unknown's avatar
unknown committed
3254
    {
3255 3256
#ifdef HAVE_QUERY_CACHE
      if (thd->variables.query_cache_wlock_invalidate)
unknown's avatar
VIEW  
unknown committed
3257
	query_cache.invalidate_locked_for_write(first_table);
3258
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
3259 3260
      thd->locked_tables=thd->lock;
      thd->lock=0;
3261
      send_ok(thd);
unknown's avatar
unknown committed
3262
    }
unknown's avatar
unknown committed
3263 3264
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3265 3266 3267
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
3268
  {
unknown's avatar
unknown committed
3269
    char *alias;
unknown's avatar
unknown committed
3270
    if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
unknown's avatar
unknown committed
3271
    {
3272
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
unknown's avatar
unknown committed
3273 3274
      break;
    }
3275 3276 3277
    /*
      If in a slave thread :
      CREATE DATABASE DB was certainly not preceded by USE DB.
3278
      For that reason, db_ok() in sql/slave.cc did not check the
3279 3280 3281
      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.
    */
3282
#ifdef HAVE_REPLICATION
3283
    if (thd->slave_thread &&
3284 3285
	(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(lex->name)))
unknown's avatar
Fix for  
unknown committed
3286
    {
unknown's avatar
unknown committed
3287
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3288
      break;
unknown's avatar
Fix for  
unknown committed
3289
    }
3290
#endif
unknown's avatar
SCRUM:  
unknown committed
3291
    if (check_access(thd,CREATE_ACL,lex->name,0,1,0))
3292
      break;
unknown's avatar
unknown committed
3293
    res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name),
unknown's avatar
unknown committed
3294
			 &lex->create_info, 0);
3295 3296
    break;
  }
unknown's avatar
unknown committed
3297
  case SQLCOM_DROP_DB:
3298
  {
unknown's avatar
unknown committed
3299
    char *alias;
unknown's avatar
unknown committed
3300
    if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
unknown's avatar
unknown committed
3301
    {
3302
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
unknown's avatar
unknown committed
3303 3304
      break;
    }
3305 3306 3307 3308 3309 3310 3311
    /*
      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.
    */
3312
#ifdef HAVE_REPLICATION
3313 3314 3315
    if (thd->slave_thread && 
	(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(lex->name)))
unknown's avatar
Fix for  
unknown committed
3316
    {
unknown's avatar
unknown committed
3317
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3318
      break;
unknown's avatar
Fix for  
unknown committed
3319
    }
3320
#endif
unknown's avatar
SCRUM:  
unknown committed
3321
    if (check_access(thd,DROP_ACL,lex->name,0,1,0))
3322
      break;
3323 3324
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3325 3326
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3327 3328
      goto error;
    }
3329 3330
    res=mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : lex->name),
                    lex->drop_if_exists, 0);
3331 3332
    break;
  }
3333 3334
  case SQLCOM_ALTER_DB:
  {
3335 3336
    char *db= lex->name ? lex->name : thd->db;
    if (!db)
3337
    {
unknown's avatar
unknown committed
3338 3339
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
      break;
3340 3341
    }
    if (!strip_sp(db) || check_db_name(db))
3342
    {
3343
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
3344 3345
      break;
    }
unknown's avatar
unknown committed
3346 3347 3348
    /*
      If in a slave thread :
      ALTER DATABASE DB may not be preceded by USE DB.
3349
      For that reason, maybe db_ok() in sql/slave.cc did not check the
unknown's avatar
unknown committed
3350 3351 3352 3353
      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
3354
    if (thd->slave_thread &&
3355 3356
	(!db_ok(db, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(db)))
unknown's avatar
unknown committed
3357
    {
unknown's avatar
unknown committed
3358
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
unknown's avatar
unknown committed
3359 3360 3361
      break;
    }
#endif
3362
    if (check_access(thd, ALTER_ACL, db, 0, 1, 0))
3363 3364 3365
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3366 3367
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3368 3369
      goto error;
    }
3370
    res= mysql_alter_db(thd, db, &lex->create_info);
3371 3372
    break;
  }
unknown's avatar
unknown committed
3373 3374 3375 3376
  case SQLCOM_SHOW_CREATE_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
3377
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
unknown's avatar
unknown committed
3378 3379
      break;
    }
unknown's avatar
fixed  
unknown committed
3380
    if (check_access(thd,SELECT_ACL,lex->name,0,1,0))
unknown's avatar
unknown committed
3381
      break;
unknown's avatar
unknown committed
3382
    res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
unknown's avatar
unknown committed
3383 3384
    break;
  }
unknown's avatar
unknown committed
3385
  case SQLCOM_CREATE_FUNCTION:                  // UDF function
unknown's avatar
unknown committed
3386 3387 3388
  {
    if (check_access(thd,INSERT_ACL,"mysql",0,1,0))
      break;
unknown's avatar
unknown committed
3389
#ifdef HAVE_DLOPEN
3390
    if (sp_find_function(thd, lex->spname))
unknown's avatar
unknown committed
3391
    {
3392
      my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str);
unknown's avatar
unknown committed
3393 3394
      goto error;
    }
3395
    if (!(res = mysql_create_function(thd, &lex->udf)))
unknown's avatar
unknown committed
3396
      send_ok(thd);
unknown's avatar
unknown committed
3397
#else
unknown's avatar
unknown committed
3398
    res= TRUE;
unknown's avatar
unknown committed
3399 3400
#endif
    break;
unknown's avatar
unknown committed
3401
  }
unknown's avatar
SCRUM:  
unknown committed
3402
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3403 3404 3405 3406 3407 3408 3409 3410
  case SQLCOM_CREATE_USER:
  {
    if (check_access(thd, GRANT_ACL,"mysql",0,1,0))
      break;
    if (!(res= mysql_create_user(thd, lex->users_list)))
    {
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
3411
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3412 3413 3414 3415 3416 3417
        mysql_bin_log.write(&qinfo);
      }
      send_ok(thd);
    }
    break;
  }
3418 3419
  case SQLCOM_DROP_USER:
  {
unknown's avatar
SCRUM:  
unknown committed
3420
    if (check_access(thd, GRANT_ACL,"mysql",0,1,0))
3421 3422 3423 3424 3425
      break;
    if (!(res= mysql_drop_user(thd, lex->users_list)))
    {
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
3426
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440
        mysql_bin_log.write(&qinfo);
      }
      send_ok(thd);
    }
    break;
  }
  case SQLCOM_RENAME_USER:
  {
    if (check_access(thd, GRANT_ACL,"mysql",0,1,0))
      break;
    if (!(res= mysql_rename_user(thd, lex->users_list)))
    {
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
3441
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3442
        mysql_bin_log.write(&qinfo);
3443 3444 3445 3446 3447 3448 3449
      }
      send_ok(thd);
    }
    break;
  }
  case SQLCOM_REVOKE_ALL:
  {
unknown's avatar
SCRUM:  
unknown committed
3450
    if (check_access(thd, GRANT_ACL ,"mysql",0,1,0))
3451 3452 3453 3454 3455
      break;
    if (!(res = mysql_revoke_all(thd, lex->users_list)))
    {
      if (mysql_bin_log.is_open())
      {
3456
	Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3457 3458 3459 3460 3461 3462
	mysql_bin_log.write(&qinfo);
      }
      send_ok(thd);
    }
    break;
  }
3463 3464 3465 3466
  case SQLCOM_REVOKE:
  case SQLCOM_GRANT:
  {
    if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
unknown's avatar
merged  
unknown committed
3467
		     first_table ?  first_table->db : select_lex->db,
unknown's avatar
VIEW  
unknown committed
3468 3469
		     first_table ? &first_table->grant.privilege : 0,
		     first_table ? 0 : 1, 0))
3470 3471
      goto error;

unknown's avatar
SCRUM  
unknown committed
3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484
    if (specialflag & SPECIAL_NO_RESOLVE)
    {
      LEX_USER *user;
      List_iterator <LEX_USER> user_list(lex->users_list);
      while ((user=user_list++))
      {
	if (hostname_requires_resolving(user->host.str))
	  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
			      ER_WARN_HOSTNAME_WONT_WORK,
			      ER(ER_WARN_HOSTNAME_WONT_WORK),
			      user->host.str);
      }
    }
unknown's avatar
VIEW  
unknown committed
3485
    if (first_table)
3486
    {
3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510
      if (!lex->columns.elements && 
          sp_exists_routine(thd, all_tables, 1, 1))
      {
        uint grants= lex->all_privileges 
		   ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
		   : lex->grant;
        if (grant_option && 
	    check_grant_procedure(thd, grants | GRANT_ACL, all_tables, 0))
	  goto error;
        res= mysql_procedure_grant(thd, all_tables, lex->users_list,
				   grants, lex->sql_command == SQLCOM_REVOKE,0);
      }
      else
      {
	if (grant_option && check_grant(thd,
					(lex->grant | lex->grant_tot_col |
					 GRANT_ACL),
					all_tables, 0, UINT_MAX, 0))
	  goto error;
        res= mysql_table_grant(thd, all_tables, lex->users_list,
			       lex->columns, lex->grant,
			       lex->sql_command == SQLCOM_REVOKE);
      }
      if (!res && mysql_bin_log.is_open())
3511
      {
unknown's avatar
unknown committed
3512
        thd->clear_error();
unknown's avatar
unknown committed
3513
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3514
        mysql_bin_log.write(&qinfo);
3515 3516 3517 3518 3519 3520
      }
    }
    else
    {
      if (lex->columns.elements)
      {
unknown's avatar
unknown committed
3521 3522
	my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
                   MYF(0));
unknown's avatar
unknown committed
3523
        goto error;
3524 3525 3526 3527 3528 3529 3530 3531
      }
      else
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
	if (mysql_bin_log.is_open())
	{
unknown's avatar
unknown committed
3532
          thd->clear_error();
3533
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3534 3535
	  mysql_bin_log.write(&qinfo);
	}
3536
	if (lex->sql_command == SQLCOM_GRANT)
unknown's avatar
unknown committed
3537
	{
unknown's avatar
unknown committed
3538 3539 3540
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
unknown's avatar
unknown committed
3541
	    reset_mqh(user);
unknown's avatar
unknown committed
3542
	}
3543 3544 3545 3546
      }
    }
    break;
  }
unknown's avatar
SCRUM  
unknown committed
3547
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
unknown's avatar
unknown committed
3548
  case SQLCOM_RESET:
3549 3550 3551 3552 3553 3554 3555
    /* 
       RESET commands are never written to the binary log, so we have to
       initialize this variable because RESET shares the same code as FLUSH
    */
    lex->no_write_to_binlog= 1;
  case SQLCOM_FLUSH:
  {
unknown's avatar
VIEW  
unknown committed
3556
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, all_tables))
unknown's avatar
unknown committed
3557
      goto error;
3558 3559 3560 3561 3562
    /*
      reload_acl_and_cache() will tell us if we are allowed to write to the
      binlog or not.
    */
    bool write_to_binlog;
unknown's avatar
unknown committed
3563
    if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
3564 3565 3566 3567 3568 3569 3570 3571 3572
    {
      /*
        We WANT to write and we CAN write.
        ! we write after unlocking the table.
      */
      if (!lex->no_write_to_binlog && write_to_binlog)
      {
        if (mysql_bin_log.is_open())
        {
3573
          Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3574 3575 3576 3577 3578
          mysql_bin_log.write(&qinfo);
        }
      }
      send_ok(thd);
    }
unknown's avatar
unknown committed
3579
    break;
3580
  }
unknown's avatar
unknown committed
3581
  case SQLCOM_KILL:
3582 3583 3584 3585 3586 3587 3588 3589 3590 3591
  {
    Item *it= (Item *)lex->value_list.head();

    if (it->fix_fields(lex->thd, 0, &it) || it->check_cols(1))
    {
      my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
		 MYF(0));
      goto error;
    }
    kill_one_thread(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
unknown's avatar
unknown committed
3592
    break;
3593
  }
unknown's avatar
SCRUM:  
unknown committed
3594
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
3595
  case SQLCOM_SHOW_GRANTS:
3596 3597
    if ((thd->priv_user &&
	 !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
unknown's avatar
SCRUM:  
unknown committed
3598
	!check_access(thd, SELECT_ACL, "mysql",0,1,0))
unknown's avatar
unknown committed
3599 3600 3601 3602
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
unknown's avatar
SCRUM:  
unknown committed
3603
#endif
3604
  case SQLCOM_HA_OPEN:
unknown's avatar
VIEW  
unknown committed
3605 3606 3607
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL, all_tables, 0))
3608
      goto error;
unknown's avatar
VIEW  
unknown committed
3609
    res= mysql_ha_open(thd, first_table);
3610 3611
    break;
  case SQLCOM_HA_CLOSE:
unknown's avatar
VIEW  
unknown committed
3612 3613
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables))
3614
      goto error;
unknown's avatar
VIEW  
unknown committed
3615
    res= mysql_ha_close(thd, first_table);
3616 3617
    break;
  case SQLCOM_HA_READ:
unknown's avatar
VIEW  
unknown committed
3618
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3619 3620 3621 3622 3623
    /*
      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.
    */
unknown's avatar
VIEW  
unknown committed
3624
    if (check_db_used(thd, all_tables))
3625
      goto error;
unknown's avatar
VIEW  
unknown committed
3626 3627 3628
    res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->backup_dir,
                       lex->insert_list, lex->ha_rkey_mode, select_lex->where,
                       select_lex->select_limit, select_lex->offset_limit);
3629 3630
    break;

unknown's avatar
unknown committed
3631
  case SQLCOM_BEGIN:
unknown's avatar
unknown committed
3632 3633 3634
    if (thd->locked_tables)
    {
      thd->lock=thd->locked_tables;
3635
      thd->locked_tables=0;			// Will be automatically closed
unknown's avatar
unknown committed
3636 3637
      close_thread_tables(thd);			// Free tables
    }
unknown's avatar
unknown committed
3638
    if (end_active_trans(thd))
unknown's avatar
unknown committed
3639
      goto error;
unknown's avatar
unknown committed
3640 3641
    else
    {
3642
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
unknown's avatar
unknown committed
3643 3644
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
3645 3646 3647
      if (!(lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) ||
          !(res= ha_start_consistent_snapshot(thd)))
        send_ok(thd);
unknown's avatar
unknown committed
3648
    }
unknown's avatar
unknown committed
3649 3650
    break;
  case SQLCOM_COMMIT:
3651 3652 3653 3654 3655
    /*
      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...)
    */
unknown's avatar
unknown committed
3656
  {
3657
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
3658 3659
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
unknown's avatar
unknown committed
3660
    {
3661
      send_ok(thd);
unknown's avatar
unknown committed
3662
    }
unknown's avatar
unknown committed
3663
    else
unknown's avatar
unknown committed
3664
      goto error;
unknown's avatar
unknown committed
3665
    break;
unknown's avatar
unknown committed
3666
  }
unknown's avatar
unknown committed
3667 3668 3669
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
3670
    {
unknown's avatar
unknown committed
3671 3672 3673 3674 3675 3676 3677 3678 3679 3680
      /*
        If a non-transactional table was updated, warn; don't warn if this is a
        slave thread (because when a slave thread executes a ROLLBACK, it has
        been read from the binary log, so it's 100% sure and normal to produce
        error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
        slave SQL thread, it would not stop the thread but just be printed in
        the error log; but we don't want users to wonder why they have this
        message in the error log, so we don't send it.
      */
      if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
unknown's avatar
unknown committed
3681 3682 3683 3684
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                     ER_WARNING_NOT_COMPLETE_ROLLBACK,
                     ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
      send_ok(thd);
3685
    }
unknown's avatar
unknown committed
3686
    else
unknown's avatar
unknown committed
3687
      res= TRUE;
3688
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
3689
    break;
unknown's avatar
unknown committed
3690 3691 3692
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
    if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
    {
unknown's avatar
unknown committed
3693
      if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
unknown's avatar
unknown committed
3694 3695 3696 3697
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                     ER_WARNING_NOT_COMPLETE_ROLLBACK,
                     ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
      send_ok(thd);
unknown's avatar
unknown committed
3698 3699
    }
    else
unknown's avatar
unknown committed
3700
      goto error;
unknown's avatar
unknown committed
3701
    break;
3702
  case SQLCOM_SAVEPOINT:
unknown's avatar
unknown committed
3703
    if (!ha_savepoint(thd, lex->savepoint_name))
unknown's avatar
unknown committed
3704
      send_ok(thd);
unknown's avatar
unknown committed
3705
    else
unknown's avatar
unknown committed
3706
      goto error;
3707
    break;
3708 3709
  case SQLCOM_CREATE_PROCEDURE:
  case SQLCOM_CREATE_SPFUNCTION:
unknown's avatar
unknown committed
3710
  {
3711
    uint namelen;
3712
    char *name, *db;
unknown's avatar
unknown committed
3713
    int result;
3714

unknown's avatar
unknown committed
3715
    DBUG_ASSERT(lex->sphead);
3716

3717
    if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0))
3718 3719 3720 3721 3722
    {
      delete lex->sphead;
      lex->sphead= 0;
      goto error;
    }
3723 3724 3725 3726 3727 3728 3729
    
    if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0])
    {
      lex->sphead->m_db.length= strlen(thd->db);
      lex->sphead->m_db.str= strmake_root(thd->mem_root, thd->db, 
      					   lex->sphead->m_db.length);
    }
3730 3731

    name= lex->sphead->name(&namelen);
3732
#ifdef HAVE_DLOPEN
unknown's avatar
unknown committed
3733 3734 3735
    if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
    {
      udf_func *udf = find_udf(name, namelen);
3736

unknown's avatar
unknown committed
3737
      if (udf)
3738
      {
3739
	my_error(ER_UDF_EXISTS, MYF(0), name);
unknown's avatar
unknown committed
3740
	delete lex->sphead;
3741
	lex->sphead= 0;
3742
	goto error;
3743
      }
unknown's avatar
unknown committed
3744 3745 3746 3747 3748
    }
#endif
    if (lex->sphead->m_type == TYPE_ENUM_FUNCTION &&
	!lex->sphead->m_has_return)
    {
3749
      my_error(ER_SP_NORETURN, MYF(0), name);
unknown's avatar
unknown committed
3750
      delete lex->sphead;
3751
      lex->sphead= 0;
unknown's avatar
unknown committed
3752 3753 3754
      goto error;
    }

3755 3756
    name= thd->strdup(name); 
    db= thd->strmake(lex->sphead->m_db.str, lex->sphead->m_db.length);
unknown's avatar
unknown committed
3757 3758
    res= (result= lex->sphead->create(thd));
    switch (result) {
unknown's avatar
unknown committed
3759
    case SP_OK:
3760
      lex->unit.cleanup();
unknown's avatar
unknown committed
3761 3762
      delete lex->sphead;
      lex->sphead= 0;
unknown's avatar
unknown committed
3763
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774
      /* only add privileges if really neccessary */
      if (sp_automatic_privileges &&
          check_procedure_access(thd, DEFAULT_CREATE_PROC_ACLS,
      				 db, name, 1))
      {
        close_thread_tables(thd);
        if (sp_grant_privileges(thd, db, name))
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
	  	       ER_PROC_AUTO_GRANT_FAIL,
		       ER(ER_PROC_AUTO_GRANT_FAIL));
      }
unknown's avatar
unknown committed
3775
#endif
3776
      send_ok(thd);
3777
      break;
unknown's avatar
unknown committed
3778
    case SP_WRITE_ROW_FAILED:
3779
      my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name);
3780
      lex->unit.cleanup();
unknown's avatar
unknown committed
3781 3782 3783
      delete lex->sphead;
      lex->sphead= 0;
      goto error;
3784
    case SP_NO_DB_ERROR:
3785
      my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
3786
      lex->unit.cleanup();
3787 3788 3789
      delete lex->sphead;
      lex->sphead= 0;
      goto error;
unknown's avatar
unknown committed
3790
    default:
3791
      my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name);
3792
      lex->unit.cleanup();
unknown's avatar
unknown committed
3793 3794 3795
      delete lex->sphead;
      lex->sphead= 0;
      goto error;
3796
    }
unknown's avatar
unknown committed
3797 3798
    break;
  }
3799 3800 3801 3802
  case SQLCOM_CALL:
    {
      sp_head *sp;

3803
      if (!(sp= sp_find_procedure(thd, lex->spname)))
3804
      {
3805
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
unknown's avatar
unknown committed
3806
                 lex->spname->m_qname.str);
3807
	goto error;
3808 3809 3810
      }
      else
      {
3811
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3812
	st_sp_security_context save_ctx;
3813
#endif
unknown's avatar
unknown committed
3814
	ha_rows select_limit;
unknown's avatar
unknown committed
3815 3816
        /* bits that should be cleared in thd->server_status */
	uint bits_to_be_cleared= 0;
3817

unknown's avatar
unknown committed
3818
	/* In case the arguments are subselects... */
unknown's avatar
VIEW  
unknown committed
3819
	if (all_tables &&
unknown's avatar
unknown committed
3820 3821 3822
	    (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
	     open_and_lock_tables(thd, all_tables)))
          goto error;
3823

3824
#ifndef EMBEDDED_LIBRARY
3825 3826
	my_bool nsok= thd->net.no_send_ok;
	thd->net.no_send_ok= TRUE;
3827
#endif
3828
	if (sp->m_multi_results)
3829
	{
3830
	  if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
3831
	  {
unknown's avatar
unknown committed
3832
	    my_message(ER_SP_BADSELECT, ER(ER_SP_BADSELECT), MYF(0));
3833 3834 3835 3836 3837
#ifndef EMBEDDED_LIBRARY
	    thd->net.no_send_ok= nsok;
#endif
	    goto error;
	  }
unknown's avatar
unknown committed
3838 3839 3840 3841 3842 3843 3844
          /*
            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;
3845 3846
	}

3847
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3848 3849 3850 3851 3852 3853 3854 3855
	if (check_procedure_access(thd, EXECUTE_ACL, 
				   sp->m_db.str, sp->m_name.str, 0))
	{
#ifndef EMBEDDED_LIBRARY
	  thd->net.no_send_ok= nsok;
#endif
	  goto error;
	}
3856
	sp_change_security_context(thd, sp, &save_ctx);
3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867
	if (save_ctx.changed && 
	    check_procedure_access(thd, EXECUTE_ACL, 
				   sp->m_db.str, sp->m_name.str, 0))
	{
#ifndef EMBEDDED_LIBRARY
	  thd->net.no_send_ok= nsok;
#endif
	  sp_restore_security_context(thd, sp, &save_ctx);
	  goto error;
	}

3868
#endif
unknown's avatar
unknown committed
3869 3870
	select_limit= thd->variables.select_limit;
	thd->variables.select_limit= HA_POS_ERROR;
3871

3872
	thd->row_count_func= 0;
3873
	res= sp->execute_procedure(thd, &lex->value_list);
3874

unknown's avatar
unknown committed
3875
	thd->variables.select_limit= select_limit;
3876
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3877
	sp_restore_security_context(thd, sp, &save_ctx);
3878
#endif
3879

3880
#ifndef EMBEDDED_LIBRARY
3881
	thd->net.no_send_ok= nsok;
3882
#endif
unknown's avatar
unknown committed
3883
        thd->server_status&= ~bits_to_be_cleared;
3884

unknown's avatar
unknown committed
3885
	if (!res)
unknown's avatar
unknown committed
3886 3887
	  send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
                                thd->row_count_func));
3888 3889
	else
	  goto error;		// Substatement should already have sent error
3890
      }
3891
      break;
3892 3893
    }
  case SQLCOM_ALTER_PROCEDURE:
3894
  case SQLCOM_ALTER_FUNCTION:
3895
    {
unknown's avatar
unknown committed
3896
      int result;
3897 3898 3899 3900
      sp_head *sp;
      st_sp_chistics chistics;

      memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
unknown's avatar
unknown committed
3901
      if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
3902
	sp= sp_find_procedure(thd, lex->spname);
3903
      else
3904 3905 3906
	sp= sp_find_function(thd, lex->spname);
      mysql_reset_errors(thd);
      if (! sp)
unknown's avatar
merge  
unknown committed
3907
	result= SP_KEY_NOT_FOUND;
3908 3909
      else
      {
3910 3911 3912
        if (check_procedure_access(thd, ALTER_PROC_ACL, sp->m_db.str, 
				  sp->m_name.str, 0))
	  goto error;
3913 3914
	memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
	if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
unknown's avatar
merge  
unknown committed
3915
	  result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
3916
	else
unknown's avatar
merge  
unknown committed
3917
	  result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
3918
      }
unknown's avatar
unknown committed
3919
      switch (result)
3920
      {
unknown's avatar
unknown committed
3921
      case SP_OK:
3922
	send_ok(thd);
unknown's avatar
unknown committed
3923 3924
	break;
      case SP_KEY_NOT_FOUND:
3925 3926
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
3927 3928
	goto error;
      default:
3929 3930
	my_error(ER_SP_CANT_ALTER, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
3931
	goto error;
3932
      }
3933
      break;
3934 3935
    }
  case SQLCOM_DROP_PROCEDURE:
3936
  case SQLCOM_DROP_FUNCTION:
3937
    {
3938
      sp_head *sp;
unknown's avatar
unknown committed
3939
      int result;
3940
      char *db, *name;
3941

3942
      if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
3943 3944 3945 3946
	sp= sp_find_procedure(thd, lex->spname);
      else
	sp= sp_find_function(thd, lex->spname);
      mysql_reset_errors(thd);
3947
      if (sp)
3948
      {
3949 3950 3951
        db= thd->strdup(sp->m_db.str);
	name= thd->strdup(sp->m_name.str);
	if (check_procedure_access(thd, ALTER_PROC_ACL, db, name, 0))
unknown's avatar
merge  
unknown committed
3952
          goto error;
unknown's avatar
unknown committed
3953
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3954 3955 3956 3957 3958 3959 3960
	if (sp_automatic_privileges &&
	    sp_revoke_privileges(thd, db, name))
	{
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
		       ER_PROC_AUTO_REVOKE_FAIL,
		       ER(ER_PROC_AUTO_REVOKE_FAIL));
	}
unknown's avatar
unknown committed
3961
#endif
3962
	if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
unknown's avatar
merge  
unknown committed
3963
	  result= sp_drop_procedure(thd, lex->spname);
3964
	else
unknown's avatar
merge  
unknown committed
3965
	  result= sp_drop_function(thd, lex->spname);
3966 3967 3968
      }
      else
      {
3969
#ifdef HAVE_DLOPEN
3970 3971 3972 3973 3974 3975 3976 3977 3978
	if (lex->sql_command == SQLCOM_DROP_FUNCTION)
	{
          udf_func *udf = find_udf(lex->spname->m_name.str,
                                   lex->spname->m_name.length);
          if (udf)
          {
	    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0))
	      goto error;
	    if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
3979
	    {
3980 3981
	      send_ok(thd);
	      break;
3982 3983
	    }
	  }
3984
	}
3985 3986
#endif
	result= SP_KEY_NOT_FOUND;
3987
      }
unknown's avatar
unknown committed
3988 3989
      res= result;
      switch (result)
3990 3991
      {
      case SP_OK:
3992
	send_ok(thd);
3993 3994
	break;
      case SP_KEY_NOT_FOUND:
3995 3996
	if (lex->drop_if_exists)
	{
3997
	  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
3998
			      ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
3999
			      SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4000
	  res= FALSE;
4001 4002 4003
	  send_ok(thd);
	  break;
	}
4004 4005
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4006 4007
	goto error;
      default:
4008 4009
	my_error(ER_SP_DROP_FAILED, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4010
	goto error;
4011
      }
4012
      break;
4013
    }
unknown's avatar
unknown committed
4014 4015
  case SQLCOM_SHOW_CREATE_PROC:
    {
4016
      if (lex->spname->m_name.length > NAME_LEN)
unknown's avatar
unknown committed
4017
      {
4018
	my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
unknown's avatar
unknown committed
4019 4020
	goto error;
      }
unknown's avatar
unknown committed
4021
      if (sp_show_create_procedure(thd, lex->spname) != SP_OK)
4022
      {			/* We don't distinguish between errors for now */
4023 4024
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4025 4026 4027 4028 4029 4030
	goto error;
      }
      break;
    }
  case SQLCOM_SHOW_CREATE_FUNC:
    {
4031
      if (lex->spname->m_name.length > NAME_LEN)
unknown's avatar
unknown committed
4032
      {
4033
	my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
unknown's avatar
unknown committed
4034 4035
	goto error;
      }
unknown's avatar
unknown committed
4036
      if (sp_show_create_function(thd, lex->spname) != SP_OK)
4037
      {			/* We don't distinguish between errors for now */
4038 4039
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4040 4041 4042 4043 4044 4045
	goto error;
      }
      break;
    }
  case SQLCOM_SHOW_STATUS_PROC:
    {
4046
      res= sp_show_status_procedure(thd, (lex->wild ?
unknown's avatar
unknown committed
4047 4048 4049 4050 4051
					  lex->wild->ptr() : NullS));
      break;
    }
  case SQLCOM_SHOW_STATUS_FUNC:
    {
4052
      res= sp_show_status_function(thd, (lex->wild ? 
unknown's avatar
unknown committed
4053 4054 4055
					 lex->wild->ptr() : NullS));
      break;
    }
unknown's avatar
VIEW  
unknown committed
4056 4057 4058 4059 4060 4061 4062
  case SQLCOM_CREATE_VIEW:
    {
      res= mysql_create_view(thd, thd->lex->create_view_mode);
      break;
    }
  case SQLCOM_DROP_VIEW:
    {
unknown's avatar
unknown committed
4063 4064 4065
      if (check_table_access(thd, DROP_ACL, all_tables, 0) ||
          end_active_trans(thd))
        goto error;
unknown's avatar
VIEW  
unknown committed
4066 4067 4068
      res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
      break;
    }
4069 4070
  case SQLCOM_CREATE_TRIGGER:
  {
4071 4072 4073
    res= mysql_create_or_drop_trigger(thd, all_tables, 1);

    /* We don't care about trigger body after this point */
4074 4075 4076 4077 4078 4079 4080 4081 4082
    delete lex->sphead;
    lex->sphead= 0;
    break;
  }
  case SQLCOM_DROP_TRIGGER:
  {
    res= mysql_create_or_drop_trigger(thd, all_tables, 0);
    break;
  }
unknown's avatar
unknown committed
4083
  default:					/* Impossible */
4084
    send_ok(thd);
unknown's avatar
unknown committed
4085 4086
    break;
  }
unknown's avatar
unknown committed
4087
  thd->proc_info="query end";
4088
  if (thd->one_shot_set)
unknown's avatar
unknown committed
4089 4090 4091 4092 4093 4094 4095 4096
  {
    /*
      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 (lex->sql_command != SQLCOM_SET_OPTION)
4097
    {
unknown's avatar
unknown committed
4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109
      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;
4110
    }
unknown's avatar
unknown committed
4111
  }
4112

4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132
  /*
    The return value for ROW_COUNT() is "implementation dependent" if
    the statement is not DELETE, INSERT or UPDATE (or a CALL executing
    such a statement), but -1 is what JDBC and ODBC wants.
   */
  switch (lex->sql_command) {
  case SQLCOM_UPDATE:
  case SQLCOM_UPDATE_MULTI:
  case SQLCOM_REPLACE:
  case SQLCOM_INSERT:
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  case SQLCOM_DELETE:
  case SQLCOM_DELETE_MULTI:
  case SQLCOM_CALL:
    break;
  default:
    thd->row_count_func= -1;
  }

unknown's avatar
unknown committed
4133
  DBUG_RETURN(res || thd->net.report_error);
unknown's avatar
unknown committed
4134 4135

error:
unknown's avatar
unknown committed
4136
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
4137 4138 4139
}


unknown's avatar
unknown committed
4140 4141
/*
  Check grants for commands which work only with one table and all other
4142
  tables belonging to subselects or implicitly opened tables.
unknown's avatar
unknown committed
4143

4144
  SYNOPSIS
unknown's avatar
unknown committed
4145 4146
    check_one_table_access()
    thd			Thread handler
4147
    privilege		requested privilege
unknown's avatar
VIEW  
unknown committed
4148
    all_tables		global table list of query
unknown's avatar
unknown committed
4149 4150 4151

  RETURN
    0 - OK
unknown's avatar
unknown committed
4152
    1 - access denied, error is sent to client
unknown's avatar
unknown committed
4153 4154
*/

4155
bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
unknown's avatar
unknown committed
4156
{
unknown's avatar
VIEW  
unknown committed
4157 4158
  if (check_access(thd, privilege, all_tables->db,
		   &all_tables->grant.privilege, 0, 0))
unknown's avatar
unknown committed
4159
    return 1;
unknown's avatar
unknown committed
4160

unknown's avatar
unknown committed
4161
  /* Show only 1 table for check_grant */
unknown's avatar
VIEW  
unknown committed
4162
  if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0))
unknown's avatar
unknown committed
4163
    return 1;
unknown's avatar
unknown committed
4164

4165
  /* Check rights on tables of subselects and implictly opened tables */
unknown's avatar
unknown committed
4166
  TABLE_LIST *subselects_tables;
unknown's avatar
VIEW  
unknown committed
4167
  if ((subselects_tables= all_tables->next_global))
unknown's avatar
unknown committed
4168
  {
unknown's avatar
VIEW  
unknown committed
4169
    if ((check_table_access(thd, SELECT_ACL, subselects_tables, 0)))
unknown's avatar
unknown committed
4170 4171 4172
      return 1;
  }
  return 0;
unknown's avatar
unknown committed
4173 4174 4175
}


unknown's avatar
unknown committed
4176
/****************************************************************************
unknown's avatar
unknown committed
4177
  Get the user (global) and database privileges for all used tables
unknown's avatar
unknown committed
4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190

  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
4191 4192
                is enough to satisfy the request and the global grants contains
                a SELECT grant.
unknown's avatar
unknown committed
4193 4194 4195
****************************************************************************/

bool
unknown's avatar
unknown committed
4196
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
4197
	     bool dont_check_global_grants, bool no_errors)
unknown's avatar
unknown committed
4198
{
unknown's avatar
unknown committed
4199 4200 4201 4202
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  ulong db_access;
#endif
  ulong dummy;
4203 4204 4205
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("db: %s  want_access: %lu  master_access: %lu",
                      db ? db : "", want_access, thd->master_access));
unknown's avatar
unknown committed
4206 4207 4208 4209 4210
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

4211
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
4212
  {
4213
    DBUG_PRINT("error",("No database"));
4214
    if (!no_errors)
unknown's avatar
unknown committed
4215 4216
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
                 MYF(0));                       /* purecov: tested */
unknown's avatar
unknown committed
4217
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4218 4219
  }

unknown's avatar
unknown committed
4220 4221 4222
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  DBUG_RETURN(0);
#else
unknown's avatar
unknown committed
4223 4224
  if ((thd->master_access & want_access) == want_access)
  {
4225 4226 4227 4228 4229 4230 4231 4232
    /*
      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
    */
    db_access= thd->db_access;
    if (!(thd->master_access & SELECT_ACL) &&
	(db && (!thd->db || strcmp(db,thd->db))))
4233
      db_access=acl_get(thd->host, thd->ip,
4234
			thd->priv_user, db, test(want_access & GRANT_ACL));
4235
    *save_priv=thd->master_access | db_access;
unknown's avatar
unknown committed
4236
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
4237
  }
4238
  if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
4239
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
4240
  {						// We can never grant this
4241
    DBUG_PRINT("error",("No possible access"));
4242
    if (!no_errors)
4243 4244 4245 4246 4247 4248
      my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
               thd->priv_user,
               thd->priv_host,
               (thd->password ?
                ER(ER_YES) :
                ER(ER_NO)));                    /* purecov: tested */
unknown's avatar
unknown committed
4249
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4250 4251 4252
  }

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

unknown's avatar
unknown committed
4255
  if (db && (!thd->db || strcmp(db,thd->db)))
4256
    db_access=acl_get(thd->host, thd->ip,
4257
		      thd->priv_user, db, test(want_access & GRANT_ACL));
unknown's avatar
unknown committed
4258 4259
  else
    db_access=thd->db_access;
4260
  DBUG_PRINT("info",("db_access: %lu", db_access));
unknown's avatar
unknown committed
4261
  /* Remove SHOW attribute and access rights we already have */
4262
  want_access &= ~(thd->master_access | EXTRA_ACL);
4263 4264
  DBUG_PRINT("info",("db_access: %lu  want_access: %lu",
                     db_access, want_access));
unknown's avatar
unknown committed
4265
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
4266 4267

  /* grant_option is set if there exists a single table or column grant */
unknown's avatar
unknown committed
4268
  if (db_access == want_access ||
4269
      (grant_option && !dont_check_global_grants &&
4270
       !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
unknown's avatar
unknown committed
4271
    DBUG_RETURN(FALSE);				/* Ok */
4272 4273

  DBUG_PRINT("error",("Access denied"));
4274
  if (!no_errors)
4275 4276 4277 4278 4279 4280
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
             thd->priv_user,
             thd->priv_host,
             (db ? db : (thd->db ?
                         thd->db :
                         "unknown")));          /* purecov: tested */
unknown's avatar
unknown committed
4281
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4282
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
4283 4284 4285
}


4286 4287 4288 4289 4290 4291 4292 4293 4294
/*
  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
4295
    One gets access right if one has ANY of the rights in want_access
4296 4297 4298 4299 4300 4301 4302 4303
    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
4304 4305

bool check_global_access(THD *thd, ulong want_access)
unknown's avatar
unknown committed
4306
{
unknown's avatar
unknown committed
4307 4308 4309
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  return 0;
#else
unknown's avatar
unknown committed
4310
  char command[128];
4311
  if ((thd->master_access & want_access))
unknown's avatar
unknown committed
4312 4313
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
4314
  my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
unknown's avatar
unknown committed
4315
  return 1;
unknown's avatar
unknown committed
4316
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
4317 4318 4319
}


unknown's avatar
unknown committed
4320
/*
unknown's avatar
unknown committed
4321 4322
  Check the privilege for all used tables.  Table privileges are cached
  in the table list for GRANT checking
unknown's avatar
unknown committed
4323 4324
*/

4325
bool
unknown's avatar
unknown committed
4326
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
4327
		   bool no_errors)
unknown's avatar
unknown committed
4328
{
unknown's avatar
unknown committed
4329 4330
  uint found=0;
  ulong found_access=0;
unknown's avatar
unknown committed
4331
  TABLE_LIST *org_tables=tables;
unknown's avatar
VIEW  
unknown committed
4332
  for (; tables; tables= tables->next_global)
unknown's avatar
unknown committed
4333
  {
4334
    if (tables->derived || tables->schema_table || tables->belong_to_view ||
4335
        (tables->table && (int)tables->table->s->tmp_table) ||
4336 4337
        my_tz_check_n_skip_implicit_tables(&tables,
                                           thd->lex->time_zone_tables_used))
unknown's avatar
unknown committed
4338
      continue;
unknown's avatar
unknown committed
4339 4340
    if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
	thd->db)
unknown's avatar
unknown committed
4341
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
4342
    else if (tables->db && tables->db == thd->db)
unknown's avatar
unknown committed
4343 4344 4345 4346 4347
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
4348 4349
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
			 0, no_errors))
unknown's avatar
unknown committed
4350 4351
	  return TRUE;				// Access denied
	found_access=tables->grant.privilege;
unknown's avatar
unknown committed
4352
	found=1;
unknown's avatar
unknown committed
4353 4354
      }
    }
4355
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
4356
			  0, no_errors))
4357
      return TRUE;
unknown's avatar
unknown committed
4358 4359
  }
  if (grant_option)
4360
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
unknown's avatar
unknown committed
4361
		       test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
unknown's avatar
unknown committed
4362 4363 4364
  return FALSE;
}

4365

4366 4367 4368 4369 4370 4371 4372 4373
bool
check_procedure_access(THD *thd, ulong want_access,char *db, char *name,
		       bool no_errors)
{
  TABLE_LIST tables[1];
  
  bzero((char *)tables, sizeof(TABLE_LIST));
  tables->db= db;
4374
  tables->table_name= tables->alias= name;
4375 4376 4377 4378 4379 4380 4381
  
  if ((thd->master_access & want_access) == want_access && !thd->db)
    tables->grant.privilege= want_access;
  else if (check_access(thd,want_access,db,&tables->grant.privilege,
			0, no_errors))
    return TRUE;
  
unknown's avatar
unknown committed
4382
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4383 4384
  if (grant_option)
    return check_grant_procedure(thd, want_access, tables, no_errors);
unknown's avatar
unknown committed
4385
#endif
4386 4387 4388 4389

  return FALSE;
}

4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424
/*
  Check if the given table has any of the asked privileges

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

  RETURN
    0  ok
    1  error
*/


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

  /* This loop will work as long as we have less than 32 privileges */
  for (access= 1; access < want_access ; access<<= 1)
  {
    if (access & want_access)
    {
      if (!check_access(thd, access, table->db,
                        &table->grant.privilege, 0, 1) &&
          !grant_option || !check_grant(thd, access, table, 0, 1, 1))
        DBUG_RETURN(0);
    }
  }
  DBUG_PRINT("exit",("no matching access rights"));
  DBUG_RETURN(1);
}


4425 4426
bool check_merge_table_access(THD *thd, char *db,
			      TABLE_LIST *table_list)
4427 4428 4429 4430
{
  int error=0;
  if (table_list)
  {
4431
    /* Check that all tables use the current database */
4432
    TABLE_LIST *tmp;
unknown's avatar
VIEW  
unknown committed
4433
    for (tmp= table_list; tmp; tmp= tmp->next_local)
4434 4435 4436 4437
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
    }
4438
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
unknown's avatar
SCRUM:  
unknown committed
4439
			     table_list,0);
4440 4441 4442 4443
  }
  return error;
}

unknown's avatar
SCRUM:  
unknown committed
4444 4445 4446

static bool check_db_used(THD *thd,TABLE_LIST *tables)
{
unknown's avatar
VIEW  
unknown committed
4447
  for (; tables; tables= tables->next_global)
unknown's avatar
SCRUM:  
unknown committed
4448 4449 4450 4451 4452
  {
    if (!tables->db)
    {
      if (!(tables->db=thd->db))
      {
unknown's avatar
unknown committed
4453 4454
	my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
                   MYF(0));                     /* purecov: tested */
unknown's avatar
SCRUM:  
unknown committed
4455 4456 4457 4458 4459 4460
	return TRUE;				/* purecov: tested */
      }
    }
  }
  return FALSE;
}
4461

4462

unknown's avatar
unknown committed
4463 4464 4465 4466 4467 4468 4469 4470 4471 4472
/****************************************************************************
	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
4473 4474 4475 4476
#ifndef DBUG_OFF
long max_stack_used;
#endif

4477
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
4478 4479 4480 4481 4482 4483 4484 4485
bool check_stack_overrun(THD *thd,char *buf __attribute__((unused)))
{
  long stack_used;
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
      (long) thread_stack_min)
  {
    sprintf(errbuff[0],ER(ER_STACK_OVERRUN),stack_used,thread_stack);
    my_message(ER_STACK_OVERRUN,errbuff[0],MYF(0));
4486
    thd->fatal_error();
unknown's avatar
unknown committed
4487 4488
    return 1;
  }
unknown's avatar
unknown committed
4489 4490 4491
#ifndef DBUG_OFF
  max_stack_used= max(max_stack_used, stack_used);
#endif
unknown's avatar
unknown committed
4492 4493
  return 0;
}
4494
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
4495 4496 4497 4498

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

4499
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
unknown's avatar
unknown committed
4500 4501
{
  LEX	*lex=current_lex;
4502
  ulong old_info=0;
unknown's avatar
unknown committed
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 4528
  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;
}


/****************************************************************************
4529
  Initialize global thd variables needed for query
unknown's avatar
unknown committed
4530 4531
****************************************************************************/

4532
void
unknown's avatar
unknown committed
4533
mysql_init_query(THD *thd, uchar *buf, uint length)
unknown's avatar
unknown committed
4534 4535
{
  DBUG_ENTER("mysql_init_query");
unknown's avatar
unknown committed
4536
  lex_start(thd, buf, length);
4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557
  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).

 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");
4558
  thd->free_list= 0;
4559
  thd->select_number= 1;
unknown's avatar
unknown committed
4560
  thd->total_warn_count=0;			// Warnings for this query
unknown's avatar
unknown committed
4561 4562
  thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
  thd->sent_row_count= thd->examined_row_count= 0;
4563
  thd->is_fatal_error= thd->rand_used= thd->time_zone_used= 0;
unknown's avatar
unknown committed
4564
  thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | 
unknown's avatar
unknown committed
4565 4566
                          SERVER_QUERY_NO_INDEX_USED |
                          SERVER_QUERY_NO_GOOD_INDEX_USED);
unknown's avatar
unknown committed
4567
  thd->tmp_table_used= 0;
unknown's avatar
unknown committed
4568 4569
  if (opt_bin_log)
    reset_dynamic(&thd->user_var_events);
4570
  thd->clear_error();
unknown's avatar
unknown committed
4571 4572 4573
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
4574

4575 4576 4577
void
mysql_init_select(LEX *lex)
{
unknown's avatar
(SCRUM)  
unknown committed
4578
  SELECT_LEX *select_lex= lex->current_select;
unknown's avatar
unknown committed
4579
  select_lex->init_select();
4580
  select_lex->select_limit= HA_POS_ERROR;
4581 4582
  lex->orig_sql_command= SQLCOM_END;
  lex->wild= 0;
4583 4584
  if (select_lex == &lex->select_lex)
  {
4585
    DBUG_ASSERT(lex->result == 0);
4586 4587
    lex->exchange= 0;
  }
4588 4589
}

4590

unknown's avatar
unknown committed
4591
bool
unknown's avatar
unknown committed
4592
mysql_new_select(LEX *lex, bool move_down)
4593
{
unknown's avatar
unknown committed
4594 4595
  SELECT_LEX *select_lex;
  if (!(select_lex= new(lex->thd->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
4596
    return 1;
4597
  select_lex->select_number= ++lex->thd->select_number;
unknown's avatar
unknown committed
4598 4599
  select_lex->init_query();
  select_lex->init_select();
unknown's avatar
VIEW  
unknown committed
4600
  select_lex->parent_lex= lex;
unknown's avatar
unknown committed
4601 4602
  if (move_down)
  {
4603
    lex->subqueries= TRUE;
unknown's avatar
unknown committed
4604
    /* first select_lex of subselect or derived table */
unknown's avatar
unknown committed
4605 4606
    SELECT_LEX_UNIT *unit;
    if (!(unit= new(lex->thd->mem_root) SELECT_LEX_UNIT()))
unknown's avatar
unknown committed
4607
      return 1;
unknown's avatar
unknown committed
4608

unknown's avatar
unknown committed
4609 4610
    unit->init_query();
    unit->init_select();
4611
    unit->thd= lex->thd;
unknown's avatar
(SCRUM)  
unknown committed
4612
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
4613 4614
    unit->link_next= 0;
    unit->link_prev= 0;
4615
    unit->return_to= lex->current_select;
unknown's avatar
unknown committed
4616
    select_lex->include_down(unit);
unknown's avatar
unknown committed
4617
    /* TODO: assign resolve_mode for fake subquery after merging with new tree */
unknown's avatar
unknown committed
4618 4619
  }
  else
unknown's avatar
(SCRUM)  
unknown committed
4620
  {
unknown's avatar
VIEW  
unknown committed
4621 4622
    if (lex->current_select->order_list.first && !lex->current_select->braces)
    {
unknown's avatar
unknown committed
4623
      my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
unknown's avatar
VIEW  
unknown committed
4624 4625
      return 1;
    }
4626
    select_lex->include_neighbour(lex->current_select);
unknown's avatar
(SCRUM)  
unknown committed
4627 4628 4629 4630 4631 4632 4633 4634
    SELECT_LEX_UNIT *unit= select_lex->master_unit();
    SELECT_LEX *fake= unit->fake_select_lex;
    if (!fake)
    {
      /*
	as far as we included SELECT_LEX for UNION unit should have
	fake SELECT_LEX for UNION processing
      */
unknown's avatar
unknown committed
4635 4636
      if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX()))
        return 1;
unknown's avatar
(SCRUM)  
unknown committed
4637 4638 4639 4640 4641
      fake->include_standalone(unit,
			       (SELECT_LEX_NODE**)&unit->fake_select_lex);
      fake->select_number= INT_MAX;
      fake->make_empty_select();
      fake->linkage= GLOBAL_OPTIONS_TYPE;
4642
      fake->select_limit= HA_POS_ERROR;
unknown's avatar
(SCRUM)  
unknown committed
4643 4644
    }
  }
unknown's avatar
unknown committed
4645

4646
  select_lex->master_unit()->global_parameters= select_lex;
4647
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
4648
  lex->current_select= select_lex;
4649
  select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
unknown's avatar
unknown committed
4650
  return 0;
4651
}
unknown's avatar
unknown committed
4652

4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667
/*
  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)
{
4668
  THD *thd;
4669
  LEX *lex;
4670
  LEX_STRING tmp, null_lex_string;
4671
  DBUG_ENTER("create_select_for_variable");
4672 4673

  thd= current_thd;
unknown's avatar
unknown committed
4674
  lex= thd->lex;
4675 4676 4677 4678
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
4679 4680 4681
  bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
  add_item_to_list(thd, get_system_var(thd, OPT_SESSION, tmp,
				       null_lex_string));
4682 4683 4684
  DBUG_VOID_RETURN;
}

4685

unknown's avatar
unknown committed
4686 4687
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
4688
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
4689
  mysql_init_select(lex);
4690
  lex->select_lex.select_limit= lex->unit.select_limit_cnt=
unknown's avatar
merged  
unknown committed
4691
    HA_POS_ERROR;
unknown's avatar
unknown committed
4692
  lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list);
unknown's avatar
VIEW  
unknown committed
4693 4694
  lex->query_tables= 0;
  lex->query_tables_last= &lex->query_tables;
unknown's avatar
unknown committed
4695
}
unknown's avatar
unknown committed
4696

4697

4698 4699 4700 4701
/*
  When you modify mysql_parse(), you may need to mofify
  mysql_test_parse_for_slave() in this same file.
*/
unknown's avatar
unknown committed
4702

4703
void mysql_parse(THD *thd, char *inBuf, uint length)
unknown's avatar
unknown committed
4704 4705 4706
{
  DBUG_ENTER("mysql_parse");

unknown's avatar
unknown committed
4707
  mysql_init_query(thd, (uchar*) inBuf, length);
unknown's avatar
unknown committed
4708
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
unknown's avatar
unknown committed
4709
  {
unknown's avatar
unknown committed
4710
    LEX *lex= thd->lex;
4711
    if (!yyparse((void *)thd) && ! thd->is_fatal_error)
unknown's avatar
unknown committed
4712
    {
unknown's avatar
SCRUM:  
unknown committed
4713
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4714
      if (mqh_used && thd->user_connect &&
4715
	  check_mqh(thd, lex->sql_command))
4716 4717 4718 4719
      {
	thd->net.error = 0;
      }
      else
unknown's avatar
SCRUM:  
unknown committed
4720
#endif
4721
      {
unknown's avatar
unknown committed
4722
	if (thd->net.report_error)
4723 4724
	{
	  if (thd->lex->sphead)
4725 4726 4727 4728 4729 4730
	  {
	    if (lex != thd->lex)
	      thd->lex->sphead->restore_lex(thd);
	    delete thd->lex->sphead;
	    thd->lex->sphead= NULL;
	  }
4731
	}
unknown's avatar
unknown committed
4732 4733 4734
	else
	{
	  mysql_execute_command(thd);
unknown's avatar
SCRUM  
unknown committed
4735
	  query_cache_end_of_result(thd);
unknown's avatar
unknown committed
4736
	}
4737
      }
4738
      lex->unit.cleanup();
unknown's avatar
unknown committed
4739 4740
    }
    else
4741 4742
    {
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
4743
			 thd->is_fatal_error));
unknown's avatar
unknown committed
4744
      query_cache_abort(&thd->net);
4745
      lex->unit.cleanup();
4746
      if (thd->lex->sphead)
4747
      {
unknown's avatar
unknown committed
4748
	/* Clean up after failed stored procedure/function */
4749 4750 4751 4752 4753
	if (lex != thd->lex)
	  thd->lex->sphead->restore_lex(thd);
	delete thd->lex->sphead;
	thd->lex->sphead= NULL;
      }
4754
    }
unknown's avatar
unknown committed
4755
    thd->proc_info="freeing items";
4756
    thd->end_statement();
4757
    thd->cleanup_after_query();
4758
    DBUG_ASSERT(thd->change_list.is_empty());
unknown's avatar
unknown committed
4759
  }
unknown's avatar
unknown committed
4760 4761 4762 4763
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
4764
#ifdef HAVE_REPLICATION
4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775
/*
  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
4776
  LEX *lex= thd->lex;
4777
  bool error= 0;
unknown's avatar
unknown committed
4778
  DBUG_ENTER("mysql_test_parse_for_slave");
4779

unknown's avatar
unknown committed
4780
  mysql_init_query(thd, (uchar*) inBuf, length);
unknown's avatar
unknown committed
4781
  if (!yyparse((void*) thd) && ! thd->is_fatal_error &&
4782
      all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
unknown's avatar
unknown committed
4783
    error= 1;                  /* Ignore question */
4784
  thd->end_statement();
4785
  thd->cleanup_after_query();
unknown's avatar
unknown committed
4786
  DBUG_RETURN(error);
4787
}
unknown's avatar
unknown committed
4788
#endif
unknown's avatar
unknown committed
4789

4790

unknown's avatar
unknown committed
4791

unknown's avatar
unknown committed
4792 4793 4794 4795 4796
/*****************************************************************************
** Store field definition for create
** Return 0 if ok
******************************************************************************/

unknown's avatar
unknown committed
4797
bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
unknown's avatar
unknown committed
4798
		       char *length, char *decimals,
4799
		       uint type_modifier,
4800 4801
		       Item *default_value, Item *on_update_value,
                       LEX_STRING *comment,
4802 4803
		       char *change,
                       List<String> *interval_list, CHARSET_INFO *cs,
unknown's avatar
unknown committed
4804
		       uint uint_geom_type)
unknown's avatar
unknown committed
4805 4806
{
  register create_field *new_field;
unknown's avatar
unknown committed
4807
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
4808
  uint allowed_type_modifier=0;
unknown's avatar
unknown committed
4809
  uint sign_len;
4810
  ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
unknown's avatar
unknown committed
4811 4812 4813 4814
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
4815
    my_error(ER_TOO_LONG_IDENT, MYF(0), field_name); /* purecov: inspected */
unknown's avatar
unknown committed
4816 4817 4818 4819 4820
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
4821
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
4822
				    0, lex->col_list));
unknown's avatar
unknown committed
4823 4824 4825 4826 4827
    lex->col_list.empty();
  }
  if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
4828
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF, 0,
unknown's avatar
unknown committed
4829 4830 4831 4832
				    lex->col_list));
    lex->col_list.empty();
  }

4833
  if (default_value)
unknown's avatar
unknown committed
4834
  {
4835
    /* 
unknown's avatar
unknown committed
4836 4837
      Default value should be literal => basic constants =>
      no need fix_fields()
4838 4839 4840
      
      We allow only one function as part of default value - 
      NOW() as default for TIMESTAMP type.
4841
    */
4842 4843 4844
    if (default_value->type() == Item::FUNC_ITEM && 
        !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
         type == FIELD_TYPE_TIMESTAMP))
4845
    {
4846
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
4847 4848 4849
      DBUG_RETURN(1);
    }
    else if (default_value->type() == Item::NULL_ITEM)
unknown's avatar
unknown committed
4850
    {
4851
      default_value= 0;
4852 4853 4854
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
4855
	my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
4856 4857 4858 4859 4860
	DBUG_RETURN(1);
      }
    }
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
4861
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
unknown's avatar
unknown committed
4862 4863 4864
      DBUG_RETURN(1);
    }
  }
4865 4866 4867

  if (on_update_value && type != FIELD_TYPE_TIMESTAMP)
  {
4868
    my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
4869 4870 4871
    DBUG_RETURN(1);
  }
    
unknown's avatar
unknown committed
4872 4873 4874 4875
  if (!(new_field=new create_field()))
    DBUG_RETURN(1);
  new_field->field=0;
  new_field->field_name=field_name;
4876
  new_field->def= default_value;
unknown's avatar
unknown committed
4877 4878 4879 4880 4881 4882 4883 4884 4885
  new_field->flags= type_modifier;
  new_field->unireg_check= (type_modifier & AUTO_INCREMENT_FLAG ?
			    Field::NEXT_NUMBER : Field::NONE);
  new_field->decimals= decimals ? (uint) set_zone(atoi(decimals),0,
						  NOT_FIXED_DEC-1) : 0;
  new_field->sql_type=type;
  new_field->length=0;
  new_field->change=change;
  new_field->interval=0;
4886
  new_field->pack_length= new_field->key_length= 0;
4887
  new_field->charset=cs;
unknown's avatar
unknown committed
4888
  new_field->geom_type= (Field::geometry_type) uint_geom_type;
unknown's avatar
unknown committed
4889

4890 4891 4892 4893 4894 4895 4896 4897
  if (!comment)
  {
    new_field->comment.str=0;
    new_field->comment.length=0;
  }
  else
  {
    /* In this case comment is always of type Item_string */
unknown's avatar
unknown committed
4898 4899
    new_field->comment.str=   (char*) comment->str;
    new_field->comment.length=comment->length;
4900
  }
unknown's avatar
unknown committed
4901 4902 4903 4904 4905
  /*
    Set flag if this field doesn't have a default value
    Enum values has always the first value as a default (set in
    make_empty_rec().
  */
unknown's avatar
unknown committed
4906
  if (!default_value && !(type_modifier & AUTO_INCREMENT_FLAG) &&
unknown's avatar
unknown committed
4907 4908
      (type_modifier & NOT_NULL_FLAG) && type != FIELD_TYPE_TIMESTAMP &&
      type != FIELD_TYPE_ENUM)
unknown's avatar
unknown committed
4909 4910
    new_field->flags|= NO_DEFAULT_VALUE_FLAG;

4911 4912
  if (length && !(new_field->length= (uint) atoi(length)))
    length=0; /* purecov: inspected */
unknown's avatar
unknown committed
4913
  sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
unknown's avatar
unknown committed
4914 4915

  if (new_field->length && new_field->decimals &&
4916
      new_field->length < new_field->decimals+1 &&
unknown's avatar
unknown committed
4917
      new_field->decimals != NOT_FIXED_DEC)
4918
    new_field->length=new_field->decimals+1; /* purecov: inspected */
unknown's avatar
unknown committed
4919 4920 4921

  switch (type) {
  case FIELD_TYPE_TINY:
4922
    if (!length) new_field->length=MAX_TINYINT_WIDTH+sign_len;
unknown's avatar
unknown committed
4923 4924 4925
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_SHORT:
4926
    if (!length) new_field->length=MAX_SMALLINT_WIDTH+sign_len;
unknown's avatar
unknown committed
4927 4928 4929
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_INT24:
4930
    if (!length) new_field->length=MAX_MEDIUMINT_WIDTH+sign_len;
unknown's avatar
unknown committed
4931 4932 4933
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONG:
4934
    if (!length) new_field->length=MAX_INT_WIDTH+sign_len;
unknown's avatar
unknown committed
4935 4936 4937
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONGLONG:
4938
    if (!length) new_field->length=MAX_BIGINT_WIDTH;
unknown's avatar
unknown committed
4939 4940 4941 4942 4943 4944
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_NULL:
    break;
  case FIELD_TYPE_DECIMAL:
    if (!length)
unknown's avatar
Cleanup  
unknown committed
4945 4946
    {
      if ((new_field->length= new_field->decimals))
4947 4948
        new_field->length++;
      else
unknown's avatar
Cleanup  
unknown committed
4949 4950
        new_field->length= 10;                  // Default length for DECIMAL
    }
4951 4952 4953 4954 4955 4956
    if (new_field->length < MAX_FIELD_WIDTH)	// Skip wrong argument
    {
      new_field->length+=sign_len;
      if (new_field->decimals)
	new_field->length++;
    }
unknown's avatar
unknown committed
4957
    break;
4958 4959 4960 4961 4962 4963 4964 4965 4966
  case MYSQL_TYPE_VARCHAR:
    /*
      Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
      if they don't have a default value
    */
    max_field_charlength= MAX_FIELD_VARCHARLENGTH;
    break;
  case MYSQL_TYPE_STRING:
    break;
unknown's avatar
unknown committed
4967 4968 4969 4970
  case FIELD_TYPE_BLOB:
  case FIELD_TYPE_TINY_BLOB:
  case FIELD_TYPE_LONG_BLOB:
  case FIELD_TYPE_MEDIUM_BLOB:
unknown's avatar
unknown committed
4971
  case FIELD_TYPE_GEOMETRY:
unknown's avatar
unknown committed
4972 4973 4974 4975 4976 4977
    if (default_value)				// Allow empty as default value
    {
      String str,*res;
      res=default_value->val_str(&str);
      if (res->length())
      {
4978 4979
	my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
                 field_name); /* purecov: inspected */
unknown's avatar
unknown committed
4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998
	DBUG_RETURN(1); /* purecov: inspected */
      }
      new_field->def=0;
    }
    new_field->flags|=BLOB_FLAG;
    break;
  case FIELD_TYPE_YEAR:
    if (!length || new_field->length != 2)
      new_field->length=4;			// Default length
    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
    break;
  case FIELD_TYPE_FLOAT:
    /* change FLOAT(precision) to FLOAT or DOUBLE */
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    if (length && !decimals)
    {
      uint tmp_length=new_field->length;
      if (tmp_length > PRECISION_FOR_DOUBLE)
      {
4999
	my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
unknown's avatar
unknown committed
5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028
	DBUG_RETURN(1);
      }
      else if (tmp_length > PRECISION_FOR_FLOAT)
      {
	new_field->sql_type=FIELD_TYPE_DOUBLE;
	new_field->length=DBL_DIG+7;			// -[digits].E+###
      }
      else
	new_field->length=FLT_DIG+6;			// -[digits].E+##
      new_field->decimals= NOT_FIXED_DEC;
      break;
    }
    if (!length)
    {
      new_field->length =  FLT_DIG+6;
      new_field->decimals= NOT_FIXED_DEC;
    }
    break;
  case FIELD_TYPE_DOUBLE:
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    if (!length)
    {
      new_field->length = DBL_DIG+7;
      new_field->decimals=NOT_FIXED_DEC;
    }
    break;
  case FIELD_TYPE_TIMESTAMP:
    if (!length)
      new_field->length= 14;			// Full date YYYYMMDDHHMMSS
5029
    else if (new_field->length != 19)
unknown's avatar
unknown committed
5030
    {
5031 5032 5033 5034
      /*
        We support only even TIMESTAMP lengths less or equal than 14
        and 19 as length of 4.1 compatible representation.
      */
unknown's avatar
unknown committed
5035 5036 5037
      new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
      new_field->length= min(new_field->length,14); /* purecov: inspected */
    }
5038
    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058
    if (default_value)
    {
      /* Grammar allows only NOW() value for ON UPDATE clause */
      if (default_value->type() == Item::FUNC_ITEM && 
          ((Item_func*)default_value)->functype() == Item_func::NOW_FUNC)
      {
        new_field->unireg_check= (on_update_value?Field::TIMESTAMP_DNUN_FIELD:
                                                  Field::TIMESTAMP_DN_FIELD);
        /*
          We don't need default value any longer moreover it is dangerous.
          Everything handled by unireg_check further.
        */
        new_field->def= 0;
      }
      else
        new_field->unireg_check= (on_update_value?Field::TIMESTAMP_UN_FIELD:
                                                  Field::NONE);
    }
    else
    {
5059 5060 5061 5062 5063 5064 5065 5066
      /*
        If we have default TIMESTAMP NOT NULL column without explicit DEFAULT
        or ON UPDATE values then for the sake of compatiblity we should treat
        this column as having DEFAULT NOW() ON UPDATE NOW() (when we don't
        have another TIMESTAMP column with auto-set option before this one)
        or DEFAULT 0 (in other cases).
        So here we are setting TIMESTAMP_OLD_FIELD only temporary, and will
        replace this value by TIMESTAMP_DNUN_FIELD or NONE later when
5067
        information about all TIMESTAMP fields in table will be availiable.
5068 5069 5070

        If we have TIMESTAMP NULL column without explicit DEFAULT value
        we treat it as having DEFAULT NULL attribute.
5071
      */
unknown's avatar
unknown committed
5072 5073 5074 5075 5076
      new_field->unireg_check= (on_update_value ?
                                Field::TIMESTAMP_UN_FIELD :
                                (new_field->flags & NOT_NULL_FLAG ?
                                 Field::TIMESTAMP_OLD_FIELD:
                                 Field::NONE));
5077
    }
unknown's avatar
unknown committed
5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093
    break;
  case FIELD_TYPE_DATE:				// Old date type
    if (protocol_version != PROTOCOL_VERSION-1)
      new_field->sql_type=FIELD_TYPE_NEWDATE;
    /* fall trough */
  case FIELD_TYPE_NEWDATE:
    new_field->length=10;
    break;
  case FIELD_TYPE_TIME:
    new_field->length=10;
    break;
  case FIELD_TYPE_DATETIME:
    new_field->length=19;
    break;
  case FIELD_TYPE_SET:
    {
5094
      if (interval_list->elements > sizeof(longlong)*8)
unknown's avatar
unknown committed
5095
      {
5096
	my_error(ER_TOO_BIG_SET, MYF(0), field_name); /* purecov: inspected */
unknown's avatar
unknown committed
5097
	DBUG_RETURN(1);				      /* purecov: inspected */
unknown's avatar
unknown committed
5098
      }
5099
      new_field->pack_length= (interval_list->elements + 7) / 8;
unknown's avatar
unknown committed
5100
      if (new_field->pack_length > 4)
5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112
        new_field->pack_length=8;

      List_iterator<String> it(*interval_list);
      String *tmp;
      while ((tmp= it++))
        new_field->interval_list.push_back(tmp);
      /*
        Set fake length to 1 to pass the below conditions.
        Real length will be set in mysql_prepare_table()
        when we know the character set of the column
      */
      new_field->length= 1;
unknown's avatar
unknown committed
5113
      break;
unknown's avatar
unknown committed
5114 5115 5116
    }
  case FIELD_TYPE_ENUM:
    {
5117 5118
      // Should be safe
      new_field->pack_length= interval_list->elements < 256 ? 1 : 2; 
5119

5120 5121 5122 5123 5124
      List_iterator<String> it(*interval_list);
      String *tmp;
      while ((tmp= it++))
        new_field->interval_list.push_back(tmp);
      new_field->length= 1; // See comment for FIELD_TYPE_SET above.
unknown's avatar
unknown committed
5125
      break;
unknown's avatar
unknown committed
5126
   }
5127 5128
  case MYSQL_TYPE_VAR_STRING:
    DBUG_ASSERT(0);                             // Impossible
5129
    break;
unknown's avatar
unknown committed
5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142
  case MYSQL_TYPE_BIT:
    {
      if (!length)
        new_field->length= 1;
      if (new_field->length > MAX_BIT_FIELD_LENGTH)
      {
        my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name,
                 MAX_BIT_FIELD_LENGTH);
        DBUG_RETURN(1);
      }
      new_field->pack_length= (new_field->length + 7) / 8;
      break;
    }
unknown's avatar
unknown committed
5143 5144
  }

5145 5146 5147 5148 5149 5150 5151
  if (!(new_field->flags & BLOB_FLAG) &&
      ((new_field->length > max_field_charlength && type != FIELD_TYPE_SET && 
        type != FIELD_TYPE_ENUM &&
        (type != MYSQL_TYPE_VARCHAR || default_value)) ||
       (!new_field->length &&
        type != MYSQL_TYPE_STRING &&
        type != MYSQL_TYPE_VARCHAR && type != FIELD_TYPE_GEOMETRY)))
unknown's avatar
unknown committed
5152
  {
5153
    my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0),
unknown's avatar
unknown committed
5154
             field_name, max_field_charlength); /* purecov: inspected */
unknown's avatar
unknown committed
5155 5156 5157 5158 5159
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
5160
    my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
unknown's avatar
unknown committed
5161 5162 5163 5164 5165 5166 5167
    DBUG_RETURN(1);
  }
  lex->create_list.push_back(new_field);
  lex->last_field=new_field;
  DBUG_RETURN(0);
}

5168

unknown's avatar
unknown committed
5169 5170 5171 5172 5173 5174 5175 5176
/* Store position for column in ALTER TABLE .. ADD column */

void store_position_for_column(const char *name)
{
  current_lex->last_field->after=my_const_cast(char*) (name);
}

bool
unknown's avatar
unknown committed
5177
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
5178 5179 5180 5181
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
5182
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
5183 5184 5185 5186 5187
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
unknown's avatar
unknown committed
5188
  thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
5189 5190 5191 5192 5193 5194 5195 5196
  return 0;
}


/* Fix escaping of _, % and \ in database and table names (for ODBC) */

static void remove_escape(char *name)
{
5197 5198
  if (!*name)					// For empty DB names
    return;
unknown's avatar
unknown committed
5199 5200
  char *to;
#ifdef USE_MB
unknown's avatar
unknown committed
5201
  char *strend=name+(uint) strlen(name);
unknown's avatar
unknown committed
5202 5203 5204 5205 5206
#endif
  for (to=name; *name ; name++)
  {
#ifdef USE_MB
    int l;
5207 5208
    if (use_mb(system_charset_info) &&
        (l = my_ismbchar(system_charset_info, name, strend)))
unknown's avatar
unknown committed
5209 5210 5211 5212 5213 5214 5215 5216
    {
	while (l--)
	    *to++ = *name++;
	name--;
	continue;
    }
#endif
    if (*name == '\\' && name[1])
unknown's avatar
unknown committed
5217
      name++;					// Skip '\\'
unknown's avatar
unknown committed
5218 5219 5220 5221 5222 5223 5224 5225 5226 5227
    *to++= *name;
  }
  *to=0;
}

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


unknown's avatar
unknown committed
5228
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
5229 5230 5231
{
  ORDER *order;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
5232
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER))))
unknown's avatar
unknown committed
5233
    DBUG_RETURN(1);
unknown's avatar
unknown committed
5234 5235
  order->item_ptr= item;
  order->item= &order->item_ptr;
unknown's avatar
unknown committed
5236 5237 5238
  order->asc = asc;
  order->free_me=0;
  order->used=0;
5239
  order->counter_used= 0;
unknown's avatar
unknown committed
5240
  list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
5241 5242 5243 5244
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263
/*
  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
    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
5264 5265
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
5266
					     LEX_STRING *alias,
unknown's avatar
unknown committed
5267 5268
					     ulong table_options,
					     thr_lock_type lock_type,
5269 5270
					     List<String> *use_index_arg,
					     List<String> *ignore_index_arg,
unknown's avatar
unknown committed
5271
                                             LEX_STRING *option)
unknown's avatar
unknown committed
5272 5273 5274
{
  register TABLE_LIST *ptr;
  char *alias_str;
5275
  LEX *lex= thd->lex;
unknown's avatar
unknown committed
5276 5277 5278 5279 5280
  DBUG_ENTER("add_table_to_list");

  if (!table)
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? alias->str : table->table.str;
unknown's avatar
unknown committed
5281
  if (check_table_name(table->table.str,table->table.length) ||
unknown's avatar
unknown committed
5282
      table->db.str && check_db_name(table->db.str))
unknown's avatar
unknown committed
5283
  {
5284
    my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
unknown's avatar
unknown committed
5285 5286 5287 5288
    DBUG_RETURN(0);
  }

  if (!alias)					/* Alias is case sensitive */
5289 5290 5291
  {
    if (table->sel)
    {
unknown's avatar
unknown committed
5292 5293
      my_message(ER_DERIVED_MUST_HAVE_ALIAS,
                 ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
5294 5295
      DBUG_RETURN(0);
    }
5296
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
5297
      DBUG_RETURN(0);
5298
  }
unknown's avatar
unknown committed
5299
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
5300
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
5301
  if (table->db.str)
5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312
  {
    ptr->db= table->db.str;
    ptr->db_length= table->db.length;
  }
  else if (thd->db)
  {
    ptr->db= thd->db;
    ptr->db_length= thd->db_length;
  }
  else
  {
5313 5314
    /* The following can't be "" as we may do 'casedn_str()' on it */
    ptr->db= empty_c_string;
5315 5316
    ptr->db_length= 0;
  }
5317 5318
  if (thd->current_arena->is_stmt_prepare())
    ptr->db= thd->strdup(ptr->db);
unknown's avatar
unknown committed
5319

5320
  ptr->alias= alias_str;
5321 5322
  if (lower_case_table_names && table->table.length)
    my_casedn_str(files_charset_info, table->table.str);
5323 5324
  ptr->table_name=table->table.str;
  ptr->table_name_length=table->table.length;
5325
  ptr->lock_type=   lock_type;
unknown's avatar
unknown committed
5326 5327
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
5328
  ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
5329
  ptr->derived=	    table->sel;
5330 5331 5332
  if (!my_strcasecmp(system_charset_info, ptr->db,
                     information_schema_name.str))
  {
5333
    ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
5334 5335 5336
    if (!schema_table ||
        (schema_table->hidden && 
         lex->orig_sql_command == SQLCOM_END))  // not a 'show' command
5337
    {
unknown's avatar
unknown committed
5338
      my_error(ER_UNKNOWN_TABLE, MYF(0),
5339
               ptr->table_name, information_schema_name.str);
5340 5341
      DBUG_RETURN(0);
    }
5342
    ptr->schema_table_name= ptr->table_name;
5343 5344
    ptr->schema_table= schema_table;
  }
5345
  ptr->select_lex=  lex->current_select;
unknown's avatar
unknown committed
5346
  ptr->cacheable_table= 1;
5347 5348 5349 5350 5351 5352
  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
5353
  ptr->option= option ? option->str : 0;
unknown's avatar
unknown committed
5354
  /* check that used name is unique */
5355
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
5356
  {
5357
    for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
5358
	 tables ;
unknown's avatar
VIEW  
unknown committed
5359
	 tables=tables->next_local)
unknown's avatar
unknown committed
5360
    {
5361 5362
      if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
	  !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
5363
      {
5364
	my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
unknown's avatar
unknown committed
5365 5366
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
5367 5368
    }
  }
5369
  /* Link table in local list (list for current select) */
unknown's avatar
VIEW  
unknown committed
5370
  table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
5371
  /* Link table in global list (all used tables) */
5372
  lex->add_to_query_tables(ptr);
unknown's avatar
unknown committed
5373 5374 5375
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
5376

5377 5378 5379 5380
/*
  Initialize a new table list for a nested join

  SYNOPSIS
unknown's avatar
unknown committed
5381
    init_nested_join()
5382
    thd         current thread
5383

5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402
  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");
5403

5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
      !(nested_join= ptr->nested_join=
                    (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
    DBUG_RETURN(1);
  join_list->push_front(ptr);
  ptr->embedding= embedding;
  ptr->join_list= join_list;
  embedding= ptr;
  join_list= &nested_join->join_list;
  join_list->empty();
  DBUG_RETURN(0);
}


/*
  End a nested join table list

  SYNOPSIS
    end_nested_join()
    thd         current thread

  DESCRIPTION
    The function returns to the previous join nest level.
    If the current level contains only one member, the function
5428
    moves it one level up, eliminating the nest.
5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459

  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;
  DBUG_ENTER("end_nested_join");
  ptr= embedding;
  join_list= ptr->join_list;
  embedding= ptr->embedding;
  NESTED_JOIN *nested_join= ptr->nested_join;
  if (nested_join->join_list.elements == 1)
  {
    TABLE_LIST *embedded= nested_join->join_list.head();
    join_list->pop();
    embedded->join_list= join_list;
    embedded->embedding= embedding;
    join_list->push_front(embedded);
    ptr= embedded;
  }
  DBUG_RETURN(ptr);
}


/*
  Nest last join operation

  SYNOPSIS
5460
    nest_last_join()
5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475
    thd         current thread

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

  RETURN VALUE
    Pointer to TABLE_LIST element created for the new nested join, if success
    0, otherwise
*/

TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
{
  TABLE_LIST *ptr;
  NESTED_JOIN *nested_join;
  DBUG_ENTER("nest_last_join");
5476

5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
      !(nested_join= ptr->nested_join=
                    (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
    DBUG_RETURN(0);
  ptr->embedding= embedding;
  ptr->join_list= join_list;
  List<TABLE_LIST> *embedded_list= &nested_join->join_list;
  embedded_list->empty();
  for (int i=0; i < 2; i++)
  {
    TABLE_LIST *table= join_list->pop();
    table->join_list= embedded_list;
    table->embedding= ptr;
    embedded_list->push_back(table);
  }
  join_list->push_front(ptr);
  nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
  DBUG_RETURN(ptr);
}


/*
5499
  Save names for a join with using clause
5500

5501 5502 5503 5504 5505 5506 5507
  SYNOPSIS
    save_names_for_using_list
    tab1      left table in join
    tab2      right table in join

  DESCRIPTION
    The function saves the full names of the tables in st_select_lex
5508 5509
    to be able to build later an on expression to replace the using clause.

5510
  RETURN VALUE
5511 5512
    None
*/
5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533

void st_select_lex::save_names_for_using_list(TABLE_LIST *tab1,
                                              TABLE_LIST *tab2)
{
  while (tab1->nested_join)
  {
    tab1= tab1->nested_join->join_list.head();
  }
  db1= tab1->db;
  table1= tab1->alias;
  while (tab2->nested_join)
  {
    TABLE_LIST *next;
    List_iterator_fast<TABLE_LIST> it(tab2->nested_join->join_list);
    tab2= it++;
    while ((next= it++))
      tab2= next;
  }
  db2= tab2->db;
  table2= tab2->alias;
}
5534

5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568

/*
  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
5569 5570 5571

  DESCRIPTION
    The function takes the current join list t[0],t[1] ... and
5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594
    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
*/

5595
TABLE_LIST *st_select_lex::convert_right_join()
5596 5597
{
  TABLE_LIST *tab2= join_list->pop();
5598
  TABLE_LIST *tab1= join_list->pop();
5599 5600 5601 5602 5603 5604 5605 5606 5607
  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
5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620
/*
  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
5621
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
5622 5623 5624 5625 5626 5627
{
  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
5628 5629 5630
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first;
       tables;
       tables= tables->next_local)
unknown's avatar
unknown committed
5631 5632 5633 5634 5635 5636 5637
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
5638

unknown's avatar
unknown committed
5639 5640
void add_join_on(TABLE_LIST *b,Item *expr)
{
5641
  if (expr)
5642
  {
5643 5644 5645 5646
    if (!b->on_expr)
      b->on_expr=expr;
    else
    {
unknown's avatar
unknown committed
5647
      /* This only happens if you have both a right and left join */
5648 5649 5650
      b->on_expr=new Item_cond_and(b->on_expr,expr);
    }
    b->on_expr->top_level_item();
5651
  }
unknown's avatar
unknown committed
5652 5653 5654
}


5655 5656 5657 5658 5659 5660 5661
/*
  Mark that we have a NATURAL JOIN between two tables

  SYNOPSIS
    add_join_natural()
    a			Table to do normal join with
    b			Do normal join with this table
5662

5663 5664 5665 5666 5667 5668 5669 5670 5671 5672
  IMPLEMENTATION
    This function just marks that table b should be joined with a.
    The function setup_cond() will create in b->on_expr a list
    of equal condition between all fields of the same name.

    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
5673 5674 5675 5676 5677
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
{
  b->natural_join=a;
}

5678
/*
5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695
  Reload/resets privileges and the different caches.

  SYNOPSIS
    reload_acl_and_cache()
    thd			Thread handler
    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
                        pointer where, if it is not NULL, reload_acl_and_cache()
                        will put 0 if it thinks we really should not write to
                        the binlog. Otherwise it will put 1.

  RETURN
    0	 ok
    !=0  error
5696 5697
*/

5698 5699
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
                          bool *write_to_binlog)
unknown's avatar
unknown committed
5700 5701 5702
{
  bool result=0;
  select_errors=0;				/* Write if more errors */
5703
  bool tmp_write_to_binlog= 1;
unknown's avatar
SCRUM  
unknown committed
5704
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
5705 5706
  if (options & REFRESH_GRANT)
  {
5707
    acl_reload(thd);
unknown's avatar
unknown committed
5708
    grant_reload(thd);
5709
    reset_mqh((LEX_USER *)NULL, TRUE);
unknown's avatar
unknown committed
5710
  }
unknown's avatar
SCRUM  
unknown committed
5711
#endif
unknown's avatar
unknown committed
5712 5713
  if (options & REFRESH_LOG)
  {
5714
    /*
unknown's avatar
unknown committed
5715 5716
      Flush the normal query log, the update log, the binary log,
      the slow query log, and the relay log (if it exists).
5717
    */
unknown's avatar
unknown committed
5718

5719 5720 5721 5722 5723 5724
    /* 
     Writing this command to the binlog may result in infinite loops when doing
     mysqlbinlog|mysql, and anyway it does not really make sense to log it
     automatically (would cause more trouble to users than it would help them)
    */
    tmp_write_to_binlog= 0;
unknown's avatar
unknown committed
5725 5726 5727
    mysql_log.new_file(1);
    mysql_bin_log.new_file(1);
    mysql_slow_log.new_file(1);
unknown's avatar
unknown committed
5728
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
5729
    if (mysql_bin_log.is_open() && expire_logs_days)
5730 5731 5732
    {
      long purge_time= time(0) - expire_logs_days*24*60*60;
      if (purge_time >= 0)
5733
	mysql_bin_log.purge_logs_before_date(purge_time);
5734
    }
5735
    pthread_mutex_lock(&LOCK_active_mi);
5736
    rotate_relay_log(active_mi);
5737
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
5738
#endif
unknown's avatar
unknown committed
5739 5740
    if (ha_flush_logs())
      result=1;
unknown's avatar
unknown committed
5741 5742
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
5743
  }
unknown's avatar
unknown committed
5744
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
5745 5746
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
5747
    query_cache.pack();				// FLUSH QUERY CACHE
unknown's avatar
unknown committed
5748
    options &= ~REFRESH_QUERY_CACHE; 	// Don't flush cache, just free memory
unknown's avatar
unknown committed
5749 5750 5751
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
5752
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
5753
  }
unknown's avatar
unknown committed
5754
#endif /*HAVE_QUERY_CACHE*/
5755 5756 5757 5758 5759
  /*
    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
5760
  {
5761
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
5762
    {
unknown's avatar
unknown committed
5763 5764 5765 5766
      /*
	Writing to the binlog could cause deadlocks, as we don't log
	UNLOCK TABLES
      */
5767
      tmp_write_to_binlog= 0;
5768 5769
      if (lock_global_read_lock(thd))
	return 1;
5770 5771
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
                                 tables);
5772 5773 5774 5775 5776 5777
      if (make_global_read_lock_block_commit(thd))
      {
        /* Don't leave things in a half-locked state */
        unlock_global_read_lock(thd);
        return 1;
      }
unknown's avatar
unknown committed
5778
    }
5779 5780
    else
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
unknown's avatar
unknown committed
5781
    my_dbopt_cleanup();
unknown's avatar
unknown committed
5782 5783 5784
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
unknown's avatar
unknown committed
5785
  if (thd && (options & REFRESH_STATUS))
unknown's avatar
unknown committed
5786 5787 5788
    refresh_status();
  if (options & REFRESH_THREADS)
    flush_thread_cache();
unknown's avatar
unknown committed
5789
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
5790
  if (options & REFRESH_MASTER)
5791 5792
  {
    tmp_write_to_binlog= 0;
5793 5794
    if (reset_master(thd))
      result=1;
5795
  }
5796
#endif
unknown's avatar
unknown committed
5797
#ifdef OPENSSL
5798 5799 5800 5801 5802 5803
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
unknown's avatar
unknown committed
5804
#ifdef HAVE_REPLICATION
5805 5806
 if (options & REFRESH_SLAVE)
 {
5807
   tmp_write_to_binlog= 0;
5808
   pthread_mutex_lock(&LOCK_active_mi);
5809
   if (reset_slave(thd, active_mi))
5810
     result=1;
5811
   pthread_mutex_unlock(&LOCK_active_mi);
5812
 }
5813
#endif
5814
 if (options & REFRESH_USER_RESOURCES)
unknown's avatar
unknown committed
5815
   reset_mqh((LEX_USER *) NULL);
5816 5817
 if (write_to_binlog)
   *write_to_binlog= tmp_write_to_binlog;
5818
 return result;
unknown's avatar
unknown committed
5819 5820
}

5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832
/*
  kill on thread

  SYNOPSIS
    kill_one_thread()
    thd			Thread class
    id			Thread id

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

unknown's avatar
SCRUM  
unknown committed
5833
void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
unknown's avatar
unknown committed
5834 5835 5836
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
5837 5838
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
5839 5840 5841 5842
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
5843 5844
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
5845 5846 5847
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
5848 5849 5850 5851 5852
  if (tmp)
  {
    if ((thd->master_access & SUPER_ACL) ||
	!strcmp(thd->user,tmp->user))
    {
unknown's avatar
SCRUM  
unknown committed
5853
      tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
5854 5855 5856 5857 5858 5859 5860
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }

unknown's avatar
unknown committed
5861
  if (!error)
5862
    send_ok(thd);
unknown's avatar
unknown committed
5863
  else
unknown's avatar
unknown committed
5864
    my_error(error, MYF(0), id);
unknown's avatar
unknown committed
5865 5866
}

unknown's avatar
unknown committed
5867

unknown's avatar
unknown committed
5868 5869 5870 5871 5872 5873 5874 5875
/* Clear most status variables */

static void refresh_status(void)
{
  pthread_mutex_lock(&LOCK_status);
  for (struct show_var_st *ptr=status_vars; ptr->name; ptr++)
  {
    if (ptr->type == SHOW_LONG)
5876
      *(ulong*) ptr->value= 0;
5877 5878 5879 5880 5881 5882 5883
    else if (ptr->type == SHOW_LONG_STATUS)
    {
      THD *thd= current_thd;
      /* We must update the global status before cleaning up the thread */
      add_to_status(&global_status_var, &thd->status_var);
      bzero((char*) &thd->status_var, sizeof(thd->status_var));
    }
unknown's avatar
unknown committed
5884
  }
unknown's avatar
unknown committed
5885 5886
  /* Reset the counters of all key caches (default and named). */
  process_key_caches(reset_key_cache_counters);
unknown's avatar
unknown committed
5887 5888
  pthread_mutex_unlock(&LOCK_status);
}
unknown's avatar
unknown committed
5889 5890 5891 5892


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

unknown's avatar
unknown committed
5893 5894
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
			       const char *table_name)
unknown's avatar
unknown committed
5895
{
5896
  char buff[FN_REFLEN],*ptr, *end;
unknown's avatar
unknown committed
5897 5898 5899 5900 5901 5902 5903
  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))
  {
unknown's avatar
unknown committed
5904
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
unknown's avatar
unknown committed
5905 5906 5907 5908
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
5909
  end=convert_dirname(buff, *filename_ptr, NullS);
unknown's avatar
unknown committed
5910
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
unknown's avatar
unknown committed
5911 5912
    return 1;					// End of memory
  *filename_ptr=ptr;
5913
  strxmov(ptr,buff,table_name,NullS);
unknown's avatar
unknown committed
5914 5915
  return 0;
}
5916

5917

5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931
/*
  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;
5932 5933
  LEX *lex= thd->lex;
  if (lex->current_select != &lex->select_lex)
5934 5935
  {
    char command[80];
5936 5937
    strmake(command, lex->yylval->symbol.str,
	    min(lex->yylval->symbol.length, sizeof(command)-1));
5938
    my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
5939 5940 5941 5942
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
5943

unknown's avatar
unknown committed
5944

unknown's avatar
unknown committed
5945
Comp_creator *comp_eq_creator(bool invert)
unknown's avatar
unknown committed
5946
{
unknown's avatar
unknown committed
5947
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
unknown's avatar
unknown committed
5948 5949
}

unknown's avatar
unknown committed
5950

unknown's avatar
unknown committed
5951
Comp_creator *comp_ge_creator(bool invert)
unknown's avatar
unknown committed
5952
{
unknown's avatar
unknown committed
5953
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
unknown's avatar
unknown committed
5954 5955
}

unknown's avatar
unknown committed
5956

unknown's avatar
unknown committed
5957
Comp_creator *comp_gt_creator(bool invert)
unknown's avatar
unknown committed
5958
{
unknown's avatar
unknown committed
5959
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
unknown's avatar
unknown committed
5960 5961
}

unknown's avatar
unknown committed
5962

unknown's avatar
unknown committed
5963
Comp_creator *comp_le_creator(bool invert)
unknown's avatar
unknown committed
5964
{
unknown's avatar
unknown committed
5965
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
unknown's avatar
unknown committed
5966 5967
}

unknown's avatar
unknown committed
5968

unknown's avatar
unknown committed
5969
Comp_creator *comp_lt_creator(bool invert)
unknown's avatar
unknown committed
5970
{
unknown's avatar
unknown committed
5971
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
unknown's avatar
unknown committed
5972 5973
}

unknown's avatar
unknown committed
5974

unknown's avatar
unknown committed
5975
Comp_creator *comp_ne_creator(bool invert)
unknown's avatar
unknown committed
5976
{
unknown's avatar
unknown committed
5977
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
unknown's avatar
unknown committed
5978
}
unknown's avatar
unknown committed
5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998


/*
  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
5999
  if ((cmp == &comp_eq_creator) && !all)       //  = ANY <=> IN
unknown's avatar
unknown committed
6000
    return new Item_in_subselect(left_expr, select_lex);
unknown's avatar
unknown committed
6001 6002

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

  Item_allany_subselect *it=
6006
    new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all);
unknown's avatar
unknown committed
6007
  if (all)
6008
    return it->upper_item= new Item_func_not_all(it);	/* ALL */
unknown's avatar
unknown committed
6009

6010
  return it->upper_item= new Item_func_nop_all(it);      /* ANY/SOME */
unknown's avatar
unknown committed
6011
}
6012 6013


6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025
/*
  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
6026
bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
6027 6028
{
  List<create_field> fields;
6029 6030
  ALTER_INFO alter_info;
  alter_info.flags= ALTER_ADD_INDEX;
6031 6032 6033 6034 6035
  HA_CREATE_INFO create_info;
  DBUG_ENTER("mysql_create_index");
  bzero((char*) &create_info,sizeof(create_info));
  create_info.db_type=DB_TYPE_DEFAULT;
  create_info.default_table_charset= thd->variables.collation_database;
6036
  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
6037
				&create_info, table_list,
6038
				fields, keys, 0, (ORDER*)0,
6039
				DUP_ERROR, 0, &alter_info));
6040 6041 6042
}


unknown's avatar
unknown committed
6043
bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
6044 6045 6046 6047 6048 6049 6050 6051
{
  List<create_field> fields;
  List<Key> keys;
  HA_CREATE_INFO create_info;
  DBUG_ENTER("mysql_drop_index");
  bzero((char*) &create_info,sizeof(create_info));
  create_info.db_type=DB_TYPE_DEFAULT;
  create_info.default_table_charset= thd->variables.collation_database;
6052 6053
  alter_info->clear();
  alter_info->flags= ALTER_DROP_INDEX;
6054
  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
6055
				&create_info, table_list,
6056
				fields, keys, 0, (ORDER*)0,
6057
				DUP_ERROR, 0, alter_info));
6058
}
unknown's avatar
merge  
unknown committed
6059 6060


6061 6062 6063 6064 6065
/*
  Multi update query pre-check

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

unknown's avatar
unknown committed
6069
  RETURN VALUE
unknown's avatar
unknown committed
6070 6071
    FALSE OK
    TRUE  Error
6072
*/
unknown's avatar
unknown committed
6073

unknown's avatar
unknown committed
6074
bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
6075 6076 6077 6078 6079
{
  const char *msg= 0;
  TABLE_LIST *table;
  LEX *lex= thd->lex;
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
6080
  DBUG_ENTER("multi_update_precheck");
6081 6082 6083

  if (select_lex->item_list.elements != lex->value_list.elements)
  {
6084
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6085
    DBUG_RETURN(TRUE);
6086 6087 6088 6089 6090
  }
  /*
    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
6091
  for (table= tables; table; table= table->next_local)
6092
  {
6093 6094 6095 6096 6097 6098
    if (table->derived)
      table->grant.privilege= SELECT_ACL;
    else if ((check_access(thd, UPDATE_ACL, table->db,
                           &table->grant.privilege, 0, 1) ||
              grant_option &&
              check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
unknown's avatar
unknown committed
6099 6100 6101
             (check_access(thd, SELECT_ACL, table->db,
                           &table->grant.privilege, 0, 0) ||
              grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
unknown's avatar
unknown committed
6102
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6103

unknown's avatar
VIEW  
unknown committed
6104
    table->table_in_first_from_clause= 1;
6105
  }
unknown's avatar
unknown committed
6106 6107 6108
  /*
    Is there tables of subqueries?
  */
6109 6110
  if (&lex->select_lex != lex->all_selects_list)
  {
6111
    DBUG_PRINT("info",("Checking sub query list"));
unknown's avatar
VIEW  
unknown committed
6112
    for (table= tables; table; table= table->next_global)
6113
    {
unknown's avatar
unknown committed
6114 6115 6116
      if (!my_tz_check_n_skip_implicit_tables(&table,
                                              lex->time_zone_tables_used) &&
          !table->table_in_first_from_clause)
6117 6118 6119
      {
	if (check_access(thd, SELECT_ACL, table->db,
			 &table->grant.privilege, 0, 0) ||
unknown's avatar
unknown committed
6120
	    grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
unknown's avatar
unknown committed
6121
	  DBUG_RETURN(TRUE);
6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133
      }
    }
  }

  if (select_lex->order_list.elements)
    msg= "ORDER BY";
  else if (select_lex->select_limit && select_lex->select_limit !=
	   HA_POS_ERROR)
    msg= "LIMIT";
  if (msg)
  {
    my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
unknown's avatar
unknown committed
6134
    DBUG_RETURN(TRUE);
6135
  }
unknown's avatar
unknown committed
6136
  DBUG_RETURN(FALSE);
6137 6138 6139 6140 6141 6142 6143
}

/*
  Multi delete query pre-check

  SYNOPSIS
    multi_delete_precheck()
unknown's avatar
unknown committed
6144
    thd			Thread handler
unknown's avatar
VIEW  
unknown committed
6145
    tables		Global/local table list
unknown's avatar
unknown committed
6146
    table_count		Pointer to table counter
6147

unknown's avatar
unknown committed
6148
  RETURN VALUE
unknown's avatar
unknown committed
6149 6150
    FALSE OK
    TRUE  error
6151
*/
unknown's avatar
unknown committed
6152 6153

bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
6154 6155 6156 6157
{
  SELECT_LEX *select_lex= &thd->lex->select_lex;
  TABLE_LIST *aux_tables=
    (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
unknown's avatar
unknown committed
6158
  TABLE_LIST *target_tbl;
unknown's avatar
VIEW  
unknown committed
6159
  DBUG_ENTER("multi_delete_precheck");
unknown's avatar
unknown committed
6160 6161

  *table_count= 0;
6162 6163 6164 6165 6166 6167

  /* sql_yacc guarantees that tables and aux_tables are not zero */
  DBUG_ASSERT(aux_tables != 0);
  if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
      check_table_access(thd,SELECT_ACL, tables,0) ||
      check_table_access(thd,DELETE_ACL, aux_tables,0))
unknown's avatar
unknown committed
6168
    DBUG_RETURN(TRUE);
6169 6170
  if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
  {
unknown's avatar
unknown committed
6171 6172
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
6173
    DBUG_RETURN(TRUE);
6174
  }
unknown's avatar
VIEW  
unknown committed
6175
  for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next_local)
6176 6177 6178 6179
  {
    (*table_count)++;
    /* All tables in aux_tables must be found in FROM PART */
    TABLE_LIST *walk;
unknown's avatar
VIEW  
unknown committed
6180
    for (walk= tables; walk; walk= walk->next_local)
6181
    {
unknown's avatar
unknown committed
6182 6183 6184
      if (!my_strcasecmp(table_alias_charset,
			 target_tbl->alias, walk->alias) &&
	  !strcmp(walk->db, target_tbl->db))
6185 6186 6187 6188
	break;
    }
    if (!walk)
    {
6189
      my_error(ER_UNKNOWN_TABLE, MYF(0),
6190
               target_tbl->table_name, "MULTI DELETE");
unknown's avatar
unknown committed
6191
      DBUG_RETURN(TRUE);
6192
    }
unknown's avatar
unknown committed
6193
    walk->lock_type= target_tbl->lock_type;
unknown's avatar
VIEW  
unknown committed
6194
    target_tbl->correspondent_table= walk;	// Remember corresponding table
6195
  }
unknown's avatar
unknown committed
6196
  DBUG_RETURN(FALSE);
6197 6198 6199
}


unknown's avatar
unknown committed
6200 6201 6202 6203 6204
/*
  simple UPDATE query pre-check

  SYNOPSIS
    update_precheck()
unknown's avatar
unknown committed
6205 6206
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
6207 6208

  RETURN VALUE
unknown's avatar
unknown committed
6209 6210
    FALSE OK
    TRUE  Error
unknown's avatar
unknown committed
6211
*/
unknown's avatar
unknown committed
6212

unknown's avatar
unknown committed
6213
bool update_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
6214 6215 6216 6217
{
  DBUG_ENTER("update_precheck");
  if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
  {
unknown's avatar
unknown committed
6218
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6219
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6220
  }
unknown's avatar
unknown committed
6221 6222
  DBUG_RETURN(check_db_used(thd, tables) ||
	       check_one_table_access(thd, UPDATE_ACL, tables));
unknown's avatar
unknown committed
6223 6224 6225 6226 6227 6228 6229 6230
}


/*
  simple DELETE query pre-check

  SYNOPSIS
    delete_precheck()
unknown's avatar
unknown committed
6231 6232
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
6233 6234

  RETURN VALUE
unknown's avatar
unknown committed
6235 6236
    FALSE  OK
    TRUE   error
unknown's avatar
unknown committed
6237
*/
unknown's avatar
unknown committed
6238

unknown's avatar
unknown committed
6239
bool delete_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
6240 6241 6242
{
  DBUG_ENTER("delete_precheck");
  if (check_one_table_access(thd, DELETE_ACL, tables))
unknown's avatar
unknown committed
6243
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6244
  /* Set privilege for the WHERE clause */
unknown's avatar
unknown committed
6245
  tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
6246
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
6247 6248 6249 6250 6251 6252 6253 6254
}


/*
  simple INSERT query pre-check

  SYNOPSIS
    insert_precheck()
unknown's avatar
unknown committed
6255 6256
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
6257 6258

  RETURN VALUE
unknown's avatar
unknown committed
6259 6260
    FALSE  OK
    TRUE   error
unknown's avatar
unknown committed
6261
*/
unknown's avatar
unknown committed
6262

unknown's avatar
merge  
unknown committed
6263
bool insert_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
6264 6265 6266 6267
{
  LEX *lex= thd->lex;
  DBUG_ENTER("insert_precheck");

unknown's avatar
unknown committed
6268 6269 6270 6271
  /*
    Check that we have modify privileges for the first table and
    select privileges for the rest
  */
unknown's avatar
unknown committed
6272 6273 6274
  ulong privilege= (INSERT_ACL |
                    (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
                    (lex->value_list.elements ? UPDATE_ACL : 0));
unknown's avatar
unknown committed
6275 6276

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

unknown's avatar
unknown committed
6279
  if (lex->update_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
6280
  {
unknown's avatar
unknown committed
6281
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6282
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6283
  }
unknown's avatar
unknown committed
6284
  DBUG_RETURN(FALSE);
6285
}
unknown's avatar
unknown committed
6286 6287 6288 6289 6290 6291 6292


/*
  CREATE TABLE query pre-check

  SYNOPSIS
    create_table_precheck()
unknown's avatar
unknown committed
6293 6294 6295
    thd			Thread handler
    tables		Global table list
    create_table	Table which will be created
unknown's avatar
unknown committed
6296 6297

  RETURN VALUE
unknown's avatar
unknown committed
6298 6299
    FALSE   OK
    TRUE   Error
unknown's avatar
unknown committed
6300
*/
unknown's avatar
unknown committed
6301

unknown's avatar
unknown committed
6302 6303
bool create_table_precheck(THD *thd, TABLE_LIST *tables,
                           TABLE_LIST *create_table)
unknown's avatar
unknown committed
6304 6305
{
  LEX *lex= thd->lex;
6306 6307
  SELECT_LEX *select_lex= &lex->select_lex;
  ulong want_priv;
unknown's avatar
merge  
unknown committed
6308
  bool error= TRUE;                                 // Error message is given
unknown's avatar
unknown committed
6309
  DBUG_ENTER("create_table_precheck");
6310 6311 6312

  want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
              CREATE_TMP_ACL : CREATE_ACL);
unknown's avatar
unknown committed
6313 6314 6315 6316 6317 6318
  lex->create_info.alias= create_table->alias;
  if (check_access(thd, want_priv, create_table->db,
		   &create_table->grant.privilege, 0, 0) ||
      check_merge_table_access(thd, create_table->db,
			       (TABLE_LIST *)
			       lex->create_info.merge_list.first))
6319 6320 6321 6322 6323 6324 6325 6326 6327 6328
    goto err;
  if (grant_option && want_priv != CREATE_TMP_ACL &&
      check_grant(thd, want_priv, create_table, 0, UINT_MAX, 0))
    goto err;

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

    /*
unknown's avatar
unknown committed
6329 6330 6331
      Only do the check for PS, becasue we on execute we have to check that
      against the opened tables to ensure we don't use a table that is part
      of the view (which can only be done after the table has been opened).
6332
    */
unknown's avatar
unknown committed
6333
    if (thd->current_arena->is_stmt_prepare())
6334
    {
unknown's avatar
unknown committed
6335 6336 6337 6338
      /*
        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
6339
          find_table_in_global_list(tables, create_table->db,
6340
                                    create_table->table_name))
unknown's avatar
unknown committed
6341
      {
6342
	error= FALSE;
unknown's avatar
unknown committed
6343 6344 6345
        goto err;
      }
    }
6346 6347 6348
    if (tables && check_table_access(thd, SELECT_ACL, tables,0))
      goto err;
  }
unknown's avatar
merge  
unknown committed
6349
  error= FALSE;
6350 6351 6352

err:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
6353
}
unknown's avatar
unknown committed
6354 6355 6356 6357 6358 6359 6360


/*
  negate given expression

  SYNOPSIS
    negate_expression()
6361
    thd  thread handler
unknown's avatar
unknown committed
6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389
    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);
}