sql_parse.cc 218 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
#ifdef HAVE_NDBCLUSTER_DB
#include "ha_ndbcluster.h"
#endif

32
#include "sp_head.h"
33
#include "sp.h"
34
#include "sp_cache.h"
35

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

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

64 65 66
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#endif
unknown's avatar
unknown committed
67

68
static void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
unknown's avatar
unknown committed
69
#ifndef NO_EMBEDDED_ACCESS_CHECKS
70
static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
unknown's avatar
unknown committed
71
#endif
72
static void decrease_user_connections(USER_CONN *uc);
unknown's avatar
unknown committed
73
static bool check_db_used(THD *thd,TABLE_LIST *tables);
unknown's avatar
unknown committed
74
static bool check_multi_update_lock(THD *thd);
unknown's avatar
unknown committed
75 76
static void remove_escape(char *name);
static void refresh_status(void);
unknown's avatar
unknown committed
77 78
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
			       const char *table_name);
unknown's avatar
unknown committed
79

80
const char *any_db="*any*";	// Special symbol for check_access
unknown's avatar
unknown committed
81 82 83 84

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

unknown's avatar
unknown committed
92 93 94 95
const char *xa_state_names[]={
  "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
};

96
static char empty_c_string[1]= {0};		// Used for not defined 'db'
unknown's avatar
unknown committed
97 98 99 100

#ifdef __WIN__
static void  test_signal(int sig_ptr)
{
unknown's avatar
unknown committed
101
#if !defined( DBUG_OFF)
unknown's avatar
unknown committed
102 103
  MessageBox(NULL,"Test signal","DBUG",MB_OK);
#endif
unknown's avatar
unknown committed
104
#if defined(OS2)
105 106
  fprintf(stderr, "Test signal %d\n", sig_ptr);
  fflush(stderr);
unknown's avatar
unknown committed
107
#endif
unknown's avatar
unknown committed
108 109 110 111
}
static void init_signals(void)
{
  int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
112
  for (int i=0 ; i < 7 ; i++)
unknown's avatar
unknown committed
113 114 115 116
    signal( signals[i], test_signal) ;
}
#endif

unknown's avatar
unknown committed
117 118 119 120 121
static void unlock_locked_tables(THD *thd)
{
  if (thd->locked_tables)
  {
    thd->lock=thd->locked_tables;
122
    thd->locked_tables=0;			// Will be automatically closed
unknown's avatar
unknown committed
123 124 125 126
    close_thread_tables(thd);			// Free tables
  }
}

127

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

unknown's avatar
WL#1967  
unknown committed
158 159 160
static bool begin_trans(THD *thd)
{
  int error=0;
161
  if (unlikely(thd->in_sub_stmt))
162 163 164 165
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    return 1;
  }
unknown's avatar
WL#1967  
unknown committed
166 167 168 169 170 171 172 173 174 175
  if (thd->locked_tables)
  {
    thd->lock=thd->locked_tables;
    thd->locked_tables=0;			// Will be automatically closed
    close_thread_tables(thd);			// Free tables
  }
  if (end_active_trans(thd))
    error= -1;
  else
  {
unknown's avatar
unknown committed
176
    LEX *lex= thd->lex;
unknown's avatar
WL#1967  
unknown committed
177 178 179 180
    thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
		   OPTION_BEGIN);
    thd->server_status|= SERVER_STATUS_IN_TRANS;
    if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
unknown's avatar
unknown committed
181
      error= ha_start_consistent_snapshot(thd);
unknown's avatar
WL#1967  
unknown committed
182 183 184
  }
  return error;
}
185

unknown's avatar
unknown committed
186
#ifdef HAVE_REPLICATION
187 188 189
/*
  Returns true if all tables should be ignored
*/
190 191
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
{
unknown's avatar
merged  
unknown committed
192
  return table_rules_on && tables && !tables_ok(thd,tables);
193
}
unknown's avatar
unknown committed
194
#endif
195 196


unknown's avatar
unknown committed
197 198
static HASH hash_user_connections;

unknown's avatar
unknown committed
199 200
static int get_or_create_user_conn(THD *thd, const char *user,
				   const char *host,
unknown's avatar
unknown committed
201
				   USER_RESOURCES *mqh)
unknown's avatar
unknown committed
202
{
203
  int return_val= 0;
unknown's avatar
unknown committed
204
  uint temp_len, user_len;
unknown's avatar
unknown committed
205 206 207 208 209 210
  char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
  struct  user_conn *uc;

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

211
  user_len= strlen(user);
212
  temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
unknown's avatar
unknown committed
213
  (void) pthread_mutex_lock(&LOCK_user_conn);
unknown's avatar
unknown committed
214 215
  if (!(uc = (struct  user_conn *) hash_search(&hash_user_connections,
					       (byte*) temp_user, temp_len)))
unknown's avatar
unknown committed
216
  {
unknown's avatar
unknown committed
217 218 219
    /* 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
220 221
			 MYF(MY_WME)))))
    {
222
      net_send_error(thd, 0, NullS);		// Out of memory
223
      return_val= 1;
unknown's avatar
unknown committed
224
      goto end;
unknown's avatar
unknown committed
225
    }
unknown's avatar
unknown committed
226 227
    uc->user=(char*) (uc+1);
    memcpy(uc->user,temp_user,temp_len+1);
228
    uc->host= uc->user + user_len +  1;
229
    uc->len= temp_len;
230
    uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
231 232
    uc->user_resources= *mqh;
    uc->intime= thd->thr_create_time;
unknown's avatar
SCRUM  
unknown committed
233
    if (my_hash_insert(&hash_user_connections, (byte*) uc))
unknown's avatar
unknown committed
234 235
    {
      my_free((char*) uc,0);
236
      net_send_error(thd, 0, NullS);		// Out of memory
237
      return_val= 1;
unknown's avatar
unknown committed
238 239 240 241
      goto end;
    }
  }
  thd->user_connect=uc;
242
  uc->connections++;
unknown's avatar
unknown committed
243 244 245
end:
  (void) pthread_mutex_unlock(&LOCK_user_conn);
  return return_val;
unknown's avatar
unknown committed
246

unknown's avatar
unknown committed
247
}
unknown's avatar
unknown committed
248 249 250


/*
251 252
  Check if user exist and password supplied is correct. 

253 254
  SYNOPSIS
    check_user()
255
    thd          thread handle, thd->security_ctx->{host,user,ip} are used
256 257 258
    command      originator of the check: now check_user is called
                 during connect and change user procedures; used for 
                 logging.
259
    passwd       scrambled password received from client
260 261 262 263
    passwd_len   length of scrambled password
    db           database name to connect to, may be NULL
    check_count  dont know exactly

264
    Note, that host, user and passwd may point to communication buffer.
265
    Current implementation does not depend on that, but future changes
266 267 268
    should be done with this in mind; 'thd' is INOUT, all other params
    are 'IN'.

269
  RETURN VALUE
270 271
    0  OK; thd->security_ctx->user/master_access/priv_user/db_access and
       thd->db are updated; OK is sent to client;
unknown's avatar
unknown committed
272 273
   -1  access denied or handshake error; error is sent to client;
   >0  error, not sent to client
unknown's avatar
unknown committed
274 275
*/

unknown's avatar
SCRUM:  
unknown committed
276 277 278
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
279
{
280
  DBUG_ENTER("check_user");
unknown's avatar
unknown committed
281
  
unknown's avatar
unknown committed
282
#ifdef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
283
  thd->main_security_ctx.master_access= GLOBAL_ACLS;       // Full rights
284
  /* Change database if necessary */
285 286
  if (db && db[0])
  {
287 288 289 290
    /*
      thd->db is saved in caller and needs to be freed by caller if this
      function returns 0
    */
291 292
    thd->db= 0;
    thd->db_length= 0;
293
    if (mysql_change_db(thd, db, FALSE))
294
    {
295 296
      /* Send the error to the client */
      net_send_error(thd);
297 298 299 300 301
      if (thd->user_connect)
	decrease_user_connections(thd->user_connect);
      DBUG_RETURN(-1);
    }
  }
302
  send_ok(thd);
303
  DBUG_RETURN(0);
unknown's avatar
unknown committed
304 305
#else

306 307 308 309 310
  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);
  
311
  /*
312 313
    If the server is running in secure auth mode, short scrambles are 
    forbidden.
314
  */
315
  if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
unknown's avatar
unknown committed
316
  {
317
    net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
318 319
    mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
320
  }
unknown's avatar
unknown committed
321 322 323 324
  if (passwd_len != 0 &&
      passwd_len != SCRAMBLE_LENGTH &&
      passwd_len != SCRAMBLE_LENGTH_323)
    DBUG_RETURN(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
325

326
  /*
327
    Clear thd->db as it points to something, that will be freed when 
328
    connection is closed. We don't want to accidentally free a wrong pointer
329 330
    if connect failed. Also in case of 'CHANGE USER' failure, current
    database will be switched to 'no database selected'.
331
  */
332 333
  thd->db= 0;
  thd->db_length= 0;
unknown's avatar
unknown committed
334
  
335
  USER_RESOURCES ur;
336
  int res= acl_getroot(thd, &ur, passwd, passwd_len);
unknown's avatar
SCRUM:  
unknown committed
337
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
338
  if (res == -1)
unknown's avatar
unknown committed
339
  {
unknown's avatar
unknown committed
340 341 342 343 344 345
    /*
      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.
    */
346
    NET *net= &thd->net;
347
    if (opt_secure_auth_local)
348
    {
349
      net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
350 351
                       thd->main_security_ctx.user,
                       thd->main_security_ctx.host_or_ip);
352
      mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
353 354
                      thd->main_security_ctx.user,
                      thd->main_security_ctx.host_or_ip);
355 356
      DBUG_RETURN(-1);
    }
unknown's avatar
unknown committed
357
    /* We have to read very specific packet size */
358
    if (send_old_password_request(thd) ||
unknown's avatar
unknown committed
359
        my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
360
    {
unknown's avatar
unknown committed
361 362 363 364 365
      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 */
366
    res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
unknown's avatar
unknown committed
367
  }
unknown's avatar
SCRUM:  
unknown committed
368
#endif /*EMBEDDED_LIBRARY*/
unknown's avatar
unknown committed
369 370
  /* here res is always >= 0 */
  if (res == 0)
unknown's avatar
unknown committed
371
  {
372 373
    if (!(thd->main_security_ctx.master_access &
          NO_ACCESS)) // authentication is OK
374
    {
unknown's avatar
unknown committed
375 376 377 378
      DBUG_PRINT("info",
                 ("Capabilities: %d  packet_length: %ld  Host: '%s'  "
                  "Login user: '%s' Priv_user: '%s'  Using password: %s "
                  "Access: %u  db: '%s'",
379 380 381 382 383
                  thd->client_capabilities,
                  thd->max_client_packet_length,
                  thd->main_security_ctx.host_or_ip,
                  thd->main_security_ctx.user,
                  thd->main_security_ctx.priv_user,
unknown's avatar
unknown committed
384
                  passwd_len ? "yes": "no",
385 386
                  thd->main_security_ctx.master_access,
                  (thd->db ? thd->db : "*none*")));
unknown's avatar
unknown committed
387 388

      if (check_count)
389
      {
unknown's avatar
unknown committed
390
        VOID(pthread_mutex_lock(&LOCK_thread_count));
unknown's avatar
unknown committed
391
        bool count_ok= thread_count <= max_connections + delayed_insert_threads
392
                       || (thd->main_security_ctx.master_access & SUPER_ACL);
unknown's avatar
unknown committed
393 394
        VOID(pthread_mutex_unlock(&LOCK_thread_count));
        if (!count_ok)
unknown's avatar
unknown committed
395
        {                                         // too many connections
396
          net_send_error(thd, ER_CON_COUNT_ERROR);
unknown's avatar
unknown committed
397 398
          DBUG_RETURN(-1);
        }
399
      }
unknown's avatar
unknown committed
400

unknown's avatar
unknown committed
401
      /* Why logging is performed before all checks've passed? */
402
      mysql_log.write(thd, command,
403 404
                      (thd->main_security_ctx.priv_user ==
                       thd->main_security_ctx.user ?
unknown's avatar
unknown committed
405 406
                       (char*) "%s@%s on %s" :
                       (char*) "%s@%s as anonymous on %s"),
407 408
                      thd->main_security_ctx.user,
                      thd->main_security_ctx.host_or_ip,
unknown's avatar
unknown committed
409 410
                      db ? db : (char*) "");

411
      /*
412 413 414
        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.
415
      */
416
      thd->main_security_ctx.db_access=0;
unknown's avatar
unknown committed
417 418

      /* Don't allow user to connect if he has done too many queries */
419
      if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
unknown's avatar
unknown committed
420
	   max_user_connections) &&
421
	  get_or_create_user_conn(thd,
422 423 424 425
            (opt_old_style_user_limits ? thd->main_security_ctx.user :
             thd->main_security_ctx.priv_user),
            (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
             thd->main_security_ctx.priv_host),
426
            &ur))
unknown's avatar
unknown committed
427 428
	DBUG_RETURN(-1);
      if (thd->user_connect &&
429 430
	  (thd->user_connect->user_resources.conn_per_hour ||
	   thd->user_connect->user_resources.user_conn ||
unknown's avatar
unknown committed
431 432 433
	   max_user_connections) &&
	  check_for_max_user_connections(thd, thd->user_connect))
	DBUG_RETURN(-1);
unknown's avatar
unknown committed
434

435
      /* Change database if necessary */
unknown's avatar
unknown committed
436
      if (db && db[0])
437
      {
438
        if (mysql_change_db(thd, db, FALSE))
unknown's avatar
unknown committed
439
        {
440 441
          /* Send error to the client */
          net_send_error(thd);
unknown's avatar
unknown committed
442 443 444 445
          if (thd->user_connect)
            decrease_user_connections(thd->user_connect);
          DBUG_RETURN(-1);
        }
446
      }
447
      send_ok(thd);
unknown's avatar
unknown committed
448 449 450
      thd->password= test(passwd_len);          // remember for error messages 
      /* Ready to handle queries */
      DBUG_RETURN(0);
unknown's avatar
unknown committed
451 452
    }
  }
unknown's avatar
unknown committed
453
  else if (res == 2) // client gave short hash, server has long hash
unknown's avatar
unknown committed
454
  {
455
    net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
unknown's avatar
unknown committed
456 457
    mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
458
  }
459
  net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
460 461
                   thd->main_security_ctx.user,
                   thd->main_security_ctx.host_or_ip,
462
                   passwd_len ? ER(ER_YES) : ER(ER_NO));
unknown's avatar
unknown committed
463
  mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
464 465
                  thd->main_security_ctx.user,
                  thd->main_security_ctx.host_or_ip,
unknown's avatar
unknown committed
466 467
                  passwd_len ? ER(ER_YES) : ER(ER_NO));
  DBUG_RETURN(-1);
unknown's avatar
unknown committed
468
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
469 470
}

unknown's avatar
unknown committed
471
/*
unknown's avatar
unknown committed
472 473
  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
474 475
*/

476 477
extern "C" byte *get_key_conn(user_conn *buff, uint *length,
			      my_bool not_used __attribute__((unused)))
unknown's avatar
unknown committed
478 479 480 481 482
{
  *length=buff->len;
  return (byte*) buff->user;
}

483
extern "C" void free_user(struct user_conn *uc)
unknown's avatar
unknown committed
484 485 486 487
{
  my_free((char*) uc,MYF(0));
}

unknown's avatar
unknown committed
488
void init_max_user_conn(void)
unknown's avatar
unknown committed
489
{
unknown's avatar
unknown committed
490 491
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
		   0,0,
492
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
493
		   0);
unknown's avatar
unknown committed
494 495 496
}


unknown's avatar
unknown committed
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
/*
  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
514 515
#ifndef NO_EMBEDDED_ACCESS_CHECKS

516
static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
unknown's avatar
unknown committed
517
{
unknown's avatar
unknown committed
518
  int error=0;
519
  DBUG_ENTER("check_for_max_user_connections");
unknown's avatar
unknown committed
520

521
  (void) pthread_mutex_lock(&LOCK_user_conn);
522
  if (max_user_connections && !uc->user_resources.user_conn &&
unknown's avatar
unknown committed
523
      max_user_connections < (uint) uc->connections)
unknown's avatar
unknown committed
524
  {
525
    net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
unknown's avatar
unknown committed
526 527
    error=1;
    goto end;
unknown's avatar
unknown committed
528
  }
529
  time_out_user_resource_limits(thd, uc);
530 531 532 533 534 535 536 537 538 539 540
  if (uc->user_resources.user_conn &&
      uc->user_resources.user_conn < uc->connections)
  {
    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
                     "max_user_connections",
                     (long) uc->user_resources.user_conn);
    error= 1;
    goto end;
  }
  if (uc->user_resources.conn_per_hour &&
      uc->user_resources.conn_per_hour <= uc->conn_per_hour)
541
  {
542
    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
unknown's avatar
unknown committed
543
                     "max_connections_per_hour",
544
                     (long) uc->user_resources.conn_per_hour);
545 546 547
    error=1;
    goto end;
  }
548
  uc->conn_per_hour++;
unknown's avatar
unknown committed
549 550

  end:
551 552
  if (error)
    uc->connections--; // no need for decrease_user_connections() here
553
  (void) pthread_mutex_unlock(&LOCK_user_conn);
554
  DBUG_RETURN(error);
unknown's avatar
unknown committed
555
}
unknown's avatar
unknown committed
556
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
557

unknown's avatar
unknown committed
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
/*
  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.
*/

576
static void decrease_user_connections(USER_CONN *uc)
unknown's avatar
unknown committed
577
{
unknown's avatar
unknown committed
578
  DBUG_ENTER("decrease_user_connections");
579 580 581
  (void) pthread_mutex_lock(&LOCK_user_conn);
  DBUG_ASSERT(uc->connections);
  if (!--uc->connections && !mqh_used)
unknown's avatar
unknown committed
582 583
  {
    /* Last connection for user; Delete it */
unknown's avatar
unknown committed
584
    (void) hash_delete(&hash_user_connections,(byte*) uc);
unknown's avatar
unknown committed
585
  }
586
  (void) pthread_mutex_unlock(&LOCK_user_conn);
587
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
588 589
}

590

unknown's avatar
unknown committed
591 592 593 594 595
void free_max_user_conn(void)
{
  hash_free(&hash_user_connections);
}

unknown's avatar
unknown committed
596

597 598 599
/*
  Mark all commands that somehow changes a table
  This is used to check number of updates / hour
unknown's avatar
unknown committed
600 601 602

  sql_command is actually set to SQLCOM_END sometimes
  so we need the +1 to include it in the array.
unknown's avatar
unknown committed
603 604 605 606 607 608

  numbers are:
     0  - read-only query
  != 0  - query that may change a table
     2  - query that returns meaningful ROW_COUNT() -
          a number of modified rows
609 610
*/

unknown's avatar
unknown committed
611
char  uc_update_queries[SQLCOM_END+1];
612 613 614

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

617 618 619
  uc_update_queries[SQLCOM_CREATE_TABLE]=1;
  uc_update_queries[SQLCOM_CREATE_INDEX]=1;
  uc_update_queries[SQLCOM_ALTER_TABLE]=1;
unknown's avatar
unknown committed
620 621 622 623 624 625
  uc_update_queries[SQLCOM_UPDATE]=2;
  uc_update_queries[SQLCOM_UPDATE_MULTI]=2;
  uc_update_queries[SQLCOM_INSERT]=2;
  uc_update_queries[SQLCOM_INSERT_SELECT]=2;
  uc_update_queries[SQLCOM_DELETE]=2;
  uc_update_queries[SQLCOM_DELETE_MULTI]=2;
626 627 628 629 630
  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;
unknown's avatar
unknown committed
631 632
  uc_update_queries[SQLCOM_REPLACE]=2;
  uc_update_queries[SQLCOM_REPLACE_SELECT]=2;
633 634 635 636
  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_DROP_INDEX]=1;
unknown's avatar
VIEW  
unknown committed
637 638
  uc_update_queries[SQLCOM_CREATE_VIEW]=1;
  uc_update_queries[SQLCOM_DROP_VIEW]=1;
639 640
}

unknown's avatar
unknown committed
641 642
bool is_update_query(enum enum_sql_command command)
{
unknown's avatar
unknown committed
643
  DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
644
  return uc_update_queries[command] != 0;
unknown's avatar
unknown committed
645
}
646

unknown's avatar
unknown committed
647
/*
648 649
  Reset per-hour user resource limits when it has been more than
  an hour since they were last checked
unknown's avatar
unknown committed
650

651 652 653 654
  SYNOPSIS:
    time_out_user_resource_limits()
    thd			Thread handler
    uc			User connection details
unknown's avatar
unknown committed
655

656 657 658 659
  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.
*/
660

661
static void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
unknown's avatar
unknown committed
662
{
unknown's avatar
unknown committed
663
  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
664
  DBUG_ENTER("time_out_user_resource_limits");
unknown's avatar
unknown committed
665

unknown's avatar
unknown committed
666
  /* If more than a hour since last check, reset resource checking */
667 668 669 670 671 672 673
  if (check_time  - uc->intime >= 3600)
  {
    uc->questions=1;
    uc->updates=0;
    uc->conn_per_hour=0;
    uc->intime=check_time;
  }
674 675 676 677 678 679 680 681 682 683 684 685

  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)
{
686 687
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  bool error= 0;
688 689 690 691 692 693 694 695
  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
696
  /* Check that we have not done too many questions / hour */
697 698 699
  if (uc->user_resources.questions &&
      uc->questions++ >= uc->user_resources.questions)
  {
700 701
    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
                     (long) uc->user_resources.questions);
702 703 704
    error=1;
    goto end;
  }
705
  if (check_command < (uint) SQLCOM_END)
unknown's avatar
unknown committed
706
  {
unknown's avatar
unknown committed
707 708 709 710
    /* 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)
    {
711 712
      net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
                       (long) uc->user_resources.updates);
unknown's avatar
unknown committed
713 714 715
      error=1;
      goto end;
    }
unknown's avatar
unknown committed
716 717
  }
end:
718
  (void) pthread_mutex_unlock(&LOCK_user_conn);
unknown's avatar
unknown committed
719
  DBUG_RETURN(error);
720 721
#else
  return (0);
unknown's avatar
unknown committed
722
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
723 724
}

unknown's avatar
unknown committed
725

unknown's avatar
unknown committed
726
static void reset_mqh(LEX_USER *lu, bool get_them= 0)
unknown's avatar
unknown committed
727
{
unknown's avatar
unknown committed
728
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
729
  (void) pthread_mutex_lock(&LOCK_user_conn);
unknown's avatar
unknown committed
730
  if (lu)  // for GRANT
unknown's avatar
unknown committed
731
  {
732
    USER_CONN *uc;
733
    uint temp_len=lu->user.length+lu->host.length+2;
unknown's avatar
unknown committed
734 735
    char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];

unknown's avatar
unknown committed
736 737
    memcpy(temp_user,lu->user.str,lu->user.length);
    memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
738
    temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
unknown's avatar
unknown committed
739
    if ((uc = (struct  user_conn *) hash_search(&hash_user_connections,
740
						(byte*) temp_user, temp_len)))
unknown's avatar
unknown committed
741 742
    {
      uc->questions=0;
743
      get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
744 745
      uc->updates=0;
      uc->conn_per_hour=0;
unknown's avatar
unknown committed
746 747
    }
  }
unknown's avatar
unknown committed
748
  else
unknown's avatar
unknown committed
749
  {
unknown's avatar
unknown committed
750
    /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
unknown's avatar
unknown committed
751
    for (uint idx=0;idx < hash_user_connections.records; idx++)
unknown's avatar
unknown committed
752
    {
unknown's avatar
unknown committed
753 754
      USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
						      idx);
755 756 757 758 759
      if (get_them)
	get_mqh(uc->user,uc->host,uc);
      uc->questions=0;
      uc->updates=0;
      uc->conn_per_hour=0;
unknown's avatar
unknown committed
760 761
    }
  }
unknown's avatar
unknown committed
762
  (void) pthread_mutex_unlock(&LOCK_user_conn);
unknown's avatar
unknown committed
763
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
764
}
unknown's avatar
unknown committed
765

unknown's avatar
unknown committed
766
/*
767
    Perform handshake, authorize client and update thd ACL variables.
768
  SYNOPSIS
769
    check_connection()
770
    thd  thread handle
771 772

  RETURN
773
     0  success, OK is sent to user, thd is updated.
774 775
    -1  error, which is sent to user
   > 0  error code (not sent to user)
unknown's avatar
unknown committed
776 777
*/

unknown's avatar
SCRUM:  
unknown committed
778 779
#ifndef EMBEDDED_LIBRARY
static int check_connection(THD *thd)
unknown's avatar
unknown committed
780
{
781
  uint connect_errors= 0;
unknown's avatar
unknown committed
782
  NET *net= &thd->net;
unknown's avatar
unknown committed
783 784
  ulong pkt_len= 0;
  char *end;
785

786 787 788
  DBUG_PRINT("info",
             ("New connection received on %s", vio_description(net->vio)));

789
  if (!thd->main_security_ctx.host)         // If TCP/IP connection
unknown's avatar
unknown committed
790
  {
791
    char ip[30];
792

793
    if (vio_peer_addr(net->vio, ip, &thd->peer_port))
unknown's avatar
unknown committed
794
      return (ER_BAD_HOST_ERROR);
795
    if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
unknown's avatar
unknown committed
796
      return (ER_OUT_OF_RESOURCES);
797
    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
unknown's avatar
unknown committed
798
    vio_in_addr(net->vio,&thd->remote.sin_addr);
799
    if (!(specialflag & SPECIAL_NO_RESOLVE))
unknown's avatar
unknown committed
800
    {
801
      vio_in_addr(net->vio,&thd->remote.sin_addr);
802 803
      thd->main_security_ctx.host=
        ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
804
      /* Cut very long hostnames to avoid possible overflows */
805
      if (thd->main_security_ctx.host)
806
      {
807 808 809 810
        if (thd->main_security_ctx.host != my_localhost)
          thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
                                          HOSTNAME_LENGTH)]= 0;
        thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
811
      }
812 813
      if (connect_errors > max_connect_errors)
        return(ER_HOST_IS_BLOCKED);
unknown's avatar
unknown committed
814
    }
unknown's avatar
unknown committed
815
    DBUG_PRINT("info",("Host: %s  ip: %s",
816 817 818 819 820
		       (thd->main_security_ctx.host ?
                        thd->main_security_ctx.host : "unknown host"),
		       (thd->main_security_ctx.ip ?
                        thd->main_security_ctx.ip : "unknown ip")));
    if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
unknown's avatar
unknown committed
821 822
      return(ER_HOST_NOT_PRIVILEGED);
  }
823
  else /* Hostname given means that the connection was on a socket */
unknown's avatar
unknown committed
824
  {
825 826 827
    DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
    thd->main_security_ctx.ip= 0;
828 829
    /* Reset sin_addr */
    bzero((char*) &thd->remote, sizeof(thd->remote));
unknown's avatar
unknown committed
830 831 832
  }
  vio_keepalive(net->vio, TRUE);
  {
unknown's avatar
unknown committed
833
    /* buff[] needs to big enough to hold the server_version variable */
834
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
835 836
    ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
			  CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
unknown's avatar
unknown committed
837

838 839 840 841 842
    if (opt_using_transactions)
      client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
    client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
unknown's avatar
unknown committed
843 844
#ifdef HAVE_OPENSSL
    if (ssl_acceptor_fd)
845
      client_flags |= CLIENT_SSL;       /* Wow, SSL is available! */
unknown's avatar
unknown committed
846
#endif /* HAVE_OPENSSL */
unknown's avatar
unknown committed
847

848 849 850 851 852 853 854 855 856 857 858
    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
859
      tail: that's why first part of the scramble is placed here, and second
860 861
      part at the end of packet.
    */
862
    end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
863 864 865
   
    int2store(end, client_flags);
    /* write server characteristics: up to 16 bytes allowed */
866
    end[2]=(char) default_charset_info->number;
867 868 869 870 871 872 873 874 875
    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
876
			  (uint) (end-buff)) ||
877
	(pkt_len= my_net_read(net)) == packet_error ||
unknown's avatar
unknown committed
878 879 880 881 882 883 884 885 886 887 888
	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
889
  if (thd->packet.alloc(thd->variables.net_buffer_length))
unknown's avatar
unknown committed
890 891 892
    return(ER_OUT_OF_RESOURCES);

  thd->client_capabilities=uint2korr(net->read_pos);
893 894 895 896
  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
897 898 899
    DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
    /*
      Use server character set and collation if
900
      - opt_character_set_client_handshake is not set
unknown's avatar
unknown committed
901 902 903 904
      - client has not specified a character set
      - client character set is the same as the servers
      - client character set doesn't exists in server
    */
905
    if (!opt_character_set_client_handshake ||
unknown's avatar
 
unknown committed
906
        !(thd->variables.character_set_client=
unknown's avatar
unknown committed
907 908 909 910
	  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))
911
    {
912 913
      thd->variables.character_set_client=
	global_system_variables.character_set_client;
914 915
      thd->variables.collation_connection=
	global_system_variables.collation_connection;
916 917
      thd->variables.character_set_results=
	global_system_variables.character_set_results;
918 919 920
    }
    else
    {
921
      thd->variables.character_set_results=
922 923 924
      thd->variables.collation_connection= 
	thd->variables.character_set_client;
    }
unknown's avatar
unknown committed
925
    thd->update_charset();
926
    end= (char*) net->read_pos+32;
927 928 929 930 931 932 933
  }
  else
  {
    thd->max_client_packet_length= uint3korr(net->read_pos+2);
    end= (char*) net->read_pos+5;
  }

934
  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
935
    thd->variables.sql_mode|= MODE_IGNORE_SPACE;
unknown's avatar
unknown committed
936
#ifdef HAVE_OPENSSL
unknown's avatar
unknown committed
937
  DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
unknown's avatar
unknown committed
938 939 940
  if (thd->client_capabilities & CLIENT_SSL)
  {
    /* Do the SSL layering. */
941 942 943 944 945
    if (!ssl_acceptor_fd)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
unknown's avatar
unknown committed
946
    DBUG_PRINT("info", ("IO layer change in progress..."));
unknown's avatar
unknown committed
947 948
    if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
    {
949
      DBUG_PRINT("error", ("Failed to accept new SSL connection"));
unknown's avatar
unknown committed
950
      inc_host_errors(&thd->remote.sin_addr);
unknown's avatar
unknown committed
951
      return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
952
    }
unknown's avatar
unknown committed
953
    DBUG_PRINT("info", ("Reading user information over SSL layer"));
954
    if ((pkt_len= my_net_read(net)) == packet_error ||
unknown's avatar
unknown committed
955 956
	pkt_len < NORMAL_HANDSHAKE_SIZE)
    {
unknown's avatar
unknown committed
957 958
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
unknown's avatar
unknown committed
959 960 961 962
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
  }
963 964 965
#endif

  if (end >= (char*) net->read_pos+ pkt_len +2)
unknown's avatar
unknown committed
966
  {
967 968
    inc_host_errors(&thd->remote.sin_addr);
    return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
969 970 971
  }

  if (thd->client_capabilities & CLIENT_INTERACTIVE)
972
    thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
973
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
974 975
      opt_using_transactions)
    net->return_status= &thd->server_status;
unknown's avatar
unknown committed
976
  net->read_timeout=(uint) thd->variables.net_read_timeout;
unknown's avatar
unknown committed
977

978 979
  char *user= end;
  char *passwd= strend(user)+1;
unknown's avatar
unknown committed
980
  char *db= passwd;
981
  char db_buff[NAME_LEN+1];                     // buffer to store db in utf8
unknown's avatar
unknown committed
982
  char user_buff[USERNAME_LENGTH+1];		// buffer to store user in utf8
983 984 985
  uint dummy_errors;

  /*
unknown's avatar
unknown committed
986 987 988 989
    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'.
  */
990
  uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
unknown's avatar
unknown committed
991 992 993
    *passwd++ : strlen(passwd);
  db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
    db + passwd_len + 1 : 0;
unknown's avatar
unknown committed
994

unknown's avatar
unknown committed
995 996
  /* Since 4.1 all database names are stored in utf8 */
  if (db)
