sql_parse.cc 164 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);
62
static void log_slow_query(THD *thd);
unknown's avatar
unknown committed
63

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

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

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

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

unknown's avatar
unknown committed
97 98 99 100 101 102 103 104 105 106
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
  }
}

107

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


unknown's avatar
unknown committed
123
#ifdef HAVE_REPLICATION
124 125 126
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
127
          ((thd->lex->sql_command != SQLCOM_DELETE_MULTI) ||
unknown's avatar
unknown committed
128 129
           !tables_ok(thd,
		      (TABLE_LIST *)thd->lex->auxilliary_table_list.first)));
130
}
unknown's avatar
unknown committed
131
#endif
132 133


134 135
static HASH hash_user_connections;

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

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

148 149
  user_len=strlen(user);
  temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
150
  (void) pthread_mutex_lock(&LOCK_user_conn);
unknown's avatar
unknown committed
151 152
  if (!(uc = (struct  user_conn *) hash_search(&hash_user_connections,
					       (byte*) temp_user, temp_len)))
153
  {
unknown's avatar
unknown committed
154 155 156
    /* 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
157 158
			 MYF(MY_WME)))))
    {
159
      send_error(thd, 0, NullS);		// Out of memory
160 161
      return_val=1;
      goto end;
unknown's avatar
unknown committed
162
    }
163 164
    uc->user=(char*) (uc+1);
    memcpy(uc->user,temp_user,temp_len+1);
165 166
    uc->user_len= user_len;
    uc->host=uc->user + uc->user_len +  1;
167
    uc->len = temp_len;
168 169 170
    uc->connections = 1;
    uc->questions=uc->updates=uc->conn_per_hour=0;
    uc->user_resources=*mqh;
unknown's avatar
unknown committed
171
    if (max_user_connections && mqh->connections > max_user_connections)
172
      uc->user_resources.connections = max_user_connections;
173
    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 179 180 181 182
      return_val=1;
      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 1347
  /*
    Commands which will always take a long time should be marked with
    this so that they will not get logged to the slow query log
  */
1348
  thd->slow_command=FALSE;
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->slow_command= TRUE;
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 1519
      log_slow_query(thd);

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->slow_command = TRUE;
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 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847
  log_slow_query(thd);

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


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

1851
  /* If not reading from backup and if the query took too long */
1852
  if (!thd->slow_command && !thd->user_time) // do not log 'slow_command' queries
unknown's avatar
unknown committed
1853
  {
1854 1855
    thd->proc_info="logging slow query";

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

1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885

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

  /* Reclaim some memory */
  thd->packet.shrink(thd->variables.net_buffer_length);
  thd->convert_buffer.shrink(thd->variables.net_buffer_length);
1912 1913 1914 1915 1916 1917

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

unknown's avatar
unknown committed
1918 1919 1920 1921 1922 1923
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/

void
1924
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
1925
{
1926
  int	res= 0;
1927
  LEX	*lex= thd->lex;
unknown's avatar
unknown committed
1928 1929
  bool slave_fake_lock= 0;
  MYSQL_LOCK *fake_prev_lock= 0;
unknown's avatar
unknown committed
1930
  SELECT_LEX *select_lex= &lex->select_lex;
1931
  TABLE_LIST *tables= (TABLE_LIST*) select_lex->table_list.first;
1932
  SELECT_LEX_UNIT *unit= &lex->unit;
unknown's avatar
unknown committed
1933 1934
  DBUG_ENTER("mysql_execute_command");

1935 1936 1937 1938 1939 1940
  /*
    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.
  */
1941
  if (tables || &lex->select_lex != lex->all_selects_list)
1942 1943
    mysql_reset_errors(thd);

unknown's avatar
SCRUM  
unknown committed
1944
#ifdef HAVE_REPLICATION
1945 1946
  if (thd->slave_thread)
  {
unknown's avatar
unknown committed
1947
    if (lex->sql_command == SQLCOM_UPDATE_MULTI)
unknown's avatar
unknown committed
1948 1949 1950
    {
      DBUG_PRINT("info",("need faked locked tables"));
      
unknown's avatar
unknown committed
1951 1952
      if (check_multi_update_lock(thd, tables, &select_lex->item_list,
				  select_lex))
unknown's avatar
unknown committed
1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963
        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
1964
    /*
unknown's avatar
merge  
unknown committed
1965
      Skip if we are in the slave thread, some table rules have been
1966 1967 1968 1969
      given and the table list says the query should not be replicated.
      Exception is 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
1970
    */
1971 1972 1973
    if (!(lex->sql_command == SQLCOM_DROP_TABLE &&
          lex->drop_temporary && lex->drop_if_exists) &&
        all_tables_not_ok(thd,tables))
unknown's avatar
unknown committed
1974 1975 1976
    {
      /* we warn the slave SQL thread */
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
1977
      DBUG_VOID_RETURN;
unknown's avatar
unknown committed
1978
    }
unknown's avatar
merge  
unknown committed
1979 1980
#ifndef TO_BE_DELETED
    /*
1981 1982 1983
      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
1984
    */
1985 1986 1987
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
unknown's avatar
unknown committed
1988
      lex->insert_list = &select_lex->item_list;
1989
    }
unknown's avatar
merge  
unknown committed
1990
#endif
1991
  }
unknown's avatar
unknown committed
1992
#endif /* !HAVE_REPLICATION */
unknown's avatar
unknown committed
1993 1994 1995 1996

  /* 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. */
1997 1998
  if ((&lex->select_lex != lex->all_selects_list ||
       lex->time_zone_tables_used) &&
1999
      lex->unit.create_total_list(thd, lex, &tables))
2000
    DBUG_VOID_RETURN;
2001

2002 2003 2004 2005 2006
  /*
    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
2007
      !(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
2008 2009
      (uc_update_queries[lex->sql_command] > 0))
  {
unknown's avatar
unknown committed
2010
    net_printf(thd, ER_OPTION_PREVENTS_STATEMENT, "--read-only");
2011 2012
    DBUG_VOID_RETURN;
  }
2013

unknown's avatar
unknown committed
2014
  statistic_increment(com_stat[lex->sql_command],&LOCK_status);
unknown's avatar
unknown committed
2015 2016 2017
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
2018 2019 2020 2021 2022 2023 2024
    /* 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;
    }

2025
    select_result *result=lex->result;
unknown's avatar
unknown committed
2026 2027 2028 2029 2030
    if (tables)
    {
      res=check_table_access(thd,
			     lex->exchange ? SELECT_ACL | FILE_ACL :
			     SELECT_ACL,
unknown's avatar
unknown committed
2031
			     tables,0);
unknown's avatar
unknown committed
2032 2033 2034
    }
    else
      res=check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
unknown's avatar
unknown committed
2035
		       any_db,0,0,0);
unknown's avatar
unknown committed
2036 2037 2038 2039 2040
    if (res)
    {
      res=0;
      break;					// Error message is given
    }
2041 2042 2043 2044
    /* 
       In case of single SELECT unit->global_parameters points on first SELECT
       TODO: move counters to SELECT_LEX
    */
2045 2046 2047
    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
2048
    if (unit->select_limit_cnt <
2049
	(ha_rows) unit->global_parameters->select_limit)
2050
      unit->select_limit_cnt= HA_POS_ERROR;		// no limit
2051
    if (unit->select_limit_cnt == HA_POS_ERROR && !select_lex->next_select())
2052
      select_lex->options&= ~OPTION_FOUND_ROWS;
unknown's avatar
unknown committed
2053 2054

    if (!(res=open_and_lock_tables(thd,tables)))
unknown's avatar
unknown committed
2055
    {
unknown's avatar
unknown committed
2056
      if (lex->describe)
unknown's avatar
unknown committed
2057
      {
2058 2059 2060 2061 2062 2063 2064
	if (!(result= new select_send()))
	{
	  send_error(thd, ER_OUT_OF_RESOURCES);
	  DBUG_VOID_RETURN;
	}
	else
	  thd->send_explain_fields(result);
2065
	res= mysql_explain_union(thd, &thd->lex->unit, result);
unknown's avatar
unknown committed
2066 2067 2068 2069 2070
	if (lex->describe & DESCRIBE_EXTENDED)
	{
	  char buff[1024];
	  String str(buff,(uint32) sizeof(buff), system_charset_info);
	  str.length(0);
2071
	  thd->lex->unit.print(&str);
unknown's avatar
unknown committed
2072 2073 2074 2075
	  str.append('\0');
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
		       ER_YES, str.ptr());
	}
2076
	result->send_eof();
2077
        delete result;
unknown's avatar
unknown committed
2078 2079 2080
      }
      else
      {
2081
	if (!result && !(result= new select_send()))
unknown's avatar
unknown committed
2082
	{
2083 2084
	  res= -1;
	  break;
unknown's avatar
unknown committed
2085
	}
unknown's avatar
unknown committed
2086
	query_cache_store_query(thd, tables);
2087 2088 2089
	res= handle_select(thd, lex, result);
        if (result != lex->result)
          delete result;
unknown's avatar
unknown committed
2090
      }
unknown's avatar
unknown committed
2091
    }
unknown's avatar
unknown committed
2092 2093
    break;
  }
unknown's avatar
unknown committed
2094
  case SQLCOM_PREPARE:
2095
  {
2096 2097 2098 2099
    char *query_str;
    uint query_len;
    if (lex->prepared_stmt_code_is_varref)
    {
2100
      /* This is PREPARE stmt FROM @var. */
2101 2102 2103 2104
      String str;
      CHARSET_INFO *to_cs= thd->variables.collation_connection;
      bool need_conversion;
      user_var_entry *entry;
2105
      String *pstr= &str;
2106
      uint32 unused;
2107
      /*
2108 2109 2110
        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.
2111
      */
2112 2113
      if ((entry=
             (user_var_entry*)hash_search(&thd->user_vars,
2114 2115 2116 2117
                                          (byte*)lex->prepared_stmt_code.str,
                                          lex->prepared_stmt_code.length))
          && entry->value)
      {
2118 2119
        my_bool is_var_null;
        pstr= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC);
2120 2121 2122 2123
        /*
          NULL value of variable checked early as entry->value so here
          we can't get NULL in normal conditions
        */
2124 2125
        DBUG_ASSERT(!is_var_null);
        if (!pstr)
2126 2127 2128 2129
        {
          res= -1;
          break;      // EOM (error should be reported by allocator)
        }
2130 2131
      }
      else
2132 2133 2134 2135 2136
      {
        /*
          variable absent or equal to NULL, so we need to set variable to
          something reasonable to get readable error message during parsing
        */
2137
        str.set("NULL", 4, &my_charset_latin1);
2138 2139
      }

2140
      need_conversion=
2141 2142
        String::needs_conversion(pstr->length(), pstr->charset(),
                                 to_cs, &unused);
2143

2144 2145
      query_len= need_conversion? (pstr->length() * to_cs->mbmaxlen) :
                                  pstr->length();
unknown's avatar
unknown committed
2146
      if (!(query_str= alloc_root(thd->mem_root, query_len+1)))
2147 2148 2149 2150
      {
        res= -1;
        break;        // EOM (error should be reported by allocator)
      }
2151

2152
      if (need_conversion)
2153 2154 2155 2156 2157 2158
      {
        uint dummy_errors;
        query_len= copy_and_convert(query_str, query_len, to_cs,
                                    pstr->ptr(), pstr->length(),
                                    pstr->charset(), &dummy_errors);
      }
2159
      else
2160
        memcpy(query_str, pstr->ptr(), pstr->length());
2161
      query_str[query_len]= 0;
2162 2163 2164
    }
    else
    {
2165 2166
      query_str= lex->prepared_stmt_code.str;
      query_len= lex->prepared_stmt_code.length;
2167
      DBUG_PRINT("info", ("PREPARE: %.*s FROM '%.*s' \n",
2168 2169
                          lex->prepared_stmt_name.length,
                          lex->prepared_stmt_name.str,
2170
                          query_len, query_str));
2171
    }
unknown's avatar
unknown committed
2172
    thd->command= COM_PREPARE;
2173 2174
    if (!mysql_stmt_prepare(thd, query_str, query_len + 1,
                            &lex->prepared_stmt_name))
unknown's avatar
unknown committed
2175 2176 2177 2178 2179
      send_ok(thd, 0L, 0L, "Statement prepared");
    break;
  }
  case SQLCOM_EXECUTE:
  {
2180
    DBUG_PRINT("info", ("EXECUTE: %.*s\n",
2181 2182 2183
                        lex->prepared_stmt_name.length,
                        lex->prepared_stmt_name.str));
    mysql_sql_stmt_execute(thd, &lex->prepared_stmt_name);
unknown's avatar
unknown committed
2184 2185 2186 2187 2188
    lex->prepared_stmt_params.empty();
    break;
  }
  case SQLCOM_DEALLOCATE_PREPARE:
  {
2189 2190 2191 2192 2193
    Statement* stmt;
    DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", 
                        lex->prepared_stmt_name.length,
                        lex->prepared_stmt_name.str));
    if ((stmt= thd->stmt_map.find_by_name(&lex->prepared_stmt_name)))
unknown's avatar
unknown committed
2194
    {
2195 2196
      thd->stmt_map.erase(stmt);
      send_ok(thd);
unknown's avatar
unknown committed
2197
    }
2198
    else
2199 2200 2201 2202 2203 2204
    {
      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
2205 2206
    break;
  }
unknown's avatar
unknown committed
2207
  case SQLCOM_DO:
unknown's avatar
unknown committed
2208
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
unknown's avatar
unknown committed
2209 2210 2211 2212 2213 2214
		   (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
2215 2216
    break;

2217
  case SQLCOM_EMPTY_QUERY:
2218
    send_ok(thd);
2219 2220
    break;

unknown's avatar
unknown committed
2221 2222 2223 2224
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

2225
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2226
  case SQLCOM_PURGE:
2227
  {
unknown's avatar
unknown committed
2228
    if (check_global_access(thd, SUPER_ACL))
2229
      goto error;
2230
    // PURGE MASTER LOGS TO 'file'
2231 2232 2233
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
2234 2235 2236 2237 2238 2239 2240 2241
  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;
  }
2242
#endif
unknown's avatar
unknown committed
2243 2244
  case SQLCOM_SHOW_WARNS:
  {
2245 2246
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
2247 2248 2249
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
unknown's avatar
unknown committed
2250 2251 2252 2253
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
2254 2255
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
2256 2257
    break;
  }
unknown's avatar
unknown committed
2258 2259
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
2260
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2261
      goto error;
2262
    /* This query don't work now. See comment in repl_failsafe.cc */
unknown's avatar
unknown committed
2263
#ifndef WORKING_NEW_MASTER
2264
    net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
unknown's avatar
unknown committed
2265 2266
    res= 1;
#else
unknown's avatar
unknown committed
2267
    res = show_new_master(thd);
unknown's avatar
unknown committed
2268
#endif
unknown's avatar
unknown committed
2269 2270
    break;
  }
2271

unknown's avatar
unknown committed
2272
#ifdef HAVE_REPLICATION
2273 2274
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
2275
    if (check_global_access(thd, REPL_SLAVE_ACL))
2276 2277 2278 2279
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
2280 2281
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
2282
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2283 2284 2285 2286
      goto error;
    res = show_binlog_events(thd);
    break;
  }
2287 2288
#endif

unknown's avatar
unknown committed
2289
  case SQLCOM_BACKUP_TABLE:
2290 2291
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
2292
	check_table_access(thd,SELECT_ACL, tables,0) ||
unknown's avatar
unknown committed
2293
	check_global_access(thd, FILE_ACL))
2294
      goto error; /* purecov: inspected */
2295
    thd->slow_command=TRUE;
2296
    res = mysql_backup_table(thd, tables);
unknown's avatar
unknown committed
2297

2298 2299
    break;
  }
unknown's avatar
unknown committed
2300
  case SQLCOM_RESTORE_TABLE:
2301 2302
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
2303
	check_table_access(thd, INSERT_ACL, tables,0) ||
unknown's avatar
unknown committed
2304
	check_global_access(thd, FILE_ACL))
2305
      goto error; /* purecov: inspected */
2306
    thd->slow_command=TRUE;
2307 2308 2309
    res = mysql_restore_table(thd, tables);
    break;
  }
unknown's avatar
unknown committed
2310 2311 2312
  case SQLCOM_ASSIGN_TO_KEYCACHE:
  {
    if (check_db_used(thd, tables) ||
unknown's avatar
unknown committed
2313 2314
        check_access(thd, INDEX_ACL, tables->db,
                     &tables->grant.privilege, 0, 0))
unknown's avatar
unknown committed
2315
      goto error;
2316
    res= mysql_assign_to_keycache(thd, tables, &lex->name_and_length);
unknown's avatar
unknown committed
2317 2318
    break;
  }
unknown's avatar
unknown committed
2319 2320 2321
  case SQLCOM_PRELOAD_KEYS:
  {
    if (check_db_used(thd, tables) ||
unknown's avatar
unknown committed
2322 2323
	check_access(thd, INDEX_ACL, tables->db,
                     &tables->grant.privilege, 0, 0))
2324
      goto error;
unknown's avatar
unknown committed
2325 2326 2327
    res = mysql_preload_keys(thd, tables);
    break;
  }
unknown's avatar
unknown committed
2328
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2329
  case SQLCOM_CHANGE_MASTER:
2330
  {
unknown's avatar
unknown committed
2331
    if (check_global_access(thd, SUPER_ACL))
2332
      goto error;
2333
    pthread_mutex_lock(&LOCK_active_mi);
2334
    res = change_master(thd,active_mi);
2335
    pthread_mutex_unlock(&LOCK_active_mi);
2336 2337
    break;
  }
unknown's avatar
unknown committed
2338
  case SQLCOM_SHOW_SLAVE_STAT:
2339
  {
2340 2341
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2342
      goto error;
2343
    pthread_mutex_lock(&LOCK_active_mi);
2344
    res = show_master_info(thd,active_mi);
2345
    pthread_mutex_unlock(&LOCK_active_mi);
2346 2347
    break;
  }
unknown's avatar
unknown committed
2348
  case SQLCOM_SHOW_MASTER_STAT:
2349
  {
2350 2351
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2352 2353 2354 2355
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
2356

2357
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
2358
    if (check_global_access(thd, SUPER_ACL))
2359
      goto error;
2360 2361 2362 2363
    if (end_active_trans(thd))
      res= -1;
    else
      res = load_master_data(thd);
2364
    break;
unknown's avatar
unknown committed
2365
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
2366 2367 2368
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
2369
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2370 2371 2372 2373 2374
	goto error;
      res = innodb_show_status(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
2375
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2376
  case SQLCOM_LOAD_MASTER_TABLE:
2377
  {
unknown's avatar
unknown committed
2378 2379
    if (!tables->db)
      tables->db=thd->db;
unknown's avatar
unknown committed
2380
    if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege,0,0))
unknown's avatar
unknown committed
2381 2382 2383 2384
      goto error;				/* purecov: inspected */
    if (grant_option)
    {
      /* Check that the first table has CREATE privilege */
unknown's avatar
unknown committed
2385
      if (check_grant(thd, CREATE_ACL, tables, 0, 1, 0))
2386
	goto error;
unknown's avatar
unknown committed
2387
    }
2388
    if (strlen(tables->real_name) > NAME_LEN)
unknown's avatar
unknown committed
2389
    {
2390
      net_printf(thd,ER_WRONG_TABLE_NAME, tables->real_name);
unknown's avatar
unknown committed
2391 2392
      break;
    }
2393
    pthread_mutex_lock(&LOCK_active_mi);
2394 2395 2396 2397
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
2398
    if (!fetch_master_table(thd, tables->db, tables->real_name,
2399
			    active_mi, 0, 0))
2400
    {
2401
      send_ok(thd);
2402
    }
2403
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2404
    break;
2405
  }
unknown's avatar
unknown committed
2406
#endif /* HAVE_REPLICATION */
2407

unknown's avatar
unknown committed
2408
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
2409
  {
unknown's avatar
unknown committed
2410
    /* Skip first table, which is the table we are creating */
2411 2412 2413
    TABLE_LIST *create_table, *create_table_local;
    tables= lex->unlink_first_table(tables, &create_table,
				    &create_table_local);
unknown's avatar
unknown committed
2414

unknown's avatar
unknown committed
2415 2416 2417
    if ((res= create_table_precheck(thd, tables, create_table)))
      goto unsent_create_error;

2418 2419 2420
#ifndef HAVE_READLINK
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
2421
    /* Fix names if symlinked tables */
unknown's avatar
unknown committed
2422
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
unknown's avatar
unknown committed
2423
			   create_table->real_name) ||
unknown's avatar
unknown committed
2424
	append_file_to_dir(thd,&lex->create_info.index_file_name,
unknown's avatar
unknown committed
2425
			   create_table->real_name))
2426 2427
    {
      res=-1;
2428
      goto unsent_create_error;
2429
    }
2430
#endif
2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443
    /*
      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;
    }
2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459
    /*
      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;
2460
      goto unsent_create_error;
2461
    }
2462
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
2463 2464 2465
    {
      select_result *result;

2466
      select_lex->options|= SELECT_NO_UNLOCK;
2467 2468 2469 2470
      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
2471
	unit->select_limit_cnt= HA_POS_ERROR;	// No limit
2472

unknown's avatar
unknown committed
2473
      if (!(res=open_and_lock_tables(thd,tables)))
2474
      {
unknown's avatar
unknown committed
2475 2476 2477 2478
	res= -1;				// If error
        if ((result=new select_create(create_table->db,
                                      create_table->real_name,
				      &lex->create_info,
2479 2480
                                      lex->create_list,
                                      lex->key_list,
2481 2482
                                      select_lex->item_list, lex->duplicates,
                                      lex->ignore)))
2483 2484 2485 2486 2487 2488
        {
          /*
            CREATE from SELECT give its SELECT_LEX for SELECT,
            and item_list belong to SELECT
          */
          select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
2489
          res=handle_select(thd, lex, result);
2490 2491
          select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE;
        }
2492 2493 2494
	//reset for PS
	lex->create_list.empty();
	lex->key_list.empty();
2495 2496
      }
    }
unknown's avatar
unknown committed
2497 2498
    else // regular create
    {
unknown's avatar
unknown committed
2499
      if (lex->name)
unknown's avatar
unknown committed
2500
        res= mysql_create_like_table(thd, create_table, &lex->create_info, 
unknown's avatar
unknown committed
2501 2502
                                     (Table_ident *)lex->name); 
      else
2503
      {
unknown's avatar
unknown committed
2504 2505
        res= mysql_create_table(thd,create_table->db,
			         create_table->real_name, &lex->create_info,
unknown's avatar
unknown committed
2506
			         lex->create_list,
2507
			         lex->key_list,0,0);
2508
      }
unknown's avatar
unknown committed
2509
      if (!res)
2510
	send_ok(thd);
unknown's avatar
unknown committed
2511
    }
2512 2513 2514 2515 2516
    /*
      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);
2517

2518 2519
unsent_create_error:
    // put tables back for PS rexecuting
2520 2521
    tables= lex->link_first_table_back(tables, create_table,
				       create_table_local);
unknown's avatar
unknown committed
2522
    break;
unknown's avatar
unknown committed
2523
  }
unknown's avatar
unknown committed
2524
  case SQLCOM_CREATE_INDEX:
unknown's avatar
unknown committed
2525
    if (check_one_table_access(thd, INDEX_ACL, tables))
unknown's avatar
unknown committed
2526
      goto error; /* purecov: inspected */
2527
    thd->slow_command=TRUE;
2528 2529 2530 2531
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_create_index(thd, tables, lex->key_list);
unknown's avatar
unknown committed
2532 2533
    break;

unknown's avatar
unknown committed
2534
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2535
  case SQLCOM_SLAVE_START:
2536
  {
2537
    pthread_mutex_lock(&LOCK_active_mi);
2538
    start_slave(thd,active_mi,1 /* net report*/);
2539
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2540
    break;
2541
  }
unknown's avatar
unknown committed
2542
  case SQLCOM_SLAVE_STOP:
2543 2544 2545 2546 2547 2548
  /*
    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,
2549
      so it waits for the client thread because t is locked by it.
2550
    - then the client thread does SLAVE STOP.
2551 2552
      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.
2553 2554 2555 2556 2557
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
  if (thd->locked_tables || thd->active_transaction())
  {
2558
    send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
2559
    break;
2560
  }
2561
  {
2562
    pthread_mutex_lock(&LOCK_active_mi);
2563
    stop_slave(thd,active_mi,1/* net report*/);
2564
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2565
    break;
2566
  }
unknown's avatar
unknown committed
2567
#endif /* HAVE_REPLICATION */
2568

unknown's avatar
unknown committed
2569 2570
  case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
2571
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
2572 2573 2574
    break;
#else
    {
unknown's avatar
unknown committed
2575
      ulong priv=0;
unknown's avatar
unknown committed
2576
      if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
unknown's avatar
unknown committed
2577
      {
2578
	net_printf(thd, ER_WRONG_TABLE_NAME, lex->name);
unknown's avatar
unknown committed
2579
	res= 1;
unknown's avatar
unknown committed
2580 2581
	break;
      }
2582 2583
      if (!select_lex->db)
	select_lex->db=tables->db;
unknown's avatar
unknown committed
2584 2585
      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
2586
	  check_merge_table_access(thd, tables->db,
2587 2588 2589
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
2590 2591
      if (grant_option)
      {
unknown's avatar
unknown committed
2592
	if (check_grant(thd, ALTER_ACL, tables, 0, UINT_MAX, 0))
unknown's avatar
unknown committed
2593 2594 2595 2596 2597 2598
	  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;
2599
	  tmp_table.db=select_lex->db;
unknown's avatar
unknown committed
2600
	  tmp_table.grant.privilege=priv;
unknown's avatar
unknown committed
2601 2602
	  if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
			  UINT_MAX, 0))
unknown's avatar
unknown committed
2603 2604 2605
	    goto error;
	}
      }
2606 2607
      /* 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
2608
      /* ALTER TABLE ends previous transaction */
2609
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2610 2611
	res= -1;
      else
unknown's avatar
unknown committed
2612
      {
2613
        thd->slow_command=TRUE;
2614
	res= mysql_alter_table(thd, select_lex->db, lex->name,
unknown's avatar
unknown committed
2615 2616
			       &lex->create_info,
			       tables, lex->create_list,
2617
			       lex->key_list,
2618
			       select_lex->order_list.elements,
2619
                               (ORDER *) select_lex->order_list.first,
2620
			       lex->duplicates, lex->ignore, &lex->alter_info);
unknown's avatar
unknown committed
2621
      }
unknown's avatar
unknown committed
2622 2623
      break;
    }
