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",
unknown's avatar
unknown committed
80
  "Prepare", "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


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)
153 154
{
  int return_val=0;
unknown's avatar
unknown committed
155
  uint temp_len, user_len;
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;
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)))
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
174 175
      return_val=1;
      goto end;
unknown's avatar
unknown committed
176
    }
177 178
    uc->user=(char*) (uc+1);
    memcpy(uc->user,temp_user,temp_len+1);
179
    uc->host= uc->user + user_len +  1;
180
    uc->len = temp_len;
181
    uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
182
    uc->user_resources=*mqh;
183
    uc->intime=thd->thr_create_time;
unknown's avatar
SCRUM  
unknown committed
184
    if (my_hash_insert(&hash_user_connections, (byte*) uc))
185 186
    {
      my_free((char*) uc,0);
187
      net_send_error(thd, 0, NullS);		// Out of memory
188 189 190 191 192
      return_val=1;
      goto end;
    }
  }
  thd->user_connect=uc;
193
  uc->connections++;
194 195 196
end:
  (void) pthread_mutex_unlock(&LOCK_user_conn);
  return return_val;
unknown's avatar
unknown committed
197

198
}
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
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
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
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
{
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);
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
{
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");
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:
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)
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
636
  {
637
    USER_CONN *uc;
638
    uint temp_len=lu->user.length+lu->host.length+2;
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)))
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;
651 652
    }
  }
unknown's avatar
unknown committed
653
  else
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++)
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;
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 */
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
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
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
unknown's avatar
unknown committed
902 903 904 905 906 907 908 909 910
  /* 
    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'.
  */
  uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? 
    *passwd++ : strlen(passwd);
  db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
    db + passwd_len + 1 : 0;
unknown's avatar
unknown committed
911

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

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

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

939

940 941
void execute_init_command(THD *thd, sys_var_str *init_command_var,
			  rw_lock_t *var_mutex)
unknown's avatar
unknown committed
942 943 944 945
{
  Vio* save_vio;
  ulong save_client_capabilities;

946 947 948 949 950 951 952 953 954
  thd->proc_info= "Execution of init_command";
  /*
    We need to lock init_command_var because
    during execution of init_command_var query
    values of init_command_var can't be changed
  */
  rw_rdlock(var_mutex);
  thd->query= init_command_var->value;
  thd->query_length= init_command_var->value_length;
unknown's avatar
unknown committed
955 956
  save_client_capabilities= thd->client_capabilities;
  thd->client_capabilities|= CLIENT_MULTI_QUERIES;
957 958 959 960
  /*
    We don't need return result of execution to client side.
    To forbid this we should set thd->net.vio to 0.
  */
unknown's avatar
unknown committed
961 962 963
  save_vio= thd->net.vio;
  thd->net.vio= 0;
  dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
964
  rw_unlock(var_mutex);
unknown's avatar
unknown committed
965 966 967 968 969
  thd->client_capabilities= save_client_capabilities;
  thd->net.vio= save_vio;
}


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

  pthread_detach_this_thread();

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

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

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

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

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

unknown's avatar
unknown committed
1042
    thd->version= refresh_version;
1043
    thd->proc_info= 0;
1044
    thd->command= COM_SLEEP;
1045 1046
    thd->set_time();
    thd->init_for_queries();
unknown's avatar
unknown committed
1047

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

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

1097 1098 1099 1100
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
unknown's avatar
unknown committed
1101

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

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

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

1129
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
1130 1131 1132 1133
    thd->options |= OPTION_BIG_SELECTS;

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

1136
  buff= (char*) thd->net.buff;
1137
  thd->init_for_queries();
unknown's avatar
unknown committed
1138 1139
  while (fgets(buff, thd->net.max_packet, file))
  {
unknown's avatar
unknown committed
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
   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
1160
    while (length && (my_isspace(thd->charset(), buff[length-1]) ||
1161
           buff[length-1] == ';'))
unknown's avatar
unknown committed
1162 1163
      length--;
    buff[length]=0;
1164
    thd->query_length=length;
unknown's avatar
unknown committed
1165 1166
    thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
    thd->query[length] = '\0';
1167 1168 1169 1170
    /*
      We don't need to obtain LOCK_thread_count here because in bootstrap
      mode we have only one thread.
    */
unknown's avatar
unknown committed
1171
    thd->query_id=query_id++;
1172
    if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
1173 1174 1175
    {
      thd->net.error = 0;
      close_thread_tables(thd);			// Free tables
unknown's avatar
unknown committed
1176
      free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
1177 1178
      break;
    }
unknown's avatar
unknown committed
1179 1180
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
1181
    if (thd->is_fatal_error)
1182
      break;
unknown's avatar
unknown committed
1183
    free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
1184
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1185
  }
1186 1187 1188

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

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

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

1214 1215 1216 1217 1218 1219 1220 1221
    /* 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
1222 1223 1224 1225 1226 1227 1228
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;
1229
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
1230
    DBUG_RETURN(1); // out of memory
unknown's avatar
VIEW  
unknown committed
1231 1232 1233 1234
  table_list->db= db;
  table_list->real_name= table_list->alias= tbl_name;
  table_list->lock_type= TL_READ_NO_INSERT;
  table_list->prev_global= &table_list;	// can be removed after merge with 4.1
unknown's avatar
unknown committed
1235

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

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

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

unknown's avatar
unknown committed
1262 1263
err:
  close_thread_tables(thd);
unknown's avatar
unknown committed
1264
  DBUG_RETURN(error);
unknown's avatar
unknown committed
1265 1266 1267
}


1268
#ifndef EMBEDDED_LIBRARY
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279

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

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

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

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

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

1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359
/*
   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
*/
1360

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

  thd->command=command;
unknown's avatar
unknown committed
1369 1370 1371 1372
  /*
    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
  */
1373
  thd->slow_command=FALSE;
1374
  thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
unknown's avatar
unknown committed
1375
  thd->set_time();
unknown's avatar
unknown committed
1376 1377 1378 1379 1380
  VOID(pthread_mutex_lock(&LOCK_thread_count));
  thd->query_id=query_id;
  if (command != COM_STATISTICS && command != COM_PING)
    query_id++;
  thread_running++;
1381
  /* TODO: set thd->lex->sql_command to SQLCOM_END here */
unknown's avatar
unknown committed
1382
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1383

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

1412
    statistic_increment(thd->status_var.com_other, &LOCK_status);
1413
    thd->slow_command= TRUE;
1414 1415 1416
    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
1417
    mysql_table_dump(thd, db, tbl_name, -1);
1418 1419
    break;
  }
