sql_parse.cc 143 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 18
   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"
#include "sql_acl.h"
19
#include "sql_repl.h"
20
#include "repl_failsafe.h"
unknown's avatar
unknown committed
21 22 23 24
#include <m_ctype.h>
#include <myisam.h>
#include <my_dir.h>

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

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

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

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

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

63
static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
64
static void decrease_user_connections(USER_CONN *uc);
unknown's avatar
unknown committed
65
static bool check_db_used(THD *thd,TABLE_LIST *tables);
66
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
unknown's avatar
SCRUM:  
unknown committed
67 68
static bool single_table_command_access(THD *thd, ulong privilege,
					TABLE_LIST *tables, int *res);
unknown's avatar
unknown committed
69 70
static void remove_escape(char *name);
static void refresh_status(void);
unknown's avatar
unknown committed
71 72
static bool append_file_to_dir(THD *thd, char **filename_ptr,
			       char *table_name);
unknown's avatar
unknown committed
73

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

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

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

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

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

static bool end_active_trans(THD *thd)
117
{
unknown's avatar
unknown committed
118
  int error=0;
unknown's avatar
unknown committed
119
  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
unknown's avatar
unknown committed
120
		      OPTION_TABLE_LOCK))
121
  {
122 123
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
124
    if (ha_commit(thd))
unknown's avatar
unknown committed
125
      error=1;
126
  }
unknown's avatar
unknown committed
127
  return error;
128 129 130
}


unknown's avatar
unknown committed
131 132
static HASH hash_user_connections;

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

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

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

unknown's avatar
unknown committed
185
}
unknown's avatar
unknown committed
186 187 188


/*
189
    Check if user exist and password supplied is correct. 
190 191
  SYNOPSIS
    check_user()
192 193 194 195 196 197 198 199 200
    thd          thread handle, thd->{host,user,ip} are used
    command      originator of the check: now check_user is called
                 during connect and change user procedures; used for 
                 logging.
    passwd       scrambled password recieved from client
    passwd_len   length of scrambled password
    db           database name to connect to, may be NULL
    check_count  dont know exactly

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

206 207 208
  RETURN VALUE
    0  OK; thd->user, thd->master_access, thd->priv_user, thd->db and
       thd->db_access are updated; OK is sent to client;
unknown's avatar
unknown committed
209 210
   -1  access denied or handshake error; error is sent to client;
   >0  error, not sent to client
unknown's avatar
unknown committed
211 212
*/

unknown's avatar
SCRUM:  
unknown committed
213 214 215
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
216
{
217
  DBUG_ENTER("check_user");
unknown's avatar
unknown committed
218
  
unknown's avatar
unknown committed
219 220 221 222 223
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  thd->master_access= GLOBAL_ACLS;			// Full rights
  return 0;
#else

224 225 226 227 228
  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);
  
229
  /*
230 231
    If the server is running in secure auth mode, short scrambles are 
    forbidden.
232
  */
233
  if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
unknown's avatar
unknown committed
234
  {
235 236 237
    net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
    mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
238
  }
unknown's avatar
unknown committed
239 240 241 242
  if (passwd_len != 0 &&
      passwd_len != SCRAMBLE_LENGTH &&
      passwd_len != SCRAMBLE_LENGTH_323)
    DBUG_RETURN(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
243

244
  /*
245 246 247 248
    Clear thd->db as it points to something, that will be freed when 
    connection is closed. We don't want to accidently free a wrong pointer
    if connect failed. Also in case of 'CHANGE USER' failure, current
    database will be switched to 'no database selected'.
249
  */
250 251
  thd->db= 0;
  thd->db_length= 0;
unknown's avatar
unknown committed
252
  
253
  USER_RESOURCES ur;
254
  int res= acl_getroot(thd, &ur, passwd, passwd_len);
unknown's avatar
SCRUM:  
unknown committed
255
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
256
  if (res == -1)
unknown's avatar
unknown committed
257
  {
unknown's avatar
unknown committed
258 259 260 261 262 263
    /*
      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.
    */
264
    NET *net= &thd->net;
265
    if (opt_secure_auth_local)
266
    {
267 268 269 270 271 272
      net_printf(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
                 thd->user, thd->host_or_ip);
      mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
                      thd->user, thd->host_or_ip);
      DBUG_RETURN(-1);
    }
273
    if (send_old_password_request(thd) ||
unknown's avatar
unknown committed
274 275 276 277 278 279 280
        my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very
    {                                                // specific packet size
      inc_host_errors(&thd->remote.sin_addr);
      DBUG_RETURN(ER_HANDSHAKE_ERROR);
    }
    /* Final attempt to check the user based on reply */
    /* So as passwd is short, errcode is always >= 0 */
281
    res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
unknown's avatar
unknown committed
282
  }
unknown's avatar
SCRUM:  
unknown committed
283
#endif /*EMBEDDED_LIBRARY*/
unknown's avatar
unknown committed
284 285
  /* here res is always >= 0 */
  if (res == 0)
unknown's avatar
unknown committed
286
  {
unknown's avatar
unknown committed
287
    if (!(thd->master_access & NO_ACCESS)) // authentification is OK 
288
    {
unknown's avatar
unknown committed
289 290 291 292 293 294 295 296 297 298
      DBUG_PRINT("info",
                 ("Capabilities: %d  packet_length: %ld  Host: '%s'  "
                  "Login user: '%s' Priv_user: '%s'  Using password: %s "
                  "Access: %u  db: '%s'",
                  thd->client_capabilities, thd->max_client_packet_length,
                  thd->host_or_ip, thd->user, thd->priv_user,
                  passwd_len ? "yes": "no",
                  thd->master_access, thd->db ? thd->db : "*none*"));

      if (check_count)
299
      {
unknown's avatar
unknown committed
300 301
        VOID(pthread_mutex_lock(&LOCK_thread_count));
        bool count_ok= thread_count < max_connections + delayed_insert_threads
302
                       || (thd->master_access & SUPER_ACL);
unknown's avatar
unknown committed
303 304 305 306 307 308
        VOID(pthread_mutex_unlock(&LOCK_thread_count));
        if (!count_ok)
        {                                         // too many connections 
          send_error(thd, ER_CON_COUNT_ERROR);
          DBUG_RETURN(-1);
        }
309
      }
unknown's avatar
unknown committed
310

unknown's avatar
unknown committed
311 312 313 314 315 316 317 318
      /* Why logging is performed before all checks've passed? */
      mysql_log.write(thd,command,
                      (thd->priv_user == thd->user ?
                       (char*) "%s@%s on %s" :
                       (char*) "%s@%s as anonymous on %s"),
                      thd->user, thd->host_or_ip,
                      db ? db : (char*) "");

319
      /*
320 321 322
        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.
323
      */
unknown's avatar
unknown committed
324 325 326
      thd->db_access=0;

      /* Don't allow user to connect if he has done too many queries */
unknown's avatar
unknown committed
327 328 329 330 331 332 333 334 335
      if ((ur.questions || ur.updates || ur.connections ||
	   max_user_connections) &&
	  get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur))
	DBUG_RETURN(-1);
      if (thd->user_connect &&
	  (thd->user_connect->user_resources.connections ||
	   max_user_connections) &&
	  check_for_max_user_connections(thd, thd->user_connect))
	DBUG_RETURN(-1);
unknown's avatar
unknown committed
336 337 338

      /* Change database if necessary: OK or FAIL is sent in mysql_change_db */
      if (db && db[0])
339
      {
unknown's avatar
unknown committed
340 341 342 343 344 345
        if (mysql_change_db(thd, db))
        {
          if (thd->user_connect)
            decrease_user_connections(thd->user_connect);
          DBUG_RETURN(-1);
        }
346 347
      }
      else
unknown's avatar
unknown committed
348
	send_ok(thd);
unknown's avatar
unknown committed
349 350 351
      thd->password= test(passwd_len);          // remember for error messages 
      /* Ready to handle queries */
      DBUG_RETURN(0);
unknown's avatar
unknown committed
352 353
    }
  }
unknown's avatar
unknown committed
354
  else if (res == 2) // client gave short hash, server has long hash
unknown's avatar
unknown committed
355
  {
unknown's avatar
unknown committed
356 357 358
    net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
    mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
359
  }
unknown's avatar
unknown committed
360 361 362 363 364 365 366 367 368
  net_printf(thd, ER_ACCESS_DENIED_ERROR,
             thd->user,
             thd->host_or_ip,
             passwd_len ? ER(ER_YES) : ER(ER_NO));
  mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
                  thd->user,
                  thd->host_or_ip,
                  passwd_len ? ER(ER_YES) : ER(ER_NO));
  DBUG_RETURN(-1);
unknown's avatar
unknown committed
369
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
370 371
}

unknown's avatar
unknown committed
372
/*
unknown's avatar
unknown committed
373 374
  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
375 376
*/

377 378
extern "C" byte *get_key_conn(user_conn *buff, uint *length,
			      my_bool not_used __attribute__((unused)))
unknown's avatar
unknown committed
379 380 381 382 383
{
  *length=buff->len;
  return (byte*) buff->user;
}

384
extern "C" void free_user(struct user_conn *uc)
unknown's avatar
unknown committed
385 386 387 388
{
  my_free((char*) uc,MYF(0));
}

unknown's avatar
unknown committed
389
void init_max_user_conn(void)
unknown's avatar
unknown committed
390
{
unknown's avatar
unknown committed
391 392
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
		   0,0,
393
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
394
		   0);
unknown's avatar
unknown committed
395 396 397
}


unknown's avatar
unknown committed
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
/*
  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
*/

415
static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
unknown's avatar
unknown committed
416
{
unknown's avatar
unknown committed
417
  int error=0;
418
  DBUG_ENTER("check_for_max_user_connections");
unknown's avatar
unknown committed
419

420
  (void) pthread_mutex_lock(&LOCK_user_conn);
421
  if (max_user_connections &&
unknown's avatar
unknown committed
422
      max_user_connections < (uint) uc->connections)
unknown's avatar
unknown committed
423
  {
424
    net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user);
unknown's avatar
unknown committed
425 426
    error=1;
    goto end;
unknown's avatar
unknown committed
427
  }
428
  if (uc->user_resources.connections &&
429
      uc->user_resources.connections <= uc->conn_per_hour)
430
  {
431
    net_printf(thd, ER_USER_LIMIT_REACHED, uc->user,
432
	       "max_connections",
433 434 435 436
	       (long) uc->user_resources.connections);
    error=1;
    goto end;
  }
437
  uc->conn_per_hour++;
unknown's avatar
unknown committed
438 439

  end:
440 441
  if (error)
    uc->connections--; // no need for decrease_user_connections() here
442
  (void) pthread_mutex_unlock(&LOCK_user_conn);
443
  DBUG_RETURN(error);
unknown's avatar
unknown committed
444 445 446
}


unknown's avatar
unknown committed
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
/*
  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.
*/

465
static void decrease_user_connections(USER_CONN *uc)
unknown's avatar
unknown committed
466
{
unknown's avatar
unknown committed
467
  DBUG_ENTER("decrease_user_connections");
468 469 470
  (void) pthread_mutex_lock(&LOCK_user_conn);
  DBUG_ASSERT(uc->connections);
  if (!--uc->connections && !mqh_used)
unknown's avatar
unknown committed
471 472
  {
    /* Last connection for user; Delete it */
unknown's avatar
unknown committed
473
    (void) hash_delete(&hash_user_connections,(byte*) uc);
unknown's avatar
unknown committed
474
  }
475
  (void) pthread_mutex_unlock(&LOCK_user_conn);
476
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
477 478
}

479

unknown's avatar
unknown committed
480 481 482 483 484
void free_max_user_conn(void)
{
  hash_free(&hash_user_connections);
}

unknown's avatar
unknown committed
485

486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
/*
  Mark all commands that somehow changes a table
  This is used to check number of updates / hour
*/

char  uc_update_queries[SQLCOM_END];

void init_update_queries(void)
{
  uc_update_queries[SQLCOM_CREATE_TABLE]=1;
  uc_update_queries[SQLCOM_CREATE_INDEX]=1;
  uc_update_queries[SQLCOM_ALTER_TABLE]=1;
  uc_update_queries[SQLCOM_UPDATE]=1;
  uc_update_queries[SQLCOM_INSERT]=1;
  uc_update_queries[SQLCOM_INSERT_SELECT]=1;
  uc_update_queries[SQLCOM_DELETE]=1;
  uc_update_queries[SQLCOM_TRUNCATE]=1;
  uc_update_queries[SQLCOM_DROP_TABLE]=1;
  uc_update_queries[SQLCOM_LOAD]=1;
  uc_update_queries[SQLCOM_CREATE_DB]=1;
  uc_update_queries[SQLCOM_DROP_DB]=1;
  uc_update_queries[SQLCOM_REPLACE]=1;
  uc_update_queries[SQLCOM_REPLACE_SELECT]=1;
  uc_update_queries[SQLCOM_RENAME_TABLE]=1;
  uc_update_queries[SQLCOM_BACKUP_TABLE]=1;
  uc_update_queries[SQLCOM_RESTORE_TABLE]=1;
  uc_update_queries[SQLCOM_DELETE_MULTI]=1;
  uc_update_queries[SQLCOM_DROP_INDEX]=1;
514
  uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
515 516
}

unknown's avatar
unknown committed
517 518 519 520
bool is_update_query(enum enum_sql_command command)
{
  return uc_update_queries[command];
}
521

unknown's avatar
unknown committed
522 523 524
/*
  Check if maximum queries per hour limit has been reached
  returns 0 if OK.
unknown's avatar
unknown committed
525

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

531

532
static bool check_mqh(THD *thd, uint check_command)
unknown's avatar
unknown committed
533 534
{
  bool error=0;
unknown's avatar
unknown committed
535
  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
536
  USER_CONN *uc=thd->user_connect;
unknown's avatar
unknown committed
537
  DBUG_ENTER("check_mqh");
unknown's avatar
unknown committed
538
  DBUG_ASSERT(uc != 0);
unknown's avatar
unknown committed
539

unknown's avatar
unknown committed
540 541 542
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  DBUG_RETURN(0);
#else
unknown's avatar
unknown committed
543
  /* If more than a hour since last check, reset resource checking */
544 545 546 547 548 549 550 551 552
  if (check_time  - uc->intime >= 3600)
  {
    (void) pthread_mutex_lock(&LOCK_user_conn);
    uc->questions=1;
    uc->updates=0;
    uc->conn_per_hour=0;
    uc->intime=check_time;
    (void) pthread_mutex_unlock(&LOCK_user_conn);
  }
unknown's avatar
unknown committed
553
  /* Check that we have not done too many questions / hour */
554 555 556
  if (uc->user_resources.questions &&
      uc->questions++ >= uc->user_resources.questions)
  {
557
    net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
558 559 560 561
	       (long) uc->user_resources.questions);
    error=1;
    goto end;
  }
562
  if (check_command < (uint) SQLCOM_END)
unknown's avatar
unknown committed
563
  {
unknown's avatar
unknown committed
564 565 566 567
    /* 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)
    {
568
      net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
unknown's avatar
unknown committed
569 570 571 572
		 (long) uc->user_resources.updates);
      error=1;
      goto end;
    }
unknown's avatar
unknown committed
573 574
  }
end:
unknown's avatar
unknown committed
575
  DBUG_RETURN(error);
unknown's avatar
unknown committed
576
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
577 578
}

unknown's avatar
unknown committed
579

unknown's avatar
unknown committed
580
static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
unknown's avatar
unknown committed
581
{
unknown's avatar
unknown committed
582
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
583
  (void) pthread_mutex_lock(&LOCK_user_conn);
unknown's avatar
unknown committed
584
  if (lu)  // for GRANT
unknown's avatar
unknown committed
585
  {
586
    USER_CONN *uc;
587
    uint temp_len=lu->user.length+lu->host.length+2;
unknown's avatar
unknown committed
588 589
    char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];

unknown's avatar
unknown committed
590 591
    memcpy(temp_user,lu->user.str,lu->user.length);
    memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
592
    temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
unknown's avatar
unknown committed
593
    if ((uc = (struct  user_conn *) hash_search(&hash_user_connections,
594
						(byte*) temp_user, temp_len)))
unknown's avatar
unknown committed
595 596
    {
      uc->questions=0;
597
      get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
598 599
      uc->updates=0;
      uc->conn_per_hour=0;
unknown's avatar
unknown committed
600 601
    }
  }
602
  else // for FLUSH PRIVILEGES and FLUSH USER_RESOURCES
unknown's avatar
unknown committed
603
  {
unknown's avatar
unknown committed
604
    for (uint idx=0;idx < hash_user_connections.records; idx++)
unknown's avatar
unknown committed
605
    {
unknown's avatar
unknown committed
606 607
      USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
						      idx);
608 609 610 611 612
      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
613 614
    }
  }
unknown's avatar
unknown committed
615
  (void) pthread_mutex_unlock(&LOCK_user_conn);
unknown's avatar
unknown committed
616
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
617
}
unknown's avatar
unknown committed
618

unknown's avatar
unknown committed
619
/*
620
    Perform handshake, authorize client and update thd ACL variables.
621
  SYNOPSIS
622
    check_connection()
623
    thd  thread handle
624 625

  RETURN
626
     0  success, OK is sent to user, thd is updated.
627 628
    -1  error, which is sent to user
   > 0  error code (not sent to user)
unknown's avatar
unknown committed
629 630
*/

unknown's avatar
SCRUM:  
unknown committed
631 632
#ifndef EMBEDDED_LIBRARY
static int check_connection(THD *thd)
unknown's avatar
unknown committed
633
{
634
  uint connect_errors= 0;
unknown's avatar
unknown committed
635
  NET *net= &thd->net;
636

637 638 639
  DBUG_PRINT("info",
             ("New connection received on %s", vio_description(net->vio)));

unknown's avatar
unknown committed
640 641
  if (!thd->host)                           // If TCP/IP connection
  {
642
    char ip[30];
643

644
    if (vio_peer_addr(net->vio, ip, &thd->peer_port))
unknown's avatar
unknown committed
645
      return (ER_BAD_HOST_ERROR);
646
    if (!(thd->ip= my_strdup(ip,MYF(0))))
unknown's avatar
unknown committed
647
      return (ER_OUT_OF_RESOURCES);
648
    thd->host_or_ip= thd->ip;
unknown's avatar
unknown committed
649 650 651
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
    /* Fast local hostname resolve for Win32 */
    if (!strcmp(thd->ip,"127.0.0.1"))
unknown's avatar
unknown committed
652
    {
unknown's avatar
SCRUM:  
unknown committed
653 654
      thd->host= (char*) my_localhost;
      thd->host_or_ip= my_localhost;
unknown's avatar
unknown committed
655
    }
unknown's avatar
unknown committed
656 657 658
    else
#endif
    {
659 660 661 662 663 664
      if (!(specialflag & SPECIAL_NO_RESOLVE))
      {
	vio_in_addr(net->vio,&thd->remote.sin_addr);
	thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
	/* Cut very long hostnames to avoid possible overflows */
	if (thd->host)
unknown's avatar
unknown committed
665
	{
666
	  thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
unknown's avatar
unknown committed
667 668
	  thd->host_or_ip= thd->host;
	}
669 670 671
	if (connect_errors > max_connect_errors)
	  return(ER_HOST_IS_BLOCKED);
      }
unknown's avatar
unknown committed
672
    }
unknown's avatar
unknown committed
673 674 675
    DBUG_PRINT("info",("Host: %s  ip: %s",
		       thd->host ? thd->host : "unknown host",
		       thd->ip ? thd->ip : "unknown ip"));
unknown's avatar
unknown committed
676 677 678
    if (acl_check_host(thd->host,thd->ip))
      return(ER_HOST_NOT_PRIVILEGED);
  }
679
  else /* Hostname given means that the connection was on a socket */
unknown's avatar
unknown committed
680
  {
unknown's avatar
unknown committed
681
    DBUG_PRINT("info",("Host: %s",thd->host));
682 683
    thd->host_or_ip= thd->host;
    thd->ip= 0;
684
    bzero((char*) &thd->remote, sizeof(struct sockaddr));
unknown's avatar
unknown committed
685 686
  }
  vio_keepalive(net->vio, TRUE);
687 688
  ulong pkt_len= 0;
  char *end;
unknown's avatar
unknown committed
689
  {
unknown's avatar
unknown committed
690
    /* buff[] needs to big enough to hold the server_version variable */
691
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
692 693
    ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
			  CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
unknown's avatar
unknown committed
694

695 696 697 698 699
    if (opt_using_transactions)
      client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
    client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
unknown's avatar
unknown committed
700 701 702 703
#ifdef HAVE_OPENSSL
    if (ssl_acceptor_fd)
      client_flags |= CLIENT_SSL;       /* Wow, SSL is avalaible! */
#endif /* HAVE_OPENSSL */
unknown's avatar
unknown committed
704

705 706 707 708 709 710 711 712 713 714 715
    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
716
      tail: that's why first part of the scramble is placed here, and second
717 718
      part at the end of packet.
    */
719
    end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
720 721 722
   
    int2store(end, client_flags);
    /* write server characteristics: up to 16 bytes allowed */
723
    end[2]=(char) default_charset_info->number;
724 725 726 727 728 729 730 731 732
    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
733
			  (uint) (end-buff)) ||
734
	(pkt_len= my_net_read(net)) == packet_error ||
unknown's avatar
unknown committed
735 736 737 738 739 740 741 742 743 744 745
	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
746
  if (thd->packet.alloc(thd->variables.net_buffer_length))
unknown's avatar
unknown committed
747 748 749
    return(ER_OUT_OF_RESOURCES);

  thd->client_capabilities=uint2korr(net->read_pos);
750 751 752 753 754 755 756 757 758 759 760
#ifdef TO_BE_REMOVED_IN_4_1_RELEASE
  /*
    This is just a safety check against any client that would use the old
    CLIENT_CHANGE_USER flag
  */
  if ((thd->client_capabilities & CLIENT_PROTOCOL_41) &&
      !(thd->client_capabilities & (CLIENT_RESERVED |
				    CLIENT_SECURE_CONNECTION |
				    CLIENT_MULTI_RESULTS)))
    thd->client_capabilities&= ~CLIENT_PROTOCOL_41;
#endif
761 762 763 764
  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
765 766 767 768 769 770 771
    DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
    /*
      Use server character set and collation if
      - client has not specified a character set
      - client character set is the same as the servers
      - client character set doesn't exists in server
    */
772
    if (!(thd->variables.character_set_client=
unknown's avatar
unknown committed
773 774 775 776
	  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))
777
    {
778 779
      thd->variables.character_set_client=
	global_system_variables.character_set_client;
780 781
      thd->variables.collation_connection=
	global_system_variables.collation_connection;
782 783
      thd->variables.character_set_results=
	global_system_variables.character_set_results;
784 785 786
    }
    else
    {
787
      thd->variables.character_set_results=
788 789 790
      thd->variables.collation_connection= 
	thd->variables.character_set_client;
    }
unknown's avatar
unknown committed
791
    thd->update_charset();
792
    end= (char*) net->read_pos+32;
793 794 795 796 797 798 799
  }
  else
  {
    thd->max_client_packet_length= uint3korr(net->read_pos+2);
    end= (char*) net->read_pos+5;
  }

800
  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
801
    thd->variables.sql_mode|= MODE_IGNORE_SPACE;
unknown's avatar
unknown committed
802
#ifdef HAVE_OPENSSL
unknown's avatar
unknown committed
803
  DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
unknown's avatar
unknown committed
804 805 806
  if (thd->client_capabilities & CLIENT_SSL)
  {
    /* Do the SSL layering. */
807 808 809 810 811
    if (!ssl_acceptor_fd)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
unknown's avatar
unknown committed
812
    DBUG_PRINT("info", ("IO layer change in progress..."));
unknown's avatar
unknown committed
813 814 815 816 817
    if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
    {
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
      inc_host_errors(&thd->remote.sin_addr);
unknown's avatar
unknown committed
818
      return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
819
    }
unknown's avatar
unknown committed
820
    DBUG_PRINT("info", ("Reading user information over SSL layer"));
821
    if ((pkt_len= my_net_read(net)) == packet_error ||
unknown's avatar
unknown committed
822 823
	pkt_len < NORMAL_HANDSHAKE_SIZE)
    {
unknown's avatar
unknown committed
824 825
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
unknown's avatar
unknown committed
826 827 828 829
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
  }
830 831 832
#endif

  if (end >= (char*) net->read_pos+ pkt_len +2)
unknown's avatar
unknown committed
833
  {
834 835
    inc_host_errors(&thd->remote.sin_addr);
    return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
836 837 838
  }

  if (thd->client_capabilities & CLIENT_INTERACTIVE)
839
    thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
840
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
841 842
      opt_using_transactions)
    net->return_status= &thd->server_status;
unknown's avatar
unknown committed
843
  net->read_timeout=(uint) thd->variables.net_read_timeout;
unknown's avatar
unknown committed
844

845 846
  char *user= end;
  char *passwd= strend(user)+1;
unknown's avatar
unknown committed
847
  char *db= passwd;
848
  char db_buff[NAME_LEN+1];                     // buffer to store db in utf8 
unknown's avatar
unknown committed
849 850 851 852 853 854 855 856 857
  /* 
    Old clients send null-terminated string as password; new clients send
    the size (1 byte) + string (not null-terminated). Hence in case of empty
    password both send '\0'.
  */
  uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? 
    *passwd++ : strlen(passwd);
  db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
    db + passwd_len + 1 : 0;
unknown's avatar
unknown committed
858

unknown's avatar
unknown committed
859 860
  /* Since 4.1 all database names are stored in utf8 */
  if (db)
unknown's avatar
unknown committed
861
  {
unknown's avatar
unknown committed
862 863 864 865
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
                             system_charset_info,
                             db, strlen(db),
                             thd->charset())]= 0;