unknown's avatar
unknown committed
997
  {
unknown's avatar
unknown committed
998 999 1000
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
                             system_charset_info,
                             db, strlen(db),
unknown's avatar
unknown committed
1001
                             thd->charset(), &dummy_errors)]= 0;
1002
    db= db_buff;
unknown's avatar
unknown committed
1003
  }
unknown's avatar
unknown committed
1004

1005 1006 1007 1008
  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
1009

1010 1011 1012
  if (thd->main_security_ctx.user)
    x_free(thd->main_security_ctx.user);
  if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0))))
1013
    return (ER_OUT_OF_RESOURCES);
unknown's avatar
unknown committed
1014
  return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
unknown's avatar
unknown committed
1015 1016
}

1017

1018 1019
void execute_init_command(THD *thd, sys_var_str *init_command_var,
			  rw_lock_t *var_mutex)
unknown's avatar
SCRUM:  
unknown committed
1020 1021 1022 1023
{
  Vio* save_vio;
  ulong save_client_capabilities;

1024 1025 1026 1027 1028 1029 1030 1031 1032
  thd->proc_info= "Execution of init_command";
  /*
    We need to lock init_command_var because
    during execution of init_command_var query
    values of init_command_var can't be changed
  */
  rw_rdlock(var_mutex);
  thd->query= init_command_var->value;
  thd->query_length= init_command_var->value_length;
unknown's avatar
SCRUM:  
unknown committed
1033 1034
  save_client_capabilities= thd->client_capabilities;
  thd->client_capabilities|= CLIENT_MULTI_QUERIES;
1035 1036 1037 1038
  /*
    We don't need return result of execution to client side.
    To forbid this we should set thd->net.vio to 0.
  */
unknown's avatar
SCRUM:  
unknown committed
1039 1040
  save_vio= thd->net.vio;
  thd->net.vio= 0;
1041
  thd->net.no_send_error= 0;
unknown's avatar
SCRUM:  
unknown committed
1042
  dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
1043
  rw_unlock(var_mutex);
unknown's avatar
SCRUM:  
unknown committed
1044 1045 1046 1047 1048
  thd->client_capabilities= save_client_capabilities;
  thd->net.vio= save_vio;
}


1049
pthread_handler_t handle_one_connection(void *arg)
unknown's avatar
unknown committed
1050 1051 1052
{
  THD *thd=(THD*) arg;
  uint launch_time  =
unknown's avatar
unknown committed
1053
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
unknown's avatar
unknown committed
1054 1055 1056 1057 1058
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status );

  pthread_detach_this_thread();

1059
#if !defined( __WIN__) && !defined(OS2)	// Win32 calls this in pthread_create
unknown's avatar
unknown committed
1060
  /* The following calls needs to be done before we call DBUG_ macros */
1061
  if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
unknown's avatar
unknown committed
1062
  {
1063
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
1064
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
1065 1066 1067 1068 1069
    end_thread(thd,0);
    return 0;
  }
#endif

1070 1071 1072 1073 1074 1075 1076
  /*
    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
1077 1078
  DBUG_PRINT("info", ("handle_one_connection called by thread %d\n",
		      thd->thread_id));
unknown's avatar
unknown committed
1079
  /* now that we've called my_thread_init(), it is safe to call DBUG_* */
unknown's avatar
unknown committed
1080

unknown's avatar
unknown committed
1081
#if defined(__WIN__)
unknown's avatar
unknown committed
1082
  init_signals();
unknown's avatar
unknown committed
1083
#elif !defined(OS2) && !defined(__NETWARE__)
unknown's avatar
unknown committed
1084 1085 1086 1087 1088 1089
  sigset_t set;
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
  if (thd->store_globals())
  {
1090
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
1091
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
1092 1093 1094 1095 1096 1097 1098 1099
    end_thread(thd,0);
    return 0;
  }

  do
  {
    int error;
    NET *net= &thd->net;
1100
    Security_context *sctx= thd->security_ctx;
unknown's avatar
unknown committed
1101
    thd->thread_stack= (char*) &thd;
1102
    net->no_send_error= 0;
unknown's avatar
unknown committed
1103

1104
    if ((error=check_connection(thd)))
unknown's avatar
unknown committed
1105 1106
    {						// Wrong permissions
      if (error > 0)
1107
	net_printf_error(thd, error, sctx->host_or_ip);
unknown's avatar
unknown committed
1108 1109
#ifdef __NT__
      if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
1110
	my_sleep(1000);				/* must wait after eof() */
unknown's avatar
unknown committed
1111
#endif
1112
      statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
1113 1114
      goto end_thread;
    }
unknown's avatar
unknown committed
1115
#ifdef __NETWARE__
1116
    netware_reg_user(sctx->ip, sctx->user, "MySQL");
unknown's avatar
unknown committed
1117
#endif
1118
    if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
1119 1120 1121 1122
      thd->options |= OPTION_BIG_SELECTS;
    if (thd->client_capabilities & CLIENT_COMPRESS)
      net->compress=1;				// Use compression

unknown's avatar
SCRUM:  
unknown committed
1123
    thd->version= refresh_version;
1124
    thd->proc_info= 0;
1125
    thd->command= COM_SLEEP;
1126 1127
    thd->set_time();
    thd->init_for_queries();
unknown's avatar
unknown committed
1128

1129
    if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
unknown's avatar
SCRUM:  
unknown committed
1130
    {
1131 1132
      execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
      if (thd->query_error)
unknown's avatar
unknown committed
1133
	thd->killed= THD::KILL_CONNECTION;
1134 1135 1136
      thd->proc_info=0;
      thd->set_time();
      thd->init_for_queries();
unknown's avatar
SCRUM:  
unknown committed
1137 1138
    }

1139 1140
    while (!net->error && net->vio != 0 &&
           !(thd->killed == THD::KILL_CONNECTION))
unknown's avatar
unknown committed
1141
    {
1142
      net->no_send_error= 0;
unknown's avatar
unknown committed
1143 1144 1145
      if (do_command(thd))
	break;
    }
unknown's avatar
unknown committed
1146 1147
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
unknown's avatar
unknown committed
1148
    if (net->error && net->vio != 0 && net->report_error)
unknown's avatar
unknown committed
1149
    {
1150
      if (!thd->killed && thd->variables.log_warnings > 1)
unknown's avatar
unknown committed
1151
	sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
unknown's avatar
unknown committed
1152
                          thd->thread_id,(thd->db ? thd->db : "unconnected"),
1153 1154
                          sctx->user ? sctx->user : "unauthenticated",
                          sctx->host_or_ip,
unknown's avatar
unknown committed
1155 1156
                          (net->last_errno ? ER(net->last_errno) :
                           ER(ER_UNKNOWN_ERROR)));
1157
      net_send_error(thd, net->last_errno, NullS);
unknown's avatar
unknown committed
1158
      statistic_increment(aborted_threads,&LOCK_status);
unknown's avatar
unknown committed
1159
    }
1160 1161 1162 1163
    else if (thd->killed)
    {
      statistic_increment(aborted_threads,&LOCK_status);
    }
unknown's avatar
unknown committed
1164
    
unknown's avatar
unknown committed
1165
end_thread:
1166
    close_connection(thd, 0, 1);
unknown's avatar
unknown committed
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
    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
1178 1179
#endif /* EMBEDDED_LIBRARY */

1180 1181 1182 1183
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
unknown's avatar
unknown committed
1184

1185
pthread_handler_t handle_bootstrap(void *arg)
unknown's avatar
unknown committed
1186
{
1187 1188 1189
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
unknown's avatar
unknown committed
1190

1191
  /* The following must be called before DBUG_ENTER */
1192
  if (my_thread_init() || thd->store_globals())
unknown's avatar
unknown committed
1193
  {
unknown's avatar
unknown committed
1194
#ifndef EMBEDDED_LIBRARY
1195
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
unknown's avatar
unknown committed
1196
#endif
1197
    thd->fatal_error();
1198
    goto end;
unknown's avatar
unknown committed
1199
  }
1200 1201
  DBUG_ENTER("handle_bootstrap");

unknown's avatar
unknown committed
1202
#ifndef EMBEDDED_LIBRARY
1203 1204
  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
1205
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
unknown's avatar
unknown committed
1206
  sigset_t set;
1207 1208
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
unknown's avatar
unknown committed
1209
#endif
unknown's avatar
unknown committed
1210
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
1211

1212
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
1213 1214 1215 1216
    thd->options |= OPTION_BIG_SELECTS;

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

1220
  buff= (char*) thd->net.buff;
unknown's avatar
unknown committed
1221
  thd->init_for_queries();
unknown's avatar
unknown committed
1222 1223
  while (fgets(buff, thd->net.max_packet, file))
  {
unknown's avatar
unknown committed
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
   ulong length= (ulong) strlen(buff);
   while (buff[length-1] != '\n' && !feof(file))
   {
     /*
       We got only a part of the current string. Will try to increase
       net buffer then read the rest of the current string.
     */
     if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
     {
       net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS);
       thd->fatal_error();
       break;
     }
     buff= (char*) thd->net.buff;
     fgets(buff + length, thd->net.max_packet - length, file);
     length+= (ulong) strlen(buff + length);
   }
   if (thd->is_fatal_error)
     break;

unknown's avatar
unknown committed
1244
    while (length && (my_isspace(thd->charset(), buff[length-1]) ||
1245
           buff[length-1] == ';'))
unknown's avatar
unknown committed
1246 1247
      length--;
    buff[length]=0;
1248
    thd->query_length=length;
unknown's avatar
unknown committed
1249 1250
    thd->query= thd->memdup_w_gap(buff, length+1, 
				  thd->db_length+1+QUERY_CACHE_FLAGS_SIZE);
unknown's avatar
unknown committed
1251
    thd->query[length] = '\0';
1252 1253 1254 1255
    /*
      We don't need to obtain LOCK_thread_count here because in bootstrap
      mode we have only one thread.
    */
unknown's avatar
unknown committed
1256
    thd->query_id=next_query_id();
unknown's avatar
unknown committed
1257 1258
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
1259
    if (thd->is_fatal_error)
1260
      break;
unknown's avatar
unknown committed
1261
    free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1262
#ifdef USING_TRANSACTIONS
1263
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1264
#endif
unknown's avatar
unknown committed
1265
  }
1266 1267 1268

  /* thd->fatal_error should be set in case something went wrong */
end:
unknown's avatar
unknown committed
1269 1270 1271 1272 1273 1274
  bootstrap_error= thd->is_fatal_error;

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

unknown's avatar
unknown committed
1275
#ifndef EMBEDDED_LIBRARY
1276 1277 1278
  (void) pthread_mutex_lock(&LOCK_thread_count);
  thread_count--;
  (void) pthread_mutex_unlock(&LOCK_thread_count);
1279
  (void) pthread_cond_broadcast(&COND_thread_count);
1280 1281
  my_thread_end();
  pthread_exit(0);
unknown's avatar
unknown committed
1282
#endif
unknown's avatar
unknown committed
1283
  DBUG_RETURN(0);
unknown's avatar
unknown committed
1284 1285
}

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

1288
void free_items(Item *item)
unknown's avatar
unknown committed
1289
{
unknown's avatar
unknown committed
1290
  Item *next;
unknown's avatar
unknown committed
1291
  DBUG_ENTER("free_items");
unknown's avatar
unknown committed
1292 1293 1294
  for (; item ; item=next)
  {
    next=item->next;
unknown's avatar
unknown committed
1295
    item->delete_self();
unknown's avatar
unknown committed
1296
  }
unknown's avatar
unknown committed
1297
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
1298 1299
}

1300 1301 1302 1303
    /* This works because items are allocated with sql_alloc() */

void cleanup_items(Item *item)
{
unknown's avatar
unknown committed
1304
  DBUG_ENTER("cleanup_items");  
1305 1306
  for (; item ; item=item->next)
    item->cleanup();
unknown's avatar
unknown committed
1307
  DBUG_VOID_RETURN;
1308 1309
}

unknown's avatar
unknown committed
1310 1311 1312 1313 1314 1315 1316
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;
1317
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
1318
    DBUG_RETURN(1); // out of memory
unknown's avatar
VIEW  
unknown committed
1319
  table_list->db= db;
1320
  table_list->table_name= table_list->alias= tbl_name;
unknown's avatar
VIEW  
unknown committed
1321 1322
  table_list->lock_type= TL_READ_NO_INSERT;
  table_list->prev_global= &table_list;	// can be removed after merge with 4.1
unknown's avatar
unknown committed
1323

unknown's avatar
unknown committed
1324 1325
  if (!db || check_db_name(db))
  {
1326
    my_error(ER_WRONG_DB_NAME ,MYF(0), db ? db : "NULL");
unknown's avatar
unknown committed
1327 1328
    goto err;
  }
1329
  if (lower_case_table_names)
1330
    my_casedn_str(files_charset_info, tbl_name);
1331
  remove_escape(table_list->table_name);
1332 1333 1334 1335

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

unknown's avatar
unknown committed
1336
  if (check_one_table_access(thd, SELECT_ACL, table_list))
unknown's avatar
unknown committed
1337 1338
    goto err;
  thd->free_list = 0;
unknown's avatar
unknown committed
1339
  thd->query_length=(uint) strlen(tbl_name);
unknown's avatar
unknown committed
1340
  thd->query = tbl_name;
unknown's avatar
unknown committed
1341
  if ((error = mysqld_dump_create_info(thd, table_list, -1)))
1342
  {
1343
    my_error(ER_GET_ERRNO, MYF(0), my_errno);
1344 1345
    goto err;
  }
unknown's avatar
unknown committed
1346
  net_flush(&thd->net);
1347
  if ((error= table->file->dump(thd,fd)))
1348
    my_error(ER_GET_ERRNO, MYF(0), error);
unknown's avatar
unknown committed
1349

unknown's avatar
unknown committed
1350
err:
unknown's avatar
unknown committed
1351
  DBUG_RETURN(error);
unknown's avatar
unknown committed
1352 1353
}

unknown's avatar
WL#1967  
unknown committed
1354 1355 1356 1357
/*
  Ends the current transaction and (maybe) begin the next

  SYNOPSIS
1358
    end_trans()
unknown's avatar
WL#1967  
unknown committed
1359 1360 1361 1362 1363 1364 1365
      thd            Current thread
      completion     Completion type

  RETURN
    0 - OK
*/

1366
int end_trans(THD *thd, enum enum_mysql_completiontype completion)
unknown's avatar
WL#1967  
unknown committed
1367 1368 1369
{
  bool do_release= 0;
  int res= 0;
1370
  DBUG_ENTER("end_trans");
unknown's avatar
WL#1967  
unknown committed
1371

1372
  if (unlikely(thd->in_sub_stmt))
1373 1374 1375 1376
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    DBUG_RETURN(1);
  }
1377 1378 1379 1380 1381 1382
  if (thd->transaction.xid_state.xa_state != XA_NOTR)
  {
    my_error(ER_XAER_RMFAIL, MYF(0),
             xa_state_names[thd->transaction.xid_state.xa_state]);
    DBUG_RETURN(1);
  }
unknown's avatar
WL#1967  
unknown committed
1383 1384 1385 1386 1387 1388 1389 1390
  switch (completion) {
  case COMMIT:
    /*
     We don't use end_active_trans() here to ensure that this works
     even if there is a problem with the OPTION_AUTO_COMMIT flag
     (Which of course should never happen...)
    */
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
1391
    res= ha_commit(thd);
unknown's avatar
unknown committed
1392
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
WL#1967  
unknown committed
1393 1394
    break;
  case COMMIT_RELEASE:
unknown's avatar
unknown committed
1395
    do_release= 1; /* fall through */
unknown's avatar
WL#1967  
unknown committed
1396 1397 1398 1399 1400 1401
  case COMMIT_AND_CHAIN:
    res= end_active_trans(thd);
    if (!res && completion == COMMIT_AND_CHAIN)
      res= begin_trans(thd);
    break;
  case ROLLBACK_RELEASE:
unknown's avatar
unknown committed
1402
    do_release= 1; /* fall through */
unknown's avatar
WL#1967  
unknown committed
1403 1404 1405 1406
  case ROLLBACK:
  case ROLLBACK_AND_CHAIN:
  {
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
unknown's avatar
unknown committed
1407
    if (ha_rollback(thd))
unknown's avatar
WL#1967  
unknown committed
1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418
      res= -1;
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
    if (!res && (completion == ROLLBACK_AND_CHAIN))
      res= begin_trans(thd);
    break;
  }
  default:
    res= -1;
    my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
    DBUG_RETURN(-1);
  }
unknown's avatar
unknown committed
1419

unknown's avatar
WL#1967  
unknown committed
1420 1421 1422
  if (res < 0)
    my_error(thd->killed_errno(), MYF(0));
  else if ((res == 0) && do_release)
unknown's avatar
unknown committed
1423 1424
    thd->killed= THD::KILL_CONNECTION;

unknown's avatar
WL#1967  
unknown committed
1425 1426
  DBUG_RETURN(res);
}
unknown's avatar
unknown committed
1427

1428
#ifndef EMBEDDED_LIBRARY
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439

/*
  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
1440 1441 1442
bool do_command(THD *thd)
{
  char *packet;
unknown's avatar
unknown committed
1443 1444
  uint old_timeout;
  ulong packet_length;
unknown's avatar
unknown committed
1445 1446 1447 1448 1449
  NET *net;
  enum enum_server_command command;
  DBUG_ENTER("do_command");

  net= &thd->net;
unknown's avatar
unknown committed
1450 1451 1452 1453
  /*
    indicator of uninitialized lex => normal flow of errors handling
    (see my_message_sql)
  */
1454
  thd->lex->current_select= 0;
unknown's avatar
unknown committed
1455 1456

  packet=0;
unknown's avatar
unknown committed
1457
  old_timeout=net->read_timeout;
unknown's avatar
unknown committed
1458
  /* Wait max for 8 hours */
unknown's avatar
unknown committed
1459
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
unknown's avatar
unknown committed
1460
  thd->clear_error();				// Clear error message
unknown's avatar
unknown committed
1461 1462 1463 1464

  net_new_transaction(net);
  if ((packet_length=my_net_read(net)) == packet_error)
  {
1465 1466 1467 1468 1469
    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)
1470 1471
    {
      statistic_increment(aborted_threads,&LOCK_status);
1472
      DBUG_RETURN(TRUE);			// We have to close it.
1473
    }
1474
    net_send_error(thd, net->last_errno, NullS);
1475
    net->error= 0;
1476
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
1477 1478 1479 1480 1481
  }
  else
  {
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
1482 1483
    if (command >= COM_END)
      command= COM_END;				// Wrong command
unknown's avatar
unknown committed
1484 1485 1486
    DBUG_PRINT("info",("Command on %s = %d (%s)",
		       vio_description(net->vio), command,
		       command_name[command]));
unknown's avatar
unknown committed
1487
  }
unknown's avatar
unknown committed
1488
  net->read_timeout=old_timeout;		// restore it
1489 1490 1491 1492 1493 1494 1495 1496 1497
  /*
    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
1498
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
1499
}
1500
#endif  /* EMBEDDED_LIBRARY */
1501

1502

1503 1504
/*
   Perform one connection-level (COM_XXXX) command.
1505

1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
  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
*/
1519

1520 1521 1522 1523
bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
1524
  bool error= 0;
1525 1526
  DBUG_ENTER("dispatch_command");

1527 1528 1529
  if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
    thd->killed= THD::NOT_KILLED;

1530
  thd->command=command;
unknown's avatar
unknown committed
1531
  /*
1532 1533
    Commands which always take a long time are logged into
    the slow log only if opt_log_slow_admin_statements is set.
unknown's avatar
unknown committed
1534
  */
1535
  thd->enable_slow_log= TRUE;
1536
  thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
unknown's avatar
unknown committed
1537
  thd->set_time();
unknown's avatar
unknown committed
1538 1539 1540
  VOID(pthread_mutex_lock(&LOCK_thread_count));
  thd->query_id=query_id;
  if (command != COM_STATISTICS && command != COM_PING)
unknown's avatar
unknown committed
1541
    next_query_id();
unknown's avatar
unknown committed
1542
  thread_running++;
1543
  /* TODO: set thd->lex->sql_command to SQLCOM_END here */
unknown's avatar
unknown committed
1544
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1545

1546 1547
  thd->server_status&=
           ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
1548
  switch (command) {
unknown's avatar
unknown committed
1549
  case COM_INIT_DB:
unknown's avatar
unknown committed
1550 1551
  {
    LEX_STRING tmp;
1552 1553
    statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB],
			&LOCK_status);
unknown's avatar
unknown committed
1554 1555
    thd->convert_string(&tmp, system_charset_info,
			packet, strlen(packet), thd->charset());
1556 1557
    if (!mysql_change_db(thd, tmp.str, FALSE))
    {
unknown's avatar
unknown committed
1558
      mysql_log.write(thd,command,"%s",thd->db);
1559 1560
      send_ok(thd);
    }
unknown's avatar
unknown committed
1561 1562
    break;
  }
unknown's avatar
unknown committed
1563
#ifdef HAVE_REPLICATION
1564 1565
  case COM_REGISTER_SLAVE:
  {
1566
    if (!register_slave(thd, (uchar*)packet, packet_length))
1567
      send_ok(thd);
1568 1569
    break;
  }
1570
#endif
unknown's avatar
unknown committed
1571
  case COM_TABLE_DUMP:
1572 1573 1574 1575 1576
  {
    char *db, *tbl_name;
    uint db_len= *(uchar*) packet;
    uint tbl_len= *(uchar*) (packet + db_len + 1);

1577
    statistic_increment(thd->status_var.com_other, &LOCK_status);
1578
    thd->enable_slow_log= opt_log_slow_admin_statements;
1579 1580 1581
    db= thd->alloc(db_len + tbl_len + 2);
    tbl_name= strmake(db, packet + 1, db_len)+1;
    strmake(tbl_name, packet + db_len + 2, tbl_len);
unknown's avatar
unknown committed
1582
    mysql_table_dump(thd, db, tbl_name, -1);
1583 1584
    break;
  }
unknown's avatar
unknown committed
1585 1586
  case COM_CHANGE_USER:
  {
unknown's avatar
unknown committed
1587
    thd->change_user();
1588
    thd->clear_error();                         // if errors from rollback
unknown's avatar
unknown committed
1589

1590
    statistic_increment(thd->status_var.com_other, &LOCK_status);
1591
    char *user= (char*) packet;
unknown's avatar
unknown committed
1592
    char *passwd= strend(user)+1;
unknown's avatar
unknown committed
1593 1594 1595 1596 1597
    /* 
      Old clients send null-terminated string ('\0' for empty string) for
      password.  New clients send the size (1 byte) + string (not null
      terminated, so also '\0' for empty string).
    */
unknown's avatar
unknown committed
1598
    char db_buff[NAME_LEN+1];                 // buffer to store db in utf8 
unknown's avatar
unknown committed
1599 1600 1601 1602
    char *db= passwd;
    uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? 
      *passwd++ : strlen(passwd);
    db+= passwd_len + 1;
1603
#ifndef EMBEDDED_LIBRARY
1604
    /* Small check for incoming packet */
unknown's avatar
unknown committed
1605
    if ((uint) ((uchar*) db - net->read_pos) > packet_length)
1606
    {
unknown's avatar
unknown committed
1607
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1608 1609
      break;
    }
1610
#endif
1611
    /* Convert database name to utf8 */
unknown's avatar
unknown committed
1612
    uint dummy_errors;
unknown's avatar
unknown committed
1613 1614
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
                             system_charset_info, db, strlen(db),
unknown's avatar
unknown committed
1615
                             thd->charset(), &dummy_errors)]= 0;
unknown's avatar
unknown committed
1616
    db= db_buff;
unknown's avatar
unknown committed
1617

1618 1619 1620
    /* Save user and privileges */
    uint save_db_length= thd->db_length;
    char *save_db= thd->db;
1621
    Security_context save_security_ctx= *thd->security_ctx;
unknown's avatar
unknown committed
1622
    USER_CONN *save_user_connect= thd->user_connect;
1623 1624

    if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
1625
    {
1626
      thd->security_ctx->user= save_security_ctx.user;
unknown's avatar
unknown committed
1627
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
1628 1629
      break;
    }
unknown's avatar
unknown committed
1630

unknown's avatar
unknown committed
1631 1632
    /* Clear variables that are allocated */
    thd->user_connect= 0;
unknown's avatar
unknown committed
1633
    int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
unknown's avatar
unknown committed
1634

1635 1636
    if (res)
    {
1637
      /* authentication failure, we shall restore old user */
1638
      if (res > 0)
unknown's avatar
unknown committed
1639
        my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1640 1641
      x_free(thd->security_ctx->user);
      *thd->security_ctx= save_security_ctx;
unknown's avatar
unknown committed
1642
      thd->user_connect= save_user_connect;
1643 1644 1645 1646 1647 1648
      thd->db= save_db;
      thd->db_length= save_db_length;
    }
    else
    {
      /* we've authenticated new user */
unknown's avatar
unknown committed
1649 1650
      if (save_user_connect)
	decrease_user_connections(save_user_connect);
1651
      x_free((gptr) save_db);
1652
      x_free((gptr)  save_security_ctx.user);
1653
    }
unknown's avatar
unknown committed
1654 1655
    break;
  }
1656
  case COM_STMT_EXECUTE:
unknown's avatar
unknown committed
1657
  {
1658
    mysql_stmt_execute(thd, packet, packet_length);
unknown's avatar
unknown committed
1659 1660
    break;
  }
1661
  case COM_STMT_FETCH:
1662 1663 1664 1665
  {
    mysql_stmt_fetch(thd, packet, packet_length);
    break;
  }
1666
  case COM_STMT_SEND_LONG_DATA:
unknown's avatar
unknown committed
1667
  {
1668
    mysql_stmt_get_longdata(thd, packet, packet_length);
unknown's avatar
unknown committed
1669 1670
    break;
  }
1671
  case COM_STMT_PREPARE:
unknown's avatar
unknown committed
1672
  {
1673
    mysql_stmt_prepare(thd, packet, packet_length);
unknown's avatar
unknown committed
1674 1675
    break;
  }
1676
  case COM_STMT_CLOSE:
unknown's avatar
unknown committed
1677
  {
1678
    mysql_stmt_close(thd, packet);
unknown's avatar
unknown committed
1679 1680
    break;
  }
1681
  case COM_STMT_RESET:
1682 1683 1684 1685
  {
    mysql_stmt_reset(thd, packet);
    break;
  }
unknown's avatar
unknown committed
1686 1687
  case COM_QUERY:
  {
1688 1689
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
1690
    char *packet_end= thd->query + thd->query_length;
1691
    mysql_log.write(thd,command,"%s",thd->query);
1692
    DBUG_PRINT("query",("%-.4096s",thd->query));
1693 1694 1695 1696

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

1697
    mysql_parse(thd,thd->query, thd->query_length);
1698

unknown's avatar
unknown committed
1699
    while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error)
1700
    {
unknown's avatar
unknown committed
1701
      char *packet= thd->lex->found_semicolon;
1702
      net->no_send_error= 0;
1703
      /*
1704
        Multiple queries exits, execute them individually
1705
	in embedded server - just store them to be executed later 
1706
      */
1707
#ifndef EMBEDDED_LIBRARY
1708 1709
      if (thd->lock || thd->open_tables || thd->derived_tables ||
          thd->prelocked_mode)
1710
        close_thread_tables(thd);
1711
#endif
1712
      ulong length= (ulong)(packet_end-packet);
1713

1714
      log_slow_statement(thd);
1715

1716
      /* Remove garbage at start of query */
unknown's avatar
unknown committed
1717
      while (my_isspace(thd->charset(), *packet) && length > 0)
1718 1719 1720 1721
      {
        packet++;
        length--;
      }
unknown's avatar
unknown committed
1722
      VOID(pthread_mutex_lock(&LOCK_thread_count));
1723
      thd->query_length= length;
1724
      thd->query= packet;
unknown's avatar
unknown committed
1725
      thd->query_id= next_query_id();
1726
      thd->set_time(); /* Reset the query start time. */
1727
      /* TODO: set thd->lex->sql_command to SQLCOM_END here */
1728
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
1729
#ifndef EMBEDDED_LIBRARY
1730
      mysql_parse(thd, packet, length);
1731
#else
unknown's avatar
unknown committed
1732 1733 1734 1735 1736 1737 1738 1739 1740 1741
      /*
	'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
1742
	thd->query_rest.copy(packet, length, thd->query_rest.charset());
unknown's avatar
unknown committed
1743 1744 1745

      thd->server_status&= ~ (SERVER_QUERY_NO_INDEX_USED |
                              SERVER_QUERY_NO_GOOD_INDEX_USED);
1746 1747
      break;
#endif /*EMBEDDED_LIBRARY*/
1748 1749
    }

unknown's avatar
unknown committed
1750 1751 1752 1753 1754
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1755
  case COM_FIELD_LIST:				// This isn't actually needed
unknown's avatar
unknown committed
1756
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1757 1758
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
unknown's avatar
unknown committed
1759 1760 1761
    break;
#else
  {
1762
    char *fields, *pend;
1763 1764
    /* Locked closure of all tables */
    TABLE_LIST *locked_tables= NULL;
unknown's avatar
unknown committed
1765
    TABLE_LIST table_list;
unknown's avatar
unknown committed
1766
    LEX_STRING conv_name;
1767
    /* Saved variable value */
1768 1769
    my_bool old_innodb_table_locks= 
              IF_INNOBASE_DB(thd->variables.innodb_table_locks, FALSE);
1770

unknown's avatar
unknown committed
1771

1772 1773
    statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
			&LOCK_status);
unknown's avatar
unknown committed
1774 1775 1776
    bzero((char*) &table_list,sizeof(table_list));
    if (!(table_list.db=thd->db))
    {
unknown's avatar
unknown committed
1777
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
unknown's avatar
unknown committed
1778 1779
      break;
    }
1780
    pend= strend(packet);
unknown's avatar
unknown committed
1781 1782
    thd->convert_string(&conv_name, system_charset_info,
			packet, (uint) (pend-packet), thd->charset());
1783
    table_list.alias= table_list.table_name= conv_name.str;
1784
    packet= pend+1;
1785 1786 1787 1788 1789 1790 1791 1792 1793

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

1794
    thd->query_length= strlen(packet);       // for simplicity: don't optimize
unknown's avatar
unknown committed
1795 1796
    if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
      break;
1797
    mysql_log.write(thd,command,"%s %s",table_list.table_name, fields);
1798
    if (lower_case_table_names)
1799 1800
      my_casedn_str(files_charset_info, table_list.table_name);
    remove_escape(table_list.table_name);	// This can't have wildcards
unknown's avatar
unknown committed
1801

unknown's avatar
unknown committed
1802
    if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
1803
		     0, 0, test(table_list.schema_table)))
unknown's avatar
unknown committed
1804
      break;
unknown's avatar
unknown committed
1805 1806
    if (grant_option &&
	check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
1807
      break;
1808 1809 1810 1811 1812 1813
    /* init structures for VIEW processing */
    table_list.select_lex= &(thd->lex->select_lex);
    mysql_init_query(thd, (uchar*)"", 0);
    thd->lex->
      select_lex.table_list.link_in_list((byte*) &table_list,
                                         (byte**) &table_list.next_local);
unknown's avatar
unknown committed
1814
    thd->lex->add_to_query_tables(&table_list);
1815

1816 1817
    /* switch on VIEW optimisation: do not fill temporary tables */
    thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
unknown's avatar
unknown committed
1818
    mysqld_list_fields(thd,&table_list,fields);
1819
    thd->lex->unit.cleanup();
1820
    thd->cleanup_after_query();
unknown's avatar
unknown committed
1821 1822 1823 1824
    break;
  }
#endif
  case COM_QUIT:
1825
    /* We don't calculate statistics for this command */
1826
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1827 1828 1829 1830
    net->error=0;				// Don't give 'abort' message
    error=TRUE;					// End server
    break;

unknown's avatar
unknown committed
1831
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1832
    {
unknown's avatar
unknown committed
1833
      char *db=thd->strdup(packet), *alias;
1834
      HA_CREATE_INFO create_info;
unknown's avatar
unknown committed
1835

1836 1837
      statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB],
			  &LOCK_status);