unknown's avatar
unknown committed
1420 1421
  case COM_CHANGE_USER:
  {
unknown's avatar
unknown committed
1422
    thd->change_user();
1423
    thd->clear_error();                         // if errors from rollback
unknown's avatar
unknown committed
1424

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

1453 1454 1455 1456 1457 1458 1459
    /* 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
1460
    USER_CONN *save_user_connect= thd->user_connect;
unknown's avatar
unknown committed
1461 1462
    
    if (!(thd->user= my_strdup(user, MYF(0))))
1463 1464
    {
      thd->user= save_user;
unknown's avatar
unknown committed
1465
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
1466 1467
      break;
    }
unknown's avatar
unknown committed
1468

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

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

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

1548
      /* Remove garbage at start of query */
unknown's avatar
unknown committed
1549
      while (my_isspace(thd->charset(), *packet) && length > 0)
1550 1551 1552 1553
      {
        packet++;
        length--;
      }
unknown's avatar
unknown committed
1554
      VOID(pthread_mutex_lock(&LOCK_thread_count));
1555
      thd->query_length= length;
1556 1557
      thd->query= packet;
      thd->query_id= query_id++;
1558
      /* TODO: set thd->lex->sql_command to SQLCOM_END here */
1559
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
1560
#ifndef EMBEDDED_LIBRARY
1561
      mysql_parse(thd, packet, length);
1562
#else
unknown's avatar
unknown committed
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572
      /*
	'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
1573
	thd->query_rest.copy(packet, length, thd->query_rest.charset());
1574 1575
      break;
#endif /*EMBEDDED_LIBRARY*/
1576 1577
    }

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

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

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

unknown's avatar
unknown committed
1616
    /*  command not cachable => no gap for data base name */
unknown's avatar
unknown committed
1617 1618
    if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
      break;
1619
    mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
1620
    if (lower_case_table_names)
unknown's avatar
unknown committed
1621
      my_casedn_str(files_charset_info, table_list.real_name);
unknown's avatar
unknown committed
1622 1623
    remove_escape(table_list.real_name);	// This can't have wildcards

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

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

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

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

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

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

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

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

  time_t start_of_query=thd->start_time;
1877
  thd->end_time();				// Set start time
1878

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

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

unknown's avatar
unknown committed
1904
  free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1905 1906 1907
  DBUG_RETURN(error);
}

1908

1909 1910 1911 1912 1913 1914 1915 1916
int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
                         enum enum_schema_tables schema_table_idx)
{
  DBUG_ENTER("prepare_schema_table");
  SELECT_LEX *sel= 0;
  switch(schema_table_idx) {
  case SCH_SCHEMATA:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
unknown's avatar
unknown committed
1917 1918
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0));   /* purecov: inspected */
1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929
    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
1930 1931
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1932 1933 1934 1935 1936 1937
    DBUG_RETURN(1);
#else
    {
      char *db= lex->select_lex.db ? lex->select_lex.db : thd->db;
      if (!db)
      {
unknown's avatar
unknown committed
1938 1939
	my_message(ER_NO_DB_ERROR,
                   ER(ER_NO_DB_ERROR), MYF(0)); /* purecov: inspected */
1940 1941 1942 1943 1944
        DBUG_RETURN(1);				/* purecov: inspected */
      }
      remove_escape(db);				// Fix escaped '_'
      if (check_db_name(db))
      {
unknown's avatar
unknown committed
1945
        my_error(ER_WRONG_DB_NAME, MYF(0), db);
1946 1947 1948 1949 1950 1951
        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
1952 1953
	my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
                 thd->priv_user, thd->priv_host, db);
1954 1955 1956 1957 1958 1959 1960 1961 1962
	DBUG_RETURN(1);
      }
      lex->select_lex.db= db;
      break;
    }
#endif
  case SCH_COLUMNS:
  case SCH_STATISTICS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1963 1964
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988
    DBUG_RETURN(1);
#else
    if (table_ident)
    {
      TABLE_LIST **query_tables_last= lex->query_tables_last;
      sel= new SELECT_LEX();
      sel->init_query();
      if(!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, 
                                 (List<String> *) 0, (List<String> *) 0))
        DBUG_RETURN(1);
      lex->query_tables_last= query_tables_last;
      TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
      char *db= table_list->db;
      remove_escape(db);			// Fix escaped '_'
      remove_escape(table_list->real_name);
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
                       &table_list->grant.privilege, 0, 0))
        DBUG_RETURN(1);				/* purecov: inspected */
      if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2,
                                      UINT_MAX, 0))
        DBUG_RETURN(1);
      break;
    }
#endif
1989 1990 1991
  case SCH_OPEN_TABLES:
  case SCH_VARIABLES:
  case SCH_STATUS:
1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016
  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);
}


2017 2018 2019 2020 2021 2022 2023 2024 2025 2026
/*
  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
2027 2028
    FALSE ok
    TRUE  error;  In this case thd->fatal_error is set
2029 2030 2031 2032 2033
*/

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

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

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

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

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

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

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

2113 2114 2115 2116 2117 2118
  /*
    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
2119
  if (all_tables || &lex->select_lex != lex->all_selects_list)
2120 2121
    mysql_reset_errors(thd);

unknown's avatar
SCRUM  
unknown committed
2122
#ifdef HAVE_REPLICATION
2123 2124
  if (thd->slave_thread)
  {
unknown's avatar
unknown committed
2125
    /*
unknown's avatar
merge  
unknown committed
2126 2127 2128
      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
2129
    if (all_tables_not_ok(thd, all_tables))
unknown's avatar
unknown committed
2130 2131
    {
      /* we warn the slave SQL thread */
unknown's avatar
unknown committed
2132
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
2133
      DBUG_RETURN(0);
unknown's avatar
unknown committed
2134
    }
unknown's avatar
merge  
unknown committed
2135 2136
#ifndef TO_BE_DELETED
    /*
2137 2138 2139
      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
2140
    */
2141 2142 2143
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
unknown's avatar
unknown committed
2144
      lex->insert_list = &select_lex->item_list;
2145
    }
unknown's avatar
merge  
unknown committed
2146
#endif
2147
  }
unknown's avatar
unknown committed
2148
#endif /* !HAVE_REPLICATION */
2149

2150 2151 2152 2153 2154
  /*
    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
2155
      !(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
2156 2157
      (uc_update_queries[lex->sql_command] > 0))
  {
unknown's avatar
unknown committed
2158
    my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
unknown's avatar
unknown committed
2159
    DBUG_RETURN(-1);
2160
  }
2161

2162 2163
  statistic_increment(thd->status_var.com_stat[lex->sql_command],
		      &LOCK_status);
unknown's avatar
unknown committed
2164 2165 2166
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
2167 2168 2169 2170 2171 2172 2173
    /* 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;
    }

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

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

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

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

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

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

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

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

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

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

unknown's avatar
unknown committed
2426
  case SQLCOM_BACKUP_TABLE:
2427
  {
unknown's avatar
VIEW  
unknown committed
2428 2429 2430
    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
2431
	check_global_access(thd, FILE_ACL))
2432
      goto error; /* purecov: inspected */
2433
    thd->slow_command=TRUE;
unknown's avatar
VIEW  
unknown committed
2434
    res = mysql_backup_table(thd, first_table);
unknown's avatar
unknown committed
2435

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

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

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

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

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

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

