sql_parse.cc 168 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

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

46 47 48
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#endif
unknown's avatar
unknown committed
49

50
static void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
unknown's avatar
unknown committed
51
#ifndef NO_EMBEDDED_ACCESS_CHECKS
52
static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
unknown's avatar
unknown committed
53
#endif
54
static void decrease_user_connections(USER_CONN *uc);
unknown's avatar
unknown committed
55
static bool check_db_used(THD *thd,TABLE_LIST *tables);
unknown's avatar
unknown committed
56
static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables, 
unknown's avatar
unknown committed
57
				    List<Item> *fields, SELECT_LEX *select_lex);
unknown's avatar
unknown committed
58 59
static void remove_escape(char *name);
static void refresh_status(void);
unknown's avatar
unknown committed
60 61
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
			       const char *table_name);
unknown's avatar
unknown committed
62

63
const char *any_db="*any*";	// Special symbol for check_access
unknown's avatar
unknown committed
64 65 66 67

const char *command_name[]={
  "Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
  "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
68
  "Connect","Kill","Debug","Ping","Time","Delayed insert","Change user",
unknown's avatar
unknown committed
69
  "Binlog Dump","Table Dump",  "Connect Out", "Register Slave",
70
  "Prepare", "Execute", "Long Data", "Close stmt",
71
  "Reset stmt", "Set option",
72
  "Error"					// Last command number
unknown's avatar
unknown committed
73 74
};

75
static char empty_c_string[1]= {0};		// Used for not defined 'db'
unknown's avatar
unknown committed
76 77 78 79

#ifdef __WIN__
static void  test_signal(int sig_ptr)
{
unknown's avatar
unknown committed
80
#if !defined( DBUG_OFF)
unknown's avatar
unknown committed
81 82
  MessageBox(NULL,"Test signal","DBUG",MB_OK);
#endif
unknown's avatar
unknown committed
83
#if defined(OS2)
84 85
  fprintf(stderr, "Test signal %d\n", sig_ptr);
  fflush(stderr);
unknown's avatar
unknown committed
86
#endif
unknown's avatar
unknown committed
87 88 89 90
}
static void init_signals(void)
{
  int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
91
  for (int i=0 ; i < 7 ; i++)
unknown's avatar
unknown committed
92 93 94 95
    signal( signals[i], test_signal) ;
}
#endif

unknown's avatar
unknown committed
96 97 98 99 100 101 102 103 104 105
static void unlock_locked_tables(THD *thd)
{
  if (thd->locked_tables)
  {
    thd->lock=thd->locked_tables;
    thd->locked_tables=0;			// Will be automaticly closed
    close_thread_tables(thd);			// Free tables
  }
}

106

unknown's avatar
unknown committed
107
static bool end_active_trans(THD *thd)
108
{
unknown's avatar
unknown committed
109
  int error=0;
unknown's avatar
unknown committed
110
  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
unknown's avatar
unknown committed
111
		      OPTION_TABLE_LOCK))
112
  {
113 114
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
115
    if (ha_commit(thd))
unknown's avatar
unknown committed
116
      error=1;
117
  }
unknown's avatar
unknown committed
118
  return error;
119 120 121
}


unknown's avatar
unknown committed
122
#ifdef HAVE_REPLICATION
123 124 125
/*
  Returns true if all tables should be ignored
*/
126 127 128
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
129
          ((thd->lex->sql_command != SQLCOM_DELETE_MULTI) ||
unknown's avatar
unknown committed
130 131
           !tables_ok(thd,
		      (TABLE_LIST *)thd->lex->auxilliary_table_list.first)));
132
}
unknown's avatar
unknown committed
133
#endif
134 135


136 137
static HASH hash_user_connections;

unknown's avatar
unknown committed
138 139
static int get_or_create_user_conn(THD *thd, const char *user,
				   const char *host,
unknown's avatar
unknown committed
140
				   USER_RESOURCES *mqh)
141
{
142
  int return_val= 0;
unknown's avatar
unknown committed
143
  uint temp_len, user_len;
144 145 146 147 148 149
  char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
  struct  user_conn *uc;

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

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

188
}
189 190 191


/*
192
    Check if user exist and password supplied is correct. 
193 194
  SYNOPSIS
    check_user()
195 196 197 198 199 200 201 202 203
    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.
    passwd       scrambled password recieved from client
    passwd_len   length of scrambled password
    db           database name to connect to, may be NULL
    check_count  dont know exactly

204 205
    Note, that host, user and passwd may point to communication buffer.
    Current implementation does not depened on that, but future changes
206 207 208
    should be done with this in mind; 'thd' is INOUT, all other params
    are 'IN'.

209 210 211
  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
212 213
   -1  access denied or handshake error; error is sent to client;
   >0  error, not sent to client
unknown's avatar
unknown committed
214 215
*/

unknown's avatar
unknown committed
216 217 218
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
219
{
220
  DBUG_ENTER("check_user");
unknown's avatar
unknown committed
221
  
unknown's avatar
unknown committed
222 223
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  thd->master_access= GLOBAL_ACLS;			// Full rights
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
  /* 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
239 240
#else

241 242 243 244 245
  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);
  
246
  /*
247 248
    If the server is running in secure auth mode, short scrambles are 
    forbidden.
249
  */
250
  if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
unknown's avatar
unknown committed
251
  {
252 253 254
    net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
    mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
255
  }
unknown's avatar
unknown committed
256 257 258 259
  if (passwd_len != 0 &&
      passwd_len != SCRAMBLE_LENGTH &&
      passwd_len != SCRAMBLE_LENGTH_323)
    DBUG_RETURN(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
260

261
  /*
262 263 264 265
    Clear thd->db as it points to something, that will be freed when 
    connection is closed. We don't want to accidently free a wrong pointer
    if connect failed. Also in case of 'CHANGE USER' failure, current
    database will be switched to 'no database selected'.
266
  */
267 268
  thd->db= 0;
  thd->db_length= 0;
unknown's avatar
unknown committed
269
  
270
  USER_RESOURCES ur;
271
  int res= acl_getroot(thd, &ur, passwd, passwd_len);
unknown's avatar
unknown committed
272
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
273
  if (res == -1)
unknown's avatar
unknown committed
274
  {
unknown's avatar
unknown committed
275 276 277 278 279 280
    /*
      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.
    */
281
    NET *net= &thd->net;
282
    if (opt_secure_auth_local)
283
    {
284 285 286 287 288 289
      net_printf(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
                 thd->user, thd->host_or_ip);
      mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
                      thd->user, thd->host_or_ip);
      DBUG_RETURN(-1);
    }
290
    if (send_old_password_request(thd) ||
unknown's avatar
unknown committed
291 292 293 294 295 296 297
        my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very
    {                                                // specific packet size
      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 */
298
    res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
unknown's avatar
unknown committed
299
  }
unknown's avatar
unknown committed
300
#endif /*EMBEDDED_LIBRARY*/
unknown's avatar
unknown committed
301 302
  /* here res is always >= 0 */
  if (res == 0)
unknown's avatar
unknown committed
303
  {
unknown's avatar
unknown committed
304
    if (!(thd->master_access & NO_ACCESS)) // authentification is OK 
305
    {
unknown's avatar
unknown committed
306 307 308 309 310 311 312 313 314 315
      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)
316
      {
unknown's avatar
unknown committed
317 318
        VOID(pthread_mutex_lock(&LOCK_thread_count));
        bool count_ok= thread_count < max_connections + delayed_insert_threads
319
                       || (thd->master_access & SUPER_ACL);
unknown's avatar
unknown committed
320 321 322 323 324 325
        VOID(pthread_mutex_unlock(&LOCK_thread_count));
        if (!count_ok)
        {                                         // too many connections 
          send_error(thd, ER_CON_COUNT_ERROR);
          DBUG_RETURN(-1);
        }
326
      }
unknown's avatar
unknown committed
327

unknown's avatar
unknown committed
328 329 330 331 332 333 334 335
      /* 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*) "");

336
      /*
337 338 339
        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.
340
      */
unknown's avatar
unknown committed
341 342 343
      thd->db_access=0;

      /* Don't allow user to connect if he has done too many queries */
unknown's avatar
unknown committed
344 345 346 347 348 349 350 351 352
      if ((ur.questions || ur.updates || ur.connections ||
	   max_user_connections) &&
	  get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur))
	DBUG_RETURN(-1);
      if (thd->user_connect &&
	  (thd->user_connect->user_resources.connections ||
	   max_user_connections) &&
	  check_for_max_user_connections(thd, thd->user_connect))
	DBUG_RETURN(-1);
unknown's avatar
unknown committed
353 354 355

      /* Change database if necessary: OK or FAIL is sent in mysql_change_db */
      if (db && db[0])
356
      {
unknown's avatar
unknown committed
357 358 359 360 361 362
        if (mysql_change_db(thd, db))
        {
          if (thd->user_connect)
            decrease_user_connections(thd->user_connect);
          DBUG_RETURN(-1);
        }
363 364
      }
      else
unknown's avatar
unknown committed
365
	send_ok(thd);
unknown's avatar
unknown committed
366 367 368
      thd->password= test(passwd_len);          // remember for error messages 
      /* Ready to handle queries */
      DBUG_RETURN(0);
unknown's avatar
unknown committed
369 370
    }
  }
unknown's avatar
unknown committed
371
  else if (res == 2) // client gave short hash, server has long hash
unknown's avatar
unknown committed
372
  {
unknown's avatar
unknown committed
373 374 375
    net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
    mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
376
  }
unknown's avatar
unknown committed
377 378 379 380 381 382 383 384 385
  net_printf(thd, ER_ACCESS_DENIED_ERROR,
             thd->user,
             thd->host_or_ip,
             passwd_len ? ER(ER_YES) : ER(ER_NO));
  mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
                  thd->user,
                  thd->host_or_ip,
                  passwd_len ? ER(ER_YES) : ER(ER_NO));
  DBUG_RETURN(-1);
unknown's avatar
unknown committed
386
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
387 388
}

unknown's avatar
unknown committed
389
/*
unknown's avatar
unknown committed
390 391
  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
392 393
*/

394 395
extern "C" byte *get_key_conn(user_conn *buff, uint *length,
			      my_bool not_used __attribute__((unused)))
unknown's avatar
unknown committed
396 397 398 399 400
{
  *length=buff->len;
  return (byte*) buff->user;
}

401
extern "C" void free_user(struct user_conn *uc)
unknown's avatar
unknown committed
402 403 404 405
{
  my_free((char*) uc,MYF(0));
}

unknown's avatar
unknown committed
406
void init_max_user_conn(void)
unknown's avatar
unknown committed
407
{
unknown's avatar
unknown committed
408 409
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
		   0,0,
410
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
411
		   0);
unknown's avatar
unknown committed
412 413 414
}


unknown's avatar
unknown committed
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
/*
  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
432 433
#ifndef NO_EMBEDDED_ACCESS_CHECKS

434
static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
unknown's avatar
unknown committed
435
{
436
  int error=0;
437
  DBUG_ENTER("check_for_max_user_connections");
unknown's avatar
unknown committed
438

439
  (void) pthread_mutex_lock(&LOCK_user_conn);
440
  if (max_user_connections &&
unknown's avatar
unknown committed
441
      max_user_connections < (uint) uc->connections)
unknown's avatar
unknown committed
442
  {
443
    net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user);
444 445
    error=1;
    goto end;
unknown's avatar
unknown committed
446
  }
447
  time_out_user_resource_limits(thd, uc);
448
  if (uc->user_resources.connections &&
449
      uc->user_resources.connections <= uc->conn_per_hour)
450
  {
451
    net_printf(thd, ER_USER_LIMIT_REACHED, uc->user,
452
	       "max_connections_per_hour",
453 454 455 456
	       (long) uc->user_resources.connections);
    error=1;
    goto end;
  }
457
  uc->conn_per_hour++;
unknown's avatar
unknown committed
458 459

  end:
460 461
  if (error)
    uc->connections--; // no need for decrease_user_connections() here
462
  (void) pthread_mutex_unlock(&LOCK_user_conn);
463
  DBUG_RETURN(error);
unknown's avatar
unknown committed
464
}
unknown's avatar
unknown committed
465
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
466

unknown's avatar
unknown committed
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
/*
  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.
*/

485
static void decrease_user_connections(USER_CONN *uc)
unknown's avatar
unknown committed
486
{
487
  DBUG_ENTER("decrease_user_connections");
488 489 490
  (void) pthread_mutex_lock(&LOCK_user_conn);
  DBUG_ASSERT(uc->connections);
  if (!--uc->connections && !mqh_used)
unknown's avatar
unknown committed
491 492
  {
    /* Last connection for user; Delete it */
unknown's avatar
unknown committed
493
    (void) hash_delete(&hash_user_connections,(byte*) uc);
unknown's avatar
unknown committed
494
  }
495
  (void) pthread_mutex_unlock(&LOCK_user_conn);
496
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
497 498
}

499

unknown's avatar
unknown committed
500 501 502 503 504
void free_max_user_conn(void)
{
  hash_free(&hash_user_connections);
}

unknown's avatar
unknown committed
505

506 507 508
/*
  Mark all commands that somehow changes a table
  This is used to check number of updates / hour
unknown's avatar
unknown committed
509 510 511

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

unknown's avatar
unknown committed
514
char  uc_update_queries[SQLCOM_END+1];
515 516 517

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

520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
  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;
539
  uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
540 541
}

unknown's avatar
unknown committed
542 543
bool is_update_query(enum enum_sql_command command)
{
unknown's avatar
unknown committed
544
  DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
unknown's avatar
unknown committed
545 546
  return uc_update_queries[command];
}
547

unknown's avatar
unknown committed
548
/*
549 550
  Reset per-hour user resource limits when it has been more than
  an hour since they were last checked
unknown's avatar
unknown committed
551

552 553 554 555
  SYNOPSIS:
    time_out_user_resource_limits()
    thd			Thread handler
    uc			User connection details
unknown's avatar
unknown committed
556

557 558 559 560
  NOTE:
    This assumes that the LOCK_user_conn mutex has been acquired, so it is
    safe to test and modify members of the USER_CONN structure.
*/
561

562
static void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
unknown's avatar
unknown committed
563
{
unknown's avatar
unknown committed
564
  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
565
  DBUG_ENTER("time_out_user_resource_limits");
unknown's avatar
unknown committed
566

unknown's avatar
unknown committed
567
  /* If more than a hour since last check, reset resource checking */
568 569 570 571 572 573 574
  if (check_time  - uc->intime >= 3600)
  {
    uc->questions=1;
    uc->updates=0;
    uc->conn_per_hour=0;
    uc->intime=check_time;
  }
575 576 577 578 579 580 581 582 583 584 585 586

  DBUG_VOID_RETURN;
}


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

static bool check_mqh(THD *thd, uint check_command)
{
587 588
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  bool error= 0;
589 590 591 592 593 594 595 596
  USER_CONN *uc=thd->user_connect;
  DBUG_ENTER("check_mqh");
  DBUG_ASSERT(uc != 0);

  (void) pthread_mutex_lock(&LOCK_user_conn);

  time_out_user_resource_limits(thd, uc);

unknown's avatar
unknown committed
597
  /* Check that we have not done too many questions / hour */
598 599 600
  if (uc->user_resources.questions &&
      uc->questions++ >= uc->user_resources.questions)
  {
601
    net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
602 603 604 605
	       (long) uc->user_resources.questions);
    error=1;
    goto end;
  }
606
  if (check_command < (uint) SQLCOM_END)
unknown's avatar
unknown committed
607
  {
unknown's avatar
unknown committed
608 609 610 611
    /* 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)
    {
612
      net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
unknown's avatar
unknown committed
613 614 615 616
		 (long) uc->user_resources.updates);
      error=1;
      goto end;
    }
unknown's avatar
unknown committed
617 618
  }
end:
619
  (void) pthread_mutex_unlock(&LOCK_user_conn);
620
  DBUG_RETURN(error);
621 622
#else
  return (0);
unknown's avatar
unknown committed
623
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
624 625
}

unknown's avatar
unknown committed
626

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

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

unknown's avatar
unknown committed
666
/*
667
    Perform handshake, authorize client and update thd ACL variables.
668
  SYNOPSIS
669
    check_connection()
670
    thd  thread handle
671 672

  RETURN
673
     0  success, OK is sent to user, thd is updated.
674 675
    -1  error, which is sent to user
   > 0  error code (not sent to user)
unknown's avatar
unknown committed
676 677
*/

unknown's avatar
unknown committed
678 679
#ifndef EMBEDDED_LIBRARY
static int check_connection(THD *thd)
unknown's avatar
unknown committed
680
{
681
  uint connect_errors= 0;
unknown's avatar
unknown committed
682
  NET *net= &thd->net;
unknown's avatar
unknown committed
683 684
  ulong pkt_len= 0;
  char *end;
685

686 687 688
  DBUG_PRINT("info",
             ("New connection received on %s", vio_description(net->vio)));

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

693
    if (vio_peer_addr(net->vio, ip, &thd->peer_port))
unknown's avatar
unknown committed
694
      return (ER_BAD_HOST_ERROR);
695
    if (!(thd->ip= my_strdup(ip,MYF(0))))
unknown's avatar
unknown committed
696
      return (ER_OUT_OF_RESOURCES);
697
    thd->host_or_ip= thd->ip;
unknown's avatar
unknown committed
698
    vio_in_addr(net->vio,&thd->remote.sin_addr);
unknown's avatar
unknown committed
699 700 701
#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
702
    {
unknown's avatar
unknown committed
703 704
      thd->host= (char*) my_localhost;
      thd->host_or_ip= my_localhost;
unknown's avatar
unknown committed
705
    }
unknown's avatar
unknown committed
706 707 708
    else
#endif
    {
709 710 711 712 713 714
      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
715
	{
716
	  thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
unknown's avatar
unknown committed
717 718
	  thd->host_or_ip= thd->host;
	}
719 720 721
	if (connect_errors > max_connect_errors)
	  return(ER_HOST_IS_BLOCKED);
      }
unknown's avatar
unknown committed
722
    }
unknown's avatar
unknown committed
723 724 725
    DBUG_PRINT("info",("Host: %s  ip: %s",
		       thd->host ? thd->host : "unknown host",
		       thd->ip ? thd->ip : "unknown ip"));
unknown's avatar
unknown committed
726 727 728
    if (acl_check_host(thd->host,thd->ip))
      return(ER_HOST_NOT_PRIVILEGED);
  }
729
  else /* Hostname given means that the connection was on a socket */
unknown's avatar
unknown committed
730
  {
unknown's avatar
unknown committed
731
    DBUG_PRINT("info",("Host: %s",thd->host));
732 733
    thd->host_or_ip= thd->host;
    thd->ip= 0;
734 735
    /* Reset sin_addr */
    bzero((char*) &thd->remote, sizeof(thd->remote));
unknown's avatar
unknown committed
736 737 738
  }
  vio_keepalive(net->vio, TRUE);
  {
unknown's avatar
unknown committed
739
    /* buff[] needs to big enough to hold the server_version variable */
740
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
741 742
    ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
			  CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
unknown's avatar
unknown committed
743

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

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

  thd->client_capabilities=uint2korr(net->read_pos);
799 800 801 802 803 804 805 806 807 808 809
#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
810 811 812 813
  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
814 815 816 817 818 819 820
    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
    */
821
    if (!(thd->variables.character_set_client=
unknown's avatar
unknown committed
822 823 824 825
	  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))
826
    {
827 828
      thd->variables.character_set_client=
	global_system_variables.character_set_client;
829 830
      thd->variables.collation_connection=
	global_system_variables.collation_connection;
831 832
      thd->variables.character_set_results=
	global_system_variables.character_set_results;
833 834 835
    }
    else
    {
836
      thd->variables.character_set_results=
837 838 839
      thd->variables.collation_connection= 
	thd->variables.character_set_client;
    }
unknown's avatar
unknown committed
840
    thd->update_charset();
841
    end= (char*) net->read_pos+32;
842 843 844 845 846 847 848
  }
  else
  {
    thd->max_client_packet_length= uint3korr(net->read_pos+2);
    end= (char*) net->read_pos+5;
  }

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

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

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

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

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

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

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

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

933

934 935
void execute_init_command(THD *thd, sys_var_str *init_command_var,
			  rw_lock_t *var_mutex)