unknown's avatar
unknown committed
2624
#endif /*DONT_ALLOW_SHOW_COMMANDS*/
unknown's avatar
unknown committed
2625
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
2626 2627 2628
  {
    TABLE_LIST *table;
    if (check_db_used(thd,tables))
unknown's avatar
unknown committed
2629
      goto error;
unknown's avatar
unknown committed
2630 2631
    for (table=tables ; table ; table=table->next->next)
    {
unknown's avatar
unknown committed
2632
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
unknown's avatar
unknown committed
2633
		       &table->grant.privilege,0,0) ||
unknown's avatar
unknown committed
2634
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next->db,
unknown's avatar
unknown committed
2635
		       &table->next->grant.privilege,0,0))
unknown's avatar
unknown committed
2636 2637 2638
	goto error;
      if (grant_option)
      {
unknown's avatar
unknown committed
2639
	TABLE_LIST old_list,new_list;
unknown's avatar
unknown committed
2640 2641 2642 2643
	/*
	  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
2644 2645 2646
	old_list=table[0];
	new_list=table->next[0];
	old_list.next=new_list.next=0;
unknown's avatar
unknown committed
2647
	if (check_grant(thd, ALTER_ACL, &old_list, 0, UINT_MAX, 0) ||
unknown's avatar
unknown committed
2648
	    (!test_all_bits(table->next->grant.privilege,
2649
			    INSERT_ACL | CREATE_ACL) &&
unknown's avatar
unknown committed
2650 2651
	     check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0,
			 UINT_MAX, 0)))
unknown's avatar
unknown committed
2652 2653 2654
	  goto error;
      }
    }
unknown's avatar
unknown committed
2655
    query_cache_invalidate3(thd, tables, 0);
2656 2657 2658
    if (end_active_trans(thd))
      res= -1;
    else if (mysql_rename_tables(thd,tables))
unknown's avatar
unknown committed
2659 2660
      res= -1;
    break;
unknown's avatar
unknown committed
2661
  }
2662
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2663 2664
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2665
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
2666 2667 2668
    DBUG_VOID_RETURN;
#else
    {
unknown's avatar
unknown committed
2669
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2670 2671 2672 2673
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
2674
#endif
2675
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2676
  case SQLCOM_SHOW_CREATE:
unknown's avatar
unknown committed
2677
#ifdef DONT_ALLOW_SHOW_COMMANDS
2678
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
2679 2680
    DBUG_VOID_RETURN;
#else
unknown's avatar
unknown committed
2681
    {
unknown's avatar
unknown committed
2682 2683
      if (check_db_used(thd, tables) ||
	  check_access(thd, SELECT_ACL | EXTRA_ACL, tables->db,
unknown's avatar
unknown committed
2684
		       &tables->grant.privilege,0,0))
unknown's avatar
unknown committed
2685
	goto error;
2686 2687 2688
      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
2689 2690
      break;
    }
unknown's avatar
unknown committed
2691
#endif
2692 2693 2694
  case SQLCOM_CHECKSUM:
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
2695
	check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
2696
      goto error; /* purecov: inspected */
2697
    res = mysql_checksum_table(thd, tables, &lex->check_opt);
2698 2699
    break;
  }
unknown's avatar
unknown committed
2700
  case SQLCOM_REPAIR:
2701 2702
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
2703
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
2704
      goto error; /* purecov: inspected */
2705
    thd->slow_command=TRUE;
2706
    res = mysql_repair_table(thd, tables, &lex->check_opt);
2707 2708 2709 2710 2711 2712
    /* ! 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
2713
	thd->clear_error(); // No binlog error generated
2714
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
2715 2716 2717
        mysql_bin_log.write(&qinfo);
      }
    }
2718 2719
    break;
  }
unknown's avatar
unknown committed
2720
  case SQLCOM_CHECK:
2721 2722
  {
    if (check_db_used(thd,tables) ||
2723
	check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
2724
      goto error; /* purecov: inspected */
2725
    thd->slow_command=TRUE;
2726 2727 2728
    res = mysql_check_table(thd, tables, &lex->check_opt);
    break;
  }
unknown's avatar
unknown committed
2729 2730
  case SQLCOM_ANALYZE:
  {
unknown's avatar
unknown committed
2731
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
2732
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
unknown's avatar
unknown committed
2733
      goto error; /* purecov: inspected */
2734
    thd->slow_command=TRUE;
2735
    res = mysql_analyze_table(thd, tables, &lex->check_opt);
2736 2737 2738 2739 2740 2741
    /* ! 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
2742
	thd->clear_error(); // No binlog error generated
2743
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
2744 2745 2746
        mysql_bin_log.write(&qinfo);
      }
    }
unknown's avatar
unknown committed
2747
    break;
unknown's avatar
unknown committed
2748
  }
2749

unknown's avatar
unknown committed
2750 2751
  case SQLCOM_OPTIMIZE:
  {
2752
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
2753
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
unknown's avatar
unknown committed
2754
      goto error; /* purecov: inspected */
2755
    thd->slow_command=TRUE;
2756 2757 2758
    res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
      mysql_recreate_table(thd, tables, 1) :
      mysql_optimize_table(thd, tables, &lex->check_opt);
2759 2760 2761 2762 2763 2764
    /* ! 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
2765
	thd->clear_error(); // No binlog error generated
2766
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
2767 2768 2769
        mysql_bin_log.write(&qinfo);
      }
    }
unknown's avatar
unknown committed
2770 2771 2772
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
unknown committed
2773 2774
    if (update_precheck(thd, tables))
      break;
2775 2776 2777 2778
    res= mysql_update(thd,tables,
                      select_lex->item_list,
                      lex->value_list,
                      select_lex->where,
2779
		      select_lex->order_list.elements,
2780 2781
                      (ORDER *) select_lex->order_list.first,
                      select_lex->select_limit,
2782
                      lex->duplicates, lex->ignore);
unknown's avatar
unknown committed
2783 2784
    if (thd->net.report_error)
      res= -1;
2785 2786
    break;
  case SQLCOM_UPDATE_MULTI:
unknown's avatar
unknown committed
2787
  {
2788
    if ((res= multi_update_precheck(thd, tables)))
unknown's avatar
unknown committed
2789 2790 2791 2792 2793 2794
      break;
    res= mysql_multi_update(thd,tables,
			    &select_lex->item_list,
			    &lex->value_list,
			    select_lex->where,
			    select_lex->options,
2795
			    lex->duplicates, lex->ignore, unit, select_lex);
unknown's avatar
unknown committed
2796
    break;
unknown's avatar
unknown committed
2797
  }
unknown's avatar
unknown committed
2798
  case SQLCOM_REPLACE:
2799 2800
  case SQLCOM_INSERT:
  {
2801
    if ((res= insert_precheck(thd, tables)))
unknown's avatar
unknown committed
2802
      break;
2803 2804 2805
    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
2806 2807
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2808
    break;
2809
  }
unknown's avatar
unknown committed
2810 2811 2812
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
2813
    TABLE_LIST *first_local_table= (TABLE_LIST *) select_lex->table_list.first;
unknown's avatar
unknown committed
2814
    if ((res= insert_precheck(thd, tables)))
2815
      break;
unknown's avatar
unknown committed
2816

2817 2818
    /* Fix lock for first table */
    if (tables->lock_type == TL_WRITE_DELAYED)
2819
      tables->lock_type= TL_WRITE;
2820

2821 2822
    /* Don't unlock tables until command is written to binary log */
    select_lex->options|= SELECT_NO_UNLOCK;
unknown's avatar
unknown committed
2823 2824

    select_result *result;
2825 2826 2827 2828
    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
2829

2830
    if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
2831
    {
2832 2833
      /* Using same table for INSERT and SELECT */
      select_lex->options |= OPTION_BUFFER_RESULT;
unknown's avatar
unknown committed
2834
    }
2835

unknown's avatar
unknown committed
2836 2837 2838 2839 2840
    if ((res= open_and_lock_tables(thd, tables)))
      break;
      
    TABLE *table= tables->table;
    /* Skip first table, which is the table we are inserting in */
unknown's avatar
unknown committed
2841 2842
    select_lex->table_list.first= (byte*) first_local_table->next;
    tables= (TABLE_LIST *) select_lex->table_list.first;
unknown's avatar
unknown committed
2843 2844 2845 2846
    first_local_table->next= 0;
    
    if (!(res= mysql_prepare_insert(thd, tables, first_local_table, 
				    table, lex->field_list, 0,
unknown's avatar
unknown committed
2847 2848
				    lex->update_list, lex->value_list,
				    lex->duplicates)) &&
unknown's avatar
unknown committed
2849
        (result= new select_insert(table, &lex->field_list,
unknown's avatar
unknown committed
2850
				   &lex->update_list, &lex->value_list,
2851
                                   lex->duplicates, lex->ignore)))
2852
    {
2853 2854 2855 2856 2857 2858 2859 2860 2861
      /*
        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
2862
      table->insert_values= 0;
unknown's avatar
unknown committed
2863
      if (thd->net.report_error)
2864
        res= -1;
2865 2866 2867
    }
    else
      res= -1;
unknown's avatar
unknown committed
2868 2869
    first_local_table->next= tables;
    lex->select_lex.table_list.first= (byte*) first_local_table;
unknown's avatar
unknown committed
2870 2871
    break;
  }
2872
  case SQLCOM_TRUNCATE:
unknown's avatar
unknown committed
2873
    if (check_one_table_access(thd, DELETE_ACL, tables))
unknown's avatar
unknown committed
2874
      goto error;
2875 2876 2877 2878 2879 2880
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
    if (thd->locked_tables || thd->active_transaction())
    {
2881
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
2882 2883
      goto error;
    }
2884
    res=mysql_truncate(thd, tables, 0);
2885
    break;
unknown's avatar
unknown committed
2886
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
2887
  {
unknown's avatar
unknown committed
2888 2889
    if ((res= delete_precheck(thd, tables)))
      break;
unknown's avatar
unknown committed
2890
    res = mysql_delete(thd,tables, select_lex->where,
2891
                       &select_lex->order_list,
unknown's avatar
unknown committed
2892
                       select_lex->select_limit, select_lex->options);
unknown's avatar
unknown committed
2893 2894
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2895 2896
    break;
  }
2897
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
2898
  {
2899 2900
    TABLE_LIST *aux_tables=
      (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
unknown's avatar
unknown committed
2901 2902
    TABLE_LIST *target_tbl;
    uint table_count;
unknown's avatar
unknown committed
2903
    multi_delete *result;
unknown's avatar
unknown committed
2904

2905 2906
    if ((res= multi_delete_precheck(thd, tables, &table_count)))
      break;
unknown's avatar
unknown committed
2907

unknown's avatar
unknown committed
2908
    /* condition will be TRUE on SP re-excuting */
2909 2910
    if (select_lex->item_list.elements != 0)
      select_lex->item_list.empty();
unknown's avatar
unknown committed
2911
    if (add_item_to_list(thd, new Item_null()))
2912
    {
unknown's avatar
unknown committed
2913
      res= -1;
2914
      break;
unknown's avatar
unknown committed
2915
    }
2916

unknown's avatar
unknown committed
2917 2918 2919 2920
    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
2921 2922 2923
    for (target_tbl= (TABLE_LIST*) aux_tables;
	 target_tbl;
	 target_tbl= target_tbl->next)
unknown's avatar
unknown committed
2924
    {
2925 2926 2927
      TABLE_LIST *orig= target_tbl->table_list;
      target_tbl->table= orig->table;
      /*
unknown's avatar
unknown committed
2928
	 Multi-delete can't be constructed over-union => we always have
unknown's avatar
unknown committed
2929
	 single SELECT on top and have to check underlying SELECTs of it
2930
      */
2931 2932
      if (lex->select_lex.check_updateable_in_subqueries(orig->db,
                                                         orig->real_name))
2933
      {
2934 2935 2936 2937
        my_error(ER_UPDATE_TABLE_USED, MYF(0),
                 orig->real_name);
        res= -1;
        break;
2938
      }
unknown's avatar
unknown committed
2939
    }
2940

2941 2942
    if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
							  table_count)))
unknown's avatar
unknown committed
2943
    {
2944 2945 2946
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
2947
			select_lex->item_list,
unknown's avatar
unknown committed
2948
			select_lex->where,
2949
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
unknown's avatar
unknown committed
2950 2951
			(ORDER *)NULL,
			select_lex->options | thd->options |
unknown's avatar
unknown committed
2952
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
2953
			result, unit, select_lex);
unknown's avatar
unknown committed
2954 2955
      if (thd->net.report_error)
	res= -1;
2956
      delete result;
unknown's avatar
unknown committed
2957 2958 2959 2960 2961 2962
    }
    else
      res= -1;					// Error is not sent
    close_thread_tables(thd);
    break;
  }
unknown's avatar
unknown committed
2963
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
2964
  {
2965 2966
    if (!lex->drop_temporary)
    {
unknown's avatar
unknown committed
2967
      if (check_table_access(thd,DROP_ACL,tables,0))
2968 2969 2970 2971 2972 2973 2974
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
unknown's avatar
unknown committed
2975
    else
unknown's avatar
unknown committed
2976 2977 2978 2979 2980 2981
    {
      /*
	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
2982 2983
	To not generate such irrelevant "table does not exist errors",
	we silently add IF EXISTS if TEMPORARY was used.
unknown's avatar
unknown committed
2984 2985 2986 2987
      */
      if (thd->slave_thread)
	lex->drop_if_exists= 1;
    }
2988
    res= mysql_rm_table(thd,tables,lex->drop_if_exists, lex->drop_temporary);
unknown's avatar
unknown committed
2989 2990
  }
  break;
unknown's avatar
unknown committed
2991
  case SQLCOM_DROP_INDEX:
unknown's avatar
unknown committed
2992
    if (check_one_table_access(thd, INDEX_ACL, tables))
unknown's avatar
unknown committed
2993
      goto error;				/* purecov: inspected */
2994 2995 2996
    if (end_active_trans(thd))
      res= -1;
    else
2997
      res = mysql_drop_index(thd, tables, &lex->alter_info);
unknown's avatar
unknown committed
2998 2999
    break;
  case SQLCOM_SHOW_DATABASES:
3000
#if defined(DONT_ALLOW_SHOW_COMMANDS)
3001
    send_error(thd,ER_NOT_ALLOWED_COMMAND);   /* purecov: inspected */
unknown's avatar
unknown committed
3002 3003 3004
    DBUG_VOID_RETURN;
#else
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
unknown's avatar
unknown committed
3005
	check_global_access(thd, SHOW_DB_ACL))