unknown's avatar
VIEW  
unknown committed
2599
      if (!(res= open_and_lock_tables(thd, select_tables)))
2600
      {
2601 2602 2603 2604 2605 2606 2607
        /*
          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))
        {
2608
          my_error(ER_UPDATE_TABLE_USED, MYF(0), create_table->real_name);
2609 2610
          goto create_error;
        }
unknown's avatar
unknown committed
2611 2612 2613 2614 2615 2616 2617 2618 2619 2620
        /* 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))
            {
2621
              my_error(ER_UPDATE_TABLE_USED, MYF(0), tab->real_name);
unknown's avatar
unknown committed
2622 2623 2624 2625
              goto create_error;
            }
          }
        }
2626

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

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

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

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

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

      res= mysql_multi_update(thd, all_tables,
                              &select_lex->item_list,
                              &lex->value_list,
                              select_lex->where,
                              select_lex->options,
                              lex->duplicates, unit, select_lex);
unknown's avatar
unknown committed
2959
    break;
unknown's avatar
unknown committed
2960
  }
unknown's avatar
unknown committed
2961
  case SQLCOM_REPLACE:
2962 2963
  case SQLCOM_INSERT:
  {
unknown's avatar
VIEW  
unknown committed
2964
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2965
    if ((res= insert_precheck(thd, all_tables)))
unknown's avatar
unknown committed
2966
      break;
unknown's avatar
VIEW  
unknown committed
2967
    res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
unknown's avatar
unknown committed
2968
		      lex->update_list, lex->value_list,
unknown's avatar
unknown committed
2969 2970
                      (lex->value_list.elements ?
                       DUP_UPDATE : lex->duplicates));
unknown's avatar
VIEW  
unknown committed
2971 2972
    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
2973
    break;
2974
  }
unknown's avatar
unknown committed
2975 2976 2977
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
unknown's avatar
VIEW  
unknown committed
2978
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2979
    if ((res= insert_precheck(thd, all_tables)))
2980
      break;
unknown's avatar
unknown committed
2981

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

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

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

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

2997 2998 2999
      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
3000
                                             &lex->update_list, &lex->value_list,
unknown's avatar
merge  
unknown committed
3001 3002
                                             lex->duplicates,
                                             lex->duplicates == DUP_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;
unknown's avatar
VIEW  
unknown committed
3009
	res= handle_select(thd, lex, result);
3010
	lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
3011 3012
        delete result;
      }
unknown's avatar
unknown committed
3013 3014 3015
      /* in case of error first_table->table can be 0 */
      if (first_table->table)
        first_table->table->insert_values= 0;
3016 3017
      /* revert changes for SP */
      lex->select_lex.table_list.first= (byte*) first_table;
3018 3019
    }
    else
unknown's avatar
unknown committed
3020
      res= TRUE;
unknown's avatar
VIEW  
unknown committed
3021 3022 3023 3024

    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
3025 3026
    break;
  }
3027
  case SQLCOM_TRUNCATE:
unknown's avatar
VIEW  
unknown committed
3028 3029
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, DELETE_ACL, all_tables))
unknown's avatar
unknown committed
3030
      goto error;