unknown's avatar
unknown committed
936 937 938 939
{
  Vio* save_vio;
  ulong save_client_capabilities;

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


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

  pthread_detach_this_thread();

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

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

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

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

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

unknown's avatar
unknown committed
1036
    thd->version= refresh_version;
1037 1038 1039
    thd->proc_info= 0;
    thd->set_time();
    thd->init_for_queries();
unknown's avatar
unknown committed
1040
    if (sys_init_connect.value_length && !(thd->master_access & SUPER_ACL))
unknown's avatar
unknown committed
1041
    {
1042 1043 1044
      execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
      if (thd->query_error)
	thd->killed= 1;
unknown's avatar
unknown committed
1045
    }
unknown's avatar
unknown committed
1046 1047 1048 1049 1050
    while (!net->error && net->vio != 0 && !thd->killed)
    {
      if (do_command(thd))
	break;
    }
1051 1052
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
unknown's avatar
unknown committed
1053
    free_root(thd->mem_root,MYF(0));
unknown's avatar
unknown committed
1054
    if (net->error && net->vio != 0 && net->report_error)
unknown's avatar
unknown committed
1055
    {
1056
      if (!thd->killed && thd->variables.log_warnings > 1)
unknown's avatar
unknown committed
1057 1058 1059 1060 1061 1062
        sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
                          thd->thread_id,(thd->db ? thd->db : "unconnected"),
                          thd->user ? thd->user : "unauthenticated",
                          thd->host_or_ip,
                          (net->last_errno ? ER(net->last_errno) :
                           ER(ER_UNKNOWN_ERROR)));
1063
      send_error(thd,net->last_errno,NullS);
unknown's avatar
unknown committed
1064
      statistic_increment(aborted_threads,&LOCK_status);
unknown's avatar
unknown committed
1065
    }
1066 1067 1068 1069
    else if (thd->killed)
    {
      statistic_increment(aborted_threads,&LOCK_status);
    }
1070
    
unknown's avatar
unknown committed
1071
end_thread:
1072
    close_connection(thd, 0, 1);
unknown's avatar
unknown committed
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
    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
1084 1085
#endif /* EMBEDDED_LIBRARY */

1086 1087 1088 1089
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
unknown's avatar
unknown committed
1090

1091
extern "C" pthread_handler_decl(handle_bootstrap,arg)
unknown's avatar
unknown committed
1092
{
1093 1094 1095
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
unknown's avatar
unknown committed
1096

1097
  /* The following must be called before DBUG_ENTER */
1098
  if (my_thread_init() || thd->store_globals())
unknown's avatar
unknown committed
1099
  {
unknown's avatar
unknown committed
1100
#ifndef EMBEDDED_LIBRARY
1101
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
unknown's avatar
unknown committed
1102
#endif
1103
    thd->fatal_error();
1104
    goto end;
unknown's avatar
unknown committed
1105
  }
1106 1107
  DBUG_ENTER("handle_bootstrap");

unknown's avatar
unknown committed
1108
#ifndef EMBEDDED_LIBRARY
1109 1110
  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
1111
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
unknown's avatar
unknown committed
1112
  sigset_t set;
1113 1114
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
unknown's avatar
unknown committed
1115
#endif
unknown's avatar
unknown committed
1116
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
1117

1118
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
1119 1120 1121 1122
    thd->options |= OPTION_BIG_SELECTS;

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

1125
  buff= (char*) thd->net.buff;
1126
  thd->init_for_queries();
unknown's avatar
unknown committed
1127 1128
  while (fgets(buff, thd->net.max_packet, file))
  {
1129 1130
    ulong length= (ulong) strlen(buff);
    while (buff[length-1] != '\n' && !feof(file))
1131
    {
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
      /*
        We got only a part of the current string. Will try to increase
        net buffer then read the rest of the current string.
      */
      if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
      {
        send_error(thd, thd->net.last_errno, NullS);
        thd->is_fatal_error= 1;
        break;
      }
      buff= (char*) thd->net.buff;
      fgets(buff + length, thd->net.max_packet - length, file);
      length+= (ulong) strlen(buff + length);
1145
    }
1146 1147
    if (thd->is_fatal_error)
      break;
unknown's avatar
unknown committed
1148
    while (length && (my_isspace(thd->charset(), buff[length-1]) ||
1149
           buff[length-1] == ';'))
unknown's avatar
unknown committed
1150 1151
      length--;
    buff[length]=0;
1152
    thd->query_length=length;
unknown's avatar
unknown committed
1153 1154
    thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
    thd->query[length] = '\0';
unknown's avatar
unknown committed
1155
    thd->query_id=query_id++;
1156
    if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
1157 1158 1159
    {
      thd->net.error = 0;
      close_thread_tables(thd);			// Free tables
unknown's avatar
unknown committed
1160
      free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
1161 1162
      break;
    }
unknown's avatar
unknown committed
1163 1164
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
1165
    if (thd->is_fatal_error)
1166
      break;
unknown's avatar
unknown committed
1167
    free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
1168
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1169
  }
1170 1171 1172

  /* thd->fatal_error should be set in case something went wrong */
end:
unknown's avatar
unknown committed
1173
#ifndef EMBEDDED_LIBRARY
1174 1175 1176
  (void) pthread_mutex_lock(&LOCK_thread_count);
  thread_count--;
  (void) pthread_mutex_unlock(&LOCK_thread_count);
1177
  (void) pthread_cond_broadcast(&COND_thread_count);
1178 1179
  my_thread_end();
  pthread_exit(0);
unknown's avatar
unknown committed
1180
#endif
1181
  DBUG_RETURN(0);				// Never reached
unknown's avatar
unknown committed
1182 1183
}

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

1186
void free_items(Item *item)
unknown's avatar
unknown committed
1187
{
1188
  for (; item ; item=item->next)
1189
    item->delete_self();
unknown's avatar
unknown committed
1190 1191
}

1192 1193 1194 1195 1196 1197 1198 1199
    /* 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
1200 1201 1202 1203 1204 1205 1206
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;
1207
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
1208
    DBUG_RETURN(1); // out of memory
unknown's avatar
unknown committed
1209
  table_list->db = db;
1210
  table_list->real_name = table_list->alias = tbl_name;
unknown's avatar
unknown committed
1211 1212 1213
  table_list->lock_type = TL_READ_NO_INSERT;
  table_list->next = 0;

1214 1215
  if (!db || check_db_name(db))
  {
1216
    net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
1217 1218
    goto err;
  }
1219
  if (lower_case_table_names)
1220
    my_casedn_str(files_charset_info, tbl_name);
unknown's avatar
unknown committed
1221
  remove_escape(table_list->real_name);
1222 1223 1224 1225

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

unknown's avatar
unknown committed
1226
  if (check_one_table_access(thd, SELECT_ACL, table_list))
unknown's avatar
unknown committed
1227 1228
    goto err;
  thd->free_list = 0;
unknown's avatar
unknown committed
1229
  thd->query_length=(uint) strlen(tbl_name);
unknown's avatar
unknown committed
1230
  thd->query = tbl_name;
1231 1232
  if ((error = mysqld_dump_create_info(thd, table, -1)))
  {
1233
    my_error(ER_GET_ERRNO, MYF(0), my_errno);
1234 1235
    goto err;
  }
unknown's avatar
unknown committed
1236
  net_flush(&thd->net);
1237
  if ((error= table->file->dump(thd,fd)))
1238
    my_error(ER_GET_ERRNO, MYF(0), error);
unknown's avatar
unknown committed
1239

unknown's avatar
unknown committed
1240 1241
err:
  close_thread_tables(thd);
unknown's avatar
unknown committed
1242
  DBUG_RETURN(error);
unknown's avatar
unknown committed
1243 1244 1245
}


1246
#ifndef EMBEDDED_LIBRARY
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257

/*
  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
1258 1259 1260
bool do_command(THD *thd)
{
  char *packet;
unknown's avatar
unknown committed
1261 1262
  uint old_timeout;
  ulong packet_length;
unknown's avatar
unknown committed
1263 1264 1265 1266 1267
  NET *net;
  enum enum_server_command command;
  DBUG_ENTER("do_command");

  net= &thd->net;
unknown's avatar
unknown committed
1268 1269 1270 1271
  /*
    indicator of uninitialized lex => normal flow of errors handling
    (see my_message_sql)
  */
1272
  thd->lex->current_select= 0;
unknown's avatar
unknown committed
1273 1274

  packet=0;
unknown's avatar
unknown committed
1275 1276 1277
  old_timeout=net->read_timeout;
  // Wait max for 8 hours
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
unknown's avatar
unknown committed
1278
  thd->clear_error();				// Clear error message
unknown's avatar
unknown committed
1279 1280 1281 1282

  net_new_transaction(net);
  if ((packet_length=my_net_read(net)) == packet_error)
  {
1283 1284 1285 1286 1287
    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)
1288 1289
    {
      statistic_increment(aborted_threads,&LOCK_status);
1290
      DBUG_RETURN(TRUE);			// We have to close it.
1291
    }
1292
    send_error(thd,net->last_errno,NullS);
1293
    net->error= 0;
1294
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
1295 1296 1297 1298 1299
  }
  else
  {
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
1300 1301
    if (command >= COM_END)
      command= COM_END;				// Wrong command
unknown's avatar
unknown committed
1302 1303 1304
    DBUG_PRINT("info",("Command on %s = %d (%s)",
		       vio_description(net->vio), command,
		       command_name[command]));
unknown's avatar
unknown committed
1305
  }
unknown's avatar
unknown committed
1306
  net->read_timeout=old_timeout;		// restore it
1307 1308 1309 1310 1311 1312 1313 1314 1315
  /*
    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
1316
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
1317
}
1318
#endif  /* EMBEDDED_LIBRARY */
1319

1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
/*
   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
*/
1335

1336 1337 1338 1339
bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
1340
  bool error= 0;
1341 1342 1343
  DBUG_ENTER("dispatch_command");

  thd->command=command;
unknown's avatar
unknown committed
1344
  /*
1345 1346
    Commands which always take a long time are logged into
    the slow log only if opt_log_slow_admin_statements is set.
unknown's avatar
unknown committed
1347
  */
1348
  thd->enable_slow_log= TRUE;
unknown's avatar
unknown committed
1349
  thd->set_time();
unknown's avatar
unknown committed
1350 1351 1352 1353 1354
  VOID(pthread_mutex_lock(&LOCK_thread_count));
  thd->query_id=query_id;
  if (command != COM_STATISTICS && command != COM_PING)
    query_id++;
  thread_running++;
1355
  /* TODO: set thd->lex->sql_command to SQLCOM_END here */
unknown's avatar
unknown committed
1356
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1357

1358 1359
  thd->server_status&=
           ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
1360
  switch (command) {
unknown's avatar
unknown committed
1361
  case COM_INIT_DB:
unknown's avatar
unknown committed
1362 1363 1364 1365 1366 1367 1368 1369 1370
  {
    LEX_STRING tmp;
    statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
    thd->convert_string(&tmp, system_charset_info,
			packet, strlen(packet), thd->charset());
    if (!mysql_change_db(thd, tmp.str))
      mysql_log.write(thd,command,"%s",thd->db);
    break;
  }
unknown's avatar
unknown committed
1371
#ifdef HAVE_REPLICATION
1372 1373
  case COM_REGISTER_SLAVE:
  {
1374
    if (!register_slave(thd, (uchar*)packet, packet_length))
1375
      send_ok(thd);
1376 1377
    break;
  }
1378
#endif
unknown's avatar
unknown committed
1379
  case COM_TABLE_DUMP:
1380 1381 1382 1383 1384 1385
  {
    char *db, *tbl_name;
    uint db_len= *(uchar*) packet;
    uint tbl_len= *(uchar*) (packet + db_len + 1);

    statistic_increment(com_other, &LOCK_status);
1386
    thd->enable_slow_log= opt_log_slow_admin_statements;
1387 1388 1389 1390 1391 1392 1393
    db= thd->alloc(db_len + tbl_len + 2);
    tbl_name= strmake(db, packet + 1, db_len)+1;
    strmake(tbl_name, packet + db_len + 2, tbl_len);
    if (mysql_table_dump(thd, db, tbl_name, -1))
      send_error(thd); // dump to NET
    break;
  }
unknown's avatar
unknown committed
1394 1395
  case COM_CHANGE_USER:
  {
unknown's avatar
unknown committed
1396
    thd->change_user();
1397
    thd->clear_error();                         // if errors from rollback
unknown's avatar
unknown committed
1398

1399 1400
    statistic_increment(com_other, &LOCK_status);
    char *user= (char*) packet;
unknown's avatar
unknown committed
1401
    char *passwd= strend(user)+1;
unknown's avatar
unknown committed
1402 1403 1404 1405 1406
    /* 
      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).
    */
1407
    char db_buff[NAME_LEN+1];                 // buffer to store db in utf8 
unknown's avatar
unknown committed
1408 1409 1410 1411
    char *db= passwd;
    uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? 
      *passwd++ : strlen(passwd);
    db+= passwd_len + 1;
1412
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1413
    /* Small check for incomming packet */
unknown's avatar
unknown committed
1414
    if ((uint) ((uchar*) db - net->read_pos) > packet_length)
1415 1416 1417 1418
    {
      send_error(thd, ER_UNKNOWN_COM_ERROR);
      break;
    }
1419
#endif
1420
    /* Convert database name to utf8 */
1421
    uint dummy_errors;
1422 1423
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
                             system_charset_info, db, strlen(db),
1424
                             thd->charset(), &dummy_errors)]= 0;
1425
    db= db_buff;
unknown's avatar
unknown committed
1426

1427 1428 1429 1430 1431 1432 1433
    /* 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
1434
    USER_CONN *save_user_connect= thd->user_connect;
unknown's avatar
unknown committed
1435 1436
    
    if (!(thd->user= my_strdup(user, MYF(0))))
1437 1438 1439 1440 1441
    {
      thd->user= save_user;
      send_error(thd, ER_OUT_OF_RESOURCES);
      break;
    }
unknown's avatar
unknown committed
1442

unknown's avatar
unknown committed
1443 1444
    /* Clear variables that are allocated */
    thd->user_connect= 0;
unknown's avatar
unknown committed
1445
    int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
unknown's avatar
unknown committed
1446

1447 1448 1449 1450 1451 1452 1453 1454
    if (res)
    {
      /* authentification failure, we shall restore old user */
      if (res > 0)
        send_error(thd, ER_UNKNOWN_COM_ERROR);
      x_free(thd->user);
      thd->user= save_user;
      thd->priv_user= save_priv_user;
unknown's avatar
unknown committed
1455
      thd->user_connect= save_user_connect;
1456 1457 1458 1459 1460 1461 1462 1463
      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
1464 1465
      if (save_user_connect)
	decrease_user_connections(save_user_connect);
1466 1467 1468
      x_free((gptr) save_db);
      x_free((gptr) save_user);
    }
unknown's avatar
unknown committed
1469 1470
    break;
  }
unknown's avatar
unknown committed
1471 1472
  case COM_EXECUTE:
  {
1473
    mysql_stmt_execute(thd, packet, packet_length);
unknown's avatar
unknown committed
1474 1475 1476 1477
    break;
  }
  case COM_LONG_DATA:
  {
1478
    mysql_stmt_get_longdata(thd, packet, packet_length);
unknown's avatar
unknown committed
1479 1480 1481 1482
    break;
  }
  case COM_PREPARE:
  {
1483
    mysql_stmt_prepare(thd, packet, packet_length);
unknown's avatar
unknown committed
1484 1485
    break;
  }
unknown's avatar
unknown committed
1486 1487 1488 1489 1490
  case COM_CLOSE_STMT:
  {
    mysql_stmt_free(thd, packet);
    break;
  }
1491 1492 1493 1494 1495
  case COM_RESET_STMT:
  {
    mysql_stmt_reset(thd, packet);
    break;
  }
unknown's avatar
unknown committed
1496 1497
  case COM_QUERY:
  {
1498 1499
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
1500
    char *packet_end= thd->query + thd->query_length;
1501
    mysql_log.write(thd,command,"%s",thd->query);
1502
    DBUG_PRINT("query",("%-.4096s",thd->query));
1503
    mysql_parse(thd,thd->query, thd->query_length);
1504

1505
    while (!thd->killed && !thd->is_fatal_error && thd->lex->found_colon)
1506
    {
1507
      char *packet= thd->lex->found_colon;
1508
      /*
1509
        Multiple queries exits, execute them individually
1510
	in embedded server - just store them to be executed later 
1511
      */
1512
#ifndef EMBEDDED_LIBRARY
1513
      if (thd->lock || thd->open_tables || thd->derived_tables)
1514
        close_thread_tables(thd);
1515
#endif
1516
      ulong length= (ulong)(packet_end-packet);
1517

1518
      log_slow_statement(thd);
1519

1520
      /* Remove garbage at start of query */
unknown's avatar
unknown committed
1521
      while (my_isspace(thd->charset(), *packet) && length > 0)
1522 1523 1524 1525
      {
        packet++;
        length--;
      }
unknown's avatar
unknown committed
1526
      VOID(pthread_mutex_lock(&LOCK_thread_count));
1527
      thd->query_length= length;
1528 1529
      thd->query= packet;
      thd->query_id= query_id++;
1530
      thd->set_time(); /* Reset the query start time. */
1531
      /* TODO: set thd->lex->sql_command to SQLCOM_END here */
1532
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
1533
#ifndef EMBEDDED_LIBRARY
1534
      mysql_parse(thd, packet, length);
1535
#else
unknown's avatar
unknown committed
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545
      /*
	'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
1546
	thd->query_rest.copy(packet, length, thd->query_rest.charset());
1547 1548 1549

      thd->server_status&= ~ (SERVER_QUERY_NO_INDEX_USED |
                              SERVER_QUERY_NO_GOOD_INDEX_USED);
1550 1551
      break;
#endif /*EMBEDDED_LIBRARY*/
1552 1553
    }

unknown's avatar
unknown committed
1554 1555 1556 1557 1558
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1559
  case COM_FIELD_LIST:				// This isn't actually needed
unknown's avatar
unknown committed
1560
#ifdef DONT_ALLOW_SHOW_COMMANDS
1561
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
1562 1563 1564
    break;
#else
  {
1565
    char *fields, *pend;
unknown's avatar
unknown committed
1566
    TABLE_LIST table_list;
unknown's avatar
unknown committed
1567 1568
    LEX_STRING conv_name;

unknown's avatar
unknown committed
1569
    statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
unknown's avatar
unknown committed
1570 1571 1572
    bzero((char*) &table_list,sizeof(table_list));
    if (!(table_list.db=thd->db))
    {
1573
      send_error(thd,ER_NO_DB_ERROR);
unknown's avatar
unknown committed
1574 1575 1576
      break;
    }
    thd->free_list=0;
1577
    pend= strend(packet);
unknown's avatar
unknown committed
1578 1579 1580
    thd->convert_string(&conv_name, system_charset_info,
			packet, (uint) (pend-packet), thd->charset());
    table_list.alias= table_list.real_name= conv_name.str;
1581
    packet= pend+1;
1582
    thd->query_length= strlen(packet);       // for simplicity: don't optimize
unknown's avatar
unknown committed
1583 1584
    if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
      break;
1585
    mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
1586
    if (lower_case_table_names)
unknown's avatar
unknown committed
1587
      my_casedn_str(files_charset_info, table_list.real_name);
unknown's avatar
unknown committed
1588 1589
    remove_escape(table_list.real_name);	// This can't have wildcards

unknown's avatar
unknown committed
1590 1591
    if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
		     0, 0))
unknown's avatar
unknown committed
1592
      break;
unknown's avatar
unknown committed
1593 1594
    if (grant_option &&
	check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
1595 1596
      break;
    mysqld_list_fields(thd,&table_list,fields);
1597
    free_items(thd->free_list);
1598
    thd->free_list= 0;
unknown's avatar
unknown committed
1599 1600 1601 1602
    break;
  }
#endif
  case COM_QUIT:
1603
    /* We don't calculate statistics for this command */
1604
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1605 1606 1607 1608
    net->error=0;				// Don't give 'abort' message
    error=TRUE;					// End server
    break;

unknown's avatar
unknown committed
1609
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1610
    {
unknown's avatar
unknown committed
1611
      char *db=thd->strdup(packet), *alias;
1612
      HA_CREATE_INFO create_info;
unknown's avatar
unknown committed
1613

unknown's avatar
unknown committed
1614
      statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
1615
      // null test to handle EOM
unknown's avatar
unknown committed
1616
      if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
1617
      {
1618
	net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
1619 1620
	break;
      }
unknown's avatar
unknown committed
1621
      if (check_access(thd,CREATE_ACL,db,0,1,0))
unknown's avatar
unknown committed
1622
	break;
1623
      mysql_log.write(thd,command,packet);
1624
      bzero(&create_info, sizeof(create_info));
1625
      if (mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
1626
                          &create_info, 0) < 0)
unknown's avatar
unknown committed
1627
        send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0);
unknown's avatar
unknown committed
1628 1629
      break;
    }
unknown's avatar
unknown committed
1630
  case COM_DROP_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1631
    {
unknown's avatar
unknown committed
1632
      statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
unknown's avatar
unknown committed
1633
      char *db=thd->strdup(packet), *alias;
1634
      // null test to handle EOM
unknown's avatar
unknown committed
1635
      if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
1636
      {
1637
	net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
1638 1639
	break;
      }
unknown's avatar
unknown committed
1640
      if (check_access(thd,DROP_ACL,db,0,1,0))
1641
	break;
unknown's avatar
unknown committed
1642 1643
      if (thd->locked_tables || thd->active_transaction())
      {
1644
	send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
1645
	break;
unknown's avatar
unknown committed
1646
      }
1647
      mysql_log.write(thd,command,db);
1648 1649
      if (mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : db),
                      0, 0) < 0)