unknown's avatar
unknown committed
3006 3007 3008 3009 3010
      goto error;
    res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
    break;
#endif
  case SQLCOM_SHOW_PROCESSLIST:
unknown's avatar
unknown committed
3011
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
3012
      break;
unknown's avatar
unknown committed
3013 3014
    mysqld_list_processes(thd,
			  thd->master_access & PROCESS_ACL ? NullS :
unknown's avatar
unknown committed
3015
			  thd->priv_user,lex->verbose);
unknown's avatar
unknown committed
3016
    break;
unknown's avatar
unknown committed
3017 3018
  case SQLCOM_SHOW_STORAGE_ENGINES:
    res= mysqld_show_storage_engines(thd);
unknown's avatar
unknown committed
3019 3020 3021 3022 3023 3024 3025
    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
3026
  case SQLCOM_SHOW_STATUS:
3027
    res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
3028
		     OPT_GLOBAL, &LOCK_status);
unknown's avatar
unknown committed
3029 3030 3031
    break;
  case SQLCOM_SHOW_VARIABLES:
    res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
3032 3033
		     init_vars, lex->option_type,
		     &LOCK_global_system_variables);
unknown's avatar
unknown committed
3034
    break;
unknown's avatar
unknown committed
3035 3036
  case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
3037
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
3038 3039 3040
    DBUG_VOID_RETURN;
#else
    {
unknown's avatar
unknown committed
3041
      if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0))
unknown's avatar
unknown committed
3042 3043 3044 3045 3046
	goto error;
      res= mysqld_show_logs(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
3047
  case SQLCOM_SHOW_TABLES:
3048
    /* FALL THROUGH */
unknown's avatar
unknown committed
3049
#ifdef DONT_ALLOW_SHOW_COMMANDS
3050
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
3051 3052 3053
    DBUG_VOID_RETURN;
#else
    {
3054
      char *db=select_lex->db ? select_lex->db : thd->db;
unknown's avatar
unknown committed
3055 3056
      if (!db)
      {
3057
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
unknown's avatar
unknown committed
3058 3059 3060
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);				// Fix escaped '_'
3061
      if (check_db_name(db))
unknown's avatar
unknown committed
3062
      {
3063
        net_printf(thd,ER_WRONG_DB_NAME, db);
3064
        goto error;
unknown's avatar
unknown committed
3065
      }
unknown's avatar
unknown committed
3066
      if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
unknown's avatar
unknown committed
3067
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
3068
      if (!thd->col_access && check_grant_db(thd,db))
unknown's avatar
unknown committed
3069
      {
unknown's avatar
unknown committed
3070
	net_printf(thd, ER_DBACCESS_DENIED_ERROR,
unknown's avatar
unknown committed
3071 3072 3073 3074 3075
		   thd->priv_user,
		   thd->priv_host,
		   db);
	goto error;
      }
unknown's avatar
unknown committed
3076
      /* grant is checked in mysqld_show_tables */
3077
      if (lex->describe)
3078
        res= mysqld_extend_show_tables(thd,db,
3079
				       (lex->wild ? lex->wild->ptr() : NullS));
unknown's avatar
unknown committed
3080 3081 3082 3083 3084 3085
      else
	res= mysqld_show_tables(thd,db,
				(lex->wild ? lex->wild->ptr() : NullS));
      break;
    }
#endif
3086 3087 3088
  case SQLCOM_SHOW_OPEN_TABLES:
    res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
3089 3090
  case SQLCOM_SHOW_CHARSETS:
    res= mysqld_show_charsets(thd,(lex->wild ? lex->wild->ptr() : NullS));
3091
    break;
3092 3093 3094
  case SQLCOM_SHOW_COLLATIONS:
    res= mysqld_show_collations(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
unknown's avatar
unknown committed
3095 3096
  case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
3097
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
3098 3099 3100
    DBUG_VOID_RETURN;
#else
    {
3101
      char *db=tables->db;
unknown's avatar
unknown committed
3102
      remove_escape(db);			// Fix escaped '_'
3103
      remove_escape(tables->real_name);
3104
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
unknown's avatar
unknown committed
3105
		       &tables->grant.privilege, 0, 0))
unknown's avatar
unknown committed
3106
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
3107
      if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
3108 3109
	goto error;
      res= mysqld_show_fields(thd,tables,
unknown's avatar
unknown committed
3110 3111
			      (lex->wild ? lex->wild->ptr() : NullS),
			      lex->verbose);
unknown's avatar
unknown committed
3112 3113 3114 3115 3116
      break;
    }
#endif
  case SQLCOM_SHOW_KEYS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
3117
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
3118 3119 3120
    DBUG_VOID_RETURN;
#else
    {
3121
      char *db=tables->db;
unknown's avatar
unknown committed
3122
      remove_escape(db);			// Fix escaped '_'
3123
      remove_escape(tables->real_name);
unknown's avatar
unknown committed
3124
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
unknown's avatar
unknown committed
3125
		       &tables->grant.privilege, 0, 0))
unknown's avatar
unknown committed
3126
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
3127
      if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
3128 3129 3130 3131 3132 3133
	goto error;
      res= mysqld_show_keys(thd,tables);
      break;
    }
#endif
  case SQLCOM_CHANGE_DB:
3134
    mysql_change_db(thd,select_lex->db);
unknown's avatar
unknown committed
3135
    break;
3136

unknown's avatar
unknown committed
3137 3138 3139
  case SQLCOM_LOAD:
  {
    uint privilege= (lex->duplicates == DUP_REPLACE ?
3140
		     INSERT_ACL | DELETE_ACL : INSERT_ACL);
3141 3142

    if (!lex->local_file)
unknown's avatar
unknown committed
3143
    {
unknown's avatar
unknown committed
3144
      if (check_access(thd,privilege | FILE_ACL,tables->db,0,0,0))
unknown's avatar
unknown committed
3145 3146 3147 3148
	goto error;
    }
    else
    {
3149
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
unknown's avatar
unknown committed
3150
	  ! opt_local_infile)
3151
      {
3152
	send_error(thd,ER_NOT_ALLOWED_COMMAND);
3153 3154
	goto error;
      }
unknown's avatar
unknown committed
3155
      if (check_one_table_access(thd, privilege, tables))
unknown's avatar
unknown committed
3156 3157 3158
	goto error;
    }
    res=mysql_load(thd, lex->exchange, tables, lex->field_list,
3159
		   lex->duplicates, lex->ignore, (bool) lex->local_file, lex->lock_option);
unknown's avatar
unknown committed
3160 3161
    break;
  }
3162

unknown's avatar
unknown committed
3163
  case SQLCOM_SET_OPTION:
3164 3165
  {
    List<set_var_base> *lex_var_list= &lex->var_list;
unknown's avatar
unknown committed
3166
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
unknown's avatar
unknown committed
3167 3168
		   (res= open_and_lock_tables(thd,tables))))
      break;
3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182
    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;
3183
      send_ok(thd);
3184
    }
unknown's avatar
unknown committed
3185 3186
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
3187
    break;
3188
  }
unknown's avatar
unknown committed
3189

unknown's avatar
unknown committed
3190
  case SQLCOM_UNLOCK_TABLES:
3191 3192 3193 3194 3195 3196
    /*
      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
3197
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
3198 3199
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
3200
      end_active_trans(thd);
unknown's avatar
unknown committed
3201
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3202 3203
    }
    if (thd->global_read_lock)
3204
      unlock_global_read_lock(thd);
3205
    send_ok(thd);
unknown's avatar
unknown committed
3206 3207
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
3208
    unlock_locked_tables(thd);
3209
    if (check_db_used(thd,tables) || end_active_trans(thd))
unknown's avatar
unknown committed
3210
      goto error;
unknown's avatar
unknown committed
3211
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables,0))
3212
      goto error;
unknown's avatar
unknown committed
3213
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
3214
    thd->options|= OPTION_TABLE_LOCK;
3215
    if (!(res= open_and_lock_tables(thd, tables)))
unknown's avatar
unknown committed
3216
    {
3217 3218 3219 3220
#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
3221 3222
      thd->locked_tables=thd->lock;
      thd->lock=0;
3223
      send_ok(thd);
unknown's avatar
unknown committed
3224
    }
unknown's avatar
unknown committed
3225 3226
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3227 3228 3229
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
3230
  {
unknown's avatar
unknown committed
3231
    char *alias;
unknown's avatar
unknown committed
3232
    if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
unknown's avatar
unknown committed
3233
    {
3234
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
3235 3236
      break;
    }
3237 3238 3239 3240 3241 3242 3243
    /*
      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.
    */
3244
#ifdef HAVE_REPLICATION
3245 3246 3247
    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
3248 3249
    {
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
3250
      break;
unknown's avatar
unknown committed
3251
    }
3252
#endif
unknown's avatar
unknown committed
3253
    if (check_access(thd,CREATE_ACL,lex->name,0,1,0))
3254
      break;
unknown's avatar
unknown committed
3255
    res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name),
unknown's avatar
unknown committed
3256
			 &lex->create_info, 0);
3257 3258
    break;
  }
unknown's avatar
unknown committed
3259
  case SQLCOM_DROP_DB:
3260
  {
unknown's avatar
unknown committed
3261
    char *alias;
unknown's avatar
unknown committed
3262
    if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
unknown's avatar
unknown committed
3263
    {
3264
      net_printf(thd, ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
3265 3266
      break;
    }
3267 3268 3269 3270 3271 3272 3273
    /*
      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.
    */
3274
#ifdef HAVE_REPLICATION
3275 3276 3277
    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
3278 3279
    {
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
3280
      break;
unknown's avatar
unknown committed
3281
    }
3282
#endif
unknown's avatar
unknown committed
3283
    if (check_access(thd,DROP_ACL,lex->name,0,1,0))
3284
      break;
3285 3286
    if (thd->locked_tables || thd->active_transaction())
    {
3287
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
3288 3289
      goto error;
    }
3290 3291
    res=mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : lex->name),
                    lex->drop_if_exists, 0);
3292 3293
    break;
  }
3294 3295
  case SQLCOM_ALTER_DB:
  {
3296 3297
    char *db= lex->name ? lex->name : thd->db;
    if (!db)
3298
    {
3299 3300 3301 3302 3303 3304
      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);
3305 3306
      break;
    }
unknown's avatar
unknown committed
3307 3308 3309
    /*
      If in a slave thread :
      ALTER DATABASE DB may not be preceded by USE DB.
3310
      For that reason, maybe db_ok() in sql/slave.cc did not check the
unknown's avatar
unknown committed
3311 3312 3313 3314
      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
3315
    if (thd->slave_thread &&
3316 3317
	(!db_ok(db, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(db)))
unknown's avatar
unknown committed
3318 3319 3320 3321 3322
    {
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
      break;
    }
#endif
3323
    if (check_access(thd, ALTER_ACL, db, 0, 1, 0))
3324 3325 3326
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
3327
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
3328 3329
      goto error;
    }
3330
    res= mysql_alter_db(thd, db, &lex->create_info);
3331 3332
    break;
  }
unknown's avatar
unknown committed
3333 3334 3335 3336
  case SQLCOM_SHOW_CREATE_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
3337
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
3338 3339
      break;
    }
unknown's avatar
unknown committed
3340
    if (check_access(thd,SELECT_ACL,lex->name,0,1,0))
unknown's avatar
unknown committed
3341
      break;
unknown's avatar
unknown committed
3342
    res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
unknown's avatar
unknown committed
3343 3344
    break;
  }
unknown's avatar
unknown committed
3345
  case SQLCOM_CREATE_FUNCTION:
unknown's avatar
unknown committed
3346
    if (check_access(thd,INSERT_ACL,"mysql",0,1,0))
unknown's avatar
unknown committed
3347 3348 3349
      break;
#ifdef HAVE_DLOPEN
    if (!(res = mysql_create_function(thd,&lex->udf)))
3350
      send_ok(thd);
unknown's avatar
unknown committed
3351 3352 3353 3354 3355
#else
    res= -1;
#endif
    break;
  case SQLCOM_DROP_FUNCTION:
unknown's avatar
unknown committed
3356
    if (check_access(thd,DELETE_ACL,"mysql",0,1,0))
unknown's avatar
unknown committed
3357 3358
      break;
#ifdef HAVE_DLOPEN
3359
    if (!(res = mysql_drop_function(thd,&lex->udf.name)))
3360
      send_ok(thd);
unknown's avatar
unknown committed
3361 3362 3363 3364
#else
    res= -1;
#endif
    break;
unknown's avatar
unknown committed
3365
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3366 3367
  case SQLCOM_DROP_USER:
  {
unknown's avatar
unknown committed
3368
    if (check_access(thd, GRANT_ACL,"mysql",0,1,0))
3369 3370 3371 3372 3373 3374
      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())
      {
3375
	Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3376 3377 3378 3379 3380 3381 3382 3383
	mysql_bin_log.write(&qinfo);
      }
      send_ok(thd);
    }
    break;
  }
  case SQLCOM_REVOKE_ALL:
  {
unknown's avatar
unknown committed
3384
    if (check_access(thd, GRANT_ACL ,"mysql",0,1,0))
3385 3386 3387 3388 3389 3390
      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())
      {
3391
	Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3392 3393 3394 3395 3396 3397
	mysql_bin_log.write(&qinfo);
      }
      send_ok(thd);
    }
    break;
  }
3398 3399 3400 3401
  case SQLCOM_REVOKE:
  case SQLCOM_GRANT:
  {
    if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
3402
		     tables ? tables->db : select_lex->db,
3403
		     tables ? &tables->grant.privilege : 0,
3404
		     tables ? 0 : 1, 0))
3405 3406
      goto error;

unknown's avatar
unknown committed
3407 3408 3409 3410
    /*
      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
    */