866
    db= db_buff;
unknown's avatar
unknown committed
867
  }
unknown's avatar
unknown committed
868

869 870
  if (thd->user)
    x_free(thd->user);
871 872
  if (!(thd->user= my_strdup(user, MYF(0))))
    return (ER_OUT_OF_RESOURCES);
unknown's avatar
unknown committed
873
  return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true);
unknown's avatar
unknown committed
874 875
}

876

877 878
void execute_init_command(THD *thd, sys_var_str *init_command_var,
			  rw_lock_t *var_mutex)
unknown's avatar
SCRUM:  
unknown committed
879 880 881 882
{
  Vio* save_vio;
  ulong save_client_capabilities;

883 884 885 886 887 888 889 890 891
  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
892 893
  save_client_capabilities= thd->client_capabilities;
  thd->client_capabilities|= CLIENT_MULTI_QUERIES;
894 895 896 897
  /*
    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
898 899 900
  save_vio= thd->net.vio;
  thd->net.vio= 0;
  dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
901
  rw_unlock(var_mutex);
unknown's avatar
SCRUM:  
unknown committed
902 903 904 905 906
  thd->client_capabilities= save_client_capabilities;
  thd->net.vio= save_vio;
}


unknown's avatar
unknown committed
907 908 909 910
pthread_handler_decl(handle_one_connection,arg)
{
  THD *thd=(THD*) arg;
  uint launch_time  =
unknown's avatar
unknown committed
911
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
unknown's avatar
unknown committed
912 913 914 915 916
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status );

  pthread_detach_this_thread();

917 918
#if !defined( __WIN__) && !defined(OS2)	// Win32 calls this in pthread_create
  // The following calls needs to be done before we call DBUG_ macros
919
  if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
unknown's avatar
unknown committed
920
  {
921
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
922
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
923 924 925 926 927
    end_thread(thd,0);
    return 0;
  }
#endif

928 929 930 931 932 933 934
  /*
    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
935 936 937 938
  DBUG_PRINT("info", ("handle_one_connection called by thread %d\n",
		      thd->thread_id));
  // now that we've called my_thread_init(), it is safe to call DBUG_*

unknown's avatar
unknown committed
939
#if defined(__WIN__)
unknown's avatar
unknown committed
940
  init_signals();				// IRENA; testing ?
unknown's avatar
unknown committed
941
#elif !defined(OS2) && !defined(__NETWARE__)
unknown's avatar
unknown committed
942 943 944 945 946 947
  sigset_t set;
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
  if (thd->store_globals())
  {
948
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
949
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
950 951 952 953 954 955 956 957 958 959
    end_thread(thd,0);
    return 0;
  }

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

960
    if ((error=check_connection(thd)))
unknown's avatar
unknown committed
961 962
    {						// Wrong permissions
      if (error > 0)
963
	net_printf(thd,error,thd->host_or_ip);
unknown's avatar
unknown committed
964 965
#ifdef __NT__
      if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
966
	my_sleep(1000);				/* must wait after eof() */
unknown's avatar
unknown committed
967
#endif
968
      statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
969 970
      goto end_thread;
    }
unknown's avatar
unknown committed
971 972 973
#ifdef __NETWARE__
    netware_reg_user(thd->ip, thd->user, "MySQL");
#endif
974
    if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
975 976 977 978
      thd->options |= OPTION_BIG_SELECTS;
    if (thd->client_capabilities & CLIENT_COMPRESS)
      net->compress=1;				// Use compression

unknown's avatar
SCRUM:  
unknown committed
979 980 981
    thd->version= refresh_version;
    if (sys_init_connect.value && !(thd->master_access & SUPER_ACL))
    {
982 983
      execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
      if (thd->query_error)
unknown's avatar
unknown committed
984
	thd->killed= THD::KILL_CONNECTION;
unknown's avatar
SCRUM:  
unknown committed
985 986 987
    }

    thd->proc_info=0;
unknown's avatar
unknown committed
988
    thd->set_time();
unknown's avatar
SCRUM  
unknown committed
989
    while (!net->error && net->vio != 0 && !(thd->killed == THD::KILL_CONNECTION))
unknown's avatar
unknown committed
990 991 992 993
    {
      if (do_command(thd))
	break;
    }
unknown's avatar
unknown committed
994 995
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
unknown's avatar
unknown committed
996
    if (net->error && net->vio != 0 && net->report_error)
unknown's avatar
unknown committed
997
    {
unknown's avatar
unknown committed
998
      if (!thd->killed && thd->variables.log_warnings)
999 1000 1001 1002 1003 1004
	sql_print_error(ER(ER_NEW_ABORTING_CONNECTION),
			thd->thread_id,(thd->db ? thd->db : "unconnected"),
			thd->user ? thd->user : "unauthenticated",
			thd->host_or_ip,
			(net->last_errno ? ER(net->last_errno) :
			 ER(ER_UNKNOWN_ERROR)));
1005
      send_error(thd,net->last_errno,NullS);
unknown's avatar
unknown committed
1006
      statistic_increment(aborted_threads,&LOCK_status);
unknown's avatar
unknown committed
1007
    }
1008 1009 1010 1011
    else if (thd->killed)
    {
      statistic_increment(aborted_threads,&LOCK_status);
    }
unknown's avatar
unknown committed
1012
    
unknown's avatar
unknown committed
1013
end_thread:
1014
    close_connection(thd, 0, 1);
unknown's avatar
unknown committed
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
    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
1026 1027
#endif /* EMBEDDED_LIBRARY */

1028 1029 1030 1031
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
unknown's avatar
unknown committed
1032

1033
extern "C" pthread_handler_decl(handle_bootstrap,arg)
unknown's avatar
unknown committed
1034
{
1035 1036 1037
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
unknown's avatar
unknown committed
1038

1039
  /* The following must be called before DBUG_ENTER */
1040
  if (my_thread_init() || thd->store_globals())
unknown's avatar
unknown committed
1041
  {
unknown's avatar
unknown committed
1042
#ifndef EMBEDDED_LIBRARY
1043
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
unknown's avatar
unknown committed
1044
#endif
1045
    thd->fatal_error();
1046
    goto end;
unknown's avatar
unknown committed
1047
  }
1048 1049
  DBUG_ENTER("handle_bootstrap");

unknown's avatar
unknown committed
1050
#ifndef EMBEDDED_LIBRARY
1051 1052
  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
1053
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
unknown's avatar
unknown committed
1054
  sigset_t set;
1055 1056
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
unknown's avatar
unknown committed
1057
#endif
unknown's avatar
unknown committed
1058
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
1059

1060
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
1061 1062 1063 1064
    thd->options |= OPTION_BIG_SELECTS;

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

1067
  buff= (char*) thd->net.buff;
unknown's avatar
unknown committed
1068 1069
  while (fgets(buff, thd->net.max_packet, file))
  {
unknown's avatar
unknown committed
1070
    uint length=(uint) strlen(buff);
unknown's avatar
unknown committed
1071
    while (length && (my_isspace(thd->charset(), buff[length-1]) ||
1072
           buff[length-1] == ';'))
unknown's avatar
unknown committed
1073 1074
      length--;
    buff[length]=0;
1075
    thd->query_length=length;
unknown's avatar
unknown committed
1076 1077
    thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
    thd->query[length] = '\0';
unknown's avatar
unknown committed
1078
    thd->query_id=query_id++;
1079
    if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
unknown's avatar
unknown committed
1080 1081 1082 1083 1084 1085
    {
      thd->net.error = 0;
      close_thread_tables(thd);			// Free tables
      free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
      break;
    }
unknown's avatar
unknown committed
1086 1087
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
1088
    if (thd->is_fatal_error)
1089
      break;
1090
    free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
1091
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1092
  }
1093 1094 1095

  /* thd->fatal_error should be set in case something went wrong */
end:
unknown's avatar
unknown committed
1096
#ifndef EMBEDDED_LIBRARY
1097 1098 1099
  (void) pthread_mutex_lock(&LOCK_thread_count);
  thread_count--;
  (void) pthread_mutex_unlock(&LOCK_thread_count);
1100
  (void) pthread_cond_broadcast(&COND_thread_count);
1101 1102
  my_thread_end();
  pthread_exit(0);
unknown's avatar
unknown committed
1103
#endif
1104
  DBUG_RETURN(0);				// Never reached
unknown's avatar
unknown committed
1105 1106
}

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

1109
void free_items(Item *item)
unknown's avatar
unknown committed
1110
{
1111
  for (; item ; item=item->next)
unknown's avatar
unknown committed
1112 1113 1114
    delete item;
}

1115 1116 1117 1118 1119 1120 1121 1122
    /* This works because items are allocated with sql_alloc() */

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

unknown's avatar
unknown committed
1123 1124 1125 1126 1127 1128 1129
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;
1130
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
1131
    DBUG_RETURN(1); // out of memory
unknown's avatar
unknown committed
1132
  table_list->db = db;
1133
  table_list->real_name = table_list->alias = tbl_name;
unknown's avatar
unknown committed
1134 1135 1136
  table_list->lock_type = TL_READ_NO_INSERT;
  table_list->next = 0;

unknown's avatar
unknown committed
1137 1138
  if (!db || check_db_name(db))
  {
unknown's avatar
unknown committed
1139
    net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
unknown's avatar
unknown committed
1140 1141
    goto err;
  }
1142
  if (lower_case_table_names)
1143
    my_casedn_str(files_charset_info, tbl_name);
unknown's avatar
unknown committed
1144
  remove_escape(table_list->real_name);
1145 1146 1147 1148

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

unknown's avatar
SCRUM:  
unknown committed
1149
  if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege,0,0))
unknown's avatar
unknown committed
1150
    goto err;
unknown's avatar
unknown committed
1151
  if (grant_option && check_grant(thd, SELECT_ACL, table_list, 0, 0))
unknown's avatar
unknown committed
1152 1153
    goto err;
  thd->free_list = 0;
unknown's avatar
unknown committed
1154
  thd->query_length=(uint) strlen(tbl_name);
unknown's avatar
unknown committed
1155
  thd->query = tbl_name;
1156 1157
  if ((error = mysqld_dump_create_info(thd, table, -1)))
  {
1158
    my_error(ER_GET_ERRNO, MYF(0), my_errno);
1159 1160
    goto err;
  }
unknown's avatar
unknown committed
1161
  net_flush(&thd->net);
1162
  if ((error= table->file->dump(thd,fd)))
1163
    my_error(ER_GET_ERRNO, MYF(0));
unknown's avatar
unknown committed
1164

unknown's avatar
unknown committed
1165 1166
err:
  close_thread_tables(thd);
unknown's avatar
unknown committed
1167
  DBUG_RETURN(error);
unknown's avatar
unknown committed
1168 1169 1170
}


1171
	/* Execute one command from socket (query or simple command) */
1172 1173

#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1174 1175 1176
bool do_command(THD *thd)
{
  char *packet;
unknown's avatar
unknown committed
1177 1178
  uint old_timeout;
  ulong packet_length;
unknown's avatar
unknown committed
1179 1180 1181 1182 1183
  NET *net;
  enum enum_server_command command;
  DBUG_ENTER("do_command");

  net= &thd->net;
unknown's avatar
unknown committed
1184 1185 1186 1187
  /*
    indicator of uninitialized lex => normal flow of errors handling
    (see my_message_sql)
  */
1188
  thd->lex->current_select= 0;
unknown's avatar
unknown committed
1189 1190

  packet=0;
unknown's avatar
unknown committed
1191 1192 1193
  old_timeout=net->read_timeout;
  // Wait max for 8 hours
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
unknown's avatar
unknown committed
1194
  thd->clear_error();				// Clear error message
unknown's avatar
unknown committed
1195 1196 1197 1198

  net_new_transaction(net);
  if ((packet_length=my_net_read(net)) == packet_error)
  {
1199 1200 1201 1202 1203
    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)
1204 1205
    {
      statistic_increment(aborted_threads,&LOCK_status);
1206
      DBUG_RETURN(TRUE);			// We have to close it.
1207
    }
1208
    send_error(thd,net->last_errno,NullS);
1209
    net->error= 0;
1210
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
1211 1212 1213
  }
  else
  {
unknown's avatar
SCRUM  
unknown committed
1214 1215
    if (thd->killed == THD::KILL_QUERY)
      thd->killed= THD::NOT_KILLED;
unknown's avatar
SCRUM  
unknown committed
1216

unknown's avatar
unknown committed
1217 1218
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
1219 1220
    if (command >= COM_END)
      command= COM_END;				// Wrong command
unknown's avatar
unknown committed
1221 1222 1223
    DBUG_PRINT("info",("Command on %s = %d (%s)",
		       vio_description(net->vio), command,
		       command_name[command]));
unknown's avatar
unknown committed
1224
  }
unknown's avatar
unknown committed
1225
  net->read_timeout=old_timeout;		// restore it
unknown's avatar
unknown committed
1226
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
1227
}
1228
#endif  /* EMBEDDED_LIBRARY */
1229

1230

1231 1232 1233 1234
bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
1235
  bool error= 0;
1236 1237 1238
  DBUG_ENTER("dispatch_command");

  thd->command=command;
unknown's avatar
unknown committed
1239 1240 1241 1242
  /*
    Commands which will always take a long time should be marked with
    this so that they will not get logged to the slow query log
  */
1243
  thd->slow_command=FALSE;
unknown's avatar
unknown committed
1244
  thd->set_time();
unknown's avatar
unknown committed
1245 1246 1247 1248 1249 1250
  VOID(pthread_mutex_lock(&LOCK_thread_count));
  thd->query_id=query_id;
  if (command != COM_STATISTICS && command != COM_PING)
    query_id++;
  thread_running++;
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1251

1252 1253
  thd->server_status&=
           ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
1254
  switch (command) {
unknown's avatar
unknown committed
1255
  case COM_INIT_DB:
unknown's avatar
unknown committed
1256 1257 1258 1259 1260 1261 1262 1263 1264
  {
    LEX_STRING tmp;
    statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
    thd->convert_string(&tmp, system_charset_info,
			packet, strlen(packet), thd->charset());
    if (!mysql_change_db(thd, tmp.str))
      mysql_log.write(thd,command,"%s",thd->db);
    break;
  }
unknown's avatar
unknown committed
1265
#ifdef HAVE_REPLICATION
1266 1267
  case COM_REGISTER_SLAVE:
  {
1268
    if (!register_slave(thd, (uchar*)packet, packet_length))
1269
      send_ok(thd);
1270 1271
    break;
  }
1272
#endif
unknown's avatar
unknown committed
1273
  case COM_TABLE_DUMP:
1274 1275 1276 1277 1278 1279
  {
    char *db, *tbl_name;
    uint db_len= *(uchar*) packet;
    uint tbl_len= *(uchar*) (packet + db_len + 1);

    statistic_increment(com_other, &LOCK_status);
1280
    thd->slow_command= TRUE;
1281 1282 1283 1284 1285 1286 1287
    db= thd->alloc(db_len + tbl_len + 2);
    tbl_name= strmake(db, packet + 1, db_len)+1;
    strmake(tbl_name, packet + db_len + 2, tbl_len);
    if (mysql_table_dump(thd, db, tbl_name, -1))
      send_error(thd); // dump to NET
    break;
  }
1288
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1289 1290
  case COM_CHANGE_USER:
  {
unknown's avatar
unknown committed
1291
    thd->change_user();
1292
    thd->clear_error();                         // if errors from rollback
unknown's avatar
unknown committed
1293

1294 1295
    statistic_increment(com_other, &LOCK_status);
    char *user= (char*) packet;
unknown's avatar
unknown committed
1296
    char *passwd= strend(user)+1;
unknown's avatar
unknown committed
1297 1298 1299 1300 1301
    /* 
      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
1302
    char db_buff[NAME_LEN+1];                 // buffer to store db in utf8 
unknown's avatar
unknown committed
1303 1304 1305 1306
    char *db= passwd;
    uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? 
      *passwd++ : strlen(passwd);
    db+= passwd_len + 1;
unknown's avatar
unknown committed
1307
    /* Small check for incomming packet */
unknown's avatar
unknown committed
1308
    if ((uint) ((uchar*) db - net->read_pos) > packet_length)
1309 1310 1311 1312
    {
      send_error(thd, ER_UNKNOWN_COM_ERROR);
      break;
    }
unknown's avatar
unknown committed
1313

1314
    /* Convert database name to utf8 */
unknown's avatar
unknown committed
1315 1316 1317 1318
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
                             system_charset_info, db, strlen(db),
                             thd->charset())]= 0;
    db= db_buff;
unknown's avatar
unknown committed
1319

1320 1321 1322 1323 1324 1325 1326
    /* Save user and privileges */
    uint save_master_access= thd->master_access;
    uint save_db_access= thd->db_access;
    uint save_db_length= thd->db_length;
    char *save_user= thd->user;
    char *save_priv_user= thd->priv_user;
    char *save_db= thd->db;
unknown's avatar
unknown committed
1327
    USER_CONN *save_user_connect= thd->user_connect;
unknown's avatar
unknown committed
1328 1329
    
    if (!(thd->user= my_strdup(user, MYF(0))))
1330 1331 1332 1333 1334
    {
      thd->user= save_user;
      send_error(thd, ER_OUT_OF_RESOURCES);
      break;
    }
unknown's avatar
unknown committed
1335

unknown's avatar
unknown committed
1336 1337
    /* Clear variables that are allocated */
    thd->user_connect= 0;
unknown's avatar
unknown committed
1338
    int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, false);
unknown's avatar
unknown committed
1339

1340 1341 1342 1343 1344 1345 1346 1347
    if (res)
    {
      /* authentification failure, we shall restore old user */
      if (res > 0)
        send_error(thd, ER_UNKNOWN_COM_ERROR);
      x_free(thd->user);
      thd->user= save_user;
      thd->priv_user= save_priv_user;
unknown's avatar
unknown committed
1348
      thd->user_connect= save_user_connect;
1349 1350 1351 1352 1353 1354 1355 1356
      thd->master_access= save_master_access;
      thd->db_access= save_db_access;
      thd->db= save_db;
      thd->db_length= save_db_length;
    }
    else
    {
      /* we've authenticated new user */
unknown's avatar
unknown committed
1357 1358
      if (save_user_connect)
	decrease_user_connections(save_user_connect);
1359 1360 1361
      x_free((gptr) save_db);
      x_free((gptr) save_user);
    }
unknown's avatar
unknown committed
1362 1363
    break;
  }
1364
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
1365 1366
  case COM_EXECUTE:
  {
1367
    mysql_stmt_execute(thd, packet);
unknown's avatar
unknown committed
1368 1369 1370 1371
    break;
  }
  case COM_LONG_DATA:
  {
1372
    mysql_stmt_get_longdata(thd, packet, packet_length);
unknown's avatar
unknown committed
1373 1374 1375 1376
    break;
  }
  case COM_PREPARE:
  {
1377
    mysql_stmt_prepare(thd, packet, packet_length);
unknown's avatar
unknown committed
1378 1379
    break;
  }
unknown's avatar
unknown committed
1380 1381 1382 1383 1384
  case COM_CLOSE_STMT:
  {
    mysql_stmt_free(thd, packet);
    break;
  }
1385 1386 1387 1388 1389
  case COM_RESET_STMT:
  {
    mysql_stmt_reset(thd, packet);
    break;
  }