unknown's avatar
unknown committed
1838
      // null test to handle EOM
unknown's avatar
unknown committed
1839
      if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
unknown's avatar
unknown committed
1840
      {
1841
	my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
unknown's avatar
unknown committed
1842 1843
	break;
      }
1844
      if (check_access(thd,CREATE_ACL,db,0,1,0,is_schema_db(db)))
unknown's avatar
unknown committed
1845
	break;
1846
      mysql_log.write(thd,command,packet);
1847
      bzero(&create_info, sizeof(create_info));
1848 1849
      mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
                      &create_info, 0);
unknown's avatar
unknown committed
1850 1851
      break;
    }
unknown's avatar
unknown committed
1852
  case COM_DROP_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1853
    {
1854 1855
      statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB],
			  &LOCK_status);
1856
      char *db=thd->strdup(packet);
unknown's avatar
unknown committed
1857
      /*  null test to handle EOM */
1858
      if (!db || check_db_name(db))
unknown's avatar
unknown committed
1859
      {
1860
	my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
unknown's avatar
unknown committed
1861 1862
	break;
      }
1863
      if (check_access(thd,DROP_ACL,db,0,1,0,is_schema_db(db)))
1864
	break;
unknown's avatar
unknown committed
1865 1866
      if (thd->locked_tables || thd->active_transaction())
      {
unknown's avatar
unknown committed
1867 1868
	my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                   ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
unknown's avatar
unknown committed
1869
	break;
unknown's avatar
unknown committed
1870
      }
1871
      mysql_log.write(thd,command,db);
1872
      mysql_rm_db(thd, db, 0, 0);
unknown's avatar
unknown committed
1873 1874
      break;
    }
1875
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1876 1877
  case COM_BINLOG_DUMP:
    {
unknown's avatar
unknown committed
1878 1879 1880 1881
      ulong pos;
      ushort flags;
      uint32 slave_server_id;

1882
      statistic_increment(thd->status_var.com_other,&LOCK_status);
1883
      thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
unknown committed
1884
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1885
	break;
unknown's avatar
unknown committed
1886

1887
      /* TODO: The following has to be changed to an 8 byte integer */
1888 1889
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
1890
      thd->server_id=0; /* avoid suicide */
unknown's avatar
unknown committed
1891
      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
unknown's avatar
unknown committed
1892
	kill_zombie_dump_threads(slave_server_id);
1893
      thd->server_id = slave_server_id;
unknown's avatar
unknown committed
1894 1895 1896

      mysql_log.write(thd, command, "Log: '%s'  Pos: %ld", packet+10,
                      (long) pos);
1897
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1898
      unregister_slave(thd,1,1);
unknown's avatar
unknown committed
1899
      /*  fake COM_QUIT -- if we get here, the thread needs to terminate */
1900 1901
      error = TRUE;
      net->error = 0;
unknown's avatar
unknown committed
1902 1903
      break;
    }
1904
#endif
unknown's avatar
unknown committed
1905
  case COM_REFRESH:
unknown's avatar
unknown committed
1906 1907 1908 1909 1910 1911
  {
    bool not_used;
    statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH],
                        &LOCK_status);
    ulong options= (ulong) (uchar) packet[0];
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1912
      break;
unknown's avatar
unknown committed
1913 1914 1915 1916 1917
    mysql_log.write(thd,command,NullS);
    if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
      send_ok(thd);
    break;
  }
1918
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1919
  case COM_SHUTDOWN:
1920
  {
1921
    statistic_increment(thd->status_var.com_other, &LOCK_status);
unknown's avatar
unknown committed
1922
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1923
      break; /* purecov: inspected */
1924
    /*
1925 1926 1927 1928
      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].
1929
    */
1930 1931
    enum mysql_enum_shutdown_level level=
      (enum mysql_enum_shutdown_level) (uchar) packet[0];
1932
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
1933 1934 1935 1936 1937 1938 1939
    if (level == SHUTDOWN_DEFAULT)
      level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable
    else if (level != SHUTDOWN_WAIT_ALL_BUFFERS)
    {
      my_error(ER_NOT_SUPPORTED_YET, MYF(0), "this shutdown level");
      break;
    }
1940
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
1941
    mysql_log.write(thd,command,NullS);
1942
    send_eof(thd);
unknown's avatar
unknown committed
1943 1944 1945
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
unknown's avatar
unknown committed
1946
#ifndef OS2
1947
    send_eof(thd);				// This is for 'quit request'
unknown's avatar
unknown committed
1948
#endif
1949
    close_connection(thd, 0, 1);
unknown's avatar
unknown committed
1950 1951 1952 1953
    close_thread_tables(thd);			// Free before kill
    kill_mysql();
    error=TRUE;
    break;
1954
  }
1955
#endif
unknown's avatar
unknown committed
1956 1957
  case COM_STATISTICS:
  {
1958
    mysql_log.write(thd,command,NullS);
1959 1960
    statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS],
			&LOCK_status);
unknown's avatar
unknown committed
1961
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1962
    char buff[200];
unknown's avatar
unknown committed
1963 1964 1965
#else
    char *buff= thd->net.last_error;
#endif
1966
    ulong uptime = (ulong) (thd->start_time - start_time);
unknown's avatar
unknown committed
1967
    sprintf((char*) buff,
1968
	    "Uptime: %lu  Threads: %d  Questions: %lu  Slow queries: %lu  Opens: %lu  Flush tables: %lu  Open tables: %u  Queries per second avg: %.3f",
unknown's avatar
unknown committed
1969
	    uptime,
1970 1971 1972
	    (int) thread_count, (ulong) thd->query_id,
            (ulong) thd->status_var.long_query_count,
	    thd->status_var.opened_tables, refresh_version, cached_tables(),
1973 1974
	    (uptime ? (ulonglong2double(thd->query_id) / (double) uptime) :
	     (double) 0));
unknown's avatar
unknown committed
1975
#ifdef SAFEMALLOC
1976
    if (sf_malloc_cur_memory)				// Using SAFEMALLOC
unknown's avatar
unknown committed
1977
      sprintf(strend(buff), "  Memory in use: %ldK  Max memory used: %ldK",
1978 1979
	      (sf_malloc_cur_memory+1023L)/1024L,
	      (sf_malloc_max_memory+1023L)/1024L);
unknown's avatar
unknown committed
1980 1981
#endif
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1982
    VOID(my_net_write(net, buff,(uint) strlen(buff)));
unknown's avatar
unknown committed
1983
    VOID(net_flush(net));
unknown's avatar
unknown committed
1984
#endif
unknown's avatar
unknown committed
1985 1986 1987
    break;
  }
  case COM_PING:
1988
    statistic_increment(thd->status_var.com_other, &LOCK_status);
1989
    send_ok(thd);				// Tell client we are alive
unknown's avatar
unknown committed
1990 1991
    break;
  case COM_PROCESS_INFO:
1992 1993
    statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
			&LOCK_status);
1994 1995
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd, PROCESS_ACL))
unknown's avatar
unknown committed
1996
      break;
1997
    mysql_log.write(thd,command,NullS);
unknown's avatar
SCRUM:  
unknown committed
1998
    mysqld_list_processes(thd,
1999 2000
			  thd->security_ctx->master_access & PROCESS_ACL ? 
			  NullS : thd->security_ctx->priv_user, 0);
unknown's avatar
unknown committed
2001 2002 2003
    break;
  case COM_PROCESS_KILL:
  {
2004
    statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
2005
    ulong id=(ulong) uint4korr(packet);
unknown's avatar
SCRUM  
unknown committed
2006
    kill_one_thread(thd,id,false);
unknown's avatar
unknown committed
2007 2008
    break;
  }
2009 2010
  case COM_SET_OPTION:
  {
2011 2012
    statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION],
			&LOCK_status);
2013 2014 2015 2016
    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
2017
      send_eof(thd);
2018 2019 2020
      break;
    case MYSQL_OPTION_MULTI_STATEMENTS_OFF:
      thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
unknown's avatar
unknown committed
2021
      send_eof(thd);
2022 2023
      break;
    default:
unknown's avatar
unknown committed
2024
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
2025 2026 2027 2028
      break;
    }
    break;
  }
unknown's avatar
unknown committed
2029
  case COM_DEBUG:
2030
    statistic_increment(thd->status_var.com_other, &LOCK_status);
unknown's avatar
unknown committed
2031
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2032
      break;					/* purecov: inspected */
2033
    mysql_print_status();
2034
    mysql_log.write(thd,command,NullS);
2035
    send_eof(thd);
unknown's avatar
unknown committed
2036 2037 2038 2039 2040
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
2041
  case COM_END:
unknown's avatar
unknown committed
2042
  default:
unknown's avatar
unknown committed
2043
    my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
2044 2045
    break;
  }
2046 2047
  if (thd->lock || thd->open_tables || thd->derived_tables ||
      thd->prelocked_mode)
unknown's avatar
unknown committed
2048 2049 2050 2051
  {
    thd->proc_info="closing tables";
    close_thread_tables(thd);			/* Free tables */
  }
unknown's avatar
unknown committed
2052 2053 2054 2055 2056 2057 2058 2059 2060 2061
  /*
    assume handlers auto-commit (if some doesn't - transaction handling
    in MySQL should be redesigned to support it; it's a big change,
    and it's not worth it - better to commit explicitly only writing
    transactions, read-only ones should better take care of themselves.
    saves some work in 2pc too)
    see also sql_base.cc - close_thread_tables()
  */
  bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
  if (!thd->active_transaction())
2062
    thd->transaction.xid_state.xid.null();
unknown's avatar
unknown committed
2063

unknown's avatar
unknown committed
2064 2065 2066
  /* report error issued during command execution */
  if (thd->killed_errno() && !thd->net.report_error)
    thd->send_kill_message();
unknown's avatar
unknown committed
2067
  if (thd->net.report_error)
2068
    net_send_error(thd);
unknown's avatar
unknown committed
2069

2070
  log_slow_statement(thd);
2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085

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


2086
void log_slow_statement(THD *thd)
2087
{
2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098
  time_t start_of_query;

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

  start_of_query= thd->start_time;
2099
  thd->end_time();				// Set start time
2100

2101 2102 2103 2104 2105
  /*
    Do not log administrative statements unless the appropriate option is
    set; do not log into slow log if reading from backup.
  */
  if (thd->enable_slow_log && !thd->user_time)
unknown's avatar
unknown committed
2106
  {
2107 2108
    thd->proc_info="logging slow query";

2109 2110
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
2111 2112
	((thd->server_status &
	  (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
2113
	 (specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES)))
2114
    {
2115
      thd->status_var.long_query_count++;
2116 2117
      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
    }
unknown's avatar
unknown committed
2118 2119 2120
  }
}

2121

2122 2123 2124 2125 2126
int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
                         enum enum_schema_tables schema_table_idx)
{
  DBUG_ENTER("prepare_schema_table");
  SELECT_LEX *sel= 0;
2127
  switch (schema_table_idx) {
2128 2129
  case SCH_SCHEMATA:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
unknown's avatar
unknown committed
2130 2131
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0));   /* purecov: inspected */
2132 2133 2134 2135 2136 2137 2138 2139 2140 2141
    DBUG_RETURN(1);
#else
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
	check_global_access(thd, SHOW_DB_ACL))
      DBUG_RETURN(1);
    break;
#endif
  case SCH_TABLE_NAMES:
  case SCH_TABLES:
  case SCH_VIEWS:
2142
  case SCH_TRIGGERS:
2143
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2144 2145
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
2146 2147 2148 2149 2150 2151
    DBUG_RETURN(1);
#else
    {
      char *db= lex->select_lex.db ? lex->select_lex.db : thd->db;
      if (!db)
      {
unknown's avatar
unknown committed
2152 2153
	my_message(ER_NO_DB_ERROR,
                   ER(ER_NO_DB_ERROR), MYF(0)); /* purecov: inspected */
2154 2155 2156 2157 2158
        DBUG_RETURN(1);				/* purecov: inspected */
      }
      remove_escape(db);				// Fix escaped '_'
      if (check_db_name(db))
      {
unknown's avatar
unknown committed
2159
        my_error(ER_WRONG_DB_NAME, MYF(0), db);
2160 2161
        DBUG_RETURN(1);
      }
2162 2163
      if (check_access(thd, SELECT_ACL, db, &thd->col_access, 0, 0,
                       is_schema_db(db)))
2164 2165 2166
        DBUG_RETURN(1);			        /* purecov: inspected */
      if (!thd->col_access && check_grant_db(thd,db))
      {
unknown's avatar
unknown committed
2167
	my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
2168 2169
                 thd->security_ctx->priv_user, thd->security_ctx->priv_host,
                 db);
2170 2171
	DBUG_RETURN(1);
      }
2172 2173 2174 2175 2176
      /*
        We need to do a copy to make this prepared statement safe if this
        was thd->db
      */
      lex->select_lex.db= thd->strdup(db);
2177 2178 2179 2180 2181 2182
      break;
    }
#endif
  case SCH_COLUMNS:
  case SCH_STATISTICS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2183 2184
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
2185 2186 2187 2188 2189 2190
    DBUG_RETURN(1);
#else
    if (table_ident)
    {
      TABLE_LIST **query_tables_last= lex->query_tables_last;
      sel= new SELECT_LEX();
unknown's avatar
unknown committed
2191 2192
      /* 'parent_lex' is used in init_query() so it must be before it. */
      sel->parent_lex= lex;
2193
      sel->init_query();
unknown's avatar
unknown committed
2194
      if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, 
2195 2196 2197 2198 2199 2200
                                 (List<String> *) 0, (List<String> *) 0))
        DBUG_RETURN(1);
      lex->query_tables_last= query_tables_last;
      TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
      char *db= table_list->db;
      remove_escape(db);			// Fix escaped '_'
2201
      remove_escape(table_list->table_name);
2202
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
2203 2204
                       &table_list->grant.privilege, 0, 0,
                       test(table_list->schema_table)))
2205 2206 2207 2208 2209 2210 2211
        DBUG_RETURN(1);				/* purecov: inspected */
      if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2,
                                      UINT_MAX, 0))
        DBUG_RETURN(1);
      break;
    }
#endif
2212 2213 2214
  case SCH_OPEN_TABLES:
  case SCH_VARIABLES:
  case SCH_STATUS:
2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235
  case SCH_PROCEDURES:
  case SCH_CHARSETS:
  case SCH_COLLATIONS:
  case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
  case SCH_USER_PRIVILEGES:
  case SCH_SCHEMA_PRIVILEGES:
  case SCH_TABLE_PRIVILEGES:
  case SCH_COLUMN_PRIVILEGES:
  case SCH_TABLE_CONSTRAINTS:
  case SCH_KEY_COLUMN_USAGE:
  default:
    break;
  }
  
  SELECT_LEX *select_lex= lex->current_select;
  if (make_schema_select(thd, select_lex, schema_table_idx))
  {
    DBUG_RETURN(1);
  }
  TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
  table_list->schema_select_lex= sel;
2236
  table_list->schema_table_reformed= 1;
2237 2238
  statistic_increment(thd->status_var.com_stat[lex->orig_sql_command],
                      &LOCK_status);
2239 2240 2241 2242
  DBUG_RETURN(0);
}


2243 2244
/*
  Read query from packet and store in thd->query
2245
  Used in COM_QUERY and COM_STMT_PREPARE
2246 2247 2248 2249 2250 2251 2252

  DESCRIPTION
    Sets the following THD variables:
      query
      query_length

  RETURN VALUES
unknown's avatar
unknown committed
2253 2254
    FALSE ok
    TRUE  error;  In this case thd->fatal_error is set
2255 2256
*/

2257
bool alloc_query(THD *thd, const char *packet, uint packet_length)
2258 2259
{
  packet_length--;				// Remove end null
2260
  /* Remove garbage at start and end of query */
unknown's avatar
unknown committed
2261
  while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
2262 2263 2264 2265
  {
    packet++;
    packet_length--;
  }
2266
  const char *pos= packet + packet_length;     // Point at end null
unknown's avatar
unknown committed
2267
  while (packet_length > 0 &&
unknown's avatar
unknown committed
2268
	 (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
2269 2270 2271 2272 2273
  {
    pos--;
    packet_length--;
  }
  /* We must allocate some extra memory for query cache */
unknown's avatar
unknown committed
2274
  thd->query_length= 0;                        // Extra safety: Avoid races
2275 2276
  if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
					      packet_length,
2277 2278
					      thd->db_length+ 1 +
					      QUERY_CACHE_FLAGS_SIZE)))
unknown's avatar
unknown committed
2279
    return TRUE;
2280 2281
  thd->query[packet_length]=0;
  thd->query_length= packet_length;
2282 2283 2284 2285

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

unknown's avatar
unknown committed
2287
  return FALSE;
2288 2289
}

2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305
static void reset_one_shot_variables(THD *thd) 
{
  thd->variables.character_set_client=
    global_system_variables.character_set_client;
  thd->variables.collation_connection=
    global_system_variables.collation_connection;
  thd->variables.collation_database=
    global_system_variables.collation_database;
  thd->variables.collation_server=
    global_system_variables.collation_server;
  thd->update_charset();
  thd->variables.time_zone=
    global_system_variables.time_zone;
  thd->one_shot_set= 0;
}

2306

unknown's avatar
unknown committed
2307 2308 2309 2310 2311
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/

unknown's avatar
unknown committed
2312
bool
2313
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
2314
{
unknown's avatar
unknown committed
2315
  bool	res= FALSE;
unknown's avatar
unknown committed
2316
  int result= 0;
unknown's avatar
unknown committed
2317
  LEX	*lex= thd->lex;
unknown's avatar
unknown committed
2318
  /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
unknown's avatar
unknown committed
2319
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
2320
  /* first table of first SELECT_LEX */
unknown's avatar
unknown committed
2321
  TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
unknown's avatar
VIEW  
unknown committed
2322 2323 2324
  /* list of all tables in query */
  TABLE_LIST *all_tables;
  /* most outer SELECT_LEX_UNIT of query */
2325
  SELECT_LEX_UNIT *unit= &lex->unit;
2326
  /* Saved variable value */
unknown's avatar
unknown committed
2327
  DBUG_ENTER("mysql_execute_command");
2328
  thd->net.no_send_error= 0;
unknown's avatar
unknown committed
2329

unknown's avatar
VIEW  
unknown committed
2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345
  /*
    In many cases first table of main SELECT_LEX have special meaning =>
    check that it is first table in global list and relink it first in 
    queries_tables list if it is necessary (we need such relinking only
    for queries with subqueries in select list, in this case tables of
    subqueries will go to global list first)

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

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

2353 2354 2355 2356 2357
  /*
    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.
2358
    Don't reset warnings when executing a stored routine.
2359
  */
2360
  if ((all_tables || &lex->select_lex != lex->all_selects_list ||
2361
       lex->sroutines.records) && !thd->spcont ||
2362
      lex->time_zone_tables_used)
unknown's avatar
unknown committed
2363
    mysql_reset_errors(thd, 0);
2364

unknown's avatar
SCRUM  
unknown committed
2365
#ifdef HAVE_REPLICATION
2366 2367
  if (thd->slave_thread)
  {
unknown's avatar
unknown committed
2368
    /*
unknown's avatar
unknown committed
2369 2370
      Check if statment should be skipped because of slave filtering
      rules
2371 2372

      Exceptions are:
unknown's avatar
unknown committed
2373 2374
      - UPDATE MULTI: For this statement, we want to check the filtering
        rules later in the code
2375
      - SET: we always execute it (Not that many SET commands exists in
unknown's avatar
unknown committed
2376 2377
        the binary log anyway -- only 4.1 masters write SET statements,
	in 5.0 there are no SET statements in the binary log)
2378 2379
      - 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
2380
    */
unknown's avatar
unknown committed
2381 2382
    if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
	!(lex->sql_command == SQLCOM_SET_OPTION) &&
2383
	!(lex->sql_command == SQLCOM_DROP_TABLE &&
2384
          lex->drop_temporary && lex->drop_if_exists) &&
unknown's avatar
Merge  
unknown committed
2385
        all_tables_not_ok(thd, all_tables))
unknown's avatar
Fix for  
unknown committed
2386 2387
    {
      /* we warn the slave SQL thread */
unknown's avatar
unknown committed
2388
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
2389
      reset_one_shot_variables(thd);
2390
      DBUG_RETURN(0);
unknown's avatar
Fix for  
unknown committed
2391
    }
unknown's avatar
merge  
unknown committed
2392 2393
#ifndef TO_BE_DELETED
    /*
2394 2395 2396
      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
2397
    */
2398 2399 2400
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
unknown's avatar
unknown committed
2401
      lex->insert_list = &select_lex->item_list;
2402
    }
unknown's avatar
merge  
unknown committed
2403
#endif
2404
  }
unknown's avatar
SCRUM:  
unknown committed
2405
#endif /* !HAVE_REPLICATION */
2406

2407 2408 2409 2410 2411
  /*
    When option readonly is set deny operations which change tables.
    Except for the replication thread and the 'super' users.
  */
  if (opt_readonly &&
2412 2413
      !(thd->slave_thread ||
        (thd->security_ctx->master_access & SUPER_ACL)) &&
unknown's avatar
unknown committed
2414
      uc_update_queries[lex->sql_command])
2415
  {
unknown's avatar
unknown committed
2416
    my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
unknown's avatar
unknown committed
2417
    DBUG_RETURN(-1);
2418
  }
2419 2420 2421
  if(lex->orig_sql_command == SQLCOM_END)
    statistic_increment(thd->status_var.com_stat[lex->sql_command],
                        &LOCK_status);
2422

unknown's avatar
unknown committed
2423 2424 2425
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
2426 2427 2428 2429
    /* assign global limit variable if limit is not given */
    {
      SELECT_LEX *param= lex->unit.global_parameters;
      if (!param->explicit_limit)
2430 2431
	param->select_limit=
          new Item_int((ulonglong)thd->variables.select_limit);
2432 2433
    }

unknown's avatar
unknown committed
2434
    select_result *result=lex->result;
unknown's avatar
VIEW  
unknown committed
2435
    if (all_tables)
unknown's avatar
unknown committed
2436
    {
2437 2438 2439 2440 2441 2442
      if (lex->orig_sql_command != SQLCOM_SHOW_STATUS_PROC &&
          lex->orig_sql_command != SQLCOM_SHOW_STATUS_FUNC)
        res= check_table_access(thd,
                                lex->exchange ? SELECT_ACL | FILE_ACL :
                                SELECT_ACL,
                                all_tables, 0);
unknown's avatar
unknown committed
2443 2444
    }
    else
unknown's avatar
VIEW  
unknown committed
2445 2446
      res= check_access(thd,
			lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
2447
			any_db, 0, 0, 0, 0);
unknown's avatar
unknown committed
2448
    if (res)
unknown's avatar
unknown committed
2449
      goto error;
unknown's avatar
unknown committed
2450

unknown's avatar
VIEW  
unknown committed
2451
    if (!(res= open_and_lock_tables(thd, all_tables)))
unknown's avatar
unknown committed
2452
    {
unknown's avatar
unknown committed
2453
      if (lex->describe)
unknown's avatar
unknown committed
2454
      {
2455 2456 2457 2458 2459 2460
        /*
          We always use select_send for EXPLAIN, even if it's an EXPLAIN
          for SELECT ... INTO OUTFILE: a user application should be able
          to prepend EXPLAIN to any query and receive output for it,
          even if the query itself redirects the output.
        */
2461
	if (!(result= new select_send()))
2462
	  goto error;
2463 2464
	else
	  thd->send_explain_fields(result);
unknown's avatar
unknown committed
2465
	res= mysql_explain_union(thd, &thd->lex->unit, result);
unknown's avatar
unknown committed
2466 2467 2468 2469 2470
	if (lex->describe & DESCRIBE_EXTENDED)
	{
	  char buff[1024];
	  String str(buff,(uint32) sizeof(buff), system_charset_info);
	  str.length(0);
unknown's avatar
unknown committed
2471
	  thd->lex->unit.print(&str);
unknown's avatar
unknown committed
2472 2473 2474 2475
	  str.append('\0');
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
		       ER_YES, str.ptr());
	}
2476
	result->send_eof();
2477
        delete result;
unknown's avatar
unknown committed
2478 2479 2480
      }
      else
      {
2481
	if (!result && !(result= new select_send()))
unknown's avatar
unknown committed
2482
          goto error;
unknown's avatar
VIEW  
unknown committed
2483
	query_cache_store_query(thd, all_tables);
2484
	res= handle_select(thd, lex, result, 0);
2485 2486
        if (result != lex->result)
          delete result;
unknown's avatar
unknown committed
2487
      }
unknown's avatar
unknown committed
2488
    }
unknown's avatar
unknown committed
2489 2490
    break;
  }
unknown's avatar
unknown committed
2491
  case SQLCOM_PREPARE:
2492
  {
2493
    mysql_sql_stmt_prepare(thd);
unknown's avatar
unknown committed
2494 2495 2496 2497
    break;
  }
  case SQLCOM_EXECUTE:
  {
2498
    mysql_sql_stmt_execute(thd);
unknown's avatar
unknown committed
2499 2500 2501 2502
    break;
  }
  case SQLCOM_DEALLOCATE_PREPARE:
  {
2503
    mysql_sql_stmt_close(thd);
unknown's avatar
unknown committed
2504 2505
    break;
  }
unknown's avatar
unknown committed
2506
  case SQLCOM_DO:
2507 2508
    if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
        open_and_lock_tables(thd, all_tables))
unknown's avatar
unknown committed
2509
      goto error;
unknown's avatar
unknown committed
2510 2511

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

2514
  case SQLCOM_EMPTY_QUERY:
2515
    send_ok(thd);
2516 2517
    break;

unknown's avatar
unknown committed
2518 2519 2520 2521
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

2522
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2523
  case SQLCOM_PURGE:
2524
  {
unknown's avatar
unknown committed
2525
    if (check_global_access(thd, SUPER_ACL))
2526
      goto error;
unknown's avatar
unknown committed
2527
    /* PURGE MASTER LOGS TO 'file' */
2528 2529 2530
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
2531 2532
  case SQLCOM_PURGE_BEFORE:
  {
2533 2534
    Item *it;

2535 2536
    if (check_global_access(thd, SUPER_ACL))
      goto error;
unknown's avatar
unknown committed
2537
    /* PURGE MASTER LOGS BEFORE 'data' */
2538
    it= (Item *)lex->value_list.head();
2539
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) ||
unknown's avatar
unknown committed
2540
        it->check_cols(1))
2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551
    {
      my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE");
      goto error;
    }
    it= new Item_func_unix_timestamp(it);
    /*
      it is OK only emulate fix_fieds, because we need only
      value of constant
    */
    it->quick_fix_field();
    res = purge_master_logs_before_date(thd, (ulong)it->val_int());
2552 2553
    break;
  }
2554
#endif
unknown's avatar
unknown committed
2555 2556
  case SQLCOM_SHOW_WARNS:
  {
2557 2558
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
2559 2560 2561
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
unknown's avatar
unknown committed
2562 2563 2564 2565
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
2566 2567
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
2568 2569
    break;
  }
unknown's avatar
unknown committed
2570 2571
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
2572
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2573
      goto error;
2574
    /* This query don't work now. See comment in repl_failsafe.cc */
unknown's avatar
unknown committed
2575
#ifndef WORKING_NEW_MASTER
unknown's avatar
unknown committed
2576 2577
    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
    goto error;
unknown's avatar
unknown committed
2578
#else
unknown's avatar
unknown committed
2579 2580
    res = show_new_master(thd);
    break;
unknown's avatar
unknown committed
2581
#endif
unknown's avatar
unknown committed
2582
  }
2583

unknown's avatar
unknown committed
2584
#ifdef HAVE_REPLICATION
2585 2586
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
2587
    if (check_global_access(thd, REPL_SLAVE_ACL))
2588 2589 2590 2591
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
2592 2593
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
2594
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2595
      goto error;
unknown's avatar
unknown committed
2596
    res = mysql_show_binlog_events(thd);
unknown's avatar
unknown committed
2597 2598
    break;
  }
2599 2600
#endif

unknown's avatar
unknown committed
2601
  case SQLCOM_BACKUP_TABLE:
2602
  {
unknown's avatar
VIEW  
unknown committed
2603 2604 2605
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL, all_tables, 0) ||
unknown's avatar
unknown committed
2606
	check_global_access(thd, FILE_ACL))
2607
      goto error; /* purecov: inspected */
2608
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2609
    res = mysql_backup_table(thd, first_table);
unknown's avatar
unknown committed
2610

2611 2612
    break;
  }
unknown's avatar
unknown committed
2613
  case SQLCOM_RESTORE_TABLE:
2614
  {
unknown's avatar
VIEW  
unknown committed
2615 2616 2617
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, INSERT_ACL, all_tables, 0) ||
unknown's avatar
unknown committed
2618
	check_global_access(thd, FILE_ACL))
2619
      goto error; /* purecov: inspected */
2620
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2621
    res = mysql_restore_table(thd, first_table);
2622 2623
    break;
  }