3411 3412 3413 3414 3415 3416 3417 3418 3419 3420

    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
3421
	     my_strcasecmp(&my_charset_latin1,
3422
                           user->host.str, thd->host_or_ip)))
3423
	{
3424 3425 3426
	  if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1))
	  {
	    send_error(thd, ER_PASSWORD_NOT_ALLOWED);
3427
	    goto error;
3428 3429
	  }
	  break;		  // We are allowed to do global changes
3430 3431 3432
	}
      }
    }
unknown's avatar
SCRUM  
unknown committed
3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445
    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);
      }
    }
3446 3447 3448 3449 3450
    if (tables)
    {
      if (grant_option && check_grant(thd,
				      (lex->grant | lex->grant_tot_col |
				       GRANT_ACL),
unknown's avatar
unknown committed
3451
				      tables, 0, UINT_MAX, 0))
3452
	goto error;
unknown's avatar
unknown committed
3453 3454 3455
      if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
				    lex->grant,
				    lex->sql_command == SQLCOM_REVOKE)))
3456
      {
3457
	mysql_update_log.write(thd, thd->query, thd->query_length);
3458 3459
	if (mysql_bin_log.is_open())
	{
unknown's avatar
unknown committed
3460
          thd->clear_error();
3461
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3462 3463 3464 3465 3466 3467 3468 3469
	  mysql_bin_log.write(&qinfo);
	}
      }
    }
    else
    {
      if (lex->columns.elements)
      {
3470
	send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE);
3471 3472 3473 3474 3475 3476 3477
	res=1;
      }
      else
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
3478
	mysql_update_log.write(thd, thd->query, thd->query_length);
3479 3480
	if (mysql_bin_log.is_open())
	{
unknown's avatar
unknown committed
3481
          thd->clear_error();
3482
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3483 3484
	  mysql_bin_log.write(&qinfo);
	}
3485
	if (mqh_used && lex->sql_command == SQLCOM_GRANT)
3486
	{
unknown's avatar
unknown committed
3487 3488 3489
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
3490
	    reset_mqh(thd,user);
3491
	}
3492 3493 3494 3495
      }
    }
    break;
  }
unknown's avatar
SCRUM  
unknown committed
3496
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
unknown's avatar
unknown committed
3497
  case SQLCOM_RESET:
3498 3499 3500 3501 3502 3503 3504
    /* 
       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
3505
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
unknown's avatar
unknown committed
3506
      goto error;
3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524
    /*
      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())
        {
3525
          Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3526 3527 3528 3529 3530
          mysql_bin_log.write(&qinfo);
        }
      }
      send_ok(thd);
    }
unknown's avatar
unknown committed
3531
    break;
3532
  }
unknown's avatar
unknown committed
3533 3534 3535
  case SQLCOM_KILL:
    kill_one_thread(thd,lex->thread_id);
    break;
unknown's avatar
unknown committed
3536
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
3537 3538
  case SQLCOM_SHOW_GRANTS:
    res=0;
3539 3540
    if ((thd->priv_user &&
	 !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
unknown's avatar
unknown committed
3541
	!check_access(thd, SELECT_ACL, "mysql",0,1,0))
unknown's avatar
unknown committed
3542 3543 3544 3545
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
unknown's avatar
unknown committed
3546
#endif
3547
  case SQLCOM_HA_OPEN:
3548
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
3549
	check_table_access(thd,SELECT_ACL, tables,0))
3550 3551 3552 3553 3554 3555 3556 3557 3558
      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:
3559 3560 3561 3562 3563
    /*
      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
3564
    if (check_db_used(thd,tables))
3565
      goto error;
unknown's avatar
unknown committed
3566
    res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
3567 3568
			lex->insert_list, lex->ha_rkey_mode, select_lex->where,
			select_lex->select_limit, select_lex->offset_limit);
3569 3570
    break;

unknown's avatar
unknown committed
3571
  case SQLCOM_BEGIN:
unknown's avatar
unknown committed
3572 3573 3574 3575 3576 3577
    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
3578 3579 3580 3581 3582 3583
    if (end_active_trans(thd))
    {
      res= -1;
    }
    else
    {
3584
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
unknown's avatar
unknown committed
3585 3586
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
3587 3588 3589
      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
3590
    }
unknown's avatar
unknown committed
3591 3592
    break;
  case SQLCOM_COMMIT:
3593 3594 3595 3596 3597
    /*
      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
3598
  {
3599
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
3600 3601
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
unknown's avatar
unknown committed
3602
    {
3603
      send_ok(thd);
unknown's avatar
unknown committed
3604
    }
unknown's avatar
unknown committed
3605 3606 3607
    else
      res= -1;
    break;
unknown's avatar
unknown committed
3608
  }
unknown's avatar
unknown committed
3609 3610 3611
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
3612
    {
unknown's avatar
unknown committed
3613 3614 3615 3616 3617 3618 3619 3620 3621 3622
      /*
        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)
3623
	send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
3624
      else
3625
	send_ok(thd);
3626
    }
unknown's avatar
unknown committed
3627 3628
    else
      res= -1;
3629
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
3630
    break;
unknown's avatar
unknown committed
3631 3632 3633
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
    if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
    {
unknown's avatar
unknown committed
3634
      if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
unknown's avatar
unknown committed
3635
	send_warning(thd, ER_WARNING_NOT_COMPLETE_ROLLBACK, 0);
unknown's avatar
unknown committed
3636
      else
unknown's avatar
unknown committed
3637
	send_ok(thd);
unknown's avatar
unknown committed
3638 3639 3640 3641
    }
    else
      res= -1;
    break;
3642
  case SQLCOM_SAVEPOINT:
unknown's avatar
unknown committed
3643
    if (!ha_savepoint(thd, lex->savepoint_name))
unknown's avatar
unknown committed
3644
      send_ok(thd);
unknown's avatar
unknown committed
3645 3646
    else
      res= -1;
3647
    break;
unknown's avatar
unknown committed
3648
  default:					/* Impossible */
3649
    send_ok(thd);
unknown's avatar
unknown committed
3650 3651 3652
    break;
  }
  thd->proc_info="query end";			// QQ
3653
  if (thd->one_shot_set)
unknown's avatar
unknown committed
3654 3655 3656 3657 3658 3659 3660 3661
  {
    /*
      If this is a SET, do nothing. This is to allow mysqlbinlog to print
      many SET commands (in this case we want the charset temp setting to
      live until the real query). This is also needed so that SET
      CHARACTER_SET_CLIENT... does not cancel itself immediately.
    */
    if (lex->sql_command != SQLCOM_SET_OPTION)
3662
    {
unknown's avatar
unknown committed
3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674
      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;
3675
    }
unknown's avatar
unknown committed
3676
  }
unknown's avatar
unknown committed
3677
  if (res < 0)
3678
    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
unknown's avatar
unknown committed
3679 3680

error:
unknown's avatar
unknown committed
3681 3682 3683 3684 3685 3686 3687 3688
  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
3689 3690 3691 3692
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
3693 3694
/*
  Check grants for commands which work only with one table and all other
3695
  tables belonging to subselects or implicitly opened tables.
unknown's avatar
unknown committed
3696

3697
  SYNOPSIS
unknown's avatar
unknown committed
3698 3699 3700 3701
    check_one_table_access()
    thd			Thread handler
    privilege		requested privelage
    tables		table list of command
unknown's avatar
unknown committed
3702 3703 3704

  RETURN
    0 - OK
unknown's avatar
unknown committed
3705
    1 - access denied, error is sent to client
unknown's avatar
unknown committed
3706
*/
unknown's avatar
unknown committed
3707 3708

int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables)
unknown's avatar
unknown committed
3709
{
unknown's avatar
unknown committed
3710 3711
  if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
    return 1;
unknown's avatar
unknown committed
3712

unknown's avatar
unknown committed
3713
  /* Show only 1 table for check_grant */
unknown's avatar
unknown committed
3714
  if (grant_option && check_grant(thd, privilege, tables, 0, 1, 0))
unknown's avatar
unknown committed
3715
    return 1;
unknown's avatar
unknown committed
3716

3717
  /* Check rights on tables of subselects and implictly opened tables */
unknown's avatar
unknown committed
3718 3719
  TABLE_LIST *subselects_tables;
  if ((subselects_tables= tables->next))
unknown's avatar
unknown committed
3720
  {
unknown's avatar
unknown committed
3721
    if ((check_table_access(thd, SELECT_ACL, subselects_tables,0)))
unknown's avatar
unknown committed
3722 3723 3724
      return 1;
  }
  return 0;
unknown's avatar
unknown committed
3725 3726 3727
}


unknown's avatar
unknown committed
3728
/****************************************************************************
unknown's avatar
unknown committed
3729
  Get the user (global) and database privileges for all used tables
unknown's avatar
unknown committed
3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742

  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
3743 3744
                is enough to satisfy the request and the global grants contains
                a SELECT grant.
unknown's avatar
unknown committed
3745 3746 3747
****************************************************************************/

bool
unknown's avatar
unknown committed
3748
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
3749
	     bool dont_check_global_grants, bool no_errors)
unknown's avatar
unknown committed
3750
{
unknown's avatar
unknown committed
3751
  DBUG_ENTER("check_access");
3752 3753
  DBUG_PRINT("enter",("db: '%s'  want_access: %lu  master_access: %lu",
                      db ? db : "", want_access, thd->master_access));
unknown's avatar
unknown committed
3754 3755
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  ulong db_access;
unknown's avatar
unknown committed
3756
  bool  db_is_pattern= test(want_access & GRANT_ACL);
unknown's avatar
unknown committed
3757 3758
#endif
  ulong dummy;
unknown's avatar
unknown committed
3759 3760 3761 3762 3763
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

3764
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
3765
  {
3766
    if (!no_errors)
3767
      send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
unknown's avatar
unknown committed
3768
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
3769 3770
  }

unknown's avatar
unknown committed
3771 3772 3773
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  DBUG_RETURN(0);
#else
unknown's avatar
unknown committed
3774 3775
  if ((thd->master_access & want_access) == want_access)
  {
3776 3777 3778 3779 3780 3781 3782
    /*
      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
3783
	(db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
unknown's avatar
unknown committed
3784
      db_access=acl_get(thd->host, thd->ip, thd->priv_user, db, db_is_pattern);
3785
    *save_priv=thd->master_access | db_access;
unknown's avatar
unknown committed
3786
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
3787
  }
3788
  if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
3789
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
3790
  {						// We can never grant this
3791
    if (!no_errors)
3792
      net_printf(thd,ER_ACCESS_DENIED_ERROR,
3793
		 thd->priv_user,
3794
		 thd->priv_host,
3795
		 thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
unknown's avatar
unknown committed
3796
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
3797 3798 3799
  }

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

unknown's avatar
unknown committed
3802
  if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
unknown's avatar
unknown committed
3803
    db_access=acl_get(thd->host, thd->ip, thd->priv_user, db, db_is_pattern);
unknown's avatar
unknown committed
3804 3805
  else
    db_access=thd->db_access;
3806 3807
  DBUG_PRINT("info",("db_access: %lu", db_access));
  /* Remove SHOW attribute and access rights we already have */
3808
  want_access &= ~(thd->master_access | EXTRA_ACL);
unknown's avatar
unknown committed
3809
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
3810 3811

  /* grant_option is set if there exists a single table or column grant */
unknown's avatar
unknown committed
3812
  if (db_access == want_access ||
3813
      ((grant_option && !dont_check_global_grants) &&
3814
       !(want_access & ~(db_access | TABLE_ACLS))))
unknown's avatar
unknown committed
3815
    DBUG_RETURN(FALSE);				/* Ok */
3816
  if (!no_errors)
3817
    net_printf(thd,ER_DBACCESS_DENIED_ERROR,
3818
	       thd->priv_user,
3819
	       thd->priv_host,
3820
	       db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
unknown's avatar
unknown committed
3821
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
3822
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
3823 3824 3825
}


3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843
/*
  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
3844 3845

bool check_global_access(THD *thd, ulong want_access)
unknown's avatar
unknown committed
3846
{
unknown's avatar
unknown committed
3847 3848 3849
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  return 0;
#else
unknown's avatar
unknown committed
3850
  char command[128];
3851
  if ((thd->master_access & want_access))
unknown's avatar
unknown committed
3852 3853
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
3854
  net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
unknown's avatar
unknown committed
3855 3856
	     command);
  return 1;
unknown's avatar
unknown committed
3857
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
3858 3859 3860
}


unknown's avatar
unknown committed
3861
/*
unknown's avatar
unknown committed
3862 3863
  Check the privilege for all used tables.  Table privileges are cached
  in the table list for GRANT checking
unknown's avatar
unknown committed
3864 3865
*/

3866
bool
unknown's avatar
unknown committed
3867
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
3868
		   bool no_errors)
unknown's avatar
unknown committed
3869
{
unknown's avatar
unknown committed
3870 3871
  uint found=0;
  ulong found_access=0;
unknown's avatar
unknown committed
3872 3873 3874
  TABLE_LIST *org_tables=tables;
  for (; tables ; tables=tables->next)
  {
3875 3876 3877 3878
    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
3879
      continue;
unknown's avatar
unknown committed
3880 3881
    if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
	thd->db)
unknown's avatar
unknown committed
3882
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
3883
    else if (tables->db && tables->db == thd->db)
unknown's avatar
unknown committed
3884 3885 3886 3887 3888
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
3889 3890
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
			 0, no_errors))