unknown's avatar
unknown committed
1390 1391
  case COM_QUERY:
  {
1392 1393
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
1394
    mysql_log.write(thd,command,"%s",thd->query);
1395
    DBUG_PRINT("query",("%-.4096s",thd->query));
1396
    mysql_parse(thd,thd->query, thd->query_length);
1397

unknown's avatar
unknown committed
1398
    while (!thd->killed && !thd->is_fatal_error && thd->lex->found_colon)
1399
    {
unknown's avatar
unknown committed
1400
      char *packet= thd->lex->found_colon;
1401
      /*
1402 1403 1404
        Multiple queries exits, execute them individually
      */
      if (thd->lock || thd->open_tables || thd->derived_tables)
1405
        close_thread_tables(thd);
1406

unknown's avatar
unknown committed
1407
      ulong length= thd->query_length-(ulong)(thd->lex->found_colon-thd->query);
1408

1409
      /* Remove garbage at start of query */
unknown's avatar
unknown committed
1410
      while (my_isspace(thd->charset(), *packet) && length > 0)
1411 1412 1413 1414 1415
      {
        packet++;
        length--;
      }
      thd->query_length= length;
1416 1417 1418 1419
      thd->query= packet;
      VOID(pthread_mutex_lock(&LOCK_thread_count));
      thd->query_id= query_id++;
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
1420 1421 1422
      mysql_parse(thd, packet, length);
    }

unknown's avatar
unknown committed
1423 1424 1425 1426 1427
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1428
  case COM_FIELD_LIST:				// This isn't actually needed
unknown's avatar
unknown committed
1429
#ifdef DONT_ALLOW_SHOW_COMMANDS
1430
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
1431 1432 1433
    break;
#else
  {
1434
    char *fields, *pend;
unknown's avatar
unknown committed
1435
    TABLE_LIST table_list;
unknown's avatar
unknown committed
1436 1437
    LEX_STRING conv_name;

unknown's avatar
unknown committed
1438
    statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
unknown's avatar
unknown committed
1439 1440 1441
    bzero((char*) &table_list,sizeof(table_list));
    if (!(table_list.db=thd->db))
    {
1442
      send_error(thd,ER_NO_DB_ERROR);
unknown's avatar
unknown committed
1443 1444 1445
      break;
    }
    thd->free_list=0;
1446
    pend= strend(packet);
unknown's avatar
unknown committed
1447 1448 1449
    thd->convert_string(&conv_name, system_charset_info,
			packet, (uint) (pend-packet), thd->charset());
    table_list.alias= table_list.real_name= conv_name.str;
1450
    packet= pend+1;
unknown's avatar
unknown committed
1451
    // command not cachable => no gap for data base name
unknown's avatar
unknown committed
1452 1453
    if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
      break;
1454
    mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
1455
    if (lower_case_table_names)
unknown's avatar
unknown committed
1456
      my_casedn_str(files_charset_info, table_list.real_name);
unknown's avatar
unknown committed
1457 1458
    remove_escape(table_list.real_name);	// This can't have wildcards

unknown's avatar
SCRUM:  
unknown committed
1459
    if (check_access(thd,SELECT_ACL,table_list.db,&thd->col_access,0,0))
unknown's avatar
unknown committed
1460 1461
      break;
    table_list.grant.privilege=thd->col_access;
unknown's avatar
unknown committed
1462
    if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2,0))
unknown's avatar
unknown committed
1463 1464
      break;
    mysqld_list_fields(thd,&table_list,fields);
1465
    free_items(thd->free_list);
unknown's avatar
unknown committed
1466 1467 1468 1469
    break;
  }
#endif
  case COM_QUIT:
1470
    /* We don't calculate statistics for this command */
1471
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1472 1473 1474 1475
    net->error=0;				// Don't give 'abort' message
    error=TRUE;					// End server
    break;

unknown's avatar
unknown committed
1476
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1477
    {
unknown's avatar
unknown committed
1478
      statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
1479
      char *db=thd->strdup(packet);
unknown's avatar
unknown committed
1480
      // null test to handle EOM
unknown's avatar
unknown committed
1481
      if (!db || !strip_sp(db) || check_db_name(db))
unknown's avatar
unknown committed
1482
      {
unknown's avatar
unknown committed
1483
	net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
unknown's avatar
unknown committed
1484 1485
	break;
      }
unknown's avatar
SCRUM:  
unknown committed
1486
      if (check_access(thd,CREATE_ACL,db,0,1,0))
unknown's avatar
unknown committed
1487
	break;
1488
      mysql_log.write(thd,command,packet);
unknown's avatar
unknown committed
1489
      mysql_create_db(thd,db,0,0);
unknown's avatar
unknown committed
1490 1491
      break;
    }
unknown's avatar
unknown committed
1492
  case COM_DROP_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1493
    {
unknown's avatar
unknown committed
1494
      statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
1495
      char *db=thd->strdup(packet);
unknown's avatar
unknown committed
1496
      // null test to handle EOM
unknown's avatar
unknown committed
1497
      if (!db || !strip_sp(db) || check_db_name(db))
unknown's avatar
unknown committed
1498
      {
unknown's avatar
unknown committed
1499
	net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
unknown's avatar
unknown committed
1500 1501
	break;
      }
unknown's avatar
SCRUM:  
unknown committed
1502
      if (check_access(thd,DROP_ACL,db,0,1,0))
1503
	break;
unknown's avatar
unknown committed
1504 1505
      if (thd->locked_tables || thd->active_transaction())
      {
1506
	send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
1507
	break;
unknown's avatar
unknown committed
1508
      }
1509
      mysql_log.write(thd,command,db);
unknown's avatar
unknown committed
1510
      mysql_rm_db(thd,db,0,0);
unknown's avatar
unknown committed
1511 1512
      break;
    }
1513
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1514 1515
  case COM_BINLOG_DUMP:
    {
unknown's avatar
unknown committed
1516
      statistic_increment(com_other,&LOCK_status);
1517
      thd->slow_command = TRUE;
unknown's avatar
unknown committed
1518
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1519
	break;
1520
      mysql_log.write(thd,command, 0);
unknown's avatar
unknown committed
1521

unknown's avatar
unknown committed
1522 1523
      ulong pos;
      ushort flags;
1524
      uint32 slave_server_id;
1525
      /* TODO: The following has to be changed to an 8 byte integer */
1526 1527
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
1528
      thd->server_id=0; /* avoid suicide */
unknown's avatar
unknown committed
1529
      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
unknown's avatar
unknown committed
1530
	kill_zombie_dump_threads(slave_server_id);
1531
      thd->server_id = slave_server_id;
1532
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1533
      unregister_slave(thd,1,1);
1534 1535 1536
      // fake COM_QUIT -- if we get here, the thread needs to terminate
      error = TRUE;
      net->error = 0;
unknown's avatar
unknown committed
1537 1538
      break;
    }
1539
#endif
unknown's avatar
unknown committed
1540 1541
  case COM_REFRESH:
    {
unknown's avatar
unknown committed
1542
      statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
unknown's avatar
unknown committed
1543
      ulong options= (ulong) (uchar) packet[0];
unknown's avatar
unknown committed
1544
      if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1545
	break;
1546
      mysql_log.write(thd,command,NullS);
1547 1548 1549 1550
      if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, NULL))
        send_error(thd, 0);
      else
        send_ok(thd);
unknown's avatar
unknown committed
1551 1552
      break;
    }
1553
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1554
  case COM_SHUTDOWN:
unknown's avatar
unknown committed
1555
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1556
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1557 1558
      break; /* purecov: inspected */
    DBUG_PRINT("quit",("Got shutdown command"));
1559
    mysql_log.write(thd,command,NullS);
1560
    send_eof(thd);
unknown's avatar
unknown committed
1561 1562 1563
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
unknown's avatar
unknown committed
1564
#ifndef OS2
1565
    send_eof(thd);				// This is for 'quit request'
unknown's avatar
unknown committed
1566
#endif
1567
    close_connection(thd, 0, 1);
unknown's avatar
unknown committed
1568 1569 1570 1571
    close_thread_tables(thd);			// Free before kill
    kill_mysql();
    error=TRUE;
    break;
1572
#endif
unknown's avatar
unknown committed
1573 1574
  case COM_STATISTICS:
  {
1575
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1576
    statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
unknown's avatar
unknown committed
1577
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1578
    char buff[200];
unknown's avatar
unknown committed
1579 1580 1581
#else
    char *buff= thd->net.last_error;
#endif
1582
    ulong uptime = (ulong) (thd->start_time - start_time);
unknown's avatar
unknown committed
1583
    sprintf((char*) buff,
1584
	    "Uptime: %ld  Threads: %d  Questions: %lu  Slow queries: %ld  Opens: %ld  Flush tables: %ld  Open tables: %u  Queries per second avg: %.3f",
unknown's avatar
unknown committed
1585 1586 1587 1588 1589
	    uptime,
	    (int) thread_count,thd->query_id,long_query_count,
	    opened_tables,refresh_version, cached_tables(),
	    uptime ? (float)thd->query_id/(float)uptime : 0);
#ifdef SAFEMALLOC
1590
    if (sf_malloc_cur_memory)				// Using SAFEMALLOC
unknown's avatar
unknown committed
1591
      sprintf(strend(buff), "  Memory in use: %ldK  Max memory used: %ldK",
1592 1593
	      (sf_malloc_cur_memory+1023L)/1024L,
	      (sf_malloc_max_memory+1023L)/1024L);
unknown's avatar
unknown committed
1594 1595
#endif
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1596
    VOID(my_net_write(net, buff,(uint) strlen(buff)));
unknown's avatar
unknown committed
1597
    VOID(net_flush(net));
unknown's avatar
unknown committed
1598
#endif
unknown's avatar
unknown committed
1599 1600 1601
    break;
  }
  case COM_PING:
unknown's avatar
unknown committed
1602
    statistic_increment(com_other,&LOCK_status);
1603
    send_ok(thd);				// Tell client we are alive
unknown's avatar
unknown committed
1604 1605
    break;
  case COM_PROCESS_INFO:
unknown's avatar
unknown committed
1606
    statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
unknown's avatar
unknown committed
1607
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
1608
      break;
1609
    mysql_log.write(thd,command,NullS);
unknown's avatar
SCRUM:  
unknown committed
1610 1611
    mysqld_list_processes(thd,
			  thd->master_access & PROCESS_ACL ? 
unknown's avatar
unknown committed
1612
			  NullS : thd->priv_user, 0);
unknown's avatar
unknown committed
1613 1614 1615
    break;
  case COM_PROCESS_KILL:
  {
unknown's avatar
unknown committed
1616
    statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
1617
    ulong id=(ulong) uint4korr(packet);
unknown's avatar
SCRUM  
unknown committed
1618
    kill_one_thread(thd,id,false);
unknown's avatar
unknown committed
1619 1620
    break;
  }
1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637
  case COM_SET_OPTION:
  {
    statistic_increment(com_stat[SQLCOM_SET_OPTION], &LOCK_status);
    enum_mysql_set_option command= (enum_mysql_set_option) uint2korr(packet);
    switch (command) {
    case MYSQL_OPTION_MULTI_STATEMENTS_ON:
      thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
      break;
    case MYSQL_OPTION_MULTI_STATEMENTS_OFF:
      thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
      break;
    default:
      send_error(thd, ER_UNKNOWN_COM_ERROR);
      break;
    }
    break;
  }
unknown's avatar
unknown committed
1638
  case COM_DEBUG:
unknown's avatar
unknown committed
1639
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1640
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1641 1642
      break;					/* purecov: inspected */
    mysql_print_status(thd);
1643
    mysql_log.write(thd,command,NullS);
1644
    send_eof(thd);
unknown's avatar
unknown committed
1645 1646 1647 1648 1649
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
1650
  case COM_END:
unknown's avatar
unknown committed
1651
  default:
1652
    send_error(thd, ER_UNKNOWN_COM_ERROR);
unknown's avatar
unknown committed
1653 1654
    break;
  }
1655
  if (thd->lock || thd->open_tables || thd->derived_tables)
unknown's avatar
unknown committed
1656 1657 1658 1659 1660
  {
    thd->proc_info="closing tables";
    close_thread_tables(thd);			/* Free tables */
  }

1661
  if (thd->is_fatal_error)
1662
    send_error(thd,0);				// End of memory ?
unknown's avatar
unknown committed
1663 1664

  time_t start_of_query=thd->start_time;
1665
  thd->end_time();				// Set start time
1666

1667
  /* If not reading from backup and if the query took too long */
1668
  if (!thd->slow_command && !thd->user_time) // do not log 'slow_command' queries
unknown's avatar
unknown committed
1669
  {
1670 1671
    thd->proc_info="logging slow query";

1672 1673
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
1674 1675
	((thd->server_status &
	  (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
1676
	 (specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES)))
1677 1678 1679 1680
    {
      long_query_count++;
      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
    }
unknown's avatar
unknown committed
1681
  }
1682
  thd->proc_info="cleaning up";
unknown's avatar
unknown committed
1683 1684 1685 1686 1687 1688
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
  thd->proc_info=0;
  thd->command=COM_SLEEP;
  thd->query=0;
  thread_running--;
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1689
  thd->packet.shrink(thd->variables.net_buffer_length);	// Reclaim some memory
1690

1691
  free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1692 1693 1694
  DBUG_RETURN(error);
}

1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712

/*
  Read query from packet and store in thd->query
  Used in COM_QUERY and COM_PREPARE

  DESCRIPTION
    Sets the following THD variables:
      query
      query_length

  RETURN VALUES
    0	ok
    1	error;  In this case thd->fatal_error is set
*/

bool alloc_query(THD *thd, char *packet, ulong packet_length)
{
  packet_length--;				// Remove end null
1713
  /* Remove garbage at start and end of query */
unknown's avatar
unknown committed
1714
  while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
1715 1716 1717 1718 1719
  {
    packet++;
    packet_length--;
  }
  char *pos=packet+packet_length;		// Point at end null
unknown's avatar
unknown committed
1720
  while (packet_length > 0 &&
unknown's avatar
unknown committed
1721
	 (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
1722 1723 1724 1725 1726 1727 1728
  {
    pos--;
    packet_length--;
  }
  /* We must allocate some extra memory for query cache */
  if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
					      packet_length,
1729 1730
					      thd->db_length+ 1 +
					      QUERY_CACHE_FLAGS_SIZE)))
1731 1732 1733 1734 1735 1736 1737 1738 1739 1740
    return 1;
  thd->query[packet_length]=0;
  thd->query_length= packet_length;
  thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory

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

unknown's avatar
unknown committed
1741 1742 1743 1744 1745
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/

1746
int
1747
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
1748
{
1749
  int	res= 0;
unknown's avatar
unknown committed
1750
  LEX	*lex= thd->lex;
1751
  TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first;
unknown's avatar
unknown committed
1752
  SELECT_LEX *select_lex= &lex->select_lex;
1753
  SELECT_LEX_UNIT *unit= &lex->unit;
unknown's avatar
unknown committed
1754 1755
  DBUG_ENTER("mysql_execute_command");

1756
  if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
1757
      lex->sql_command != SQLCOM_CREATE_SPFUNCTION)
1758 1759 1760 1761 1762
  {
    if (sp_cache_functions(thd, lex))
      DBUG_RETURN(-1);
  }

1763 1764 1765 1766 1767 1768
  /*
    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.
  */
1769
  if (tables || &lex->select_lex != lex->all_selects_list)
1770 1771
    mysql_reset_errors(thd);

unknown's avatar
SCRUM  
unknown committed
1772
#ifdef HAVE_REPLICATION
1773 1774
  if (thd->slave_thread)
  {
unknown's avatar
unknown committed
1775
    /*
unknown's avatar
merge  
unknown committed
1776 1777 1778 1779
      Skip if we are in the slave thread, some table rules have been
      given and the table list says the query should not be replicated
    */
    if (table_rules_on && tables && !tables_ok(thd,tables))
unknown's avatar
Fix for  
unknown committed
1780 1781 1782
    {
      /* we warn the slave SQL thread */
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
1783
      DBUG_RETURN(0);
unknown's avatar
Fix for  
unknown committed
1784
    }
unknown's avatar
merge  
unknown committed
1785 1786
#ifndef TO_BE_DELETED
    /*
1787 1788 1789
      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
1790
    */
1791 1792 1793
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
unknown's avatar
unknown committed
1794
      lex->insert_list = &select_lex->item_list;
1795
    }
unknown's avatar
merge  
unknown committed
1796
#endif
1797
  }
unknown's avatar
SCRUM:  
unknown committed
1798
#endif /* !HAVE_REPLICATION */
1799
  /*
unknown's avatar
unknown committed
1800 1801
    TODO: make derived tables processing 'inside' SELECT processing.
    TODO: solve problem with depended derived tables in subselects
1802
  */
unknown's avatar
unknown committed
1803
  if (lex->derived_tables)
unknown's avatar
unknown committed
1804
  {
1805 1806 1807
    for (SELECT_LEX *sl= lex->all_selects_list;
	 sl;
	 sl= sl->next_select_in_list())
1808
    {
1809 1810 1811
      for (TABLE_LIST *cursor= sl->get_table_list();
	   cursor;
	   cursor= cursor->next)
1812
      {
1813 1814 1815
	if (cursor->derived && (res=mysql_derived(thd, lex,
						  cursor->derived,
						  cursor)))
unknown's avatar
unknown committed
1816
	{
1817 1818
	  if (res < 0 || thd->net.report_error)
	    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
1819
	  DBUG_RETURN(res);
1820
	}
1821 1822
      }
    }
1823
  }
unknown's avatar
unknown committed
1824
  if (&lex->select_lex != lex->all_selects_list &&
unknown's avatar
unknown committed
1825
      lex->sql_command != SQLCOM_CREATE_TABLE &&
unknown's avatar
unknown committed
1826
      lex->unit.create_total_list(thd, lex, &tables, 0))
1827
    DBUG_RETURN(0);
1828 1829 1830 1831 1832 1833
  
  /*
    When option readonly is set deny operations which change tables.
    Except for the replication thread and the 'super' users.
  */
  if (opt_readonly &&
unknown's avatar
unknown committed
1834
      !(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
1835 1836
      (uc_update_queries[lex->sql_command] > 0))
  {
unknown's avatar
unknown committed
1837
    send_error(thd, ER_CANT_UPDATE_WITH_READLOCK);
unknown's avatar
unknown committed
1838
    DBUG_RETURN(-1);
1839
  }
1840

unknown's avatar
unknown committed
1841
  statistic_increment(com_stat[lex->sql_command],&LOCK_status);
unknown's avatar
unknown committed
1842 1843 1844
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
unknown's avatar
unknown committed
1845
    select_result *result=lex->result;
unknown's avatar
unknown committed
1846 1847 1848 1849 1850
    if (tables)
    {
      res=check_table_access(thd,
			     lex->exchange ? SELECT_ACL | FILE_ACL :
			     SELECT_ACL,
unknown's avatar
SCRUM:  
unknown committed
1851
			     tables,0);
unknown's avatar
unknown committed
1852 1853 1854
    }
    else
      res=check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
unknown's avatar
SCRUM:  
unknown committed
1855
		       any_db,0,0,0);
unknown's avatar
unknown committed
1856 1857 1858 1859 1860
    if (res)
    {
      res=0;
      break;					// Error message is given
    }
1861 1862 1863 1864
    /* 
       In case of single SELECT unit->global_parameters points on first SELECT
       TODO: move counters to SELECT_LEX
    */
1865 1866 1867
    unit->offset_limit_cnt= (ha_rows) unit->global_parameters->offset_limit;
    unit->select_limit_cnt= (ha_rows) (unit->global_parameters->select_limit+
      unit->global_parameters->offset_limit);
unknown's avatar
unknown committed
1868
    if (unit->select_limit_cnt <
1869
	(ha_rows) unit->global_parameters->select_limit)
1870
      unit->select_limit_cnt= HA_POS_ERROR;		// no limit
1871
    if (unit->select_limit_cnt == HA_POS_ERROR && !select_lex->next_select())
1872
      select_lex->options&= ~OPTION_FOUND_ROWS;
unknown's avatar
unknown committed
1873 1874

    if (!(res=open_and_lock_tables(thd,tables)))
unknown's avatar
unknown committed
1875
    {
unknown's avatar
unknown committed
1876
      if (lex->describe)
unknown's avatar
unknown committed
1877
      {
1878 1879 1880
	if (!(result= new select_send()))
	{
	  send_error(thd, ER_OUT_OF_RESOURCES);
1881
	  goto error;
1882 1883 1884
	}
	else
	  thd->send_explain_fields(result);
1885
	fix_tables_pointers(lex->all_selects_list);
unknown's avatar
unknown committed
1886
	res= mysql_explain_union(thd, &thd->lex->unit, result);
unknown's avatar
unknown committed
1887 1888
	MYSQL_LOCK *save_lock= thd->lock;
	thd->lock= (MYSQL_LOCK *)0;
unknown's avatar
unknown committed
1889 1890 1891 1892 1893
	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
1894
	  thd->lex->unit.print(&str);
unknown's avatar
unknown committed
1895 1896 1897 1898
	  str.append('\0');
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
		       ER_YES, str.ptr());
	}
1899
	result->send_eof();
unknown's avatar
unknown committed
1900 1901 1902 1903
	thd->lock= save_lock;
      }
      else
      {
unknown's avatar
unknown committed
1904 1905
	if (!result)
	{
unknown's avatar
unknown committed
1906
	  if (!(result=new select_send()))
unknown's avatar
unknown committed
1907 1908 1909 1910 1911 1912 1913 1914 1915
	  {
	    res= -1;
#ifdef DELETE_ITEMS
	    delete select_lex->having;
	    delete select_lex->where;
#endif
	    break;
	  }
	}
unknown's avatar
unknown committed
1916 1917 1918
	query_cache_store_query(thd, tables);
	res=handle_select(thd, lex, result);
      }
unknown's avatar
unknown committed
1919
    }
unknown's avatar
unknown committed
1920 1921
    break;
  }
unknown's avatar
SCRUM:  
unknown committed
1922

unknown's avatar
unknown committed
1923
  case SQLCOM_DO:
unknown's avatar
SCRUM:  
unknown committed
1924
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
unknown's avatar
unknown committed
1925 1926 1927 1928 1929 1930 1931
		   (res= open_and_lock_tables(thd,tables))))
	break;

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

1934
  case SQLCOM_EMPTY_QUERY:
1935
    send_ok(thd);
1936 1937
    break;

unknown's avatar
unknown committed
1938 1939 1940 1941
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

1942
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1943
  case SQLCOM_PURGE:
1944
  {
unknown's avatar
unknown committed
1945
    if (check_global_access(thd, SUPER_ACL))
1946
      goto error;
1947
    // PURGE MASTER LOGS TO 'file'
1948 1949 1950
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
1951 1952 1953 1954 1955 1956 1957 1958
  case SQLCOM_PURGE_BEFORE:
  {
    if (check_global_access(thd, SUPER_ACL))
      goto error;
    // PURGE MASTER LOGS BEFORE 'data'
    res = purge_master_logs_before_date(thd, lex->purge_time);
    break;
  }
1959
#endif
unknown's avatar
unknown committed
1960 1961
  case SQLCOM_SHOW_WARNS:
  {
1962 1963
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
1964 1965 1966
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
unknown's avatar
unknown committed
1967 1968 1969 1970
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
1971 1972
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
1973 1974
    break;
  }
unknown's avatar
unknown committed
1975 1976
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
1977
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1978
      goto error;
1979
    /* This query don't work now. See comment in repl_failsafe.cc */
unknown's avatar
unknown committed
1980
#ifndef WORKING_NEW_MASTER
1981
    net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
unknown's avatar
unknown committed
1982 1983
    res= 1;
#else
unknown's avatar
unknown committed
1984
    res = show_new_master(thd);
unknown's avatar
unknown committed
1985
#endif
unknown's avatar
unknown committed
1986 1987
    break;
  }
1988

unknown's avatar
unknown committed
1989
#ifdef HAVE_REPLICATION
1990 1991
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
1992
    if (check_global_access(thd, REPL_SLAVE_ACL))
1993 1994 1995 1996
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
1997 1998
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
1999
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2000 2001 2002 2003
      goto error;
    res = show_binlog_events(thd);
    break;
  }
2004 2005
#endif

unknown's avatar
unknown committed
2006
  case SQLCOM_BACKUP_TABLE:
2007 2008
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
SCRUM:  
unknown committed
2009
	check_table_access(thd,SELECT_ACL, tables,0) ||
unknown's avatar
unknown committed
2010
	check_global_access(thd, FILE_ACL))
2011
      goto error; /* purecov: inspected */
2012
    thd->slow_command=TRUE;
2013
    res = mysql_backup_table(thd, tables);
unknown's avatar
unknown committed
2014

2015 2016
    break;
  }
unknown's avatar
unknown committed
2017
  case SQLCOM_RESTORE_TABLE:
2018 2019
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
SCRUM:  
unknown committed
2020
	check_table_access(thd, INSERT_ACL, tables,0) ||
unknown's avatar
unknown committed
2021
	check_global_access(thd, FILE_ACL))
2022
      goto error; /* purecov: inspected */
2023
    thd->slow_command=TRUE;
2024 2025 2026
    res = mysql_restore_table(thd, tables);
    break;
  }
unknown's avatar
unknown committed
2027 2028 2029
  case SQLCOM_ASSIGN_TO_KEYCACHE:
  {
    if (check_db_used(thd, tables) ||
unknown's avatar
unknown committed
2030 2031
        check_access(thd, INDEX_ACL, tables->db,
                     &tables->grant.privilege, 0, 0))
unknown's avatar
unknown committed
2032
      goto error;
2033
    res= mysql_assign_to_keycache(thd, tables, &lex->name_and_length);
unknown's avatar
unknown committed
2034 2035
    break;
  }
unknown's avatar
unknown committed
2036 2037 2038
  case SQLCOM_PRELOAD_KEYS:
  {
    if (check_db_used(thd, tables) ||
unknown's avatar
unknown committed
2039 2040
	check_access(thd, INDEX_ACL, tables->db,
                     &tables->grant.privilege, 0, 0))
2041
      goto error;
unknown's avatar
unknown committed
2042 2043 2044
    res = mysql_preload_keys(thd, tables);
    break;
  }
unknown's avatar
unknown committed
2045
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2046
  case SQLCOM_CHANGE_MASTER:
2047
  {
unknown's avatar
unknown committed
2048
    if (check_global_access(thd, SUPER_ACL))
2049
      goto error;
2050 2051 2052
    LOCK_ACTIVE_MI;
    res = change_master(thd,active_mi);
    UNLOCK_ACTIVE_MI;
2053 2054
    break;
  }
unknown's avatar
unknown committed
2055
  case SQLCOM_SHOW_SLAVE_STAT:
2056
  {
2057 2058
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2059
      goto error;
2060 2061 2062
    LOCK_ACTIVE_MI;
    res = show_master_info(thd,active_mi);
    UNLOCK_ACTIVE_MI;
2063 2064
    break;
  }
unknown's avatar
unknown committed
2065
  case SQLCOM_SHOW_MASTER_STAT:
2066
  {
2067 2068
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2069 2070 2071 2072
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
2073

2074
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
2075
    if (check_global_access(thd, SUPER_ACL))
2076
      goto error;
2077 2078 2079 2080
    if (end_active_trans(thd))
      res= -1;
    else
      res = load_master_data(thd);
2081
    break;
unknown's avatar
unknown committed
2082
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
2083 2084 2085
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
2086
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2087 2088 2089 2090 2091
	goto error;
      res = innodb_show_status(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
2092
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2093
  case SQLCOM_LOAD_MASTER_TABLE:
2094
  {
unknown's avatar
unknown committed
2095 2096
    if (!tables->db)
      tables->db=thd->db;
unknown's avatar
SCRUM:  
unknown committed
2097
    if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege,0,0))
unknown's avatar
unknown committed
2098 2099 2100 2101 2102 2103
      goto error;				/* purecov: inspected */
    if (grant_option)
    {
      /* Check that the first table has CREATE privilege */
      TABLE_LIST *tmp_table_list=tables->next;
      tables->next=0;
unknown's avatar
unknown committed
2104
      bool error=check_grant(thd,CREATE_ACL,tables,0,0);
unknown's avatar
unknown committed
2105 2106
      tables->next=tmp_table_list;
      if (error)
2107
	goto error;
unknown's avatar
unknown committed
2108
    }
2109
    if (strlen(tables->real_name) > NAME_LEN)
unknown's avatar
unknown committed
2110
    {
unknown's avatar
unknown committed
2111
      net_printf(thd,ER_WRONG_TABLE_NAME, tables->real_name);
unknown's avatar
unknown committed
2112 2113
      break;
    }
2114
    LOCK_ACTIVE_MI;
2115 2116 2117 2118
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
2119
    if (!fetch_master_table(thd, tables->db, tables->real_name,
2120
			    active_mi, 0, 0))
2121
    {
2122
      send_ok(thd);
2123 2124
    }
    UNLOCK_ACTIVE_MI;
unknown's avatar
unknown committed
2125
    break;
2126
  }
unknown's avatar
unknown committed
2127
#endif /* HAVE_REPLICATION */
2128

unknown's avatar
unknown committed
2129
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
2130
  {
unknown's avatar
unknown committed
2131 2132 2133 2134 2135 2136 2137
    /* Skip first table, which is the table we are creating */
    TABLE_LIST *create_table= tables;
    tables= tables->next;
    lex->select_lex.table_list.first= (byte*) (tables);
    create_table->next= 0;
    if (&lex->select_lex != lex->all_selects_list &&
	lex->unit.create_total_list(thd, lex, &tables, 0))
unknown's avatar
unknown committed
2138
      DBUG_RETURN(-1);
unknown's avatar
unknown committed
2139

unknown's avatar
unknown committed
2140 2141
    ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
		      CREATE_TMP_ACL : CREATE_ACL);
unknown's avatar
unknown committed
2142 2143 2144
    if (check_access(thd, want_priv, create_table->db,
		     &create_table->grant.privilege, 0, 0) ||
	check_merge_table_access(thd, create_table->db,
2145 2146
				 (TABLE_LIST *)
				 lex->create_info.merge_list.first))
unknown's avatar
unknown committed
2147
      goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
2148 2149
    if (grant_option && want_priv != CREATE_TMP_ACL &&
	check_grant(thd, want_priv, create_table,0,0))
unknown's avatar
unknown committed
2150
	goto error;
2151 2152 2153
#ifndef HAVE_READLINK
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
unknown's avatar
unknown committed
2154
    /* Fix names if symlinked tables */
unknown's avatar
unknown committed
2155
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
unknown's avatar
unknown committed
2156
			   create_table->real_name) ||
unknown's avatar
unknown committed
2157
	append_file_to_dir(thd,&lex->create_info.index_file_name,
unknown's avatar
unknown committed
2158
			   create_table->real_name))
unknown's avatar
unknown committed
2159 2160 2161 2162
    {
      res=-1;
      break;
    }
2163
#endif
2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176
    /*
      If we are using SET CHARSET without DEFAULT, add an implicite
      DEFAULT to not confuse old users. (This may change).
    */
    if ((lex->create_info.used_fields & 
	 (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
	HA_CREATE_USED_CHARSET)
    {
      lex->create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
      lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
      lex->create_info.default_table_charset= lex->create_info.table_charset;
      lex->create_info.table_charset= 0;
    }
2177
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
2178 2179 2180 2181
    {
      select_result *result;

      if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
unknown's avatar
unknown committed
2182 2183
	  find_real_table_in_list(tables, create_table->db,
				  create_table->real_name))
unknown's avatar
unknown committed
2184
      {
unknown's avatar
unknown committed
2185
	net_printf(thd,ER_UPDATE_TABLE_USED, create_table->real_name);
2186
	DBUG_RETURN(-1);
unknown's avatar
unknown committed
2187
      }
unknown's avatar
unknown committed
2188 2189
      if (tables && check_table_access(thd, SELECT_ACL, tables,0))
	goto error;				// Error message is given
2190
      select_lex->options|= SELECT_NO_UNLOCK;
2191 2192 2193 2194
      unit->offset_limit_cnt= select_lex->offset_limit;
      unit->select_limit_cnt= select_lex->select_limit+
	select_lex->offset_limit;
      if (unit->select_limit_cnt < select_lex->select_limit)
unknown's avatar
unknown committed
2195
	unit->select_limit_cnt= HA_POS_ERROR;	// No limit
2196

unknown's avatar
unknown committed
2197
      if (!(res=open_and_lock_tables(thd,tables)))
2198
      {
unknown's avatar
unknown committed
2199 2200 2201 2202
	res= -1;				// If error
        if ((result=new select_create(create_table->db,
                                      create_table->real_name,
				      &lex->create_info,
2203 2204 2205 2206 2207 2208
                                      lex->create_list,
                                      lex->key_list,
                                      select_lex->item_list,lex->duplicates)))
          res=handle_select(thd, lex, result);
      }
    }
unknown's avatar
unknown committed
2209 2210
    else // regular create
    {
unknown's avatar
unknown committed
2211
      if (lex->name)
unknown's avatar
unknown committed
2212
        res= mysql_create_like_table(thd, create_table, &lex->create_info, 
unknown's avatar
unknown committed
2213 2214
                                     (Table_ident *)lex->name); 
      else
2215
      {
unknown's avatar
unknown committed
2216 2217
        res= mysql_create_table(thd,create_table->db,
			         create_table->real_name, &lex->create_info,
unknown's avatar
unknown committed
2218 2219
			         lex->create_list,
			         lex->key_list,0,0,0); // do logging
2220
      }
unknown's avatar
unknown committed
2221
      if (!res)
2222
	send_ok(thd);
unknown's avatar
unknown committed
2223 2224
    }
    break;
unknown's avatar
unknown committed
2225
  }
unknown's avatar
unknown committed
2226 2227 2228
  case SQLCOM_CREATE_INDEX:
    if (!tables->db)
      tables->db=thd->db;
unknown's avatar
SCRUM:  
unknown committed
2229
    if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege,0,0))
unknown's avatar
unknown committed
2230
      goto error; /* purecov: inspected */
unknown's avatar
unknown committed
2231
    if (grant_option && check_grant(thd,INDEX_ACL,tables,0,0))
unknown's avatar
unknown committed
2232
      goto error;
2233
    thd->slow_command=TRUE;
2234 2235 2236 2237
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_create_index(thd, tables, lex->key_list);
unknown's avatar
unknown committed
2238 2239
    break;

unknown's avatar
unknown committed
2240
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2241
  case SQLCOM_SLAVE_START:
2242 2243 2244 2245
  {
    LOCK_ACTIVE_MI;
    start_slave(thd,active_mi,1 /* net report*/);
    UNLOCK_ACTIVE_MI;
unknown's avatar
unknown committed
2246
    break;
2247
  }
unknown's avatar
unknown committed
2248
  case SQLCOM_SLAVE_STOP:
2249 2250 2251 2252 2253 2254
  /*
    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,
2255
      so it waits for the client thread because t is locked by it.
2256
    - then the client thread does SLAVE STOP.
2257 2258
      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.
2259 2260 2261 2262 2263
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
  if (thd->locked_tables || thd->active_transaction())
  {
2264
    send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
2265
    goto error;
2266
  }
2267 2268 2269 2270
  {
    LOCK_ACTIVE_MI;
    stop_slave(thd,active_mi,1/* net report*/);
    UNLOCK_ACTIVE_MI;
unknown's avatar
unknown committed
2271
    break;
2272
  }
unknown's avatar
unknown committed
2273
#endif /* HAVE_REPLICATION */
2274

unknown's avatar
unknown committed
2275 2276
  case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
2277
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
2278
    goto error;
unknown's avatar
unknown committed
2279 2280
#else
    {
unknown's avatar
unknown committed
2281
      ulong priv=0;
unknown's avatar
unknown committed
2282
      if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
unknown's avatar
unknown committed
2283
      {
unknown's avatar
unknown committed
2284
	net_printf(thd, ER_WRONG_TABLE_NAME, lex->name);
unknown's avatar
unknown committed
2285 2286 2287
	res=0;
	break;
      }
2288 2289
      if (!tables->db)
	tables->db=thd->db;
2290 2291
      if (!select_lex->db)
	select_lex->db=tables->db;
unknown's avatar
SCRUM:  
unknown committed
2292 2293
      if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege,0,0) ||
	  check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0)||
unknown's avatar
unknown committed
2294
	  check_merge_table_access(thd, tables->db,
2295 2296 2297
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
2298 2299 2300 2301
      if (!tables->db)
	tables->db=thd->db;
      if (grant_option)
      {
unknown's avatar
unknown committed
2302
	if (check_grant(thd,ALTER_ACL,tables,0,0))
unknown's avatar
unknown committed
2303 2304 2305 2306 2307 2308
	  goto error;
	if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
	{					// Rename of table
	  TABLE_LIST tmp_table;
	  bzero((char*) &tmp_table,sizeof(tmp_table));
	  tmp_table.real_name=lex->name;
2309
	  tmp_table.db=select_lex->db;
unknown's avatar
unknown committed
2310
	  tmp_table.grant.privilege=priv;
unknown's avatar
unknown committed
2311
	  if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables,0,0))
unknown's avatar
unknown committed
2312 2313 2314
	    goto error;
	}
      }
unknown's avatar
unknown committed
2315 2316
      /* 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
2317
      /* ALTER TABLE ends previous transaction */
2318
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2319 2320
	res= -1;
      else
unknown's avatar
unknown committed
2321
      {
2322
        thd->slow_command=TRUE;
2323
	res= mysql_alter_table(thd, select_lex->db, lex->name,
unknown's avatar
unknown committed
2324 2325 2326
			       &lex->create_info,
			       tables, lex->create_list,
			       lex->key_list, lex->drop_list, lex->alter_list,
2327
			       select_lex->order_list.elements,
2328
                               (ORDER *) select_lex->order_list.first,
2329
			       lex->drop_primary, lex->duplicates,
unknown's avatar
unknown committed
2330 2331 2332
			       lex->alter_keys_onoff,
                               lex->tablespace_op,
			       lex->simple_alter);
unknown's avatar
unknown committed
2333
      }
unknown's avatar
unknown committed
2334 2335
      break;
    }
unknown's avatar
SCRUM:  
unknown committed
2336
#endif /*DONT_ALLOW_SHOW_COMMANDS*/
unknown's avatar
unknown committed
2337
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
2338 2339 2340
  {
    TABLE_LIST *table;
    if (check_db_used(thd,tables))
unknown's avatar
unknown committed
2341
      goto error;
unknown's avatar
unknown committed
2342 2343
    for (table=tables ; table ; table=table->next->next)
    {
unknown's avatar
unknown committed
2344
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
unknown's avatar
SCRUM:  
unknown committed
2345
		       &table->grant.privilege,0,0) ||
unknown's avatar
unknown committed
2346
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next->db,
unknown's avatar
SCRUM:  
unknown committed
2347
		       &table->next->grant.privilege,0,0))
unknown's avatar
unknown committed
2348 2349 2350
	goto error;
      if (grant_option)
      {
unknown's avatar
unknown committed
2351 2352 2353 2354
	TABLE_LIST old_list,new_list;
	old_list=table[0];
	new_list=table->next[0];
	old_list.next=new_list.next=0;
unknown's avatar
unknown committed
2355
	if (check_grant(thd,ALTER_ACL,&old_list,0,0) ||
unknown's avatar
unknown committed
2356
	    (!test_all_bits(table->next->grant.privilege,
2357
			    INSERT_ACL | CREATE_ACL) &&
unknown's avatar
unknown committed
2358
	     check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list,0,0)))
unknown's avatar
unknown committed
2359 2360 2361
	  goto error;
      }
    }
unknown's avatar
unknown committed
2362
    query_cache_invalidate3(thd, tables, 0);
2363 2364 2365
    if (end_active_trans(thd))
      res= -1;
    else if (mysql_rename_tables(thd,tables))
unknown's avatar
unknown committed
2366 2367
      res= -1;
    break;
unknown's avatar
unknown committed
2368
  }
2369
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2370 2371
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2372
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
2373
    goto error;
unknown's avatar
unknown committed
2374 2375
#else
    {
unknown's avatar
unknown committed
2376
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2377 2378 2379 2380
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
2381
#endif
2382
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2383
  case SQLCOM_SHOW_CREATE:
unknown's avatar
unknown committed
2384
#ifdef DONT_ALLOW_SHOW_COMMANDS
2385
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
2386
    goto error;
unknown's avatar
unknown committed
2387
#else
unknown's avatar
unknown committed
2388
    {
unknown's avatar
unknown committed
2389 2390
      if (check_db_used(thd, tables) ||
	  check_access(thd, SELECT_ACL | EXTRA_ACL, tables->db,
unknown's avatar
SCRUM:  
unknown committed
2391
		       &tables->grant.privilege,0,0))
unknown's avatar
unknown committed
2392
	goto error;
unknown's avatar
unknown committed
2393
      res = mysqld_show_create(thd, tables);
unknown's avatar
unknown committed
2394 2395
      break;
    }
unknown's avatar
unknown committed
2396
#endif
2397 2398 2399
  case SQLCOM_CHECKSUM:
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
SCRUM:  
unknown committed
2400
	check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
2401
      goto error; /* purecov: inspected */
2402
    res = mysql_checksum_table(thd, tables, &lex->check_opt);
2403 2404
    break;
  }
unknown's avatar
unknown committed
2405
  case SQLCOM_REPAIR:
2406 2407
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
SCRUM:  
unknown committed
2408
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
2409
      goto error; /* purecov: inspected */
2410
    thd->slow_command=TRUE;
2411
    res = mysql_repair_table(thd, tables, &lex->check_opt);
2412 2413 2414 2415 2416 2417 2418 2419 2420
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
      if (mysql_bin_log.is_open())
      {
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
        mysql_bin_log.write(&qinfo);
      }
    }
2421 2422
    break;
  }
unknown's avatar
unknown committed
2423
  case SQLCOM_CHECK:
2424 2425
  {
    if (check_db_used(thd,tables) ||
2426
	check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
2427
      goto error; /* purecov: inspected */
2428
    thd->slow_command=TRUE;
2429 2430 2431
    res = mysql_check_table(thd, tables, &lex->check_opt);
    break;
  }
unknown's avatar
unknown committed
2432 2433
  case SQLCOM_ANALYZE:
  {
unknown's avatar
unknown committed
2434
    if (check_db_used(thd,tables) ||
unknown's avatar
SCRUM:  
unknown committed
2435
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
unknown's avatar
unknown committed
2436
      goto error; /* purecov: inspected */
2437
    thd->slow_command=TRUE;
2438
    res = mysql_analyze_table(thd, tables, &lex->check_opt);
2439 2440 2441 2442 2443 2444 2445 2446 2447
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
      if (mysql_bin_log.is_open())
      {
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
        mysql_bin_log.write(&qinfo);
      }
    }
unknown's avatar
unknown committed
2448
    break;
unknown's avatar
unknown committed
2449
  }
2450

unknown's avatar
unknown committed
2451 2452 2453
  case SQLCOM_OPTIMIZE:
  {
    HA_CREATE_INFO create_info;
2454
    if (check_db_used(thd,tables) ||
unknown's avatar
SCRUM:  
unknown committed
2455
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
unknown's avatar
unknown committed
2456
      goto error; /* purecov: inspected */
2457
    thd->slow_command=TRUE;
2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468
    if (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC))
    {
      /* Use ALTER TABLE */
      lex->create_list.empty();
      lex->key_list.empty();
      lex->col_list.empty();
      lex->drop_list.empty();
      lex->alter_list.empty();
      bzero((char*) &create_info,sizeof(create_info));
      create_info.db_type=DB_TYPE_DEFAULT;
      create_info.row_type=ROW_TYPE_DEFAULT;
2469
      create_info.default_table_charset=default_charset_info;
2470 2471 2472
      res= mysql_alter_table(thd, NullS, NullS, &create_info,
			     tables, lex->create_list,
			     lex->key_list, lex->drop_list, lex->alter_list,
2473 2474
                             0, (ORDER *) 0,
			     0, DUP_ERROR);
2475 2476 2477
    }
    else
      res = mysql_optimize_table(thd, tables, &lex->check_opt);
2478 2479 2480 2481 2482 2483 2484 2485 2486
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
      if (mysql_bin_log.is_open())
      {
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
        mysql_bin_log.write(&qinfo);
      }
    }
unknown's avatar
unknown committed
2487 2488 2489
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
unknown committed
2490
    if (check_db_used(thd,tables))
unknown's avatar
unknown committed
2491
      goto error;
2492

unknown's avatar
unknown committed
2493
    if (single_table_command_access(thd, UPDATE_ACL, tables, &res))
unknown's avatar
unknown committed
2494
	goto error;
2495
    if (select_lex->item_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
2496
    {
2497
      send_error(thd,ER_WRONG_VALUE_COUNT);
2498
      goto error;
unknown's avatar
unknown committed
2499
    }
2500 2501 2502 2503
    res= mysql_update(thd,tables,
                      select_lex->item_list,
                      lex->value_list,
                      select_lex->where,
2504
		      select_lex->order_list.elements,
2505 2506 2507
                      (ORDER *) select_lex->order_list.first,
                      select_lex->select_limit,
                      lex->duplicates);
unknown's avatar
unknown committed
2508 2509
    if (thd->net.report_error)
      res= -1;
2510 2511
    break;
  case SQLCOM_UPDATE_MULTI:
unknown's avatar
SCRUM:  
unknown committed
2512
    if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege,0,0))