unknown's avatar
unknown committed
2624 2625
  case SQLCOM_ASSIGN_TO_KEYCACHE:
  {
unknown's avatar
VIEW  
unknown committed
2626 2627 2628
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
        check_access(thd, INDEX_ACL, first_table->db,
2629 2630
                     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
unknown's avatar
unknown committed
2631
      goto error;
unknown's avatar
unknown committed
2632
    res= mysql_assign_to_keycache(thd, first_table, &lex->ident);
unknown's avatar
unknown committed
2633 2634
    break;
  }
unknown's avatar
unknown committed
2635 2636
  case SQLCOM_PRELOAD_KEYS:
  {
unknown's avatar
VIEW  
unknown committed
2637 2638 2639
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_access(thd, INDEX_ACL, first_table->db,
2640 2641
                     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
2642
      goto error;
unknown's avatar
VIEW  
unknown committed
2643
    res = mysql_preload_keys(thd, first_table);
unknown's avatar
unknown committed
2644 2645
    break;
  }
unknown's avatar
unknown committed
2646
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2647
  case SQLCOM_CHANGE_MASTER:
2648
  {
unknown's avatar
unknown committed
2649
    if (check_global_access(thd, SUPER_ACL))
2650
      goto error;
2651
    pthread_mutex_lock(&LOCK_active_mi);
2652
    res = change_master(thd,active_mi);
2653
    pthread_mutex_unlock(&LOCK_active_mi);
2654 2655
    break;
  }
unknown's avatar
unknown committed
2656
  case SQLCOM_SHOW_SLAVE_STAT:
2657
  {
2658 2659
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2660
      goto error;
2661
    pthread_mutex_lock(&LOCK_active_mi);
2662
    res = show_master_info(thd,active_mi);
2663
    pthread_mutex_unlock(&LOCK_active_mi);
2664 2665
    break;
  }
unknown's avatar
unknown committed
2666
  case SQLCOM_SHOW_MASTER_STAT:
2667
  {
2668 2669
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2670 2671 2672 2673
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
2674

2675
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
2676
    if (check_global_access(thd, SUPER_ACL))
2677
      goto error;
2678
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2679
      goto error;
2680 2681
    else
      res = load_master_data(thd);
2682
    break;
unknown's avatar
unknown committed
2683
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
2684 2685 2686 2687 2688 2689 2690
#ifdef HAVE_NDBCLUSTER_DB
  case SQLCOM_SHOW_NDBCLUSTER_STATUS:
    {
      res = ndbcluster_show_status(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
2691 2692 2693
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
2694
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2695 2696 2697 2698
	goto error;
      res = innodb_show_status(thd);
      break;
    }
unknown's avatar
unknown committed
2699 2700 2701
  case SQLCOM_SHOW_MUTEX_STATUS:
    {
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2702
        goto error;
unknown's avatar
unknown committed
2703 2704 2705
      res = innodb_mutex_show_status(thd);
      break;
    }
unknown's avatar
unknown committed
2706
#endif
unknown's avatar
unknown committed
2707
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2708
  case SQLCOM_LOAD_MASTER_TABLE:
2709
  {
unknown's avatar
VIEW  
unknown committed
2710 2711 2712 2713
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (!first_table->db)
      first_table->db= thd->db;
    if (check_access(thd, CREATE_ACL, first_table->db,
2714 2715
		     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
unknown's avatar
unknown committed
2716 2717 2718 2719
      goto error;				/* purecov: inspected */
    if (grant_option)
    {
      /* Check that the first table has CREATE privilege */
unknown's avatar
VIEW  
unknown committed
2720
      if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
2721
	goto error;
unknown's avatar
unknown committed
2722
    }
2723
    if (strlen(first_table->table_name) > NAME_LEN)
unknown's avatar
unknown committed
2724
    {
2725
      my_error(ER_WRONG_TABLE_NAME, MYF(0), first_table->table_name);
unknown's avatar
unknown committed
2726 2727
      break;
    }
2728
    pthread_mutex_lock(&LOCK_active_mi);
2729 2730 2731 2732
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
2733
    if (!fetch_master_table(thd, first_table->db, first_table->table_name,
2734
			    active_mi, 0, 0))
2735
    {
2736
      send_ok(thd);
2737
    }
2738
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2739
    break;
2740
  }
unknown's avatar
unknown committed
2741
#endif /* HAVE_REPLICATION */
2742

unknown's avatar
unknown committed
2743
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
2744
  {
2745
    /* If CREATE TABLE of non-temporary table, do implicit commit */
2746 2747 2748 2749 2750 2751 2752 2753 2754 2755
    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
    {
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
    else 
    {
unknown's avatar
unknown committed
2756 2757
      /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
      thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
2758
    }
unknown's avatar
VIEW  
unknown committed
2759 2760 2761 2762 2763
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    bool link_to_local;
    // Skip first table, which is the table we are creating
    TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
    TABLE_LIST *select_tables= lex->query_tables;
unknown's avatar
unknown committed
2764

unknown's avatar
VIEW  
unknown committed
2765
    if ((res= create_table_precheck(thd, select_tables, create_table)))
unknown's avatar
unknown committed
2766
      goto end_with_restore_list;
unknown's avatar
unknown committed
2767

2768 2769 2770
#ifndef HAVE_READLINK
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
unknown's avatar
unknown committed
2771
    /* Fix names if symlinked tables */
unknown's avatar
unknown committed
2772
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
2773
			   create_table->table_name) ||
unknown's avatar
VIEW  
unknown committed
2774
	append_file_to_dir(thd, &lex->create_info.index_file_name,
2775
			   create_table->table_name))
unknown's avatar
unknown committed
2776
      goto end_with_restore_list;
2777
#endif
2778
    /*
2779
      If we are using SET CHARSET without DEFAULT, add an implicit
2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790
      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;
    }
2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805
    /*
      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))
    {
unknown's avatar
unknown committed
2806 2807
      res= 1;
      goto end_with_restore_list;
2808
    }
2809
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
2810 2811
    {
      select_result *result;
2812

2813
      select_lex->options|= SELECT_NO_UNLOCK;
2814
      unit->set_limit(select_lex);
2815

unknown's avatar
VIEW  
unknown committed
2816
      if (!(res= open_and_lock_tables(thd, select_tables)))
2817
      {
2818 2819 2820 2821
        /*
          Is table which we are changing used somewhere in other parts
          of query
        */
2822
        if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
2823
        {
2824 2825 2826 2827 2828 2829 2830
          TABLE_LIST *duplicate;
          if ((duplicate= unique_table(create_table, select_tables)))
          {
            update_non_unique_table_error(create_table, "CREATE", duplicate);
            res= 1;
            goto end_with_restart_wait;
          }
2831
        }
unknown's avatar
unknown committed
2832 2833 2834 2835 2836 2837 2838 2839
        /* If we create merge table, we have to test tables in merge, too */
        if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
        {
          TABLE_LIST *tab;
          for (tab= (TABLE_LIST*) lex->create_info.merge_list.first;
               tab;
               tab= tab->next_local)
          {
2840 2841
            TABLE_LIST *duplicate;
            if ((duplicate= unique_table(tab, select_tables)))
unknown's avatar
unknown committed
2842
            {
2843
              update_non_unique_table_error(tab, "CREATE", duplicate);
unknown's avatar
unknown committed
2844 2845
              res= 1;
              goto end_with_restart_wait;
unknown's avatar
unknown committed
2846 2847 2848
            }
          }
        }
2849

unknown's avatar
VIEW  
unknown committed
2850 2851 2852 2853 2854
        if ((result= new select_create(create_table,
				       &lex->create_info,
				       lex->create_list,
				       lex->key_list,
				       select_lex->item_list,
2855 2856
				       lex->duplicates,
				       lex->ignore)))
2857 2858 2859 2860 2861
        {
          /*
            CREATE from SELECT give its SELECT_LEX for SELECT,
            and item_list belong to SELECT
          */
2862
          res= handle_select(thd, lex, result, 0);
2863
          delete result;
2864
        }
unknown's avatar
unknown committed
2865
	/* reset for PS */
2866 2867
	lex->create_list.empty();
	lex->key_list.empty();
2868 2869
      }
    }
unknown's avatar
unknown committed
2870
    else
unknown's avatar
unknown committed
2871
    {
unknown's avatar
unknown committed
2872
      /* regular create */
unknown's avatar
unknown committed
2873
      if (lex->name)
unknown's avatar
unknown committed
2874
        res= mysql_create_like_table(thd, create_table, &lex->create_info, 
unknown's avatar
unknown committed
2875 2876
                                     (Table_ident *)lex->name); 
      else
2877
      {
unknown's avatar
VIEW  
unknown committed
2878
        res= mysql_create_table(thd, create_table->db,
2879
				create_table->table_name, &lex->create_info,
unknown's avatar
VIEW  
unknown committed
2880
				lex->create_list,
unknown's avatar
unknown committed
2881
				lex->key_list, 0, 0);
2882
      }
unknown's avatar
unknown committed
2883
      if (!res)
2884
	send_ok(thd);
unknown's avatar
unknown committed
2885
    }
2886

unknown's avatar
unknown committed
2887
end_with_restart_wait:
2888 2889 2890 2891 2892 2893
    /*
      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);

unknown's avatar
unknown committed
2894
    /* put tables back for PS rexecuting */
unknown's avatar
unknown committed
2895
end_with_restore_list:
unknown's avatar
VIEW  
unknown committed
2896
    lex->link_first_table_back(create_table, link_to_local);
unknown's avatar
unknown committed
2897
    break;
unknown's avatar
unknown committed
2898
  }
unknown's avatar
unknown committed
2899
  case SQLCOM_CREATE_INDEX:
unknown's avatar
VIEW  
unknown committed
2900 2901
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, INDEX_ACL, all_tables))
unknown's avatar
unknown committed
2902
      goto error; /* purecov: inspected */
2903
    thd->enable_slow_log= opt_log_slow_admin_statements;
2904
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2905
      goto error;
2906
    else
unknown's avatar
VIEW  
unknown committed
2907
      res = mysql_create_index(thd, first_table, lex->key_list);
unknown's avatar
unknown committed
2908 2909
    break;

unknown's avatar
unknown committed
2910
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2911
  case SQLCOM_SLAVE_START:
2912
  {
2913
    pthread_mutex_lock(&LOCK_active_mi);
2914
    start_slave(thd,active_mi,1 /* net report*/);
2915
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2916
    break;
2917
  }
unknown's avatar
unknown committed
2918
  case SQLCOM_SLAVE_STOP:
2919 2920 2921 2922 2923 2924
  /*
    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,
2925
      so it waits for the client thread because t is locked by it.
2926
    - then the client thread does SLAVE STOP.
2927 2928
      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.
2929 2930 2931
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
2932
  if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock)
2933
  {
2934 2935
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
2936
    goto error;
2937
  }
2938
  {
2939
    pthread_mutex_lock(&LOCK_active_mi);
2940
    stop_slave(thd,active_mi,1/* net report*/);
2941
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2942
    break;
2943
  }
unknown's avatar
unknown committed
2944
#endif /* HAVE_REPLICATION */
2945

unknown's avatar
unknown committed
2946
  case SQLCOM_ALTER_TABLE:
unknown's avatar
VIEW  
unknown committed
2947
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2948
#if defined(DONT_ALLOW_SHOW_COMMANDS)
unknown's avatar
unknown committed
2949 2950
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2951
    goto error;
unknown's avatar
unknown committed
2952 2953
#else
    {
unknown's avatar
unknown committed
2954
      ulong priv=0;
unknown's avatar
unknown committed
2955
      if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
unknown's avatar
unknown committed
2956
      {
2957
	my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name);
unknown's avatar
unknown committed
2958
        goto error;
unknown's avatar
unknown committed
2959
      }
2960
      if (!select_lex->db)
2961 2962 2963 2964 2965 2966 2967 2968 2969 2970
      {
        /*
          In the case of ALTER TABLE ... RENAME we should supply the
          default database if the new name is not explicitly qualified
          by a database. (Bug #11493)
        */
        if (lex->alter_info.flags & ALTER_RENAME)
        {
          if (! thd->db)
          {
unknown's avatar
unknown committed
2971
            my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
2972 2973 2974 2975 2976
            goto error;
          }
          select_lex->db= thd->db;
        }
        else
2977
          select_lex->db= first_table->db;
2978
      }
unknown's avatar
VIEW  
unknown committed
2979
      if (check_access(thd, ALTER_ACL, first_table->db,
2980 2981 2982 2983
		       &first_table->grant.privilege, 0, 0,
                       test(first_table->schema_table)) ||
	  check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0,
                       is_schema_db(select_lex->db))||
unknown's avatar
VIEW  
unknown committed
2984
	  check_merge_table_access(thd, first_table->db,
2985 2986 2987
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
2988 2989
      if (grant_option)
      {
unknown's avatar
VIEW  
unknown committed
2990
	if (check_grant(thd, ALTER_ACL, all_tables, 0, UINT_MAX, 0))
unknown's avatar
unknown committed
2991 2992 2993 2994 2995
	  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));
2996
	  tmp_table.table_name=lex->name;
2997
	  tmp_table.db=select_lex->db;
unknown's avatar
unknown committed
2998
	  tmp_table.grant.privilege=priv;
unknown's avatar
unknown committed
2999 3000
	  if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
			  UINT_MAX, 0))
unknown's avatar
unknown committed
3001 3002 3003
	    goto error;
	}
      }
unknown's avatar
unknown committed
3004 3005
      /* 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
3006
      /* ALTER TABLE ends previous transaction */
3007
      if (end_active_trans(thd))
unknown's avatar
unknown committed
3008
	goto error;
unknown's avatar
unknown committed
3009
      else
unknown's avatar
unknown committed
3010
      {
3011
        thd->enable_slow_log= opt_log_slow_admin_statements;
3012
	res= mysql_alter_table(thd, select_lex->db, lex->name,
unknown's avatar
unknown committed
3013
			       &lex->create_info,
unknown's avatar
VIEW  
unknown committed
3014
			       first_table, lex->create_list,
3015
			       lex->key_list,
3016
			       select_lex->order_list.elements,
3017
                               (ORDER *) select_lex->order_list.first,
unknown's avatar
unknown committed
3018 3019
			       lex->duplicates, lex->ignore, &lex->alter_info,
                               1);
unknown's avatar
unknown committed
3020
      }
unknown's avatar
unknown committed
3021 3022
      break;
    }
unknown's avatar
SCRUM:  
unknown committed
3023
#endif /*DONT_ALLOW_SHOW_COMMANDS*/
unknown's avatar
unknown committed
3024
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
3025
  {
unknown's avatar
VIEW  
unknown committed
3026
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3027
    TABLE_LIST *table;
unknown's avatar
VIEW  
unknown committed
3028
    if (check_db_used(thd, all_tables))
unknown's avatar
unknown committed
3029
      goto error;
unknown's avatar
VIEW  
unknown committed
3030
    for (table= first_table; table; table= table->next_local->next_local)
unknown's avatar
unknown committed
3031
    {
unknown's avatar
unknown committed
3032
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
3033
		       &table->grant.privilege,0,0, test(table->schema_table)) ||
unknown's avatar
VIEW  
unknown committed
3034
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
3035 3036
		       &table->next_local->grant.privilege, 0, 0,
                       test(table->next_local->schema_table)))
unknown's avatar
unknown committed
3037 3038 3039
	goto error;
      if (grant_option)
      {
unknown's avatar
VIEW  
unknown committed
3040
	TABLE_LIST old_list, new_list;
unknown's avatar
unknown committed
3041 3042 3043 3044
	/*
	  we do not need initialize old_list and new_list because we will
	  come table[0] and table->next[0] there
	*/
unknown's avatar
VIEW  
unknown committed
3045 3046 3047 3048
	old_list= table[0];
	new_list= table->next_local[0];
	if (check_grant(thd, ALTER_ACL, &old_list, 0, 1, 0) ||
	    (!test_all_bits(table->next_local->grant.privilege,
3049
			    INSERT_ACL | CREATE_ACL) &&
unknown's avatar
VIEW  
unknown committed
3050
	     check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
unknown's avatar
unknown committed
3051 3052 3053
	  goto error;
      }
    }
unknown's avatar
VIEW  
unknown committed
3054
    query_cache_invalidate3(thd, first_table, 0);
unknown's avatar
unknown committed
3055 3056
    if (end_active_trans(thd) || mysql_rename_tables(thd, first_table))
      goto error;
unknown's avatar
unknown committed
3057
    break;
unknown's avatar
unknown committed
3058
  }
3059
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
3060 3061
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
3062 3063
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
3064
    goto error;
unknown's avatar
unknown committed
3065 3066
#else
    {
unknown's avatar
unknown committed
3067
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
3068 3069 3070 3071
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
3072
#endif
3073
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
3074
  case SQLCOM_SHOW_CREATE:
unknown's avatar
VIEW  
unknown committed
3075
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3076
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
3077 3078
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
3079
    goto error;
unknown's avatar
unknown committed
3080
#else
unknown's avatar
unknown committed
3081
    {
3082 3083 3084 3085
      /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
      if (lex->only_view)
        first_table->skip_temporary= 1;

unknown's avatar
VIEW  
unknown committed
3086 3087
      if (check_db_used(thd, all_tables) ||
	  check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db,
3088 3089
		       &first_table->grant.privilege, 0, 0, 
                       test(first_table->schema_table)))
unknown's avatar
unknown committed
3090
	goto error;
unknown's avatar
unknown committed
3091
      if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0))
3092
	goto error;
unknown's avatar
unknown committed
3093
      res= mysqld_show_create(thd, first_table);
unknown's avatar
unknown committed
3094 3095
      break;
    }
unknown's avatar
unknown committed
3096
#endif
3097 3098
  case SQLCOM_CHECKSUM:
  {
unknown's avatar
VIEW  
unknown committed
3099 3100 3101
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, 0))
3102
      goto error; /* purecov: inspected */
unknown's avatar
VIEW  
unknown committed
3103
    res = mysql_checksum_table(thd, first_table, &lex->check_opt);
3104 3105
    break;
  }
unknown's avatar
unknown committed
3106
  case SQLCOM_REPAIR:
3107
  {
unknown's avatar
VIEW  
unknown committed
3108 3109 3110
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
3111
      goto error; /* purecov: inspected */
3112
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
3113
    res= mysql_repair_table(thd, first_table, &lex->check_opt);
3114 3115 3116 3117 3118
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
3119
	thd->clear_error(); // No binlog error generated
3120
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3121 3122 3123
        mysql_bin_log.write(&qinfo);
      }
    }
3124 3125
    break;
  }
unknown's avatar
unknown committed
3126
  case SQLCOM_CHECK:
3127
  {
unknown's avatar
VIEW  
unknown committed
3128 3129 3130
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0))
3131
      goto error; /* purecov: inspected */
3132
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
3133
    res = mysql_check_table(thd, first_table, &lex->check_opt);
3134 3135
    break;
  }
unknown's avatar
unknown committed
3136 3137
  case SQLCOM_ANALYZE:
  {
unknown's avatar
VIEW  
unknown committed
3138 3139 3140
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
unknown's avatar
unknown committed
3141
      goto error; /* purecov: inspected */
3142
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
3143
    res = mysql_analyze_table(thd, first_table, &lex->check_opt);
3144 3145 3146 3147 3148
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
3149
	thd->clear_error(); // No binlog error generated
3150
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3151 3152 3153
        mysql_bin_log.write(&qinfo);
      }
    }
unknown's avatar
unknown committed
3154
    break;
unknown's avatar
unknown committed
3155
  }
3156

unknown's avatar
unknown committed
3157 3158
  case SQLCOM_OPTIMIZE:
  {
unknown's avatar
VIEW  
unknown committed
3159 3160 3161
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
unknown's avatar
unknown committed
3162
      goto error; /* purecov: inspected */
3163
    thd->enable_slow_log= opt_log_slow_admin_statements;
3164
    res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
unknown's avatar
VIEW  
unknown committed
3165 3166
      mysql_recreate_table(thd, first_table, 1) :
      mysql_optimize_table(thd, first_table, &lex->check_opt);
3167 3168 3169 3170 3171
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
3172
	thd->clear_error(); // No binlog error generated
3173
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3174 3175 3176
        mysql_bin_log.write(&qinfo);
      }
    }
unknown's avatar
unknown committed
3177 3178 3179
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
VIEW  
unknown committed
3180 3181
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (update_precheck(thd, all_tables))
unknown's avatar
unknown committed
3182
      break;
3183 3184
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
unknown's avatar
unknown committed
3185 3186 3187 3188 3189 3190
    res= (result= mysql_update(thd, all_tables,
                               select_lex->item_list,
                               lex->value_list,
                               select_lex->where,
                               select_lex->order_list.elements,
                               (ORDER *) select_lex->order_list.first,
3191
                               unit->select_limit_cnt,
3192
                               lex->duplicates, lex->ignore));
3193
    /* mysql_update return 2 if we need to switch to multi-update */
unknown's avatar
unknown committed
3194
    if (result != 2)
3195
      break;
3196
  case SQLCOM_UPDATE_MULTI:
3197
    {
unknown's avatar
unknown committed
3198
      DBUG_ASSERT(first_table == all_tables && first_table != 0);
3199
      /* if we switched from normal update, rights are checked */
unknown's avatar
unknown committed
3200 3201 3202 3203 3204 3205 3206 3207
      if (result != 2)
      {
        if ((res= multi_update_precheck(thd, all_tables)))
          break;
      }
      else
        res= 0;

3208 3209
      if ((res= mysql_multi_update_prepare(thd)))
	break;
unknown's avatar
unknown committed
3210

3211
#ifdef HAVE_REPLICATION
3212
      /* Check slave filtering rules */
unknown's avatar
unknown committed
3213
      if (thd->slave_thread && all_tables_not_ok(thd, all_tables))
unknown's avatar
unknown committed
3214 3215 3216 3217 3218
      {
	/* we warn the slave SQL thread */
	my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
	break;
      }
3219
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
3220

unknown's avatar
unknown committed
3221 3222 3223 3224 3225
      res= mysql_multi_update(thd, all_tables,
                              &select_lex->item_list,
                              &lex->value_list,
                              select_lex->where,
                              select_lex->options,
3226
                              lex->duplicates, lex->ignore, unit, select_lex);
unknown's avatar
unknown committed
3227
    break;
unknown's avatar
unknown committed
3228
  }
unknown's avatar
unknown committed
3229
  case SQLCOM_REPLACE:
3230 3231
  case SQLCOM_INSERT:
  {
unknown's avatar
VIEW  
unknown committed
3232
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3233
    if ((res= insert_precheck(thd, all_tables)))
unknown's avatar
unknown committed
3234
      break;
3235 3236
    /* Skip first table, which is the table we are inserting in */
    select_lex->context.table_list= first_table->next_local;
unknown's avatar
VIEW  
unknown committed
3237
    res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
unknown's avatar
unknown committed
3238
		      lex->update_list, lex->value_list,
3239
                      lex->duplicates, lex->ignore);
unknown's avatar
VIEW  
unknown committed
3240 3241
    if (first_table->view && !first_table->contain_auto_increment)
      thd->last_insert_id= 0; // do not show last insert ID if VIEW have not it
unknown's avatar
unknown committed
3242
    break;
3243
  }
unknown's avatar
unknown committed
3244 3245 3246
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
unknown's avatar
unknown committed
3247
    select_result *result;
unknown's avatar
VIEW  
unknown committed
3248
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3249
    if ((res= insert_precheck(thd, all_tables)))
3250
      break;
unknown's avatar
unknown committed
3251

3252
    /* Fix lock for first table */
unknown's avatar
VIEW  
unknown committed
3253 3254
    if (first_table->lock_type == TL_WRITE_DELAYED)
      first_table->lock_type= TL_WRITE;
3255

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

3259
    unit->set_limit(select_lex);
unknown's avatar
VIEW  
unknown committed
3260
    if (!(res= open_and_lock_tables(thd, all_tables)))
3261
    {
3262
      /* Skip first table, which is the table we are inserting in */
unknown's avatar
unknown committed
3263 3264
      TABLE_LIST *second_table= first_table->next_local;
      select_lex->table_list.first= (byte*) second_table;
3265 3266
      select_lex->context.table_list= 
        select_lex->context.first_name_resolution_table= second_table;
3267 3268 3269
      res= mysql_insert_select_prepare(thd);
      if (!res && (result= new select_insert(first_table, first_table->table,
                                             &lex->field_list,
3270 3271
                                             &lex->update_list,
                                             &lex->value_list,
3272
                                             lex->duplicates, lex->ignore)))
3273
      {
unknown's avatar
unknown committed
3274 3275 3276 3277 3278 3279 3280
        /*
          Skip first table, which is the table we are inserting in.
          Below we set context.table_list again because the call above to
          mysql_insert_select_prepare() calls resolve_in_table_list_only(),
          which in turn resets context.table_list and
          context.first_name_resolution_table.
        */
3281 3282
        select_lex->context.table_list= 
          select_lex->context.first_name_resolution_table= second_table;
3283
	res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
3284 3285
        delete result;
      }
3286
      /* revert changes for SP */
unknown's avatar
unknown committed
3287
      select_lex->table_list.first= (byte*) first_table;
3288
    }
unknown's avatar
VIEW  
unknown committed
3289 3290 3291

    if (first_table->view && !first_table->contain_auto_increment)
      thd->last_insert_id= 0; // do not show last insert ID if VIEW have not it
unknown's avatar
unknown committed
3292 3293
    break;
  }
3294
  case SQLCOM_TRUNCATE:
3295 3296 3297 3298 3299
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
VIEW  
unknown committed
3300 3301
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, DELETE_ACL, all_tables))
unknown's avatar
unknown committed
3302
      goto error;
3303 3304 3305 3306
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
3307
    if ((thd->locked_tables && !lex->sphead) || thd->active_transaction())
3308
    {
unknown's avatar
unknown committed
3309 3310
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3311 3312
      goto error;
    }
unknown's avatar
VIEW  
unknown committed
3313

unknown's avatar
unknown committed
3314
    res= mysql_truncate(thd, first_table, 0);
3315
    break;
unknown's avatar
unknown committed
3316
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
3317
  {
unknown's avatar
VIEW  
unknown committed
3318 3319
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if ((res= delete_precheck(thd, all_tables)))
unknown's avatar
unknown committed
3320
      break;
3321 3322
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
unknown's avatar
VIEW  
unknown committed
3323
    res = mysql_delete(thd, all_tables, select_lex->where,
3324
                       &select_lex->order_list,
unknown's avatar
unknown committed
3325 3326
                       unit->select_limit_cnt, select_lex->options,
                       FALSE);
unknown's avatar
unknown committed
3327 3328
    break;
  }
unknown's avatar
unknown committed
3329
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
3330
  {
unknown's avatar
VIEW  
unknown committed
3331
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3332 3333
    TABLE_LIST *aux_tables=
      (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
unknown's avatar
unknown committed
3334
    multi_delete *result;
unknown's avatar
unknown committed
3335

3336
    if ((res= multi_delete_precheck(thd, all_tables)))
3337
      break;
unknown's avatar
unknown committed
3338

unknown's avatar
unknown committed
3339
    /* condition will be TRUE on SP re-excuting */
3340 3341
    if (select_lex->item_list.elements != 0)
      select_lex->item_list.empty();
unknown's avatar
unknown committed
3342
    if (add_item_to_list(thd, new Item_null()))
unknown's avatar
unknown committed
3343
      goto error;
3344

unknown's avatar
unknown committed
3345
    thd->proc_info="init";
unknown's avatar
VIEW  
unknown committed
3346 3347 3348 3349
    if ((res= open_and_lock_tables(thd, all_tables)))
      break;

    if ((res= mysql_multi_delete_prepare(thd)))
unknown's avatar
unknown committed
3350
      goto error;
3351

3352
    if (!thd->is_fatal_error && (result= new multi_delete(aux_tables,
3353
							  lex->table_count)))
unknown's avatar
unknown committed
3354
    {
3355 3356 3357
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
unknown's avatar
unknown committed
3358
			select_lex->item_list,
unknown's avatar
unknown committed
3359
			select_lex->where,
3360
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
unknown's avatar
unknown committed
3361 3362
			(ORDER *)NULL,
			select_lex->options | thd->options |
3363 3364
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
                        OPTION_SETUP_TABLES_DONE,
3365
			result, unit, select_lex);
3366
      delete result;
unknown's avatar
unknown committed
3367 3368
    }
    else
3369
      res= TRUE;                                // Error
unknown's avatar
unknown committed
3370 3371
    break;
  }
unknown's avatar
unknown committed
3372
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
3373
  {
unknown's avatar
VIEW  
unknown committed
3374
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3375 3376
    if (!lex->drop_temporary)
    {
unknown's avatar
VIEW  
unknown committed
3377
      if (check_table_access(thd, DROP_ACL, all_tables, 0))
3378 3379
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
unknown's avatar
unknown committed
3380
        goto error;
3381
    }
unknown's avatar
unknown committed
3382
    else
unknown's avatar
unknown committed
3383 3384 3385 3386 3387 3388
    {
      /*
	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
3389 3390
	To not generate such irrelevant "table does not exist errors",
	we silently add IF EXISTS if TEMPORARY was used.
unknown's avatar
unknown committed
3391 3392 3393
      */
      if (thd->slave_thread)
	lex->drop_if_exists= 1;
3394

unknown's avatar
unknown committed
3395 3396
      /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
      thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
unknown's avatar
unknown committed
3397
    }
unknown's avatar
VIEW  
unknown committed
3398 3399
    res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
			lex->drop_temporary);
unknown's avatar
unknown committed
3400 3401
  }
  break;
unknown's avatar
unknown committed
3402
  case SQLCOM_DROP_INDEX:
unknown's avatar
VIEW  
unknown committed
3403 3404
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, INDEX_ACL, all_tables))
unknown's avatar
unknown committed
3405
      goto error;				/* purecov: inspected */
3406
    if (end_active_trans(thd))
unknown's avatar
unknown committed
3407
      goto error;
3408
    else
unknown's avatar
VIEW  
unknown committed
3409
      res = mysql_drop_index(thd, first_table, &lex->alter_info);
unknown's avatar
unknown committed
3410 3411
    break;
  case SQLCOM_SHOW_PROCESSLIST:
3412 3413
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
3414
      break;
unknown's avatar
SCRUM:  
unknown committed
3415
    mysqld_list_processes(thd,
3416 3417 3418 3419
			  (thd->security_ctx->master_access & PROCESS_ACL ?
                           NullS :
                           thd->security_ctx->priv_user),
                          lex->verbose);
unknown's avatar
unknown committed
3420
    break;
unknown's avatar
unknown committed
3421 3422
  case SQLCOM_SHOW_STORAGE_ENGINES:
    res= mysqld_show_storage_engines(thd);
unknown's avatar
unknown committed
3423 3424 3425 3426 3427 3428 3429
    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
3430 3431
  case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
3432 3433
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
3434
    goto error;
unknown's avatar
unknown committed
3435 3436
#else
    {
3437
      if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0,0))
unknown's avatar
unknown committed
3438 3439 3440 3441
	goto error;
      res= mysqld_show_logs(thd);
      break;
    }
unknown's avatar
unknown committed
3442 3443
#endif
  case SQLCOM_CHANGE_DB:
3444 3445
    if (!mysql_change_db(thd,select_lex->db,FALSE))
      send_ok(thd);
unknown's avatar
unknown committed
3446
    break;
3447

unknown's avatar
unknown committed
3448 3449
  case SQLCOM_LOAD:
  {
unknown's avatar
VIEW  
unknown committed
3450
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3451
    uint privilege= (lex->duplicates == DUP_REPLACE ?
unknown's avatar
unknown committed
3452 3453
		     INSERT_ACL | DELETE_ACL : INSERT_ACL) |
                    (lex->local_file ? 0 : FILE_ACL);
3454

unknown's avatar
unknown committed
3455
    if (lex->local_file)
unknown's avatar
unknown committed
3456
    {
3457
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
3458
          !opt_local_infile)
3459
      {
unknown's avatar
unknown committed
3460
	my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0));
3461 3462
	goto error;
      }
unknown's avatar
unknown committed
3463
    }
unknown's avatar
unknown committed
3464 3465 3466 3467

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

unknown's avatar
VIEW  
unknown committed
3468
    res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
unknown's avatar
unknown committed
3469
                    lex->update_list, lex->value_list, lex->duplicates,
3470
                    lex->ignore, (bool) lex->local_file);
unknown's avatar
unknown committed
3471 3472
    break;
  }
3473

unknown's avatar
unknown committed
3474
  case SQLCOM_SET_OPTION:
3475 3476
  {
    List<set_var_base> *lex_var_list= &lex->var_list;
3477
    if ((check_table_access(thd, SELECT_ACL, all_tables, 0) ||
unknown's avatar
unknown committed
3478 3479
	 open_and_lock_tables(thd, all_tables)))
      goto error;
3480 3481
    if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
    {
unknown's avatar
unknown committed
3482 3483
      my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
      goto error;
3484 3485 3486 3487 3488 3489 3490 3491
    }
    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;
3492
      send_ok(thd);
3493
    }
unknown's avatar
unknown committed
3494
    break;
3495
  }
unknown's avatar
unknown committed
3496

unknown's avatar
unknown committed
3497
  case SQLCOM_UNLOCK_TABLES:
3498 3499 3500 3501 3502 3503
    /*
      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
3504
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
3505 3506
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
3507
      end_active_trans(thd);
unknown's avatar
unknown committed
3508
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3509 3510
    }
    if (thd->global_read_lock)
3511
      unlock_global_read_lock(thd);
3512
    send_ok(thd);
unknown's avatar
unknown committed
3513 3514
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
3515
    unlock_locked_tables(thd);
unknown's avatar
VIEW  
unknown committed
3516
    if (check_db_used(thd, all_tables) || end_active_trans(thd))
unknown's avatar
unknown committed
3517
      goto error;
unknown's avatar
VIEW  
unknown committed
3518
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
3519
      goto error;
unknown's avatar
unknown committed
3520
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
3521
    thd->options|= OPTION_TABLE_LOCK;
unknown's avatar
VIEW  
unknown committed
3522

3523
    if (!(res= simple_open_n_lock_tables(thd, all_tables)))
unknown's avatar
unknown committed
3524
    {
3525 3526
#ifdef HAVE_QUERY_CACHE
      if (thd->variables.query_cache_wlock_invalidate)
unknown's avatar
VIEW  
unknown committed
3527
	query_cache.invalidate_locked_for_write(first_table);
3528
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
3529 3530
      thd->locked_tables=thd->lock;
      thd->lock=0;
3531
      send_ok(thd);
unknown's avatar
unknown committed
3532
    }
unknown's avatar
unknown committed
3533 3534
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3535 3536 3537
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
3538
  {
3539 3540 3541 3542 3543
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
unknown committed
3544
    char *alias;
unknown's avatar
unknown committed
3545
    if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
unknown's avatar
unknown committed
3546
    {
3547
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
unknown's avatar
unknown committed
3548 3549
      break;
    }
3550 3551 3552
    /*
      If in a slave thread :
      CREATE DATABASE DB was certainly not preceded by USE DB.
3553
      For that reason, db_ok() in sql/slave.cc did not check the
3554 3555 3556
      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.
    */
3557
#ifdef HAVE_REPLICATION
3558
    if (thd->slave_thread &&
3559 3560
	(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(lex->name)))
unknown's avatar
Fix for  
unknown committed
3561
    {
unknown's avatar
unknown committed
3562
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3563
      break;
unknown's avatar
Fix for  
unknown committed
3564
    }