3031 3032 3033 3034 3035 3036
    /*
      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
3037 3038
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3039 3040
      goto error;
    }
unknown's avatar
VIEW  
unknown committed
3041

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

unknown's avatar
VIEW  
unknown committed
3062
    if ((res= multi_delete_precheck(thd, all_tables, &table_count)))
3063
      break;
unknown's avatar
unknown committed
3064

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

unknown's avatar
unknown committed
3071
    thd->proc_info="init";
unknown's avatar
VIEW  
unknown committed
3072 3073 3074
    if ((res= open_and_lock_tables(thd, all_tables)))
      break;

3075 3076 3077 3078 3079 3080 3081 3082 3083 3084
    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
3085
    if ((res= mysql_multi_delete_prepare(thd)))
unknown's avatar
unknown committed
3086
      goto error;
3087

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

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

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

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

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

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

unknown's avatar
SCRUM  
unknown committed
3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487
    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
3488
    if (first_table)
3489
    {
3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513
      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())
3514
      {
unknown's avatar
unknown committed
3515
        thd->clear_error();
unknown's avatar
unknown committed
3516
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3517
        mysql_bin_log.write(&qinfo);
3518 3519 3520 3521 3522 3523
      }
    }
    else
    {
      if (lex->columns.elements)
      {
unknown's avatar
unknown committed
3524 3525
	my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
                   MYF(0));
unknown's avatar
unknown committed
3526
        goto error;
3527 3528 3529 3530 3531 3532 3533 3534
      }
      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
3535
          thd->clear_error();
3536
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3537 3538
	  mysql_bin_log.write(&qinfo);
	}
3539
	if (lex->sql_command == SQLCOM_GRANT)
3540
	{
unknown's avatar
unknown committed
3541 3542 3543
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
unknown's avatar
unknown committed
3544
	    reset_mqh(user);
3545
	}
3546 3547 3548 3549
      }
    }
    break;
  }
unknown's avatar
SCRUM  
unknown committed
3550
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
unknown's avatar
unknown committed
3551
  case SQLCOM_RESET:
3552 3553 3554 3555 3556 3557 3558
    /* 
       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
3559
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, all_tables))
unknown's avatar
unknown committed
3560
      goto error;
3561 3562 3563 3564 3565
    /*
      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
3566
    if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
3567 3568 3569 3570 3571 3572 3573 3574 3575
    {
      /*
        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())
        {
3576
          Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3577 3578 3579 3580 3581
          mysql_bin_log.write(&qinfo);
        }
      }
      send_ok(thd);
    }
unknown's avatar
unknown committed
3582
    break;
3583
  }
unknown's avatar
unknown committed
3584
  case SQLCOM_KILL:
3585 3586 3587 3588 3589 3590 3591 3592 3593 3594
  {
    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
3595
    break;
3596
  }
unknown's avatar
unknown committed
3597
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
3598
  case SQLCOM_SHOW_GRANTS:
3599 3600
    if ((thd->priv_user &&
	 !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
unknown's avatar
unknown committed
3601
	!check_access(thd, SELECT_ACL, "mysql",0,1,0))
unknown's avatar
unknown committed
3602 3603 3604 3605
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
unknown's avatar
unknown committed
3606
#endif
3607
  case SQLCOM_HA_OPEN:
unknown's avatar
VIEW  
unknown committed
3608 3609 3610
    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))
3611
      goto error;
unknown's avatar
VIEW  
unknown committed
3612
    res= mysql_ha_open(thd, first_table);
3613 3614
    break;
  case SQLCOM_HA_CLOSE:
unknown's avatar
VIEW  
unknown committed
3615 3616
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables))
3617
      goto error;
unknown's avatar
VIEW  
unknown committed
3618
    res= mysql_ha_close(thd, first_table);
3619 3620
    break;
  case SQLCOM_HA_READ:
unknown's avatar
VIEW  
unknown committed
3621
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3622 3623 3624 3625 3626
    /*
      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
3627
    if (check_db_used(thd, all_tables))
3628
      goto error;
unknown's avatar
VIEW  
unknown committed
3629 3630 3631
    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);
3632 3633
    break;

unknown's avatar
unknown committed
3634
  case SQLCOM_BEGIN:
unknown's avatar
unknown committed
3635 3636 3637
    if (thd->locked_tables)
    {
      thd->lock=thd->locked_tables;
3638
      thd->locked_tables=0;			// Will be automatically closed
unknown's avatar
unknown committed
3639 3640
      close_thread_tables(thd);			// Free tables
    }
unknown's avatar
unknown committed
3641
    if (end_active_trans(thd))
unknown's avatar
unknown committed
3642
      goto error;
unknown's avatar
unknown committed
3643 3644
    else
    {
3645
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
unknown's avatar
unknown committed
3646 3647
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
3648 3649 3650
      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
3651
    }
unknown's avatar
unknown committed
3652 3653
    break;
  case SQLCOM_COMMIT:
3654 3655 3656 3657 3658
    /*
      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
3659
  {
3660
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
3661 3662
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
unknown's avatar
unknown committed
3663
    {
3664
      send_ok(thd);
unknown's avatar
unknown committed
3665
    }
unknown's avatar
unknown committed
3666
    else
unknown's avatar
unknown committed
3667
      goto error;
unknown's avatar
unknown committed
3668
    break;
unknown's avatar
unknown committed
3669
  }
unknown's avatar
unknown committed
3670 3671 3672
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
3673
    {
unknown's avatar
unknown committed
3674 3675 3676 3677 3678 3679 3680 3681 3682 3683
      /*
        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
3684 3685 3686 3687
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                     ER_WARNING_NOT_COMPLETE_ROLLBACK,
                     ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
      send_ok(thd);
3688
    }
unknown's avatar
unknown committed
3689
    else
unknown's avatar
unknown committed
3690
      res= TRUE;
3691
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
3692
    break;
unknown's avatar
unknown committed
3693 3694 3695
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
    if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
    {
unknown's avatar
unknown committed
3696
      if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
unknown's avatar
unknown committed
3697 3698 3699 3700
        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
3701 3702
    }
    else
unknown's avatar
unknown committed
3703
      goto error;
unknown's avatar
unknown committed
3704
    break;
3705
  case SQLCOM_SAVEPOINT:
unknown's avatar
unknown committed
3706
    if (!ha_savepoint(thd, lex->savepoint_name))
unknown's avatar
unknown committed
3707
      send_ok(thd);
unknown's avatar
unknown committed
3708
    else
unknown's avatar
unknown committed
3709
      goto error;
3710
    break;
3711 3712
  case SQLCOM_CREATE_PROCEDURE:
  case SQLCOM_CREATE_SPFUNCTION:
unknown's avatar
unknown committed
3713
  {
3714
    uint namelen;
3715
    char *name, *db;
unknown's avatar
unknown committed
3716
    int result;
3717

unknown's avatar
unknown committed
3718
    DBUG_ASSERT(lex->sphead);
3719

3720
    if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0))
3721 3722 3723 3724 3725
    {
      delete lex->sphead;
      lex->sphead= 0;
      goto error;
    }
3726 3727 3728 3729 3730 3731 3732
    
    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);
    }
3733 3734

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

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

3758 3759
    name= thd->strdup(name); 
    db= thd->strmake(lex->sphead->m_db.str, lex->sphead->m_db.length);
unknown's avatar
unknown committed
3760 3761
    res= (result= lex->sphead->create(thd));
    switch (result) {
unknown's avatar
unknown committed
3762
    case SP_OK:
3763
      lex->unit.cleanup();
unknown's avatar
unknown committed
3764 3765
      delete lex->sphead;
      lex->sphead= 0;
unknown's avatar
unknown committed
3766
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777
      /* 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
3778
#endif
3779
      send_ok(thd);
3780
      break;
unknown's avatar
unknown committed
3781
    case SP_WRITE_ROW_FAILED:
3782
      my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name);
3783
      lex->unit.cleanup();
unknown's avatar
unknown committed
3784 3785 3786
      delete lex->sphead;
      lex->sphead= 0;
      goto error;
3787
    case SP_NO_DB_ERROR:
3788
      my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
3789
      lex->unit.cleanup();
3790 3791 3792
      delete lex->sphead;
      lex->sphead= 0;
      goto error;
unknown's avatar
unknown committed
3793
    default:
3794
      my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name);
3795
      lex->unit.cleanup();
unknown's avatar
unknown committed
3796 3797 3798
      delete lex->sphead;
      lex->sphead= 0;
      goto error;
3799
    }
unknown's avatar
unknown committed
3800 3801
    break;
  }
3802 3803 3804 3805
  case SQLCOM_CALL:
    {
      sp_head *sp;

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

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

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

3850
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3851 3852 3853 3854 3855 3856 3857 3858
	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;
	}
3859
	sp_change_security_context(thd, sp, &save_ctx);
3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870
	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;
	}

3871
#endif
unknown's avatar
unknown committed
3872 3873
	select_limit= thd->variables.select_limit;
	thd->variables.select_limit= HA_POS_ERROR;
3874

3875
	thd->row_count_func= 0;
3876
	res= sp->execute_procedure(thd, &lex->value_list);
3877

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

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

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

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

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

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

4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135
  /*
    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
4136
  DBUG_RETURN(res || thd->net.report_error);
unknown's avatar
unknown committed
4137 4138

error:
unknown's avatar
unknown committed
4139
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
4140 4141 4142
}


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

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

  RETURN
    0 - OK
unknown's avatar
unknown committed
4155
    1 - access denied, error is sent to client
unknown's avatar
unknown committed
4156 4157
*/

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

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

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


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

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

bool
unknown's avatar
unknown committed
4199
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
4200
	     bool dont_check_global_grants, bool no_errors)
unknown's avatar
unknown committed
4201
{
unknown's avatar
unknown committed
4202 4203 4204 4205
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  ulong db_access;
#endif
  ulong dummy;
4206 4207 4208
  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
4209 4210 4211 4212 4213
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

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

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

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

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

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

  DBUG_PRINT("error",("Access denied"));
4277
  if (!no_errors)
4278 4279 4280 4281 4282 4283
    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
4284
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4285
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
4286 4287 4288
}


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

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


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

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

4368

4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384
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;
  tables->real_name= tables->alias= name;
  
  if ((thd->master_access & want_access) == want_access && !thd->db)
    tables->grant.privilege= want_access;
  else if (check_access(thd,want_access,db,&tables->grant.privilege,
			0, no_errors))
    return TRUE;
  
unknown's avatar
unknown committed
4385
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4386 4387
  if (grant_option)
    return check_grant_procedure(thd, want_access, tables, no_errors);