unknown's avatar
unknown committed
1650
        send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0);
unknown's avatar
unknown committed
1651 1652
      break;
    }
1653
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1654 1655
  case COM_BINLOG_DUMP:
    {
unknown's avatar
unknown committed
1656 1657 1658 1659
      ulong pos;
      ushort flags;
      uint32 slave_server_id;

unknown's avatar
unknown committed
1660
      statistic_increment(com_other,&LOCK_status);
1661
      thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
unknown committed
1662
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1663
	break;
unknown's avatar
unknown committed
1664

1665
      /* TODO: The following has to be changed to an 8 byte integer */
1666 1667
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
1668
      thd->server_id=0; /* avoid suicide */
unknown's avatar
unknown committed
1669
      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
unknown's avatar
unknown committed
1670
	kill_zombie_dump_threads(slave_server_id);
1671
      thd->server_id = slave_server_id;
unknown's avatar
unknown committed
1672 1673 1674

      mysql_log.write(thd, command, "Log: '%s'  Pos: %ld", packet+10,
                      (long) pos);
1675
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1676
      unregister_slave(thd,1,1);
1677 1678 1679
      // fake COM_QUIT -- if we get here, the thread needs to terminate
      error = TRUE;
      net->error = 0;
unknown's avatar
unknown committed
1680 1681
      break;
    }
1682
#endif
unknown's avatar
unknown committed
1683 1684
  case COM_REFRESH:
    {
unknown's avatar
unknown committed
1685
      statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
unknown's avatar
unknown committed
1686
      ulong options= (ulong) (uchar) packet[0];
unknown's avatar
unknown committed
1687
      if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1688
	break;
1689
      mysql_log.write(thd,command,NullS);
1690 1691 1692 1693
      if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, NULL))
        send_error(thd, 0);
      else
        send_ok(thd);
unknown's avatar
unknown committed
1694 1695
      break;
    }
1696
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1697
  case COM_SHUTDOWN:
1698
  {
unknown's avatar
unknown committed
1699
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1700
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1701
      break; /* purecov: inspected */
1702
    /*
1703 1704 1705 1706
      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].
1707
    */
1708 1709
    enum mysql_enum_shutdown_level level=
      (enum mysql_enum_shutdown_level) (uchar) packet[0];
1710
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
1711 1712 1713 1714 1715 1716 1717 1718
    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");
      send_error(thd);
      break;
    }
1719
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
1720
    mysql_log.write(thd,command,NullS);
1721
    send_eof(thd);
unknown's avatar
unknown committed
1722 1723 1724
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
unknown's avatar
unknown committed
1725
#ifndef OS2
1726
    send_eof(thd);				// This is for 'quit request'
unknown's avatar
unknown committed
1727
#endif
1728
    close_connection(thd, 0, 1);
unknown's avatar
unknown committed
1729
    close_thread_tables(thd);			// Free before kill
unknown's avatar
unknown committed
1730
    free_root(thd->mem_root,MYF(0));
1731
    free_root(&thd->transaction.mem_root,MYF(0));
unknown's avatar
unknown committed
1732 1733 1734
    kill_mysql();
    error=TRUE;
    break;
1735
  }
1736
#endif
unknown's avatar
unknown committed
1737 1738
  case COM_STATISTICS:
  {
1739
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1740
    statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
unknown's avatar
unknown committed
1741
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1742
    char buff[200];
unknown's avatar
unknown committed
1743 1744 1745
#else
    char *buff= thd->net.last_error;
#endif
1746
    ulong uptime = (ulong) (thd->start_time - start_time);
unknown's avatar
unknown committed
1747
    sprintf((char*) buff,
1748
	    "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
1749 1750 1751 1752 1753
	    uptime,
	    (int) thread_count,thd->query_id,long_query_count,
	    opened_tables,refresh_version, cached_tables(),
	    uptime ? (float)thd->query_id/(float)uptime : 0);
#ifdef SAFEMALLOC
1754
    if (sf_malloc_cur_memory)				// Using SAFEMALLOC
unknown's avatar
unknown committed
1755
      sprintf(strend(buff), "  Memory in use: %ldK  Max memory used: %ldK",
1756 1757
	      (sf_malloc_cur_memory+1023L)/1024L,
	      (sf_malloc_max_memory+1023L)/1024L);
unknown's avatar
unknown committed
1758 1759
#endif
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1760
    VOID(my_net_write(net, buff,(uint) strlen(buff)));
unknown's avatar
unknown committed
1761
    VOID(net_flush(net));
unknown's avatar
unknown committed
1762
#endif
unknown's avatar
unknown committed
1763 1764 1765
    break;
  }
  case COM_PING:
unknown's avatar
unknown committed
1766
    statistic_increment(com_other,&LOCK_status);
1767
    send_ok(thd);				// Tell client we are alive
unknown's avatar
unknown committed
1768 1769
    break;
  case COM_PROCESS_INFO:
unknown's avatar
unknown committed
1770
    statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
unknown's avatar
unknown committed
1771
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
1772
      break;
1773
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1774 1775
    mysqld_list_processes(thd,
			  thd->master_access & PROCESS_ACL ? 
unknown's avatar
unknown committed
1776
			  NullS : thd->priv_user, 0);
unknown's avatar
unknown committed
1777 1778 1779
    break;
  case COM_PROCESS_KILL:
  {
unknown's avatar
unknown committed
1780
    statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
1781
    ulong id=(ulong) uint4korr(packet);
unknown's avatar
unknown committed
1782 1783 1784
    kill_one_thread(thd,id);
    break;
  }
1785 1786 1787 1788 1789 1790 1791
  case COM_SET_OPTION:
  {
    statistic_increment(com_stat[SQLCOM_SET_OPTION], &LOCK_status);
    enum_mysql_set_option command= (enum_mysql_set_option) uint2korr(packet);
    switch (command) {
    case MYSQL_OPTION_MULTI_STATEMENTS_ON:
      thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
unknown's avatar
unknown committed
1792
      send_eof(thd);
1793 1794 1795
      break;
    case MYSQL_OPTION_MULTI_STATEMENTS_OFF:
      thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
unknown's avatar
unknown committed
1796
      send_eof(thd);
1797 1798 1799 1800 1801 1802 1803
      break;
    default:
      send_error(thd, ER_UNKNOWN_COM_ERROR);
      break;
    }
    break;
  }
unknown's avatar
unknown committed
1804
  case COM_DEBUG:
unknown's avatar
unknown committed
1805
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1806
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1807 1808
      break;					/* purecov: inspected */
    mysql_print_status(thd);
1809
    mysql_log.write(thd,command,NullS);
1810
    send_eof(thd);
unknown's avatar
unknown committed
1811 1812 1813 1814 1815
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
1816
  case COM_END:
unknown's avatar
unknown committed
1817
  default:
1818
    send_error(thd, ER_UNKNOWN_COM_ERROR);
unknown's avatar
unknown committed
1819 1820
    break;
  }
1821
  if (thd->lock || thd->open_tables || thd->derived_tables)
unknown's avatar
unknown committed
1822 1823 1824 1825 1826
  {
    thd->proc_info="closing tables";
    close_thread_tables(thd);			/* Free tables */
  }

1827
  if (thd->is_fatal_error)
1828
    send_error(thd,0);				// End of memory ?
unknown's avatar
unknown committed
1829

1830
  log_slow_statement(thd);
1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845

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


1846
void log_slow_statement(THD *thd)
1847
{
unknown's avatar
unknown committed
1848
  time_t start_of_query=thd->start_time;
1849
  thd->end_time();				// Set start time
1850

1851 1852 1853 1854 1855
  /*
    Do not log administrative statements unless the appropriate option is
    set; do not log into slow log if reading from backup.
  */
  if (thd->enable_slow_log && !thd->user_time)
unknown's avatar
unknown committed
1856
  {
1857 1858
    thd->proc_info="logging slow query";

1859 1860
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
1861 1862
	((thd->server_status &
	  (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
1863
	 (specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES)))
1864 1865 1866 1867
    {
      long_query_count++;
      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
    }
unknown's avatar
unknown committed
1868 1869 1870
  }
}

1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888

/*
  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
    0	ok
    1	error;  In this case thd->fatal_error is set
*/

bool alloc_query(THD *thd, char *packet, ulong packet_length)
{
  packet_length--;				// Remove end null
1889
  /* Remove garbage at start and end of query */
unknown's avatar
unknown committed
1890
  while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
1891 1892 1893 1894 1895
  {
    packet++;
    packet_length--;
  }
  char *pos=packet+packet_length;		// Point at end null
unknown's avatar
unknown committed
1896
  while (packet_length > 0 &&
unknown's avatar
unknown committed
1897
	 (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
1898 1899 1900 1901 1902
  {
    pos--;
    packet_length--;
  }
  /* We must allocate some extra memory for query cache */
unknown's avatar
unknown committed
1903
  thd->query_length= 0;                        // Extra safety: Avoid races
1904 1905
  if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
					      packet_length,
1906 1907
					      thd->db_length+ 1 +
					      QUERY_CACHE_FLAGS_SIZE)))
1908 1909 1910
    return 1;
  thd->query[packet_length]=0;
  thd->query_length= packet_length;
1911 1912 1913 1914

  /* Reclaim some memory */
  thd->packet.shrink(thd->variables.net_buffer_length);
  thd->convert_buffer.shrink(thd->variables.net_buffer_length);
1915 1916 1917 1918 1919 1920

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

1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937
static void reset_one_shot_variables(THD *thd) 
{
  thd->variables.character_set_client=
    global_system_variables.character_set_client;
  thd->variables.collation_connection=
    global_system_variables.collation_connection;
  thd->variables.collation_database=
    global_system_variables.collation_database;
  thd->variables.collation_server=
    global_system_variables.collation_server;
  thd->update_charset();
  thd->variables.time_zone=
    global_system_variables.time_zone;
  thd->one_shot_set= 0;
}


unknown's avatar
unknown committed
1938 1939 1940 1941 1942 1943
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/

void
1944
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
1945
{
1946
  int	res= 0;
1947
  LEX	*lex= thd->lex;
unknown's avatar
unknown committed
1948 1949
  bool slave_fake_lock= 0;
  MYSQL_LOCK *fake_prev_lock= 0;
unknown's avatar
unknown committed
1950
  SELECT_LEX *select_lex= &lex->select_lex;
1951
  TABLE_LIST *tables= (TABLE_LIST*) select_lex->table_list.first;
1952
  SELECT_LEX_UNIT *unit= &lex->unit;
unknown's avatar
unknown committed
1953 1954
  DBUG_ENTER("mysql_execute_command");

1955 1956 1957 1958 1959 1960
  /*
    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.
  */
1961 1962
  if (tables || &lex->select_lex != lex->all_selects_list ||
      lex->time_zone_tables_used)
1963 1964
    mysql_reset_errors(thd);

unknown's avatar
unknown committed
1965 1966 1967 1968
  /*
    When subselects or time_zone info is used in a query
    we create a new TABLE_LIST containing all referenced tables
    and set local variable 'tables' to point to this list.
1969
  */
1970 1971 1972 1973 1974
  if ((&lex->select_lex != lex->all_selects_list ||
       lex->time_zone_tables_used) &&
      lex->unit.create_total_list(thd, lex, &tables))
    DBUG_VOID_RETURN;

unknown's avatar
SCRUM  
unknown committed
1975
#ifdef HAVE_REPLICATION
1976 1977
  if (thd->slave_thread)
  {
unknown's avatar
unknown committed
1978
    if (lex->sql_command == SQLCOM_UPDATE_MULTI)
unknown's avatar
unknown committed
1979 1980 1981
    {
      DBUG_PRINT("info",("need faked locked tables"));
      
unknown's avatar
unknown committed
1982 1983
      if (check_multi_update_lock(thd, tables, &select_lex->item_list,
				  select_lex))
unknown's avatar
unknown committed
1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994
        goto error;

      /* Fix for replication, the tables are opened and locked,
         now we pretend that we have performed a LOCK TABLES action */
	 
      fake_prev_lock= thd->locked_tables;
      if (thd->lock)
        thd->locked_tables= thd->lock;
      thd->lock= 0;
      slave_fake_lock= 1;
    }
unknown's avatar
unknown committed
1995
    /*
unknown's avatar
merge  
unknown committed
1996
      Skip if we are in the slave thread, some table rules have been
1997
      given and the table list says the query should not be replicated.
1998 1999 2000

      Exceptions are:
      - SET: we always execute it (Not that many SET commands exists in
unknown's avatar
unknown committed
2001 2002
        the binary log anyway -- only 4.1 masters write SET statements,
	in 5.0 there are no SET statements in the binary log)
2003 2004
      - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we
        have stale files on slave caused by exclusion of one tmp table).
unknown's avatar
merge  
unknown committed
2005
    */
2006 2007
    if (!(lex->sql_command == SQLCOM_SET_OPTION) &&
	!(lex->sql_command == SQLCOM_DROP_TABLE &&
2008 2009
          lex->drop_temporary && lex->drop_if_exists) &&
        all_tables_not_ok(thd,tables))
unknown's avatar
unknown committed
2010 2011 2012
    {
      /* we warn the slave SQL thread */
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
2013
      reset_one_shot_variables(thd);
2014
      DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2015
    }
unknown's avatar
merge  
unknown committed
2016 2017
#ifndef TO_BE_DELETED
    /*
2018 2019 2020
      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
2021
    */
2022 2023 2024
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
unknown's avatar
unknown committed
2025
      lex->insert_list = &select_lex->item_list;
2026
    }
unknown's avatar
merge  
unknown committed
2027
#endif
2028
  }
unknown's avatar
unknown committed
2029
#endif /* !HAVE_REPLICATION */
unknown's avatar
unknown committed
2030

2031 2032 2033 2034 2035
  /*
    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
2036
      !(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
2037 2038
      (uc_update_queries[lex->sql_command] > 0))
  {
unknown's avatar
unknown committed
2039
    net_printf(thd, ER_OPTION_PREVENTS_STATEMENT, "--read-only");
2040 2041
    DBUG_VOID_RETURN;
  }
2042

unknown's avatar
unknown committed
2043
  statistic_increment(com_stat[lex->sql_command],&LOCK_status);
unknown's avatar
unknown committed
2044 2045 2046
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
2047 2048 2049 2050 2051 2052 2053
    /* 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;
    }

2054
    select_result *result=lex->result;
unknown's avatar
unknown committed
2055 2056 2057 2058 2059
    if (tables)
    {
      res=check_table_access(thd,
			     lex->exchange ? SELECT_ACL | FILE_ACL :
			     SELECT_ACL,
unknown's avatar
unknown committed
2060
			     tables,0);
unknown's avatar
unknown committed
2061 2062 2063
    }
    else
      res=check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
unknown's avatar
unknown committed
2064
		       any_db,0,0,0);
unknown's avatar
unknown committed
2065 2066 2067 2068 2069
    if (res)
    {
      res=0;
      break;					// Error message is given
    }
2070 2071 2072 2073
    /* 
       In case of single SELECT unit->global_parameters points on first SELECT
       TODO: move counters to SELECT_LEX
    */
2074 2075 2076
    unit->offset_limit_cnt= (ha_rows) unit->global_parameters->offset_limit;
    unit->select_limit_cnt= (ha_rows) (unit->global_parameters->select_limit+
      unit->global_parameters->offset_limit);
unknown's avatar
unknown committed
2077
    if (unit->select_limit_cnt <
2078
	(ha_rows) unit->global_parameters->select_limit)
2079
      unit->select_limit_cnt= HA_POS_ERROR;		// no limit
2080
    if (unit->select_limit_cnt == HA_POS_ERROR && !select_lex->next_select())
2081
      select_lex->options&= ~OPTION_FOUND_ROWS;
unknown's avatar
unknown committed
2082 2083

    if (!(res=open_and_lock_tables(thd,tables)))
unknown's avatar
unknown committed
2084
    {
unknown's avatar
unknown committed
2085
      if (lex->describe)
unknown's avatar
unknown committed
2086
      {
2087 2088 2089 2090 2091 2092 2093
	if (!(result= new select_send()))
	{
	  send_error(thd, ER_OUT_OF_RESOURCES);
	  DBUG_VOID_RETURN;
	}
	else
	  thd->send_explain_fields(result);
2094
	res= mysql_explain_union(thd, &thd->lex->unit, result);
unknown's avatar
unknown committed
2095 2096 2097 2098 2099
	if (lex->describe & DESCRIBE_EXTENDED)
	{
	  char buff[1024];
	  String str(buff,(uint32) sizeof(buff), system_charset_info);
	  str.length(0);
2100
	  thd->lex->unit.print(&str);
unknown's avatar
unknown committed
2101 2102 2103 2104
	  str.append('\0');
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
		       ER_YES, str.ptr());
	}
2105
	result->send_eof();
2106
        delete result;
unknown's avatar
unknown committed
2107 2108 2109
      }
      else
      {
2110
	if (!result && !(result= new select_send()))
unknown's avatar
unknown committed
2111
	{
2112 2113
	  res= -1;
	  break;
unknown's avatar
unknown committed
2114
	}
unknown's avatar
unknown committed
2115
	query_cache_store_query(thd, tables);
2116 2117 2118
	res= handle_select(thd, lex, result);
        if (result != lex->result)
          delete result;
unknown's avatar
unknown committed
2119
      }
unknown's avatar
unknown committed
2120
    }
unknown's avatar
unknown committed
2121 2122
    break;
  }
unknown's avatar
unknown committed
2123
  case SQLCOM_PREPARE:
2124
  {
2125 2126 2127 2128
    char *query_str;
    uint query_len;
    if (lex->prepared_stmt_code_is_varref)
    {
2129
      /* This is PREPARE stmt FROM @var. */
2130 2131 2132 2133
      String str;
      CHARSET_INFO *to_cs= thd->variables.collation_connection;
      bool need_conversion;
      user_var_entry *entry;
2134
      String *pstr= &str;
2135
      uint32 unused;
2136
      /*
2137 2138 2139
        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.
2140
      */
2141 2142
      if ((entry=
             (user_var_entry*)hash_search(&thd->user_vars,
2143 2144 2145 2146
                                          (byte*)lex->prepared_stmt_code.str,
                                          lex->prepared_stmt_code.length))
          && entry->value)
      {
2147 2148
        my_bool is_var_null;
        pstr= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC);
2149 2150 2151 2152
        /*
          NULL value of variable checked early as entry->value so here
          we can't get NULL in normal conditions
        */
2153 2154
        DBUG_ASSERT(!is_var_null);
        if (!pstr)
2155 2156 2157 2158
        {
          res= -1;
          break;      // EOM (error should be reported by allocator)
        }
2159 2160
      }
      else
2161 2162 2163 2164 2165
      {
        /*
          variable absent or equal to NULL, so we need to set variable to
          something reasonable to get readable error message during parsing
        */
2166
        str.set("NULL", 4, &my_charset_latin1);
2167 2168
      }

2169
      need_conversion=
2170 2171
        String::needs_conversion(pstr->length(), pstr->charset(),
                                 to_cs, &unused);
2172

2173 2174
      query_len= need_conversion? (pstr->length() * to_cs->mbmaxlen) :
                                  pstr->length();
unknown's avatar
unknown committed
2175
      if (!(query_str= alloc_root(thd->mem_root, query_len+1)))
2176 2177 2178 2179
      {
        res= -1;
        break;        // EOM (error should be reported by allocator)
      }
2180

2181
      if (need_conversion)
2182 2183 2184 2185 2186 2187
      {
        uint dummy_errors;
        query_len= copy_and_convert(query_str, query_len, to_cs,
                                    pstr->ptr(), pstr->length(),
                                    pstr->charset(), &dummy_errors);
      }
2188
      else
2189
        memcpy(query_str, pstr->ptr(), pstr->length());
2190
      query_str[query_len]= 0;
2191 2192 2193
    }
    else
    {
2194 2195
      query_str= lex->prepared_stmt_code.str;
      query_len= lex->prepared_stmt_code.length;
2196
      DBUG_PRINT("info", ("PREPARE: %.*s FROM '%.*s' \n",
2197 2198
                          lex->prepared_stmt_name.length,
                          lex->prepared_stmt_name.str,
2199
                          query_len, query_str));
2200
    }
unknown's avatar
unknown committed
2201
    thd->command= COM_PREPARE;
2202 2203
    if (!mysql_stmt_prepare(thd, query_str, query_len + 1,
                            &lex->prepared_stmt_name))
unknown's avatar
unknown committed
2204 2205 2206 2207 2208
      send_ok(thd, 0L, 0L, "Statement prepared");
    break;
  }
  case SQLCOM_EXECUTE:
  {
2209
    DBUG_PRINT("info", ("EXECUTE: %.*s\n",
2210 2211 2212
                        lex->prepared_stmt_name.length,
                        lex->prepared_stmt_name.str));
    mysql_sql_stmt_execute(thd, &lex->prepared_stmt_name);
unknown's avatar
unknown committed
2213 2214 2215 2216 2217
    lex->prepared_stmt_params.empty();
    break;
  }
  case SQLCOM_DEALLOCATE_PREPARE:
  {
2218 2219 2220 2221
    Statement* stmt;
    DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", 
                        lex->prepared_stmt_name.length,
                        lex->prepared_stmt_name.str));