3565
#endif
3566
    if (check_access(thd,CREATE_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
3567
      break;
unknown's avatar
unknown committed
3568
    res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name),
unknown's avatar
unknown committed
3569
			 &lex->create_info, 0);
3570 3571
    break;
  }
unknown's avatar
unknown committed
3572
  case SQLCOM_DROP_DB:
3573
  {
3574 3575 3576 3577 3578
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
3579
    if (check_db_name(lex->name))
unknown's avatar
unknown committed
3580
    {
3581
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
unknown's avatar
unknown committed
3582 3583
      break;
    }
3584 3585 3586 3587 3588 3589 3590
    /*
      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.
    */
3591
#ifdef HAVE_REPLICATION
3592 3593 3594
    if (thd->slave_thread && 
	(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(lex->name)))
unknown's avatar
Fix for  
unknown committed
3595
    {
unknown's avatar
unknown committed
3596
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3597
      break;
unknown's avatar
Fix for  
unknown committed
3598
    }
3599
#endif
3600
    if (check_access(thd,DROP_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
3601
      break;
3602 3603
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3604 3605
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3606 3607
      goto error;
    }
3608
    res= mysql_rm_db(thd, lex->name, lex->drop_if_exists, 0);
3609 3610
    break;
  }
3611 3612
  case SQLCOM_ALTER_DB:
  {
3613 3614
    char *db= lex->name ? lex->name : thd->db;
    if (!db)
3615
    {
unknown's avatar
unknown committed
3616 3617
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
      break;
3618 3619
    }
    if (!strip_sp(db) || check_db_name(db))
3620
    {
3621
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
3622 3623
      break;
    }
unknown's avatar
unknown committed
3624 3625 3626
    /*
      If in a slave thread :
      ALTER DATABASE DB may not be preceded by USE DB.
3627
      For that reason, maybe db_ok() in sql/slave.cc did not check the
unknown's avatar
unknown committed
3628 3629 3630 3631
      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
3632
    if (thd->slave_thread &&
3633 3634
	(!db_ok(db, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(db)))
unknown's avatar
unknown committed
3635
    {
unknown's avatar
unknown committed
3636
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
unknown's avatar
unknown committed
3637 3638 3639
      break;
    }
#endif
3640
    if (check_access(thd, ALTER_ACL, db, 0, 1, 0, is_schema_db(db)))
3641 3642 3643
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3644 3645
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3646 3647
      goto error;
    }
3648
    res= mysql_alter_db(thd, db, &lex->create_info);
3649 3650
    break;
  }
unknown's avatar
unknown committed
3651 3652 3653 3654
  case SQLCOM_SHOW_CREATE_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
3655
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
unknown's avatar
unknown committed
3656 3657
      break;
    }
3658
    if (check_access(thd,SELECT_ACL,lex->name,0,1,0,is_schema_db(lex->name)))
unknown's avatar
unknown committed
3659
      break;
unknown's avatar
unknown committed
3660
    res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
unknown's avatar
unknown committed
3661 3662
    break;
  }
unknown's avatar
unknown committed
3663
  case SQLCOM_CREATE_FUNCTION:                  // UDF function
unknown's avatar
unknown committed
3664
  {
3665
    if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
unknown's avatar
unknown committed
3666
      break;
unknown's avatar
unknown committed
3667
#ifdef HAVE_DLOPEN
3668
    if (sp_find_function(thd, lex->spname))
unknown's avatar
unknown committed
3669
    {
3670
      my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str);
unknown's avatar
unknown committed
3671 3672
      goto error;
    }
3673
    if (!(res = mysql_create_function(thd, &lex->udf)))
unknown's avatar
unknown committed
3674
      send_ok(thd);
unknown's avatar
unknown committed
3675
#else
unknown's avatar
unknown committed
3676
    my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled");
unknown's avatar
unknown committed
3677
    res= TRUE;
unknown's avatar
unknown committed
3678 3679
#endif
    break;
unknown's avatar
unknown committed
3680
  }
unknown's avatar
SCRUM:  
unknown committed
3681
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3682 3683
  case SQLCOM_CREATE_USER:
  {
3684
    if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) &&
unknown's avatar
unknown committed
3685
        check_global_access(thd,CREATE_USER_ACL))
3686 3687 3688 3689 3690
      break;
    if (!(res= mysql_create_user(thd, lex->users_list)))
    {
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
3691
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3692 3693 3694 3695 3696 3697
        mysql_bin_log.write(&qinfo);
      }
      send_ok(thd);
    }
    break;
  }
3698 3699
  case SQLCOM_DROP_USER:
  {
3700
    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) &&
unknown's avatar
unknown committed
3701
        check_global_access(thd,CREATE_USER_ACL))
3702 3703 3704 3705 3706
      break;
    if (!(res= mysql_drop_user(thd, lex->users_list)))
    {
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
3707
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3708 3709 3710 3711 3712 3713 3714 3715
        mysql_bin_log.write(&qinfo);
      }
      send_ok(thd);
    }
    break;
  }
  case SQLCOM_RENAME_USER:
  {
3716
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
unknown's avatar
unknown committed
3717
        check_global_access(thd,CREATE_USER_ACL))
3718 3719 3720 3721 3722
      break;
    if (!(res= mysql_rename_user(thd, lex->users_list)))
    {
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
3723
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3724
        mysql_bin_log.write(&qinfo);
3725 3726 3727 3728 3729 3730 3731
      }
      send_ok(thd);
    }
    break;
  }
  case SQLCOM_REVOKE_ALL:
  {
3732
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
unknown's avatar
unknown committed
3733
        check_global_access(thd,CREATE_USER_ACL))
3734 3735 3736 3737 3738
      break;
    if (!(res = mysql_revoke_all(thd, lex->users_list)))
    {
      if (mysql_bin_log.is_open())
      {
3739
	Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3740 3741 3742 3743 3744 3745
	mysql_bin_log.write(&qinfo);
      }
      send_ok(thd);
    }
    break;
  }
3746 3747 3748 3749
  case SQLCOM_REVOKE:
  case SQLCOM_GRANT:
  {
    if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
unknown's avatar
merged  
unknown committed
3750
		     first_table ?  first_table->db : select_lex->db,
unknown's avatar
VIEW  
unknown committed
3751
		     first_table ? &first_table->grant.privilege : 0,
3752 3753 3754
		     first_table ? 0 : 1, 0,
                     first_table ? (bool) first_table->schema_table :
                     select_lex->db ? is_schema_db(select_lex->db) : 0))
3755 3756
      goto error;

3757
    if (thd->security_ctx->user)              // If not replication
unknown's avatar
unknown committed
3758 3759
    {
      LEX_USER *user;
3760 3761
      uint counter;

unknown's avatar
unknown committed
3762
      List_iterator <LEX_USER> user_list(lex->users_list);
unknown's avatar
unknown committed
3763
      while ((user= user_list++))
unknown's avatar
unknown committed
3764
      {
unknown's avatar
unknown committed
3765 3766 3767 3768 3769 3770 3771 3772
        if (specialflag & SPECIAL_NO_RESOLVE &&
            hostname_requires_resolving(user->host.str))
          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                              ER_WARN_HOSTNAME_WONT_WORK,
                              ER(ER_WARN_HOSTNAME_WONT_WORK),
                              user->host.str);
        // Are we trying to change a password of another user
        DBUG_ASSERT(user->host.str != 0);
3773
        if (strcmp(thd->security_ctx->user, user->user.str) ||
unknown's avatar
unknown committed
3774
            my_strcasecmp(system_charset_info,
3775
                          user->host.str, thd->security_ctx->host_or_ip))
unknown's avatar
unknown committed
3776 3777 3778
        {
          // TODO: use check_change_password()
          if (check_acl_user(user, &counter) && user->password.str &&
3779
              check_access(thd, UPDATE_ACL,"mysql",0,1,1,0))
unknown's avatar
unknown committed
3780 3781 3782 3783 3784 3785
          {
            my_message(ER_PASSWORD_NOT_ALLOWED,
                       ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
            goto error;
          }
        }
unknown's avatar
SCRUM  
unknown committed
3786 3787
      }
    }
unknown's avatar
VIEW  
unknown committed
3788
    if (first_table)
3789
    {
3790 3791
      if (lex->type == TYPE_ENUM_PROCEDURE ||
          lex->type == TYPE_ENUM_FUNCTION)
3792 3793 3794 3795 3796
      {
        uint grants= lex->all_privileges 
		   ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
		   : lex->grant;
        if (grant_option && 
3797 3798
	    check_grant_routine(thd, grants | GRANT_ACL, all_tables,
                                lex->type == TYPE_ENUM_PROCEDURE, 0))
3799
	  goto error;
3800 3801 3802 3803
        res= mysql_routine_grant(thd, all_tables,
                                 lex->type == TYPE_ENUM_PROCEDURE, 
                                 lex->users_list, grants,
                                 lex->sql_command == SQLCOM_REVOKE, 0);
3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816
      }
      else
      {
	if (grant_option && check_grant(thd,
					(lex->grant | lex->grant_tot_col |
					 GRANT_ACL),
					all_tables, 0, UINT_MAX, 0))
	  goto error;
        res= mysql_table_grant(thd, all_tables, lex->users_list,
			       lex->columns, lex->grant,
			       lex->sql_command == SQLCOM_REVOKE);
      }
      if (!res && mysql_bin_log.is_open())
3817
      {
unknown's avatar
unknown committed
3818
        thd->clear_error();
unknown's avatar
unknown committed
3819
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3820
        mysql_bin_log.write(&qinfo);
3821 3822 3823 3824
      }
    }
    else
    {
3825
      if (lex->columns.elements || lex->type)
3826
      {
unknown's avatar
unknown committed
3827 3828
	my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
                   MYF(0));
unknown's avatar
unknown committed
3829
        goto error;
3830 3831 3832 3833 3834 3835 3836 3837
      }
      else
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
	if (mysql_bin_log.is_open())
	{
unknown's avatar
unknown committed
3838
          thd->clear_error();
3839
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3840 3841
	  mysql_bin_log.write(&qinfo);
	}
3842
	if (lex->sql_command == SQLCOM_GRANT)
unknown's avatar
unknown committed
3843
	{
unknown's avatar
unknown committed
3844 3845 3846
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
unknown's avatar
unknown committed
3847
	    reset_mqh(user);
unknown's avatar
unknown committed
3848
	}
3849 3850 3851 3852
      }
    }
    break;
  }
unknown's avatar
SCRUM  
unknown committed
3853
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
unknown's avatar
unknown committed
3854
  case SQLCOM_RESET:
3855 3856 3857
    /*
      RESET commands are never written to the binary log, so we have to
      initialize this variable because RESET shares the same code as FLUSH
3858 3859 3860 3861
    */
    lex->no_write_to_binlog= 1;
  case SQLCOM_FLUSH:
  {
unknown's avatar
unknown committed
3862
    bool write_to_binlog;
unknown's avatar
VIEW  
unknown committed
3863
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, all_tables))
unknown's avatar
unknown committed
3864
      goto error;
3865 3866 3867 3868
    /*
      reload_acl_and_cache() will tell us if we are allowed to write to the
      binlog or not.
    */
unknown's avatar
unknown committed
3869
    if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
3870 3871 3872 3873 3874 3875 3876 3877 3878
    {
      /*
        We WANT to write and we CAN write.
        ! we write after unlocking the table.
      */
      if (!lex->no_write_to_binlog && write_to_binlog)
      {
        if (mysql_bin_log.is_open())
        {
3879
          Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
3880 3881 3882 3883 3884
          mysql_bin_log.write(&qinfo);
        }
      }
      send_ok(thd);
    }
unknown's avatar
unknown committed
3885
    break;
3886
  }
unknown's avatar
unknown committed
3887
  case SQLCOM_KILL:
3888 3889 3890
  {
    Item *it= (Item *)lex->value_list.head();

3891
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1))
3892 3893 3894 3895 3896 3897
    {
      my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
		 MYF(0));
      goto error;
    }
    kill_one_thread(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
unknown's avatar
unknown committed
3898
    break;
3899
  }
unknown's avatar
SCRUM:  
unknown committed
3900
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
3901
  case SQLCOM_SHOW_GRANTS:
3902 3903
    if ((thd->security_ctx->priv_user &&
	 !strcmp(thd->security_ctx->priv_user, lex->grant_user->user.str)) ||
3904
	!check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
unknown's avatar
unknown committed
3905 3906 3907 3908
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
unknown's avatar
SCRUM:  
unknown committed
3909
#endif
3910
  case SQLCOM_HA_OPEN:
unknown's avatar
VIEW  
unknown committed
3911 3912 3913
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables) ||
	check_table_access(thd, SELECT_ACL, all_tables, 0))
3914
      goto error;
unknown's avatar
unknown committed
3915
    res= mysql_ha_open(thd, first_table, 0);
3916 3917
    break;
  case SQLCOM_HA_CLOSE:
unknown's avatar
VIEW  
unknown committed
3918 3919
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_db_used(thd, all_tables))
3920
      goto error;
unknown's avatar
VIEW  
unknown committed
3921
    res= mysql_ha_close(thd, first_table);
3922 3923
    break;
  case SQLCOM_HA_READ:
unknown's avatar
VIEW  
unknown committed
3924
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3925 3926 3927 3928 3929
    /*
      There is no need to check for table permissions here, because
      if a user has no permissions to read a table, he won't be
      able to open it (with SQLCOM_HA_OPEN) in the first place.
    */
unknown's avatar
VIEW  
unknown committed
3930
    if (check_db_used(thd, all_tables))
3931
      goto error;
3932
    unit->set_limit(select_lex);
unknown's avatar
unknown committed
3933
    res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
unknown's avatar
VIEW  
unknown committed
3934
                       lex->insert_list, lex->ha_rkey_mode, select_lex->where,
3935
                       unit->select_limit_cnt, unit->offset_limit_cnt);
3936 3937
    break;

unknown's avatar
unknown committed
3938
  case SQLCOM_BEGIN:
3939 3940 3941 3942 3943 3944
    if (thd->transaction.xid_state.xa_state != XA_NOTR)
    {
      my_error(ER_XAER_RMFAIL, MYF(0),
               xa_state_names[thd->transaction.xid_state.xa_state]);
      break;
    }
unknown's avatar
WL#1967  
unknown committed
3945
    if (begin_trans(thd))
unknown's avatar
unknown committed
3946
      goto error;
unknown's avatar
unknown committed
3947
    send_ok(thd);
unknown's avatar
unknown committed
3948 3949
    break;
  case SQLCOM_COMMIT:
3950
    if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
unknown's avatar
unknown committed
3951
                              lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
unknown's avatar
unknown committed
3952
      goto error;
3953
    send_ok(thd);
unknown's avatar
unknown committed
3954 3955
    break;
  case SQLCOM_ROLLBACK:
3956
    if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
unknown's avatar
unknown committed
3957
                              lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
unknown's avatar
WL#1967  
unknown committed
3958
      goto error;
3959
    send_ok(thd);
unknown's avatar
unknown committed
3960
    break;
unknown's avatar
unknown committed
3961
  case SQLCOM_RELEASE_SAVEPOINT:
unknown's avatar
unknown committed
3962
  {
3963 3964
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
unknown's avatar
unknown committed
3965 3966 3967
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
3968
                       (uchar *)sv->name, sv->length) == 0)
unknown's avatar
unknown committed
3969 3970
        break;
    }
3971
    if (sv)
unknown's avatar
unknown committed
3972
    {
3973
      if (ha_release_savepoint(thd, sv))
unknown's avatar
unknown committed
3974
        res= TRUE; // cannot happen
unknown's avatar
unknown committed
3975 3976
      else
        send_ok(thd);
3977
      thd->transaction.savepoints=sv->prev;
unknown's avatar
unknown committed
3978
    }
unknown's avatar
unknown committed
3979
    else
unknown's avatar
unknown committed
3980
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
3981
    break;
unknown's avatar
unknown committed
3982
  }
unknown's avatar
unknown committed
3983
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
unknown's avatar
unknown committed
3984
  {
3985 3986
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
unknown's avatar
unknown committed
3987 3988 3989
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
3990
                       (uchar *)sv->name, sv->length) == 0)
unknown's avatar
unknown committed
3991 3992
        break;
    }
3993
    if (sv)
unknown's avatar
unknown committed
3994
    {
3995
      if (ha_rollback_to_savepoint(thd, sv))
unknown's avatar
unknown committed
3996 3997
        res= TRUE; // cannot happen
      else
unknown's avatar
unknown committed
3998 3999 4000 4001 4002 4003 4004 4005
      {
        if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
            !thd->slave_thread)
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_WARNING_NOT_COMPLETE_ROLLBACK,
                       ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
        send_ok(thd);
      }
4006
      thd->transaction.savepoints=sv;
unknown's avatar
unknown committed
4007 4008
    }
    else
unknown's avatar
unknown committed
4009
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
4010
    break;
unknown's avatar
unknown committed
4011
  }
4012
  case SQLCOM_SAVEPOINT:
unknown's avatar
unknown committed
4013 4014
    if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) ||
        !opt_using_transactions)
unknown's avatar
unknown committed
4015
      send_ok(thd);
unknown's avatar
unknown committed
4016
    else
unknown's avatar
unknown committed
4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054
    {
      SAVEPOINT **sv, *newsv;
      for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
      {
        if (my_strnncoll(system_charset_info,
                         (uchar *)lex->ident.str, lex->ident.length,
                         (uchar *)(*sv)->name, (*sv)->length) == 0)
          break;
      }
      if (*sv) /* old savepoint of the same name exists */
      {
        newsv=*sv;
        ha_release_savepoint(thd, *sv); // it cannot fail
        *sv=(*sv)->prev;
      }
      else if ((newsv=(SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
                                               savepoint_alloc_size)) == 0)
      {
        my_error(ER_OUT_OF_RESOURCES, MYF(0));
        break;
      }
      newsv->name=strmake_root(&thd->transaction.mem_root,
                               lex->ident.str, lex->ident.length);
      newsv->length=lex->ident.length;
      /*
        if we'll get an error here, don't add new savepoint to the list.
        we'll lose a little bit of memory in transaction mem_root, but it'll
        be free'd when transaction ends anyway
      */
      if (ha_savepoint(thd, newsv))
        res= TRUE;
      else
      {
        newsv->prev=thd->transaction.savepoints;
        thd->transaction.savepoints=newsv;
        send_ok(thd);
      }
    }
unknown's avatar
WL#1967  
unknown committed
4055
    break;
4056 4057
  case SQLCOM_CREATE_PROCEDURE:
  case SQLCOM_CREATE_SPFUNCTION:
unknown's avatar
unknown committed
4058
  {
4059
    uint namelen;
4060
    char *name, *db;
unknown's avatar
unknown committed
4061
    int result;
4062

4063
    DBUG_ASSERT(lex->sphead != 0);
4064

4065 4066
    if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
                     is_schema_db(lex->sphead->m_db.str)))
4067 4068 4069 4070 4071 4072
    {
      delete lex->sphead;
      lex->sphead= 0;
      goto error;
    }

4073 4074 4075
    if (end_active_trans(thd)) 
      goto error;

4076 4077 4078
    if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0])
    {
      lex->sphead->m_db.length= strlen(thd->db);
unknown's avatar
unknown committed
4079 4080
      lex->sphead->m_db.str= strmake_root(thd->mem_root, thd->db,
                                           lex->sphead->m_db.length);
4081
    }
4082 4083

    name= lex->sphead->name(&namelen);
4084
#ifdef HAVE_DLOPEN
unknown's avatar
unknown committed
4085 4086 4087
    if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
    {
      udf_func *udf = find_udf(name, namelen);
4088

unknown's avatar
unknown committed
4089
      if (udf)
4090
      {
4091
	my_error(ER_UDF_EXISTS, MYF(0), name);
unknown's avatar
unknown committed
4092
	delete lex->sphead;
4093
	lex->sphead= 0;
4094
	goto error;
4095
      }
unknown's avatar
unknown committed
4096 4097 4098
    }
#endif
    if (lex->sphead->m_type == TYPE_ENUM_FUNCTION &&
4099
	!(lex->sphead->m_flags & sp_head::HAS_RETURN))
unknown's avatar
unknown committed
4100
    {
4101
      my_error(ER_SP_NORETURN, MYF(0), name);
unknown's avatar
unknown committed
4102
      delete lex->sphead;
4103
      lex->sphead= 0;
unknown's avatar
unknown committed
4104 4105 4106
      goto error;
    }

4107 4108
    name= thd->strdup(name); 
    db= thd->strmake(lex->sphead->m_db.str, lex->sphead->m_db.length);
unknown's avatar
unknown committed
4109
    res= (result= lex->sphead->create(thd));
unknown's avatar
unknown committed
4110 4111
    if (result == SP_OK)
    {
4112
      lex->unit.cleanup();
unknown's avatar
unknown committed
4113 4114
      delete lex->sphead;
      lex->sphead= 0;
unknown's avatar
unknown committed
4115
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4116
      /* only add privileges if really neccessary */
4117
      if (sp_automatic_privileges && !opt_noacl &&
4118 4119 4120
          check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
      			       db, name,
                               lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
4121 4122
      {
        close_thread_tables(thd);
4123 4124
        if (sp_grant_privileges(thd, db, name, 
                                lex->sql_command == SQLCOM_CREATE_PROCEDURE))
4125 4126 4127 4128
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
	  	       ER_PROC_AUTO_GRANT_FAIL,
		       ER(ER_PROC_AUTO_GRANT_FAIL));
      }
unknown's avatar
unknown committed
4129
#endif
4130
      send_ok(thd);
unknown's avatar
unknown committed
4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150
    }
    else
    {
      switch (result) {
      case SP_WRITE_ROW_FAILED:
	my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name);
	break;
      case SP_NO_DB_ERROR:
	my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
	break;
      case SP_BAD_IDENTIFIER:
	my_error(ER_TOO_LONG_IDENT, MYF(0), name);
	break;
      case SP_BODY_TOO_LONG:
	my_error(ER_TOO_LONG_BODY, MYF(0), name);
	break;
      default:
	my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name);
	break;
      }
4151
      lex->unit.cleanup();
unknown's avatar
unknown committed
4152 4153 4154
      delete lex->sphead;
      lex->sphead= 0;
      goto error;
4155
    }
unknown's avatar
unknown committed
4156 4157
    break;
  }
4158 4159 4160 4161
  case SQLCOM_CALL:
    {
      sp_head *sp;

4162 4163 4164 4165 4166 4167 4168 4169 4170
      /*
        This will cache all SP and SF and open and lock all tables
        required for execution.
      */
      if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
	  open_and_lock_tables(thd, all_tables))
       goto error;

      /*
4171 4172
        By this moment all needed SPs should be in cache so no need to look 
        into DB. 
4173 4174
      */
      if (!(sp= sp_find_procedure(thd, lex->spname, TRUE)))
4175
      {
4176
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
unknown's avatar
unknown committed
4177
                 lex->spname->m_qname.str);
4178
	goto error;
4179 4180 4181
      }
      else
      {
4182
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4183
	Security_context *save_ctx;
4184
#endif
unknown's avatar
unknown committed
4185
	ha_rows select_limit;
unknown's avatar
unknown committed
4186 4187
        /* bits that should be cleared in thd->server_status */
	uint bits_to_be_cleared= 0;
4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199
        /*
          Check that the stored procedure doesn't contain Dynamic SQL
          and doesn't return result sets: such stored procedures can't
          be called from a function or trigger.
        */
        if (thd->in_sub_stmt)
        {
          const char *where= (thd->in_sub_stmt & SUB_STMT_TRIGGER ?
                              "trigger" : "function");
          if (sp->is_not_allowed_in_function(where))
            goto error;
        }
4200

4201
#ifndef EMBEDDED_LIBRARY
4202 4203
	my_bool nsok= thd->net.no_send_ok;
	thd->net.no_send_ok= TRUE;
4204
#endif
4205
	if (sp->m_flags & sp_head::MULTI_RESULTS)
4206
	{
4207
	  if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
4208
	  {
4209 4210 4211 4212
            /*
              The client does not support multiple result sets being sent
              back
            */
4213
	    my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
4214 4215 4216 4217 4218
#ifndef EMBEDDED_LIBRARY
	    thd->net.no_send_ok= nsok;
#endif
	    goto error;
	  }
unknown's avatar
unknown committed
4219 4220 4221 4222 4223 4224 4225
          /*
            If SERVER_MORE_RESULTS_EXISTS is not set,
            then remember that it should be cleared
          */
	  bits_to_be_cleared= (~thd->server_status &
                               SERVER_MORE_RESULTS_EXISTS);
	  thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
4226 4227
	}

4228
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4229 4230 4231
	if (check_routine_access(thd, EXECUTE_ACL,
				 sp->m_db.str, sp->m_name.str, TRUE, 0) ||
          sp_change_security_context(thd, sp, &save_ctx))
4232 4233 4234 4235 4236 4237
	{
#ifndef EMBEDDED_LIBRARY
	  thd->net.no_send_ok= nsok;
#endif
	  goto error;
	}
4238 4239 4240
	if (save_ctx &&
            check_routine_access(thd, EXECUTE_ACL,
                                 sp->m_db.str, sp->m_name.str, TRUE, 0))
4241 4242 4243 4244
	{
#ifndef EMBEDDED_LIBRARY
	  thd->net.no_send_ok= nsok;
#endif
4245
	  sp_restore_security_context(thd, save_ctx);
4246 4247 4248
	  goto error;
	}

4249
#endif
unknown's avatar
unknown committed
4250 4251
	select_limit= thd->variables.select_limit;
	thd->variables.select_limit= HA_POS_ERROR;
4252

4253
        thd->row_count_func= 0;
4254 4255
        
        /* 
4256
          We never write CALL statements into binlog:
4257 4258 4259 4260 4261
           - If the mode is non-prelocked, each statement will be logged
             separately.
           - If the mode is prelocked, the invoking statement will care
             about writing into binlog.
          So just execute the statement.
4262
        */
4263
	res= sp->execute_procedure(thd, &lex->value_list);
4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274
        if (mysql_bin_log.is_open() &&
            (sp->m_chistics->daccess == SP_CONTAINS_SQL ||
             sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA))
        {
          if (res)
            push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                         ER_FAILED_ROUTINE_BREAK_BINLOG,
			 ER(ER_FAILED_ROUTINE_BREAK_BINLOG));
          else
            thd->clear_error();
        }
4275

4276 4277 4278
	/*
          If warnings have been cleared, we have to clear total_warn_count
          too, otherwise the clients get confused.
4279 4280 4281 4282
	 */
	if (thd->warn_list.is_empty())
	  thd->total_warn_count= 0;

unknown's avatar
unknown committed
4283
	thd->variables.select_limit= select_limit;
4284
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4285
	sp_restore_security_context(thd, save_ctx);
4286
#endif
4287

4288
#ifndef EMBEDDED_LIBRARY
4289
	thd->net.no_send_ok= nsok;
4290
#endif
unknown's avatar
unknown committed
4291
        thd->server_status&= ~bits_to_be_cleared;
4292

unknown's avatar
unknown committed
4293
	if (!res)
unknown's avatar
unknown committed
4294 4295
	  send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
                                thd->row_count_func));
4296 4297
	else
	  goto error;		// Substatement should already have sent error
4298
      }
4299
      break;
4300 4301
    }
  case SQLCOM_ALTER_PROCEDURE:
4302
  case SQLCOM_ALTER_FUNCTION:
4303
    {
unknown's avatar
unknown committed
4304
      int result;
4305 4306 4307 4308
      sp_head *sp;
      st_sp_chistics chistics;

      memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
unknown's avatar
unknown committed
4309
      if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
4310
	sp= sp_find_procedure(thd, lex->spname);
4311
      else
4312
	sp= sp_find_function(thd, lex->spname);
unknown's avatar
unknown committed
4313
      mysql_reset_errors(thd, 0);
4314
      if (! sp)
4315 4316 4317 4318 4319 4320 4321 4322 4323
      {
	if (lex->spname->m_db.str)
	  result= SP_KEY_NOT_FOUND;
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
      }
4324 4325
      else
      {
4326 4327 4328
        if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str, 
				 sp->m_name.str,
                                 lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
4329
	  goto error;
4330 4331 4332

        if (end_active_trans(thd)) 
          goto error;
4333
	memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349
        if (!trust_routine_creators &&  mysql_bin_log.is_open() &&
            !sp->m_chistics->detistic &&
            (chistics.daccess == SP_CONTAINS_SQL ||
             chistics.daccess == SP_MODIFIES_SQL_DATA))
        {
          my_message(ER_BINLOG_UNSAFE_ROUTINE,
		     ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0));
          result= SP_INTERNAL_ERROR;
        }
        else
        {
          if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
            result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
          else
            result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
        }
4350
      }
unknown's avatar
unknown committed
4351
      switch (result)
4352
      {
unknown's avatar
unknown committed
4353
      case SP_OK:
4354 4355 4356 4357 4358 4359
        if (mysql_bin_log.is_open())
        {
          thd->clear_error();
          Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
          mysql_bin_log.write(&qinfo);
        }
4360
	send_ok(thd);
unknown's avatar
unknown committed
4361 4362
	break;
      case SP_KEY_NOT_FOUND:
4363 4364
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
4365 4366
	goto error;
      default:
4367 4368
	my_error(ER_SP_CANT_ALTER, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
4369
	goto error;
4370
      }
4371
      break;
4372 4373
    }
  case SQLCOM_DROP_PROCEDURE:
4374
  case SQLCOM_DROP_FUNCTION:
4375
    {
4376
      sp_head *sp;
unknown's avatar
unknown committed
4377
      int result;
4378
      char *db, *name;
4379

4380
      if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
4381 4382 4383
	sp= sp_find_procedure(thd, lex->spname);
      else
	sp= sp_find_function(thd, lex->spname);
unknown's avatar
unknown committed
4384
      mysql_reset_errors(thd, 0);
4385
      if (sp)
4386
      {
4387 4388
        db= thd->strdup(sp->m_db.str);
	name= thd->strdup(sp->m_name.str);
4389 4390
	if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
unknown's avatar
merge  
unknown committed
4391
          goto error;
4392 4393 4394

        if (end_active_trans(thd)) 
          goto error;
unknown's avatar
unknown committed
4395
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4396
	if (sp_automatic_privileges && !opt_noacl &&
4397 4398
	    sp_revoke_privileges(thd, db, name, 
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE))
4399 4400 4401 4402 4403
	{
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
		       ER_PROC_AUTO_REVOKE_FAIL,
		       ER(ER_PROC_AUTO_REVOKE_FAIL));
	}
unknown's avatar
unknown committed
4404
#endif
4405
	if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
unknown's avatar
merge  
unknown committed
4406
	  result= sp_drop_procedure(thd, lex->spname);
4407
	else
unknown's avatar
merge  
unknown committed
4408
	  result= sp_drop_function(thd, lex->spname);
4409 4410 4411
      }
      else
      {
4412
#ifdef HAVE_DLOPEN
4413 4414 4415 4416 4417 4418
	if (lex->sql_command == SQLCOM_DROP_FUNCTION)
	{
          udf_func *udf = find_udf(lex->spname->m_name.str,
                                   lex->spname->m_name.length);
          if (udf)
          {
4419
	    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
4420 4421
	      goto error;
	    if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
4422
	    {
4423 4424
	      send_ok(thd);
	      break;
4425 4426
	    }
	  }
4427
	}
4428
#endif
4429 4430 4431 4432 4433 4434 4435
	if (lex->spname->m_db.str)
	  result= SP_KEY_NOT_FOUND;
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
4436
      }
unknown's avatar
unknown committed
4437 4438
      res= result;
      switch (result)
4439 4440
      {
      case SP_OK:
4441 4442 4443 4444 4445 4446
        if (mysql_bin_log.is_open())
        {
          thd->clear_error();
          Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
          mysql_bin_log.write(&qinfo);
        }
4447
	send_ok(thd);
4448 4449
	break;
      case SP_KEY_NOT_FOUND:
4450 4451
	if (lex->drop_if_exists)
	{
4452
	  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
4453
			      ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
4454
			      SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4455
	  res= FALSE;
4456 4457 4458
	  send_ok(thd);
	  break;
	}
4459 4460
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4461 4462
	goto error;
      default:
4463 4464
	my_error(ER_SP_DROP_FAILED, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4465
	goto error;
4466
      }
4467
      break;
4468
    }