unknown's avatar
unknown committed
4388
#endif
4389 4390 4391 4392

  return FALSE;
}

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 4425 4426 4427
/*
  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);
}


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

unknown's avatar
unknown committed
4447 4448 4449

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

4465

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

4480
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
4481 4482 4483 4484 4485 4486 4487 4488
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));
4489
    thd->fatal_error();
unknown's avatar
unknown committed
4490 4491
    return 1;
  }
unknown's avatar
unknown committed
4492 4493 4494
#ifndef DBUG_OFF
  max_stack_used= max(max_stack_used, stack_used);
#endif
unknown's avatar
unknown committed
4495 4496
  return 0;
}
4497
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
4498 4499 4500 4501

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

4502
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
unknown's avatar
unknown committed
4503 4504
{
  LEX	*lex=current_lex;
4505
  ulong old_info=0;
unknown's avatar
unknown committed
4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531
  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;
}


/****************************************************************************
4532
  Initialize global thd variables needed for query
unknown's avatar
unknown committed
4533 4534
****************************************************************************/

4535
void
unknown's avatar
unknown committed
4536
mysql_init_query(THD *thd, uchar *buf, uint length)
unknown's avatar
unknown committed
4537 4538
{
  DBUG_ENTER("mysql_init_query");
unknown's avatar
unknown committed
4539
  lex_start(thd, buf, length);
4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560
  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");
4561
  thd->free_list= 0;
4562
  thd->select_number= 1;
unknown's avatar
unknown committed
4563
  thd->total_warn_count=0;			// Warnings for this query
unknown's avatar
unknown committed
4564 4565
  thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
  thd->sent_row_count= thd->examined_row_count= 0;
4566
  thd->is_fatal_error= thd->rand_used= thd->time_zone_used= 0;
unknown's avatar
unknown committed
4567
  thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | 
unknown's avatar
unknown committed
4568 4569
                          SERVER_QUERY_NO_INDEX_USED |
                          SERVER_QUERY_NO_GOOD_INDEX_USED);
unknown's avatar
unknown committed
4570
  thd->tmp_table_used= 0;
unknown's avatar
unknown committed
4571 4572
  if (opt_bin_log)
    reset_dynamic(&thd->user_var_events);
4573
  thd->clear_error();
unknown's avatar
unknown committed
4574 4575 4576
  DBUG_VOID_RETURN;
}

4577

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

4593

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

unknown's avatar
unknown committed
4612 4613
    unit->init_query();
    unit->init_select();
4614
    unit->thd= lex->thd;
unknown's avatar
unknown committed
4615
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
4616 4617
    unit->link_next= 0;
    unit->link_prev= 0;
4618
    unit->return_to= lex->current_select;
unknown's avatar
unknown committed
4619
    select_lex->include_down(unit);
unknown's avatar
unknown committed
4620
    /* TODO: assign resolve_mode for fake subquery after merging with new tree */
unknown's avatar
unknown committed
4621 4622
  }
  else
unknown's avatar
unknown committed
4623
  {
unknown's avatar
VIEW  
unknown committed
4624 4625
    if (lex->current_select->order_list.first && !lex->current_select->braces)
    {
unknown's avatar
unknown committed
4626
      my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
unknown's avatar
VIEW  
unknown committed
4627 4628
      return 1;
    }
4629
    select_lex->include_neighbour(lex->current_select);
unknown's avatar
unknown committed
4630 4631 4632 4633 4634 4635 4636 4637
    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
4638 4639
      if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX()))
        return 1;
unknown's avatar
unknown committed
4640 4641 4642 4643 4644
      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;
4645
      fake->select_limit= HA_POS_ERROR;
unknown's avatar
unknown committed
4646 4647
    }
  }
unknown's avatar
unknown committed
4648

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

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

  thd= current_thd;
unknown's avatar
unknown committed
4677
  lex= thd->lex;
4678 4679 4680 4681
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
4682 4683 4684
  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));
4685 4686 4687
  DBUG_VOID_RETURN;
}

4688

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

4700

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

4706
void mysql_parse(THD *thd, char *inBuf, uint length)
unknown's avatar
unknown committed
4707 4708 4709
{
  DBUG_ENTER("mysql_parse");

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


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

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

4793

unknown's avatar
unknown committed
4794

unknown's avatar
unknown committed
4795 4796 4797 4798 4799
/*****************************************************************************
** Store field definition for create
** Return 0 if ok
******************************************************************************/

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

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

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

  if (on_update_value && type != FIELD_TYPE_TIMESTAMP)
  {
4871
    my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
4872 4873 4874
    DBUG_RETURN(1);
  }
    
unknown's avatar
unknown committed
4875 4876 4877 4878
  if (!(new_field=new create_field()))
    DBUG_RETURN(1);
  new_field->field=0;
  new_field->field_name=field_name;
4879
  new_field->def= default_value;
unknown's avatar
unknown committed
4880 4881 4882 4883 4884 4885 4886 4887 4888
  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;
4889
  new_field->pack_length= new_field->key_length= 0;
4890
  new_field->charset=cs;
unknown's avatar
unknown committed
4891
  new_field->geom_type= (Field::geometry_type) uint_geom_type;
unknown's avatar
unknown committed
4892

4893 4894 4895 4896 4897 4898 4899 4900
  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
4901 4902
    new_field->comment.str=   (char*) comment->str;
    new_field->comment.length=comment->length;
4903
  }
unknown's avatar
unknown committed
4904 4905 4906 4907 4908
  /*
    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
4909
  if (!default_value && !(type_modifier & AUTO_INCREMENT_FLAG) &&
unknown's avatar
unknown committed
4910 4911
      (type_modifier & NOT_NULL_FLAG) && type != FIELD_TYPE_TIMESTAMP &&
      type != FIELD_TYPE_ENUM)
unknown's avatar
unknown committed
4912 4913
    new_field->flags|= NO_DEFAULT_VALUE_FLAG;

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

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

  switch (type) {
  case FIELD_TYPE_TINY:
4925
    if (!length) new_field->length=MAX_TINYINT_WIDTH+sign_len;
unknown's avatar
unknown committed
4926 4927 4928
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_SHORT:
4929
    if (!length) new_field->length=MAX_SMALLINT_WIDTH+sign_len;
unknown's avatar
unknown committed
4930 4931 4932
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_INT24:
4933
    if (!length) new_field->length=MAX_MEDIUMINT_WIDTH+sign_len;
unknown's avatar
unknown committed
4934 4935 4936
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONG:
4937
    if (!length) new_field->length=MAX_INT_WIDTH+sign_len;
unknown's avatar
unknown committed
4938 4939 4940
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONGLONG:
4941
    if (!length) new_field->length=MAX_BIGINT_WIDTH;
unknown's avatar
unknown committed
4942 4943 4944 4945 4946 4947
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_NULL:
    break;
  case FIELD_TYPE_DECIMAL:
    if (!length)
unknown's avatar
unknown committed
4948 4949
    {
      if ((new_field->length= new_field->decimals))
4950 4951
        new_field->length++;
      else
unknown's avatar
unknown committed
4952 4953
        new_field->length= 10;                  // Default length for DECIMAL
    }
4954 4955 4956 4957 4958 4959
    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
4960
    break;
4961 4962 4963 4964 4965 4966 4967 4968 4969
  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
4970 4971 4972 4973
  case FIELD_TYPE_BLOB:
  case FIELD_TYPE_TINY_BLOB:
  case FIELD_TYPE_LONG_BLOB:
  case FIELD_TYPE_MEDIUM_BLOB:
unknown's avatar
unknown committed
4974
  case FIELD_TYPE_GEOMETRY:
unknown's avatar
unknown committed
4975 4976 4977 4978 4979 4980
    if (default_value)				// Allow empty as default value
    {
      String str,*res;
      res=default_value->val_str(&str);
      if (res->length())
      {
4981 4982
	my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
                 field_name); /* purecov: inspected */