2222 2223
    /* We account deallocate in the same manner as mysql_stmt_close */
    statistic_increment(com_stmt_close, &LOCK_status);
2224
    if ((stmt= thd->stmt_map.find_by_name(&lex->prepared_stmt_name)))
unknown's avatar
unknown committed
2225
    {
2226 2227
      thd->stmt_map.erase(stmt);
      send_ok(thd);
unknown's avatar
unknown committed
2228
    }
2229
    else
2230 2231 2232 2233 2234 2235
    {
      res= -1;
      my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0),
               lex->prepared_stmt_name.length, lex->prepared_stmt_name.str,
               "DEALLOCATE PREPARE");
    }
unknown's avatar
unknown committed
2236 2237
    break;
  }
unknown's avatar
unknown committed
2238
  case SQLCOM_DO:
unknown's avatar
unknown committed
2239
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
unknown's avatar
unknown committed
2240 2241 2242 2243 2244 2245
		   (res= open_and_lock_tables(thd,tables))))
	break;

    res= mysql_do(thd, *lex->insert_list);
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2246 2247
    break;

2248
  case SQLCOM_EMPTY_QUERY:
2249
    send_ok(thd);
2250 2251
    break;

unknown's avatar
unknown committed
2252 2253 2254 2255
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

2256
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2257
  case SQLCOM_PURGE:
2258
  {
unknown's avatar
unknown committed
2259
    if (check_global_access(thd, SUPER_ACL))
2260
      goto error;
2261
    // PURGE MASTER LOGS TO 'file'
2262 2263 2264
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
2265 2266 2267 2268 2269 2270 2271 2272
  case SQLCOM_PURGE_BEFORE:
  {
    if (check_global_access(thd, SUPER_ACL))
      goto error;
    // PURGE MASTER LOGS BEFORE 'data'
    res = purge_master_logs_before_date(thd, lex->purge_time);
    break;
  }
2273
#endif
unknown's avatar
unknown committed
2274 2275
  case SQLCOM_SHOW_WARNS:
  {
2276 2277
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
2278 2279 2280
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
unknown's avatar
unknown committed
2281 2282 2283 2284
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
2285 2286
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
2287 2288
    break;
  }
unknown's avatar
unknown committed
2289 2290
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
2291
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2292
      goto error;
2293
    /* This query don't work now. See comment in repl_failsafe.cc */
unknown's avatar
unknown committed
2294
#ifndef WORKING_NEW_MASTER
2295
    net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
unknown's avatar
unknown committed
2296 2297
    res= 1;
#else
unknown's avatar
unknown committed
2298
    res = show_new_master(thd);
unknown's avatar
unknown committed
2299
#endif
unknown's avatar
unknown committed
2300 2301
    break;
  }
2302

unknown's avatar
unknown committed
2303
#ifdef HAVE_REPLICATION
2304 2305
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
2306
    if (check_global_access(thd, REPL_SLAVE_ACL))
2307 2308 2309 2310
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
2311 2312
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
2313
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2314 2315 2316 2317
      goto error;
    res = show_binlog_events(thd);
    break;
  }
2318 2319
#endif

unknown's avatar
unknown committed
2320
  case SQLCOM_BACKUP_TABLE:
2321 2322
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
2323
	check_table_access(thd,SELECT_ACL, tables,0) ||
unknown's avatar
unknown committed
2324
	check_global_access(thd, FILE_ACL))
2325
      goto error; /* purecov: inspected */
2326
    thd->enable_slow_log= opt_log_slow_admin_statements;
2327
    res = mysql_backup_table(thd, tables);
unknown's avatar
unknown committed
2328

2329 2330
    break;
  }
unknown's avatar
unknown committed
2331
  case SQLCOM_RESTORE_TABLE:
2332 2333
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
2334
	check_table_access(thd, INSERT_ACL, tables,0) ||
unknown's avatar
unknown committed
2335
	check_global_access(thd, FILE_ACL))
2336
      goto error; /* purecov: inspected */
2337
    thd->enable_slow_log= opt_log_slow_admin_statements;
2338 2339 2340
    res = mysql_restore_table(thd, tables);
    break;
  }
unknown's avatar
unknown committed
2341 2342 2343
  case SQLCOM_ASSIGN_TO_KEYCACHE:
  {
    if (check_db_used(thd, tables) ||
unknown's avatar
unknown committed
2344 2345
        check_access(thd, INDEX_ACL, tables->db,
                     &tables->grant.privilege, 0, 0))
unknown's avatar
unknown committed
2346
      goto error;
2347
    res= mysql_assign_to_keycache(thd, tables, &lex->name_and_length);
unknown's avatar
unknown committed
2348 2349
    break;
  }
unknown's avatar
unknown committed
2350 2351 2352
  case SQLCOM_PRELOAD_KEYS:
  {
    if (check_db_used(thd, tables) ||
unknown's avatar
unknown committed
2353 2354
	check_access(thd, INDEX_ACL, tables->db,
                     &tables->grant.privilege, 0, 0))
2355
      goto error;
unknown's avatar
unknown committed
2356 2357 2358
    res = mysql_preload_keys(thd, tables);
    break;
  }
unknown's avatar
unknown committed
2359
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2360
  case SQLCOM_CHANGE_MASTER:
2361
  {
unknown's avatar
unknown committed
2362
    if (check_global_access(thd, SUPER_ACL))
2363
      goto error;
2364
    pthread_mutex_lock(&LOCK_active_mi);
2365
    res = change_master(thd,active_mi);
2366
    pthread_mutex_unlock(&LOCK_active_mi);
2367 2368
    break;
  }
unknown's avatar
unknown committed
2369
  case SQLCOM_SHOW_SLAVE_STAT:
2370
  {
2371 2372
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2373
      goto error;
2374
    pthread_mutex_lock(&LOCK_active_mi);
2375
    res = show_master_info(thd,active_mi);
2376
    pthread_mutex_unlock(&LOCK_active_mi);
2377 2378
    break;
  }
unknown's avatar
unknown committed
2379
  case SQLCOM_SHOW_MASTER_STAT:
2380
  {
2381 2382
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2383 2384 2385 2386
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
2387

2388
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
2389
    if (check_global_access(thd, SUPER_ACL))
2390
      goto error;
2391 2392 2393 2394
    if (end_active_trans(thd))
      res= -1;
    else
      res = load_master_data(thd);
2395
    break;
unknown's avatar
unknown committed
2396
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
2397 2398 2399
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
2400
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2401 2402 2403 2404 2405
	goto error;
      res = innodb_show_status(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
2406
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2407
  case SQLCOM_LOAD_MASTER_TABLE:
2408
  {
unknown's avatar
unknown committed
2409 2410
    if (!tables->db)
      tables->db=thd->db;
unknown's avatar
unknown committed
2411
    if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege,0,0))
unknown's avatar
unknown committed
2412 2413 2414 2415
      goto error;				/* purecov: inspected */
    if (grant_option)
    {
      /* Check that the first table has CREATE privilege */
unknown's avatar
unknown committed
2416
      if (check_grant(thd, CREATE_ACL, tables, 0, 1, 0))
2417
	goto error;
unknown's avatar
unknown committed
2418
    }
2419
    if (strlen(tables->real_name) > NAME_LEN)
unknown's avatar
unknown committed
2420
    {
2421
      net_printf(thd,ER_WRONG_TABLE_NAME, tables->real_name);
unknown's avatar
unknown committed
2422 2423
      break;
    }
2424
    pthread_mutex_lock(&LOCK_active_mi);
2425 2426 2427 2428
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
2429
    if (!fetch_master_table(thd, tables->db, tables->real_name,
2430
			    active_mi, 0, 0))
2431
    {
2432
      send_ok(thd);
2433
    }
2434
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2435
    break;
2436
  }
unknown's avatar
unknown committed
2437
#endif /* HAVE_REPLICATION */
2438

unknown's avatar
unknown committed
2439
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
2440
  {
2441
    /* If CREATE TABLE of non-temporary table, do implicit commit */
2442 2443 2444 2445 2446 2447 2448 2449 2450 2451
    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
    {
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
    else 
    {
unknown's avatar
unknown committed
2452 2453
      /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
      thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
2454
    }
unknown's avatar
unknown committed
2455
    /* Skip first table, which is the table we are creating */
2456 2457 2458
    TABLE_LIST *create_table, *create_table_local;
    tables= lex->unlink_first_table(tables, &create_table,
				    &create_table_local);
unknown's avatar
unknown committed
2459

unknown's avatar
unknown committed
2460 2461 2462
    if ((res= create_table_precheck(thd, tables, create_table)))
      goto unsent_create_error;

2463 2464 2465
#ifndef HAVE_READLINK
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
2466
    /* Fix names if symlinked tables */
unknown's avatar
unknown committed
2467
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
unknown's avatar
unknown committed
2468
			   create_table->real_name) ||
unknown's avatar
unknown committed
2469
	append_file_to_dir(thd,&lex->create_info.index_file_name,
unknown's avatar
unknown committed
2470
			   create_table->real_name))
2471 2472
    {
      res=-1;
2473
      goto unsent_create_error;
2474
    }
2475
#endif
2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488
    /*
      If we are using SET CHARSET without DEFAULT, add an implicite
      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;
    }
2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504
    /*
      The create-select command will open and read-lock the select table
      and then create, open and write-lock the new table. If a global
      read lock steps in, we get a deadlock. The write lock waits for
      the global read lock, while the global read lock waits for the
      select table to be closed. So we wait until the global readlock is
      gone before starting both steps. Note that
      wait_if_global_read_lock() sets a protection against a new global
      read lock when it succeeds. This needs to be released by
      start_waiting_global_read_lock(). We protect the normal CREATE
      TABLE in the same way. That way we avoid that a new table is
      created during a gobal read lock.
    */
    if (wait_if_global_read_lock(thd, 0, 1))
    {
      res= -1;
2505
      goto unsent_create_error;
2506
    }
2507
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
2508 2509 2510
    {
      select_result *result;

2511
      select_lex->options|= SELECT_NO_UNLOCK;
2512 2513 2514 2515
      unit->offset_limit_cnt= select_lex->offset_limit;
      unit->select_limit_cnt= select_lex->select_limit+
	select_lex->offset_limit;
      if (unit->select_limit_cnt < select_lex->select_limit)
unknown's avatar
unknown committed
2516
	unit->select_limit_cnt= HA_POS_ERROR;	// No limit
2517

unknown's avatar
unknown committed
2518
      if (!(res=open_and_lock_tables(thd,tables)))
2519
      {
unknown's avatar
unknown committed
2520 2521 2522 2523
	res= -1;				// If error
        if ((result=new select_create(create_table->db,
                                      create_table->real_name,
				      &lex->create_info,
2524 2525
                                      lex->create_list,
                                      lex->key_list,
2526 2527
                                      select_lex->item_list, lex->duplicates,
                                      lex->ignore)))
2528 2529 2530 2531 2532 2533
        {
          /*
            CREATE from SELECT give its SELECT_LEX for SELECT,
            and item_list belong to SELECT
          */
          select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
2534
          res=handle_select(thd, lex, result);
2535 2536
          select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE;
        }
2537 2538 2539
	//reset for PS
	lex->create_list.empty();
	lex->key_list.empty();
2540 2541
      }
    }
unknown's avatar
unknown committed
2542 2543
    else // regular create
    {
unknown's avatar
unknown committed
2544
      if (lex->name)
unknown's avatar
unknown committed
2545
        res= mysql_create_like_table(thd, create_table, &lex->create_info, 
unknown's avatar
unknown committed
2546 2547
                                     (Table_ident *)lex->name); 
      else
2548
      {
unknown's avatar
unknown committed
2549 2550
        res= mysql_create_table(thd,create_table->db,
			         create_table->real_name, &lex->create_info,
unknown's avatar
unknown committed
2551
			         lex->create_list,
2552
			         lex->key_list,0,0);
2553
      }
unknown's avatar
unknown committed
2554
      if (!res)
2555
	send_ok(thd);
unknown's avatar
unknown committed
2556
    }
2557 2558 2559 2560 2561
    /*
      Release the protection against the global read lock and wake
      everyone, who might want to set a global read lock.
    */
    start_waiting_global_read_lock(thd);
2562

2563 2564
unsent_create_error:
    // put tables back for PS rexecuting
2565 2566
    tables= lex->link_first_table_back(tables, create_table,
				       create_table_local);
unknown's avatar
unknown committed
2567
    break;
unknown's avatar
unknown committed
2568
  }
unknown's avatar
unknown committed
2569
  case SQLCOM_CREATE_INDEX:
unknown's avatar
unknown committed
2570
    if (check_one_table_access(thd, INDEX_ACL, tables))
unknown's avatar
unknown committed
2571
      goto error; /* purecov: inspected */
2572
    thd->enable_slow_log= opt_log_slow_admin_statements;
2573 2574 2575 2576
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_create_index(thd, tables, lex->key_list);
unknown's avatar
unknown committed
2577 2578
    break;

unknown's avatar
unknown committed
2579
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2580
  case SQLCOM_SLAVE_START:
2581
  {
2582
    pthread_mutex_lock(&LOCK_active_mi);
2583
    start_slave(thd,active_mi,1 /* net report*/);
2584
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2585
    break;
2586
  }
unknown's avatar
unknown committed
2587
  case SQLCOM_SLAVE_STOP:
2588 2589 2590 2591 2592 2593
  /*
    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,
2594
      so it waits for the client thread because t is locked by it.
2595
    - then the client thread does SLAVE STOP.
2596 2597
      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.
2598 2599 2600 2601 2602
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
  if (thd->locked_tables || thd->active_transaction())
  {
2603
    send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
2604
    break;
2605
  }
2606
  {
2607
    pthread_mutex_lock(&LOCK_active_mi);
2608
    stop_slave(thd,active_mi,1/* net report*/);
2609
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2610
    break;
2611
  }
unknown's avatar
unknown committed
2612
#endif /* HAVE_REPLICATION */
2613

unknown's avatar
unknown committed
2614 2615
  case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
2616
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
2617 2618 2619
    break;
#else
    {
unknown's avatar
unknown committed
2620
      ulong priv=0;
unknown's avatar
unknown committed
2621
      if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
unknown's avatar
unknown committed
2622
      {
2623
	net_printf(thd, ER_WRONG_TABLE_NAME, lex->name);
unknown's avatar
unknown committed
2624
	res= 1;
unknown's avatar
unknown committed
2625 2626
	break;
      }
2627
      if (!select_lex->db)
2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645
      {
        /*
          In the case of ALTER TABLE ... RENAME we should supply the
          default database if the new name is not explicitly qualified
          by a database. (Bug #11493)
        */
        if (lex->alter_info.flags & ALTER_RENAME)
        {
          if (! thd->db)
          {
            send_error(thd,ER_NO_DB_ERROR);
            goto error;
          }
          select_lex->db= thd->db;
        }
        else
          select_lex->db=tables->db;
      }
unknown's avatar
unknown committed
2646 2647
      if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege,0,0) ||
	  check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0)||
unknown's avatar
unknown committed
2648
	  check_merge_table_access(thd, tables->db,
2649 2650 2651
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
2652 2653
      if (grant_option)
      {
unknown's avatar
unknown committed
2654
	if (check_grant(thd, ALTER_ACL, tables, 0, UINT_MAX, 0))
unknown's avatar
unknown committed
2655 2656 2657 2658 2659 2660
	  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;
2661
	  tmp_table.db=select_lex->db;
unknown's avatar
unknown committed
2662
	  tmp_table.grant.privilege=priv;
unknown's avatar
unknown committed
2663 2664
	  if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
			  UINT_MAX, 0))
unknown's avatar
unknown committed
2665 2666 2667
	    goto error;
	}
      }
2668 2669
      /* 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
2670
      /* ALTER TABLE ends previous transaction */
2671
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2672 2673
	res= -1;
      else
unknown's avatar
unknown committed
2674
      {
2675
        thd->enable_slow_log= opt_log_slow_admin_statements;
2676
	res= mysql_alter_table(thd, select_lex->db, lex->name,
unknown's avatar
unknown committed
2677 2678
			       &lex->create_info,
			       tables, lex->create_list,
2679
			       lex->key_list,
2680
			       select_lex->order_list.elements,
2681
                               (ORDER *) select_lex->order_list.first,
2682
			       lex->duplicates, lex->ignore, &lex->alter_info);
unknown's avatar
unknown committed
2683
      }
unknown's avatar
unknown committed
2684 2685
      break;
    }
unknown's avatar
unknown committed
2686
#endif /*DONT_ALLOW_SHOW_COMMANDS*/
unknown's avatar
unknown committed
2687
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
2688 2689 2690
  {
    TABLE_LIST *table;
    if (check_db_used(thd,tables))
unknown's avatar
unknown committed
2691
      goto error;
unknown's avatar
unknown committed
2692 2693
    for (table=tables ; table ; table=table->next->next)
    {
unknown's avatar
unknown committed
2694
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
unknown's avatar
unknown committed
2695
		       &table->grant.privilege,0,0) ||
unknown's avatar
unknown committed
2696
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next->db,
unknown's avatar
unknown committed
2697
		       &table->next->grant.privilege,0,0))
unknown's avatar
unknown committed
2698 2699 2700
	goto error;
      if (grant_option)
      {
unknown's avatar
unknown committed
2701
	TABLE_LIST old_list,new_list;
unknown's avatar
unknown committed
2702 2703 2704 2705
	/*
	  we do not need initialize old_list and new_list because we will
	  come table[0] and table->next[0] there
	*/
unknown's avatar
unknown committed
2706 2707 2708
	old_list=table[0];
	new_list=table->next[0];
	old_list.next=new_list.next=0;
unknown's avatar
unknown committed
2709
	if (check_grant(thd, ALTER_ACL, &old_list, 0, UINT_MAX, 0) ||
unknown's avatar
unknown committed
2710
	    (!test_all_bits(table->next->grant.privilege,
2711
			    INSERT_ACL | CREATE_ACL) &&
unknown's avatar
unknown committed
2712 2713
	     check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0,
			 UINT_MAX, 0)))
unknown's avatar
unknown committed
2714 2715 2716
	  goto error;
      }
    }
unknown's avatar
unknown committed
2717
    query_cache_invalidate3(thd, tables, 0);
2718 2719 2720
    if (end_active_trans(thd))
      res= -1;
    else if (mysql_rename_tables(thd,tables))
unknown's avatar
unknown committed
2721 2722
      res= -1;
    break;
unknown's avatar
unknown committed
2723
  }
2724
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2725 2726
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2727
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
2728 2729 2730
    DBUG_VOID_RETURN;
#else
    {
unknown's avatar
unknown committed
2731
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2732 2733 2734 2735
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
2736
#endif
2737
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2738
  case SQLCOM_SHOW_CREATE:
unknown's avatar
unknown committed
2739
#ifdef DONT_ALLOW_SHOW_COMMANDS
2740
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
2741 2742
    DBUG_VOID_RETURN;
#else
unknown's avatar
unknown committed
2743
    {
unknown's avatar
unknown committed
2744 2745
      if (check_db_used(thd, tables) ||
	  check_access(thd, SELECT_ACL | EXTRA_ACL, tables->db,
unknown's avatar
unknown committed
2746
		       &tables->grant.privilege,0,0))
unknown's avatar
unknown committed
2747
	goto error;
2748 2749 2750
      if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
	goto error;
      res= mysqld_show_create(thd, tables);
unknown's avatar
unknown committed
2751 2752
      break;
    }
unknown's avatar
unknown committed
2753
#endif
2754 2755 2756
  case SQLCOM_CHECKSUM:
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
2757
	check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
2758
      goto error; /* purecov: inspected */
2759
    res = mysql_checksum_table(thd, tables, &lex->check_opt);
2760 2761
    break;
  }
unknown's avatar
unknown committed
2762
  case SQLCOM_REPAIR:
2763 2764
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
2765
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
2766
      goto error; /* purecov: inspected */
2767
    thd->enable_slow_log= opt_log_slow_admin_statements;
2768
    res = mysql_repair_table(thd, tables, &lex->check_opt);
2769 2770 2771 2772 2773 2774
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
      mysql_update_log.write(thd, thd->query, thd->query_length);
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
2775
	thd->clear_error(); // No binlog error generated
2776
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
2777 2778 2779
        mysql_bin_log.write(&qinfo);
      }
    }
2780 2781
    break;
  }
unknown's avatar
unknown committed
2782
  case SQLCOM_CHECK:
2783 2784
  {
    if (check_db_used(thd,tables) ||
2785
	check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
2786
      goto error; /* purecov: inspected */
2787
    thd->enable_slow_log= opt_log_slow_admin_statements;
2788 2789 2790
    res = mysql_check_table(thd, tables, &lex->check_opt);
    break;
  }
unknown's avatar
unknown committed
2791 2792
  case SQLCOM_ANALYZE:
  {
unknown's avatar
unknown committed
2793
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
2794
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
unknown's avatar
unknown committed
2795
      goto error; /* purecov: inspected */
2796
    thd->enable_slow_log= opt_log_slow_admin_statements;
2797
    res = mysql_analyze_table(thd, tables, &lex->check_opt);
2798 2799 2800 2801 2802 2803
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
      mysql_update_log.write(thd, thd->query, thd->query_length);
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
2804
	thd->clear_error(); // No binlog error generated
2805
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
2806 2807 2808
        mysql_bin_log.write(&qinfo);
      }
    }
unknown's avatar
unknown committed
2809
    break;
unknown's avatar
unknown committed
2810
  }
2811

unknown's avatar
unknown committed
2812 2813
  case SQLCOM_OPTIMIZE:
  {
2814
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
2815
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
unknown's avatar
unknown committed
2816
      goto error; /* purecov: inspected */
2817
    thd->enable_slow_log= opt_log_slow_admin_statements;
2818 2819 2820
    res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
      mysql_recreate_table(thd, tables, 1) :
      mysql_optimize_table(thd, tables, &lex->check_opt);
2821 2822 2823 2824 2825 2826
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
      mysql_update_log.write(thd, thd->query, thd->query_length);
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
2827
	thd->clear_error(); // No binlog error generated
2828
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
2829 2830 2831
        mysql_bin_log.write(&qinfo);
      }
    }
unknown's avatar
unknown committed
2832 2833 2834
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
unknown committed
2835 2836
    if (update_precheck(thd, tables))
      break;
2837 2838 2839 2840
    res= mysql_update(thd,tables,
                      select_lex->item_list,
                      lex->value_list,
                      select_lex->where,
2841
		      select_lex->order_list.elements,
2842 2843
                      (ORDER *) select_lex->order_list.first,
                      select_lex->select_limit,
2844
                      lex->duplicates, lex->ignore);
unknown's avatar
unknown committed
2845 2846
    if (thd->net.report_error)
      res= -1;
2847 2848
    break;
  case SQLCOM_UPDATE_MULTI:
unknown's avatar
unknown committed
2849
  {
2850
    if ((res= multi_update_precheck(thd, tables)))
unknown's avatar
unknown committed
2851 2852 2853 2854 2855 2856
      break;
    res= mysql_multi_update(thd,tables,
			    &select_lex->item_list,
			    &lex->value_list,
			    select_lex->where,
			    select_lex->options,
2857
			    lex->duplicates, lex->ignore, unit, select_lex);
unknown's avatar
unknown committed
2858
    break;
unknown's avatar
unknown committed
2859
  }
unknown's avatar
unknown committed
2860
  case SQLCOM_REPLACE:
2861 2862
  case SQLCOM_INSERT:
  {
2863
    if ((res= insert_precheck(thd, tables)))
unknown's avatar
unknown committed
2864
      break;
2865 2866 2867
    res= mysql_insert(thd,tables,lex->field_list,lex->many_values,
                      lex->update_list, lex->value_list,
                      lex->duplicates, lex->ignore);
unknown's avatar
unknown committed
2868 2869
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2870
    break;
2871
  }
unknown's avatar
unknown committed
2872 2873 2874
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
2875
    TABLE_LIST *first_local_table= (TABLE_LIST *) select_lex->table_list.first;
unknown's avatar
unknown committed
2876 2877
    TABLE_LIST dup_tables;
    TABLE *insert_table;
unknown's avatar
unknown committed
2878
    if ((res= insert_precheck(thd, tables)))
2879
      break;
unknown's avatar
unknown committed
2880

2881 2882
    /* Fix lock for first table */
    if (tables->lock_type == TL_WRITE_DELAYED)
2883
      tables->lock_type= TL_WRITE;
2884

2885 2886
    /* Don't unlock tables until command is written to binary log */
    select_lex->options|= SELECT_NO_UNLOCK;
unknown's avatar
unknown committed
2887 2888

    select_result *result;
2889 2890 2891 2892
    unit->offset_limit_cnt= select_lex->offset_limit;
    unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit;
    if (unit->select_limit_cnt < select_lex->select_limit)
      unit->select_limit_cnt= HA_POS_ERROR;		// No limit
unknown's avatar
unknown committed
2893

2894
    if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
2895
    {
2896 2897
      /* Using same table for INSERT and SELECT */
      select_lex->options |= OPTION_BUFFER_RESULT;
unknown's avatar
unknown committed
2898
    }
2899

unknown's avatar
unknown committed
2900 2901 2902
    if ((res= open_and_lock_tables(thd, tables)))
      break;
      
unknown's avatar
unknown committed
2903
    insert_table= tables->table;
unknown's avatar
unknown committed
2904
    /* Skip first table, which is the table we are inserting in */
unknown's avatar
unknown committed
2905
    select_lex->table_list.first= (byte*) first_local_table->next;
unknown's avatar
unknown committed
2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920
    tables= (TABLE_LIST *) select_lex->table_list.first;
    dup_tables= *first_local_table;
    first_local_table->next= 0;
    if (select_lex->group_list.elements != 0)
    {
      /*
        When we are using GROUP BY we can't refere to other tables in the
        ON DUPLICATE KEY part
      */         
      dup_tables.next= 0;
    }

    if (!(res= mysql_prepare_insert(thd, tables, first_local_table,
				    &dup_tables, insert_table,
                                    lex->field_list, 0,
unknown's avatar
unknown committed
2921 2922
				    lex->update_list, lex->value_list,
				    lex->duplicates)) &&
unknown's avatar
unknown committed
2923 2924
        (result= new select_insert(insert_table, first_local_table,
				   &dup_tables, &lex->field_list,
unknown's avatar
unknown committed
2925
				   &lex->update_list, &lex->value_list,
2926
                                   lex->duplicates, lex->ignore)))
2927
    {
2928 2929 2930 2931 2932 2933 2934 2935 2936
      /*
        insert/replace from SELECT give its SELECT_LEX for SELECT,
        and item_list belong to SELECT
      */
      lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
      res= handle_select(thd, lex, result);
      /* revert changes for SP */
      lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
      delete result;
unknown's avatar
unknown committed
2937
      if (thd->net.report_error)
2938
        res= -1;
2939 2940 2941
    }
    else
      res= -1;
2942
    insert_table->insert_values= 0;        // Set by mysql_prepare_insert()
unknown's avatar
unknown committed
2943
    first_local_table->next= tables;
unknown's avatar
unknown committed
2944
    lex->select_lex.table_list.first= (byte*) first_local_table;
unknown's avatar
unknown committed
2945 2946
    break;
  }
2947
  case SQLCOM_TRUNCATE:
2948 2949 2950 2951 2952
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
unknown committed
2953
    if (check_one_table_access(thd, DELETE_ACL, tables))
unknown's avatar
unknown committed
2954
      goto error;
2955 2956 2957 2958 2959 2960
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
    if (thd->locked_tables || thd->active_transaction())
    {
2961
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
2962 2963
      goto error;
    }
2964
    res=mysql_truncate(thd, tables, 0);
2965
    break;
unknown's avatar
unknown committed
2966
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
2967
  {
unknown's avatar
unknown committed
2968 2969
    if ((res= delete_precheck(thd, tables)))
      break;
unknown's avatar
unknown committed
2970
    res = mysql_delete(thd,tables, select_lex->where,
2971
                       &select_lex->order_list,
unknown's avatar
unknown committed
2972
                       select_lex->select_limit, select_lex->options);
unknown's avatar
unknown committed
2973 2974
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2975 2976
    break;
  }
2977
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
2978
  {
2979 2980
    TABLE_LIST *aux_tables=
      (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
unknown's avatar
unknown committed
2981 2982
    TABLE_LIST *target_tbl;
    uint table_count;
unknown's avatar
unknown committed
2983
    multi_delete *result;
unknown's avatar
unknown committed
2984

2985 2986
    if ((res= multi_delete_precheck(thd, tables, &table_count)))
      break;
unknown's avatar
unknown committed
2987

unknown's avatar
unknown committed
2988
    /* condition will be TRUE on SP re-excuting */
2989 2990
    if (select_lex->item_list.elements != 0)
      select_lex->item_list.empty();
unknown's avatar
unknown committed
2991
    if (add_item_to_list(thd, new Item_null()))
2992
    {
unknown's avatar
unknown committed
2993
      res= -1;
2994
      break;
unknown's avatar
unknown committed
2995
    }
2996

unknown's avatar
unknown committed
2997 2998 2999 3000
    thd->proc_info="init";
    if ((res=open_and_lock_tables(thd,tables)))
      break;
    /* Fix tables-to-be-deleted-from list to point at opened tables */
unknown's avatar
unknown committed
3001 3002 3003
    for (target_tbl= (TABLE_LIST*) aux_tables;
	 target_tbl;
	 target_tbl= target_tbl->next)
unknown's avatar
unknown committed
3004
    {
3005 3006 3007
      TABLE_LIST *orig= target_tbl->table_list;
      target_tbl->table= orig->table;
      /*
unknown's avatar
unknown committed
3008
	 Multi-delete can't be constructed over-union => we always have
unknown's avatar
unknown committed
3009
	 single SELECT on top and have to check underlying SELECTs of it
3010
      */
3011 3012
      if (lex->select_lex.check_updateable_in_subqueries(orig->db,
                                                         orig->real_name))
3013
      {
3014 3015 3016 3017
        my_error(ER_UPDATE_TABLE_USED, MYF(0),
                 orig->real_name);
        res= -1;
        break;
3018
      }
unknown's avatar
unknown committed
3019
    }
3020

3021 3022
    if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
							  table_count)))
unknown's avatar
unknown committed
3023
    {
3024 3025 3026
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
3027
			select_lex->item_list,
unknown's avatar
unknown committed
3028
			select_lex->where,
3029
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
unknown's avatar
unknown committed
3030 3031
			(ORDER *)NULL,
			select_lex->options | thd->options |
unknown's avatar
unknown committed
3032
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
3033
			result, unit, select_lex);
unknown's avatar
unknown committed
3034 3035
      if (thd->net.report_error)
	res= -1;
3036
      delete result;
unknown's avatar
unknown committed
3037 3038 3039 3040 3041 3042
    }
    else
      res= -1;					// Error is not sent
    close_thread_tables(thd);
    break;
  }
unknown's avatar
unknown committed
3043
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
3044
  {
3045 3046
    if (!lex->drop_temporary)
    {
unknown's avatar
unknown committed
3047
      if (check_table_access(thd,DROP_ACL,tables,0))
3048 3049 3050 3051 3052 3053 3054
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
unknown's avatar
unknown committed
3055
    else
unknown's avatar
unknown committed
3056 3057 3058 3059 3060 3061
    {
      /*
	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
3062 3063
	To not generate such irrelevant "table does not exist errors",
	we silently add IF EXISTS if TEMPORARY was used.
unknown's avatar
unknown committed
3064 3065 3066
      */
      if (thd->slave_thread)
	lex->drop_if_exists= 1;
3067

unknown's avatar
unknown committed
3068 3069
      /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
      thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
unknown's avatar
unknown committed
3070
    }
3071
    res= mysql_rm_table(thd,tables,lex->drop_if_exists, lex->drop_temporary);
unknown's avatar
unknown committed
3072 3073
  }
  break;
unknown's avatar
unknown committed
3074
  case SQLCOM_DROP_INDEX:
unknown's avatar
unknown committed
3075
    if (check_one_table_access(thd, INDEX_ACL, tables))
unknown's avatar
unknown committed
3076
      goto error;				/* purecov: inspected */
3077 3078 3079
    if (end_active_trans(thd))
      res= -1;
    else
3080
      res = mysql_drop_index(thd, tables, &lex->alter_info);
unknown's avatar
unknown committed
3081 3082
    break;
  case SQLCOM_SHOW_DATABASES:
3083
#if defined(DONT_ALLOW_SHOW_COMMANDS)
3084
    send_error(thd,ER_NOT_ALLOWED_COMMAND);   /* purecov: inspected */
unknown's avatar
unknown committed
3085 3086 3087
    DBUG_VOID_RETURN;
#else
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
unknown's avatar
unknown committed
3088
	check_global_access(thd, SHOW_DB_ACL))
unknown's avatar
unknown committed
3089 3090 3091 3092 3093
      goto error;
    res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
    break;
#endif
  case SQLCOM_SHOW_PROCESSLIST:
unknown's avatar
unknown committed
3094
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
3095
      break;
unknown's avatar
unknown committed
3096 3097
    mysqld_list_processes(thd,
			  thd->master_access & PROCESS_ACL ? NullS :
unknown's avatar
unknown committed
3098
			  thd->priv_user,lex->verbose);
unknown's avatar
unknown committed
3099
    break;
unknown's avatar
unknown committed
3100 3101
  case SQLCOM_SHOW_STORAGE_ENGINES:
    res= mysqld_show_storage_engines(thd);
unknown's avatar
unknown committed
3102 3103 3104 3105 3106 3107 3108
    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
3109
  case SQLCOM_SHOW_STATUS:
3110
    res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
3111
		     OPT_GLOBAL, &LOCK_status);
unknown's avatar
unknown committed
3112 3113 3114
    break;
  case SQLCOM_SHOW_VARIABLES:
    res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
3115 3116
		     init_vars, lex->option_type,
		     &LOCK_global_system_variables);
unknown's avatar
unknown committed
3117
    break;
unknown's avatar
unknown committed
3118 3119
  case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
3120
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
3121 3122 3123
    DBUG_VOID_RETURN;
#else
    {
unknown's avatar
unknown committed
3124
      if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0))
unknown's avatar
unknown committed
3125 3126 3127 3128 3129
	goto error;
      res= mysqld_show_logs(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
3130
  case SQLCOM_SHOW_TABLES:
3131
    /* FALL THROUGH */
unknown's avatar
unknown committed
3132
#ifdef DONT_ALLOW_SHOW_COMMANDS
3133
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
3134 3135 3136
    DBUG_VOID_RETURN;
#else
    {
3137
      char *db=select_lex->db ? select_lex->db : thd->db;
unknown's avatar
unknown committed
3138 3139
      if (!db)
      {
3140
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
unknown's avatar
unknown committed
3141 3142 3143
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);				// Fix escaped '_'
3144
      if (check_db_name(db))
unknown's avatar
unknown committed
3145
      {
3146
        net_printf(thd,ER_WRONG_DB_NAME, db);
3147
        goto error;
unknown's avatar
unknown committed
3148
      }
unknown's avatar
unknown committed
3149
      if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
unknown's avatar
unknown committed
3150
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
3151
      if (!thd->col_access && check_grant_db(thd,db))
unknown's avatar
unknown committed
3152
      {
unknown's avatar
unknown committed
3153
	net_printf(thd, ER_DBACCESS_DENIED_ERROR,
unknown's avatar
unknown committed
3154 3155 3156 3157 3158
		   thd->priv_user,
		   thd->priv_host,
		   db);
	goto error;
      }
unknown's avatar
unknown committed
3159
      /* grant is checked in mysqld_show_tables */
3160
      if (lex->describe)
3161
        res= mysqld_extend_show_tables(thd,db,
3162
				       (lex->wild ? lex->wild->ptr() : NullS));
unknown's avatar
unknown committed
3163 3164 3165 3166 3167 3168
      else
	res= mysqld_show_tables(thd,db,
				(lex->wild ? lex->wild->ptr() : NullS));
      break;
    }
#endif
3169 3170 3171
  case SQLCOM_SHOW_OPEN_TABLES:
    res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
3172 3173
  case SQLCOM_SHOW_CHARSETS:
    res= mysqld_show_charsets(thd,(lex->wild ? lex->wild->ptr() : NullS));
3174
    break;
3175 3176 3177
  case SQLCOM_SHOW_COLLATIONS:
    res= mysqld_show_collations(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
unknown's avatar
unknown committed
3178 3179
  case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
3180
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
3181 3182 3183
    DBUG_VOID_RETURN;
#else
    {
3184
      char *db=tables->db;
unknown's avatar
unknown committed
3185
      remove_escape(db);			// Fix escaped '_'
3186
      remove_escape(tables->real_name);
3187
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
unknown's avatar
unknown committed
3188
		       &tables->grant.privilege, 0, 0))
unknown's avatar
unknown committed
3189
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
3190
      if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
3191 3192
	goto error;
      res= mysqld_show_fields(thd,tables,
unknown's avatar
unknown committed
3193 3194
			      (lex->wild ? lex->wild->ptr() : NullS),
			      lex->verbose);
unknown's avatar
unknown committed
3195 3196 3197 3198 3199
      break;
    }
#endif
  case SQLCOM_SHOW_KEYS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
3200
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
3201 3202 3203
    DBUG_VOID_RETURN;
#else
    {
3204
      char *db=tables->db;
unknown's avatar
unknown committed
3205
      remove_escape(db);			// Fix escaped '_'
3206
      remove_escape(tables->real_name);
unknown's avatar
unknown committed
3207
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
unknown's avatar
unknown committed
3208
		       &tables->grant.privilege, 0, 0))
unknown's avatar
unknown committed
3209
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
3210
      if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
3211 3212 3213 3214 3215 3216
	goto error;
      res= mysqld_show_keys(thd,tables);
      break;
    }
#endif
  case SQLCOM_CHANGE_DB:
3217
    mysql_change_db(thd,select_lex->db);
unknown's avatar
unknown committed
3218
    break;
3219

unknown's avatar
unknown committed
3220 3221 3222
  case SQLCOM_LOAD:
  {
    uint privilege= (lex->duplicates == DUP_REPLACE ?
3223
		     INSERT_ACL | DELETE_ACL : INSERT_ACL);
3224 3225

    if (!lex->local_file)
unknown's avatar
unknown committed
3226
    {
unknown's avatar
unknown committed
3227
      if (check_access(thd,privilege | FILE_ACL,tables->db,0,0,0))
unknown's avatar
unknown committed
3228 3229 3230 3231
	goto error;
    }
    else
    {
3232
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
unknown's avatar
unknown committed
3233
	  ! opt_local_infile)
3234
      {
3235
	send_error(thd,ER_NOT_ALLOWED_COMMAND);
3236 3237
	goto error;
      }
unknown's avatar
unknown committed
3238
      if (check_one_table_access(thd, privilege, tables))
unknown's avatar
unknown committed
3239 3240 3241
	goto error;
    }
    res=mysql_load(thd, lex->exchange, tables, lex->field_list,
3242
		   lex->duplicates, lex->ignore, (bool) lex->local_file, lex->lock_option);
unknown's avatar
unknown committed
3243 3244
    break;
  }
3245

unknown's avatar
unknown committed
3246
  case SQLCOM_SET_OPTION:
3247 3248
  {
    List<set_var_base> *lex_var_list= &lex->var_list;
unknown's avatar
unknown committed
3249
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
unknown's avatar
unknown committed
3250 3251
		   (res= open_and_lock_tables(thd,tables))))
      break;
3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265
    if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
    {
      my_printf_error(0, "The SET ONE_SHOT syntax is reserved for \
purposes internal to the MySQL server", MYF(0));
      res= -1;
      break;
    }
    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;
3266
      send_ok(thd);
3267
    }
unknown's avatar
unknown committed
3268 3269
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
3270
    break;
3271
  }
unknown's avatar
unknown committed
3272

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

unknown's avatar
unknown committed
3504 3505 3506 3507
    /*
      Check that the user isn't trying to change a password for another
      user if he doesn't have UPDATE privilege to the MySQL database
    */
3508 3509 3510 3511 3512 3513 3514 3515 3516 3517

    if (thd->user)				// If not replication
    {
      LEX_USER *user;
      List_iterator <LEX_USER> user_list(lex->users_list);
      while ((user=user_list++))
      {
	if (user->password.str &&
	    (strcmp(thd->user,user->user.str) ||
	     user->host.str &&
unknown's avatar
unknown committed
3518
	     my_strcasecmp(&my_charset_latin1,
3519
                           user->host.str, thd->host_or_ip)))
3520
	{
3521 3522 3523
	  if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1))
	  {
	    send_error(thd, ER_PASSWORD_NOT_ALLOWED);
3524
	    goto error;
3525 3526
	  }
	  break;		  // We are allowed to do global changes
3527 3528 3529
	}
      }
    }
unknown's avatar
SCRUM  
unknown committed
3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542
    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);
      }
    }
3543 3544 3545 3546 3547
    if (tables)
    {
      if (grant_option && check_grant(thd,
				      (lex->grant | lex->grant_tot_col |
				       GRANT_ACL),
unknown's avatar
unknown committed
3548
				      tables, 0, UINT_MAX, 0))
3549
	goto error;
unknown's avatar
unknown committed
3550 3551 3552
      if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
				    lex->grant,
				    lex->sql_command == SQLCOM_REVOKE)))