2513
      goto error;
unknown's avatar
unknown committed
2514
    if (grant_option && check_grant(thd,UPDATE_ACL,tables,0,0))
2515 2516
      goto error;
    if (select_lex->item_list.elements != lex->value_list.elements)
2517
    {
2518
      send_error(thd,ER_WRONG_VALUE_COUNT);
2519
      goto error;
2520 2521
    }
    {
unknown's avatar
unknown committed
2522
      const char *msg= 0;
unknown's avatar
unknown committed
2523
      if (select_lex->order_list.elements)
unknown's avatar
unknown committed
2524
	msg= "ORDER BY";
unknown's avatar
unknown committed
2525 2526
      else if (select_lex->select_limit && select_lex->select_limit !=
	       HA_POS_ERROR)
unknown's avatar
unknown committed
2527
	msg= "LIMIT";
unknown's avatar
unknown committed
2528
      if (msg)
2529
      {
2530
	net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg);
unknown's avatar
unknown committed
2531 2532
	res= 1;
	break;
2533
      }
unknown's avatar
unknown committed
2534 2535 2536 2537 2538
      res= mysql_multi_update(thd,tables,
			      &select_lex->item_list,
			      &lex->value_list,
			      select_lex->where,
			      select_lex->options,
unknown's avatar
unknown committed
2539
			      lex->duplicates, unit, select_lex);
2540
    }
unknown's avatar
unknown committed
2541 2542
    break;
  case SQLCOM_REPLACE:
2543 2544
  case SQLCOM_INSERT:
  {
2545
    my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
2546
    ulong privilege= (lex->duplicates == DUP_REPLACE ?
2547
                      INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
2548

unknown's avatar
unknown committed
2549
    if (single_table_command_access(thd, privilege, tables, &res))
2550
	goto error;
2551 2552 2553
    if (select_lex->item_list.elements != lex->value_list.elements)
    {
      send_error(thd,ER_WRONG_VALUE_COUNT);
2554
      goto error;
2555
    }
unknown's avatar
unknown committed
2556
    res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
2557
                       select_lex->item_list, lex->value_list,
unknown's avatar
SCRUM  
unknown committed
2558
                       (update ? DUP_UPDATE : lex->duplicates));
unknown's avatar
unknown committed
2559 2560
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2561
    break;
2562
  }
unknown's avatar
unknown committed
2563 2564 2565
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
unknown's avatar
unknown committed
2566 2567 2568 2569
    /*
      Check that we have modify privileges for the first table and
      select privileges for the rest
    */
2570
    {
2571 2572
      ulong privilege= (lex->duplicates == DUP_REPLACE ?
                        INSERT_ACL | DELETE_ACL : INSERT_ACL);
2573 2574 2575
      TABLE_LIST *save_next=tables->next;
      tables->next=0;
      if (check_access(thd, privilege,
unknown's avatar
SCRUM:  
unknown committed
2576
		       tables->db,&tables->grant.privilege,0,0) ||
unknown's avatar
unknown committed
2577
	  (grant_option && check_grant(thd, privilege, tables,0,0)))
2578
	goto error;
unknown's avatar
SCRUM:  
unknown committed
2579

2580
      tables->next=save_next;
unknown's avatar
SCRUM:  
unknown committed
2581
      if ((res=check_table_access(thd, SELECT_ACL, save_next,0)))
2582 2583
	goto error;
    }
unknown's avatar
unknown committed
2584

2585 2586
    /* Fix lock for first table */
    if (tables->lock_type == TL_WRITE_DELAYED)
2587
      tables->lock_type= TL_WRITE;
2588

2589 2590
    /* Don't unlock tables until command is written to binary log */
    select_lex->options|= SELECT_NO_UNLOCK;
unknown's avatar
unknown committed
2591 2592

    select_result *result;
2593 2594 2595 2596
    unit->offset_limit_cnt= select_lex->offset_limit;
    unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit;
    if (unit->select_limit_cnt < select_lex->select_limit)
      unit->select_limit_cnt= HA_POS_ERROR;		// No limit
unknown's avatar
unknown committed
2597

2598
    if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
2599
    {
2600 2601
      /* Using same table for INSERT and SELECT */
      select_lex->options |= OPTION_BUFFER_RESULT;
unknown's avatar
unknown committed
2602
    }
2603 2604 2605 2606

    /* Skip first table, which is the table we are inserting in */
    lex->select_lex.table_list.first=
      (byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
unknown's avatar
unknown committed
2607 2608
    lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE;

2609 2610 2611
    if (!(res=open_and_lock_tables(thd, tables)))
    {
      if ((result=new select_insert(tables->table,&lex->field_list,
2612
				    lex->duplicates)))
2613
	res=handle_select(thd,lex,result);
unknown's avatar
unknown committed
2614 2615
      if (thd->net.report_error)
	res= -1;
2616 2617 2618
    }
    else
      res= -1;
unknown's avatar
unknown committed
2619 2620
    break;
  }
2621
  case SQLCOM_TRUNCATE:
unknown's avatar
SCRUM:  
unknown committed
2622
    if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege,0,0))
2623
      goto error; /* purecov: inspected */
unknown's avatar
unknown committed
2624
    if (grant_option && check_grant(thd,DELETE_ACL,tables,0,0))
unknown's avatar
unknown committed
2625
      goto error;
2626 2627 2628 2629 2630 2631
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
    if (thd->locked_tables || thd->active_transaction())
    {
2632
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
2633 2634 2635 2636
      goto error;
    }
    res=mysql_truncate(thd,tables);
    break;
unknown's avatar
unknown committed
2637
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
2638
  {
unknown's avatar
unknown committed
2639 2640
    if (single_table_command_access(thd, DELETE_ACL, tables, &res))
      goto error;
unknown's avatar
unknown committed
2641 2642
    // Set privilege for the WHERE clause
    tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
2643
    res = mysql_delete(thd,tables, select_lex->where,
2644
                       &select_lex->order_list,
unknown's avatar
unknown committed
2645
                       select_lex->select_limit, select_lex->options);
unknown's avatar
unknown committed
2646 2647
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2648 2649
    break;
  }
unknown's avatar
unknown committed
2650
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
2651
  {
2652
    TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
unknown's avatar
unknown committed
2653 2654 2655
    TABLE_LIST *auxi;
    uint table_count=0;
    multi_delete *result;
unknown's avatar
unknown committed
2656

unknown's avatar
unknown committed
2657 2658
    /* sql_yacc guarantees that tables and aux_tables are not zero */
    if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
unknown's avatar
SCRUM:  
unknown committed
2659 2660
	check_table_access(thd,SELECT_ACL, tables,0) ||
	check_table_access(thd,DELETE_ACL, aux_tables,0))
unknown's avatar
unknown committed
2661 2662
      goto error;
    if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
2663
    {
2664
      send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
unknown's avatar
unknown committed
2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679
      goto error;
    }
    for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
    {
      table_count++;
      /* All tables in aux_tables must be found in FROM PART */
      TABLE_LIST *walk;
      for (walk=(TABLE_LIST*) tables ; walk ; walk=walk->next)
      {
	if (!strcmp(auxi->real_name,walk->real_name) &&
	    !strcmp(walk->db,auxi->db))
	  break;
      }
      if (!walk)
      {
2680
	net_printf(thd,ER_NONUNIQ_TABLE,auxi->real_name);
unknown's avatar
unknown committed
2681 2682
	goto error;
      }
unknown's avatar
unknown committed
2683
      walk->lock_type= auxi->lock_type;
2684
      auxi->table_list=  walk;		// Remember corresponding table
2685
    }
unknown's avatar
unknown committed
2686
    if (add_item_to_list(thd, new Item_null()))
2687
    {
unknown's avatar
unknown committed
2688
      res= -1;
2689
      break;
unknown's avatar
unknown committed
2690 2691 2692 2693 2694 2695
    }
    thd->proc_info="init";
    if ((res=open_and_lock_tables(thd,tables)))
      break;
    /* Fix tables-to-be-deleted-from list to point at opened tables */
    for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
2696
      auxi->table= auxi->table_list->table;
2697
    if (&lex->select_lex != lex->all_selects_list)
unknown's avatar
unknown committed
2698
    {
2699 2700 2701 2702 2703
      for (TABLE_LIST *t= select_lex->get_table_list();
	   t; t= t->next)
      {
	if (find_real_table_in_list(t->table_list->next, t->db, t->real_name))
	{
unknown's avatar
unknown committed
2704
	  my_error(ER_UPDATE_TABLE_USED, MYF(0), t->real_name);
2705 2706 2707 2708
	  res= -1;
	  break;
	}
      }
unknown's avatar
unknown committed
2709
    }
unknown's avatar
unknown committed
2710
    fix_tables_pointers(lex->all_selects_list);
2711 2712
    if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
							  table_count)))
unknown's avatar
unknown committed
2713
    {
2714 2715 2716
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
unknown's avatar
unknown committed
2717
			select_lex->item_list,
unknown's avatar
unknown committed
2718
			select_lex->where,
2719
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
unknown's avatar
unknown committed
2720 2721
			(ORDER *)NULL,
			select_lex->options | thd->options |
unknown's avatar
unknown committed
2722
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
2723
			result, unit, select_lex);
unknown's avatar
unknown committed
2724 2725
      if (thd->net.report_error)
	res= -1;
2726
      delete result;
unknown's avatar
unknown committed
2727 2728 2729 2730 2731 2732
    }
    else
      res= -1;					// Error is not sent
    close_thread_tables(thd);
    break;
  }
unknown's avatar
unknown committed
2733
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
2734
  {
2735 2736
    if (!lex->drop_temporary)
    {
unknown's avatar
SCRUM:  
unknown committed
2737
      if (check_table_access(thd,DROP_ACL,tables,0))
2738 2739 2740 2741 2742 2743 2744
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
unknown's avatar
unknown committed
2745
    else
unknown's avatar
unknown committed
2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757
    {
      /*
	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.
	To not generate such irrelevant "table does not exist errors", we
	silently add IF EXISTS if TEMPORARY was used.
      */
      if (thd->slave_thread)
	lex->drop_if_exists= 1;
    }
2758
    res= mysql_rm_table(thd,tables,lex->drop_if_exists, lex->drop_temporary);
unknown's avatar
unknown committed
2759 2760
  }
  break;
unknown's avatar
unknown committed
2761 2762 2763
  case SQLCOM_DROP_INDEX:
    if (!tables->db)
      tables->db=thd->db;
unknown's avatar
SCRUM:  
unknown committed
2764
    if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege,0,0))
unknown's avatar
unknown committed
2765
      goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
2766
    if (grant_option && check_grant(thd,INDEX_ACL,tables,0,0))
unknown's avatar
unknown committed
2767
      goto error;
2768 2769 2770 2771
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_drop_index(thd, tables, lex->drop_list);
unknown's avatar
unknown committed
2772 2773
    break;
  case SQLCOM_SHOW_DATABASES:
2774
#if defined(DONT_ALLOW_SHOW_COMMANDS)
2775
    send_error(thd,ER_NOT_ALLOWED_COMMAND);   /* purecov: inspected */
2776
    goto error;
unknown's avatar
unknown committed
2777 2778
#else
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
unknown's avatar
unknown committed
2779
	check_global_access(thd, SHOW_DB_ACL))
unknown's avatar
unknown committed
2780 2781 2782 2783 2784
      goto error;
    res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
    break;
#endif
  case SQLCOM_SHOW_PROCESSLIST:
unknown's avatar
unknown committed
2785
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
2786
      break;
unknown's avatar
SCRUM:  
unknown committed
2787 2788
    mysqld_list_processes(thd,
			  thd->master_access & PROCESS_ACL ? NullS :
unknown's avatar
unknown committed
2789
			  thd->priv_user,lex->verbose);
unknown's avatar
unknown committed
2790
    break;
unknown's avatar
unknown committed
2791 2792
  case SQLCOM_SHOW_STORAGE_ENGINES:
    res= mysqld_show_storage_engines(thd);
unknown's avatar
unknown committed
2793 2794 2795 2796 2797 2798 2799
    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
2800
  case SQLCOM_SHOW_STATUS:
2801
    res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
2802
		     OPT_GLOBAL, &LOCK_status);
unknown's avatar
unknown committed
2803 2804 2805
    break;
  case SQLCOM_SHOW_VARIABLES:
    res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
2806 2807
		     init_vars, lex->option_type,
		     &LOCK_global_system_variables);
unknown's avatar
unknown committed
2808
    break;
unknown's avatar
unknown committed
2809 2810
  case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2811
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
2812
    goto error;
unknown's avatar
unknown committed
2813 2814
#else
    {
unknown's avatar
SCRUM:  
unknown committed
2815
      if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0))
unknown's avatar
unknown committed
2816 2817 2818 2819 2820
	goto error;
      res= mysqld_show_logs(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
2821
  case SQLCOM_SHOW_TABLES:
2822
    /* FALL THROUGH */
unknown's avatar
unknown committed
2823
#ifdef DONT_ALLOW_SHOW_COMMANDS
2824
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
2825
    goto error;
unknown's avatar
unknown committed
2826 2827
#else
    {
2828
      char *db=select_lex->db ? select_lex->db : thd->db;
unknown's avatar
unknown committed
2829 2830
      if (!db)
      {
2831
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
unknown's avatar
unknown committed
2832 2833 2834
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);				// Fix escaped '_'
unknown's avatar
unknown committed
2835
      if (check_db_name(db))
unknown's avatar
unknown committed
2836
      {
unknown's avatar
unknown committed
2837
        net_printf(thd,ER_WRONG_DB_NAME, db);
unknown's avatar
unknown committed
2838
        goto error;
unknown's avatar
unknown committed
2839
      }
unknown's avatar
SCRUM:  
unknown committed
2840
      if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
unknown's avatar
unknown committed
2841
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
2842
      if (!thd->col_access && check_grant_db(thd,db))
unknown's avatar
unknown committed
2843
      {
unknown's avatar
unknown committed
2844
	net_printf(thd, ER_DBACCESS_DENIED_ERROR,
unknown's avatar
unknown committed
2845 2846 2847 2848 2849
		   thd->priv_user,
		   thd->priv_host,
		   db);
	goto error;
      }
unknown's avatar
unknown committed
2850
      /* grant is checked in mysqld_show_tables */
2851
      if (select_lex->options & SELECT_DESCRIBE)
2852
        res= mysqld_extend_show_tables(thd,db,
2853
				       (lex->wild ? lex->wild->ptr() : NullS));
unknown's avatar
unknown committed
2854 2855 2856 2857 2858 2859
      else
	res= mysqld_show_tables(thd,db,
				(lex->wild ? lex->wild->ptr() : NullS));
      break;
    }
#endif
2860 2861 2862
  case SQLCOM_SHOW_OPEN_TABLES:
    res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
2863 2864
  case SQLCOM_SHOW_CHARSETS:
    res= mysqld_show_charsets(thd,(lex->wild ? lex->wild->ptr() : NullS));
2865
    break;
2866 2867 2868
  case SQLCOM_SHOW_COLLATIONS:
    res= mysqld_show_collations(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
unknown's avatar
unknown committed
2869 2870
  case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2871
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
2872
    goto error;
unknown's avatar
unknown committed
2873 2874
#else
    {
2875 2876
      char *db=tables->db;
      if (!*db)
unknown's avatar
unknown committed
2877
      {
2878
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
unknown's avatar
unknown committed
2879 2880 2881
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);			// Fix escaped '_'
2882
      remove_escape(tables->real_name);
unknown's avatar
SCRUM:  
unknown committed
2883
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access,0,0))
unknown's avatar
unknown committed
2884 2885
	goto error;				/* purecov: inspected */
      tables->grant.privilege=thd->col_access;
unknown's avatar
unknown committed
2886
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2,0))
unknown's avatar
unknown committed
2887 2888
	goto error;
      res= mysqld_show_fields(thd,tables,
unknown's avatar
unknown committed
2889 2890
			      (lex->wild ? lex->wild->ptr() : NullS),
			      lex->verbose);
unknown's avatar
unknown committed
2891 2892 2893 2894 2895
      break;
    }
#endif
  case SQLCOM_SHOW_KEYS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2896
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
2897
    goto error;
unknown's avatar
unknown committed
2898 2899
#else
    {
2900
      char *db=tables->db;
unknown's avatar
unknown committed
2901 2902
      if (!db)
      {
2903
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
unknown's avatar
unknown committed
2904 2905 2906
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);			// Fix escaped '_'
2907
      remove_escape(tables->real_name);
unknown's avatar
unknown committed
2908 2909
      if (!tables->db)
	tables->db=thd->db;
unknown's avatar
SCRUM:  
unknown committed
2910
      if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
unknown's avatar
unknown committed
2911 2912
	goto error; /* purecov: inspected */
      tables->grant.privilege=thd->col_access;
unknown's avatar
unknown committed
2913
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2,0))
unknown's avatar
unknown committed
2914 2915 2916 2917 2918 2919
	goto error;
      res= mysqld_show_keys(thd,tables);
      break;
    }
#endif
  case SQLCOM_CHANGE_DB:
2920
    mysql_change_db(thd,select_lex->db);
unknown's avatar
unknown committed
2921
    break;
2922

unknown's avatar
unknown committed
2923 2924 2925
  case SQLCOM_LOAD:
  {
    uint privilege= (lex->duplicates == DUP_REPLACE ?
2926
		     INSERT_ACL | DELETE_ACL : INSERT_ACL);
2927 2928

    if (!lex->local_file)
unknown's avatar
unknown committed
2929
    {
unknown's avatar
SCRUM:  
unknown committed
2930
      if (check_access(thd,privilege | FILE_ACL,tables->db,0,0,0))
unknown's avatar
unknown committed
2931 2932 2933 2934
	goto error;
    }
    else
    {
2935
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
unknown's avatar
unknown committed
2936
	  ! opt_local_infile)
2937
      {
2938
	send_error(thd,ER_NOT_ALLOWED_COMMAND);
2939 2940
	goto error;
      }
unknown's avatar
unknown committed
2941 2942 2943
      if (check_access(thd,privilege,tables->db,&tables->grant.privilege,0,
		       0) ||
	  grant_option && check_grant(thd,privilege,tables,0,0))
unknown's avatar
unknown committed
2944 2945 2946 2947 2948 2949
	goto error;
    }
    res=mysql_load(thd, lex->exchange, tables, lex->field_list,
		   lex->duplicates, (bool) lex->local_file, lex->lock_option);
    break;
  }
2950

unknown's avatar
unknown committed
2951
  case SQLCOM_SET_OPTION:
unknown's avatar
SCRUM:  
unknown committed
2952
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
unknown's avatar
unknown committed
2953 2954 2955 2956
		   (res= open_and_lock_tables(thd,tables))))
      break;
    fix_tables_pointers(lex->all_selects_list);
    if (!(res= sql_set_variables(thd, &lex->var_list)))
2957
      send_ok(thd);
unknown's avatar
unknown committed
2958 2959
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2960
    break;
unknown's avatar
unknown committed
2961

unknown's avatar
unknown committed
2962
  case SQLCOM_UNLOCK_TABLES:
unknown's avatar
unknown committed
2963
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
2964 2965
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
2966
      end_active_trans(thd);
unknown's avatar
unknown committed
2967
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
2968 2969
    }
    if (thd->global_read_lock)
2970
      unlock_global_read_lock(thd);
2971
    send_ok(thd);
unknown's avatar
unknown committed
2972 2973
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
2974
    unlock_locked_tables(thd);
2975
    if (check_db_used(thd,tables) || end_active_trans(thd))
unknown's avatar
unknown committed
2976
      goto error;
unknown's avatar
SCRUM:  
unknown committed
2977
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables,0))
2978
      goto error;
unknown's avatar
unknown committed
2979
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
2980
    thd->options|= OPTION_TABLE_LOCK;
unknown's avatar
unknown committed
2981 2982 2983 2984
    if (!(res=open_and_lock_tables(thd,tables)))
    {
      thd->locked_tables=thd->lock;
      thd->lock=0;
2985
      send_ok(thd);
unknown's avatar
unknown committed
2986
    }
unknown's avatar
unknown committed
2987 2988
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
2989 2990 2991
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
2992
  {
unknown's avatar
unknown committed
2993
    if (!strip_sp(lex->name) || check_db_name(lex->name))
unknown's avatar
unknown committed
2994
    {
unknown's avatar
unknown committed
2995
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
2996 2997
      break;
    }
2998 2999 3000 3001 3002 3003 3004
    /*
      If in a slave thread :
      CREATE DATABASE DB was certainly not preceded by USE DB.
      For that reason, db_ok() in sql/slave.cc did not check the 
      do_db/ignore_db. And as this query involves no tables, tables_ok()
      above was not called. So we have to check rules again here.
    */
3005
#ifdef HAVE_REPLICATION
3006 3007 3008
    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
3009 3010
    {
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
3011
      break;
unknown's avatar
Fix for  
unknown committed
3012
    }
3013
#endif
unknown's avatar
SCRUM:  
unknown committed
3014
    if (check_access(thd,CREATE_ACL,lex->name,0,1,0))
3015
      break;
3016
    res=mysql_create_db(thd,lex->name,&lex->create_info,0);
3017 3018
    break;
  }
unknown's avatar
unknown committed
3019
  case SQLCOM_DROP_DB:
3020
  {
unknown's avatar
unknown committed
3021
    if (!strip_sp(lex->name) || check_db_name(lex->name))
unknown's avatar
unknown committed
3022
    {
unknown's avatar
unknown committed
3023
      net_printf(thd, ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
3024 3025
      break;
    }
3026 3027 3028 3029 3030 3031 3032
    /*
      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.
    */
3033
#ifdef HAVE_REPLICATION
3034 3035 3036
    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
3037 3038
    {
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
3039
      break;
unknown's avatar
Fix for  
unknown committed
3040
    }
3041
#endif
unknown's avatar
SCRUM:  
unknown committed
3042
    if (check_access(thd,DROP_ACL,lex->name,0,1,0))
3043
      break;
3044 3045
    if (thd->locked_tables || thd->active_transaction())
    {
3046
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
3047 3048
      goto error;
    }
unknown's avatar
unknown committed
3049
    res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0);
3050 3051
    break;
  }
3052 3053 3054 3055
  case SQLCOM_ALTER_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