unknown's avatar
unknown committed
4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001
	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)
      {
5002
	my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
unknown's avatar
unknown committed
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 5029 5030 5031
	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
5032
    else if (new_field->length != 19)
unknown's avatar
unknown committed
5033
    {
5034 5035 5036 5037
      /*
        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
5038 5039 5040
      new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
      new_field->length= min(new_field->length,14); /* purecov: inspected */
    }
5041
    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061
    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
    {
5062 5063 5064 5065 5066 5067 5068 5069
      /*
        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
5070
        information about all TIMESTAMP fields in table will be availiable.
5071 5072 5073

        If we have TIMESTAMP NULL column without explicit DEFAULT value
        we treat it as having DEFAULT NULL attribute.
5074
      */
unknown's avatar
unknown committed
5075 5076 5077 5078 5079
      new_field->unireg_check= (on_update_value ?
                                Field::TIMESTAMP_UN_FIELD :
                                (new_field->flags & NOT_NULL_FLAG ?
                                 Field::TIMESTAMP_OLD_FIELD:
                                 Field::NONE));
5080
    }
unknown's avatar
unknown committed
5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096
    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:
    {
5097
      if (interval_list->elements > sizeof(longlong)*8)
unknown's avatar
unknown committed
5098
      {
5099
	my_error(ER_TOO_BIG_SET, MYF(0), field_name); /* purecov: inspected */
unknown's avatar
unknown committed
5100
	DBUG_RETURN(1);				      /* purecov: inspected */
unknown's avatar
unknown committed
5101
      }
5102
      new_field->pack_length= (interval_list->elements + 7) / 8;
unknown's avatar
unknown committed
5103
      if (new_field->pack_length > 4)
5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115
        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
5116
      break;
unknown's avatar
unknown committed
5117 5118 5119
    }
  case FIELD_TYPE_ENUM:
    {
5120 5121
      // Should be safe
      new_field->pack_length= interval_list->elements < 256 ? 1 : 2; 
5122

5123 5124 5125 5126 5127
      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
5128
      break;
unknown's avatar
unknown committed
5129
   }
5130 5131
  case MYSQL_TYPE_VAR_STRING:
    DBUG_ASSERT(0);                             // Impossible
5132
    break;
unknown's avatar
unknown committed
5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145
  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
5146 5147
  }

5148 5149 5150 5151 5152 5153 5154
  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
5155
  {
5156
    my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0),
unknown's avatar
unknown committed
5157
             field_name, max_field_charlength); /* purecov: inspected */
unknown's avatar
unknown committed
5158 5159 5160 5161 5162
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
5163
    my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
unknown's avatar
unknown committed
5164 5165 5166 5167 5168 5169 5170
    DBUG_RETURN(1);
  }
  lex->create_list.push_back(new_field);
  lex->last_field=new_field;
  DBUG_RETURN(0);
}

5171

unknown's avatar
unknown committed
5172 5173 5174 5175 5176 5177 5178 5179
/* 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
5180
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
5181 5182 5183 5184
{
  ORDER *order;
  Item	**item_ptr;

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


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

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

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


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


unknown's avatar
unknown committed
5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266
/*
  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
5267 5268
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
5269
					     LEX_STRING *alias,
unknown's avatar
unknown committed
5270 5271
					     ulong table_options,
					     thr_lock_type lock_type,
5272 5273
					     List<String> *use_index_arg,
					     List<String> *ignore_index_arg,
unknown's avatar
unknown committed
5274
                                             LEX_STRING *option)
unknown's avatar
unknown committed
5275 5276 5277
{
  register TABLE_LIST *ptr;
  char *alias_str;
5278
  LEX *lex= thd->lex;
unknown's avatar
unknown committed
5279 5280 5281 5282 5283
  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
5284
  if (check_table_name(table->table.str,table->table.length) ||
5285
      table->db.str && check_db_name(table->db.str))
unknown's avatar
unknown committed
5286
  {
5287
    my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
unknown's avatar
unknown committed
5288 5289 5290 5291
    DBUG_RETURN(0);
  }

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

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

unknown's avatar
unknown committed
5378

5379 5380 5381 5382
/*
  Initialize a new table list for a nested join

  SYNOPSIS
5383
    init_table_list()
5384
    thd         current thread
5385

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

5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429
  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
5430
    moves it one level up, eliminating the nest.
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 5460 5461

  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
5462
    nest_last_join()
5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477
    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");
5478

5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500
  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);
}


/*
5501
  Save names for a join with using clause
5502

5503 5504 5505 5506 5507 5508 5509
  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
5510 5511
    to be able to build later an on expression to replace the using clause.

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

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

/*
  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
5571 5572 5573

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

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

unknown's avatar
unknown committed
5640

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


5657 5658 5659 5660 5661 5662 5663
/*
  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
5664

5665 5666 5667 5668 5669 5670 5671 5672 5673 5674
  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
5675 5676 5677 5678 5679
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
{
  b->natural_join=a;
}

5680
/*
5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697
  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
5698 5699
*/

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

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

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

unknown's avatar
unknown committed
5863
  if (!error)
5864
    send_ok(thd);
unknown's avatar
unknown committed
5865
  else
unknown's avatar
unknown committed
5866
    my_error(error, MYF(0), id);
unknown's avatar
unknown committed
5867 5868 5869 5870 5871 5872 5873 5874 5875 5876
}

/* 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)
5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888
      *(ulong*) ptr->value= 0;
    else if (ptr->type == SHOW_KEY_CACHE_LONG)
    {
      /*
	Reset value in 'default' key cache.
	This needs to be recoded when we have thread specific key values
      */
      char *value= (((char*) sql_key_cache) +
		    (uint) ((char*) (ptr->value) -
			    (char*) &dflt_key_cache_var));
      *(ulong*) value= 0;
    }
5889 5890 5891 5892 5893 5894 5895
    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
5896 5897 5898
  }
  pthread_mutex_unlock(&LOCK_status);
}
5899 5900 5901 5902


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

unknown's avatar
unknown committed
5903 5904
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
			       const char *table_name)