3553
      {
3554
	mysql_update_log.write(thd, thd->query, thd->query_length);
3555 3556
	if (mysql_bin_log.is_open())
	{
unknown's avatar
unknown committed
3557
          thd->clear_error();
3558
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3559 3560 3561 3562 3563 3564 3565 3566
	  mysql_bin_log.write(&qinfo);
	}
      }
    }
    else
    {
      if (lex->columns.elements)
      {
3567
	send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE);
3568 3569 3570 3571 3572 3573 3574
	res=1;
      }
      else
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
3575
	mysql_update_log.write(thd, thd->query, thd->query_length);
3576 3577
	if (mysql_bin_log.is_open())
	{
unknown's avatar
unknown committed
3578
          thd->clear_error();
3579
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3580 3581
	  mysql_bin_log.write(&qinfo);
	}
3582
	if (mqh_used && lex->sql_command == SQLCOM_GRANT)
3583
	{
unknown's avatar
unknown committed
3584 3585 3586
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
3587
	    reset_mqh(thd,user);
3588
	}
3589 3590 3591 3592
      }
    }
    break;
  }
unknown's avatar
SCRUM  
unknown committed
3593
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
unknown's avatar
unknown committed
3594
  case SQLCOM_RESET:
3595 3596 3597 3598 3599 3600 3601
    /* 
       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
unknown committed
3602
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
unknown's avatar
unknown committed
3603
      goto error;
3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621
    /*
      reload_acl_and_cache() will tell us if we are allowed to write to the
      binlog or not.
    */
    bool write_to_binlog;
    if (reload_acl_and_cache(thd, lex->type, tables, &write_to_binlog))
      send_error(thd, 0);
    else
    {
      /*
        We WANT to write and we CAN write.
        ! we write after unlocking the table.
      */
      if (!lex->no_write_to_binlog && write_to_binlog)
      {
        mysql_update_log.write(thd, thd->query, thd->query_length);
        if (mysql_bin_log.is_open())
        {
3622
          Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3623 3624 3625 3626 3627
          mysql_bin_log.write(&qinfo);
        }
      }
      send_ok(thd);
    }
unknown's avatar
unknown committed
3628
    break;
3629
  }
unknown's avatar
unknown committed
3630 3631 3632
  case SQLCOM_KILL:
    kill_one_thread(thd,lex->thread_id);
    break;
unknown's avatar
unknown committed
3633
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
3634 3635
  case SQLCOM_SHOW_GRANTS:
    res=0;
3636 3637
    if ((thd->priv_user &&
	 !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
unknown's avatar
unknown committed
3638
	!check_access(thd, SELECT_ACL, "mysql",0,1,0))
unknown's avatar
unknown committed
3639 3640 3641 3642
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
unknown's avatar
unknown committed
3643
#endif
3644
  case SQLCOM_HA_OPEN:
3645
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
3646
	check_table_access(thd,SELECT_ACL, tables,0))
3647 3648 3649 3650 3651 3652 3653 3654 3655
      goto error;
    res = mysql_ha_open(thd, tables);
    break;
  case SQLCOM_HA_CLOSE:
    if (check_db_used(thd,tables))
      goto error;
    res = mysql_ha_close(thd, tables);
    break;
  case SQLCOM_HA_READ:
3656 3657 3658 3659 3660
    /*
      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
unknown committed
3661
    if (check_db_used(thd,tables))
3662
      goto error;
unknown's avatar
unknown committed
3663
    res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
3664 3665
			lex->insert_list, lex->ha_rkey_mode, select_lex->where,
			select_lex->select_limit, select_lex->offset_limit);
3666 3667
    break;

unknown's avatar
unknown committed
3668
  case SQLCOM_BEGIN:
unknown's avatar
unknown committed
3669 3670 3671 3672 3673 3674
    if (thd->locked_tables)
    {
      thd->lock=thd->locked_tables;
      thd->locked_tables=0;			// Will be automaticly closed
      close_thread_tables(thd);			// Free tables
    }
unknown's avatar
unknown committed
3675 3676 3677 3678 3679 3680
    if (end_active_trans(thd))
    {
      res= -1;
    }
    else
    {
3681
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
unknown's avatar
unknown committed
3682 3683
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
3684 3685 3686
      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
3687
    }
unknown's avatar
unknown committed
3688 3689
    break;
  case SQLCOM_COMMIT:
3690 3691 3692 3693 3694
    /*
      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
3695
  {
3696
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
3697 3698
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
unknown's avatar
unknown committed
3699
    {
3700
      send_ok(thd);
unknown's avatar
unknown committed
3701
    }
unknown's avatar
unknown committed
3702 3703 3704
    else
      res= -1;
    break;
unknown's avatar
unknown committed
3705
  }
unknown's avatar
unknown committed
3706 3707 3708
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
3709
    {
unknown's avatar
unknown committed
3710 3711 3712 3713 3714 3715 3716 3717 3718 3719
      /*
        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)
3720
	send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
3721
      else
3722
	send_ok(thd);
3723
    }
unknown's avatar
unknown committed
3724 3725
    else
      res= -1;
3726
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
3727
    break;
unknown's avatar
unknown committed
3728 3729 3730
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
    if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
    {
unknown's avatar
unknown committed
3731
      if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
unknown's avatar
unknown committed
3732
	send_warning(thd, ER_WARNING_NOT_COMPLETE_ROLLBACK, 0);
unknown's avatar
unknown committed
3733
      else
unknown's avatar
unknown committed
3734
	send_ok(thd);
unknown's avatar
unknown committed
3735 3736 3737 3738
    }
    else
      res= -1;
    break;
3739
  case SQLCOM_SAVEPOINT:
unknown's avatar
unknown committed
3740
    if (!ha_savepoint(thd, lex->savepoint_name))
unknown's avatar
unknown committed
3741
      send_ok(thd);
unknown's avatar
unknown committed
3742 3743
    else
      res= -1;
3744
    break;
unknown's avatar
unknown committed
3745
  default:					/* Impossible */
3746
    send_ok(thd);
unknown's avatar
unknown committed
3747 3748 3749
    break;
  }
  thd->proc_info="query end";			// QQ
3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762

  /*
    Reset system variables temporarily modified by SET ONE SHOT.

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

unknown's avatar
unknown committed
3763
  if (res < 0)
3764
    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
unknown's avatar
unknown committed
3765 3766

error:
unknown's avatar
unknown committed
3767 3768 3769 3770 3771 3772 3773 3774
  if (unlikely(slave_fake_lock))
  {
    DBUG_PRINT("info",("undoing faked lock"));
    thd->lock= thd->locked_tables;
    thd->locked_tables= fake_prev_lock;
    if (thd->lock == thd->locked_tables)
      thd->lock= 0;
  }
unknown's avatar
unknown committed
3775 3776 3777 3778
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
3779 3780
/*
  Check grants for commands which work only with one table and all other
3781
  tables belonging to subselects or implicitly opened tables.
unknown's avatar
unknown committed
3782

3783
  SYNOPSIS
unknown's avatar
unknown committed
3784 3785 3786 3787
    check_one_table_access()
    thd			Thread handler
    privilege		requested privelage
    tables		table list of command
unknown's avatar
unknown committed
3788 3789 3790

  RETURN
    0 - OK
unknown's avatar
unknown committed
3791
    1 - access denied, error is sent to client
unknown's avatar
unknown committed
3792
*/
unknown's avatar
unknown committed
3793 3794

int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables)
unknown's avatar
unknown committed
3795
{
unknown's avatar
unknown committed
3796 3797
  if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
    return 1;
unknown's avatar
unknown committed
3798

unknown's avatar
unknown committed
3799
  /* Show only 1 table for check_grant */
unknown's avatar
unknown committed
3800
  if (grant_option && check_grant(thd, privilege, tables, 0, 1, 0))
unknown's avatar
unknown committed
3801
    return 1;
unknown's avatar
unknown committed
3802

3803
  /* Check rights on tables of subselects and implictly opened tables */
unknown's avatar
unknown committed
3804 3805
  TABLE_LIST *subselects_tables;
  if ((subselects_tables= tables->next))
unknown's avatar
unknown committed
3806
  {
unknown's avatar
unknown committed
3807
    if ((check_table_access(thd, SELECT_ACL, subselects_tables,0)))
unknown's avatar
unknown committed
3808 3809 3810
      return 1;
  }
  return 0;
unknown's avatar
unknown committed
3811 3812 3813
}


unknown's avatar
unknown committed
3814
/****************************************************************************
unknown's avatar
unknown committed
3815
  Get the user (global) and database privileges for all used tables
unknown's avatar
unknown committed
3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828

  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
3829 3830
                is enough to satisfy the request and the global grants contains
                a SELECT grant.
unknown's avatar
unknown committed
3831 3832 3833
****************************************************************************/

bool
unknown's avatar
unknown committed
3834
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
3835
	     bool dont_check_global_grants, bool no_errors)
unknown's avatar
unknown committed
3836
{
unknown's avatar
unknown committed
3837
  DBUG_ENTER("check_access");
3838 3839
  DBUG_PRINT("enter",("db: '%s'  want_access: %lu  master_access: %lu",
                      db ? db : "", want_access, thd->master_access));
unknown's avatar
unknown committed
3840 3841
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  ulong db_access;
unknown's avatar
unknown committed
3842
  bool  db_is_pattern= test(want_access & GRANT_ACL);
unknown's avatar
unknown committed
3843 3844
#endif
  ulong dummy;
unknown's avatar
unknown committed
3845 3846 3847 3848 3849
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

3850
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
3851
  {
3852
    if (!no_errors)
3853
      send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
unknown's avatar
unknown committed
3854
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
3855 3856
  }

unknown's avatar
unknown committed
3857 3858 3859
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  DBUG_RETURN(0);
#else
unknown's avatar
unknown committed
3860 3861
  if ((thd->master_access & want_access) == want_access)
  {
3862 3863 3864 3865 3866 3867 3868
    /*
      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) &&
unknown's avatar
unknown committed
3869
	(db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
unknown's avatar
unknown committed
3870
      db_access=acl_get(thd->host, thd->ip, thd->priv_user, db, db_is_pattern);
3871
    *save_priv=thd->master_access | db_access;
unknown's avatar
unknown committed
3872
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
3873
  }
3874
  if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
3875
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
3876
  {						// We can never grant this
3877
    if (!no_errors)
3878
      net_printf(thd,ER_ACCESS_DENIED_ERROR,
3879
		 thd->priv_user,
3880
		 thd->priv_host,
3881
		 thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
unknown's avatar
unknown committed
3882
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
3883 3884 3885
  }

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

unknown's avatar
unknown committed
3888
  if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
unknown's avatar
unknown committed
3889
    db_access=acl_get(thd->host, thd->ip, thd->priv_user, db, db_is_pattern);
unknown's avatar
unknown committed
3890 3891
  else
    db_access=thd->db_access;
3892 3893
  DBUG_PRINT("info",("db_access: %lu", db_access));
  /* Remove SHOW attribute and access rights we already have */
3894
  want_access &= ~(thd->master_access | EXTRA_ACL);
unknown's avatar
unknown committed
3895
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
3896 3897

  /* grant_option is set if there exists a single table or column grant */
unknown's avatar
unknown committed
3898
  if (db_access == want_access ||
3899
      ((grant_option && !dont_check_global_grants) &&
3900
       !(want_access & ~(db_access | TABLE_ACLS))))
unknown's avatar
unknown committed
3901
    DBUG_RETURN(FALSE);				/* Ok */
3902
  if (!no_errors)
3903
    net_printf(thd,ER_DBACCESS_DENIED_ERROR,
3904
	       thd->priv_user,
3905
	       thd->priv_host,
3906
	       db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
unknown's avatar
unknown committed
3907
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
3908
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
3909 3910 3911
}


3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929
/*
  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
    One gets access rigth if one has ANY of the rights in want_access
    This is useful as one in most cases only need one global right,
    but in some case we want to check if the user has SUPER or
    REPL_CLIENT_ACL rights.

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

bool check_global_access(THD *thd, ulong want_access)
unknown's avatar
unknown committed
3932
{
unknown's avatar
unknown committed
3933 3934 3935
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  return 0;
#else
unknown's avatar
unknown committed
3936
  char command[128];
3937
  if ((thd->master_access & want_access))
unknown's avatar
unknown committed
3938 3939
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
3940
  net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
unknown's avatar
unknown committed
3941 3942
	     command);
  return 1;
unknown's avatar
unknown committed
3943
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
3944 3945 3946
}


unknown's avatar
unknown committed
3947
/*
unknown's avatar
unknown committed
3948 3949
  Check the privilege for all used tables.  Table privileges are cached
  in the table list for GRANT checking
unknown's avatar
unknown committed
3950 3951
*/

3952
bool
unknown's avatar
unknown committed
3953
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
3954
		   bool no_errors)
unknown's avatar
unknown committed
3955
{
unknown's avatar
unknown committed
3956 3957
  uint found=0;
  ulong found_access=0;
unknown's avatar
unknown committed
3958 3959 3960
  TABLE_LIST *org_tables=tables;
  for (; tables ; tables=tables->next)
  {
3961 3962 3963 3964
    if (tables->derived ||
        (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
3965
      continue;
unknown's avatar
unknown committed
3966 3967
    if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
	thd->db)
unknown's avatar
unknown committed
3968
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
3969
    else if (tables->db && tables->db == thd->db)
unknown's avatar
unknown committed
3970 3971 3972 3973 3974
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
3975 3976
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
			 0, no_errors))
unknown's avatar
unknown committed
3977 3978
	  return TRUE;				// Access denied
	found_access=tables->grant.privilege;
unknown's avatar
unknown committed
3979
	found=1;
unknown's avatar
unknown committed
3980 3981
      }
    }
3982
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
3983
			  0, no_errors))
3984
      return TRUE;
unknown's avatar
unknown committed
3985 3986
  }
  if (grant_option)
3987
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
unknown's avatar
unknown committed
3988
		       test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
unknown's avatar
unknown committed
3989 3990 3991
  return FALSE;
}

3992 3993
bool check_merge_table_access(THD *thd, char *db,
			      TABLE_LIST *table_list)
3994 3995 3996 3997
{
  int error=0;
  if (table_list)
  {
3998
    /* Check that all tables use the current database */
3999 4000
    TABLE_LIST *tmp;
    for (tmp=table_list; tmp ; tmp=tmp->next)
4001 4002 4003 4004
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
    }
4005
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
unknown's avatar
unknown committed
4006
			     table_list,0);
4007 4008 4009 4010
  }
  return error;
}

unknown's avatar
unknown committed
4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026

static bool check_db_used(THD *thd,TABLE_LIST *tables)
{
  for (; tables ; tables=tables->next)
  {
    if (!tables->db)
    {
      if (!(tables->db=thd->db))
      {
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
	return TRUE;				/* purecov: tested */
      }
    }
  }
  return FALSE;
}
4027

unknown's avatar
unknown committed
4028 4029 4030 4031 4032 4033 4034 4035 4036 4037
/****************************************************************************
	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
4038 4039 4040 4041
#ifndef DBUG_OFF
long max_stack_used;
#endif

4042
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
4043 4044 4045 4046 4047 4048 4049 4050
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));
4051
    thd->fatal_error();
unknown's avatar
unknown committed
4052 4053
    return 1;
  }
unknown's avatar
unknown committed
4054 4055 4056
#ifndef DBUG_OFF
  max_stack_used= max(max_stack_used, stack_used);
#endif
unknown's avatar
unknown committed
4057 4058
  return 0;
}
4059
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
4060 4061 4062 4063

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

4064
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
unknown's avatar
unknown committed
4065 4066
{
  LEX	*lex=current_lex;
4067
  ulong old_info=0;
unknown's avatar
unknown committed
4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092
  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;
}

/****************************************************************************
4093
  Initialize global thd variables needed for query
unknown's avatar
unknown committed
4094 4095
****************************************************************************/

4096
void
unknown's avatar
unknown committed
4097
mysql_init_query(THD *thd, uchar *buf, uint length)
unknown's avatar
unknown committed
4098 4099
{
  DBUG_ENTER("mysql_init_query");
unknown's avatar
unknown committed
4100
  lex_start(thd, buf, length);
4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121
  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");
4122
  thd->free_list= 0;
4123 4124
  thd->select_number= 1;
  thd->total_warn_count= 0;                     // Warnings for this query
unknown's avatar
unknown committed
4125 4126
  thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
  thd->sent_row_count= thd->examined_row_count= 0;
4127
  thd->is_fatal_error= thd->rand_used= thd->time_zone_used= 0;
unknown's avatar
unknown committed
4128 4129 4130
  thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | 
			  SERVER_QUERY_NO_INDEX_USED |
			  SERVER_QUERY_NO_GOOD_INDEX_USED);
unknown's avatar
unknown committed
4131
  thd->tmp_table_used= 0;
unknown's avatar
unknown committed
4132 4133
  if (opt_bin_log)
    reset_dynamic(&thd->user_var_events);
4134
  thd->clear_error();
unknown's avatar
unknown committed
4135 4136 4137
  DBUG_VOID_RETURN;
}

4138

4139 4140 4141
void
mysql_init_select(LEX *lex)
{
unknown's avatar
unknown committed
4142
  SELECT_LEX *select_lex= lex->current_select;
unknown's avatar
unknown committed
4143
  select_lex->init_select();
4144
  select_lex->select_limit= HA_POS_ERROR;
4145 4146
  if (select_lex == &lex->select_lex)
  {
4147
    DBUG_ASSERT(lex->result == 0);
4148 4149
    lex->exchange= 0;
  }
4150 4151
}

4152

unknown's avatar
unknown committed
4153
bool
unknown's avatar
unknown committed
4154
mysql_new_select(LEX *lex, bool move_down)
4155
{
unknown's avatar
unknown committed
4156 4157
  SELECT_LEX *select_lex;
  if (!(select_lex= new(lex->thd->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
4158
    return 1;
4159
  select_lex->select_number= ++lex->thd->select_number;
unknown's avatar
unknown committed
4160 4161
  select_lex->init_query();
  select_lex->init_select();
4162 4163 4164 4165 4166 4167 4168 4169
  /*
    Don't evaluate this subquery during statement prepare even if
    it's a constant one. The flag is switched off in the end of
    mysql_stmt_prepare.
  */
  if (lex->thd->current_arena->is_stmt_prepare())
    select_lex->uncacheable|= UNCACHEABLE_PREPARE;

unknown's avatar
unknown committed
4170 4171
  if (move_down)
  {
4172
    lex->subqueries= TRUE;
unknown's avatar
unknown committed
4173
    /* first select_lex of subselect or derived table */
unknown's avatar
unknown committed
4174 4175
    SELECT_LEX_UNIT *unit;
    if (!(unit= new(lex->thd->mem_root) SELECT_LEX_UNIT()))
unknown's avatar
unknown committed
4176
      return 1;
unknown's avatar
unknown committed
4177

unknown's avatar
unknown committed
4178 4179
    unit->init_query();
    unit->init_select();
4180
    unit->thd= lex->thd;
unknown's avatar
unknown committed
4181
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
4182 4183
    unit->link_next= 0;
    unit->link_prev= 0;
4184
    unit->return_to= lex->current_select;
unknown's avatar
unknown committed
4185
    select_lex->include_down(unit);
4186
    // TODO: assign resolve_mode for fake subquery after merging with new tree
unknown's avatar
unknown committed
4187 4188
  }
  else
unknown's avatar
unknown committed
4189
  {
4190
    select_lex->include_neighbour(lex->current_select);
unknown's avatar
unknown committed
4191 4192 4193 4194 4195 4196 4197 4198
    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
4199 4200
      if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX()))
        return 1;
unknown's avatar
unknown committed
4201 4202 4203 4204 4205
      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;
4206
      fake->select_limit= HA_POS_ERROR;
unknown's avatar
unknown committed
4207 4208
    }
  }
unknown's avatar
unknown committed
4209

4210
  select_lex->master_unit()->global_parameters= select_lex;
4211
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
4212
  lex->current_select= select_lex;
4213
  select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
unknown's avatar
unknown committed
4214
  return 0;
4215
}
unknown's avatar
unknown committed
4216

4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231
/*
  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)
{
4232
  THD *thd;
4233
  LEX *lex;
4234
  LEX_STRING tmp, null_lex_string;
4235 4236
  Item *var;
  char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end;
4237
  DBUG_ENTER("create_select_for_variable");
4238 4239

  thd= current_thd;
4240
  lex= thd->lex;
4241 4242 4243 4244
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
4245
  bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
4246 4247 4248 4249
  /*
    We set the name of Item to @@session.var_name because that then is used
    as the column name in the output.
  */
unknown's avatar
unknown committed
4250 4251 4252 4253 4254 4255
  if ((var= get_system_var(thd, OPT_SESSION, tmp, null_lex_string)))
  {
    end= strxmov(buff, "@@session.", var_name, NullS);
    var->set_name(buff, end-buff, system_charset_info);
    add_item_to_list(thd, var);
  }
4256 4257 4258
  DBUG_VOID_RETURN;
}

4259

unknown's avatar
unknown committed
4260 4261
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
4262
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
4263
  mysql_init_select(lex);
4264
  lex->select_lex.select_limit= lex->unit.select_limit_cnt=