unknown's avatar
unknown committed
4469 4470
  case SQLCOM_SHOW_CREATE_PROC:
    {
4471
      if (lex->spname->m_name.length > NAME_LEN)
unknown's avatar
unknown committed
4472
      {
4473
	my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
unknown's avatar
unknown committed
4474 4475
	goto error;
      }
unknown's avatar
unknown committed
4476
      if (sp_show_create_procedure(thd, lex->spname) != SP_OK)
4477
      {			/* We don't distinguish between errors for now */
4478 4479
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4480 4481 4482 4483 4484 4485
	goto error;
      }
      break;
    }
  case SQLCOM_SHOW_CREATE_FUNC:
    {
4486
      if (lex->spname->m_name.length > NAME_LEN)
unknown's avatar
unknown committed
4487
      {
4488
	my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
unknown's avatar
unknown committed
4489 4490
	goto error;
      }
unknown's avatar
unknown committed
4491
      if (sp_show_create_function(thd, lex->spname) != SP_OK)
4492
      {			/* We don't distinguish between errors for now */
4493 4494
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4495 4496 4497 4498 4499 4500
	goto error;
      }
      break;
    }
  case SQLCOM_SHOW_STATUS_PROC:
    {
4501
      res= sp_show_status_procedure(thd, (lex->wild ?
unknown's avatar
unknown committed
4502 4503 4504 4505 4506
					  lex->wild->ptr() : NullS));
      break;
    }
  case SQLCOM_SHOW_STATUS_FUNC:
    {
4507
      res= sp_show_status_function(thd, (lex->wild ? 
unknown's avatar
unknown committed
4508 4509 4510
					 lex->wild->ptr() : NullS));
      break;
    }
unknown's avatar
VIEW  
unknown committed
4511 4512
  case SQLCOM_CREATE_VIEW:
    {
4513 4514 4515
      if (!(res= mysql_create_view(thd, thd->lex->create_view_mode)) &&
          mysql_bin_log.is_open())
      {
4516
        String buff;
unknown's avatar
unknown committed
4517 4518 4519 4520
        const LEX_STRING command[3]=
          {{(char *)STRING_WITH_LEN("CREATE ")},
           {(char *)STRING_WITH_LEN("ALTER ")},
           {(char *)STRING_WITH_LEN("CREATE OR REPLACE ")}};
unknown's avatar
unknown committed
4521
        thd->clear_error();
4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538

        buff.append(command[thd->lex->create_view_mode].str,
                    command[thd->lex->create_view_mode].length);
        view_store_options(thd, first_table, &buff);
        buff.append("VIEW ", 5);
        if (!first_table->current_db_used)
        {
          append_identifier(thd, &buff, first_table->db,
                            first_table->db_length);
          buff.append('.');
        }
        append_identifier(thd, &buff, first_table->table_name,
                          first_table->table_name_length);
        buff.append(" AS ", 4);
        buff.append(first_table->source.str, first_table->source.length);

        Query_log_event qinfo(thd, buff.ptr(), buff.length(), 0, FALSE);
4539 4540
        mysql_bin_log.write(&qinfo);
      }
unknown's avatar
VIEW  
unknown committed
4541 4542 4543 4544
      break;
    }
  case SQLCOM_DROP_VIEW:
    {
unknown's avatar
unknown committed
4545 4546 4547
      if (check_table_access(thd, DROP_ACL, all_tables, 0) ||
          end_active_trans(thd))
        goto error;
4548 4549 4550
      if (!(res= mysql_drop_view(thd, first_table, thd->lex->drop_mode)) &&
          mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
4551
        thd->clear_error();
4552 4553 4554
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
        mysql_bin_log.write(&qinfo);
      }
unknown's avatar
VIEW  
unknown committed
4555 4556
      break;
    }
4557 4558
  case SQLCOM_CREATE_TRIGGER:
  {
4559 4560 4561
    res= mysql_create_or_drop_trigger(thd, all_tables, 1);

    /* We don't care about trigger body after this point */
4562 4563 4564 4565 4566 4567 4568 4569 4570
    delete lex->sphead;
    lex->sphead= 0;
    break;
  }
  case SQLCOM_DROP_TRIGGER:
  {
    res= mysql_create_or_drop_trigger(thd, all_tables, 0);
    break;
  }
unknown's avatar
unknown committed
4571
  case SQLCOM_XA_START:
4572 4573
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
        thd->lex->xa_opt == XA_RESUME)
unknown's avatar
unknown committed
4574
    {
4575
      if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
unknown's avatar
unknown committed
4576 4577 4578 4579
      {
        my_error(ER_XAER_NOTA, MYF(0));
        break;
      }
4580
      thd->transaction.xid_state.xa_state=XA_ACTIVE;
unknown's avatar
unknown committed
4581 4582 4583
      send_ok(thd);
      break;
    }
unknown's avatar
unknown committed
4584
    if (thd->lex->xa_opt != XA_NONE)
unknown's avatar
unknown committed
4585 4586 4587 4588
    { // JOIN is not supported yet. TODO
      my_error(ER_XAER_INVAL, MYF(0));
      break;
    }
4589
    if (thd->transaction.xid_state.xa_state != XA_NOTR)
unknown's avatar
unknown committed
4590
    {
unknown's avatar
unknown committed
4591
      my_error(ER_XAER_RMFAIL, MYF(0),
4592
               xa_state_names[thd->transaction.xid_state.xa_state]);
unknown's avatar
unknown committed
4593 4594 4595 4596 4597 4598 4599
      break;
    }
    if (thd->active_transaction() || thd->locked_tables)
    {
      my_error(ER_XAER_OUTSIDE, MYF(0));
      break;
    }
4600 4601 4602 4603 4604 4605 4606 4607 4608
    if (xid_cache_search(thd->lex->xid))
    {
      my_error(ER_XAER_DUPID, MYF(0));
      break;
    }
    DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
    thd->transaction.xid_state.xa_state=XA_ACTIVE;
    thd->transaction.xid_state.xid.set(thd->lex->xid);
    xid_cache_insert(&thd->transaction.xid_state);
unknown's avatar
unknown committed
4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620
    thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
                   OPTION_BEGIN);
    thd->server_status|= SERVER_STATUS_IN_TRANS;
    send_ok(thd);
    break;
  case SQLCOM_XA_END:
    /* fake it */
    if (thd->lex->xa_opt != XA_NONE)
    { // SUSPEND and FOR MIGRATE are not supported yet. TODO
      my_error(ER_XAER_INVAL, MYF(0));
      break;
    }
4621
    if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
unknown's avatar
unknown committed
4622
    {
unknown's avatar
unknown committed
4623
      my_error(ER_XAER_RMFAIL, MYF(0),
4624
               xa_state_names[thd->transaction.xid_state.xa_state]);
unknown's avatar
unknown committed
4625 4626
      break;
    }
4627
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
unknown's avatar
unknown committed
4628 4629 4630 4631
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
4632
    thd->transaction.xid_state.xa_state=XA_IDLE;
unknown's avatar
unknown committed
4633 4634 4635
    send_ok(thd);
    break;
  case SQLCOM_XA_PREPARE:
4636
    if (thd->transaction.xid_state.xa_state != XA_IDLE)
unknown's avatar
unknown committed
4637
    {
unknown's avatar
unknown committed
4638
      my_error(ER_XAER_RMFAIL, MYF(0),
4639
               xa_state_names[thd->transaction.xid_state.xa_state]);
unknown's avatar
unknown committed
4640 4641
      break;
    }
4642
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
unknown's avatar
unknown committed
4643 4644 4645 4646 4647 4648 4649
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
    if (ha_prepare(thd))
    {
      my_error(ER_XA_RBROLLBACK, MYF(0));
4650 4651
      xid_cache_delete(&thd->transaction.xid_state);
      thd->transaction.xid_state.xa_state=XA_NOTR;
unknown's avatar
unknown committed
4652 4653
      break;
    }
4654
    thd->transaction.xid_state.xa_state=XA_PREPARED;
unknown's avatar
unknown committed
4655 4656 4657
    send_ok(thd);
    break;
  case SQLCOM_XA_COMMIT:
4658
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
unknown's avatar
unknown committed
4659
    {
4660 4661
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
unknown's avatar
unknown committed
4662
        my_error(ER_XAER_NOTA, MYF(0));
unknown's avatar
unknown committed
4663
      else
4664 4665 4666
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
        xid_cache_delete(xs);
unknown's avatar
unknown committed
4667
        send_ok(thd);
4668
      }
unknown's avatar
unknown committed
4669 4670
      break;
    }
4671
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
unknown's avatar
unknown committed
4672
        thd->lex->xa_opt == XA_ONE_PHASE)
unknown's avatar
unknown committed
4673
    {
unknown's avatar
unknown committed
4674 4675 4676
      int r;
      if ((r= ha_commit(thd)))
        my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
unknown's avatar
unknown committed
4677 4678 4679
      else
        send_ok(thd);
    }
4680
    else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
unknown's avatar
unknown committed
4681
             thd->lex->xa_opt == XA_NONE)
unknown's avatar
unknown committed
4682
    {
4683 4684 4685
      if (wait_if_global_read_lock(thd, 0, 0))
      {
        ha_rollback(thd);
unknown's avatar
unknown committed
4686
        my_error(ER_XAER_RMERR, MYF(0));
4687
      }
unknown's avatar
unknown committed
4688
      else
4689 4690 4691 4692 4693 4694 4695
      {
        if (ha_commit_one_phase(thd, 1))
          my_error(ER_XAER_RMERR, MYF(0));
        else
          send_ok(thd);
        start_waiting_global_read_lock(thd);
      }
unknown's avatar
unknown committed
4696 4697 4698
    }
    else
    {
unknown's avatar
unknown committed
4699
      my_error(ER_XAER_RMFAIL, MYF(0),
4700
               xa_state_names[thd->transaction.xid_state.xa_state]);
unknown's avatar
unknown committed
4701 4702 4703 4704
      break;
    }
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
4705 4706
    xid_cache_delete(&thd->transaction.xid_state);
    thd->transaction.xid_state.xa_state=XA_NOTR;
unknown's avatar
unknown committed
4707 4708
    break;
  case SQLCOM_XA_ROLLBACK:
4709
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
unknown's avatar
unknown committed
4710
    {
4711 4712
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
unknown's avatar
unknown committed
4713
        my_error(ER_XAER_NOTA, MYF(0));
unknown's avatar
unknown committed
4714
      else
4715 4716 4717
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
        xid_cache_delete(xs);
unknown's avatar
unknown committed
4718
        send_ok(thd);
4719
      }
unknown's avatar
unknown committed
4720 4721
      break;
    }
4722 4723
    if (thd->transaction.xid_state.xa_state != XA_IDLE &&
        thd->transaction.xid_state.xa_state != XA_PREPARED)
unknown's avatar
unknown committed
4724
    {
unknown's avatar
unknown committed
4725
      my_error(ER_XAER_RMFAIL, MYF(0),
4726
               xa_state_names[thd->transaction.xid_state.xa_state]);
unknown's avatar
unknown committed
4727 4728 4729 4730 4731 4732 4733 4734
      break;
    }
    if (ha_rollback(thd))
      my_error(ER_XAER_RMERR, MYF(0));
    else
      send_ok(thd);
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
4735 4736
    xid_cache_delete(&thd->transaction.xid_state);
    thd->transaction.xid_state.xa_state=XA_NOTR;
unknown's avatar
unknown committed
4737 4738
    break;
  case SQLCOM_XA_RECOVER:
4739
    res= mysql_xa_recover(thd);
unknown's avatar
unknown committed
4740 4741 4742
    break;
  default:
    DBUG_ASSERT(0);                             /* Impossible */
4743
    send_ok(thd);
unknown's avatar
unknown committed
4744 4745
    break;
  }
unknown's avatar
unknown committed
4746
  thd->proc_info="query end";
4747
  /* Two binlog-related cleanups: */
4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760

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

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

4761

4762 4763 4764 4765 4766
  /*
    The return value for ROW_COUNT() is "implementation dependent" if
    the statement is not DELETE, INSERT or UPDATE (or a CALL executing
    such a statement), but -1 is what JDBC and ODBC wants.
   */
unknown's avatar
unknown committed
4767
  if (lex->sql_command != SQLCOM_CALL && uc_update_queries[lex->sql_command]<2)
4768
    thd->row_count_func= -1;
unknown's avatar
unknown committed
4769
  goto cleanup;
unknown's avatar
unknown committed
4770 4771

error:
unknown's avatar
unknown committed
4772
  res= 1;
4773

unknown's avatar
unknown committed
4774 4775
cleanup:
  DBUG_RETURN(res || thd->net.report_error);
unknown's avatar
unknown committed
4776 4777 4778
}


unknown's avatar
unknown committed
4779 4780
/*
  Check grants for commands which work only with one table and all other
4781
  tables belonging to subselects or implicitly opened tables.
unknown's avatar
unknown committed
4782

4783
  SYNOPSIS
unknown's avatar
unknown committed
4784 4785
    check_one_table_access()
    thd			Thread handler
4786
    privilege		requested privilege
unknown's avatar
VIEW  
unknown committed
4787
    all_tables		global table list of query
unknown's avatar
unknown committed
4788 4789 4790

  RETURN
    0 - OK
unknown's avatar
unknown committed
4791
    1 - access denied, error is sent to client
unknown's avatar
unknown committed
4792 4793
*/

4794
bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
unknown's avatar
unknown committed
4795
{
unknown's avatar
VIEW  
unknown committed
4796
  if (check_access(thd, privilege, all_tables->db,
4797 4798
		   &all_tables->grant.privilege, 0, 0,
                   test(all_tables->schema_table)))
unknown's avatar
unknown committed
4799
    return 1;
unknown's avatar
unknown committed
4800

unknown's avatar
unknown committed
4801
  /* Show only 1 table for check_grant */
unknown's avatar
VIEW  
unknown committed
4802
  if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0))
unknown's avatar
unknown committed
4803
    return 1;
unknown's avatar
unknown committed
4804

4805
  /* Check rights on tables of subselects and implictly opened tables */
unknown's avatar
unknown committed
4806
  TABLE_LIST *subselects_tables;
unknown's avatar
VIEW  
unknown committed
4807
  if ((subselects_tables= all_tables->next_global))
unknown's avatar
unknown committed
4808
  {
unknown's avatar
VIEW  
unknown committed
4809
    if ((check_table_access(thd, SELECT_ACL, subselects_tables, 0)))
unknown's avatar
unknown committed
4810 4811 4812
      return 1;
  }
  return 0;
unknown's avatar
unknown committed
4813 4814 4815
}


unknown's avatar
unknown committed
4816
/****************************************************************************
unknown's avatar
unknown committed
4817
  Get the user (global) and database privileges for all used tables
unknown's avatar
unknown committed
4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830

  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
4831 4832
                is enough to satisfy the request and the global grants contains
                a SELECT grant.
unknown's avatar
unknown committed
4833 4834 4835
****************************************************************************/

bool
unknown's avatar
unknown committed
4836
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
4837
	     bool dont_check_global_grants, bool no_errors, bool schema_db)
unknown's avatar
unknown committed
4838
{
4839
  Security_context *sctx= thd->security_ctx;
unknown's avatar
unknown committed
4840 4841
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  ulong db_access;
unknown's avatar
unknown committed
4842
  bool  db_is_pattern= test(want_access & GRANT_ACL);
unknown's avatar
unknown committed
4843 4844
#endif
  ulong dummy;
4845
  const char *db_name;
4846 4847
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("db: %s  want_access: %lu  master_access: %lu",
4848
                      db ? db : "", want_access, sctx->master_access));
unknown's avatar
unknown committed
4849 4850 4851 4852 4853
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

4854
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
4855
  {
4856
    DBUG_PRINT("error",("No database"));
4857
    if (!no_errors)
unknown's avatar
unknown committed
4858 4859
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
                 MYF(0));                       /* purecov: tested */
unknown's avatar
unknown committed
4860
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4861 4862
  }

4863 4864 4865 4866 4867 4868 4869
  db_name= db ? db : thd->db;
  if (schema_db)
  {
    if (want_access & ~(SELECT_ACL | EXTRA_ACL))
    {
      if (!no_errors)
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
4870 4871
                 sctx->priv_user,
                 sctx->priv_host, db_name);
4872 4873 4874 4875 4876 4877 4878 4879 4880
      DBUG_RETURN(TRUE);
    }
    else
    {
      *save_priv= SELECT_ACL;
      DBUG_RETURN(FALSE);
    }
  }

unknown's avatar
unknown committed
4881 4882 4883
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  DBUG_RETURN(0);
#else
4884
  if ((sctx->master_access & want_access) == want_access)
unknown's avatar
unknown committed
4885
  {
4886 4887 4888 4889 4890
    /*
      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
    */
4891 4892
    db_access= sctx->db_access;
    if (!(sctx->master_access & SELECT_ACL) &&
unknown's avatar
unknown committed
4893
	(db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
4894 4895 4896
      db_access=acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
                        db_is_pattern);
    *save_priv=sctx->master_access | db_access;
unknown's avatar
unknown committed
4897
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
4898
  }
4899
  if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
4900
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
4901
  {						// We can never grant this
4902
    DBUG_PRINT("error",("No possible access"));
4903
    if (!no_errors)
4904
      my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
4905 4906
               sctx->priv_user,
               sctx->priv_host,
4907 4908 4909
               (thd->password ?
                ER(ER_YES) :
                ER(ER_NO)));                    /* purecov: tested */
unknown's avatar
unknown committed
4910
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4911 4912 4913
  }

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

unknown's avatar
unknown committed
4916
  if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
4917 4918
    db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
                       db_is_pattern);
unknown's avatar
unknown committed
4919
  else
4920
    db_access= sctx->db_access;
4921
  DBUG_PRINT("info",("db_access: %lu", db_access));
unknown's avatar
unknown committed
4922
  /* Remove SHOW attribute and access rights we already have */
4923
  want_access &= ~(sctx->master_access | EXTRA_ACL);
4924 4925
  DBUG_PRINT("info",("db_access: %lu  want_access: %lu",
                     db_access, want_access));
4926
  db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
4927 4928

  /* grant_option is set if there exists a single table or column grant */
unknown's avatar
unknown committed
4929
  if (db_access == want_access ||
4930
      (grant_option && !dont_check_global_grants &&
4931
       !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
unknown's avatar
unknown committed
4932
    DBUG_RETURN(FALSE);				/* Ok */
4933 4934

  DBUG_PRINT("error",("Access denied"));
4935
  if (!no_errors)
4936
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
4937
             sctx->priv_user, sctx->priv_host,
4938 4939 4940
             (db ? db : (thd->db ?
                         thd->db :
                         "unknown")));          /* purecov: tested */
unknown's avatar
unknown committed
4941
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4942
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
4943 4944 4945
}


4946 4947 4948 4949 4950 4951 4952 4953 4954
/*
  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
4955
    One gets access right if one has ANY of the rights in want_access
4956 4957 4958 4959 4960 4961 4962 4963
    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
4964 4965

bool check_global_access(THD *thd, ulong want_access)
unknown's avatar
unknown committed
4966
{
unknown's avatar
unknown committed
4967 4968 4969
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  return 0;
#else
unknown's avatar
unknown committed
4970
  char command[128];
4971
  if ((thd->security_ctx->master_access & want_access))
unknown's avatar
unknown committed
4972 4973
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
4974
  my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
unknown's avatar
unknown committed
4975
  return 1;
unknown's avatar
unknown committed
4976
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
4977 4978 4979
}


unknown's avatar
unknown committed
4980
/*
unknown's avatar
unknown committed
4981 4982
  Check the privilege for all used tables.  Table privileges are cached
  in the table list for GRANT checking
unknown's avatar
unknown committed
4983 4984
*/

4985
bool
unknown's avatar
unknown committed
4986
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
4987
		   bool no_errors)
unknown's avatar
unknown committed
4988
{
unknown's avatar
unknown committed
4989 4990
  uint found=0;
  ulong found_access=0;
unknown's avatar
unknown committed
4991
  TABLE_LIST *org_tables=tables;
unknown's avatar
VIEW  
unknown committed
4992
  for (; tables; tables= tables->next_global)
unknown's avatar
unknown committed
4993
  {
4994
    if (tables->schema_table && 
4995
        (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
4996 4997 4998
    {
      if (!no_errors)
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
4999
                 thd->security_ctx->priv_user, thd->security_ctx->priv_host,
5000 5001 5002
                 information_schema_name.str);
      return TRUE;
    }
5003
    if (tables->derived || tables->schema_table || tables->belong_to_view ||
5004
        (tables->table && (int)tables->table->s->tmp_table) ||
5005 5006
        my_tz_check_n_skip_implicit_tables(&tables,
                                           thd->lex->time_zone_tables_used))
unknown's avatar
unknown committed
5007
      continue;
5008 5009
    if ((thd->security_ctx->master_access & want_access) ==
        (want_access & ~EXTRA_ACL) &&
unknown's avatar
unknown committed
5010
	thd->db)
unknown's avatar
unknown committed
5011
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
5012
    else if (tables->db && tables->db == thd->db)
unknown's avatar
unknown committed
5013 5014 5015 5016 5017
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
5018
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
5019
			 0, no_errors, test(tables->schema_table)))
unknown's avatar
unknown committed
5020 5021
	  return TRUE;				// Access denied
	found_access=tables->grant.privilege;
unknown's avatar
unknown committed
5022
	found=1;
unknown's avatar
unknown committed
5023 5024
      }
    }
5025
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
5026
			  0, no_errors, test(tables->schema_table)))
5027
      return TRUE;
unknown's avatar
unknown committed
5028 5029
  }
  if (grant_option)
5030
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
unknown's avatar
unknown committed
5031
		       test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
unknown's avatar
unknown committed
5032 5033 5034
  return FALSE;
}

5035

5036
bool
5037 5038
check_routine_access(THD *thd, ulong want_access,char *db, char *name,
		     bool is_proc, bool no_errors)
5039 5040 5041 5042 5043
{
  TABLE_LIST tables[1];
  
  bzero((char *)tables, sizeof(TABLE_LIST));
  tables->db= db;
5044
  tables->table_name= tables->alias= name;
5045
  
5046 5047
  if ((thd->security_ctx->master_access & want_access) == want_access &&
      !thd->db)
5048 5049
    tables->grant.privilege= want_access;
  else if (check_access(thd,want_access,db,&tables->grant.privilege,
5050
			0, no_errors, test(tables->schema_table)))
5051 5052
    return TRUE;
  
unknown's avatar
unknown committed
5053
#ifndef NO_EMBEDDED_ACCESS_CHECKS
5054
  if (grant_option)
5055
    return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
unknown's avatar
unknown committed
5056
#endif
5057 5058 5059 5060

  return FALSE;
}

5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075

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

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

  RETURN
    0            ok
    1            error
*/

5076 5077
bool check_some_routine_access(THD *thd, const char *db, const char *name,
                               bool is_proc)
5078 5079
{
  ulong save_priv;
5080
  if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
5081
    return FALSE;
5082 5083 5084 5085 5086
  /*
    There are no routines in information_schema db. So we can safely
    pass zero to last paramter of check_access function
  */
  if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1, 0) ||
5087 5088
      (save_priv & SHOW_PROC_ACLS))
    return FALSE;
5089
  return check_routine_level_acl(thd, db, name, is_proc);
5090 5091 5092
}


5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117
/*
  Check if the given table has any of the asked privileges

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

  RETURN
    0  ok
    1  error
*/


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

  /* This loop will work as long as we have less than 32 privileges */
  for (access= 1; access < want_access ; access<<= 1)
  {
    if (access & want_access)
    {
      if (!check_access(thd, access, table->db,
5118 5119
                        &table->grant.privilege, 0, 1,
                        test(table->schema_table)) &&
5120 5121 5122 5123 5124 5125 5126 5127 5128
          !grant_option || !check_grant(thd, access, table, 0, 1, 1))
        DBUG_RETURN(0);
    }
  }
  DBUG_PRINT("exit",("no matching access rights"));
  DBUG_RETURN(1);
}


5129 5130
bool check_merge_table_access(THD *thd, char *db,
			      TABLE_LIST *table_list)
5131 5132 5133 5134
{
  int error=0;
  if (table_list)
  {
5135
    /* Check that all tables use the current database */
5136
    TABLE_LIST *tmp;
unknown's avatar
VIEW  
unknown committed
5137
    for (tmp= table_list; tmp; tmp= tmp->next_local)
5138 5139 5140 5141
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
    }
5142
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
unknown's avatar
SCRUM:  
unknown committed
5143
			     table_list,0);
5144 5145 5146 5147
  }
  return error;
}

unknown's avatar
SCRUM:  
unknown committed
5148 5149 5150

static bool check_db_used(THD *thd,TABLE_LIST *tables)
{
unknown's avatar
VIEW  
unknown committed
5151
  for (; tables; tables= tables->next_global)
unknown's avatar
SCRUM:  
unknown committed
5152 5153 5154 5155 5156
  {
    if (!tables->db)
    {
      if (!(tables->db=thd->db))
      {
unknown's avatar
unknown committed
5157 5158
	my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
                   MYF(0));                     /* purecov: tested */
unknown's avatar
SCRUM:  
unknown committed
5159 5160 5161 5162 5163 5164
	return TRUE;				/* purecov: tested */
      }
    }
  }
  return FALSE;
}
5165

5166

unknown's avatar
unknown committed
5167 5168 5169 5170 5171 5172 5173 5174 5175 5176
/****************************************************************************
	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
5177 5178 5179 5180
#ifndef DBUG_OFF
long max_stack_used;
#endif

5181
#ifndef EMBEDDED_LIBRARY
5182 5183 5184 5185 5186 5187 5188 5189
/*
  Note: The 'buf' parameter is necessary, even if it is unused here.
  - fix_fields functions has a "dummy" buffer large enough for the
    corresponding exec. (Thus we only have to check in fix_fields.)
  - Passing to check_stack_overrun() prevents the compiler from removing it.
 */
bool check_stack_overrun(THD *thd, long margin,
			 char *buf __attribute__((unused)))
unknown's avatar
unknown committed
5190 5191 5192
{
  long stack_used;
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
unknown's avatar
unknown committed
5193
      (long) (thread_stack - margin))
unknown's avatar
unknown committed
5194
  {
5195 5196 5197
    sprintf(errbuff[0],ER(ER_STACK_OVERRUN_NEED_MORE),
            stack_used,thread_stack,margin);
    my_message(ER_STACK_OVERRUN_NEED_MORE,errbuff[0],MYF(0));
5198
    thd->fatal_error();
unknown's avatar
unknown committed
5199 5200
    return 1;
  }
unknown's avatar
unknown committed
5201 5202 5203
#ifndef DBUG_OFF
  max_stack_used= max(max_stack_used, stack_used);
#endif
unknown's avatar
unknown committed
5204 5205
  return 0;
}
5206
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
5207 5208 5209 5210

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

5211
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
unknown's avatar
unknown committed
5212 5213
{
  LEX	*lex=current_lex;
5214
  ulong old_info=0;
unknown's avatar
unknown committed
5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240
  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;
}


/****************************************************************************
5241
  Initialize global thd variables needed for query
unknown's avatar
unknown committed
5242 5243
****************************************************************************/

5244
void
unknown's avatar
unknown committed
5245
mysql_init_query(THD *thd, uchar *buf, uint length)
unknown's avatar
unknown committed
5246 5247
{
  DBUG_ENTER("mysql_init_query");
unknown's avatar
unknown committed
5248
  lex_start(thd, buf, length);
5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269
  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");
5270
  thd->free_list= 0;
5271
  thd->select_number= 1;
unknown's avatar
unknown committed
5272
  thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
5273
  thd->is_fatal_error= thd->time_zone_used= 0;
unknown's avatar
unknown committed
5274
  thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | 
unknown's avatar
unknown committed
5275 5276
                          SERVER_QUERY_NO_INDEX_USED |
                          SERVER_QUERY_NO_GOOD_INDEX_USED);
5277
  DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
unknown's avatar
unknown committed
5278
  thd->tmp_table_used= 0;
5279 5280
  if (!thd->in_sub_stmt)
  {
5281
    if (opt_bin_log)
5282
    {
5283
      reset_dynamic(&thd->user_var_events);
5284 5285
      thd->user_var_events_alloc= thd->mem_root;
    }
5286
    thd->clear_error();
5287 5288 5289 5290
    thd->total_warn_count=0;			// Warnings for this query
    thd->rand_used= 0;
    thd->sent_row_count= thd->examined_row_count= 0;
  }
unknown's avatar
unknown committed
5291 5292 5293
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
5294

5295 5296 5297
void
mysql_init_select(LEX *lex)
{
unknown's avatar
(SCRUM)  
unknown committed
5298
  SELECT_LEX *select_lex= lex->current_select;
unknown's avatar
unknown committed
5299
  select_lex->init_select();
5300
  lex->wild= 0;
5301 5302
  if (select_lex == &lex->select_lex)
  {
5303
    DBUG_ASSERT(lex->result == 0);
5304 5305
    lex->exchange= 0;
  }
5306 5307
}

5308

unknown's avatar
unknown committed
5309
bool
unknown's avatar
unknown committed
5310
mysql_new_select(LEX *lex, bool move_down)
5311
{
unknown's avatar
unknown committed
5312
  SELECT_LEX *select_lex;
5313
  THD *thd= lex->thd;
unknown's avatar
unknown committed
5314 5315
  DBUG_ENTER("mysql_new_select");

5316
  if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
5317
    DBUG_RETURN(1);
5318
  select_lex->select_number= ++thd->select_number;
unknown's avatar
unknown committed
5319
  select_lex->parent_lex= lex; /* Used in init_query. */
unknown's avatar
unknown committed
5320 5321
  select_lex->init_query();
  select_lex->init_select();
5322 5323 5324 5325 5326
  /*
    Don't evaluate this subquery during statement prepare even if
    it's a constant one. The flag is switched off in the end of
    mysql_stmt_prepare.
  */
unknown's avatar
Rename:  
unknown committed
5327
  if (thd->stmt_arena->is_stmt_prepare())
5328
    select_lex->uncacheable|= UNCACHEABLE_PREPARE;
unknown's avatar
unknown committed
5329 5330
  if (move_down)
  {
unknown's avatar
unknown committed
5331
    SELECT_LEX_UNIT *unit;
5332
    lex->subqueries= TRUE;
unknown's avatar
unknown committed
5333
    /* first select_lex of subselect or derived table */
5334
    if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
unknown's avatar
unknown committed
5335
      DBUG_RETURN(1);
unknown's avatar
unknown committed
5336

unknown's avatar
unknown committed
5337 5338
    unit->init_query();
    unit->init_select();
5339
    unit->thd= thd;
unknown's avatar
(SCRUM)  
unknown committed
5340
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
5341 5342
    unit->link_next= 0;
    unit->link_prev= 0;
5343
    unit->return_to= lex->current_select;
unknown's avatar
unknown committed
5344
    select_lex->include_down(unit);
5345 5346 5347 5348 5349
    /*
      By default we assume that it is usual subselect and we have outer name
      resolution context, if no we will assign it to 0 later
    */
    select_lex->context.outer_context= &select_lex->outer_select()->context;
unknown's avatar
unknown committed
5350 5351
  }
  else
unknown's avatar
(SCRUM)  
unknown committed
5352
  {
5353
    Name_resolution_context *outer_context;
unknown's avatar
VIEW  
unknown committed
5354 5355
    if (lex->current_select->order_list.first && !lex->current_select->braces)
    {
unknown's avatar
unknown committed
5356
      my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
unknown's avatar
unknown committed
5357
      DBUG_RETURN(1);
unknown's avatar
VIEW  
unknown committed
5358
    }
5359
    select_lex->include_neighbour(lex->current_select);
5360 5361 5362 5363 5364 5365
    /*
      we are not sure that we have one level of SELECTs above, so we take
      outer_context address from first select of unit
    */
    outer_context=
      select_lex->master_unit()->first_select()->context.outer_context;
unknown's avatar
(SCRUM)  
unknown committed
5366 5367 5368 5369 5370 5371 5372 5373
    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
      */
5374
      if (!(fake= unit->fake_select_lex= new (thd->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
5375
        DBUG_RETURN(1);
unknown's avatar
(SCRUM)  
unknown committed
5376 5377 5378
      fake->include_standalone(unit,
			       (SELECT_LEX_NODE**)&unit->fake_select_lex);
      fake->select_number= INT_MAX;
unknown's avatar
unknown committed
5379
      fake->parent_lex= lex; /* Used in init_query. */
unknown's avatar
(SCRUM)  
unknown committed
5380 5381
      fake->make_empty_select();
      fake->linkage= GLOBAL_OPTIONS_TYPE;
5382
      fake->select_limit= 0;
5383 5384 5385 5386 5387

      fake->context.outer_context= outer_context;
      /* allow item list resolving in fake select for ORDER BY */
      fake->context.resolve_in_select_list= TRUE;
      fake->context.select_lex= fake;
unknown's avatar
unknown committed
5388 5389 5390 5391 5392
      /*
        Remove the name resolution context of the fake select from the
        context stack.
       */
      lex->pop_context();
unknown's avatar
(SCRUM)  
unknown committed
5393
    }
5394
    select_lex->context.outer_context= outer_context;
unknown's avatar
(SCRUM)  
unknown committed
5395
  }
unknown's avatar
unknown committed
5396

5397
  select_lex->master_unit()->global_parameters= select_lex;
5398
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
5399
  lex->current_select= select_lex;
5400 5401 5402 5403 5404
  /*
    in subquery is SELECT query and we allow resolution of names in SELECT
    list
  */
  select_lex->context.resolve_in_select_list= TRUE;
unknown's avatar
unknown committed
5405
  DBUG_RETURN(0);
5406
}
unknown's avatar
unknown committed
5407

5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422
/*
  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)
{
5423
  THD *thd;
5424
  LEX *lex;
5425
  LEX_STRING tmp, null_lex_string;
5426 5427
  Item *var;
  char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end;
5428
  DBUG_ENTER("create_select_for_variable");
5429 5430

  thd= current_thd;
unknown's avatar
unknown committed
5431
  lex= thd->lex;
5432 5433 5434 5435
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
5436
  bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
5437 5438 5439 5440
  /*
    We set the name of Item to @@session.var_name because that then is used
    as the column name in the output.
  */
unknown's avatar
unknown committed
5441 5442 5443 5444 5445 5446
  if ((var= get_system_var(thd, OPT_SESSION, tmp, null_lex_string)))
  {
    end= strxmov(buff, "@@session.", var_name, NullS);
    var->set_name(buff, end-buff, system_charset_info);
    add_item_to_list(thd, var);
  }
5447 5448 5449
  DBUG_VOID_RETURN;
}

5450

unknown's avatar
unknown committed
5451 5452
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
5453
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
5454
  mysql_init_select(lex);
5455 5456
  lex->select_lex.select_limit= 0;
  lex->unit.select_limit_cnt= HA_POS_ERROR;
unknown's avatar
unknown committed
5457
  lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list);