5905
{
5906
  char buff[FN_REFLEN],*ptr, *end;
5907 5908 5909 5910 5911 5912 5913
  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))
  {
5914
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
5915 5916 5917 5918
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
5919
  end=convert_dirname(buff, *filename_ptr, NullS);
unknown's avatar
unknown committed
5920
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
5921 5922
    return 1;					// End of memory
  *filename_ptr=ptr;
5923
  strxmov(ptr,buff,table_name,NullS);
5924 5925
  return 0;
}
5926

5927

5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941
/*
  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;
5942 5943
  LEX *lex= thd->lex;
  if (lex->current_select != &lex->select_lex)
5944 5945
  {
    char command[80];
5946 5947
    strmake(command, lex->yylval->symbol.str,
	    min(lex->yylval->symbol.length, sizeof(command)-1));
5948
    my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
5949 5950 5951 5952
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
5953

unknown's avatar
unknown committed
5954

unknown's avatar
unknown committed
5955
Comp_creator *comp_eq_creator(bool invert)
unknown's avatar
unknown committed
5956
{
unknown's avatar
unknown committed
5957
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
unknown's avatar
unknown committed
5958 5959
}

unknown's avatar
unknown committed
5960

unknown's avatar
unknown committed
5961
Comp_creator *comp_ge_creator(bool invert)
unknown's avatar
unknown committed
5962
{
unknown's avatar
unknown committed
5963
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
unknown's avatar
unknown committed
5964 5965
}

unknown's avatar
unknown committed
5966

unknown's avatar
unknown committed
5967
Comp_creator *comp_gt_creator(bool invert)
unknown's avatar
unknown committed
5968
{
unknown's avatar
unknown committed
5969
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
unknown's avatar
unknown committed
5970 5971
}

unknown's avatar
unknown committed
5972

unknown's avatar
unknown committed
5973
Comp_creator *comp_le_creator(bool invert)
unknown's avatar
unknown committed
5974
{
unknown's avatar
unknown committed
5975
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
unknown's avatar
unknown committed
5976 5977
}

unknown's avatar
unknown committed
5978

unknown's avatar
unknown committed
5979
Comp_creator *comp_lt_creator(bool invert)
unknown's avatar
unknown committed
5980
{
unknown's avatar
unknown committed
5981
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
unknown's avatar
unknown committed
5982 5983
}

unknown's avatar
unknown committed
5984

unknown's avatar
unknown committed
5985
Comp_creator *comp_ne_creator(bool invert)
unknown's avatar
unknown committed
5986
{
unknown's avatar
unknown committed
5987
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
unknown's avatar
unknown committed
5988
}
unknown's avatar
unknown committed
5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008


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

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

  Item_allany_subselect *it=
6016
    new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all);
unknown's avatar
unknown committed
6017
  if (all)
6018
    return it->upper_item= new Item_func_not_all(it);	/* ALL */
unknown's avatar
unknown committed
6019

6020
  return it->upper_item= new Item_func_nop_all(it);      /* ANY/SOME */
unknown's avatar
unknown committed
6021
}
6022 6023


6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035
/*
  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
6036
bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
6037 6038
{
  List<create_field> fields;
6039 6040
  ALTER_INFO alter_info;
  alter_info.flags= ALTER_ADD_INDEX;
6041 6042 6043 6044 6045 6046 6047
  HA_CREATE_INFO create_info;
  DBUG_ENTER("mysql_create_index");
  bzero((char*) &create_info,sizeof(create_info));
  create_info.db_type=DB_TYPE_DEFAULT;
  create_info.default_table_charset= thd->variables.collation_database;
  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
				&create_info, table_list,
6048 6049
				fields, keys, 0, (ORDER*)0,
				DUP_ERROR, &alter_info));
6050 6051 6052
}


unknown's avatar
unknown committed
6053
bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
6054 6055 6056 6057 6058 6059 6060 6061
{
  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;
6062 6063
  alter_info->clear();
  alter_info->flags= ALTER_DROP_INDEX;
6064 6065
  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
				&create_info, table_list,
6066 6067
				fields, keys, 0, (ORDER*)0,
				DUP_ERROR, alter_info));
6068
}
unknown's avatar
merge  
unknown committed
6069 6070


6071 6072 6073 6074 6075
/*
  Multi update query pre-check

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

unknown's avatar
unknown committed
6079
  RETURN VALUE
unknown's avatar
unknown committed
6080 6081
    FALSE OK
    TRUE  Error
6082
*/
unknown's avatar
unknown committed
6083

unknown's avatar
unknown committed
6084
bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
6085 6086 6087 6088 6089
{
  const char *msg= 0;
  TABLE_LIST *table;
  LEX *lex= thd->lex;
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
6090
  DBUG_ENTER("multi_update_precheck");
6091 6092 6093

  if (select_lex->item_list.elements != lex->value_list.elements)
  {
6094
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6095
    DBUG_RETURN(TRUE);
6096 6097 6098 6099 6100
  }
  /*
    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
6101
  for (table= tables; table; table= table->next_local)
6102
  {
6103 6104 6105 6106 6107 6108
    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
6109 6110 6111
             (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
6112
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6113

unknown's avatar
VIEW  
unknown committed
6114
    table->table_in_first_from_clause= 1;
6115
  }
unknown's avatar
unknown committed
6116 6117 6118
  /*
    Is there tables of subqueries?
  */
6119 6120
  if (&lex->select_lex != lex->all_selects_list)
  {
6121
    DBUG_PRINT("info",("Checking sub query list"));
unknown's avatar
VIEW  
unknown committed
6122
    for (table= tables; table; table= table->next_global)
6123
    {
unknown's avatar
unknown committed
6124 6125 6126
      if (!my_tz_check_n_skip_implicit_tables(&table,
                                              lex->time_zone_tables_used) &&
          !table->table_in_first_from_clause)
6127 6128 6129
      {
	if (check_access(thd, SELECT_ACL, table->db,
			 &table->grant.privilege, 0, 0) ||
unknown's avatar
unknown committed
6130
	    grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
unknown's avatar
unknown committed
6131
	  DBUG_RETURN(TRUE);
6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143
      }
    }
  }

  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
6144
    DBUG_RETURN(TRUE);
6145
  }
unknown's avatar
unknown committed
6146
  DBUG_RETURN(FALSE);
6147 6148 6149 6150 6151 6152 6153
}

/*
  Multi delete query pre-check

  SYNOPSIS
    multi_delete_precheck()
unknown's avatar
unknown committed
6154
    thd			Thread handler
unknown's avatar
VIEW  
unknown committed
6155
    tables		Global/local table list
unknown's avatar
unknown committed
6156
    table_count		Pointer to table counter
6157

unknown's avatar
unknown committed
6158
  RETURN VALUE
unknown's avatar
unknown committed
6159 6160
    FALSE OK
    TRUE  error
6161
*/
unknown's avatar
unknown committed
6162 6163

bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
6164 6165 6166 6167
{
  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
6168
  TABLE_LIST *target_tbl;
unknown's avatar
VIEW  
unknown committed
6169
  DBUG_ENTER("multi_delete_precheck");
unknown's avatar
unknown committed
6170 6171

  *table_count= 0;
6172 6173 6174 6175 6176 6177

  /* 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
6178
    DBUG_RETURN(TRUE);
6179 6180
  if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
  {
unknown's avatar
unknown committed
6181 6182
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
6183
    DBUG_RETURN(TRUE);
6184
  }
unknown's avatar
VIEW  
unknown committed
6185
  for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next_local)
6186 6187 6188 6189
  {
    (*table_count)++;
    /* All tables in aux_tables must be found in FROM PART */
    TABLE_LIST *walk;
unknown's avatar
VIEW  
unknown committed
6190
    for (walk= tables; walk; walk= walk->next_local)
6191
    {
unknown's avatar
unknown committed
6192 6193 6194
      if (!my_strcasecmp(table_alias_charset,
			 target_tbl->alias, walk->alias) &&
	  !strcmp(walk->db, target_tbl->db))
6195 6196 6197 6198
	break;
    }
    if (!walk)
    {
6199 6200
      my_error(ER_UNKNOWN_TABLE, MYF(0),
               target_tbl->real_name, "MULTI DELETE");
unknown's avatar
unknown committed
6201
      DBUG_RETURN(TRUE);
6202
    }
unknown's avatar
unknown committed
6203
    walk->lock_type= target_tbl->lock_type;
unknown's avatar
VIEW  
unknown committed
6204
    target_tbl->correspondent_table= walk;	// Remember corresponding table
6205
  }
unknown's avatar
unknown committed
6206
  DBUG_RETURN(FALSE);
6207 6208 6209
}


unknown's avatar
unknown committed
6210 6211 6212 6213 6214
/*
  simple UPDATE query pre-check

  SYNOPSIS
    update_precheck()
unknown's avatar
unknown committed
6215 6216
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
6217 6218

  RETURN VALUE
unknown's avatar
unknown committed
6219 6220
    FALSE OK
    TRUE  Error
unknown's avatar
unknown committed
6221
*/
unknown's avatar
unknown committed
6222

unknown's avatar
unknown committed
6223
bool update_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
6224 6225 6226 6227
{
  DBUG_ENTER("update_precheck");
  if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
  {
unknown's avatar
unknown committed
6228
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6229
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6230
  }
unknown's avatar
unknown committed
6231 6232
  DBUG_RETURN(check_db_used(thd, tables) ||
	       check_one_table_access(thd, UPDATE_ACL, tables));
unknown's avatar
unknown committed
6233 6234 6235 6236 6237 6238 6239 6240
}


/*
  simple DELETE query pre-check

  SYNOPSIS
    delete_precheck()
unknown's avatar
unknown committed
6241 6242
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
6243 6244

  RETURN VALUE
unknown's avatar
unknown committed
6245 6246
    FALSE  OK
    TRUE   error
unknown's avatar
unknown committed
6247
*/
unknown's avatar
unknown committed
6248

unknown's avatar
unknown committed
6249
bool delete_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
6250 6251 6252
{
  DBUG_ENTER("delete_precheck");
  if (check_one_table_access(thd, DELETE_ACL, tables))
unknown's avatar
unknown committed
6253
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6254
  /* Set privilege for the WHERE clause */
unknown's avatar
unknown committed
6255
  tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
6256
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
6257 6258 6259 6260 6261 6262 6263 6264
}


/*
  simple INSERT query pre-check

  SYNOPSIS
    insert_precheck()
unknown's avatar
unknown committed
6265 6266
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
6267 6268

  RETURN VALUE
unknown's avatar
unknown committed
6269 6270
    FALSE  OK
    TRUE   error
unknown's avatar
unknown committed
6271
*/
unknown's avatar
unknown committed
6272

unknown's avatar
merge  
unknown committed
6273
bool insert_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
6274 6275 6276 6277
{
  LEX *lex= thd->lex;
  DBUG_ENTER("insert_precheck");

unknown's avatar
unknown committed
6278 6279 6280 6281
  /*
    Check that we have modify privileges for the first table and
    select privileges for the rest
  */
unknown's avatar
unknown committed
6282 6283 6284
  ulong privilege= (INSERT_ACL |
                    (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
                    (lex->value_list.elements ? UPDATE_ACL : 0));
unknown's avatar
unknown committed
6285 6286

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

unknown's avatar
unknown committed
6289
  if (lex->update_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
6290
  {
unknown's avatar
unknown committed
6291
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6292
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6293
  }
unknown's avatar
unknown committed
6294
  DBUG_RETURN(FALSE);
6295
}
unknown's avatar
unknown committed
6296 6297 6298 6299 6300 6301 6302


/*
  CREATE TABLE query pre-check

  SYNOPSIS
    create_table_precheck()
unknown's avatar
unknown committed
6303 6304 6305
    thd			Thread handler
    tables		Global table list
    create_table	Table which will be created
unknown's avatar
unknown committed
6306 6307

  RETURN VALUE
unknown's avatar
unknown committed
6308 6309
    FALSE   OK
    TRUE   Error
unknown's avatar
unknown committed
6310
*/
unknown's avatar
unknown committed
6311

unknown's avatar
unknown committed
6312 6313
bool create_table_precheck(THD *thd, TABLE_LIST *tables,
                           TABLE_LIST *create_table)
unknown's avatar
unknown committed
6314 6315
{
  LEX *lex= thd->lex;
6316 6317
  SELECT_LEX *select_lex= &lex->select_lex;
  ulong want_priv;
unknown's avatar
merge  
unknown committed
6318
  bool error= TRUE;                                 // Error message is given
unknown's avatar
unknown committed
6319
  DBUG_ENTER("create_table_precheck");
6320 6321 6322

  want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
              CREATE_TMP_ACL : CREATE_ACL);
unknown's avatar
unknown committed
6323 6324 6325 6326 6327 6328
  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))
6329 6330 6331 6332 6333 6334 6335 6336 6337 6338
    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
6339 6340 6341
      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).
6342
    */
unknown's avatar
unknown committed
6343
    if (thd->current_arena->is_stmt_prepare())
6344
    {
unknown's avatar
unknown committed
6345 6346 6347 6348
      /*
        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
6349 6350
          find_table_in_global_list(tables, create_table->db,
                                    create_table->real_name))
unknown's avatar
unknown committed
6351
      {
6352
	error= FALSE;
unknown's avatar
unknown committed
6353 6354 6355
        goto err;
      }
    }
6356 6357 6358
    if (tables && check_table_access(thd, SELECT_ACL, tables,0))
      goto err;
  }
unknown's avatar
merge  
unknown committed
6359
  error= FALSE;
6360 6361 6362

err:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
6363
}
unknown's avatar
unknown committed
6364 6365 6366 6367 6368 6369 6370


/*
  negate given expression

  SYNOPSIS
    negate_expression()
6371
    thd  thread handler
unknown's avatar
unknown committed
6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399
    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);
}