unknown's avatar
unknown committed
4265
    HA_POS_ERROR;
unknown's avatar
unknown committed
4266
  lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list);
4267
  lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
unknown's avatar
unknown committed
4268
}
unknown's avatar
unknown committed
4269

4270

4271 4272 4273 4274
/*
  When you modify mysql_parse(), you may need to mofify
  mysql_test_parse_for_slave() in this same file.
*/
unknown's avatar
unknown committed
4275

4276
void mysql_parse(THD *thd, char *inBuf, uint length)
unknown's avatar
unknown committed
4277 4278 4279
{
  DBUG_ENTER("mysql_parse");

unknown's avatar
unknown committed
4280
  mysql_init_query(thd, (uchar*) inBuf, length);
unknown's avatar
unknown committed
4281
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
unknown's avatar
unknown committed
4282
  {
unknown's avatar
unknown committed
4283
    LEX *lex= thd->lex;
4284
    if (!yyparse((void *)thd) && ! thd->is_fatal_error)
unknown's avatar
unknown committed
4285
    {
unknown's avatar
unknown committed
4286
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4287
      if (mqh_used && thd->user_connect &&
4288
	  check_mqh(thd, lex->sql_command))
4289 4290 4291 4292
      {
	thd->net.error = 0;
      }
      else
unknown's avatar
unknown committed
4293
#endif
4294
      {
unknown's avatar
unknown committed
4295 4296 4297 4298
	if (thd->net.report_error)
	  send_error(thd, 0, NullS);
	else
	{
4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312
          /*
            Binlog logs a string starting from thd->query and having length
            thd->query_length; so we set thd->query_length correctly (to not
            log several statements in one event, when we executed only first).
            We set it to not see the ';' (otherwise it would get into binlog
            and Query_log_event::print() would give ';;' output).
            This also helps display only the current query in SHOW
            PROCESSLIST.
            Note that we don't need LOCK_thread_count to modify query_length.
          */
          if (lex->found_colon &&
              (thd->query_length= (ulong)(lex->found_colon - thd->query)))
            thd->query_length--;
          /* Actually execute the query */
unknown's avatar
unknown committed
4313
	  mysql_execute_command(thd);
unknown's avatar
SCRUM  
unknown committed
4314
	  query_cache_end_of_result(thd);
unknown's avatar
unknown committed
4315
	}
4316
      }
unknown's avatar
unknown committed
4317 4318
    }
    else
4319 4320
    {
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
4321
			 thd->is_fatal_error));
unknown's avatar
unknown committed
4322
      query_cache_abort(&thd->net);
4323
    }
unknown's avatar
unknown committed
4324
    thd->proc_info="freeing items";
4325
    thd->end_statement();
4326
    DBUG_ASSERT(thd->change_list.is_empty());
unknown's avatar
unknown committed
4327
  }
unknown's avatar
unknown committed
4328 4329 4330 4331
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
4332
#ifdef HAVE_REPLICATION
4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343
/*
  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
4344
  LEX *lex= thd->lex;
4345 4346
  bool error= 0;

unknown's avatar
unknown committed
4347
  mysql_init_query(thd, (uchar*) inBuf, length);
unknown's avatar
unknown committed
4348
  if (!yyparse((void*) thd) && ! thd->is_fatal_error &&
4349 4350
      all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
    error= 1;                /* Ignore question */
4351
  thd->end_statement();
4352 4353
  return error;
}
unknown's avatar
unknown committed
4354
#endif
unknown's avatar
unknown committed
4355

4356

unknown's avatar
unknown committed
4357 4358 4359 4360 4361
/*****************************************************************************
** Store field definition for create
** Return 0 if ok
******************************************************************************/

unknown's avatar
unknown committed
4362
bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
unknown's avatar
unknown committed
4363
		       char *length, char *decimals,
4364
		       uint type_modifier,
4365 4366
		       Item *default_value, Item *on_update_value,
                       LEX_STRING *comment,
4367 4368
		       char *change,
                       List<String> *interval_list, CHARSET_INFO *cs,
unknown's avatar
unknown committed
4369
		       uint uint_geom_type)
unknown's avatar
unknown committed
4370 4371
{
  register create_field *new_field;
4372
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
4373
  uint allowed_type_modifier=0;
4374
  char warn_buff[MYSQL_ERRMSG_SIZE];
unknown's avatar
unknown committed
4375 4376 4377 4378
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
4379
    net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
unknown's avatar
unknown committed
4380 4381 4382 4383 4384
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
4385
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
4386
				    0, lex->col_list));
unknown's avatar
unknown committed
4387 4388 4389 4390 4391
    lex->col_list.empty();
  }
  if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
4392
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF, 0,
unknown's avatar
unknown committed
4393 4394 4395 4396
				    lex->col_list));
    lex->col_list.empty();
  }

4397
  if (default_value)
unknown's avatar
unknown committed
4398
  {
4399
    /* 
unknown's avatar
unknown committed
4400 4401
      Default value should be literal => basic constants =>
      no need fix_fields()
4402 4403 4404
      
      We allow only one function as part of default value - 
      NOW() as default for TIMESTAMP type.
4405
    */
4406 4407 4408 4409 4410 4411 4412 4413
    if (default_value->type() == Item::FUNC_ITEM && 
        !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
         type == FIELD_TYPE_TIMESTAMP))
    {
      net_printf(thd, ER_INVALID_DEFAULT, field_name);
      DBUG_RETURN(1);
    }
    else if (default_value->type() == Item::NULL_ITEM)
unknown's avatar
unknown committed
4414
    {
4415
      default_value= 0;
4416 4417 4418
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
unknown's avatar
unknown committed
4419
	net_printf(thd,ER_INVALID_DEFAULT,field_name);
4420 4421 4422 4423 4424
	DBUG_RETURN(1);
      }
    }
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
unknown's avatar
unknown committed
4425
      net_printf(thd, ER_INVALID_DEFAULT, field_name);
unknown's avatar
unknown committed
4426 4427 4428
      DBUG_RETURN(1);
    }
  }
4429 4430 4431 4432 4433 4434 4435

  if (on_update_value && type != FIELD_TYPE_TIMESTAMP)
  {
    net_printf(thd, ER_INVALID_ON_UPDATE, field_name);
    DBUG_RETURN(1);
  }
    
unknown's avatar
unknown committed
4436 4437 4438 4439
  if (!(new_field=new create_field()))
    DBUG_RETURN(1);
  new_field->field=0;
  new_field->field_name=field_name;
4440
  new_field->def= default_value;
unknown's avatar
unknown committed
4441 4442 4443 4444 4445 4446 4447 4448 4449 4450
  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;
  new_field->pack_length=0;
4451
  new_field->charset=cs;
unknown's avatar
unknown committed
4452
  new_field->geom_type= (Field::geometry_type) uint_geom_type;
unknown's avatar
unknown committed
4453

4454 4455 4456 4457 4458 4459 4460 4461
  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
4462 4463
    new_field->comment.str=   (char*) comment->str;
    new_field->comment.length=comment->length;
4464
  }
4465 4466
  if (length && !(new_field->length= (uint) atoi(length)))
    length=0; /* purecov: inspected */
unknown's avatar
unknown committed
4467 4468 4469
  uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;

  if (new_field->length && new_field->decimals &&
4470
      new_field->length < new_field->decimals+1 &&
unknown's avatar
unknown committed
4471
      new_field->decimals != NOT_FIXED_DEC)
4472
    new_field->length=new_field->decimals+1; /* purecov: inspected */
unknown's avatar
unknown committed
4473 4474 4475

  switch (type) {
  case FIELD_TYPE_TINY:
4476
    if (!length) new_field->length=MAX_TINYINT_WIDTH+sign_len;
unknown's avatar
unknown committed
4477 4478 4479
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_SHORT:
4480
    if (!length) new_field->length=MAX_SMALLINT_WIDTH+sign_len;
unknown's avatar
unknown committed
4481 4482 4483
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_INT24:
4484
    if (!length) new_field->length=MAX_MEDIUMINT_WIDTH+sign_len;
unknown's avatar
unknown committed
4485 4486 4487
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONG:
4488
    if (!length) new_field->length=MAX_INT_WIDTH+sign_len;
unknown's avatar
unknown committed
4489 4490 4491
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONGLONG:
4492
    if (!length) new_field->length=MAX_BIGINT_WIDTH;
unknown's avatar
unknown committed
4493 4494 4495 4496 4497 4498
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_NULL:
    break;
  case FIELD_TYPE_DECIMAL:
    if (!length)
unknown's avatar
unknown committed
4499 4500
    {
      if ((new_field->length= new_field->decimals))
4501 4502
        new_field->length++;
      else
unknown's avatar
unknown committed
4503 4504
        new_field->length= 10;                  // Default length for DECIMAL
    }
4505 4506 4507 4508 4509 4510
    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
4511
    break;
4512 4513
  case FIELD_TYPE_STRING:
  case FIELD_TYPE_VAR_STRING:
4514
    if (new_field->length <= MAX_FIELD_CHARLENGTH || default_value)
4515 4516 4517 4518
      break;
    /* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */
    new_field->sql_type= FIELD_TYPE_BLOB;
    sprintf(warn_buff, ER(ER_AUTO_CONVERT), field_name, "CHAR",
unknown's avatar
unknown committed
4519
	    (cs == &my_charset_bin) ? "BLOB" : "TEXT");
4520 4521 4522
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_AUTO_CONVERT,
		 warn_buff);
    /* fall through */
unknown's avatar
unknown committed
4523 4524 4525 4526
  case FIELD_TYPE_BLOB:
  case FIELD_TYPE_TINY_BLOB:
  case FIELD_TYPE_LONG_BLOB:
  case FIELD_TYPE_MEDIUM_BLOB:
unknown's avatar
unknown committed
4527
  case FIELD_TYPE_GEOMETRY:
4528 4529 4530 4531 4532
    if (new_field->length)
    {
      /* The user has given a length to the blob column */
      if (new_field->length < 256)
	type= FIELD_TYPE_TINY_BLOB;
4533
      else if (new_field->length < 65536)
4534 4535 4536 4537 4538 4539 4540 4541
	type= FIELD_TYPE_BLOB;
      else if (new_field->length < 256L*256L*256L)
	type= FIELD_TYPE_MEDIUM_BLOB;
      else
	type= FIELD_TYPE_LONG_BLOB;
      new_field->length= 0;
    }
    new_field->sql_type= type;
unknown's avatar
unknown committed
4542 4543 4544 4545 4546 4547
    if (default_value)				// Allow empty as default value
    {
      String str,*res;
      res=default_value->val_str(&str);
      if (res->length())
      {
4548
	net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
unknown's avatar
unknown committed
4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567
	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)
      {
4568
	net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
unknown's avatar
unknown committed
4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597
	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
4598
    else if (new_field->length != 19)
unknown's avatar
unknown committed
4599
    {
4600 4601 4602 4603
      /*
        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
4604 4605 4606
      new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
      new_field->length= min(new_field->length,14); /* purecov: inspected */
    }
4607
    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627
    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
    {
4628 4629 4630 4631 4632 4633 4634 4635
      /*
        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
4636
        information about all TIMESTAMP fields in table will be availiable.
4637 4638 4639

        If we have TIMESTAMP NULL column without explicit DEFAULT value
        we treat it as having DEFAULT NULL attribute.
4640
      */
4641 4642 4643 4644 4645
      new_field->unireg_check= on_update_value ?
                               Field::TIMESTAMP_UN_FIELD :
                               (new_field->flags & NOT_NULL_FLAG ?
                                Field::TIMESTAMP_OLD_FIELD:
                                Field::NONE);
4646
    }
unknown's avatar
unknown committed
4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662
    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:
    {
4663
      if (interval_list->elements > sizeof(longlong)*8)
unknown's avatar
unknown committed
4664
      {
4665 4666
        net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
        DBUG_RETURN(1);				/* purecov: inspected */
unknown's avatar
unknown committed
4667
      }
4668
      new_field->pack_length= get_set_pack_length(interval_list->elements);
4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679

      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
4680 4681 4682 4683
    }
    break;
  case FIELD_TYPE_ENUM:
    {
4684
      // Should be safe
4685
      new_field->pack_length= get_enum_pack_length(interval_list->elements);
4686 4687 4688 4689 4690 4691

      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
4692
    }
4693
    break;
unknown's avatar
unknown committed
4694 4695
  }

4696 4697
  if ((new_field->length > MAX_FIELD_CHARLENGTH && type != FIELD_TYPE_SET && 
       type != FIELD_TYPE_ENUM) ||
unknown's avatar
unknown committed
4698
      (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
4699
       type != FIELD_TYPE_STRING &&
unknown's avatar
SCRUM  
unknown committed
4700
       type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
unknown's avatar
unknown committed
4701
  {
4702
    net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
4703
	       MAX_FIELD_CHARLENGTH);		/* purecov: inspected */
unknown's avatar
unknown committed
4704 4705 4706 4707 4708
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
4709
    net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
unknown's avatar
unknown committed
4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730
    DBUG_RETURN(1);
  }
  if (!new_field->pack_length)
    new_field->pack_length=calc_pack_length(new_field->sql_type ==
					    FIELD_TYPE_VAR_STRING ?
					    FIELD_TYPE_STRING :
					    new_field->sql_type,
					    new_field->length);
  lex->create_list.push_back(new_field);
  lex->last_field=new_field;
  DBUG_RETURN(0);
}

/* 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
4731
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
4732 4733 4734 4735
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
4736
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
4737 4738 4739 4740 4741
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
4742
  thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
4743 4744 4745 4746 4747 4748 4749 4750
  return 0;
}


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

static void remove_escape(char *name)
{
4751 4752
  if (!*name)					// For empty DB names
    return;
unknown's avatar
unknown committed
4753 4754
  char *to;
#ifdef USE_MB
unknown's avatar
unknown committed
4755
  char *strend=name+(uint) strlen(name);
unknown's avatar
unknown committed
4756 4757 4758 4759 4760 4761
#endif
  for (to=name; *name ; name++)
  {
#ifdef USE_MB
    int l;
/*    if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
4762 4763
    if (use_mb(system_charset_info) &&
        (l = my_ismbchar(system_charset_info, name, strend)))
unknown's avatar
unknown committed
4764 4765 4766 4767 4768 4769 4770 4771
    {
	while (l--)
	    *to++ = *name++;
	name--;
	continue;
    }
#endif
    if (*name == '\\' && name[1])
unknown's avatar
unknown committed
4772
      name++;					// Skip '\\'
unknown's avatar
unknown committed
4773 4774 4775 4776 4777 4778 4779 4780 4781 4782
    *to++= *name;
  }
  *to=0;
}

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


unknown's avatar
unknown committed
4783
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
4784 4785 4786
{
  ORDER *order;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
4787
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER))))
unknown's avatar
unknown committed
4788
    DBUG_RETURN(1);
unknown's avatar
unknown committed
4789 4790
  order->item_ptr= item;
  order->item= &order->item_ptr;
unknown's avatar
unknown committed
4791 4792 4793
  order->asc = asc;
  order->free_me=0;
  order->used=0;
unknown's avatar
unknown committed
4794
  list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
4795 4796 4797 4798
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817
/*
  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
4818 4819
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
4820
					     LEX_STRING *alias,
unknown's avatar
unknown committed
4821 4822
					     ulong table_options,
					     thr_lock_type lock_type,
4823 4824
					     List<String> *use_index_arg,
					     List<String> *ignore_index_arg,
unknown's avatar
unknown committed
4825
                                             LEX_STRING *option)
unknown's avatar
unknown committed
4826 4827 4828 4829 4830 4831 4832 4833
{
  register TABLE_LIST *ptr;
  char *alias_str;
  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
4834
  if (check_table_name(table->table.str,table->table.length) ||
4835
      table->db.str && check_db_name(table->db.str))
unknown's avatar
unknown committed
4836
  {
4837
    net_printf(thd, ER_WRONG_TABLE_NAME, table->table.str);
unknown's avatar
unknown committed
4838 4839 4840 4841
    DBUG_RETURN(0);
  }

  if (!alias)					/* Alias is case sensitive */
4842 4843 4844 4845 4846 4847
  {
    if (table->sel)
    {
      net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
      DBUG_RETURN(0);
    }
4848
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
4849
      DBUG_RETURN(0);
4850
  }
unknown's avatar
unknown committed
4851
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
4852
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
4853
  if (table->db.str)
4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864
  {
    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
  {
4865 4866
    /* The following can't be "" as we may do 'casedn_str()' on it */
    ptr->db= empty_c_string;
4867 4868
    ptr->db_length= 0;
  }
4869 4870
  if (thd->current_arena->is_stmt_prepare())
    ptr->db= thd->strdup(ptr->db);
unknown's avatar
unknown committed
4871

4872
  ptr->alias= alias_str;
4873 4874
  if (lower_case_table_names && table->table.length)
    my_casedn_str(files_charset_info, table->table.str);
unknown's avatar
unknown committed
4875
  ptr->real_name=table->table.str;
4876
  ptr->real_name_length=table->table.length;
4877
  ptr->lock_type=   lock_type;
unknown's avatar
unknown committed
4878 4879
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
4880
  ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
4881
  ptr->derived=	    table->sel;
unknown's avatar
unknown committed
4882
  ptr->cacheable_table= 1;
4883 4884 4885 4886 4887 4888
  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
4889
  ptr->option= option ? option->str : 0;
unknown's avatar
unknown committed
4890
  /* check that used name is unique */
4891
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
4892
  {
4893
    for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
4894
	 tables ;
unknown's avatar
unknown committed
4895
	 tables=tables->next)
unknown's avatar
unknown committed
4896
    {
4897 4898
      if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
	  !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
4899
      {
4900
	net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
unknown's avatar
unknown committed
4901 4902
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
4903 4904
    }
  }
unknown's avatar
unknown committed
4905
  table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
unknown's avatar
unknown committed
4906 4907 4908
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
4909

unknown's avatar
unknown committed
4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922
/*
  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
4923
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
4924 4925 4926 4927 4928 4929
{
  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
unknown committed
4930
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
4931 4932 4933 4934 4935 4936 4937 4938 4939
       tables ;
       tables=tables->next)
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
4940

unknown's avatar
unknown committed
4941 4942
void add_join_on(TABLE_LIST *b,Item *expr)
{
4943
  if (expr)
4944
  {
4945 4946 4947 4948 4949 4950 4951 4952
    if (!b->on_expr)
      b->on_expr=expr;
    else
    {
      // This only happens if you have both a right and left join
      b->on_expr=new Item_cond_and(b->on_expr,expr);
    }
    b->on_expr->top_level_item();
4953
  }
unknown's avatar
unknown committed
4954 4955 4956
}


4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974
/*
  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
  
  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
4975 4976 4977 4978 4979
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
{
  b->natural_join=a;
}

4980
/*
4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997
  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
4998 4999
*/

5000 5001
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
                          bool *write_to_binlog)
unknown's avatar
unknown committed
5002 5003 5004
{
  bool result=0;
  select_errors=0;				/* Write if more errors */
5005
  bool tmp_write_to_binlog= 1;
unknown's avatar
SCRUM  
unknown committed
5006
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
5007 5008
  if (options & REFRESH_GRANT)
  {
5009
    acl_reload(thd);
unknown's avatar
unknown committed
5010
    grant_reload(thd);
5011
    if (mqh_used)
unknown's avatar
unknown committed
5012
      reset_mqh(thd,(LEX_USER *) NULL,TRUE);
unknown's avatar
unknown committed
5013
  }
unknown's avatar
SCRUM  
unknown committed
5014
#endif
unknown's avatar
unknown committed
5015 5016
  if (options & REFRESH_LOG)
  {
5017
    /*
unknown's avatar
unknown committed
5018 5019
      Flush the normal query log, the update log, the binary log,
      the slow query log, and the relay log (if it exists).
5020
    */
unknown's avatar
unknown committed
5021

unknown's avatar
unknown committed
5022 5023 5024 5025 5026
    /*
      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)
5027 5028
    */
    tmp_write_to_binlog= 0;
unknown's avatar
unknown committed
5029 5030 5031 5032
    mysql_log.new_file(1);
    mysql_update_log.new_file(1);
    mysql_bin_log.new_file(1);
    mysql_slow_log.new_file(1);
unknown's avatar
unknown committed
5033
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
5034
    if (mysql_bin_log.is_open() && expire_logs_days)
5035 5036 5037
    {
      long purge_time= time(0) - expire_logs_days*24*60*60;
      if (purge_time >= 0)
5038
	mysql_bin_log.purge_logs_before_date(purge_time);
5039
    }
5040
    pthread_mutex_lock(&LOCK_active_mi);
5041
    rotate_relay_log(active_mi);
5042
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
5043
#endif
unknown's avatar
unknown committed
5044 5045
    if (ha_flush_logs())
      result=1;
unknown's avatar
unknown committed
5046 5047
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
5048
  }
unknown's avatar
unknown committed
5049
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
5050 5051
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
5052
    query_cache.pack();				// FLUSH QUERY CACHE
unknown's avatar
unknown committed
5053 5054 5055 5056
    options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
5057
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
5058
  }
unknown's avatar
unknown committed
5059
#endif /*HAVE_QUERY_CACHE*/
5060 5061 5062 5063 5064
  /*
    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
5065
  {
5066
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
5067
    {
5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078
      /*
        We must not try to aspire a global read lock if we have a write
        locked table. This would lead to a deadlock when trying to
        reopen (and re-lock) the table after the flush.
      */
      if (thd->locked_tables)
      {
        THR_LOCK_DATA **lock_p= thd->locked_tables->locks;
        THR_LOCK_DATA **end_p= lock_p + thd->locked_tables->lock_count;

        for (; lock_p < end_p; lock_p++)
unknown's avatar
unknown committed
5079
        {
5080 5081 5082 5083 5084
          if ((*lock_p)->type == TL_WRITE)
          {
            my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
            return 1;
          }
unknown's avatar
unknown committed
5085
        }
5086
      }
unknown's avatar
unknown committed
5087 5088 5089 5090
      /*
	Writing to the binlog could cause deadlocks, as we don't log
	UNLOCK TABLES
      */
5091
      tmp_write_to_binlog= 0;
5092 5093
      if (lock_global_read_lock(thd))
	return 1;
5094 5095 5096
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
                                 tables);
      make_global_read_lock_block_commit(thd);