unknown's avatar
unknown committed
3056
      net_printf(thd, ER_WRONG_DB_NAME, lex->name);
3057 3058
      break;
    }
unknown's avatar
SCRUM:  
unknown committed
3059
    if (check_access(thd,ALTER_ACL,lex->name,0,1,0))
3060 3061 3062
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
3063
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
3064 3065
      goto error;
    }
3066
    res=mysql_alter_db(thd,lex->name,&lex->create_info);
3067 3068
    break;
  }
unknown's avatar
unknown committed
3069 3070 3071 3072
  case SQLCOM_SHOW_CREATE_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
unknown's avatar
unknown committed
3073
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
3074 3075
      break;
    }
unknown's avatar
SCRUM:  
unknown committed
3076
    if (check_access(thd,DROP_ACL,lex->name,0,1,0))
unknown's avatar
unknown committed
3077 3078 3079
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
3080
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
3081 3082
      goto error;
    }
unknown's avatar
unknown committed
3083
    res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
unknown's avatar
unknown committed
3084 3085
    break;
  }
3086
  case SQLCOM_CREATE_FUNCTION:	// UDF function
unknown's avatar
unknown committed
3087 3088 3089 3090
  {
    sp_head *sph;
    if (check_access(thd,INSERT_ACL,"mysql",0,1,0))
      break;
unknown's avatar
unknown committed
3091
#ifdef HAVE_DLOPEN
unknown's avatar
unknown committed
3092
    if ((sph= sp_find_function(thd, &lex->udf.name)))
unknown's avatar
unknown committed
3093 3094 3095 3096 3097 3098
    {
      net_printf(thd, ER_UDF_EXISTS, lex->udf.name.str);
      goto error;
    }
    if (!(res = mysql_create_function(thd,&lex->udf)))
      send_ok(thd);
unknown's avatar
unknown committed
3099
#else
unknown's avatar
unknown committed
3100
    res= -1;
unknown's avatar
unknown committed
3101 3102
#endif
    break;
unknown's avatar
unknown committed
3103
  }
unknown's avatar
SCRUM:  
unknown committed
3104
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3105 3106
  case SQLCOM_DROP_USER:
  {
unknown's avatar
SCRUM:  
unknown committed
3107
    if (check_access(thd, GRANT_ACL,"mysql",0,1,0))
3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121
      break;
    if (!(res= mysql_drop_user(thd, lex->users_list)))
    {
      if (mysql_bin_log.is_open())
      {
	Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
	mysql_bin_log.write(&qinfo);
      }
      send_ok(thd);
    }
    break;
  }
  case SQLCOM_REVOKE_ALL:
  {
unknown's avatar
SCRUM:  
unknown committed
3122
    if (check_access(thd, GRANT_ACL ,"mysql",0,1,0))
3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134
      break;
    if (!(res = mysql_revoke_all(thd, lex->users_list)))
    {
      if (mysql_bin_log.is_open())
      {
	Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
	mysql_bin_log.write(&qinfo);
      }
      send_ok(thd);
    }
    break;
  }
3135 3136 3137 3138 3139 3140
  case SQLCOM_REVOKE:
  case SQLCOM_GRANT:
  {
    if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
		     tables && tables->db ? tables->db : select_lex->db,
		     tables ? &tables->grant.privilege : 0,
unknown's avatar
SCRUM:  
unknown committed
3141
		     tables ? 0 : 1,0))
3142 3143
      goto error;

unknown's avatar
unknown committed
3144 3145 3146 3147
    /*
      Check that the user isn't trying to change a password for another
      user if he doesn't have UPDATE privilege to the MySQL database
    */
3148 3149 3150 3151 3152 3153 3154 3155 3156 3157

    if (thd->user)				// If not replication
    {
      LEX_USER *user;
      List_iterator <LEX_USER> user_list(lex->users_list);
      while ((user=user_list++))
      {
	if (user->password.str &&
	    (strcmp(thd->user,user->user.str) ||
	     user->host.str &&
unknown's avatar
unknown committed
3158
	     my_strcasecmp(&my_charset_latin1,
3159
                           user->host.str, thd->host_or_ip)))
3160
	{
unknown's avatar
SCRUM:  
unknown committed
3161
	  if (check_access(thd, UPDATE_ACL, "mysql",0,1,0))
3162 3163 3164 3165 3166
	    goto error;
	  break;			// We are allowed to do changes
	}
      }
    }
unknown's avatar
SCRUM  
unknown committed
3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179
    if (specialflag & SPECIAL_NO_RESOLVE)
    {
      LEX_USER *user;
      List_iterator <LEX_USER> user_list(lex->users_list);
      while ((user=user_list++))
      {
	if (hostname_requires_resolving(user->host.str))
	  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
			      ER_WARN_HOSTNAME_WONT_WORK,
			      ER(ER_WARN_HOSTNAME_WONT_WORK),
			      user->host.str);
      }
    }
3180 3181 3182 3183 3184
    if (tables)
    {
      if (grant_option && check_grant(thd,
				      (lex->grant | lex->grant_tot_col |
				       GRANT_ACL),
unknown's avatar
unknown committed
3185
				      tables,0,0))
3186
	goto error;
unknown's avatar
unknown committed
3187 3188
      if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
				    lex->grant,
3189 3190
				    lex->sql_command == SQLCOM_REVOKE)) &&
          mysql_bin_log.is_open())
3191
      {
unknown's avatar
unknown committed
3192
        thd->clear_error();
3193 3194
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
        mysql_bin_log.write(&qinfo);
3195 3196 3197 3198 3199 3200
      }
    }
    else
    {
      if (lex->columns.elements)
      {
3201
	send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE);
3202 3203 3204 3205 3206 3207 3208 3209 3210
	res=1;
      }
      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
3211
          thd->clear_error();
3212
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
3213 3214
	  mysql_bin_log.write(&qinfo);
	}
3215
	if (mqh_used && lex->sql_command == SQLCOM_GRANT)
unknown's avatar
unknown committed
3216
	{
unknown's avatar
unknown committed
3217 3218 3219
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
3220
	    reset_mqh(thd,user);
unknown's avatar
unknown committed
3221
	}
3222 3223 3224 3225
      }
    }
    break;
  }
unknown's avatar
SCRUM  
unknown committed
3226
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
unknown's avatar
unknown committed
3227
  case SQLCOM_RESET:
3228 3229 3230 3231 3232 3233 3234
    /* 
       RESET commands are never written to the binary log, so we have to
       initialize this variable because RESET shares the same code as FLUSH
    */
    lex->no_write_to_binlog= 1;
  case SQLCOM_FLUSH:
  {
unknown's avatar
unknown committed
3235
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
unknown's avatar
unknown committed
3236
      goto error;
3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259
    /*
      reload_acl_and_cache() will tell us if we are allowed to write to the
      binlog or not.
    */
    bool write_to_binlog;
    if (reload_acl_and_cache(thd, lex->type, tables, &write_to_binlog))
      send_error(thd, 0);
    else
    {
      /*
        We WANT to write and we CAN write.
        ! we write after unlocking the table.
      */
      if (!lex->no_write_to_binlog && write_to_binlog)
      {
        if (mysql_bin_log.is_open())
        {
          Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
          mysql_bin_log.write(&qinfo);
        }
      }
      send_ok(thd);
    }
unknown's avatar
unknown committed
3260
    break;
3261
  }
unknown's avatar
unknown committed
3262
  case SQLCOM_KILL:
unknown's avatar
SCRUM  
unknown committed
3263
    kill_one_thread(thd,lex->thread_id, lex->type & ONLY_KILL_QUERY);
unknown's avatar
unknown committed
3264
    break;
unknown's avatar
SCRUM:  
unknown committed
3265
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
3266 3267
  case SQLCOM_SHOW_GRANTS:
    res=0;
3268 3269
    if ((thd->priv_user &&
	 !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
unknown's avatar
SCRUM:  
unknown committed
3270
	!check_access(thd, SELECT_ACL, "mysql",0,1,0))
unknown's avatar
unknown committed
3271 3272 3273 3274
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
unknown's avatar
SCRUM:  
unknown committed
3275
#endif
3276
  case SQLCOM_HA_OPEN:
3277
    if (check_db_used(thd,tables) ||
unknown's avatar
SCRUM:  
unknown committed
3278
	check_table_access(thd,SELECT_ACL, tables,0))
3279 3280 3281 3282 3283 3284 3285 3286 3287
      goto error;
    res = mysql_ha_open(thd, tables);
    break;
  case SQLCOM_HA_CLOSE:
    if (check_db_used(thd,tables))
      goto error;
    res = mysql_ha_close(thd, tables);
    break;
  case SQLCOM_HA_READ:
3288 3289 3290 3291 3292
    /*
      There is no need to check for table permissions here, because
      if a user has no permissions to read a table, he won't be
      able to open it (with SQLCOM_HA_OPEN) in the first place.
    */
unknown's avatar
unknown committed
3293
    if (check_db_used(thd,tables))
3294
      goto error;
unknown's avatar
unknown committed
3295
    res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
3296 3297
			lex->insert_list, lex->ha_rkey_mode, select_lex->where,
			select_lex->select_limit, select_lex->offset_limit);
3298 3299
    break;

unknown's avatar
unknown committed
3300
  case SQLCOM_BEGIN:
unknown's avatar
unknown committed
3301 3302 3303 3304 3305 3306
    if (thd->locked_tables)
    {
      thd->lock=thd->locked_tables;
      thd->locked_tables=0;			// Will be automaticly closed
      close_thread_tables(thd);			// Free tables
    }
unknown's avatar
unknown committed
3307 3308 3309 3310 3311 3312
    if (end_active_trans(thd))
    {
      res= -1;
    }
    else
    {
3313
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
unknown's avatar
unknown committed
3314 3315
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
3316
      send_ok(thd);
unknown's avatar
unknown committed
3317
    }
unknown's avatar
unknown committed
3318 3319
    break;
  case SQLCOM_COMMIT:
3320 3321 3322 3323 3324
    /*
      We don't use end_active_trans() here to ensure that this works
      even if there is a problem with the OPTION_AUTO_COMMIT flag
      (Which of course should never happen...)
    */
unknown's avatar
unknown committed
3325
  {
3326
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
3327 3328
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
unknown's avatar
unknown committed
3329
    {
3330
      send_ok(thd);
unknown's avatar
unknown committed
3331
    }
unknown's avatar
unknown committed
3332 3333 3334
    else
      res= -1;
    break;
unknown's avatar
unknown committed
3335
  }
unknown's avatar
unknown committed
3336 3337 3338
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
3339
    {
unknown's avatar
unknown committed
3340 3341 3342 3343 3344 3345 3346 3347 3348 3349
      /*
        If a non-transactional table was updated, warn; don't warn if this is a
        slave thread (because when a slave thread executes a ROLLBACK, it has
        been read from the binary log, so it's 100% sure and normal to produce
        error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
        slave SQL thread, it would not stop the thread but just be printed in
        the error log; but we don't want users to wonder why they have this
        message in the error log, so we don't send it.
      */
      if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
3350
	send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
3351
      else
3352
	send_ok(thd);
3353
    }
unknown's avatar
unknown committed
3354 3355
    else
      res= -1;
3356
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
3357
    break;
unknown's avatar
unknown committed
3358 3359 3360
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
    if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
    {
unknown's avatar
unknown committed
3361
      if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
unknown's avatar
unknown committed
3362
	send_warning(thd, ER_WARNING_NOT_COMPLETE_ROLLBACK, 0);
unknown's avatar
unknown committed
3363
      else
unknown's avatar
unknown committed
3364
	send_ok(thd);
unknown's avatar
unknown committed
3365 3366 3367 3368
    }
    else
      res= -1;
    break;
3369
  case SQLCOM_SAVEPOINT:
unknown's avatar
unknown committed
3370
    if (!ha_savepoint(thd, lex->savepoint_name))
unknown's avatar
unknown committed
3371
      send_ok(thd);
unknown's avatar
unknown committed
3372 3373
    else
      res= -1;
3374
    break;
3375 3376
  case SQLCOM_CREATE_PROCEDURE:
  case SQLCOM_CREATE_SPFUNCTION:
unknown's avatar
unknown committed
3377
  {
3378
    if (!lex->sphead)
3379
    {
3380 3381
      res= -1;			// Shouldn't happen
      break;
3382
    }
unknown's avatar
unknown committed
3383 3384
    uint namelen;
    char *name= lex->sphead->name(&namelen);
3385
#ifdef HAVE_DLOPEN
unknown's avatar
unknown committed
3386 3387 3388
    if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
    {
      udf_func *udf = find_udf(name, namelen);
3389

unknown's avatar
unknown committed
3390
      if (udf)
3391
      {
unknown's avatar
unknown committed
3392
	net_printf(thd, ER_UDF_EXISTS, name);
unknown's avatar
unknown committed
3393
	delete lex->sphead;
unknown's avatar
unknown committed
3394
	lex->sphead=0;
3395
	goto error;
3396
      }
unknown's avatar
unknown committed
3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413
    }
#endif
    if (lex->sphead->m_type == TYPE_ENUM_FUNCTION &&
	!lex->sphead->m_has_return)
    {
      net_printf(thd, ER_SP_NORETURN, name);
      delete lex->sphead;
      lex->sphead=0;
      goto error;
    }

    res= lex->sphead->create(thd);
    switch (res) {
    case SP_OK:
      send_ok(thd);
      delete lex->sphead;
      lex->sphead= 0;
3414
      break;
unknown's avatar
unknown committed
3415 3416 3417 3418 3419 3420 3421 3422 3423 3424
    case SP_WRITE_ROW_FAILED:
      net_printf(thd, ER_SP_ALREADY_EXISTS, SP_TYPE_STRING(lex), name);
      delete lex->sphead;
      lex->sphead= 0;
      goto error;
    default:
      net_printf(thd, ER_SP_STORE_FAILED, SP_TYPE_STRING(lex), name);
      delete lex->sphead;
      lex->sphead= 0;
      goto error;
3425
    }
unknown's avatar
unknown committed
3426 3427
    break;
  }
3428 3429 3430 3431
  case SQLCOM_CALL:
    {
      sp_head *sp;

unknown's avatar
unknown committed
3432
      if (!(sp= sp_find_procedure(thd, &lex->udf.name)))
3433
      {
3434
	net_printf(thd, ER_SP_DOES_NOT_EXIST, "PROCEDURE", lex->udf.name);
3435
	goto error;
3436 3437 3438
      }
      else
      {
3439
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3440
	st_sp_security_context save_ctx;
3441
#endif
3442 3443 3444
	uint smrx;
	LINT_INIT(smrx);

unknown's avatar
unknown committed
3445
	// In case the arguments are subselects...
unknown's avatar
unknown committed
3446
	if (tables && ((res= check_table_access(thd, SELECT_ACL, tables, 0)) ||
unknown's avatar
unknown committed
3447 3448
		       (res= open_and_lock_tables(thd, tables))))
	{
3449
	  break;
unknown's avatar
unknown committed
3450
	}
3451 3452
	fix_tables_pointers(lex->all_selects_list);

3453
#ifndef EMBEDDED_LIBRARY
3454 3455 3456 3457
	// When executing substatements, they're assumed to send_error when
	// it happens, but not to send_ok.
	my_bool nsok= thd->net.no_send_ok;
	thd->net.no_send_ok= TRUE;
3458
#endif
3459
	if (sp->m_multi_results)
3460
	{
3461
	  if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472
	  {
	    send_error(thd, ER_SP_BADSELECT);
#ifndef EMBEDDED_LIBRARY
	    thd->net.no_send_ok= nsok;
#endif
	    goto error;
	  }
	  smrx= thd->server_status & SERVER_MORE_RESULTS_EXISTS;
	  thd->server_status |= SERVER_MORE_RESULTS_EXISTS;
	}

3473
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3474
	sp_change_security_context(thd, sp, &save_ctx);
3475
#endif
3476

3477
	res= sp->execute_procedure(thd, &lex->value_list);
3478

3479
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3480
	sp_restore_security_context(thd, sp, &save_ctx);
3481
#endif
3482

3483
#ifndef EMBEDDED_LIBRARY
3484
	thd->net.no_send_ok= nsok;
3485
#endif
3486
	if (sp->m_multi_results)
3487 3488 3489 3490
	{
	  if (! smrx)
	    thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
	}
3491

3492 3493
	if (res == 0)
	  send_ok(thd);
3494 3495
	else
	  goto error;		// Substatement should already have sent error
3496
      }
3497
      break;
3498 3499
    }
  case SQLCOM_ALTER_PROCEDURE:
3500
  case SQLCOM_ALTER_FUNCTION:
3501
    {
unknown's avatar
unknown committed
3502 3503 3504 3505 3506
      res= -1;
      uint newname_len= 0;
      if (lex->name)
	newname_len= strlen(lex->name);
      if (newname_len > NAME_LEN)
3507
      {
unknown's avatar
unknown committed
3508
	net_printf(thd, ER_TOO_LONG_IDENT, lex->name);
3509
	goto error;
3510
      }
unknown's avatar
unknown committed
3511 3512
      if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
	res= sp_update_procedure(thd, lex->udf.name.str, lex->udf.name.length,
3513
				 lex->name, newname_len, &lex->sp_chistics);
3514
      else
unknown's avatar
unknown committed
3515
	res= sp_update_function(thd, lex->udf.name.str, lex->udf.name.length,
3516
				lex->name, newname_len,	&lex->sp_chistics);
unknown's avatar
unknown committed
3517
      switch (res)
3518
      {
unknown's avatar
unknown committed
3519
      case SP_OK:
3520
	send_ok(thd);
unknown's avatar
unknown committed
3521 3522 3523 3524 3525 3526 3527
	break;
      case SP_KEY_NOT_FOUND:
	net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex),lex->udf.name);
	goto error;
      default:
	net_printf(thd, ER_SP_CANT_ALTER, SP_COM_STRING(lex),lex->udf.name);
	goto error;
3528
      }
3529
      break;
3530 3531
    }
  case SQLCOM_DROP_PROCEDURE:
3532
  case SQLCOM_DROP_FUNCTION:
3533
    {
3534 3535
      if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
	res= sp_drop_procedure(thd, lex->udf.name.str, lex->udf.name.length);
3536 3537
      else
      {
3538 3539 3540
	res= sp_drop_function(thd, lex->udf.name.str, lex->udf.name.length);
#ifdef HAVE_DLOPEN
	if (res == SP_KEY_NOT_FOUND)
3541
	{
3542 3543 3544
	  udf_func *udf = find_udf(lex->udf.name.str, lex->udf.name.length);
	  if (udf)
	  {
unknown's avatar
unknown committed
3545
	    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0))
3546 3547 3548 3549 3550 3551 3552
	      goto error;
	    if (!(res = mysql_drop_function(thd,&lex->udf.name)))
	    {
	      send_ok(thd);
	      break;
	    }
	  }
3553
	}
3554 3555 3556 3557 3558
#endif
      }
      switch (res)
      {
      case SP_OK:
3559
	send_ok(thd);
3560 3561
	break;
      case SP_KEY_NOT_FOUND:
3562 3563 3564 3565 3566 3567 3568 3569 3570
	if (lex->drop_if_exists)
	{
	  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
			      ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
			      SP_COM_STRING(lex), lex->udf.name.str);
	  res= 0;
	  send_ok(thd);
	  break;
	}
3571 3572
	net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex),
		   lex->udf.name.str);
3573 3574
	goto error;
      default:
3575 3576
	net_printf(thd, ER_SP_DROP_FAILED, SP_COM_STRING(lex),
		   lex->udf.name.str);
3577
	goto error;
3578
      }
3579
      break;
3580
    }
unknown's avatar
unknown committed
3581 3582 3583 3584 3585 3586 3587 3588 3589
  case SQLCOM_SHOW_CREATE_PROC:
    {
      res= -1;
      if (lex->udf.name.length > NAME_LEN)
      {
	net_printf(thd, ER_TOO_LONG_IDENT, lex->udf.name.str);
	goto error;
      }
      res= sp_show_create_procedure(thd, &lex->udf.name);
3590 3591 3592
      if (res != SP_OK)
      {			/* We don't distinguish between errors for now */
	net_printf(thd, ER_SP_DOES_NOT_EXIST,
unknown's avatar
unknown committed
3593
		   SP_COM_STRING(lex), lex->udf.name.str);
3594
	res= 0;
unknown's avatar
unknown committed
3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606
	goto error;
      }
      break;
    }
  case SQLCOM_SHOW_CREATE_FUNC:
    {
      if (lex->udf.name.length > NAME_LEN)
      {
	net_printf(thd, ER_TOO_LONG_IDENT, lex->udf.name.str);
	goto error;
      }
      res= sp_show_create_function(thd, &lex->udf.name);
3607 3608
      if (res != SP_OK)
      {			/* We don't distinguish between errors for now */
unknown's avatar
unknown committed
3609 3610
	net_printf(thd, ER_SP_DOES_NOT_EXIST,
		   SP_COM_STRING(lex), lex->udf.name.str);
3611
	res= 0;
unknown's avatar
unknown committed
3612 3613
	goto error;
      }
unknown's avatar
unknown committed
3614
      res= 0;
unknown's avatar
unknown committed
3615 3616 3617 3618
      break;
    }
  case SQLCOM_SHOW_STATUS_PROC:
    {
3619
      res= sp_show_status_procedure(thd, (lex->wild ?
unknown's avatar
unknown committed
3620 3621 3622 3623 3624
					  lex->wild->ptr() : NullS));
      break;
    }
  case SQLCOM_SHOW_STATUS_FUNC:
    {
3625
      res= sp_show_status_function(thd, (lex->wild ? 
unknown's avatar
unknown committed
3626 3627 3628
					 lex->wild->ptr() : NullS));
      break;
    }
unknown's avatar
unknown committed
3629
  default:					/* Impossible */
3630
    send_ok(thd);
unknown's avatar
unknown committed
3631 3632 3633
    break;
  }
  thd->proc_info="query end";			// QQ
3634 3635 3636

  // We end up here if res == 0 and send_ok() has been done,
  // or res != 0 and no send_error() has yet been done.
unknown's avatar
unknown committed
3637
  if (res < 0)
unknown's avatar
SCRUM  
unknown committed
3638
    send_error(thd,thd->killed_errno());
3639
  DBUG_RETURN(res);
unknown's avatar
unknown committed
3640 3641

error:
3642
  // We end up here if send_error() has already been done.
3643
  DBUG_RETURN(-1);
unknown's avatar
unknown committed
3644 3645 3646
}