unknown's avatar
unknown committed
3891 3892
	  return TRUE;				// Access denied
	found_access=tables->grant.privilege;
unknown's avatar
unknown committed
3893
	found=1;
unknown's avatar
unknown committed
3894 3895
      }
    }
3896
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
3897
			  0, no_errors))
3898
      return TRUE;
unknown's avatar
unknown committed
3899 3900
  }
  if (grant_option)
3901
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
unknown's avatar
unknown committed
3902
		       test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
unknown's avatar
unknown committed
3903 3904 3905
  return FALSE;
}

3906 3907
bool check_merge_table_access(THD *thd, char *db,
			      TABLE_LIST *table_list)
3908 3909 3910 3911
{
  int error=0;
  if (table_list)
  {
3912
    /* Check that all tables use the current database */
3913 3914
    TABLE_LIST *tmp;
    for (tmp=table_list; tmp ; tmp=tmp->next)
3915 3916 3917 3918
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
    }
3919
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
unknown's avatar
unknown committed
3920
			     table_list,0);
3921 3922 3923 3924
  }
  return error;
}

unknown's avatar
unknown committed
3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940

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

unknown's avatar
unknown committed
3942 3943 3944 3945 3946 3947 3948 3949 3950 3951
/****************************************************************************
	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
3952 3953 3954 3955
#ifndef DBUG_OFF
long max_stack_used;
#endif

3956
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
3957 3958 3959 3960 3961 3962 3963 3964
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));
3965
    thd->fatal_error();
unknown's avatar
unknown committed
3966 3967
    return 1;
  }
unknown's avatar
unknown committed
3968 3969 3970
#ifndef DBUG_OFF
  max_stack_used= max(max_stack_used, stack_used);
#endif
unknown's avatar
unknown committed
3971 3972
  return 0;
}
3973
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
3974 3975 3976 3977

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

3978
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
unknown's avatar
unknown committed
3979 3980
{
  LEX	*lex=current_lex;
3981
  ulong old_info=0;
unknown's avatar
unknown committed
3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006
  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;
}

/****************************************************************************
4007
  Initialize global thd variables needed for query
unknown's avatar
unknown committed
4008 4009
****************************************************************************/

4010
void
unknown's avatar
unknown committed
4011
mysql_init_query(THD *thd, uchar *buf, uint length)
unknown's avatar
unknown committed
4012 4013
{
  DBUG_ENTER("mysql_init_query");
unknown's avatar
unknown committed
4014
  lex_start(thd, buf, length);
4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035
  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");
4036
  thd->free_list= 0;
4037 4038
  thd->select_number= 1;
  thd->total_warn_count= 0;                     // Warnings for this query
unknown's avatar
unknown committed
4039 4040
  thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
  thd->sent_row_count= thd->examined_row_count= 0;
4041
  thd->is_fatal_error= thd->rand_used= thd->time_zone_used= 0;
unknown's avatar
unknown committed
4042 4043 4044
  thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | 
			  SERVER_QUERY_NO_INDEX_USED |
			  SERVER_QUERY_NO_GOOD_INDEX_USED);
unknown's avatar
unknown committed
4045
  thd->tmp_table_used= 0;
unknown's avatar
unknown committed
4046 4047
  if (opt_bin_log)
    reset_dynamic(&thd->user_var_events);
4048
  thd->clear_error();
unknown's avatar
unknown committed
4049 4050 4051
  DBUG_VOID_RETURN;
}

4052

4053 4054 4055
void
mysql_init_select(LEX *lex)
{
unknown's avatar
unknown committed
4056
  SELECT_LEX *select_lex= lex->current_select;
unknown's avatar
unknown committed
4057
  select_lex->init_select();
4058
  select_lex->select_limit= HA_POS_ERROR;
4059 4060
  if (select_lex == &lex->select_lex)
  {
4061
    DBUG_ASSERT(lex->result == 0);
4062 4063
    lex->exchange= 0;
  }
4064 4065
}

4066

unknown's avatar
unknown committed
4067
bool
unknown's avatar
unknown committed
4068
mysql_new_select(LEX *lex, bool move_down)
4069
{
unknown's avatar
unknown committed
4070 4071
  SELECT_LEX *select_lex;
  if (!(select_lex= new(lex->thd->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
4072
    return 1;
4073
  select_lex->select_number= ++lex->thd->select_number;
unknown's avatar
unknown committed
4074 4075 4076 4077
  select_lex->init_query();
  select_lex->init_select();
  if (move_down)
  {
4078
    lex->subqueries= TRUE;
unknown's avatar
unknown committed
4079
    /* first select_lex of subselect or derived table */
unknown's avatar
unknown committed
4080 4081
    SELECT_LEX_UNIT *unit;
    if (!(unit= new(lex->thd->mem_root) SELECT_LEX_UNIT()))
unknown's avatar
unknown committed
4082
      return 1;
unknown's avatar
unknown committed
4083

unknown's avatar
unknown committed
4084 4085
    unit->init_query();
    unit->init_select();
4086
    unit->thd= lex->thd;
unknown's avatar
unknown committed
4087
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
4088 4089
    unit->link_next= 0;
    unit->link_prev= 0;
4090
    unit->return_to= lex->current_select;
unknown's avatar
unknown committed
4091
    select_lex->include_down(unit);
4092
    // TODO: assign resolve_mode for fake subquery after merging with new tree
unknown's avatar
unknown committed
4093 4094
  }
  else
unknown's avatar
unknown committed
4095
  {
4096
    select_lex->include_neighbour(lex->current_select);
unknown's avatar
unknown committed
4097 4098 4099 4100 4101 4102 4103 4104
    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
4105 4106
      if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX()))
        return 1;
unknown's avatar
unknown committed
4107 4108 4109 4110 4111
      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;
4112
      fake->select_limit= HA_POS_ERROR;
unknown's avatar
unknown committed
4113 4114
    }
  }
unknown's avatar
unknown committed
4115

4116
  select_lex->master_unit()->global_parameters= select_lex;
4117
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
4118
  lex->current_select= select_lex;
4119
  select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
unknown's avatar
unknown committed
4120
  return 0;
4121
}
unknown's avatar
unknown committed
4122

4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137
/*
  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)
{
4138
  THD *thd;
4139
  LEX *lex;
4140
  LEX_STRING tmp, null_lex_string;
4141
  DBUG_ENTER("create_select_for_variable");
4142 4143

  thd= current_thd;
4144
  lex= thd->lex;
4145 4146 4147 4148
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
4149 4150 4151
  bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
  add_item_to_list(thd, get_system_var(thd, OPT_SESSION, tmp,
				       null_lex_string));
4152 4153 4154
  DBUG_VOID_RETURN;
}

4155

unknown's avatar
unknown committed
4156 4157
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
4158
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
4159
  mysql_init_select(lex);
4160
  lex->select_lex.select_limit= lex->unit.select_limit_cnt=
unknown's avatar
unknown committed
4161
    HA_POS_ERROR;
unknown's avatar
unknown committed
4162
  lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list);
4163
  lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
unknown's avatar
unknown committed
4164
}
unknown's avatar
unknown committed
4165

4166

4167 4168 4169 4170
/*
  When you modify mysql_parse(), you may need to mofify
  mysql_test_parse_for_slave() in this same file.
*/
unknown's avatar
unknown committed
4171

4172
void mysql_parse(THD *thd, char *inBuf, uint length)
unknown's avatar
unknown committed
4173 4174 4175
{
  DBUG_ENTER("mysql_parse");

unknown's avatar
unknown committed
4176
  mysql_init_query(thd, (uchar*) inBuf, length);
unknown's avatar
unknown committed
4177
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
unknown's avatar
unknown committed
4178
  {
unknown's avatar
unknown committed
4179
    LEX *lex= thd->lex;
4180
    if (!yyparse((void *)thd) && ! thd->is_fatal_error)
unknown's avatar
unknown committed
4181
    {
unknown's avatar
unknown committed
4182
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4183
      if (mqh_used && thd->user_connect &&
4184
	  check_mqh(thd, lex->sql_command))
4185 4186 4187 4188
      {
	thd->net.error = 0;
      }
      else
unknown's avatar
unknown committed
4189
#endif
4190
      {
unknown's avatar
unknown committed
4191 4192 4193 4194
	if (thd->net.report_error)
	  send_error(thd, 0, NullS);
	else
	{
4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208
          /*
            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
4209
	  mysql_execute_command(thd);
unknown's avatar
SCRUM  
unknown committed
4210
	  query_cache_end_of_result(thd);
unknown's avatar
unknown committed
4211
	}
4212
      }
unknown's avatar
unknown committed
4213 4214
    }
    else
4215 4216
    {
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
4217
			 thd->is_fatal_error));
unknown's avatar
unknown committed
4218
      query_cache_abort(&thd->net);
4219
    }
unknown's avatar
unknown committed
4220
    thd->proc_info="freeing items";
4221
    thd->end_statement();
4222
    DBUG_ASSERT(thd->change_list.is_empty());
unknown's avatar
unknown committed
4223
  }
unknown's avatar
unknown committed
4224 4225 4226 4227
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
4228
#ifdef HAVE_REPLICATION
4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239
/*
  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
4240
  LEX *lex= thd->lex;
4241 4242
  bool error= 0;

unknown's avatar
unknown committed
4243
  mysql_init_query(thd, (uchar*) inBuf, length);
unknown's avatar
unknown committed
4244
  if (!yyparse((void*) thd) && ! thd->is_fatal_error &&
4245 4246
      all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
    error= 1;                /* Ignore question */
4247
  thd->end_statement();
4248 4249
  return error;
}
unknown's avatar
unknown committed
4250
#endif
unknown's avatar
unknown committed
4251

4252

unknown's avatar
unknown committed
4253 4254 4255 4256 4257
/*****************************************************************************
** Store field definition for create
** Return 0 if ok
******************************************************************************/

unknown's avatar
unknown committed
4258
bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
unknown's avatar
unknown committed
4259
		       char *length, char *decimals,
4260
		       uint type_modifier,
4261 4262
		       Item *default_value, Item *on_update_value,
                       LEX_STRING *comment,
4263 4264
		       char *change,
                       List<String> *interval_list, CHARSET_INFO *cs,
unknown's avatar
unknown committed
4265
		       uint uint_geom_type)
unknown's avatar
unknown committed
4266 4267
{
  register create_field *new_field;
4268
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
4269
  uint allowed_type_modifier=0;
4270
  char warn_buff[MYSQL_ERRMSG_SIZE];
unknown's avatar
unknown committed
4271 4272 4273 4274
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
4275
    net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
unknown's avatar
unknown committed
4276 4277 4278 4279 4280
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
4281
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
4282
				    0, lex->col_list));
unknown's avatar
unknown committed
4283 4284 4285 4286 4287
    lex->col_list.empty();
  }
  if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
4288
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF, 0,
unknown's avatar
unknown committed
4289 4290 4291 4292
				    lex->col_list));
    lex->col_list.empty();
  }

4293
  if (default_value)
unknown's avatar
unknown committed
4294
  {
4295
    /* 
unknown's avatar
unknown committed
4296 4297
      Default value should be literal => basic constants =>
      no need fix_fields()
4298 4299 4300
      
      We allow only one function as part of default value - 
      NOW() as default for TIMESTAMP type.
4301
    */
4302 4303 4304 4305 4306 4307 4308 4309
    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
4310
    {
4311
      default_value= 0;
4312 4313 4314
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
unknown's avatar
unknown committed
4315
	net_printf(thd,ER_INVALID_DEFAULT,field_name);
4316 4317 4318 4319 4320
	DBUG_RETURN(1);
      }
    }
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
unknown's avatar
unknown committed
4321
      net_printf(thd, ER_INVALID_DEFAULT, field_name);
unknown's avatar
unknown committed
4322 4323 4324
      DBUG_RETURN(1);
    }
  }
4325 4326 4327 4328 4329 4330 4331

  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
4332 4333 4334 4335
  if (!(new_field=new create_field()))
    DBUG_RETURN(1);
  new_field->field=0;
  new_field->field_name=field_name;
4336
  new_field->def= default_value;
unknown's avatar
unknown committed
4337 4338 4339 4340 4341 4342 4343 4344 4345 4346
  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;
4347
  new_field->charset=cs;
unknown's avatar
unknown committed
4348
  new_field->geom_type= (Field::geometry_type) uint_geom_type;
unknown's avatar
unknown committed
4349

4350 4351 4352 4353 4354 4355 4356 4357
  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
4358 4359
    new_field->comment.str=   (char*) comment->str;
    new_field->comment.length=comment->length;
4360
  }
4361 4362
  if (length && !(new_field->length= (uint) atoi(length)))
    length=0; /* purecov: inspected */
unknown's avatar
unknown committed
4363 4364 4365
  uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;

  if (new_field->length && new_field->decimals &&
4366
      new_field->length < new_field->decimals+1 &&
unknown's avatar
unknown committed
4367
      new_field->decimals != NOT_FIXED_DEC)
4368
    new_field->length=new_field->decimals+1; /* purecov: inspected */