unknown's avatar
unknown committed
5097
    }
5098 5099
    else
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
unknown's avatar
unknown committed
5100
    my_dbopt_cleanup();
unknown's avatar
unknown committed
5101 5102 5103 5104 5105 5106 5107
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
  if (options & REFRESH_STATUS)
    refresh_status();
  if (options & REFRESH_THREADS)
    flush_thread_cache();
unknown's avatar
unknown committed
5108
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
5109
  if (options & REFRESH_MASTER)
5110 5111
  {
    tmp_write_to_binlog= 0;
5112 5113
    if (reset_master(thd))
      result=1;
5114
  }
5115
#endif
unknown's avatar
unknown committed
5116
#ifdef OPENSSL
5117 5118 5119 5120 5121 5122
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
unknown's avatar
unknown committed
5123
#ifdef HAVE_REPLICATION
5124 5125
 if (options & REFRESH_SLAVE)
 {
5126
   tmp_write_to_binlog= 0;
5127
   pthread_mutex_lock(&LOCK_active_mi);
5128
   if (reset_slave(thd, active_mi))
5129
     result=1;
5130
   pthread_mutex_unlock(&LOCK_active_mi);
5131
 }
5132
#endif
5133
 if (options & REFRESH_USER_RESOURCES)
5134
   reset_mqh(thd,(LEX_USER *) NULL);
5135 5136
 if (write_to_binlog)
   *write_to_binlog= tmp_write_to_binlog;
5137
 return result;
unknown's avatar
unknown committed
5138 5139
}

5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151
/*
  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
*/

5152
void kill_one_thread(THD *thd, ulong id)
unknown's avatar
unknown committed
5153 5154 5155
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
5156 5157
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
5158 5159 5160 5161
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
5162 5163
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
5164 5165 5166
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179
  if (tmp)
  {
    if ((thd->master_access & SUPER_ACL) ||
	!strcmp(thd->user,tmp->user))
    {
      tmp->awake(1 /*prepare to die*/);
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }

unknown's avatar
unknown committed
5180
  if (!error)
5181
    send_ok(thd);
unknown's avatar
unknown committed
5182
  else
5183
    net_printf(thd,error,id);
unknown's avatar
unknown committed
5184 5185
}

unknown's avatar
unknown committed
5186

unknown's avatar
unknown committed
5187 5188 5189 5190 5191 5192 5193 5194
/* 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)
5195
      *(ulong*) ptr->value= 0;
unknown's avatar
unknown committed
5196
  }
unknown's avatar
unknown committed
5197 5198
  /* Reset the counters of all key caches (default and named). */
  process_key_caches(reset_key_cache_counters);
unknown's avatar
unknown committed
5199 5200
  pthread_mutex_unlock(&LOCK_status);
}
5201 5202 5203 5204


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

unknown's avatar
unknown committed
5205 5206
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
			       const char *table_name)
5207
{
5208
  char buff[FN_REFLEN],*ptr, *end;
5209 5210 5211 5212 5213 5214 5215
  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))
  {
5216
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
5217 5218 5219 5220
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
5221
  end=convert_dirname(buff, *filename_ptr, NullS);
unknown's avatar
unknown committed
5222
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
5223 5224
    return 1;					// End of memory
  *filename_ptr=ptr;
5225
  strxmov(ptr,buff,table_name,NullS);
5226 5227
  return 0;
}
5228

5229

5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243
/*
  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;
5244
  if (thd->lex->current_select != &thd->lex->select_lex)
5245 5246
  {
    char command[80];
5247 5248
    strmake(command, thd->lex->yylval->symbol.str,
	    min(thd->lex->yylval->symbol.length, sizeof(command)-1));
5249
    net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
5250 5251 5252 5253
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
5254

unknown's avatar
unknown committed
5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273
/*
  Setup locking for multi-table updates. Used by the replication slave.
  Replication slave SQL thread examines (all_tables_not_ok()) the
  locking state of referenced tables to determine if the query has to
  be executed or ignored. Since in multi-table update, the 
  'default' lock is read-only, this lock is corrected early enough by
  calling this function, before the slave decides to execute/ignore.

  SYNOPSIS
    check_multi_update_lock()
    thd		Current thread
    tables	List of user-supplied tables
    fields	List of fields requiring update

  RETURN VALUES
    0	ok
    1	error
*/
static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables, 
unknown's avatar
unknown committed
5274
				    List<Item> *fields, SELECT_LEX *select_lex)
unknown's avatar
unknown committed
5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290
{
  bool res= 1;
  TABLE_LIST *table;
  DBUG_ENTER("check_multi_update_lock");
  
  if (check_db_used(thd, tables))
    goto error;

  /*
    Ensure that we have UPDATE or SELECT privilege for each table
    The exact privilege is checked in mysql_multi_update()
  */
  for (table= tables ; table ; table= table->next)
  {
    TABLE_LIST *save= table->next;
    table->next= 0;
unknown's avatar
unknown committed
5291 5292 5293
    if ((check_access(thd, UPDATE_ACL, table->db, &table->grant.privilege,0,1) ||
        (grant_option && check_grant(thd, UPDATE_ACL, table,0,1,1))) &&
	check_one_table_access(thd, SELECT_ACL, table))
unknown's avatar
unknown committed
5294 5295 5296 5297
	goto error;
    table->next= save;
  }
    
unknown's avatar
unknown committed
5298
  if (mysql_multi_update_lock(thd, tables, fields, select_lex))
unknown's avatar
unknown committed
5299 5300 5301 5302 5303 5304 5305
    goto error;
  
  res= 0;
  
error:
  DBUG_RETURN(res);
}
unknown's avatar
unknown committed
5306

unknown's avatar
unknown committed
5307

unknown's avatar
unknown committed
5308
Comp_creator *comp_eq_creator(bool invert)
unknown's avatar
unknown committed
5309
{
unknown's avatar
unknown committed
5310
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
unknown's avatar
unknown committed
5311 5312
}

unknown's avatar
unknown committed
5313

unknown's avatar
unknown committed
5314
Comp_creator *comp_ge_creator(bool invert)
unknown's avatar
unknown committed
5315
{
unknown's avatar
unknown committed
5316
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
unknown's avatar
unknown committed
5317 5318
}

unknown's avatar
unknown committed
5319

unknown's avatar
unknown committed
5320
Comp_creator *comp_gt_creator(bool invert)
unknown's avatar
unknown committed
5321
{
unknown's avatar
unknown committed
5322
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
unknown's avatar
unknown committed
5323 5324
}

unknown's avatar
unknown committed
5325

unknown's avatar
unknown committed
5326
Comp_creator *comp_le_creator(bool invert)
unknown's avatar
unknown committed
5327
{
unknown's avatar
unknown committed
5328
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
unknown's avatar
unknown committed
5329 5330
}

unknown's avatar
unknown committed
5331

unknown's avatar
unknown committed
5332
Comp_creator *comp_lt_creator(bool invert)
unknown's avatar
unknown committed
5333
{
unknown's avatar
unknown committed
5334
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
unknown's avatar
unknown committed
5335 5336
}

unknown's avatar
unknown committed
5337

unknown's avatar
unknown committed
5338
Comp_creator *comp_ne_creator(bool invert)
unknown's avatar
unknown committed
5339
{
unknown's avatar
unknown committed
5340
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
unknown's avatar
unknown committed
5341
}
unknown's avatar
unknown committed
5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361


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

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

  Item_allany_subselect *it=
5369
    new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all);
unknown's avatar
unknown committed
5370
  if (all)
5371
    return it->upper_item= new Item_func_not_all(it);	/* ALL */
unknown's avatar
unknown committed
5372

5373
  return it->upper_item= new Item_func_nop_all(it);      /* ANY/SOME */
unknown's avatar
unknown committed
5374
}
5375 5376


5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391
/*
  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.
*/

int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
{
  List<create_field> fields;
5392 5393 5394
  ALTER_INFO alter_info;
  alter_info.flags= ALTER_ADD_INDEX;
  alter_info.is_simple= 0;
5395 5396 5397 5398 5399 5400 5401
  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,
5402
				fields, keys, 0, (ORDER*)0,
5403
				DUP_ERROR, 0, &alter_info));
5404 5405 5406
}


5407
int mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
5408 5409 5410 5411 5412 5413 5414 5415
{
  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;
5416 5417 5418
  alter_info->clear();
  alter_info->flags= ALTER_DROP_INDEX;
  alter_info->is_simple= 0;
5419 5420
  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
				&create_info, table_list,
5421
				fields, keys, 0, (ORDER*)0,
5422
				DUP_ERROR, 0, alter_info));
5423
}
unknown's avatar
merge  
unknown committed
5424 5425


5426 5427 5428 5429 5430
/*
  Multi update query pre-check

  SYNOPSIS
    multi_update_precheck()
unknown's avatar
unknown committed
5431 5432
    thd		Thread handler
    tables	Global table list
5433

unknown's avatar
unknown committed
5434
  RETURN VALUE
unknown's avatar
unknown committed
5435 5436 5437
    0   OK
    1   Error (message is sent to user)
    -1  Error (message is not sent to user)
5438
*/
unknown's avatar
unknown committed
5439

5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459
int multi_update_precheck(THD *thd, TABLE_LIST *tables)
{
  DBUG_ENTER("multi_update_precheck");
  const char *msg= 0;
  TABLE_LIST *table;
  LEX *lex= thd->lex;
  SELECT_LEX *select_lex= &lex->select_lex;
  TABLE_LIST *update_list= (TABLE_LIST*)select_lex->table_list.first;

  if (select_lex->item_list.elements != lex->value_list.elements)
  {
    my_error(ER_WRONG_VALUE_COUNT, MYF(0));
    DBUG_RETURN(-1);
  }
  /*
    Ensure that we have UPDATE or SELECT privilege for each table
    The exact privilege is checked in mysql_multi_update()
  */
  for (table= update_list; table; table= table->next)
  {
5460 5461 5462 5463 5464 5465
    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)) &&
5466 5467
	(check_access(thd, SELECT_ACL, table->db,
		      &table->grant.privilege, 0, 0) ||
unknown's avatar
unknown committed
5468
	 grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
5469
      DBUG_RETURN(1);
unknown's avatar
unknown committed
5470 5471 5472 5473 5474

    /*
      We assign following flag only to copy of table, because it will
      be checked only if query contains subqueries i.e. only if copy exists
    */
5475
    if (table->table_list)
unknown's avatar
unknown committed
5476
      table->table_list->table_in_update_from_clause= 1;
5477
  }
unknown's avatar
unknown committed
5478 5479 5480
  /*
    Is there tables of subqueries?
  */
5481
  if (&lex->select_lex != lex->all_selects_list || lex->time_zone_tables_used)
5482
  {
5483
    DBUG_PRINT("info",("Checking sub query list"));
5484 5485
    for (table= tables; table; table= table->next)
    {
5486 5487 5488 5489
      if (my_tz_check_n_skip_implicit_tables(&table,
                                             lex->time_zone_tables_used))
        continue;
      else if (table->table_in_update_from_clause)
5490 5491 5492 5493 5494 5495 5496 5497 5498
      {
	/*
	  If we check table by local TABLE_LIST copy then we should copy
	  grants to global table list, because it will be used for table
	  opening.
	*/
	if (table->table_list)
	  table->grant= table->table_list->grant;
      }
5499
      else if (!table->derived)
5500 5501 5502
      {
	if (check_access(thd, SELECT_ACL, table->db,
			 &table->grant.privilege, 0, 0) ||
unknown's avatar
unknown committed
5503
	    grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526
	  DBUG_RETURN(1);
      }
    }
  }

  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);
    DBUG_RETURN(-1);
  }
  DBUG_RETURN(0);
}

/*
  Multi delete query pre-check

  SYNOPSIS
    multi_delete_precheck()
unknown's avatar
unknown committed
5527 5528 5529
    thd			Thread handler
    tables		Global table list
    table_count		Pointer to table counter
5530

unknown's avatar
unknown committed
5531
  RETURN VALUE
unknown's avatar
unknown committed
5532 5533 5534
    0   OK
    1   error (message is sent to user)
    -1  error (message is not sent to user)
5535
*/
unknown's avatar
unknown committed
5536

5537 5538 5539 5540 5541 5542 5543
int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
{
  DBUG_ENTER("multi_delete_precheck");
  SELECT_LEX *select_lex= &thd->lex->select_lex;
  TABLE_LIST *aux_tables=
    (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
  TABLE_LIST *delete_tables= (TABLE_LIST *)select_lex->table_list.first;
unknown's avatar
unknown committed
5544 5545 5546
  TABLE_LIST *target_tbl;

  *table_count= 0;
5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558

  /* 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))
    DBUG_RETURN(1);
  if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
  {
    my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, MYF(0));
    DBUG_RETURN(-1);
  }
unknown's avatar
unknown committed
5559
  for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next)
5560 5561 5562 5563 5564 5565
  {
    (*table_count)++;
    /* All tables in aux_tables must be found in FROM PART */
    TABLE_LIST *walk;
    for (walk= delete_tables; walk; walk= walk->next)
    {
unknown's avatar
unknown committed
5566 5567 5568
      if (!my_strcasecmp(table_alias_charset,
			 target_tbl->alias, walk->alias) &&
	  !strcmp(walk->db, target_tbl->db))
5569 5570 5571 5572
	break;
    }
    if (!walk)
    {
unknown's avatar
unknown committed
5573 5574
      my_error(ER_UNKNOWN_TABLE, MYF(0), target_tbl->real_name,
	       "MULTI DELETE");
5575 5576 5577 5578
      DBUG_RETURN(-1);
    }
    if (walk->derived)
    {
unknown's avatar
unknown committed
5579 5580
      my_error(ER_NON_UPDATABLE_TABLE, MYF(0), target_tbl->real_name,
	       "DELETE");
5581 5582
      DBUG_RETURN(-1);
    }
unknown's avatar
unknown committed
5583 5584
    walk->lock_type= target_tbl->lock_type;
    target_tbl->table_list= walk;	// Remember corresponding table
unknown's avatar
unknown committed
5585 5586 5587
    
    /* in case of subselects, we need to set lock_type in
     * corresponding table in list of all tables */
5588 5589 5590 5591 5592
    if (walk->table_list)
    {
      target_tbl->table_list= walk->table_list;
      walk->table_list->lock_type= walk->lock_type;
    }
5593 5594 5595 5596 5597
  }
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
5598 5599 5600 5601 5602
/*
  simple UPDATE query pre-check

  SYNOPSIS
    update_precheck()
unknown's avatar
unknown committed
5603 5604
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
5605 5606

  RETURN VALUE
unknown's avatar
unknown committed
5607 5608 5609
    0   OK
    1   Error (message is sent to user)
    -1  Error (message is not sent to user)
unknown's avatar
unknown committed
5610
*/
unknown's avatar
unknown committed
5611

unknown's avatar
unknown committed
5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629
int update_precheck(THD *thd, TABLE_LIST *tables)
{
  DBUG_ENTER("update_precheck");
  if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
  {
    my_error(ER_WRONG_VALUE_COUNT, MYF(0));
    DBUG_RETURN(-1);
  }
  DBUG_RETURN((check_db_used(thd, tables) ||
	       check_one_table_access(thd, UPDATE_ACL, tables)) ? 1 : 0);
}


/*
  simple DELETE query pre-check

  SYNOPSIS
    delete_precheck()
unknown's avatar
unknown committed
5630 5631
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
5632 5633

  RETURN VALUE
unknown's avatar
unknown committed
5634 5635 5636
    0   OK
    1   error (message is sent to user)
    -1  error (message is not sent to user)
unknown's avatar
unknown committed
5637
*/
unknown's avatar
unknown committed
5638

unknown's avatar
unknown committed
5639 5640 5641 5642 5643
int delete_precheck(THD *thd, TABLE_LIST *tables)
{
  DBUG_ENTER("delete_precheck");
  if (check_one_table_access(thd, DELETE_ACL, tables))
    DBUG_RETURN(1);
unknown's avatar
unknown committed
5644
  /* Set privilege for the WHERE clause */
unknown's avatar
unknown committed
5645 5646 5647 5648 5649 5650 5651 5652 5653 5654
  tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
  DBUG_RETURN(0);
}


/*
  simple INSERT query pre-check

  SYNOPSIS
    insert_precheck()
unknown's avatar
unknown committed
5655 5656
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
5657 5658

  RETURN VALUE
unknown's avatar
unknown committed
5659 5660 5661
    0   OK
    1   error (message is sent to user)
    -1  error (message is not sent to user)
unknown's avatar
unknown committed
5662
*/
unknown's avatar
unknown committed
5663

5664
int insert_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
5665 5666 5667 5668
{
  LEX *lex= thd->lex;
  DBUG_ENTER("insert_precheck");

unknown's avatar
unknown committed
5669 5670 5671 5672
  /*
    Check that we have modify privileges for the first table and
    select privileges for the rest
  */
5673 5674 5675
  ulong privilege= INSERT_ACL |
                   (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
                   (lex->duplicates == DUP_UPDATE ? UPDATE_ACL : 0);
unknown's avatar
unknown committed
5676 5677

  if (check_one_table_access(thd, privilege, tables))
5678
    DBUG_RETURN(1);
unknown's avatar
unknown committed
5679

unknown's avatar
unknown committed
5680
  if (lex->update_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
5681 5682 5683 5684
  {
    my_error(ER_WRONG_VALUE_COUNT, MYF(0));
    DBUG_RETURN(-1);
  }
5685 5686
  DBUG_RETURN(0);
}
unknown's avatar
unknown committed
5687 5688 5689 5690 5691 5692 5693


/*
  CREATE TABLE query pre-check

  SYNOPSIS
    create_table_precheck()
unknown's avatar
unknown committed
5694 5695 5696
    thd			Thread handler
    tables		Global table list
    create_table	Table which will be created
unknown's avatar
unknown committed
5697 5698

  RETURN VALUE
unknown's avatar
unknown committed
5699 5700
    0   OK
    1   Error (message is sent to user)
unknown's avatar
unknown committed
5701
*/
unknown's avatar
unknown committed
5702

unknown's avatar
unknown committed
5703 5704 5705 5706
int create_table_precheck(THD *thd, TABLE_LIST *tables,
			  TABLE_LIST *create_table)
{
  LEX *lex= thd->lex;
5707 5708 5709
  SELECT_LEX *select_lex= &lex->select_lex;
  ulong want_priv;
  int error= 1;                                 // Error message is given
unknown's avatar
unknown committed
5710
  DBUG_ENTER("create_table_precheck");
5711 5712 5713

  want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
              CREATE_TMP_ACL : CREATE_ACL);
unknown's avatar
unknown committed
5714 5715 5716 5717 5718 5719
  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))
5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763
    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 */

    /*
      For temporary tables or PREPARED STATEMETNS we don't have to check
      if the created table exists
    */
    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
        ! thd->current_arena->is_stmt_prepare() &&
        find_real_table_in_list(tables, create_table->db,
                                create_table->real_name))
    {
      net_printf(thd,ER_UPDATE_TABLE_USED, create_table->real_name);

      goto err;
    }
    if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
    {
      TABLE_LIST *tab;
      for (tab= tables; tab; tab= tab->next)
      {
        if (find_real_table_in_list((TABLE_LIST*) lex->create_info.
                                    merge_list.first,
                                    tables->db, tab->real_name))
        {
          net_printf(thd, ER_UPDATE_TABLE_USED, tab->real_name);
          goto err;
        }
      }  
    }    

    if (tables && check_table_access(thd, SELECT_ACL, tables,0))
      goto err;
  }
  error= 0;

err:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
5764
}
unknown's avatar
unknown committed
5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800


/*
  negate given expression

  SYNOPSIS
    negate_expression()
    thd  therad handler
    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);
}