unknown's avatar
unknown committed
3647 3648 3649 3650
/*
  Check grants for commands which work only with one table and all other
  tables belong to subselects.

3651
  SYNOPSIS
unknown's avatar
unknown committed
3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662
    single_table_command_access()
    thd - Thread handler
    privilege - asked privelage
    tables - table list of command
    res - pointer on result code variable

  RETURN
    0 - OK
    1 - access denied
*/

unknown's avatar
unknown committed
3663
static bool single_table_command_access(THD *thd, ulong privilege,
unknown's avatar
unknown committed
3664 3665 3666
					TABLE_LIST *tables, int *res)
					 
{
unknown's avatar
unknown committed
3667 3668
  if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
    return 1;
unknown's avatar
unknown committed
3669

unknown's avatar
unknown committed
3670 3671 3672 3673 3674
  // Show only 1 table for check_grant
  TABLE_LIST *subselects_tables= tables->next;
  tables->next= 0;
  if (grant_option && check_grant(thd,  privilege, tables, 0, 0))
    return 1;
unknown's avatar
unknown committed
3675

unknown's avatar
unknown committed
3676 3677 3678 3679 3680 3681 3682 3683
  // check rights on tables of subselect (if exists)
  if (subselects_tables)
  {
    tables->next= subselects_tables;
    if ((*res= check_table_access(thd, SELECT_ACL, subselects_tables,0)))
      return 1;
  }
  return 0;
unknown's avatar
unknown committed
3684 3685 3686
}


unknown's avatar
unknown committed
3687
/****************************************************************************
unknown's avatar
unknown committed
3688
  Get the user (global) and database privileges for all used tables
unknown's avatar
unknown committed
3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701

  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
3702 3703
                is enough to satisfy the request and the global grants contains
                a SELECT grant.
unknown's avatar
unknown committed
3704 3705 3706
****************************************************************************/

bool
unknown's avatar
unknown committed
3707
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
3708
	     bool dont_check_global_grants, bool no_errors)
unknown's avatar
unknown committed
3709
{
unknown's avatar
unknown committed
3710 3711 3712 3713
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("want_access: %lu  master_access: %lu", want_access,
		      thd->master_access));
  ulong db_access,dummy;
unknown's avatar
unknown committed
3714 3715 3716 3717 3718
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

3719
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
3720
  {
3721
    if (!no_errors)
3722
      send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
unknown's avatar
unknown committed
3723
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
3724 3725
  }

unknown's avatar
unknown committed
3726 3727 3728
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  DBUG_RETURN(0);
#else
unknown's avatar
unknown committed
3729 3730
  if ((thd->master_access & want_access) == want_access)
  {
3731 3732 3733 3734 3735 3736 3737 3738
    /*
      If we don't have a global SELECT privilege, we have to get the database
      specific access rights to be able to handle queries of type
      UPDATE t1 SET a=1 WHERE b > 0
    */
    db_access= thd->db_access;
    if (!(thd->master_access & SELECT_ACL) &&
	(db && (!thd->db || strcmp(db,thd->db))))
3739
      db_access=acl_get(thd->host, thd->ip,
3740
			thd->priv_user, db, test(want_access & GRANT_ACL));
3741
    *save_priv=thd->master_access | db_access;
unknown's avatar
unknown committed
3742
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
3743
  }
3744
  if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
3745
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
3746
  {						// We can never grant this
3747
    if (!no_errors)
3748
      net_printf(thd,ER_ACCESS_DENIED_ERROR,
3749
		 thd->priv_user,
3750
		 thd->priv_host,
3751
		 thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
unknown's avatar
unknown committed
3752
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
3753 3754 3755
  }

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

unknown's avatar
unknown committed
3758
  if (db && (!thd->db || strcmp(db,thd->db)))
3759
    db_access=acl_get(thd->host, thd->ip,
3760
		      thd->priv_user, db, test(want_access & GRANT_ACL));
unknown's avatar
unknown committed
3761 3762
  else
    db_access=thd->db_access;
3763 3764
  // Remove SHOW attribute and access rights we already have
  want_access &= ~(thd->master_access | EXTRA_ACL);
unknown's avatar
unknown committed
3765
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
3766 3767

  /* grant_option is set if there exists a single table or column grant */
unknown's avatar
unknown committed
3768
  if (db_access == want_access ||
3769
      ((grant_option && !dont_check_global_grants) &&
3770
       !(want_access & ~(db_access | TABLE_ACLS))))
unknown's avatar
unknown committed
3771
    DBUG_RETURN(FALSE);				/* Ok */
3772
  if (!no_errors)
3773
    net_printf(thd,ER_DBACCESS_DENIED_ERROR,
3774
	       thd->priv_user,
3775
	       thd->priv_host,
3776
	       db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
unknown's avatar
unknown committed
3777
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
3778
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
3779 3780 3781
}


3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799
/*
  check for global access and give descriptive error message if it fails

  SYNOPSIS
    check_global_access()
    thd			Thread handler
    want_access		Use should have any of these global rights

  WARNING
    One gets access rigth if one has ANY of the rights in want_access
    This is useful as one in most cases only need one global right,
    but in some case we want to check if the user has SUPER or
    REPL_CLIENT_ACL rights.

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

bool check_global_access(THD *thd, ulong want_access)
unknown's avatar
unknown committed
3802
{
unknown's avatar
unknown committed
3803 3804 3805
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  return 0;
#else
unknown's avatar
unknown committed
3806
  char command[128];
3807
  if ((thd->master_access & want_access))
unknown's avatar
unknown committed
3808 3809
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
3810
  net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
unknown's avatar
unknown committed
3811 3812
	     command);
  return 1;
unknown's avatar
unknown committed
3813
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
3814 3815 3816
}


unknown's avatar
unknown committed
3817
/*
unknown's avatar
unknown committed
3818 3819
  Check the privilege for all used tables.  Table privileges are cached
  in the table list for GRANT checking
unknown's avatar
unknown committed
3820 3821
*/

3822
bool
unknown's avatar
unknown committed
3823
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
3824
		   bool no_errors)
unknown's avatar
unknown committed
3825
{
unknown's avatar
unknown committed
3826 3827
  uint found=0;
  ulong found_access=0;
unknown's avatar
unknown committed
3828 3829 3830
  TABLE_LIST *org_tables=tables;
  for (; tables ; tables=tables->next)
  {
3831
    if (tables->derived || (tables->table && (int)tables->table->tmp_table))
unknown's avatar
unknown committed
3832
      continue;
unknown's avatar
unknown committed
3833 3834
    if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
	thd->db)
unknown's avatar
unknown committed
3835
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
3836
    else if (tables->db && tables->db == thd->db)
unknown's avatar
unknown committed
3837 3838 3839 3840 3841
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
3842 3843
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
			 0, no_errors))
unknown's avatar
unknown committed
3844 3845
	  return TRUE;				// Access denied
	found_access=tables->grant.privilege;
unknown's avatar
unknown committed
3846
	found=1;
unknown's avatar
unknown committed
3847 3848
      }
    }
3849
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
3850
			  0, no_errors))
3851
      return TRUE;
unknown's avatar
unknown committed
3852 3853
  }
  if (grant_option)
3854
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
3855
		       test(want_access & EXTRA_ACL), no_errors);
unknown's avatar
unknown committed
3856 3857 3858
  return FALSE;
}

unknown's avatar
unknown committed
3859 3860
static bool check_merge_table_access(THD *thd, char *db,
				     TABLE_LIST *table_list)
3861 3862 3863 3864
{
  int error=0;
  if (table_list)
  {
3865
    /* Check that all tables use the current database */
3866 3867
    TABLE_LIST *tmp;
    for (tmp=table_list; tmp ; tmp=tmp->next)
3868 3869 3870 3871
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
    }
3872
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
unknown's avatar
SCRUM:  
unknown committed
3873
			     table_list,0);
3874 3875 3876 3877
  }
  return error;
}

unknown's avatar
SCRUM:  
unknown committed
3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893

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

unknown's avatar
unknown committed
3895 3896 3897 3898 3899 3900 3901 3902 3903 3904
/****************************************************************************
	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

3905
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
3906 3907 3908 3909 3910 3911 3912 3913
bool check_stack_overrun(THD *thd,char *buf __attribute__((unused)))
{
  long stack_used;
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
      (long) thread_stack_min)
  {
    sprintf(errbuff[0],ER(ER_STACK_OVERRUN),stack_used,thread_stack);
    my_message(ER_STACK_OVERRUN,errbuff[0],MYF(0));
3914
    thd->fatal_error();
unknown's avatar
unknown committed
3915 3916 3917 3918
    return 1;
  }
  return 0;
}
3919
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953

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

bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize)
{
  LEX	*lex=current_lex;
  int  old_info=0;
  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;
}


/****************************************************************************
3954
  Initialize global thd variables needed for query
unknown's avatar
unknown committed
3955 3956
****************************************************************************/

3957
void
3958
mysql_init_query(THD *thd, bool lexonly)
unknown's avatar
unknown committed
3959 3960
{
  DBUG_ENTER("mysql_init_query");
3961
  LEX *lex= thd->lex;
3962 3963
  lex->unit.init_query();
  lex->unit.init_select();
3964
  lex->unit.thd= thd;
3965 3966 3967
  lex->select_lex.init_query();
  lex->value_list.empty();
  lex->param_list.empty();
unknown's avatar
(SCRUM)  
unknown committed
3968 3969
  lex->unit.next= lex->unit.master= 
    lex->unit.link_next= lex->unit.return_to=0;
unknown's avatar
unknown committed
3970
  lex->unit.prev= lex->unit.link_prev= 0;
unknown's avatar
(SCRUM)  
unknown committed
3971
  lex->unit.slave= lex->unit.global_parameters= lex->current_select=
3972
    lex->all_selects_list= &lex->select_lex;
3973 3974
  lex->select_lex.master= &lex->unit;
  lex->select_lex.prev= &lex->unit.slave;
unknown's avatar
unknown committed
3975
  lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
3976
  lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
3977
  lex->select_lex.options=0;
3978 3979
  lex->select_lex.init_order();
  lex->select_lex.group_list.empty();
3980 3981
  lex->describe= 0;
  lex->derived_tables= FALSE;
3982 3983
  lex->lock_option= TL_READ;
  lex->found_colon= 0;
3984
  lex->safe_to_cache_query= 1;
3985 3986 3987 3988 3989 3990 3991 3992
  if (! lexonly)
  {
    thd->select_number= lex->select_lex.select_number= 1;
    thd->free_list= 0;
    thd->total_warn_count=0;			// Warnings for this query
    thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
    thd->sent_row_count= thd->examined_row_count= 0;
    thd->is_fatal_error= thd->rand_used= 0;
unknown's avatar
unknown committed
3993 3994 3995
    thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | 
			    SERVER_QUERY_NO_INDEX_USED |
			    SERVER_QUERY_NO_GOOD_INDEX_USED);
3996 3997 3998 3999 4000
    thd->tmp_table_used= 0;
    if (opt_bin_log)
      reset_dynamic(&thd->user_var_events);
    thd->clear_error();
  }
unknown's avatar
unknown committed
4001 4002 4003
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
4004

4005 4006 4007
void
mysql_init_select(LEX *lex)
{
unknown's avatar
(SCRUM)  
unknown committed
4008
  SELECT_LEX *select_lex= lex->current_select;
unknown's avatar
unknown committed
4009
  select_lex->init_select();
unknown's avatar
(SCRUM)  
unknown committed
4010
  select_lex->select_limit= lex->thd->variables.select_limit;
4011 4012 4013 4014 4015 4016
  if (select_lex == &lex->select_lex)
  {
    lex->exchange= 0;
    lex->result= 0;
    lex->proc_list.first= 0;
  }
4017 4018
}

4019

unknown's avatar
unknown committed
4020
bool
unknown's avatar
unknown committed
4021
mysql_new_select(LEX *lex, bool move_down)
4022
{
unknown's avatar
unknown committed
4023
  SELECT_LEX *select_lex = new(&lex->thd->mem_root) SELECT_LEX();
unknown's avatar
unknown committed
4024 4025
  if (!select_lex)
    return 1;
4026
  select_lex->select_number= ++lex->thd->select_number;
unknown's avatar
unknown committed
4027 4028 4029 4030 4031
  select_lex->init_query();
  select_lex->init_select();
  if (move_down)
  {
    /* first select_lex of subselect or derived table */
unknown's avatar
unknown committed
4032
    SELECT_LEX_UNIT *unit= new(&lex->thd->mem_root) SELECT_LEX_UNIT();
unknown's avatar
unknown committed
4033 4034 4035 4036
    if (!unit)
      return 1;
    unit->init_query();
    unit->init_select();
4037
    unit->thd= lex->thd;
unknown's avatar
(SCRUM)  
unknown committed
4038
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
4039 4040
    unit->link_next= 0;
    unit->link_prev= 0;
4041
    unit->return_to= lex->current_select;
unknown's avatar
unknown committed
4042
    select_lex->include_down(unit);
4043
    // TODO: assign resolve_mode for fake subquery after merging with new tree
unknown's avatar
unknown committed
4044 4045
  }
  else
unknown's avatar
(SCRUM)  
unknown committed
4046
  {
4047
    select_lex->include_neighbour(lex->current_select);
unknown's avatar
(SCRUM)  
unknown committed
4048 4049 4050 4051 4052 4053 4054 4055
    SELECT_LEX_UNIT *unit= select_lex->master_unit();
    SELECT_LEX *fake= unit->fake_select_lex;
    if (!fake)
    {
      /*
	as far as we included SELECT_LEX for UNION unit should have
	fake SELECT_LEX for UNION processing
      */
unknown's avatar
unknown committed
4056
      fake= unit->fake_select_lex= new(&lex->thd->mem_root) SELECT_LEX();
unknown's avatar
(SCRUM)  
unknown committed
4057 4058 4059 4060 4061 4062 4063 4064
      fake->include_standalone(unit,
			       (SELECT_LEX_NODE**)&unit->fake_select_lex);
      fake->select_number= INT_MAX;
      fake->make_empty_select();
      fake->linkage= GLOBAL_OPTIONS_TYPE;
      fake->select_limit= lex->thd->variables.select_limit;
    }
  }
unknown's avatar
unknown committed
4065

4066
  select_lex->master_unit()->global_parameters= select_lex;
4067
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
4068
  lex->current_select= select_lex;
4069
  select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
unknown's avatar
unknown committed
4070
  return 0;
4071
}
unknown's avatar
unknown committed
4072

4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087
/*
  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)
{
4088
  THD *thd;
4089
  LEX *lex;
4090
  LEX_STRING tmp, null_lex_string;
4091
  DBUG_ENTER("create_select_for_variable");
4092 4093

  thd= current_thd;
unknown's avatar
unknown committed
4094
  lex= thd->lex;
4095 4096 4097 4098
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
4099 4100 4101
  bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
  add_item_to_list(thd, get_system_var(thd, OPT_SESSION, tmp,
				       null_lex_string));
4102 4103 4104
  DBUG_VOID_RETURN;
}

4105

unknown's avatar
unknown committed
4106 4107
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
4108
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
4109
  mysql_init_select(lex);
4110
  lex->select_lex.select_limit= lex->unit.select_limit_cnt=
unknown's avatar
merged  
unknown committed
4111
    HA_POS_ERROR;
unknown's avatar
unknown committed
4112
  lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list);
unknown's avatar
unknown committed
4113
}
unknown's avatar
unknown committed
4114

4115

unknown's avatar
unknown committed
4116
void
unknown's avatar
unknown committed
4117
mysql_parse(THD *thd, char *inBuf, uint length)
unknown's avatar
unknown committed
4118 4119 4120 4121
{
  DBUG_ENTER("mysql_parse");

  mysql_init_query(thd);
unknown's avatar
unknown committed
4122
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
unknown's avatar
unknown committed
4123 4124
  {
    LEX *lex=lex_start(thd, (uchar*) inBuf, length);
4125
    if (!yyparse((void *)thd) && ! thd->is_fatal_error)
unknown's avatar
unknown committed
4126
    {
unknown's avatar
SCRUM:  
unknown committed
4127
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4128
      if (mqh_used && thd->user_connect &&
4129
	  check_mqh(thd, lex->sql_command))
4130 4131 4132 4133
      {
	thd->net.error = 0;
      }
      else
unknown's avatar
SCRUM:  
unknown committed
4134
#endif
4135
      {
unknown's avatar
unknown committed
4136
	if (thd->net.report_error)
4137
	{
unknown's avatar
unknown committed
4138
	  send_error(thd, 0, NullS);
4139
	  if (thd->lex->sphead)
4140 4141 4142 4143 4144 4145
	  {
	    if (lex != thd->lex)
	      thd->lex->sphead->restore_lex(thd);
	    delete thd->lex->sphead;
	    thd->lex->sphead= NULL;
	  }
4146
	}
unknown's avatar
unknown committed
4147 4148 4149 4150 4151
	else
	{
	  mysql_execute_command(thd);
	  query_cache_end_of_result(&thd->net);
	}
4152
      }
unknown's avatar
unknown committed
4153 4154
    }
    else
4155 4156
    {
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
4157
			 thd->is_fatal_error));
unknown's avatar
unknown committed
4158
      query_cache_abort(&thd->net);
4159
      if (thd->lex->sphead)
4160
      {
unknown's avatar
unknown committed
4161
	/* Clean up after failed stored procedure/function */
4162 4163 4164 4165 4166
	if (lex != thd->lex)
	  thd->lex->sphead->restore_lex(thd);
	delete thd->lex->sphead;
	thd->lex->sphead= NULL;
      }
4167
    }
unknown's avatar
unknown committed
4168
    thd->proc_info="freeing items";
4169
    free_items(thd->free_list);  /* Free strings used by items */
unknown's avatar
unknown committed
4170 4171
    lex_end(lex);
  }
unknown's avatar
unknown committed
4172 4173 4174 4175 4176 4177 4178 4179 4180
  DBUG_VOID_RETURN;
}


/*****************************************************************************
** Store field definition for create
** Return 0 if ok
******************************************************************************/

unknown's avatar
unknown committed
4181
bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
unknown's avatar
unknown committed
4182
		       char *length, char *decimals,
4183
		       uint type_modifier,
unknown's avatar
unknown committed
4184
		       Item *default_value, LEX_STRING *comment,
unknown's avatar
unknown committed
4185 4186
		       char *change, TYPELIB *interval, CHARSET_INFO *cs,
		       uint uint_geom_type)
unknown's avatar
unknown committed
4187 4188
{
  register create_field *new_field;
unknown's avatar
unknown committed
4189
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
4190
  uint allowed_type_modifier=0;
4191
  char warn_buff[MYSQL_ERRMSG_SIZE];
unknown's avatar
unknown committed
4192 4193 4194 4195
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
4196
    net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
unknown's avatar
unknown committed
4197 4198 4199 4200 4201
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
4202
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
unknown's avatar
unknown committed
4203 4204 4205 4206 4207 4208
				    lex->col_list));
    lex->col_list.empty();
  }
  if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
4209
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF,
unknown's avatar
unknown committed
4210 4211 4212 4213
				    lex->col_list));
    lex->col_list.empty();
  }

4214
  if (default_value)
unknown's avatar
unknown committed
4215
  {
4216 4217
    if (type == FIELD_TYPE_TIMESTAMP)
    {
unknown's avatar
unknown committed
4218
      net_printf(thd, ER_INVALID_DEFAULT, field_name);
4219 4220 4221
      DBUG_RETURN(1);
    }
    else if (default_value->type() == Item::NULL_ITEM)
unknown's avatar
unknown committed
4222
    {
4223 4224 4225 4226
      default_value=0;
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
unknown's avatar
unknown committed
4227
	net_printf(thd,ER_INVALID_DEFAULT,field_name);
4228 4229 4230 4231 4232
	DBUG_RETURN(1);
      }
    }
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
unknown's avatar
unknown committed
4233
      net_printf(thd, ER_INVALID_DEFAULT, field_name);
unknown's avatar
unknown committed
4234 4235 4236 4237 4238 4239 4240
      DBUG_RETURN(1);
    }
  }
  if (!(new_field=new create_field()))
    DBUG_RETURN(1);
  new_field->field=0;
  new_field->field_name=field_name;
4241
  new_field->def= default_value;
unknown's avatar
unknown committed
4242 4243 4244 4245 4246 4247 4248 4249 4250 4251
  new_field->flags= type_modifier;
  new_field->unireg_check= (type_modifier & AUTO_INCREMENT_FLAG ?
			    Field::NEXT_NUMBER : Field::NONE);
  new_field->decimals= decimals ? (uint) set_zone(atoi(decimals),0,
						  NOT_FIXED_DEC-1) : 0;
  new_field->sql_type=type;
  new_field->length=0;
  new_field->change=change;
  new_field->interval=0;
  new_field->pack_length=0;
4252
  new_field->charset=cs;
unknown's avatar
unknown committed
4253
  new_field->geom_type= (Field::geometry_type) uint_geom_type;
unknown's avatar
unknown committed
4254

4255 4256 4257 4258 4259 4260 4261 4262
  if (!comment)
  {
    new_field->comment.str=0;
    new_field->comment.length=0;
  }
  else
  {
    /* In this case comment is always of type Item_string */
unknown's avatar
unknown committed
4263 4264
    new_field->comment.str=   (char*) comment->str;
    new_field->comment.length=comment->length;
4265
  }
4266 4267
  if (length && !(new_field->length= (uint) atoi(length)))
    length=0; /* purecov: inspected */
unknown's avatar
unknown committed
4268 4269 4270
  uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;

  if (new_field->length && new_field->decimals &&
4271
      new_field->length < new_field->decimals+1 &&
unknown's avatar
unknown committed
4272
      new_field->decimals != NOT_FIXED_DEC)
4273
    new_field->length=new_field->decimals+1; /* purecov: inspected */
unknown's avatar
unknown committed
4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299

  switch (type) {
  case FIELD_TYPE_TINY:
    if (!length) new_field->length=3+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_SHORT:
    if (!length) new_field->length=5+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_INT24:
    if (!length) new_field->length=8+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONG:
    if (!length) new_field->length=10+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONGLONG:
    if (!length) new_field->length=20;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_NULL:
    break;
  case FIELD_TYPE_DECIMAL:
    if (!length)
4300 4301 4302 4303 4304 4305 4306
      new_field->length= 10;			// Default length for DECIMAL
    if (new_field->length < MAX_FIELD_WIDTH)	// Skip wrong argument
    {
      new_field->length+=sign_len;
      if (new_field->decimals)
	new_field->length++;
    }
unknown's avatar
unknown committed
4307
    break;
4308 4309
  case FIELD_TYPE_STRING:
  case FIELD_TYPE_VAR_STRING:
4310
    if (new_field->length <= MAX_FIELD_CHARLENGTH || default_value)
4311 4312 4313 4314
      break;
    /* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */
    new_field->sql_type= FIELD_TYPE_BLOB;
    sprintf(warn_buff, ER(ER_AUTO_CONVERT), field_name, "CHAR",
unknown's avatar
unknown committed
4315
	    (cs == &my_charset_bin) ? "BLOB" : "TEXT");
4316 4317 4318
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_AUTO_CONVERT,
		 warn_buff);
    /* fall through */