unknown's avatar
unknown committed
4369 4370 4371

  switch (type) {
  case FIELD_TYPE_TINY:
4372
    if (!length) new_field->length=MAX_TINYINT_WIDTH+sign_len;
unknown's avatar
unknown committed
4373 4374 4375
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_SHORT:
4376
    if (!length) new_field->length=MAX_SMALLINT_WIDTH+sign_len;
unknown's avatar
unknown committed
4377 4378 4379
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_INT24:
4380
    if (!length) new_field->length=MAX_MEDIUMINT_WIDTH+sign_len;
unknown's avatar
unknown committed
4381 4382 4383
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONG:
4384
    if (!length) new_field->length=MAX_INT_WIDTH+sign_len;
unknown's avatar
unknown committed
4385 4386 4387
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONGLONG:
4388
    if (!length) new_field->length=MAX_BIGINT_WIDTH;
unknown's avatar
unknown committed
4389 4390 4391 4392 4393 4394
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_NULL:
    break;
  case FIELD_TYPE_DECIMAL:
    if (!length)
unknown's avatar
unknown committed
4395 4396
    {
      if ((new_field->length= new_field->decimals))
4397 4398
        new_field->length++;
      else
unknown's avatar
unknown committed
4399 4400
        new_field->length= 10;                  // Default length for DECIMAL
    }
4401 4402 4403 4404 4405 4406
    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
4407
    break;
4408 4409
  case FIELD_TYPE_STRING:
  case FIELD_TYPE_VAR_STRING:
4410
    if (new_field->length <= MAX_FIELD_CHARLENGTH || default_value)
4411 4412 4413 4414
      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
4415
	    (cs == &my_charset_bin) ? "BLOB" : "TEXT");
4416 4417 4418
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_AUTO_CONVERT,
		 warn_buff);
    /* fall through */
unknown's avatar
unknown committed
4419 4420 4421 4422
  case FIELD_TYPE_BLOB:
  case FIELD_TYPE_TINY_BLOB:
  case FIELD_TYPE_LONG_BLOB:
  case FIELD_TYPE_MEDIUM_BLOB:
unknown's avatar
unknown committed
4423
  case FIELD_TYPE_GEOMETRY:
4424 4425 4426 4427 4428
    if (new_field->length)
    {
      /* The user has given a length to the blob column */
      if (new_field->length < 256)
	type= FIELD_TYPE_TINY_BLOB;
4429
      else if (new_field->length < 65536)
4430 4431 4432 4433 4434 4435 4436 4437
	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
4438 4439 4440 4441 4442 4443
    if (default_value)				// Allow empty as default value
    {
      String str,*res;
      res=default_value->val_str(&str);
      if (res->length())
      {
4444
	net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
unknown's avatar
unknown committed
4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463
	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)
      {
4464
	net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
unknown's avatar
unknown committed
4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493
	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
4494
    else if (new_field->length != 19)
unknown's avatar
unknown committed
4495
    {
4496 4497 4498 4499
      /*
        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
4500 4501 4502
      new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
      new_field->length= min(new_field->length,14); /* purecov: inspected */
    }
4503
    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523
    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
    {
4524 4525 4526 4527 4528 4529 4530 4531
      /*
        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
4532
        information about all TIMESTAMP fields in table will be availiable.
4533 4534 4535

        If we have TIMESTAMP NULL column without explicit DEFAULT value
        we treat it as having DEFAULT NULL attribute.
4536
      */
4537 4538 4539 4540 4541
      new_field->unireg_check= on_update_value ?
                               Field::TIMESTAMP_UN_FIELD :
                               (new_field->flags & NOT_NULL_FLAG ?
                                Field::TIMESTAMP_OLD_FIELD:
                                Field::NONE);
4542
    }
unknown's avatar
unknown committed
4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558
    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:
    {
4559
      if (interval_list->elements > sizeof(longlong)*8)
unknown's avatar
unknown committed
4560
      {
4561 4562
        net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
        DBUG_RETURN(1);				/* purecov: inspected */
unknown's avatar
unknown committed
4563
      }
4564
      new_field->pack_length= get_set_pack_length(interval_list->elements);
4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575

      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
4576 4577 4578 4579
    }
    break;
  case FIELD_TYPE_ENUM:
    {
4580
      // Should be safe
4581
      new_field->pack_length= get_enum_pack_length(interval_list->elements);
4582 4583 4584 4585 4586 4587

      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
4588
    }
4589
    break;
unknown's avatar
unknown committed
4590 4591
  }

4592 4593
  if ((new_field->length > MAX_FIELD_CHARLENGTH && type != FIELD_TYPE_SET && 
       type != FIELD_TYPE_ENUM) ||
unknown's avatar
unknown committed
4594
      (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
4595
       type != FIELD_TYPE_STRING &&
unknown's avatar
SCRUM  
unknown committed
4596
       type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
unknown's avatar
unknown committed
4597
  {
4598
    net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
4599
	       MAX_FIELD_CHARLENGTH);		/* purecov: inspected */
unknown's avatar
unknown committed
4600 4601 4602 4603 4604
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
4605
    net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
unknown's avatar
unknown committed
4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626
    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
4627
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
4628 4629 4630 4631
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
4632
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
4633 4634 4635 4636 4637
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
4638
  thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
4639 4640 4641 4642 4643 4644 4645 4646
  return 0;
}


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

static void remove_escape(char *name)
{
4647 4648
  if (!*name)					// For empty DB names
    return;
unknown's avatar
unknown committed
4649 4650
  char *to;
#ifdef USE_MB
unknown's avatar
unknown committed
4651
  char *strend=name+(uint) strlen(name);
unknown's avatar
unknown committed
4652 4653 4654 4655 4656 4657
#endif
  for (to=name; *name ; name++)
  {
#ifdef USE_MB
    int l;
/*    if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
4658 4659
    if (use_mb(system_charset_info) &&
        (l = my_ismbchar(system_charset_info, name, strend)))
unknown's avatar
unknown committed
4660 4661 4662 4663 4664 4665 4666 4667
    {
	while (l--)
	    *to++ = *name++;
	name--;
	continue;
    }
#endif
    if (*name == '\\' && name[1])
unknown's avatar
unknown committed
4668
      name++;					// Skip '\\'
unknown's avatar
unknown committed
4669 4670 4671 4672 4673 4674 4675 4676 4677 4678
    *to++= *name;
  }
  *to=0;
}

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


unknown's avatar
unknown committed
4679
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
4680 4681 4682
{
  ORDER *order;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
4683
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER))))
unknown's avatar
unknown committed
4684
    DBUG_RETURN(1);
unknown's avatar
unknown committed
4685 4686
  order->item_ptr= item;
  order->item= &order->item_ptr;
unknown's avatar
unknown committed
4687 4688 4689
  order->asc = asc;
  order->free_me=0;
  order->used=0;
unknown's avatar
unknown committed
4690
  list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
4691 4692 4693 4694
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713
/*
  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
4714 4715
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
4716
					     LEX_STRING *alias,
unknown's avatar
unknown committed
4717 4718
					     ulong table_options,
					     thr_lock_type lock_type,
4719 4720
					     List<String> *use_index_arg,
					     List<String> *ignore_index_arg,
unknown's avatar
unknown committed
4721
                                             LEX_STRING *option)
unknown's avatar
unknown committed
4722 4723 4724 4725 4726 4727 4728 4729
{
  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
4730
  if (check_table_name(table->table.str,table->table.length) ||
4731
      table->db.str && check_db_name(table->db.str))
unknown's avatar
unknown committed
4732
  {
4733
    net_printf(thd, ER_WRONG_TABLE_NAME, table->table.str);
unknown's avatar
unknown committed
4734 4735 4736 4737
    DBUG_RETURN(0);
  }

  if (!alias)					/* Alias is case sensitive */
4738 4739 4740 4741 4742 4743
  {
    if (table->sel)
    {
      net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
      DBUG_RETURN(0);
    }
4744
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
4745
      DBUG_RETURN(0);
4746
  }
unknown's avatar
unknown committed
4747
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
4748
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
4749
  if (table->db.str)
4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760
  {
    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
  {
4761 4762
    /* The following can't be "" as we may do 'casedn_str()' on it */
    ptr->db= empty_c_string;
4763 4764
    ptr->db_length= 0;
  }
4765 4766
  if (thd->current_arena->is_stmt_prepare())
    ptr->db= thd->strdup(ptr->db);
unknown's avatar
unknown committed
4767

4768
  ptr->alias= alias_str;
4769 4770
  if (lower_case_table_names && table->table.length)
    my_casedn_str(files_charset_info, table->table.str);
unknown's avatar
unknown committed
4771
  ptr->real_name=table->table.str;
4772
  ptr->real_name_length=table->table.length;
4773
  ptr->lock_type=   lock_type;
unknown's avatar
unknown committed
4774 4775
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
4776
  ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
4777
  ptr->derived=	    table->sel;
unknown's avatar
unknown committed
4778
  ptr->cacheable_table= 1;
4779 4780 4781 4782 4783 4784
  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
4785
  ptr->option= option ? option->str : 0;
unknown's avatar
unknown committed
4786
  /* check that used name is unique */
4787
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
4788
  {
4789
    for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
4790
	 tables ;
unknown's avatar
unknown committed
4791
	 tables=tables->next)
unknown's avatar
unknown committed
4792
    {
4793 4794
      if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
	  !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
4795
      {
4796
	net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
unknown's avatar
unknown committed
4797 4798
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
4799 4800
    }
  }
unknown's avatar
unknown committed
4801
  table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
unknown's avatar
unknown committed
4802 4803 4804
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
4805

unknown's avatar
unknown committed
4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818
/*
  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
4819
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
4820 4821 4822 4823 4824 4825
{
  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
4826
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
4827 4828 4829 4830 4831 4832 4833 4834 4835
       tables ;
       tables=tables->next)
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
4836

unknown's avatar
unknown committed
4837 4838
void add_join_on(TABLE_LIST *b,Item *expr)
{
4839
  if (expr)
4840
  {
4841 4842 4843 4844 4845 4846 4847 4848
    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();
4849
  }
unknown's avatar
unknown committed
4850 4851 4852
}


4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870
/*
  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
4871 4872 4873 4874 4875
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
{
  b->natural_join=a;
}

4876
/*
4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893
  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
4894 4895
*/

4896 4897
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
                          bool *write_to_binlog)
unknown's avatar
unknown committed
4898 4899 4900
{
  bool result=0;
  select_errors=0;				/* Write if more errors */
4901
  bool tmp_write_to_binlog= 1;
unknown's avatar
SCRUM  
unknown committed
4902
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
4903 4904
  if (options & REFRESH_GRANT)
  {
4905
    acl_reload(thd);
unknown's avatar
unknown committed
4906
    grant_reload(thd);
4907
    if (mqh_used)
unknown's avatar
unknown committed
4908
      reset_mqh(thd,(LEX_USER *) NULL,TRUE);
unknown's avatar
unknown committed
4909
  }
unknown's avatar
SCRUM  
unknown committed
4910
#endif
unknown's avatar
unknown committed
4911 4912
  if (options & REFRESH_LOG)
  {
4913
    /*
unknown's avatar
unknown committed
4914 4915
      Flush the normal query log, the update log, the binary log,
      the slow query log, and the relay log (if it exists).
4916
    */
unknown's avatar
unknown committed
4917

4918 4919 4920 4921 4922 4923
    /* 
     Writing this command to the binlog may result in infinite loops when doing
     mysqlbinlog|mysql, and anyway it does not really make sense to log it
     automatically (would cause more trouble to users than it would help them)
    */
    tmp_write_to_binlog= 0;
unknown's avatar
unknown committed
4924 4925 4926 4927
    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
4928
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
4929
    if (mysql_bin_log.is_open() && expire_logs_days)
4930 4931 4932
    {
      long purge_time= time(0) - expire_logs_days*24*60*60;
      if (purge_time >= 0)
4933
	mysql_bin_log.purge_logs_before_date(purge_time);
4934
    }
4935
    pthread_mutex_lock(&LOCK_active_mi);
4936
    rotate_relay_log(active_mi);
4937
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
4938
#endif
unknown's avatar
unknown committed
4939 4940
    if (ha_flush_logs())
      result=1;
unknown's avatar
unknown committed
4941 4942
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
4943
  }
unknown's avatar
unknown committed
4944
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
4945 4946
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
4947
    query_cache.pack();				// FLUSH QUERY CACHE
unknown's avatar
unknown committed
4948 4949 4950 4951
    options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
4952
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
4953
  }
unknown's avatar
unknown committed
4954
#endif /*HAVE_QUERY_CACHE*/
4955 4956 4957 4958 4959
  /*
    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
4960
  {
4961
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
4962
    {
unknown's avatar
unknown committed
4963 4964 4965 4966
      /*
	Writing to the binlog could cause deadlocks, as we don't log
	UNLOCK TABLES
      */
4967
      tmp_write_to_binlog= 0;
4968 4969
      if (lock_global_read_lock(thd))
	return 1;
4970 4971 4972
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
                                 tables);
      make_global_read_lock_block_commit(thd);
unknown's avatar
unknown committed
4973
    }
4974 4975
    else
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
unknown's avatar
unknown committed
4976
    my_dbopt_cleanup();
unknown's avatar
unknown committed
4977 4978 4979 4980 4981 4982 4983
  }
  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
4984
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
4985
  if (options & REFRESH_MASTER)
4986 4987
  {
    tmp_write_to_binlog= 0;
4988 4989
    if (reset_master(thd))
      result=1;
4990
  }
4991
#endif
unknown's avatar
unknown committed
4992
#ifdef OPENSSL
4993 4994 4995 4996 4997 4998
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
unknown's avatar
unknown committed
4999
#ifdef HAVE_REPLICATION
5000 5001
 if (options & REFRESH_SLAVE)
 {
5002
   tmp_write_to_binlog= 0;
5003
   pthread_mutex_lock(&LOCK_active_mi);
5004
   if (reset_slave(thd, active_mi))
5005
     result=1;
5006
   pthread_mutex_unlock(&LOCK_active_mi);
5007
 }
5008
#endif
5009
 if (options & REFRESH_USER_RESOURCES)
5010
   reset_mqh(thd,(LEX_USER *) NULL);
5011 5012
 if (write_to_binlog)
   *write_to_binlog= tmp_write_to_binlog;
5013
 return result;
unknown's avatar
unknown committed
5014 5015
}

5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027
/*
  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
*/

5028
void kill_one_thread(THD *thd, ulong id)
unknown's avatar
unknown committed
5029 5030 5031
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
5032 5033
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
5034 5035 5036 5037
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
5038 5039
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
5040 5041 5042
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055
  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
5056
  if (!error)
5057
    send_ok(thd);
unknown's avatar
unknown committed
5058
  else
5059
    net_printf(thd,error,id);
unknown's avatar
unknown committed
5060 5061
}