5458
  lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
unknown's avatar
VIEW  
unknown committed
5459 5460
  lex->query_tables= 0;
  lex->query_tables_last= &lex->query_tables;
unknown's avatar
unknown committed
5461
}
unknown's avatar
unknown committed
5462

5463

5464 5465 5466 5467
/*
  When you modify mysql_parse(), you may need to mofify
  mysql_test_parse_for_slave() in this same file.
*/
unknown's avatar
unknown committed
5468

5469
void mysql_parse(THD *thd, char *inBuf, uint length)
unknown's avatar
unknown committed
5470 5471
{
  DBUG_ENTER("mysql_parse");
unknown's avatar
unknown committed
5472
  mysql_init_query(thd, (uchar*) inBuf, length);
unknown's avatar
unknown committed
5473
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
unknown's avatar
unknown committed
5474
  {
unknown's avatar
unknown committed
5475
    LEX *lex= thd->lex;
5476
    
5477 5478
    sp_cache_flush_obsolete(&thd->sp_proc_cache);
    sp_cache_flush_obsolete(&thd->sp_func_cache);
5479
    
5480
    if (!yyparse((void *)thd) && ! thd->is_fatal_error)
unknown's avatar
unknown committed
5481
    {
unknown's avatar
SCRUM:  
unknown committed
5482
#ifndef NO_EMBEDDED_ACCESS_CHECKS
5483
      if (mqh_used && thd->user_connect &&
5484
	  check_mqh(thd, lex->sql_command))
5485 5486 5487 5488
      {
	thd->net.error = 0;
      }
      else
unknown's avatar
SCRUM:  
unknown committed
5489
#endif
5490
      {
unknown's avatar
unknown committed
5491
	if (thd->net.report_error)
5492 5493
	{
	  if (thd->lex->sphead)
5494 5495 5496 5497
	  {
	    delete thd->lex->sphead;
	    thd->lex->sphead= NULL;
	  }
5498
	}
unknown's avatar
unknown committed
5499 5500
	else
	{
5501 5502 5503 5504 5505 5506 5507 5508 5509 5510
          /*
            Binlog logs a string starting from thd->query and having length
            thd->query_length; so we set thd->query_length correctly (to not
            log several statements in one event, when we executed only first).
            We set it to not see the ';' (otherwise it would get into binlog
            and Query_log_event::print() would give ';;' output).
            This also helps display only the current query in SHOW
            PROCESSLIST.
            Note that we don't need LOCK_thread_count to modify query_length.
          */
unknown's avatar
unknown committed
5511 5512
          if (lex->found_semicolon &&
              (thd->query_length= (ulong)(lex->found_semicolon - thd->query)))
5513 5514
            thd->query_length--;
          /* Actually execute the query */
unknown's avatar
unknown committed
5515
	  mysql_execute_command(thd);
unknown's avatar
SCRUM  
unknown committed
5516
	  query_cache_end_of_result(thd);
unknown's avatar
unknown committed
5517
	}
5518
      }
5519
      lex->unit.cleanup();
unknown's avatar
unknown committed
5520 5521
    }
    else
5522 5523
    {
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
5524
			 thd->is_fatal_error));
unknown's avatar
unknown committed
5525
      query_cache_abort(&thd->net);
5526
      lex->unit.cleanup();
5527
      if (thd->lex->sphead)
5528
      {
unknown's avatar
unknown committed
5529
	/* Clean up after failed stored procedure/function */
5530 5531 5532
	delete thd->lex->sphead;
	thd->lex->sphead= NULL;
      }
5533
    }
unknown's avatar
unknown committed
5534
    thd->proc_info="freeing items";
5535
    thd->end_statement();
5536
    thd->cleanup_after_query();
5537
    DBUG_ASSERT(thd->change_list.is_empty());
unknown's avatar
unknown committed
5538
  }
unknown's avatar
unknown committed
5539 5540 5541 5542
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
5543
#ifdef HAVE_REPLICATION
5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554
/*
  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
5555
  LEX *lex= thd->lex;
5556
  bool error= 0;
unknown's avatar
unknown committed
5557
  DBUG_ENTER("mysql_test_parse_for_slave");
5558

unknown's avatar
unknown committed
5559
  mysql_init_query(thd, (uchar*) inBuf, length);
unknown's avatar
unknown committed
5560
  if (!yyparse((void*) thd) && ! thd->is_fatal_error &&
5561
      all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
unknown's avatar
unknown committed
5562
    error= 1;                  /* Ignore question */
5563
  thd->end_statement();
5564
  thd->cleanup_after_query();
unknown's avatar
unknown committed
5565
  DBUG_RETURN(error);
5566
}
unknown's avatar
unknown committed
5567
#endif
unknown's avatar
unknown committed
5568

5569

unknown's avatar
unknown committed
5570

unknown's avatar
unknown committed
5571 5572 5573 5574 5575
/*****************************************************************************
** Store field definition for create
** Return 0 if ok
******************************************************************************/

unknown's avatar
unknown committed
5576
bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
unknown's avatar
unknown committed
5577
		       char *length, char *decimals,
5578
		       uint type_modifier,
5579 5580
		       Item *default_value, Item *on_update_value,
                       LEX_STRING *comment,
5581 5582
		       char *change,
                       List<String> *interval_list, CHARSET_INFO *cs,
unknown's avatar
unknown committed
5583
		       uint uint_geom_type)
unknown's avatar
unknown committed
5584 5585
{
  register create_field *new_field;
unknown's avatar
unknown committed
5586
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
5587 5588 5589 5590
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
5591
    my_error(ER_TOO_LONG_IDENT, MYF(0), field_name); /* purecov: inspected */
unknown's avatar
unknown committed
5592 5593 5594 5595 5596
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
5597
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
5598
				    0, lex->col_list));
unknown's avatar
unknown committed
5599 5600 5601 5602 5603
    lex->col_list.empty();
  }
  if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
5604
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF, 0,
unknown's avatar
unknown committed
5605 5606 5607 5608
				    lex->col_list));
    lex->col_list.empty();
  }

5609
  if (default_value)
unknown's avatar
unknown committed
5610
  {
5611
    /* 
unknown's avatar
unknown committed
5612 5613
      Default value should be literal => basic constants =>
      no need fix_fields()
5614 5615 5616
      
      We allow only one function as part of default value - 
      NOW() as default for TIMESTAMP type.
5617
    */
5618 5619 5620
    if (default_value->type() == Item::FUNC_ITEM && 
        !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
         type == FIELD_TYPE_TIMESTAMP))
5621
    {
5622
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
5623 5624 5625
      DBUG_RETURN(1);
    }
    else if (default_value->type() == Item::NULL_ITEM)
unknown's avatar
unknown committed
5626
    {
5627
      default_value= 0;
5628 5629 5630
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
5631
	my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
5632 5633 5634 5635 5636
	DBUG_RETURN(1);
      }
    }
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
5637
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
unknown's avatar
unknown committed
5638 5639 5640
      DBUG_RETURN(1);
    }
  }
5641 5642 5643

  if (on_update_value && type != FIELD_TYPE_TIMESTAMP)
  {
5644
    my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
5645 5646
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
5647

5648 5649 5650 5651 5652 5653
  if (type == FIELD_TYPE_TIMESTAMP && length)
  {
    /* Display widths are no longer supported for TIMSTAMP as of MySQL 4.1.
       In other words, for declarations such as TIMESTAMP(2), TIMESTAMP(4),
       and so on, the display width is ignored.
    */
unknown's avatar
unknown committed
5654
    char buf[32];
5655
    my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length);
5656 5657 5658
    push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN,
                        ER_WARN_DEPRECATED_SYNTAX,
                        ER(ER_WARN_DEPRECATED_SYNTAX),
unknown's avatar
unknown committed
5659
                        buf, "TIMESTAMP");
5660 5661
  }

unknown's avatar
unknown committed
5662 5663 5664
  if (!(new_field= new_create_field(thd, field_name, type, length, decimals,
		type_modifier, default_value, on_update_value,
		comment, change, interval_list, cs, uint_geom_type)))
unknown's avatar
unknown committed
5665
    DBUG_RETURN(1);
unknown's avatar
unknown committed
5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692

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

/*****************************************************************************
** Create field definition for create
** Return 0 on failure, otherwise return create_field instance
******************************************************************************/
  
create_field *
new_create_field(THD *thd, char *field_name, enum_field_types type,
		 char *length, char *decimals,
		 uint type_modifier, 
		 Item *default_value, Item *on_update_value,
		 LEX_STRING *comment,
		 char *change, List<String> *interval_list, CHARSET_INFO *cs,
		 uint uint_geom_type)
{
  register create_field *new_field;
  uint sign_len, allowed_type_modifier=0;
  ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
  DBUG_ENTER("new_create_field");
  
  if (!(new_field=new create_field()))
    DBUG_RETURN(NULL);
unknown's avatar
unknown committed
5693 5694
  new_field->field=0;
  new_field->field_name=field_name;
5695
  new_field->def= default_value;
unknown's avatar
unknown committed
5696 5697 5698
  new_field->flags= type_modifier;
  new_field->unireg_check= (type_modifier & AUTO_INCREMENT_FLAG ?
			    Field::NEXT_NUMBER : Field::NONE);
5699 5700 5701 5702 5703 5704 5705 5706
  new_field->decimals= decimals ? (uint)atoi(decimals) : 0;
  if (new_field->decimals >= NOT_FIXED_DEC)
  {
    my_error(ER_TOO_BIG_SCALE, MYF(0), new_field->decimals, field_name,
             NOT_FIXED_DEC-1);
    DBUG_RETURN(NULL);
  }

unknown's avatar
unknown committed
5707 5708 5709 5710
  new_field->sql_type=type;
  new_field->length=0;
  new_field->change=change;
  new_field->interval=0;
5711
  new_field->pack_length= new_field->key_length= 0;
5712
  new_field->charset=cs;
unknown's avatar
unknown committed
5713
  new_field->geom_type= (Field::geometry_type) uint_geom_type;
unknown's avatar
unknown committed
5714

unknown's avatar
unknown committed
5715
  new_field->comment=*comment;
unknown's avatar
unknown committed
5716 5717 5718
  /*
    Set flag if this field doesn't have a default value
  */
unknown's avatar
unknown committed
5719
  if (!default_value && !(type_modifier & AUTO_INCREMENT_FLAG) &&
5720
      (type_modifier & NOT_NULL_FLAG) && type != FIELD_TYPE_TIMESTAMP)
unknown's avatar
unknown committed
5721 5722
    new_field->flags|= NO_DEFAULT_VALUE_FLAG;

5723 5724
  if (length && !(new_field->length= (uint) atoi(length)))
    length=0; /* purecov: inspected */
unknown's avatar
unknown committed
5725
  sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
unknown's avatar
unknown committed
5726 5727 5728

  switch (type) {
  case FIELD_TYPE_TINY:
5729
    if (!length) new_field->length=MAX_TINYINT_WIDTH+sign_len;
unknown's avatar
unknown committed
5730 5731 5732
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_SHORT:
5733
    if (!length) new_field->length=MAX_SMALLINT_WIDTH+sign_len;
unknown's avatar
unknown committed
5734 5735 5736
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_INT24:
5737
    if (!length) new_field->length=MAX_MEDIUMINT_WIDTH+sign_len;
unknown's avatar
unknown committed
5738 5739 5740
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONG:
5741
    if (!length) new_field->length=MAX_INT_WIDTH+sign_len;
unknown's avatar
unknown committed
5742 5743 5744
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONGLONG:
5745
    if (!length) new_field->length=MAX_BIGINT_WIDTH;
unknown's avatar
unknown committed
5746 5747 5748 5749
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_NULL:
    break;
unknown's avatar
unknown committed
5750
  case FIELD_TYPE_NEWDECIMAL:
5751
    if (!length && !new_field->decimals)
5752 5753
      new_field->length= 10;
    if (new_field->length > DECIMAL_MAX_PRECISION)
unknown's avatar
Cleanup  
unknown committed
5754
    {
5755 5756 5757
      my_error(ER_TOO_BIG_PRECISION, MYF(0), new_field->length, field_name,
               DECIMAL_MAX_PRECISION);
      DBUG_RETURN(NULL);
unknown's avatar
Cleanup  
unknown committed
5758
    }
5759
    if (new_field->length < new_field->decimals)
unknown's avatar
unknown committed
5760
    {
unknown's avatar
unknown committed
5761
      my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
5762
      DBUG_RETURN(NULL);
unknown's avatar
unknown committed
5763
    }
5764 5765 5766 5767 5768 5769
    new_field->length=
      my_decimal_precision_to_length(new_field->length, new_field->decimals,
                                     type_modifier & UNSIGNED_FLAG);
    new_field->pack_length=
      my_decimal_get_binary_size(new_field->length, new_field->decimals);
    break;
5770 5771 5772 5773 5774 5775 5776 5777 5778
  case MYSQL_TYPE_VARCHAR:
    /*
      Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
      if they don't have a default value
    */
    max_field_charlength= MAX_FIELD_VARCHARLENGTH;
    break;
  case MYSQL_TYPE_STRING:
    break;
unknown's avatar
unknown committed
5779 5780 5781 5782
  case FIELD_TYPE_BLOB:
  case FIELD_TYPE_TINY_BLOB:
  case FIELD_TYPE_LONG_BLOB:
  case FIELD_TYPE_MEDIUM_BLOB:
unknown's avatar
unknown committed
5783
  case FIELD_TYPE_GEOMETRY:
unknown's avatar
unknown committed
5784 5785 5786 5787 5788 5789
    if (default_value)				// Allow empty as default value
    {
      String str,*res;
      res=default_value->val_str(&str);
      if (res->length())
      {
5790 5791
	my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
                 field_name); /* purecov: inspected */
unknown's avatar
unknown committed
5792
	DBUG_RETURN(NULL);
unknown's avatar
unknown committed
5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810
      }
      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)
      {
5811
	my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
unknown's avatar
unknown committed
5812
	DBUG_RETURN(NULL);
unknown's avatar
unknown committed
5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823
      }
      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;
    }
5824
    if (!length && !decimals)
unknown's avatar
unknown committed
5825 5826 5827 5828
    {
      new_field->length =  FLT_DIG+6;
      new_field->decimals= NOT_FIXED_DEC;
    }
5829 5830 5831
    if (new_field->length < new_field->decimals &&
        new_field->decimals != NOT_FIXED_DEC)
    {
5832
      my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
5833 5834
      DBUG_RETURN(NULL);
    }
unknown's avatar
unknown committed
5835 5836 5837
    break;
  case FIELD_TYPE_DOUBLE:
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
5838
    if (!length && !decimals)
unknown's avatar
unknown committed
5839 5840 5841 5842
    {
      new_field->length = DBL_DIG+7;
      new_field->decimals=NOT_FIXED_DEC;
    }
5843 5844 5845
    if (new_field->length < new_field->decimals &&
        new_field->decimals != NOT_FIXED_DEC)
    {
5846
      my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
5847 5848
      DBUG_RETURN(NULL);
    }
unknown's avatar
unknown committed
5849 5850 5851 5852
    break;
  case FIELD_TYPE_TIMESTAMP:
    if (!length)
      new_field->length= 14;			// Full date YYYYMMDDHHMMSS
5853
    else if (new_field->length != 19)
unknown's avatar
unknown committed
5854
    {
5855 5856 5857 5858
      /*
        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
5859 5860 5861
      new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
      new_field->length= min(new_field->length,14); /* purecov: inspected */
    }
5862
    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882
    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
    {
5883 5884 5885 5886 5887 5888 5889 5890
      /*
        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
5891
        information about all TIMESTAMP fields in table will be availiable.
5892 5893 5894

        If we have TIMESTAMP NULL column without explicit DEFAULT value
        we treat it as having DEFAULT NULL attribute.
5895
      */
unknown's avatar
unknown committed
5896 5897 5898 5899 5900
      new_field->unireg_check= (on_update_value ?
                                Field::TIMESTAMP_UN_FIELD :
                                (new_field->flags & NOT_NULL_FLAG ?
                                 Field::TIMESTAMP_OLD_FIELD:
                                 Field::NONE));
5901
    }
unknown's avatar
unknown committed
5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917
    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:
    {
5918
      if (interval_list->elements > sizeof(longlong)*8)
unknown's avatar
unknown committed
5919
      {
5920
	my_error(ER_TOO_BIG_SET, MYF(0), field_name); /* purecov: inspected */
unknown's avatar
unknown committed
5921
	DBUG_RETURN(NULL);
unknown's avatar
unknown committed
5922
      }
5923
      new_field->pack_length= get_set_pack_length(interval_list->elements);
5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934

      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
5935
      break;
unknown's avatar
unknown committed
5936 5937 5938
    }
  case FIELD_TYPE_ENUM:
    {
5939
      // Should be safe
5940
      new_field->pack_length= get_enum_pack_length(interval_list->elements);
5941

5942 5943 5944 5945 5946
      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
5947
      break;
unknown's avatar
unknown committed
5948
   }
5949 5950
  case MYSQL_TYPE_VAR_STRING:
    DBUG_ASSERT(0);                             // Impossible
5951
    break;
unknown's avatar
unknown committed
5952 5953 5954 5955 5956 5957
  case MYSQL_TYPE_BIT:
    {
      if (!length)
        new_field->length= 1;
      if (new_field->length > MAX_BIT_FIELD_LENGTH)
      {
5958
        my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name,
unknown's avatar
unknown committed
5959
                 MAX_BIT_FIELD_LENGTH);
unknown's avatar
unknown committed
5960
        DBUG_RETURN(NULL);
unknown's avatar
unknown committed
5961 5962 5963 5964
      }
      new_field->pack_length= (new_field->length + 7) / 8;
      break;
    }
unknown's avatar
unknown committed
5965 5966
  case FIELD_TYPE_DECIMAL:
    DBUG_ASSERT(0); /* Was obsolete */
unknown's avatar
unknown committed
5967 5968
  }

5969 5970 5971 5972 5973 5974 5975
  if (!(new_field->flags & BLOB_FLAG) &&
      ((new_field->length > max_field_charlength && type != FIELD_TYPE_SET && 
        type != FIELD_TYPE_ENUM &&
        (type != MYSQL_TYPE_VARCHAR || default_value)) ||
       (!new_field->length &&
        type != MYSQL_TYPE_STRING &&
        type != MYSQL_TYPE_VARCHAR && type != FIELD_TYPE_GEOMETRY)))
unknown's avatar
unknown committed
5976
  {
5977 5978 5979 5980
    my_error((type == MYSQL_TYPE_VAR_STRING || type == MYSQL_TYPE_VARCHAR ||
              type == MYSQL_TYPE_STRING) ?  ER_TOO_BIG_FIELDLENGTH :
             ER_TOO_BIG_DISPLAYWIDTH,
             MYF(0),
unknown's avatar
unknown committed
5981
             field_name, max_field_charlength); /* purecov: inspected */
unknown's avatar
unknown committed
5982
    DBUG_RETURN(NULL);
unknown's avatar
unknown committed
5983 5984 5985 5986
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
5987
    my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
unknown's avatar
unknown committed
5988
    DBUG_RETURN(NULL);
unknown's avatar
unknown committed
5989
  }
unknown's avatar
unknown committed
5990
  DBUG_RETURN(new_field);
unknown's avatar
unknown committed
5991 5992
}

5993

unknown's avatar
unknown committed
5994 5995 5996 5997 5998 5999 6000 6001
/* 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
6002
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
6003 6004 6005 6006
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
6007
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
6008 6009 6010 6011 6012
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
unknown's avatar
unknown committed
6013
  thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
6014 6015 6016 6017 6018 6019 6020 6021
  return 0;
}


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

static void remove_escape(char *name)
{
6022 6023
  if (!*name)					// For empty DB names
    return;
unknown's avatar
unknown committed
6024 6025
  char *to;
#ifdef USE_MB
unknown's avatar
unknown committed
6026
  char *strend=name+(uint) strlen(name);
unknown's avatar
unknown committed
6027 6028 6029 6030 6031
#endif
  for (to=name; *name ; name++)
  {
#ifdef USE_MB
    int l;
6032 6033
    if (use_mb(system_charset_info) &&
        (l = my_ismbchar(system_charset_info, name, strend)))
unknown's avatar
unknown committed
6034 6035 6036 6037 6038 6039 6040 6041
    {
	while (l--)
	    *to++ = *name++;
	name--;
	continue;
    }
#endif
    if (*name == '\\' && name[1])
unknown's avatar
unknown committed
6042
      name++;					// Skip '\\'
unknown's avatar
unknown committed
6043 6044 6045 6046 6047 6048 6049 6050 6051 6052
    *to++= *name;
  }
  *to=0;
}

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


unknown's avatar
unknown committed
6053
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
6054 6055 6056
{
  ORDER *order;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
6057
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER))))
unknown's avatar
unknown committed
6058
    DBUG_RETURN(1);
unknown's avatar
unknown committed
6059 6060
  order->item_ptr= item;
  order->item= &order->item_ptr;
unknown's avatar
unknown committed
6061 6062 6063
  order->asc = asc;
  order->free_me=0;
  order->used=0;
6064
  order->counter_used= 0;
unknown's avatar
unknown committed
6065
  list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
6066 6067 6068 6069
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088
/*
  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
6089 6090
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
6091
					     LEX_STRING *alias,
unknown's avatar
unknown committed
6092 6093
					     ulong table_options,
					     thr_lock_type lock_type,
6094 6095
					     List<String> *use_index_arg,
					     List<String> *ignore_index_arg,
unknown's avatar
unknown committed
6096
                                             LEX_STRING *option)
unknown's avatar
unknown committed
6097 6098
{
  register TABLE_LIST *ptr;
unknown's avatar
unknown committed
6099
  TABLE_LIST *previous_table_ref; /* The table preceding the current one. */
unknown's avatar
unknown committed
6100
  char *alias_str;
6101
  LEX *lex= thd->lex;
unknown's avatar
unknown committed
6102
  DBUG_ENTER("add_table_to_list");
6103
  LINT_INIT(previous_table_ref);
unknown's avatar
unknown committed
6104 6105 6106 6107

  if (!table)
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? alias->str : table->table.str;
unknown's avatar
unknown committed
6108
  if (check_table_name(table->table.str,table->table.length) ||
unknown's avatar
unknown committed
6109
      table->db.str && check_db_name(table->db.str))
unknown's avatar
unknown committed
6110
  {
6111
    my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
unknown's avatar
unknown committed
6112 6113 6114 6115
    DBUG_RETURN(0);
  }

  if (!alias)					/* Alias is case sensitive */
6116 6117 6118
  {
    if (table->sel)
    {
unknown's avatar
unknown committed
6119 6120
      my_message(ER_DERIVED_MUST_HAVE_ALIAS,
                 ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
6121 6122
      DBUG_RETURN(0);
    }
6123
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
6124
      DBUG_RETURN(0);
6125
  }
unknown's avatar
unknown committed
6126
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
6127
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
6128
  if (table->db.str)
6129 6130 6131 6132 6133 6134 6135 6136
  {
    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;
6137
    ptr->current_db_used= 1;
6138 6139 6140
  }
  else
  {
6141 6142
    /* The following can't be "" as we may do 'casedn_str()' on it */
    ptr->db= empty_c_string;
6143
    ptr->db_length= 0;
6144
    ptr->current_db_used= 1;
6145
  }
unknown's avatar
Rename:  
unknown committed
6146
  if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
6147
    ptr->db= thd->strdup(ptr->db);
unknown's avatar
unknown committed
6148

6149
  ptr->alias= alias_str;
6150 6151
  if (lower_case_table_names && table->table.length)
    my_casedn_str(files_charset_info, table->table.str);
6152 6153
  ptr->table_name=table->table.str;
  ptr->table_name_length=table->table.length;
6154
  ptr->lock_type=   lock_type;
unknown's avatar
unknown committed
6155 6156
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
6157
  ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
6158
  ptr->derived=	    table->sel;
6159 6160 6161
  if (!my_strcasecmp(system_charset_info, ptr->db,
                     information_schema_name.str))
  {
6162
    ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
6163 6164 6165
    if (!schema_table ||
        (schema_table->hidden && 
         lex->orig_sql_command == SQLCOM_END))  // not a 'show' command
6166
    {
unknown's avatar
unknown committed
6167
      my_error(ER_UNKNOWN_TABLE, MYF(0),
6168
               ptr->table_name, information_schema_name.str);
6169 6170
      DBUG_RETURN(0);
    }
6171
    ptr->schema_table_name= ptr->table_name;
6172 6173
    ptr->schema_table= schema_table;
  }
6174
  ptr->select_lex=  lex->current_select;
unknown's avatar
unknown committed
6175
  ptr->cacheable_table= 1;
6176 6177 6178 6179 6180 6181
  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
6182
  ptr->option= option ? option->str : 0;
unknown's avatar
unknown committed
6183
  /* check that used name is unique */
6184
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
6185
  {
unknown's avatar
unknown committed
6186 6187 6188 6189
    TABLE_LIST *first_table= (TABLE_LIST*) table_list.first;
    if (lex->sql_command == SQLCOM_CREATE_VIEW)
      first_table= first_table ? first_table->next_local : NULL;
    for (TABLE_LIST *tables= first_table ;
unknown's avatar
unknown committed
6190
	 tables ;
unknown's avatar
VIEW  
unknown committed
6191
	 tables=tables->next_local)
unknown's avatar
unknown committed
6192
    {
6193 6194
      if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
	  !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
6195
      {
6196
	my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
unknown's avatar
unknown committed
6197 6198
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
6199 6200
    }
  }
unknown's avatar
unknown committed
6201 6202 6203
  /* Store the table reference preceding the current one. */
  if (table_list.elements > 0)
  {
6204 6205 6206 6207 6208 6209
    /*
      table_list.next points to the last inserted TABLE_LIST->next_local'
      element
    */
    previous_table_ref= (TABLE_LIST*) (table_list.next -
                                       offsetof(TABLE_LIST, next_local));
unknown's avatar
unknown committed
6210
    DBUG_ASSERT(previous_table_ref);
6211 6212 6213 6214 6215 6216 6217 6218
    /*
      Set next_name_resolution_table of the previous table reference to point
      to the current table reference. In effect the list
      TABLE_LIST::next_name_resolution_table coincides with
      TABLE_LIST::next_local. Later this may be changed in
      store_top_level_join_columns() for NATURAL/USING joins.
    */
    previous_table_ref->next_name_resolution_table= ptr;
unknown's avatar
unknown committed
6219
  }
6220

unknown's avatar
unknown committed
6221 6222 6223 6224 6225 6226
  /*
    Link the current table reference in a local list (list for current select).
    Notice that as a side effect here we set the next_local field of the
    previous table reference to 'ptr'. Here we also add one element to the
    list 'table_list'.
  */
unknown's avatar
VIEW  
unknown committed
6227
  table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
unknown's avatar
unknown committed
6228
  ptr->next_name_resolution_table= NULL;
6229
  /* Link table in global list (all used tables) */
6230
  lex->add_to_query_tables(ptr);
unknown's avatar
unknown committed
6231 6232 6233
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
6234

6235 6236 6237 6238
/*
  Initialize a new table list for a nested join

  SYNOPSIS
unknown's avatar
unknown committed
6239
    init_nested_join()
6240
    thd         current thread
6241

6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260
  DESCRIPTION
    The function initializes a structure of the TABLE_LIST type
    for a nested join. It sets up its nested join list as empty.
    The created structure is added to the front of the current
    join list in the st_select_lex object. Then the function
    changes the current nest level for joins to refer to the newly
    created empty list after having saved the info on the old level
    in the initialized structure.

  RETURN VALUE
    0,  if success
    1,  otherwise
*/

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

6262 6263
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
6264
    DBUG_RETURN(1);
6265 6266 6267
  nested_join= ptr->nested_join=
    ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));

6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287
  join_list->push_front(ptr);
  ptr->embedding= embedding;
  ptr->join_list= join_list;
  embedding= ptr;
  join_list= &nested_join->join_list;
  join_list->empty();
  DBUG_RETURN(0);
}


/*
  End a nested join table list

  SYNOPSIS
    end_nested_join()
    thd         current thread

  DESCRIPTION
    The function returns to the previous join nest level.
    If the current level contains only one member, the function
6288
    moves it one level up, eliminating the nest.
6289 6290 6291 6292 6293 6294 6295 6296 6297

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

TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
{
  TABLE_LIST *ptr;
6298
  NESTED_JOIN *nested_join;
6299
  DBUG_ENTER("end_nested_join");
6300

unknown's avatar
unknown committed
6301
  DBUG_ASSERT(embedding);
6302 6303 6304
  ptr= embedding;
  join_list= ptr->join_list;
  embedding= ptr->embedding;
6305
  nested_join= ptr->nested_join;
6306 6307 6308 6309 6310 6311 6312 6313 6314
  if (nested_join->join_list.elements == 1)
  {
    TABLE_LIST *embedded= nested_join->join_list.head();
    join_list->pop();
    embedded->join_list= join_list;
    embedded->embedding= embedding;
    join_list->push_front(embedded);
    ptr= embedded;
  }
6315
  else if (nested_join->join_list.elements == 0)
unknown's avatar
unknown committed
6316 6317
  {
    join_list->pop();
6318
    ptr= 0;                                     // return value
unknown's avatar
unknown committed
6319
  }
6320 6321 6322 6323 6324 6325 6326 6327
  DBUG_RETURN(ptr);
}


/*
  Nest last join operation

  SYNOPSIS
6328
    nest_last_join()
6329 6330 6331 6332 6333 6334
    thd         current thread

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

  RETURN VALUE
6335 6336 6337
    0  Error
    #  Pointer to TABLE_LIST element created for the new nested join

6338 6339 6340 6341 6342 6343
*/

TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
{
  TABLE_LIST *ptr;
  NESTED_JOIN *nested_join;
6344
  List<TABLE_LIST> *embedded_list;
6345
  DBUG_ENTER("nest_last_join");
6346

6347 6348
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
6349
    DBUG_RETURN(0);
6350 6351 6352
  nested_join= ptr->nested_join=
    ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));

6353 6354
  ptr->embedding= embedding;
  ptr->join_list= join_list;
6355
  embedded_list= &nested_join->join_list;
6356
  embedded_list->empty();
6357 6358

  for (uint i=0; i < 2; i++)
6359 6360 6361 6362 6363
  {
    TABLE_LIST *table= join_list->pop();
    table->join_list= embedded_list;
    table->embedding= ptr;
    embedded_list->push_back(table);
unknown's avatar
unknown committed
6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376
    if (table->natural_join)
    {
      ptr->is_natural_join= TRUE;
      /*
        If this is a JOIN ... USING, move the list of joined fields to the
        table reference that describes the join.
      */
      if (table->join_using_fields)
      {
        ptr->join_using_fields= table->join_using_fields;
        table->join_using_fields= NULL;
      }
    }
6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416
  }
  join_list->push_front(ptr);
  nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
  DBUG_RETURN(ptr);
}


/*
  Add a table to the current join list

  SYNOPSIS
    add_joined_table()
    table       the table to add

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

  RETURN VALUE
    None
*/

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


/*
  Convert a right join into equivalent left join

  SYNOPSIS
    convert_right_join()
    thd         current thread
6417 6418 6419

  DESCRIPTION
    The function takes the current join list t[0],t[1] ... and
6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442
    effectively converts it into the list t[1],t[0] ...
    Although the outer_join flag for the new nested table contains
    JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
    operation.

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

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

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

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

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

6443
TABLE_LIST *st_select_lex::convert_right_join()
6444 6445
{
  TABLE_LIST *tab2= join_list->pop();
6446
  TABLE_LIST *tab1= join_list->pop();
6447 6448 6449 6450 6451 6452 6453 6454 6455
  DBUG_ENTER("convert_right_join");

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

  DBUG_RETURN(tab1);
}

unknown's avatar
unknown committed
6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468
/*
  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
6469
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
6470 6471 6472 6473 6474 6475
{
  bool for_update= lock_type >= TL_READ_NO_INSERT;
  DBUG_ENTER("set_lock_for_tables");
  DBUG_PRINT("enter", ("lock_type: %d  for_update: %d", lock_type,
		       for_update));

unknown's avatar
VIEW  
unknown committed
6476 6477 6478
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first;
       tables;
       tables= tables->next_local)
unknown's avatar
unknown committed
6479 6480 6481 6482 6483 6484 6485
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
6486

unknown's avatar
unknown committed
6487 6488 6489 6490 6491 6492
/*
  Create a new name resolution context for a JOIN ... ON clause.

  SYNOPSIS
    make_join_on_context()
    thd       pointer to current thread
unknown's avatar
unknown committed
6493
    left_op   left  operand of the JOIN
unknown's avatar
unknown committed
6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509
    right_op  rigth operand of the JOIN

  DESCRIPTION
    Create a new name resolution context for a JOIN ... ON clause,
    and set the first and last leaves of the list of table references
    to be used for name resolution.

  RETURN
    A new context if all is OK
    NULL - if a memory allocation error occured
*/

Name_resolution_context *
make_join_on_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op)
{
  Name_resolution_context *on_context;
6510
  if (!(on_context= new (thd->mem_root) Name_resolution_context))
unknown's avatar
unknown committed
6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537
    return NULL;
  on_context->init();
  on_context->first_name_resolution_table=
    left_op->first_leaf_for_name_resolution();
  on_context->last_name_resolution_table=
    right_op->last_leaf_for_name_resolution();
  return on_context;
}


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

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

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

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

void add_join_on(TABLE_LIST *b, Item *expr)
unknown's avatar
unknown committed
6538
{
6539
  if (expr)
6540
  {
6541
    if (!b->on_expr)
unknown's avatar
unknown committed
6542
      b->on_expr= expr;
6543 6544
    else
    {
unknown's avatar
unknown committed
6545 6546 6547 6548 6549 6550
      /*
        If called from the parser, this happens if you have both a
        right and left join. If called later, it happens if we add more
        than one condition to the ON clause.
      */
      b->on_expr= new Item_cond_and(b->on_expr,expr);
6551 6552
    }
    b->on_expr->top_level_item();
6553
  }
unknown's avatar
unknown committed
6554 6555 6556
}


6557
/*
unknown's avatar
unknown committed
6558 6559
  Mark that there is a NATURAL JOIN or JOIN ... USING between two
  tables.
6560 6561 6562

  SYNOPSIS
    add_join_natural()
unknown's avatar
unknown committed
6563 6564 6565 6566
    a			Left join argument
    b			Right join argument
    using_fields        Field names from USING clause
  
6567
  IMPLEMENTATION
unknown's avatar
unknown committed
6568 6569 6570 6571 6572 6573 6574 6575 6576 6577
    This function marks that table b should be joined with a either via
    a NATURAL JOIN or via JOIN ... USING. Both join types are special
    cases of each other, so we treat them together. The function
    setup_conds() creates a list of equal condition between all fields
    of the same name for NATURAL JOIN or the fields in 'using_fields'
    for JOIN ... USING. The list of equality conditions is stored
    either in b->on_expr, or in JOIN::conds, depending on whether there
    was an outer join.

  EXAMPLE
6578 6579 6580
    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
6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591

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

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

  RETURN
    None
6592 6593
*/

unknown's avatar
unknown committed
6594
void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields)
unknown's avatar
unknown committed
6595
{
unknown's avatar
unknown committed
6596 6597
  b->natural_join= a;
  b->join_using_fields= using_fields;
unknown's avatar
unknown committed
6598 6599
}

unknown's avatar
unknown committed
6600

6601
/*
6602 6603 6604 6605
  Reload/resets privileges and the different caches.

  SYNOPSIS
    reload_acl_and_cache()
6606
    thd			Thread handler (can be NULL!)
6607 6608 6609 6610 6611
    options             What should be reset/reloaded (tables, privileges,
    slave...)
    tables              Tables to flush (if any)
    write_to_binlog     Depending on 'options', it may be very bad to write the
                        query to the binlog (e.g. FLUSH SLAVE); this is a
unknown's avatar
unknown committed
6612 6613 6614
                        pointer where reload_acl_and_cache() will put 0 if
                        it thinks we really should not write to the binlog.
                        Otherwise it will put 1.
6615 6616 6617

  RETURN
    0	 ok
unknown's avatar
unknown committed
6618
    !=0  error.  thd->killed or thd->net.report_error is set
6619 6620
*/

6621 6622
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
                          bool *write_to_binlog)
unknown's avatar
unknown committed
6623 6624 6625
{
  bool result=0;
  select_errors=0;				/* Write if more errors */
6626
  bool tmp_write_to_binlog= 1;
6627

6628
  if (thd && thd->in_sub_stmt)
6629 6630 6631 6632 6633
  {
    my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH");
    return 1;
  }

unknown's avatar
SCRUM  
unknown committed
6634
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
6635 6636
  if (options & REFRESH_GRANT)
  {
6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655
    THD *tmp_thd= 0;
    /*
      If reload_acl_and_cache() is called from SIGHUP handler we have to
      allocate temporary THD for execution of acl_reload()/grant_reload().
    */
    if (!thd && (thd= (tmp_thd= new THD)))
      thd->store_globals();
    if (thd)
    {
      (void)acl_reload(thd);
      (void)grant_reload(thd);
    }
    if (tmp_thd)
    {
      delete tmp_thd;
      /* Remember that we don't have a THD */
      my_pthread_setspecific_ptr(THR_THD,  0);
      thd= 0;
    }
6656
    reset_mqh((LEX_USER *)NULL, TRUE);
unknown's avatar
unknown committed
6657
  }
unknown's avatar
SCRUM  
unknown committed
6658
#endif
unknown's avatar
unknown committed
6659 6660
  if (options & REFRESH_LOG)
  {
6661
    /*
unknown's avatar
unknown committed
6662 6663
      Flush the normal query log, the update log, the binary log,
      the slow query log, and the relay log (if it exists).
6664
    */
unknown's avatar
unknown committed
6665

6666
    /*
unknown's avatar
unknown committed
6667 6668 6669 6670
      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)
6671 6672
    */
    tmp_write_to_binlog= 0;
unknown's avatar
unknown committed
6673 6674
    mysql_log.new_file(1);
    mysql_slow_log.new_file(1);
6675
    mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
unknown's avatar
unknown committed
6676
#ifdef HAVE_REPLICATION
6677
    pthread_mutex_lock(&LOCK_active_mi);
6678
    rotate_relay_log(active_mi);
6679
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
6680
#endif
unknown's avatar
unknown committed
6681 6682
    if (ha_flush_logs())
      result=1;
unknown's avatar
unknown committed
6683 6684
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
6685
  }
unknown's avatar
unknown committed
6686
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
6687 6688
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
6689
    query_cache.pack();				// FLUSH QUERY CACHE
6690
    options &= ~REFRESH_QUERY_CACHE;    // Don't flush cache, just free memory
unknown's avatar
unknown committed
6691 6692 6693
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
6694
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
6695
  }
unknown's avatar
unknown committed
6696
#endif /*HAVE_QUERY_CACHE*/
6697 6698 6699 6700 6701
  /*
    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
6702
  {
6703
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
6704
    {
6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715
      /*
        We must not try to aspire a global read lock if we have a write
        locked table. This would lead to a deadlock when trying to
        reopen (and re-lock) the table after the flush.
      */
      if (thd->locked_tables)
      {
        THR_LOCK_DATA **lock_p= thd->locked_tables->locks;
        THR_LOCK_DATA **end_p= lock_p + thd->locked_tables->lock_count;

        for (; lock_p < end_p; lock_p++)
unknown's avatar
unknown committed
6716
        {
6717 6718 6719 6720 6721
          if ((*lock_p)->type == TL_WRITE)
          {
            my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
            return 1;
          }
unknown's avatar
unknown committed
6722
        }
6723
      }
unknown's avatar
unknown committed
6724 6725 6726 6727
      /*
	Writing to the binlog could cause deadlocks, as we don't log
	UNLOCK TABLES
      */
6728
      tmp_write_to_binlog= 0;
6729
      if (lock_global_read_lock(thd))
unknown's avatar
unknown committed
6730
	return 1;                               // Killed
6731 6732
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
                                 tables);
unknown's avatar
unknown committed
6733
      if (make_global_read_lock_block_commit(thd)) // Killed
6734 6735 6736 6737 6738
      {
        /* Don't leave things in a half-locked state */
        unlock_global_read_lock(thd);
        return 1;
      }
unknown's avatar
unknown committed
6739
    }
6740 6741
    else
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
unknown's avatar
unknown committed
6742
    my_dbopt_cleanup();
unknown's avatar
unknown committed
6743 6744 6745
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
unknown's avatar
unknown committed
6746
  if (thd && (options & REFRESH_STATUS))
unknown's avatar
unknown committed
6747 6748 6749
    refresh_status();
  if (options & REFRESH_THREADS)
    flush_thread_cache();
unknown's avatar
unknown committed
6750
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
6751
  if (options & REFRESH_MASTER)
6752 6753
  {
    tmp_write_to_binlog= 0;
6754
    if (reset_master(thd))
unknown's avatar
unknown committed
6755
    {
6756
      result=1;
unknown's avatar
unknown committed
6757 6758
      thd->fatal_error();                       // Ensure client get error
    }
6759
  }
6760
#endif
unknown's avatar
unknown committed
6761
#ifdef OPENSSL
6762 6763 6764 6765 6766 6767
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
unknown's avatar
unknown committed
6768
#ifdef HAVE_REPLICATION
6769 6770
 if (options & REFRESH_SLAVE)
 {
6771
   tmp_write_to_binlog= 0;
6772
   pthread_mutex_lock(&LOCK_active_mi);
6773
   if (reset_slave(thd, active_mi))
6774
     result=1;
6775
   pthread_mutex_unlock(&LOCK_active_mi);
6776
 }
6777
#endif
6778
 if (options & REFRESH_USER_RESOURCES)
unknown's avatar
unknown committed
6779
   reset_mqh((LEX_USER *) NULL);
unknown's avatar
unknown committed
6780
 *write_to_binlog= tmp_write_to_binlog;
6781
 return result;
unknown's avatar
unknown committed
6782 6783
}

6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795
/*
  kill on thread

  SYNOPSIS
    kill_one_thread()
    thd			Thread class
    id			Thread id

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

unknown's avatar
SCRUM  
unknown committed
6796
void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
unknown's avatar
unknown committed
6797 6798 6799
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
6800 6801
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
6802 6803 6804 6805
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
6806 6807
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
6808 6809 6810
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
6811 6812
  if (tmp)
  {
6813 6814
    if ((thd->security_ctx->master_access & SUPER_ACL) ||
	!strcmp(thd->security_ctx->user, tmp->security_ctx->user))
6815
    {
unknown's avatar
SCRUM  
unknown committed
6816
      tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
6817 6818 6819 6820 6821 6822 6823
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }

unknown's avatar
unknown committed
6824
  if (!error)
6825
    send_ok(thd);
unknown's avatar
unknown committed
6826
  else
unknown's avatar
unknown committed
6827
    my_error(error, MYF(0), id);
unknown's avatar
unknown committed
6828 6829
}

unknown's avatar
unknown committed
6830

unknown's avatar
unknown committed
6831 6832 6833 6834 6835 6836 6837 6838
/* 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)
6839
      *(ulong*) ptr->value= 0;
6840 6841 6842 6843 6844 6845 6846
    else if (ptr->type == SHOW_LONG_STATUS)
    {
      THD *thd= current_thd;
      /* We must update the global status before cleaning up the thread */
      add_to_status(&global_status_var, &thd->status_var);
      bzero((char*) &thd->status_var, sizeof(thd->status_var));
    }
unknown's avatar
unknown committed
6847
  }
unknown's avatar
unknown committed
6848 6849
  /* Reset the counters of all key caches (default and named). */
  process_key_caches(reset_key_cache_counters);
unknown's avatar
unknown committed
6850 6851
  pthread_mutex_unlock(&LOCK_status);
}
unknown's avatar
unknown committed
6852 6853 6854 6855


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

unknown's avatar
unknown committed
6856 6857
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
			       const char *table_name)
unknown's avatar
unknown committed
6858
{
6859
  char buff[FN_REFLEN],*ptr, *end;
unknown's avatar
unknown committed
6860 6861 6862 6863 6864 6865 6866
  if (!*filename_ptr)
    return 0;					// nothing to do

  /* Check that the filename is not too long and it's a hard path */
  if (strlen(*filename_ptr)+strlen(table_name) >= FN_REFLEN-1 ||
      !test_if_hard_path(*filename_ptr))
  {
unknown's avatar
unknown committed
6867
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
unknown's avatar
unknown committed
6868 6869 6870 6871
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
6872
  end=convert_dirname(buff, *filename_ptr, NullS);
unknown's avatar
unknown committed
6873
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
unknown's avatar
unknown committed
6874 6875
    return 1;					// End of memory
  *filename_ptr=ptr;
6876
  strxmov(ptr,buff,table_name,NullS);
unknown's avatar
unknown committed
6877 6878
  return 0;
}
6879

6880

6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894
/*
  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;
6895 6896
  LEX *lex= thd->lex;
  if (lex->current_select != &lex->select_lex)
6897 6898
  {
    char command[80];
6899 6900
    strmake(command, lex->yylval->symbol.str,
	    min(lex->yylval->symbol.length, sizeof(command)-1));
6901
    my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
6902 6903 6904 6905
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
6906

unknown's avatar
unknown committed
6907

unknown's avatar
unknown committed
6908
Comp_creator *comp_eq_creator(bool invert)
unknown's avatar
unknown committed
6909
{
unknown's avatar
unknown committed
6910
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
unknown's avatar
unknown committed
6911 6912
}

unknown's avatar
unknown committed
6913

unknown's avatar
unknown committed
6914
Comp_creator *comp_ge_creator(bool invert)
unknown's avatar
unknown committed
6915
{
unknown's avatar
unknown committed
6916
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
unknown's avatar
unknown committed
6917 6918
}

unknown's avatar
unknown committed
6919

unknown's avatar
unknown committed
6920
Comp_creator *comp_gt_creator(bool invert)
unknown's avatar
unknown committed
6921
{
unknown's avatar
unknown committed
6922
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
unknown's avatar
unknown committed
6923 6924
}

unknown's avatar
unknown committed
6925

unknown's avatar
unknown committed
6926
Comp_creator *comp_le_creator(bool invert)
unknown's avatar
unknown committed
6927
{
unknown's avatar
unknown committed
6928
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
unknown's avatar
unknown committed
6929 6930
}

unknown's avatar
unknown committed
6931

unknown's avatar
unknown committed
6932
Comp_creator *comp_lt_creator(bool invert)
unknown's avatar
unknown committed
6933
{
unknown's avatar
unknown committed
6934
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
unknown's avatar
unknown committed
6935 6936
}

unknown's avatar
unknown committed
6937

unknown's avatar
unknown committed
6938
Comp_creator *comp_ne_creator(bool invert)
unknown's avatar
unknown committed
6939
{
unknown's avatar
unknown committed
6940
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
unknown's avatar
unknown committed
6941
}
unknown's avatar
unknown committed
6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961


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

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

  Item_allany_subselect *it=
6969
    new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all);
unknown's avatar
unknown committed
6970
  if (all)
6971
    return it->upper_item= new Item_func_not_all(it);	/* ALL */
unknown's avatar
unknown committed
6972

6973
  return it->upper_item= new Item_func_nop_all(it);      /* ANY/SOME */
unknown's avatar
unknown committed
6974
}
6975 6976


6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988
/*
  CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
  the proper arguments.  This isn't very fast but it should work for most
  cases.

  In the future ALTER TABLE will notice that only added indexes
  and create these one by one for the existing table without having to do
  a full rebuild.

  One should normally create all indexes with CREATE TABLE or ALTER TABLE.
*/

unknown's avatar
unknown committed
6989
bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
6990 6991
{
  List<create_field> fields;
6992 6993
  ALTER_INFO alter_info;
  alter_info.flags= ALTER_ADD_INDEX;
6994 6995 6996 6997 6998
  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;
6999
  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
7000
				&create_info, table_list,
7001
				fields, keys, 0, (ORDER*)0,
unknown's avatar
unknown committed
7002
				DUP_ERROR, 0, &alter_info, 1));
7003 7004 7005
}


unknown's avatar
unknown committed
7006
bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
7007 7008 7009 7010 7011 7012 7013 7014
{
  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;
7015 7016
  alter_info->clear();
  alter_info->flags= ALTER_DROP_INDEX;
7017
  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
7018
				&create_info, table_list,
7019
				fields, keys, 0, (ORDER*)0,
unknown's avatar
unknown committed
7020
				DUP_ERROR, 0, alter_info, 1));
7021
}
unknown's avatar
merge  
unknown committed
7022 7023


7024 7025 7026 7027 7028
/*
  Multi update query pre-check

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

unknown's avatar
unknown committed
7032
  RETURN VALUE
unknown's avatar
unknown committed
7033 7034
    FALSE OK
    TRUE  Error
7035
*/
unknown's avatar
unknown committed
7036

unknown's avatar
unknown committed
7037
bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
7038 7039 7040 7041 7042
{
  const char *msg= 0;
  TABLE_LIST *table;
  LEX *lex= thd->lex;
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
7043
  DBUG_ENTER("multi_update_precheck");
7044 7045 7046

  if (select_lex->item_list.elements != lex->value_list.elements)
  {
7047
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7048
    DBUG_RETURN(TRUE);
7049 7050 7051 7052 7053
  }
  /*
    Ensure that we have UPDATE or SELECT privilege for each table
    The exact privilege is checked in mysql_multi_update()
  */
unknown's avatar
VIEW  
unknown committed
7054
  for (table= tables; table; table= table->next_local)
7055
  {
7056 7057 7058
    if (table->derived)
      table->grant.privilege= SELECT_ACL;
    else if ((check_access(thd, UPDATE_ACL, table->db,
7059 7060
                           &table->grant.privilege, 0, 1,
                           test(table->schema_table)) ||
7061 7062
              grant_option &&
              check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
unknown's avatar
unknown committed
7063
             (check_access(thd, SELECT_ACL, table->db,
7064 7065
                           &table->grant.privilege, 0, 0,
                           test(table->schema_table)) ||
unknown's avatar
unknown committed
7066
              grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
unknown's avatar
unknown committed
7067
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7068

unknown's avatar
VIEW  
unknown committed
7069
    table->table_in_first_from_clause= 1;
7070
  }
unknown's avatar
unknown committed
7071 7072 7073
  /*
    Is there tables of subqueries?
  */
7074
  if (&lex->select_lex != lex->all_selects_list || lex->time_zone_tables_used)
7075
  {
7076
    DBUG_PRINT("info",("Checking sub query list"));
unknown's avatar
VIEW  
unknown committed
7077
    for (table= tables; table; table= table->next_global)
7078
    {
unknown's avatar
unknown committed
7079 7080 7081
      if (!my_tz_check_n_skip_implicit_tables(&table,
                                              lex->time_zone_tables_used) &&
          !table->table_in_first_from_clause)
7082 7083
      {
	if (check_access(thd, SELECT_ACL, table->db,
7084 7085
			 &table->grant.privilege, 0, 0,
                         test(table->schema_table)) ||
unknown's avatar
unknown committed
7086
	    grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
unknown's avatar
unknown committed
7087
	  DBUG_RETURN(TRUE);
7088 7089 7090 7091 7092 7093
      }
    }
  }

  if (select_lex->order_list.elements)
    msg= "ORDER BY";
7094
  else if (select_lex->select_limit)
7095 7096 7097 7098
    msg= "LIMIT";
  if (msg)
  {
    my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
unknown's avatar
unknown committed
7099
    DBUG_RETURN(TRUE);
7100
  }
unknown's avatar
unknown committed
7101
  DBUG_RETURN(FALSE);
7102 7103 7104 7105 7106 7107 7108
}

/*
  Multi delete query pre-check

  SYNOPSIS
    multi_delete_precheck()
unknown's avatar
unknown committed
7109
    thd			Thread handler
unknown's avatar
VIEW  
unknown committed
7110
    tables		Global/local table list
7111

unknown's avatar
unknown committed
7112
  RETURN VALUE
unknown's avatar
unknown committed
7113 7114
    FALSE OK
    TRUE  error
7115
*/
unknown's avatar
unknown committed
7116

7117
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
7118 7119 7120 7121
{
  SELECT_LEX *select_lex= &thd->lex->select_lex;
  TABLE_LIST *aux_tables=
    (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
unknown's avatar
VIEW  
unknown committed
7122
  DBUG_ENTER("multi_delete_precheck");
unknown's avatar
unknown committed
7123

7124 7125 7126 7127 7128
  /* sql_yacc guarantees that tables and aux_tables are not zero */
  DBUG_ASSERT(aux_tables != 0);
  if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
      check_table_access(thd,SELECT_ACL, tables,0) ||
      check_table_access(thd,DELETE_ACL, aux_tables,0))
unknown's avatar
unknown committed
7129
    DBUG_RETURN(TRUE);
7130 7131
  if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
  {
unknown's avatar
unknown committed
7132 7133
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
7134
    DBUG_RETURN(TRUE);
7135
  }
7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162
  DBUG_RETURN(FALSE);
}


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

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

  RETURN VALUE
    FALSE - success
    TRUE  - error
*/

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

  lex->table_count= 0;

  for (target_tbl= (TABLE_LIST *)lex->auxilliary_table_list.first;
       target_tbl; target_tbl= target_tbl->next_local)
7163
  {
7164
    lex->table_count++;
7165 7166
    /* All tables in aux_tables must be found in FROM PART */
    TABLE_LIST *walk;
unknown's avatar
VIEW  
unknown committed
7167
    for (walk= tables; walk; walk= walk->next_local)
7168
    {
unknown's avatar
unknown committed
7169 7170 7171
      if (!my_strcasecmp(table_alias_charset,
			 target_tbl->alias, walk->alias) &&
	  !strcmp(walk->db, target_tbl->db))
7172 7173 7174 7175
	break;
    }
    if (!walk)
    {
7176
      my_error(ER_UNKNOWN_TABLE, MYF(0),
7177
               target_tbl->table_name, "MULTI DELETE");
unknown's avatar
unknown committed
7178
      DBUG_RETURN(TRUE);
7179
    }
unknown's avatar
unknown committed
7180 7181 7182 7183 7184
    if (!walk->derived)
    {
      target_tbl->table_name= walk->table_name;
      target_tbl->table_name_length= walk->table_name_length;
    }
unknown's avatar
merged  
unknown committed
7185
    walk->updating= target_tbl->updating;
unknown's avatar
unknown committed
7186
    walk->lock_type= target_tbl->lock_type;
unknown's avatar
VIEW  
unknown committed
7187
    target_tbl->correspondent_table= walk;	// Remember corresponding table
7188
  }
unknown's avatar
unknown committed
7189
  DBUG_RETURN(FALSE);
7190 7191 7192
}


unknown's avatar
unknown committed
7193 7194 7195 7196 7197
/*
  simple UPDATE query pre-check

  SYNOPSIS
    update_precheck()
unknown's avatar
unknown committed
7198 7199
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
7200 7201

  RETURN VALUE
unknown's avatar
unknown committed
7202 7203
    FALSE OK
    TRUE  Error
unknown's avatar
unknown committed
7204
*/
unknown's avatar
unknown committed
7205

unknown's avatar
unknown committed
7206
bool update_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7207 7208 7209 7210
{
  DBUG_ENTER("update_precheck");
  if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
  {
unknown's avatar
unknown committed
7211
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7212
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7213
  }
unknown's avatar
unknown committed
7214 7215
  DBUG_RETURN(check_db_used(thd, tables) ||
	       check_one_table_access(thd, UPDATE_ACL, tables));
unknown's avatar
unknown committed
7216 7217 7218 7219 7220 7221 7222 7223
}


/*
  simple DELETE query pre-check

  SYNOPSIS
    delete_precheck()
unknown's avatar
unknown committed
7224 7225
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
7226 7227

  RETURN VALUE
unknown's avatar
unknown committed
7228 7229
    FALSE  OK
    TRUE   error
unknown's avatar
unknown committed
7230
*/
unknown's avatar
unknown committed
7231

unknown's avatar
unknown committed
7232
bool delete_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7233 7234 7235
{
  DBUG_ENTER("delete_precheck");
  if (check_one_table_access(thd, DELETE_ACL, tables))
unknown's avatar
unknown committed
7236
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7237
  /* Set privilege for the WHERE clause */
unknown's avatar
unknown committed
7238
  tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
7239
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
7240 7241 7242 7243 7244 7245 7246 7247
}


/*
  simple INSERT query pre-check

  SYNOPSIS
    insert_precheck()
unknown's avatar
unknown committed
7248 7249
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
7250 7251

  RETURN VALUE
unknown's avatar
unknown committed
7252 7253
    FALSE  OK
    TRUE   error
unknown's avatar
unknown committed
7254
*/
unknown's avatar
unknown committed
7255

unknown's avatar
merge  
unknown committed
7256
bool insert_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7257 7258 7259 7260
{
  LEX *lex= thd->lex;
  DBUG_ENTER("insert_precheck");

unknown's avatar
unknown committed
7261 7262 7263 7264
  /*
    Check that we have modify privileges for the first table and
    select privileges for the rest
  */
unknown's avatar
unknown committed
7265 7266 7267
  ulong privilege= (INSERT_ACL |
                    (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
                    (lex->value_list.elements ? UPDATE_ACL : 0));
unknown's avatar
unknown committed
7268 7269

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

unknown's avatar
unknown committed
7272
  if (lex->update_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
7273
  {
unknown's avatar
unknown committed
7274
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7275
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7276
  }
unknown's avatar
unknown committed
7277
  DBUG_RETURN(FALSE);
7278
}
unknown's avatar
unknown committed
7279 7280 7281 7282 7283 7284 7285


/*
  CREATE TABLE query pre-check

  SYNOPSIS
    create_table_precheck()
unknown's avatar
unknown committed
7286 7287 7288
    thd			Thread handler
    tables		Global table list
    create_table	Table which will be created
unknown's avatar
unknown committed
7289 7290

  RETURN VALUE
unknown's avatar
unknown committed
7291 7292
    FALSE   OK
    TRUE   Error
unknown's avatar
unknown committed
7293
*/
unknown's avatar
unknown committed
7294

unknown's avatar
unknown committed
7295 7296
bool create_table_precheck(THD *thd, TABLE_LIST *tables,
                           TABLE_LIST *create_table)
unknown's avatar
unknown committed
7297 7298
{
  LEX *lex= thd->lex;
7299 7300
  SELECT_LEX *select_lex= &lex->select_lex;
  ulong want_priv;
unknown's avatar
merge  
unknown committed
7301
  bool error= TRUE;                                 // Error message is given
unknown's avatar
unknown committed
7302
  DBUG_ENTER("create_table_precheck");
7303 7304 7305

  want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
              CREATE_TMP_ACL : CREATE_ACL);
unknown's avatar
unknown committed
7306 7307
  lex->create_info.alias= create_table->alias;
  if (check_access(thd, want_priv, create_table->db,
7308 7309
		   &create_table->grant.privilege, 0, 0,
                   test(create_table->schema_table)) ||
unknown's avatar
unknown committed
7310 7311 7312
      check_merge_table_access(thd, create_table->db,
			       (TABLE_LIST *)
			       lex->create_info.merge_list.first))
7313 7314 7315 7316 7317 7318 7319 7320 7321
    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 */

7322 7323
#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
    /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
7324
    /*
unknown's avatar
unknown committed
7325 7326 7327
      Only do the check for PS, becasue we on execute we have to check that
      against the opened tables to ensure we don't use a table that is part
      of the view (which can only be done after the table has been opened).
7328
    */
unknown's avatar
Rename:  
unknown committed
7329
    if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
7330
    {
unknown's avatar
unknown committed
7331 7332 7333 7334
      /*
        For temporary tables we don't have to check if the created table exists
      */
      if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
unknown's avatar
unknown committed
7335
          find_table_in_global_list(tables, create_table->db,
7336
                                    create_table->table_name))
unknown's avatar
unknown committed
7337
      {
7338
	error= FALSE;
unknown's avatar
unknown committed
7339 7340 7341
        goto err;
      }
    }
7342
#endif
7343 7344 7345
    if (tables && check_table_access(thd, SELECT_ACL, tables,0))
      goto err;
  }
unknown's avatar
merge  
unknown committed
7346
  error= FALSE;
7347 7348 7349

err:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
7350
}
unknown's avatar
unknown committed
7351 7352 7353 7354 7355 7356 7357


/*
  negate given expression

  SYNOPSIS
    negate_expression()
7358
    thd  thread handler
unknown's avatar
unknown committed
7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386
    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);
}
7387 7388 7389 7390 7391 7392 7393


/*
  Assign as view definer current user

  SYNOPSIS
    default_definer()
7394
    Secytity_context     current decurity context
7395 7396 7397 7398 7399 7400 7401
    definer              structure where it should be assigned

  RETURN
    FALSE   OK
    TRUE    Error
*/

7402
bool default_view_definer(Security_context *sctx, st_lex_user *definer)
7403
{
7404 7405 7406
  definer->user.str= sctx->priv_user;
  definer->user.length= strlen(sctx->priv_user);
  if (*sctx->priv_host != 0)
7407
  {
7408 7409
    definer->host.str= sctx->priv_host;
    definer->host.length= strlen(sctx->priv_host);
7410 7411 7412 7413 7414 7415 7416 7417
  }
  else
  {
    my_error(ER_NO_VIEW_USER, MYF(0));
    return TRUE;
  }
  return FALSE;
}