unknown's avatar
unknown committed
4319 4320 4321 4322
  case FIELD_TYPE_BLOB:
  case FIELD_TYPE_TINY_BLOB:
  case FIELD_TYPE_LONG_BLOB:
  case FIELD_TYPE_MEDIUM_BLOB:
unknown's avatar
unknown committed
4323
  case FIELD_TYPE_GEOMETRY:
4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337
    if (new_field->length)
    {
      /* The user has given a length to the blob column */
      if (new_field->length < 256)
	type= FIELD_TYPE_TINY_BLOB;
      if (new_field->length < 65536)
	type= FIELD_TYPE_BLOB;
      else if (new_field->length < 256L*256L*256L)
	type= FIELD_TYPE_MEDIUM_BLOB;
      else
	type= FIELD_TYPE_LONG_BLOB;
      new_field->length= 0;
    }
    new_field->sql_type= type;
unknown's avatar
unknown committed
4338 4339 4340 4341 4342 4343
    if (default_value)				// Allow empty as default value
    {
      String str,*res;
      res=default_value->val_str(&str);
      if (res->length())
      {
4344
	net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
unknown's avatar
unknown committed
4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363
	DBUG_RETURN(1); /* purecov: inspected */
      }
      new_field->def=0;
    }
    new_field->flags|=BLOB_FLAG;
    break;
  case FIELD_TYPE_YEAR:
    if (!length || new_field->length != 2)
      new_field->length=4;			// Default length
    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
    break;
  case FIELD_TYPE_FLOAT:
    /* change FLOAT(precision) to FLOAT or DOUBLE */
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    if (length && !decimals)
    {
      uint tmp_length=new_field->length;
      if (tmp_length > PRECISION_FOR_DOUBLE)
      {
4364
	net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
unknown's avatar
unknown committed
4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417
	DBUG_RETURN(1);
      }
      else if (tmp_length > PRECISION_FOR_FLOAT)
      {
	new_field->sql_type=FIELD_TYPE_DOUBLE;
	new_field->length=DBL_DIG+7;			// -[digits].E+###
      }
      else
	new_field->length=FLT_DIG+6;			// -[digits].E+##
      new_field->decimals= NOT_FIXED_DEC;
      break;
    }
    if (!length)
    {
      new_field->length =  FLT_DIG+6;
      new_field->decimals= NOT_FIXED_DEC;
    }
    break;
  case FIELD_TYPE_DOUBLE:
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    if (!length)
    {
      new_field->length = DBL_DIG+7;
      new_field->decimals=NOT_FIXED_DEC;
    }
    break;
  case FIELD_TYPE_TIMESTAMP:
    if (!length)
      new_field->length= 14;			// Full date YYYYMMDDHHMMSS
    else
    {
      new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
      new_field->length= min(new_field->length,14); /* purecov: inspected */
    }
    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG | NOT_NULL_FLAG;
    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:
    {
      if (interval->count > sizeof(longlong)*8)
      {
4418
	net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
unknown's avatar
unknown committed
4419 4420 4421 4422 4423 4424 4425 4426
	DBUG_RETURN(1);				/* purecov: inspected */
      }
      new_field->pack_length=(interval->count+7)/8;
      if (new_field->pack_length > 4)
	new_field->pack_length=8;
      new_field->interval=interval;
      new_field->length=0;
      for (const char **pos=interval->type_names; *pos ; pos++)
unknown's avatar
unknown committed
4427 4428 4429
      {
	new_field->length+=(uint) strip_sp((char*) *pos)+1;
      }
unknown's avatar
unknown committed
4430 4431 4432 4433
      new_field->length--;
      set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
      if (default_value)
      {
4434 4435
	char *not_used;
	uint not_used2;
4436
	bool not_used3;
4437

unknown's avatar
unknown committed
4438 4439 4440
	thd->cuted_fields=0;
	String str,*res;
	res=default_value->val_str(&str);
4441
	(void) find_set(interval, res->ptr(), res->length(), &not_used,
4442
			&not_used2, &not_used3);
unknown's avatar
unknown committed
4443 4444
	if (thd->cuted_fields)
	{
4445
	  net_printf(thd,ER_INVALID_DEFAULT,field_name);
unknown's avatar
unknown committed
4446 4447 4448 4449 4450 4451 4452 4453 4454
	  DBUG_RETURN(1);
	}
      }
    }
    break;
  case FIELD_TYPE_ENUM:
    {
      new_field->interval=interval;
      new_field->pack_length=interval->count < 256 ? 1 : 2; // Should be safe
unknown's avatar
unknown committed
4455
      new_field->length=(uint) strip_sp((char*) interval->type_names[0]);
unknown's avatar
unknown committed
4456 4457
      for (const char **pos=interval->type_names+1; *pos ; pos++)
      {
unknown's avatar
unknown committed
4458
	uint length=(uint) strip_sp((char*) *pos);
unknown's avatar
unknown committed
4459 4460 4461 4462 4463 4464 4465
	set_if_bigger(new_field->length,length);
      }
      set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
      if (default_value)
      {
	String str,*res;
	res=default_value->val_str(&str);
4466 4467
	res->strip_sp();
	if (!find_type(interval, res->ptr(), res->length(), 0))
unknown's avatar
unknown committed
4468
	{
4469
	  net_printf(thd,ER_INVALID_DEFAULT,field_name);
unknown's avatar
unknown committed
4470 4471 4472 4473 4474 4475 4476
	  DBUG_RETURN(1);
	}
      }
      break;
    }
  }

4477 4478
  if ((new_field->length > MAX_FIELD_CHARLENGTH && type != FIELD_TYPE_SET && 
       type != FIELD_TYPE_ENUM) ||
unknown's avatar
unknown committed
4479
      (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
4480
       type != FIELD_TYPE_STRING &&
unknown's avatar
SCRUM  
unknown committed
4481
       type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
unknown's avatar
unknown committed
4482
  {
4483
    net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
4484
	       MAX_FIELD_CHARLENGTH);		/* purecov: inspected */
unknown's avatar
unknown committed
4485 4486 4487 4488 4489
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
4490
    net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
unknown's avatar
unknown committed
4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511
    DBUG_RETURN(1);
  }
  if (!new_field->pack_length)
    new_field->pack_length=calc_pack_length(new_field->sql_type ==
					    FIELD_TYPE_VAR_STRING ?
					    FIELD_TYPE_STRING :
					    new_field->sql_type,
					    new_field->length);
  lex->create_list.push_back(new_field);
  lex->last_field=new_field;
  DBUG_RETURN(0);
}

/* Store position for column in ALTER TABLE .. ADD column */

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

bool
unknown's avatar
unknown committed
4512
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
4513 4514 4515 4516
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
4517
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
4518 4519 4520 4521 4522
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
unknown's avatar
unknown committed
4523
  thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
4524 4525 4526 4527 4528 4529 4530 4531
  return 0;
}


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

static void remove_escape(char *name)
{
4532 4533
  if (!*name)					// For empty DB names
    return;
unknown's avatar
unknown committed
4534 4535
  char *to;
#ifdef USE_MB
unknown's avatar
unknown committed
4536
  char *strend=name+(uint) strlen(name);
unknown's avatar
unknown committed
4537 4538 4539 4540 4541 4542
#endif
  for (to=name; *name ; name++)
  {
#ifdef USE_MB
    int l;
/*    if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
4543 4544
    if (use_mb(system_charset_info) &&
        (l = my_ismbchar(system_charset_info, name, strend)))
unknown's avatar
unknown committed
4545 4546 4547 4548 4549 4550 4551 4552
    {
	while (l--)
	    *to++ = *name++;
	name--;
	continue;
    }
#endif
    if (*name == '\\' && name[1])
unknown's avatar
unknown committed
4553
      name++;					// Skip '\\'
unknown's avatar
unknown committed
4554 4555 4556 4557 4558 4559 4560 4561 4562 4563
    *to++= *name;
  }
  *to=0;
}

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


unknown's avatar
unknown committed
4564
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
4565 4566 4567 4568
{
  ORDER *order;
  Item	**item_ptr;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
4569
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
4570 4571 4572 4573 4574 4575 4576
    DBUG_RETURN(1);
  item_ptr = (Item**) (order+1);
  *item_ptr=item;
  order->item= item_ptr;
  order->asc = asc;
  order->free_me=0;
  order->used=0;
unknown's avatar
unknown committed
4577
  list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
4578 4579 4580 4581
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600
/*
  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
4601 4602
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
4603
					     LEX_STRING *alias,
unknown's avatar
unknown committed
4604 4605
					     ulong table_options,
					     thr_lock_type lock_type,
4606 4607
					     List<String> *use_index_arg,
					     List<String> *ignore_index_arg,
unknown's avatar
unknown committed
4608
                                             LEX_STRING *option)
unknown's avatar
unknown committed
4609 4610 4611 4612 4613 4614 4615 4616
{
  register TABLE_LIST *ptr;
  char *alias_str;
  DBUG_ENTER("add_table_to_list");

  if (!table)
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? alias->str : table->table.str;
unknown's avatar
unknown committed
4617
  if (check_table_name(table->table.str,table->table.length) ||
unknown's avatar
unknown committed
4618
      table->db.str && check_db_name(table->db.str))
unknown's avatar
unknown committed
4619
  {
unknown's avatar
unknown committed
4620
    net_printf(thd, ER_WRONG_TABLE_NAME, table->table.str);
unknown's avatar
unknown committed
4621 4622 4623 4624
    DBUG_RETURN(0);
  }

  if (!alias)					/* Alias is case sensitive */
4625 4626 4627 4628 4629 4630
  {
    if (table->sel)
    {
      net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
      DBUG_RETURN(0);
    }
4631
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
4632
      DBUG_RETURN(0);
4633
  }
unknown's avatar
unknown committed
4634
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
4635
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
4636
  if (table->db.str)
4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647
  {
    ptr->db= table->db.str;
    ptr->db_length= table->db.length;
  }
  else if (thd->db)
  {
    ptr->db= thd->db;
    ptr->db_length= thd->db_length;
  }
  else
  {
4648 4649
    /* The following can't be "" as we may do 'casedn_str()' on it */
    ptr->db= empty_c_string;
4650 4651
    ptr->db_length= 0;
  }
unknown's avatar
unknown committed
4652

4653
  ptr->alias= alias_str;
4654 4655
  if (lower_case_table_names && table->table.length)
    my_casedn_str(files_charset_info, table->table.str);
unknown's avatar
unknown committed
4656
  ptr->real_name=table->table.str;
4657
  ptr->real_name_length=table->table.length;
4658
  ptr->lock_type=   lock_type;
unknown's avatar
unknown committed
4659 4660
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
4661
  ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
4662
  ptr->derived=	    table->sel;
4663 4664 4665 4666 4667 4668
  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
4669
  ptr->option= option ? option->str : 0;
unknown's avatar
unknown committed
4670
  /* check that used name is unique */
4671
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
4672
  {
4673
    for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
4674
	 tables ;
unknown's avatar
unknown committed
4675
	 tables=tables->next)
unknown's avatar
unknown committed
4676
    {
4677
      if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
4678
      {
4679
	net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
unknown's avatar
unknown committed
4680 4681
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
4682 4683
    }
  }
unknown's avatar
unknown committed
4684
  table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
unknown's avatar
unknown committed
4685 4686 4687
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
4688

unknown's avatar
unknown committed
4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701
/*
  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
4702
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
4703 4704 4705 4706 4707 4708
{
  bool for_update= lock_type >= TL_READ_NO_INSERT;
  DBUG_ENTER("set_lock_for_tables");
  DBUG_PRINT("enter", ("lock_type: %d  for_update: %d", lock_type,
		       for_update));

unknown's avatar
unknown committed
4709
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
4710 4711 4712 4713 4714 4715 4716 4717 4718
       tables ;
       tables=tables->next)
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
4719

unknown's avatar
unknown committed
4720 4721
void add_join_on(TABLE_LIST *b,Item *expr)
{
4722
  if (expr)
4723
  {
4724 4725 4726 4727 4728 4729 4730 4731
    if (!b->on_expr)
      b->on_expr=expr;
    else
    {
      // This only happens if you have both a right and left join
      b->on_expr=new Item_cond_and(b->on_expr,expr);
    }
    b->on_expr->top_level_item();
4732
  }
unknown's avatar
unknown committed
4733 4734 4735
}


4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753
/*
  Mark that we have a NATURAL JOIN between two tables

  SYNOPSIS
    add_join_natural()
    a			Table to do normal join with
    b			Do normal join with this table
  
  IMPLEMENTATION
    This function just marks that table b should be joined with a.
    The function setup_cond() will create in b->on_expr a list
    of equal condition between all fields of the same name.

    SELECT * FROM t1 NATURAL LEFT JOIN t2
     <=>
    SELECT * FROM t1 LEFT JOIN t2 ON (t1.i=t2.i and t1.j=t2.j ... )
*/

unknown's avatar
unknown committed
4754 4755 4756 4757 4758
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
{
  b->natural_join=a;
}

4759
/*
4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776
  Reload/resets privileges and the different caches.

  SYNOPSIS
    reload_acl_and_cache()
    thd			Thread handler
    options             What should be reset/reloaded (tables, privileges,
    slave...)
    tables              Tables to flush (if any)
    write_to_binlog     Depending on 'options', it may be very bad to write the
                        query to the binlog (e.g. FLUSH SLAVE); this is a
                        pointer where, if it is not NULL, reload_acl_and_cache()
                        will put 0 if it thinks we really should not write to
                        the binlog. Otherwise it will put 1.

  RETURN
    0	 ok
    !=0  error
4777 4778
*/

4779 4780
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
                          bool *write_to_binlog)
unknown's avatar
unknown committed
4781 4782 4783
{
  bool result=0;
  select_errors=0;				/* Write if more errors */
4784
  bool tmp_write_to_binlog= 1;
unknown's avatar
SCRUM  
unknown committed
4785
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
4786 4787
  if (options & REFRESH_GRANT)
  {
4788
    acl_reload(thd);
unknown's avatar
unknown committed
4789
    grant_reload(thd);
4790
    if (mqh_used)
4791
      reset_mqh(thd,(LEX_USER *) NULL,true);
unknown's avatar
unknown committed
4792
  }
unknown's avatar
SCRUM  
unknown committed
4793
#endif
unknown's avatar
unknown committed
4794 4795
  if (options & REFRESH_LOG)
  {
4796
    /*
unknown's avatar
unknown committed
4797 4798
      Flush the normal query log, the update log, the binary log,
      the slow query log, and the relay log (if it exists).
4799
    */
unknown's avatar
unknown committed
4800

4801 4802 4803 4804 4805 4806
    /* 
     Writing this command to the binlog may result in infinite loops when doing
     mysqlbinlog|mysql, and anyway it does not really make sense to log it
     automatically (would cause more trouble to users than it would help them)
    */
    tmp_write_to_binlog= 0;
unknown's avatar
unknown committed
4807 4808 4809
    mysql_log.new_file(1);
    mysql_bin_log.new_file(1);
    mysql_slow_log.new_file(1);
unknown's avatar
unknown committed
4810
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
4811
    if (expire_logs_days)
4812 4813 4814
    {
      long purge_time= time(0) - expire_logs_days*24*60*60;
      if (purge_time >= 0)
4815
	mysql_bin_log.purge_logs_before_date(purge_time);
4816
    }
4817 4818 4819
    LOCK_ACTIVE_MI;
    rotate_relay_log(active_mi);
    UNLOCK_ACTIVE_MI;
unknown's avatar
unknown committed
4820
#endif
unknown's avatar
unknown committed
4821 4822
    if (ha_flush_logs())
      result=1;
unknown's avatar
unknown committed
4823 4824
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
4825
  }
unknown's avatar
unknown committed
4826
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
4827 4828
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
4829
    query_cache.pack();				// FLUSH QUERY CACHE
unknown's avatar
unknown committed
4830 4831 4832 4833
    options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
4834
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
4835
  }
unknown's avatar
unknown committed
4836
#endif /*HAVE_QUERY_CACHE*/
4837 4838 4839 4840 4841
  /*
    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
4842
  {
4843
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
4844
    {
unknown's avatar
unknown committed
4845 4846 4847 4848
      /*
	Writing to the binlog could cause deadlocks, as we don't log
	UNLOCK TABLES
      */
4849
      tmp_write_to_binlog= 0;
4850 4851
      if (lock_global_read_lock(thd))
	return 1;
unknown's avatar
unknown committed
4852
    }
unknown's avatar
unknown committed
4853
    result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
unknown's avatar
unknown committed
4854 4855 4856 4857 4858 4859 4860
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
  if (options & REFRESH_STATUS)
    refresh_status();
  if (options & REFRESH_THREADS)
    flush_thread_cache();
unknown's avatar
unknown committed
4861
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
4862
  if (options & REFRESH_MASTER)
4863 4864
  {
    tmp_write_to_binlog= 0;
4865 4866
    if (reset_master(thd))
      result=1;
4867
  }
4868
#endif
unknown's avatar
unknown committed
4869
#ifdef OPENSSL
4870 4871 4872 4873 4874 4875
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
unknown's avatar
unknown committed
4876
#ifdef HAVE_REPLICATION
4877 4878
 if (options & REFRESH_SLAVE)
 {
4879
   tmp_write_to_binlog= 0;
4880
   LOCK_ACTIVE_MI;
4881
   if (reset_slave(thd, active_mi))
4882 4883 4884
     result=1;
   UNLOCK_ACTIVE_MI;
 }
4885
#endif
4886
 if (options & REFRESH_USER_RESOURCES)
4887
   reset_mqh(thd,(LEX_USER *) NULL);
4888 4889
 if (write_to_binlog)
   *write_to_binlog= tmp_write_to_binlog;
4890
 return result;
unknown's avatar
unknown committed
4891 4892
}

4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904
/*
  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
4905
void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
unknown's avatar
unknown committed
4906 4907 4908
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
4909 4910
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
4911 4912 4913 4914
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
4915 4916
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
4917 4918 4919
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
4920 4921 4922 4923 4924
  if (tmp)
  {
    if ((thd->master_access & SUPER_ACL) ||
	!strcmp(thd->user,tmp->user))
    {
unknown's avatar
SCRUM  
unknown committed
4925
      tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
4926 4927 4928 4929 4930 4931 4932
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }

unknown's avatar
unknown committed
4933
  if (!error)
4934
    send_ok(thd);
unknown's avatar
unknown committed
4935
  else
4936
    net_printf(thd,error,id);
unknown's avatar
unknown committed
4937 4938 4939 4940 4941 4942 4943 4944 4945 4946
}

/* 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)
4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958
      *(ulong*) ptr->value= 0;
    else if (ptr->type == SHOW_KEY_CACHE_LONG)
    {
      /*
	Reset value in 'default' key cache.
	This needs to be recoded when we have thread specific key values
      */
      char *value= (((char*) sql_key_cache) +
		    (uint) ((char*) (ptr->value) -
			    (char*) &dflt_key_cache_var));
      *(ulong*) value= 0;
    }
unknown's avatar
unknown committed
4959 4960 4961
  }
  pthread_mutex_unlock(&LOCK_status);
}
unknown's avatar
unknown committed
4962 4963 4964 4965


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

unknown's avatar
unknown committed
4966
static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
unknown's avatar
unknown committed
4967
{
4968
  char buff[FN_REFLEN],*ptr, *end;
unknown's avatar
unknown committed
4969 4970 4971 4972 4973 4974 4975
  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
4976
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
unknown's avatar
unknown committed
4977 4978 4979 4980
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
4981
  end=convert_dirname(buff, *filename_ptr, NullS);
unknown's avatar
unknown committed
4982
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
unknown's avatar
unknown committed
4983 4984
    return 1;					// End of memory
  *filename_ptr=ptr;
4985
  strxmov(ptr,buff,table_name,NullS);
unknown's avatar
unknown committed
4986 4987
  return 0;
}
4988

4989

4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003
/*
  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;
unknown's avatar
unknown committed
5004
  if (thd->lex->current_select != &thd->lex->select_lex)
5005 5006
  {
    char command[80];
unknown's avatar
unknown committed
5007 5008
    strmake(command, thd->lex->yylval->symbol.str,
	    min(thd->lex->yylval->symbol.length, sizeof(command)-1));
5009
    net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
5010 5011 5012 5013
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
5014

unknown's avatar
unknown committed
5015

unknown's avatar
unknown committed
5016
Comp_creator *comp_eq_creator(bool invert)
unknown's avatar
unknown committed
5017
{
unknown's avatar
unknown committed
5018
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
unknown's avatar
unknown committed
5019 5020
}

unknown's avatar
unknown committed
5021

unknown's avatar
unknown committed
5022
Comp_creator *comp_ge_creator(bool invert)
unknown's avatar
unknown committed
5023
{
unknown's avatar
unknown committed
5024
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
unknown's avatar
unknown committed
5025 5026
}

unknown's avatar
unknown committed
5027

unknown's avatar
unknown committed
5028
Comp_creator *comp_gt_creator(bool invert)
unknown's avatar
unknown committed
5029
{
unknown's avatar
unknown committed
5030
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
unknown's avatar
unknown committed
5031 5032
}

unknown's avatar
unknown committed
5033

unknown's avatar
unknown committed
5034
Comp_creator *comp_le_creator(bool invert)
unknown's avatar
unknown committed
5035
{
unknown's avatar
unknown committed
5036
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
unknown's avatar
unknown committed
5037 5038
}

unknown's avatar
unknown committed
5039

unknown's avatar
unknown committed
5040
Comp_creator *comp_lt_creator(bool invert)
unknown's avatar
unknown committed
5041
{
unknown's avatar
unknown committed
5042
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
unknown's avatar
unknown committed
5043 5044
}

unknown's avatar
unknown committed
5045

unknown's avatar
unknown committed
5046
Comp_creator *comp_ne_creator(bool invert)
unknown's avatar
unknown committed
5047
{
unknown's avatar
unknown committed
5048
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
unknown's avatar
unknown committed
5049
}
unknown's avatar
unknown committed
5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069


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

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

  Item_allany_subselect *it=
5077
    new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all);
unknown's avatar
unknown committed
5078 5079 5080 5081 5082
  if (all)
    return it->upper_not= new Item_func_not_all(it);	/* ALL */

  return it;						/* ANY/SOME */
}