unknown's avatar
unknown committed
5062

unknown's avatar
unknown committed
5063 5064 5065 5066 5067 5068 5069 5070
/* 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)
5071
      *(ulong*) ptr->value= 0;
unknown's avatar
unknown committed
5072
  }
unknown's avatar
unknown committed
5073 5074
  /* Reset the counters of all key caches (default and named). */
  process_key_caches(reset_key_cache_counters);
unknown's avatar
unknown committed
5075 5076
  pthread_mutex_unlock(&LOCK_status);
}
5077 5078 5079 5080


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

unknown's avatar
unknown committed
5081 5082
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
			       const char *table_name)
5083
{
5084
  char buff[FN_REFLEN],*ptr, *end;
5085 5086 5087 5088 5089 5090 5091
  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))
  {
5092
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
5093 5094 5095 5096
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
5097
  end=convert_dirname(buff, *filename_ptr, NullS);
unknown's avatar
unknown committed
5098
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
5099 5100
    return 1;					// End of memory
  *filename_ptr=ptr;
5101
  strxmov(ptr,buff,table_name,NullS);
5102 5103
  return 0;
}
5104

5105

5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119
/*
  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;
5120
  if (thd->lex->current_select != &thd->lex->select_lex)
5121 5122
  {
    char command[80];
5123 5124
    strmake(command, thd->lex->yylval->symbol.str,
	    min(thd->lex->yylval->symbol.length, sizeof(command)-1));
5125
    net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
5126 5127 5128 5129
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
5130

unknown's avatar
unknown committed
5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149
/*
  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
5150
				    List<Item> *fields, SELECT_LEX *select_lex)
unknown's avatar
unknown committed
5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166
{
  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
5167 5168 5169
    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
5170 5171 5172 5173
	goto error;
    table->next= save;
  }
    
unknown's avatar
unknown committed
5174
  if (mysql_multi_update_lock(thd, tables, fields, select_lex))
unknown's avatar
unknown committed
5175 5176 5177 5178 5179 5180 5181
    goto error;
  
  res= 0;
  
error:
  DBUG_RETURN(res);
}
unknown's avatar
unknown committed
5182

unknown's avatar
unknown committed
5183

unknown's avatar
unknown committed
5184
Comp_creator *comp_eq_creator(bool invert)
unknown's avatar
unknown committed
5185
{
unknown's avatar
unknown committed
5186
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
unknown's avatar
unknown committed
5187 5188
}

unknown's avatar
unknown committed
5189

unknown's avatar
unknown committed
5190
Comp_creator *comp_ge_creator(bool invert)
unknown's avatar
unknown committed
5191
{
unknown's avatar
unknown committed
5192
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
unknown's avatar
unknown committed
5193 5194
}

unknown's avatar
unknown committed
5195

unknown's avatar
unknown committed
5196
Comp_creator *comp_gt_creator(bool invert)
unknown's avatar
unknown committed
5197
{
unknown's avatar
unknown committed
5198
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
unknown's avatar
unknown committed
5199 5200
}

unknown's avatar
unknown committed
5201

unknown's avatar
unknown committed
5202
Comp_creator *comp_le_creator(bool invert)
unknown's avatar
unknown committed
5203
{
unknown's avatar
unknown committed
5204
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
unknown's avatar
unknown committed
5205 5206
}

unknown's avatar
unknown committed
5207

unknown's avatar
unknown committed
5208
Comp_creator *comp_lt_creator(bool invert)
unknown's avatar
unknown committed
5209
{
unknown's avatar
unknown committed
5210
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
unknown's avatar
unknown committed
5211 5212
}

unknown's avatar
unknown committed
5213

unknown's avatar
unknown committed
5214
Comp_creator *comp_ne_creator(bool invert)
unknown's avatar
unknown committed
5215
{
unknown's avatar
unknown committed
5216
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
unknown's avatar
unknown committed
5217
}
unknown's avatar
unknown committed
5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237


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

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

  Item_allany_subselect *it=
5245
    new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all);
unknown's avatar
unknown committed
5246
  if (all)
5247
    return it->upper_item= new Item_func_not_all(it);	/* ALL */
unknown's avatar
unknown committed
5248

5249
  return it->upper_item= new Item_func_nop_all(it);      /* ANY/SOME */
unknown's avatar
unknown committed
5250
}
5251 5252


5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267
/*
  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;
5268 5269 5270
  ALTER_INFO alter_info;
  alter_info.flags= ALTER_ADD_INDEX;
  alter_info.is_simple= 0;
5271 5272 5273 5274 5275 5276 5277
  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,
5278
				fields, keys, 0, (ORDER*)0,
5279
				DUP_ERROR, 0, &alter_info));
5280 5281 5282
}


5283
int mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
5284 5285 5286 5287 5288 5289 5290 5291
{
  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;
5292 5293 5294
  alter_info->clear();
  alter_info->flags= ALTER_DROP_INDEX;
  alter_info->is_simple= 0;
5295 5296
  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
				&create_info, table_list,
5297
				fields, keys, 0, (ORDER*)0,
5298
				DUP_ERROR, 0, alter_info));
5299
}
unknown's avatar
merge  
unknown committed
5300 5301


5302 5303 5304 5305 5306
/*
  Multi update query pre-check

  SYNOPSIS
    multi_update_precheck()
unknown's avatar
unknown committed
5307 5308
    thd		Thread handler
    tables	Global table list
5309

unknown's avatar
unknown committed
5310
  RETURN VALUE
unknown's avatar
unknown committed
5311 5312 5313
    0   OK
    1   Error (message is sent to user)
    -1  Error (message is not sent to user)
5314
*/
unknown's avatar
unknown committed
5315

5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335
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)
  {
5336 5337 5338 5339 5340 5341
    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)) &&
5342 5343
	(check_access(thd, SELECT_ACL, table->db,
		      &table->grant.privilege, 0, 0) ||
unknown's avatar
unknown committed
5344
	 grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
5345
      DBUG_RETURN(1);
unknown's avatar
unknown committed
5346 5347 5348 5349 5350

    /*
      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
    */
5351
    if (table->table_list)
unknown's avatar
unknown committed
5352
      table->table_list->table_in_update_from_clause= 1;
5353
  }
unknown's avatar
unknown committed
5354 5355 5356
  /*
    Is there tables of subqueries?
  */
5357 5358
  if (&lex->select_lex != lex->all_selects_list)
  {
5359
    DBUG_PRINT("info",("Checking sub query list"));
5360 5361
    for (table= tables; table; table= table->next)
    {
5362 5363 5364 5365
      if (my_tz_check_n_skip_implicit_tables(&table,
                                             lex->time_zone_tables_used))
        continue;
      else if (table->table_in_update_from_clause)
5366 5367 5368 5369 5370 5371 5372 5373 5374
      {
	/*
	  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;
      }
5375
      else if (!table->derived)
5376 5377 5378
      {
	if (check_access(thd, SELECT_ACL, table->db,
			 &table->grant.privilege, 0, 0) ||
unknown's avatar
unknown committed
5379
	    grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402
	  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
5403 5404 5405
    thd			Thread handler
    tables		Global table list
    table_count		Pointer to table counter
5406

unknown's avatar
unknown committed
5407
  RETURN VALUE
unknown's avatar
unknown committed
5408 5409 5410
    0   OK
    1   error (message is sent to user)
    -1  error (message is not sent to user)
5411
*/
unknown's avatar
unknown committed
5412

5413 5414 5415 5416 5417 5418 5419
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
5420 5421 5422
  TABLE_LIST *target_tbl;

  *table_count= 0;
5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434

  /* 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
5435
  for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next)
5436 5437 5438 5439 5440 5441
  {
    (*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
5442 5443 5444
      if (!my_strcasecmp(table_alias_charset,
			 target_tbl->alias, walk->alias) &&
	  !strcmp(walk->db, target_tbl->db))
5445 5446 5447 5448
	break;
    }
    if (!walk)
    {
unknown's avatar
unknown committed
5449 5450
      my_error(ER_UNKNOWN_TABLE, MYF(0), target_tbl->real_name,
	       "MULTI DELETE");
5451 5452 5453 5454
      DBUG_RETURN(-1);
    }
    if (walk->derived)
    {
unknown's avatar
unknown committed
5455 5456
      my_error(ER_NON_UPDATABLE_TABLE, MYF(0), target_tbl->real_name,
	       "DELETE");
5457 5458
      DBUG_RETURN(-1);
    }
unknown's avatar
unknown committed
5459 5460
    walk->lock_type= target_tbl->lock_type;
    target_tbl->table_list= walk;	// Remember corresponding table
unknown's avatar
unknown committed
5461 5462 5463
    
    /* in case of subselects, we need to set lock_type in
     * corresponding table in list of all tables */
5464 5465 5466 5467 5468
    if (walk->table_list)
    {
      target_tbl->table_list= walk->table_list;
      walk->table_list->lock_type= walk->lock_type;
    }
5469 5470 5471 5472 5473
  }
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
5474 5475 5476 5477 5478
/*
  simple UPDATE query pre-check

  SYNOPSIS
    update_precheck()
unknown's avatar
unknown committed
5479 5480
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
5481 5482

  RETURN VALUE
unknown's avatar
unknown committed
5483 5484 5485
    0   OK
    1   Error (message is sent to user)
    -1  Error (message is not sent to user)
unknown's avatar
unknown committed
5486
*/
unknown's avatar
unknown committed
5487

unknown's avatar
unknown committed
5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505
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
5506 5507
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
5508 5509

  RETURN VALUE
unknown's avatar
unknown committed
5510 5511 5512
    0   OK
    1   error (message is sent to user)
    -1  error (message is not sent to user)
unknown's avatar
unknown committed
5513
*/
unknown's avatar
unknown committed
5514

unknown's avatar
unknown committed
5515 5516 5517 5518 5519
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
5520
  /* Set privilege for the WHERE clause */
unknown's avatar
unknown committed
5521 5522 5523 5524 5525 5526 5527 5528 5529 5530
  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
5531 5532
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
5533 5534

  RETURN VALUE
unknown's avatar
unknown committed
5535 5536 5537
    0   OK
    1   error (message is sent to user)
    -1  error (message is not sent to user)
unknown's avatar
unknown committed
5538
*/
unknown's avatar
unknown committed
5539

5540
int insert_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
5541 5542 5543 5544
{
  LEX *lex= thd->lex;
  DBUG_ENTER("insert_precheck");

unknown's avatar
unknown committed
5545 5546 5547 5548
  /*
    Check that we have modify privileges for the first table and
    select privileges for the rest
  */
5549 5550 5551
  ulong privilege= INSERT_ACL |
                   (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
                   (lex->duplicates == DUP_UPDATE ? UPDATE_ACL : 0);
unknown's avatar
unknown committed
5552 5553

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

unknown's avatar
unknown committed
5556
  if (lex->update_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
5557 5558 5559 5560
  {
    my_error(ER_WRONG_VALUE_COUNT, MYF(0));
    DBUG_RETURN(-1);
  }
5561 5562
  DBUG_RETURN(0);
}
unknown's avatar
unknown committed
5563 5564 5565 5566 5567 5568 5569


/*
  CREATE TABLE query pre-check

  SYNOPSIS
    create_table_precheck()
unknown's avatar
unknown committed
5570 5571 5572
    thd			Thread handler
    tables		Global table list
    create_table	Table which will be created
unknown's avatar
unknown committed
5573 5574

  RETURN VALUE
unknown's avatar
unknown committed
5575 5576
    0   OK
    1   Error (message is sent to user)
unknown's avatar
unknown committed
5577
*/
unknown's avatar
unknown committed
5578

unknown's avatar
unknown committed
5579 5580 5581 5582
int create_table_precheck(THD *thd, TABLE_LIST *tables,
			  TABLE_LIST *create_table)
{
  LEX *lex= thd->lex;
5583 5584 5585
  SELECT_LEX *select_lex= &lex->select_lex;
  ulong want_priv;
  int error= 1;                                 // Error message is given
unknown's avatar
unknown committed
5586
  DBUG_ENTER("create_table_precheck");
5587 5588 5589

  want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
              CREATE_TMP_ACL : CREATE_ACL);
unknown's avatar
unknown committed
5590 5591 5592 5593 5594 5595
  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))
5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639
    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
5640
}
unknown's avatar
unknown committed
5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676


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