sql_parse.cc 144 KB
Newer Older
1
/* Copyright (C) 2000-2003 MySQL AB
2

bk@work.mysql.com's avatar
bk@work.mysql.com 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

bk@work.mysql.com's avatar
bk@work.mysql.com 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

bk@work.mysql.com's avatar
bk@work.mysql.com 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"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
21 22 23 24
#include <m_ctype.h>
#include <myisam.h>
#include <my_dir.h>

heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
25
#ifdef HAVE_INNOBASE_DB
26
#include "ha_innodb.h"
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
27 28
#endif

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

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?
*/
43 44 45
#define SSL_HANDSHAKE_SIZE      2
#define NORMAL_HANDSHAKE_SIZE   6
#define MIN_HANDSHAKE_SIZE      2
46
#else
47
#define MIN_HANDSHAKE_SIZE      6
48
#endif /* HAVE_OPENSSL */
bk@work.mysql.com's avatar
bk@work.mysql.com 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
bk@work.mysql.com's avatar
bk@work.mysql.com committed
62

63
static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
64
static void decrease_user_connections(USER_CONN *uc);
65
static bool check_db_used(THD *thd,TABLE_LIST *tables);
hf@deer.(none)'s avatar
hf@deer.(none) committed
66
#ifndef NO_EMBEDDED_ACCESS_CHECKS
67
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
hf@deer.(none)'s avatar
hf@deer.(none) committed
68 69 70 71 72 73
static bool single_table_command_access(THD *thd, ulong privilege,
					TABLE_LIST *tables, int *res);
#else
#define check_merge_table_access(thd, db, tables) false
#define single_table_command_access(thd, privilege, tables, res) false
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
74 75
static void remove_escape(char *name);
static void refresh_status(void);
76 77
static bool append_file_to_dir(THD *thd, char **filename_ptr,
			       char *table_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
78

79
const char *any_db="*any*";	// Special symbol for check_access
bk@work.mysql.com's avatar
bk@work.mysql.com committed
80 81 82 83 84

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",
85
  "Binlog Dump","Table Dump",  "Connect Out", "Register Slave",
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
86
  "Prepare", "Prepare Execute", "Long Data", "Close stmt",
87
  "Error"					// Last command number
bk@work.mysql.com's avatar
bk@work.mysql.com committed
88 89
};

90
static char empty_c_string[1]= {0};		// Used for not defined 'db'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
91 92 93 94

#ifdef __WIN__
static void  test_signal(int sig_ptr)
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
95
#if !defined( DBUG_OFF)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
96 97
  MessageBox(NULL,"Test signal","DBUG",MB_OK);
#endif
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
98
#if defined(OS2)
99 100
  fprintf(stderr, "Test signal %d\n", sig_ptr);
  fflush(stderr);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
101
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
102 103 104 105
}
static void init_signals(void)
{
  int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
106
  for (int i=0 ; i < 7 ; i++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
107 108 109 110
    signal( signals[i], test_signal) ;
}
#endif

111 112 113 114 115 116 117 118 119 120 121
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)
122
{
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
123
  int error=0;
124
  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
125
		      OPTION_TABLE_LOCK))
126
  {
127 128
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
129
    if (ha_commit(thd))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
130
      error=1;
131
  }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
132
  return error;
133 134 135
}


136 137
static HASH hash_user_connections;

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

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

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

190
}
191

hf@deer.(none)'s avatar
hf@deer.(none) committed
192
#ifndef NO_EMBEDDED_ACCESS_CHECKS
193 194

/*
195
    Check if user exist and password supplied is correct. 
196 197
  SYNOPSIS
    check_user()
198 199 200 201 202 203 204 205 206
    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

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

212 213 214
  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;
215 216
   -1  access denied or handshake error; error is sent to client;
   >0  error, not sent to client
bk@work.mysql.com's avatar
bk@work.mysql.com committed
217 218
*/

hf@deer.(none)'s avatar
hf@deer.(none) committed
219 220 221
int check_user(THD *thd, enum enum_server_command command, 
	       const char *passwd, uint passwd_len, const char *db,
	       bool check_count)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
222
{
223
  DBUG_ENTER("check_user");
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
224
  
225 226 227 228 229
  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);
  
230
  /*
231 232
    If the server is running in secure auth mode, short scrambles are 
    forbidden.
233
  */
234
  if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
235
  {
236 237 238
    net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
    mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
    DBUG_RETURN(-1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
239
  }
240 241 242 243
  if (passwd_len != 0 &&
      passwd_len != SCRAMBLE_LENGTH &&
      passwd_len != SCRAMBLE_LENGTH_323)
    DBUG_RETURN(ER_HANDSHAKE_ERROR);
peter@mysql.com's avatar
peter@mysql.com committed
244

245
  /*
246 247 248 249
    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'.
250
  */
251 252
  thd->db= 0;
  thd->db_length= 0;
253
  
254
  USER_RESOURCES ur;
255
  int res= acl_getroot(thd, &ur, passwd, passwd_len);
hf@deer.(none)'s avatar
hf@deer.(none) committed
256
#ifndef EMBEDDED_LIBRARY
257
  if (res == -1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
258
  {
259 260 261 262 263 264
    /*
      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.
    */
265
    NET *net= &thd->net;
266
    if (opt_secure_auth_local)
267
    {
268 269 270 271 272 273
      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);
    }
274
    if (send_old_password_request(thd) ||
275 276 277 278 279 280 281
        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 */
282
    res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
283
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
284
#endif /*EMBEDDED_LIBRARY*/
285 286
  /* here res is always >= 0 */
  if (res == 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
287
  {
288
    if (!(thd->master_access & NO_ACCESS)) // authentification is OK 
289
    {
290 291 292 293 294 295 296 297 298 299
      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)
300
      {
301 302
        VOID(pthread_mutex_lock(&LOCK_thread_count));
        bool count_ok= thread_count < max_connections + delayed_insert_threads
303
                       || (thd->master_access & SUPER_ACL);
304 305 306 307 308 309
        VOID(pthread_mutex_unlock(&LOCK_thread_count));
        if (!count_ok)
        {                                         // too many connections 
          send_error(thd, ER_CON_COUNT_ERROR);
          DBUG_RETURN(-1);
        }
310
      }
peter@mysql.com's avatar
peter@mysql.com committed
311

312 313 314 315 316 317 318 319
      /* 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*) "");

320
      /*
321 322 323
        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.
324
      */
325 326 327
      thd->db_access=0;

      /* Don't allow user to connect if he has done too many queries */
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
328 329 330 331 332 333 334 335 336
      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);
337 338 339

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

hf@deer.(none)'s avatar
hf@deer.(none) committed
372
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
373 374


375
/*
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
376 377
  Check for maximum allowable user connections, if the mysqld server is
  started with corresponding variable that is greater then 0.
378 379
*/

380 381
extern "C" byte *get_key_conn(user_conn *buff, uint *length,
			      my_bool not_used __attribute__((unused)))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
382 383 384 385 386
{
  *length=buff->len;
  return (byte*) buff->user;
}

387
extern "C" void free_user(struct user_conn *uc)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
388 389 390 391
{
  my_free((char*) uc,MYF(0));
}

peter@mysql.com's avatar
peter@mysql.com committed
392
void init_max_user_conn(void)
393
{
394 395
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
		   0,0,
396
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
397
		   0);
398 399 400
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
/*
  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
*/

418
static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
419
{
420
  int error=0;
421
  DBUG_ENTER("check_for_max_user_connections");
peter@mysql.com's avatar
peter@mysql.com committed
422

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

  end:
443 444
  if (error)
    uc->connections--; // no need for decrease_user_connections() here
445
  (void) pthread_mutex_unlock(&LOCK_user_conn);
446
  DBUG_RETURN(error);
447 448 449
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
/*
  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.
*/

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

482

483 484 485 486 487
void free_max_user_conn(void)
{
  hash_free(&hash_user_connections);
}

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
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 514 515 516
/*
  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;
517
  uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
518 519
}

520 521 522 523
bool is_update_query(enum enum_sql_command command)
{
  return uc_update_queries[command];
}
524

hf@deer.(none)'s avatar
hf@deer.(none) committed
525
#ifndef NO_EMBEDDED_ACCESS_CHECKS
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
526 527 528
/*
  Check if maximum queries per hour limit has been reached
  returns 0 if OK.
529

530 531 532
  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.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
533 534
*/

535

536
static bool check_mqh(THD *thd, uint check_command)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
537 538
{
  bool error=0;
539
  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
540
  USER_CONN *uc=thd->user_connect;
541
  DBUG_ENTER("check_mqh");
542
  DBUG_ASSERT(uc != 0);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
543

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

579

580
static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
581 582
{

583
  (void) pthread_mutex_lock(&LOCK_user_conn);
peter@mysql.com's avatar
peter@mysql.com committed
584
  if (lu)  // for GRANT
585
  {
586
    USER_CONN *uc;
587
    uint temp_len=lu->user.length+lu->host.length+2;
588 589
    char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];

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;
593
    if ((uc = (struct  user_conn *) hash_search(&hash_user_connections,
594
						(byte*) temp_user, temp_len)))
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;
600 601
    }
  }
602
  else // for FLUSH PRIVILEGES and FLUSH USER_RESOURCES
603
  {
604
    for (uint idx=0;idx < hash_user_connections.records; idx++)
605
    {
606 607 608 609 610 611
      USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections, idx);
      if (get_them)
	get_mqh(uc->user,uc->host,uc);
      uc->questions=0;
      uc->updates=0;
      uc->conn_per_hour=0;
612 613
    }
  }
614
  (void) pthread_mutex_unlock(&LOCK_user_conn);
615
}
hf@deer.(none)'s avatar
hf@deer.(none) committed
616
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
617

bk@work.mysql.com's avatar
bk@work.mysql.com committed
618
/*
619
    Perform handshake, authorize client and update thd ACL variables.
620
  SYNOPSIS
621
    check_connection()
622
    thd  thread handle
623 624

  RETURN
625
     0  success, OK is sent to user, thd is updated.
626 627
    -1  error, which is sent to user
   > 0  error code (not sent to user)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
628 629
*/

hf@deer.(none)'s avatar
hf@deer.(none) committed
630 631
#ifndef EMBEDDED_LIBRARY
static int check_connection(THD *thd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
632
{
633
  uint connect_errors= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
634
  NET *net= &thd->net;
635

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
639 640
  if (!thd->host)                           // If TCP/IP connection
  {
641
    char ip[30];
642

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

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

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

  thd->client_capabilities=uint2korr(net->read_pos);
749 750 751 752 753 754 755 756 757 758 759
#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
760 761 762 763
  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);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
764 765 766 767 768 769 770
    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
    */
771
    if (!(thd->variables.character_set_client=
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
772 773 774 775
	  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))
776
    {
777 778
      thd->variables.character_set_client=
	global_system_variables.character_set_client;
779 780
      thd->variables.collation_connection=
	global_system_variables.collation_connection;
781 782
      thd->variables.character_set_results=
	global_system_variables.character_set_results;
783 784 785
    }
    else
    {
786
      thd->variables.character_set_results=
787 788 789
      thd->variables.collation_connection= 
	thd->variables.character_set_client;
    }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
790
    thd->update_charset();
791
    end= (char*) net->read_pos+32;
792 793 794 795 796 797 798
  }
  else
  {
    thd->max_client_packet_length= uint3korr(net->read_pos+2);
    end= (char*) net->read_pos+5;
  }

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

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

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

844 845
  char *user= end;
  char *passwd= strend(user)+1;
846
  char *db= passwd;
847
  char db_buff[NAME_LEN+1];                     // buffer to store db in utf8 
848 849 850 851 852 853 854 855 856
  /* 
    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;
peter@mysql.com's avatar
peter@mysql.com committed
857

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

868 869
  if (thd->user)
    x_free(thd->user);
870 871
  if (!(thd->user= my_strdup(user, MYF(0))))
    return (ER_OUT_OF_RESOURCES);
872
  return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
873 874
}

875

876 877
void execute_init_command(THD *thd, sys_var_str *init_command_var,
			  rw_lock_t *var_mutex)
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
878 879 880 881
{
  Vio* save_vio;
  ulong save_client_capabilities;

882 883 884 885 886 887 888 889 890
  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;
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
891 892
  save_client_capabilities= thd->client_capabilities;
  thd->client_capabilities|= CLIENT_MULTI_QUERIES;
893 894 895 896
  /*
    We don't need return result of execution to client side.
    To forbid this we should set thd->net.vio to 0.
  */
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
897 898 899
  save_vio= thd->net.vio;
  thd->net.vio= 0;
  dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
900
  rw_unlock(var_mutex);
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
901 902 903 904 905
  thd->client_capabilities= save_client_capabilities;
  thd->net.vio= save_vio;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
906 907 908 909
pthread_handler_decl(handle_one_connection,arg)
{
  THD *thd=(THD*) arg;
  uint launch_time  =
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
910
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
911 912 913 914 915
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status );

  pthread_detach_this_thread();

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

927 928 929 930 931 932 933
  /*
    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.
  */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
934 935 936 937
  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_*

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

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

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

gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
978 979 980
    thd->version= refresh_version;
    if (sys_init_connect.value && !(thd->master_access & SUPER_ACL))
    {
981 982
      execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
      if (thd->query_error)
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
983
	thd->killed= THD::KILL_CONNECTION;
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
984 985 986
    }

    thd->proc_info=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
987
    thd->set_time();
hf@genie.(none)'s avatar
SCRUM  
hf@genie.(none) committed
988
    while (!net->error && net->vio != 0 && !(thd->killed == THD::KILL_CONNECTION))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
989 990 991 992
    {
      if (do_command(thd))
	break;
    }
993 994
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
995
    if (net->error && net->vio != 0 && net->report_error)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
996
    {
997
      if (!thd->killed && thd->variables.log_warnings)
998 999 1000 1001 1002 1003
	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)));
1004
      send_error(thd,net->last_errno,NullS);
1005
      statistic_increment(aborted_threads,&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1006
    }
1007 1008 1009 1010
    else if (thd->killed)
    {
      statistic_increment(aborted_threads,&LOCK_status);
    }
1011
    
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1012
end_thread:
1013
    close_connection(thd, 0, 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
    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 */
}

hf@deer.(none)'s avatar
hf@deer.(none) committed
1025 1026
#endif /* EMBEDDED_LIBRARY */

1027 1028 1029 1030
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1031

1032
extern "C" pthread_handler_decl(handle_bootstrap,arg)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1033
{
1034 1035 1036
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1037

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

hf@deer.(none)'s avatar
hf@deer.(none) committed
1049
#ifndef EMBEDDED_LIBRARY
1050 1051
  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1052
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1053
  sigset_t set;
1054 1055
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1056
#endif
hf@deer.(none)'s avatar
hf@deer.(none) committed
1057
#endif /* EMBEDDED_LIBRARY */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1058

1059
  if (thd->variables.max_join_size == HA_POS_ERROR)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1060 1061 1062 1063
    thd->options |= OPTION_BIG_SELECTS;

  thd->proc_info=0;
  thd->version=refresh_version;
1064
  thd->priv_user=thd->user=(char*) my_strdup("boot", MYF(MY_WME));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1065

1066
  buff= (char*) thd->net.buff;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1067 1068
  while (fgets(buff, thd->net.max_packet, file))
  {
1069
    uint length=(uint) strlen(buff);
1070
    while (length && (my_isspace(thd->charset(), buff[length-1]) ||
1071
           buff[length-1] == ';'))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1072 1073
      length--;
    buff[length]=0;
1074
    thd->query_length=length;
1075 1076
    thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
    thd->query[length] = '\0';
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1077
    thd->query_id=query_id++;
hf@deer.(none)'s avatar
hf@deer.(none) committed
1078
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1079
    if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
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;
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
1086
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1087 1088
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
1089
    if (thd->is_fatal_error)
1090
      break;
1091
    free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
1092
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1093
  }
1094 1095 1096

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

1108
    /* This works because items are allocated with sql_alloc() */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1109

1110
void free_items(Item *item)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1111
{
1112
  for (; item ; item=item->next)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1113 1114 1115
    delete item;
}

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

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

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

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

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

hf@deer.(none)'s avatar
hf@deer.(none) committed
1150 1151
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege,0,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1152
    goto err;
1153
  if (grant_option && check_grant(thd, SELECT_ACL, table_list))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1154
    goto err;
hf@deer.(none)'s avatar
hf@deer.(none) committed
1155
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1156
  thd->free_list = 0;
1157
  thd->query_length=(uint) strlen(tbl_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1158
  thd->query = tbl_name;
1159 1160
  if ((error = mysqld_dump_create_info(thd, table, -1)))
  {
1161
    my_error(ER_GET_ERRNO, MYF(0), my_errno);
1162 1163
    goto err;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1164
  net_flush(&thd->net);
1165
  if ((error= table->file->dump(thd,fd)))
1166
    my_error(ER_GET_ERRNO, MYF(0));
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1167

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1168 1169
err:
  close_thread_tables(thd);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1170
  DBUG_RETURN(error);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1171 1172 1173
}


1174
	/* Execute one command from socket (query or simple command) */
1175 1176

#ifndef EMBEDDED_LIBRARY
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1177 1178 1179
bool do_command(THD *thd)
{
  char *packet;
1180 1181
  uint old_timeout;
  ulong packet_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1182 1183 1184 1185 1186
  NET *net;
  enum enum_server_command command;
  DBUG_ENTER("do_command");

  net= &thd->net;
1187 1188 1189 1190
  /*
    indicator of uninitialized lex => normal flow of errors handling
    (see my_message_sql)
  */
1191
  thd->lex->current_select= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1192 1193

  packet=0;
1194 1195 1196
  old_timeout=net->read_timeout;
  // Wait max for 8 hours
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
1197
  thd->clear_error();				// Clear error message
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1198 1199 1200 1201

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1220 1221
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
1222 1223
    if (command >= COM_END)
      command= COM_END;				// Wrong command
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1224 1225 1226
    DBUG_PRINT("info",("Command on %s = %d (%s)",
		       vio_description(net->vio), command,
		       command_name[command]));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1227
  }
1228
  net->read_timeout=old_timeout;		// restore it
1229
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
1230
}
1231
#endif  /* EMBEDDED_LIBRARY */
1232

1233

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

  thd->command=command;
1242 1243 1244 1245
  /*
    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
  */
1246
  thd->slow_command=FALSE;
1247
  thd->set_time();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1248 1249 1250 1251 1252 1253
  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));
1254

1255 1256
  thd->server_status&=
           ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
1257
  switch (command) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1258
  case COM_INIT_DB:
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1259 1260 1261 1262 1263 1264 1265 1266 1267
  {
    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;
  }
1268
#ifdef HAVE_REPLICATION
1269 1270
  case COM_REGISTER_SLAVE:
  {
1271
    if (!register_slave(thd, (uchar*)packet, packet_length))
1272
      send_ok(thd);
1273 1274
    break;
  }
1275
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1276
  case COM_TABLE_DUMP:
1277 1278 1279 1280 1281 1282
  {
    char *db, *tbl_name;
    uint db_len= *(uchar*) packet;
    uint tbl_len= *(uchar*) (packet + db_len + 1);

    statistic_increment(com_other, &LOCK_status);
1283
    thd->slow_command= TRUE;
1284 1285 1286 1287 1288 1289 1290
    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;
  }
1291
#ifndef EMBEDDED_LIBRARY
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1292 1293
  case COM_CHANGE_USER:
  {
1294
    thd->change_user();
1295
    thd->clear_error();                         // if errors from rollback
1296

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

1317
    /* Convert database name to utf8 */
1318 1319 1320 1321
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
                             system_charset_info, db, strlen(db),
                             thd->charset())]= 0;
    db= db_buff;
peter@mysql.com's avatar
peter@mysql.com committed
1322

1323 1324 1325 1326 1327 1328 1329
    /* 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;
1330
    USER_CONN *save_user_connect= thd->user_connect;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1331 1332
    
    if (!(thd->user= my_strdup(user, MYF(0))))
1333 1334 1335 1336 1337
    {
      thd->user= save_user;
      send_error(thd, ER_OUT_OF_RESOURCES);
      break;
    }
peter@mysql.com's avatar
peter@mysql.com committed
1338

1339 1340
    /* Clear variables that are allocated */
    thd->user_connect= 0;
1341
    int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, false);
peter@mysql.com's avatar
peter@mysql.com committed
1342

1343 1344 1345 1346 1347 1348 1349 1350
    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;
1351
      thd->user_connect= save_user_connect;
1352 1353 1354 1355 1356 1357 1358 1359
      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 */
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1360 1361
      if (save_user_connect)
	decrease_user_connections(save_user_connect);
1362 1363 1364
      x_free((gptr) save_db);
      x_free((gptr) save_user);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1365 1366
    break;
  }
1367
#endif /* EMBEDDED_LIBRARY */
1368 1369
  case COM_EXECUTE:
  {
1370
    mysql_stmt_execute(thd, packet);
1371 1372 1373 1374
    break;
  }
  case COM_LONG_DATA:
  {
1375
    mysql_stmt_get_longdata(thd, packet, packet_length);
1376 1377 1378 1379
    break;
  }
  case COM_PREPARE:
  {
1380
    mysql_stmt_prepare(thd, packet, packet_length);
1381 1382
    break;
  }
1383 1384 1385 1386 1387
  case COM_CLOSE_STMT:
  {
    mysql_stmt_free(thd, packet);
    break;
  }
1388 1389 1390 1391 1392
  case COM_RESET_STMT:
  {
    mysql_stmt_reset(thd, packet);
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1393 1394
  case COM_QUERY:
  {
1395 1396
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
1397
    mysql_log.write(thd,command,"%s",thd->query);
1398
    DBUG_PRINT("query",("%-.4096s",thd->query));
1399
    mysql_parse(thd,thd->query, thd->query_length);
1400

1401
    while (!thd->killed && !thd->is_fatal_error && thd->lex->found_colon)
1402
    {
1403
      char *packet= thd->lex->found_colon;
1404
      /*
1405 1406 1407
        Multiple queries exits, execute them individually
      */
      if (thd->lock || thd->open_tables || thd->derived_tables)
1408
        close_thread_tables(thd);
1409

1410
      ulong length= thd->query_length-(ulong)(thd->lex->found_colon-thd->query);
1411

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1426 1427 1428 1429 1430
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1431
  case COM_FIELD_LIST:				// This isn't actually needed
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1432
#ifdef DONT_ALLOW_SHOW_COMMANDS
1433
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1434 1435 1436
    break;
#else
  {
1437
    char *fields, *pend;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1438
    TABLE_LIST table_list;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1439 1440
    LEX_STRING conv_name;

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

hf@deer.(none)'s avatar
hf@deer.(none) committed
1462 1463
#ifndef NO_EMBEDDED_ACCESS_CHECKS
    if (check_access(thd,SELECT_ACL,table_list.db,&thd->col_access,0,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1464 1465 1466 1467
      break;
    table_list.grant.privilege=thd->col_access;
    if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2))
      break;
hf@deer.(none)'s avatar
hf@deer.(none) committed
1468
#endif /*DONT_ALLOW_SHOW_COMMANDS*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1469
    mysqld_list_fields(thd,&table_list,fields);
1470
    free_items(thd->free_list);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1471 1472 1473 1474
    break;
  }
#endif
  case COM_QUIT:
1475
    /* We don't calculate statistics for this command */
1476
    mysql_log.write(thd,command,NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1477 1478 1479 1480
    net->error=0;				// Don't give 'abort' message
    error=TRUE;					// End server
    break;

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

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

1673
  if (thd->is_fatal_error)
1674
    send_error(thd,0);				// End of memory ?
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1675 1676

  time_t start_of_query=thd->start_time;
1677
  thd->end_time();				// Set start time
1678

1679
  /* If not reading from backup and if the query took too long */
1680
  if (!thd->slow_command && !thd->user_time) // do not log 'slow_command' queries
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1681
  {
1682 1683
    thd->proc_info="logging slow query";

1684 1685
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
1686 1687
	((thd->server_status &
	  (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
1688
	 (specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES)))
1689 1690 1691 1692
    {
      long_query_count++;
      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1693
  }
1694
  thd->proc_info="cleaning up";
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1695 1696 1697 1698 1699 1700
  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));
1701
  thd->packet.shrink(thd->variables.net_buffer_length);	// Reclaim some memory
1702

1703
  free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1704 1705 1706
  DBUG_RETURN(error);
}

1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724

/*
  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
1725
  /* Remove garbage at start and end of query */
1726
  while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
1727 1728 1729 1730 1731
  {
    packet++;
    packet_length--;
  }
  char *pos=packet+packet_length;		// Point at end null
peter@mysql.com's avatar
peter@mysql.com committed
1732
  while (packet_length > 0 &&
1733
	 (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
1734 1735 1736 1737 1738 1739 1740
  {
    pos--;
    packet_length--;
  }
  /* We must allocate some extra memory for query cache */
  if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
					      packet_length,
1741 1742
					      thd->db_length+ 1 +
					      QUERY_CACHE_FLAGS_SIZE)))
1743 1744 1745 1746 1747 1748 1749 1750 1751 1752
    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;
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1753 1754 1755 1756 1757
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/

1758
int
1759
mysql_execute_command(THD *thd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1760
{
1761
  int	res= 0;
1762
  LEX	*lex= thd->lex;
1763
  TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1764
  SELECT_LEX *select_lex= &lex->select_lex;
1765
  SELECT_LEX_UNIT *unit= &lex->unit;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1766 1767
  DBUG_ENTER("mysql_execute_command");

1768
  if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
1769
      lex->sql_command != SQLCOM_CREATE_SPFUNCTION)
1770 1771 1772 1773 1774
  {
    if (sp_cache_functions(thd, lex))
      DBUG_RETURN(-1);
  }

1775 1776 1777 1778 1779 1780
  /*
    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.
  */
1781
  if (tables || &lex->select_lex != lex->all_selects_list)
1782 1783
    mysql_reset_errors(thd);

hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
1784
#ifdef HAVE_REPLICATION
1785 1786
  if (thd->slave_thread)
  {
peter@mysql.com's avatar
peter@mysql.com committed
1787
    /*
monty@hundin.mysql.fi's avatar
merge  
monty@hundin.mysql.fi committed
1788 1789 1790 1791
      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))
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1792 1793 1794
    {
      /* we warn the slave SQL thread */
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
1795
      DBUG_RETURN(0);
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1796
    }
monty@hundin.mysql.fi's avatar
merge  
monty@hundin.mysql.fi committed
1797 1798
#ifndef TO_BE_DELETED
    /*
1799 1800 1801
      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()
monty@hundin.mysql.fi's avatar
merge  
monty@hundin.mysql.fi committed
1802
    */
1803 1804 1805
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
1806
      lex->insert_list = &select_lex->item_list;
1807
    }
monty@hundin.mysql.fi's avatar
merge  
monty@hundin.mysql.fi committed
1808
#endif
1809
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
1810
#endif /* !HAVE_REPLICATION */
1811
  /*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1812 1813
    TODO: make derived tables processing 'inside' SELECT processing.
    TODO: solve problem with depended derived tables in subselects
1814
  */
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1815
  if (lex->derived_tables)
1816
  {
1817 1818 1819
    for (SELECT_LEX *sl= lex->all_selects_list;
	 sl;
	 sl= sl->next_select_in_list())
1820
    {
1821 1822 1823
      for (TABLE_LIST *cursor= sl->get_table_list();
	   cursor;
	   cursor= cursor->next)
1824
      {
1825 1826 1827
	if (cursor->derived && (res=mysql_derived(thd, lex,
						  cursor->derived,
						  cursor)))
peter@mysql.com's avatar
peter@mysql.com committed
1828
	{
1829 1830
	  if (res < 0 || thd->net.report_error)
	    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
1831
	  DBUG_RETURN(res);
1832
	}
1833 1834
      }
    }
1835
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1836 1837
  if (&lex->select_lex != lex->all_selects_list &&
      lex->unit.create_total_list(thd, lex, &tables, 0))
1838
    DBUG_RETURN(0);
1839 1840 1841 1842 1843 1844
  
  /*
    When option readonly is set deny operations which change tables.
    Except for the replication thread and the 'super' users.
  */
  if (opt_readonly &&
hf@deer.(none)'s avatar
hf@deer.(none) committed
1845 1846 1847 1848 1849
      !(thd->slave_thread
#ifndef NO_EMBEDDED_ACCESS_CHECKS
	|| (thd->master_access & SUPER_ACL)
#endif
	) &&
1850 1851
      (uc_update_queries[lex->sql_command] > 0))
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1852
    send_error(thd, ER_CANT_UPDATE_WITH_READLOCK);
1853
    DBUG_RETURN(-1);
1854
  }
1855

1856
  statistic_increment(com_stat[lex->sql_command],&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1857 1858 1859
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
1860
    select_result *result=lex->result;
hf@deer.(none)'s avatar
hf@deer.(none) committed
1861
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1862 1863 1864 1865 1866
    if (tables)
    {
      res=check_table_access(thd,
			     lex->exchange ? SELECT_ACL | FILE_ACL :
			     SELECT_ACL,
hf@deer.(none)'s avatar
hf@deer.(none) committed
1867
			     tables,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1868 1869 1870
    }
    else
      res=check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
hf@deer.(none)'s avatar
hf@deer.(none) committed
1871
		       any_db,0,0,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1872 1873 1874 1875 1876
    if (res)
    {
      res=0;
      break;					// Error message is given
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
1877
#endif
1878 1879 1880 1881
    /* 
       In case of single SELECT unit->global_parameters points on first SELECT
       TODO: move counters to SELECT_LEX
    */
1882 1883 1884
    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);
peter@mysql.com's avatar
peter@mysql.com committed
1885
    if (unit->select_limit_cnt <
1886
	(ha_rows) unit->global_parameters->select_limit)
1887
      unit->select_limit_cnt= HA_POS_ERROR;		// no limit
1888
    if (unit->select_limit_cnt == HA_POS_ERROR && !select_lex->next_select())
1889
      select_lex->options&= ~OPTION_FOUND_ROWS;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1890 1891

    if (!(res=open_and_lock_tables(thd,tables)))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1892
    {
1893
      if (lex->describe)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1894
      {
1895 1896 1897
	if (!(result= new select_send()))
	{
	  send_error(thd, ER_OUT_OF_RESOURCES);
1898
	  goto error;
1899 1900 1901
	}
	else
	  thd->send_explain_fields(result);
1902
	fix_tables_pointers(lex->all_selects_list);
1903
	res= mysql_explain_union(thd, &thd->lex->unit, result);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1904 1905
	MYSQL_LOCK *save_lock= thd->lock;
	thd->lock= (MYSQL_LOCK *)0;
1906 1907 1908 1909 1910
	if (lex->describe & DESCRIBE_EXTENDED)
	{
	  char buff[1024];
	  String str(buff,(uint32) sizeof(buff), system_charset_info);
	  str.length(0);
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
1911
	  thd->lex->unit.print(&str);
1912 1913 1914 1915
	  str.append('\0');
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
		       ER_YES, str.ptr());
	}
1916
	result->send_eof();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1917 1918 1919 1920
	thd->lock= save_lock;
      }
      else
      {
1921 1922
	if (!result)
	{
1923
	  if (!(result=new select_send()))
1924 1925 1926 1927 1928 1929 1930 1931 1932
	  {
	    res= -1;
#ifdef DELETE_ITEMS
	    delete select_lex->having;
	    delete select_lex->where;
#endif
	    break;
	  }
	}
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1933 1934 1935
	query_cache_store_query(thd, tables);
	res=handle_select(thd, lex, result);
      }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1936
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1937 1938
    break;
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
1939

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1940
  case SQLCOM_DO:
hf@deer.(none)'s avatar
hf@deer.(none) committed
1941
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
1942 1943 1944 1945 1946 1947 1948
		   (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;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1949 1950
    break;

1951
  case SQLCOM_EMPTY_QUERY:
1952
    send_ok(thd);
1953 1954
    break;

1955 1956 1957 1958
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

1959
#ifndef EMBEDDED_LIBRARY
1960
  case SQLCOM_PURGE:
1961
  {
1962
    if (check_global_access(thd, SUPER_ACL))
1963
      goto error;
1964
    // PURGE MASTER LOGS TO 'file'
1965 1966 1967
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
1968 1969 1970 1971 1972 1973 1974 1975
  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;
  }
1976
#endif
1977 1978
  case SQLCOM_SHOW_WARNS:
  {
1979 1980
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
1981 1982 1983
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
1984 1985 1986 1987
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
1988 1989
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
1990 1991
    break;
  }
1992 1993
  case SQLCOM_SHOW_NEW_MASTER:
  {
1994
    if (check_global_access(thd, REPL_SLAVE_ACL))
1995
      goto error;
1996
    /* This query don't work now. See comment in repl_failsafe.cc */
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1997
#ifndef WORKING_NEW_MASTER
1998
    net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1999 2000
    res= 1;
#else
2001
    res = show_new_master(thd);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2002
#endif
2003 2004
    break;
  }
2005

2006
#ifdef HAVE_REPLICATION
2007 2008
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
2009
    if (check_global_access(thd, REPL_SLAVE_ACL))
2010 2011 2012 2013
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
2014 2015
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
2016
    if (check_global_access(thd, REPL_SLAVE_ACL))
2017 2018 2019 2020
      goto error;
    res = show_binlog_events(thd);
    break;
  }
2021 2022
#endif

2023
  case SQLCOM_BACKUP_TABLE:
2024 2025
  {
    if (check_db_used(thd,tables) ||
hf@deer.(none)'s avatar
hf@deer.(none) committed
2026
	check_table_access(thd,SELECT_ACL, tables,0) ||
2027
	check_global_access(thd, FILE_ACL))
2028
      goto error; /* purecov: inspected */
2029
    thd->slow_command=TRUE;
2030
    res = mysql_backup_table(thd, tables);
2031

2032 2033
    break;
  }
2034
  case SQLCOM_RESTORE_TABLE:
2035 2036
  {
    if (check_db_used(thd,tables) ||
hf@deer.(none)'s avatar
hf@deer.(none) committed
2037
	check_table_access(thd, INSERT_ACL, tables,0) ||
2038
	check_global_access(thd, FILE_ACL))
2039
      goto error; /* purecov: inspected */
2040
    thd->slow_command=TRUE;
2041 2042 2043
    res = mysql_restore_table(thd, tables);
    break;
  }
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
2044 2045 2046
  case SQLCOM_ASSIGN_TO_KEYCACHE:
  {
    if (check_db_used(thd, tables) ||
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
2047 2048
        check_access(thd, INDEX_ACL, tables->db,
                     &tables->grant.privilege, 0, 0))
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
2049
      goto error;
2050
    res= mysql_assign_to_keycache(thd, tables, &lex->name_and_length);
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
2051 2052
    break;
  }
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
2053 2054 2055
  case SQLCOM_PRELOAD_KEYS:
  {
    if (check_db_used(thd, tables) ||
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
2056 2057
	check_access(thd, INDEX_ACL, tables->db,
                     &tables->grant.privilege, 0, 0))
2058
      goto error;
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
2059 2060 2061
    res = mysql_preload_keys(thd, tables);
    break;
  }
2062
#ifdef HAVE_REPLICATION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2063
  case SQLCOM_CHANGE_MASTER:
2064
  {
2065
    if (check_global_access(thd, SUPER_ACL))
2066
      goto error;
2067 2068 2069
    LOCK_ACTIVE_MI;
    res = change_master(thd,active_mi);
    UNLOCK_ACTIVE_MI;
2070 2071
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2072
  case SQLCOM_SHOW_SLAVE_STAT:
2073
  {
2074 2075
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2076
      goto error;
2077 2078 2079
    LOCK_ACTIVE_MI;
    res = show_master_info(thd,active_mi);
    UNLOCK_ACTIVE_MI;
2080 2081
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2082
  case SQLCOM_SHOW_MASTER_STAT:
2083
  {
2084 2085
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2086 2087 2088 2089
      goto error;
    res = show_binlog_info(thd);
    break;
  }
peter@mysql.com's avatar
peter@mysql.com committed
2090

2091
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
2092
    if (check_global_access(thd, SUPER_ACL))
2093
      goto error;
2094 2095 2096 2097
    if (end_active_trans(thd))
      res= -1;
    else
      res = load_master_data(thd);
2098
    break;
2099
#endif /* HAVE_REPLICATION */
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
2100 2101 2102
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
2103
      if (check_global_access(thd, SUPER_ACL))
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
2104 2105 2106 2107 2108
	goto error;
      res = innodb_show_status(thd);
      break;
    }
#endif
2109
#ifdef HAVE_REPLICATION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2110
  case SQLCOM_LOAD_MASTER_TABLE:
2111
  {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2112 2113
    if (!tables->db)
      tables->db=thd->db;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2114 2115
#ifndef NO_EMBEDDED_ACCESS_CHECKS
    if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege,0,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2116 2117 2118 2119 2120 2121 2122 2123 2124
      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;
      bool error=check_grant(thd,CREATE_ACL,tables);
      tables->next=tmp_table_list;
      if (error)
2125
	goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2126
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2127
#endif
2128
    if (strlen(tables->real_name) > NAME_LEN)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2129
    {
2130
      net_printf(thd,ER_WRONG_TABLE_NAME, tables->real_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2131 2132
      break;
    }
2133
    LOCK_ACTIVE_MI;
2134 2135 2136 2137
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
2138
    if (!fetch_master_table(thd, tables->db, tables->real_name,
2139
			    active_mi, 0, 0))
2140
    {
2141
      send_ok(thd);
2142 2143
    }
    UNLOCK_ACTIVE_MI;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2144
    break;
2145
  }
2146
#endif /* HAVE_REPLICATION */
2147

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2148
  case SQLCOM_CREATE_TABLE:
2149
  {
hf@deer.(none)'s avatar
hf@deer.(none) committed
2150
#ifndef NO_EMBEDDED_ACCESS_CHECKS
2151 2152
    ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
		      CREATE_TMP_ACL : CREATE_ACL);
hf@deer.(none)'s avatar
hf@deer.(none) committed
2153
#endif
2154 2155
    if (!tables->db)
      tables->db=thd->db;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2156 2157
#ifndef NO_EMBEDDED_ACCESS_CHECKS
    if (check_access(thd,want_priv,tables->db,&tables->grant.privilege,0,0) ||
2158 2159 2160
	check_merge_table_access(thd, tables->db,
				 (TABLE_LIST *)
				 lex->create_info.merge_list.first))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2161
      goto error;				/* purecov: inspected */
2162
    if (grant_option && want_priv != CREATE_TMP_ACL)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2163 2164 2165 2166
    {
      /* Check that the first table has CREATE privilege */
      TABLE_LIST *tmp_table_list=tables->next;
      tables->next=0;
2167
      bool error=check_grant(thd, want_priv, tables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2168 2169 2170 2171
      tables->next=tmp_table_list;
      if (error)
	goto error;
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2172
#endif
2173
    if (strlen(tables->real_name) > NAME_LEN)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2174
    {
2175
      net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2176 2177 2178
      res=0;
      break;
    }
2179 2180 2181
#ifndef HAVE_READLINK
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
2182
    /* Fix names if symlinked tables */
2183
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
2184
			   tables->real_name) ||
2185
	append_file_to_dir(thd,&lex->create_info.index_file_name,
2186
			   tables->real_name))
2187 2188 2189 2190
    {
      res=-1;
      break;
    }
2191
#endif
2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204
    /*
      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;
    }
2205
    if (select_lex->item_list.elements)		// With select
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2206 2207 2208 2209
    {
      select_result *result;

      if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
2210
	  find_real_table_in_list(tables->next, tables->db, tables->real_name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2211
      {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2212
	net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
2213
	DBUG_RETURN(-1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2214
      }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2215
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2216 2217
      if (tables->next)
      {
hf@deer.(none)'s avatar
hf@deer.(none) committed
2218
	if (check_table_access(thd, SELECT_ACL, tables->next,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2219 2220
	  goto error;				// Error message is given
      }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2221
#endif
2222
      select_lex->options|= SELECT_NO_UNLOCK;
2223 2224 2225 2226 2227
      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
2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243

      /* Skip first table, which is the table we are creating */
      lex->select_lex.table_list.first=
	(byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
      if (!(res=open_and_lock_tables(thd,tables->next)))
      {
        if ((result=new select_create(tables->db ? tables->db : thd->db,
                                      tables->real_name, &lex->create_info,
                                      lex->create_list,
                                      lex->key_list,
                                      select_lex->item_list,lex->duplicates)))
          res=handle_select(thd, lex, result);
	else
	  res= -1;
      }
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2244 2245
    else // regular create
    {
venu@myvenu.com's avatar
venu@myvenu.com committed
2246 2247 2248 2249
      if (lex->name)
        res= mysql_create_like_table(thd, tables, &lex->create_info, 
                                     (Table_ident *)lex->name); 
      else
2250
      {
venu@myvenu.com's avatar
venu@myvenu.com committed
2251 2252 2253 2254
        res= mysql_create_table(thd,tables->db ? tables->db : thd->db,
			         tables->real_name, &lex->create_info,
			         lex->create_list,
			         lex->key_list,0,0,0); // do logging
2255
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2256
      if (!res)
2257
	send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2258 2259
    }
    break;
2260
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2261 2262 2263
  case SQLCOM_CREATE_INDEX:
    if (!tables->db)
      tables->db=thd->db;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2264 2265
#ifndef NO_EMBEDDED_ACCESS_CHECKS
    if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege,0,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2266 2267 2268
      goto error; /* purecov: inspected */
    if (grant_option && check_grant(thd,INDEX_ACL,tables))
      goto error;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2269
#endif
2270
    thd->slow_command=TRUE;
2271 2272 2273 2274
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_create_index(thd, tables, lex->key_list);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2275 2276
    break;

2277
#ifdef HAVE_REPLICATION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2278
  case SQLCOM_SLAVE_START:
2279 2280 2281 2282
  {
    LOCK_ACTIVE_MI;
    start_slave(thd,active_mi,1 /* net report*/);
    UNLOCK_ACTIVE_MI;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2283
    break;
2284
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2285
  case SQLCOM_SLAVE_STOP:
2286 2287 2288 2289 2290 2291
  /*
    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,
2292
      so it waits for the client thread because t is locked by it.
2293
    - then the client thread does SLAVE STOP.
2294 2295
      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.
2296 2297 2298 2299 2300
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
  if (thd->locked_tables || thd->active_transaction())
  {
2301
    send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
2302
    goto error;
2303
  }
2304 2305 2306 2307
  {
    LOCK_ACTIVE_MI;
    stop_slave(thd,active_mi,1/* net report*/);
    UNLOCK_ACTIVE_MI;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2308
    break;
2309
  }
2310
#endif /* HAVE_REPLICATION */
2311

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2312 2313
  case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
2314
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
2315
    goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2316 2317
#else
    {
2318
      ulong priv=0;
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
2319
      if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2320
      {
2321
	net_printf(thd, ER_WRONG_TABLE_NAME, lex->name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2322 2323 2324
	res=0;
	break;
      }
2325 2326
      if (!tables->db)
	tables->db=thd->db;
2327 2328
      if (!select_lex->db)
	select_lex->db=tables->db;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2329 2330
      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)||
peter@mysql.com's avatar
peter@mysql.com committed
2331
	  check_merge_table_access(thd, tables->db,
2332 2333 2334
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2335 2336
      if (!tables->db)
	tables->db=thd->db;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2337
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2338 2339 2340 2341 2342 2343 2344 2345 2346
      if (grant_option)
      {
	if (check_grant(thd,ALTER_ACL,tables))
	  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;
2347
	  tmp_table.db=select_lex->db;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2348 2349 2350 2351 2352
	  tmp_table.grant.privilege=priv;
	  if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables))
	    goto error;
	}
      }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2353
#endif
2354 2355
      /* Don't yet allow changing of symlinks with ALTER TABLE */
      lex->create_info.data_file_name=lex->create_info.index_file_name=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2356
      /* ALTER TABLE ends previous transaction */
2357
      if (end_active_trans(thd))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2358 2359
	res= -1;
      else
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2360
      {
2361
        thd->slow_command=TRUE;
2362
	res= mysql_alter_table(thd, select_lex->db, lex->name,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2363 2364 2365
			       &lex->create_info,
			       tables, lex->create_list,
			       lex->key_list, lex->drop_list, lex->alter_list,
2366
			       select_lex->order_list.elements,
2367
                               (ORDER *) select_lex->order_list.first,
2368
			       lex->drop_primary, lex->duplicates,
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
2369 2370 2371
			       lex->alter_keys_onoff,
                               lex->tablespace_op,
			       lex->simple_alter);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2372
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2373 2374
      break;
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2375
#endif /*DONT_ALLOW_SHOW_COMMANDS*/
2376
  case SQLCOM_RENAME_TABLE:
2377 2378 2379
  {
    TABLE_LIST *table;
    if (check_db_used(thd,tables))
2380
      goto error;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2381
#ifndef NO_EMBEDDED_ACCESS_CHECKS
2382 2383
    for (table=tables ; table ; table=table->next->next)
    {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2384
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
hf@deer.(none)'s avatar
hf@deer.(none) committed
2385
		       &table->grant.privilege,0,0) ||
2386
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next->db,
hf@deer.(none)'s avatar
hf@deer.(none) committed
2387
		       &table->next->grant.privilege,0,0))
2388 2389 2390
	goto error;
      if (grant_option)
      {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2391 2392 2393 2394 2395
	TABLE_LIST old_list,new_list;
	old_list=table[0];
	new_list=table->next[0];
	old_list.next=new_list.next=0;
	if (check_grant(thd,ALTER_ACL,&old_list) ||
2396
	    (!test_all_bits(table->next->grant.privilege,
2397
			    INSERT_ACL | CREATE_ACL) &&
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2398
	     check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list)))
2399 2400 2401
	  goto error;
      }
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2402
#endif
2403
    query_cache_invalidate3(thd, tables, 0);
2404 2405 2406
    if (end_active_trans(thd))
      res= -1;
    else if (mysql_rename_tables(thd,tables))
2407 2408
      res= -1;
    break;
2409
  }
2410
#ifndef EMBEDDED_LIBRARY
2411 2412
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2413
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
2414
    goto error;
2415 2416
#else
    {
2417
      if (check_global_access(thd, SUPER_ACL))
2418 2419 2420 2421
	goto error;
      res = show_binlogs(thd);
      break;
    }
peter@mysql.com's avatar
peter@mysql.com committed
2422
#endif
2423
#endif /* EMBEDDED_LIBRARY */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2424
  case SQLCOM_SHOW_CREATE:
2425
#ifdef DONT_ALLOW_SHOW_COMMANDS
2426
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
2427
    goto error;
2428
#else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2429
    {
2430 2431
      if (check_db_used(thd, tables) ||
	  check_access(thd, SELECT_ACL | EXTRA_ACL, tables->db,
hf@deer.(none)'s avatar
hf@deer.(none) committed
2432
		       &tables->grant.privilege,0,0))
2433
	goto error;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2434
      res = mysqld_show_create(thd, tables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2435 2436
      break;
    }
2437
#endif
2438 2439 2440
  case SQLCOM_CHECKSUM:
  {
    if (check_db_used(thd,tables) ||
hf@deer.(none)'s avatar
hf@deer.(none) committed
2441
	check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
2442
      goto error; /* purecov: inspected */
2443
    res = mysql_checksum_table(thd, tables, &lex->check_opt);
2444 2445
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2446
  case SQLCOM_REPAIR:
2447 2448
  {
    if (check_db_used(thd,tables) ||
hf@deer.(none)'s avatar
hf@deer.(none) committed
2449
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
2450
      goto error; /* purecov: inspected */
2451
    thd->slow_command=TRUE;
2452
    res = mysql_repair_table(thd, tables, &lex->check_opt);
2453 2454 2455 2456 2457 2458 2459 2460 2461
    /* ! 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);
      }
    }
2462 2463
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2464
  case SQLCOM_CHECK:
2465 2466
  {
    if (check_db_used(thd,tables) ||
2467
	check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
2468
      goto error; /* purecov: inspected */
2469
    thd->slow_command=TRUE;
2470 2471 2472
    res = mysql_check_table(thd, tables, &lex->check_opt);
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2473 2474
  case SQLCOM_ANALYZE:
  {
2475
    if (check_db_used(thd,tables) ||
hf@deer.(none)'s avatar
hf@deer.(none) committed
2476
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2477
      goto error; /* purecov: inspected */
2478
    thd->slow_command=TRUE;
2479
    res = mysql_analyze_table(thd, tables, &lex->check_opt);
2480 2481 2482 2483 2484 2485 2486 2487 2488
    /* ! 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);
      }
    }
2489
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2490
  }
2491

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2492 2493 2494
  case SQLCOM_OPTIMIZE:
  {
    HA_CREATE_INFO create_info;
2495
    if (check_db_used(thd,tables) ||
hf@deer.(none)'s avatar
hf@deer.(none) committed
2496
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2497
      goto error; /* purecov: inspected */
2498
    thd->slow_command=TRUE;
2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509
    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;
2510
      create_info.default_table_charset=default_charset_info;
2511 2512 2513
      res= mysql_alter_table(thd, NullS, NullS, &create_info,
			     tables, lex->create_list,
			     lex->key_list, lex->drop_list, lex->alter_list,
2514 2515
                             0, (ORDER *) 0,
			     0, DUP_ERROR);
2516 2517 2518
    }
    else
      res = mysql_optimize_table(thd, tables, &lex->check_opt);
2519 2520 2521 2522 2523 2524 2525 2526 2527
    /* ! 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);
      }
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2528 2529 2530
    break;
  }
  case SQLCOM_UPDATE:
2531
    if (check_db_used(thd,tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2532
      goto error;
2533

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2534
    if (single_table_command_access(thd, UPDATE_ACL, tables, &res))
2535
	goto error;
2536
    if (select_lex->item_list.elements != lex->value_list.elements)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2537
    {
2538
      send_error(thd,ER_WRONG_VALUE_COUNT);
2539
      goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2540
    }
2541 2542 2543 2544
    res= mysql_update(thd,tables,
                      select_lex->item_list,
                      lex->value_list,
                      select_lex->where,
2545
		      select_lex->order_list.elements,
2546 2547 2548
                      (ORDER *) select_lex->order_list.first,
                      select_lex->select_limit,
                      lex->duplicates);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2549 2550
    if (thd->net.report_error)
      res= -1;
2551 2552
    break;
  case SQLCOM_UPDATE_MULTI:
hf@deer.(none)'s avatar
hf@deer.(none) committed
2553 2554
#ifndef NO_EMBEDDED_ACCESS_CHECKS
    if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege,0,0))
2555 2556 2557
      goto error;
    if (grant_option && check_grant(thd,UPDATE_ACL,tables))
      goto error;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2558
#endif
2559
    if (select_lex->item_list.elements != lex->value_list.elements)
2560
    {
2561
      send_error(thd,ER_WRONG_VALUE_COUNT);
2562
      goto error;
2563 2564
    }
    {
2565
      const char *msg= 0;
2566
      if (select_lex->order_list.elements)
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2567
	msg= "ORDER BY";
2568 2569
      else if (select_lex->select_limit && select_lex->select_limit !=
	       HA_POS_ERROR)
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2570
	msg= "LIMIT";
2571
      if (msg)
2572
      {
2573
	net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg);
2574 2575
	res= 1;
	break;
2576
      }
2577 2578 2579 2580 2581
      res= mysql_multi_update(thd,tables,
			      &select_lex->item_list,
			      &lex->value_list,
			      select_lex->where,
			      select_lex->options,
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2582
			      lex->duplicates, unit, select_lex);
2583
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2584 2585
    break;
  case SQLCOM_REPLACE:
2586 2587
  case SQLCOM_INSERT:
  {
hf@deer.(none)'s avatar
hf@deer.(none) committed
2588
#ifndef NO_EMBEDDED_ACCESS_CHECKS
2589
    my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
2590
    ulong privilege= (lex->duplicates == DUP_REPLACE ?
2591
                      INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
2592

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2593
    if (single_table_command_access(thd, privilege, tables, &res))
2594
	goto error;
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
2595 2596
#else
    my_bool update=(lex->value_list.elements ? 1 : 0);
hf@deer.(none)'s avatar
hf@deer.(none) committed
2597
#endif
2598 2599 2600
    if (select_lex->item_list.elements != lex->value_list.elements)
    {
      send_error(thd,ER_WRONG_VALUE_COUNT);
2601
      goto error;
2602
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2603
    res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
2604
                       select_lex->item_list, lex->value_list,
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
2605
                       (update ? DUP_UPDATE : lex->duplicates));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2606 2607
    if (thd->net.report_error)
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2608
    break;
2609
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2610 2611 2612
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
2613

2614 2615 2616 2617
    /*
      Check that we have modify privileges for the first table and
      select privileges for the rest
    */
hf@deer.(none)'s avatar
hf@deer.(none) committed
2618
#ifndef NO_EMBEDDED_ACCESS_CHECKS
2619
    {
2620 2621
      ulong privilege= (lex->duplicates == DUP_REPLACE ?
                        INSERT_ACL | DELETE_ACL : INSERT_ACL);
2622 2623 2624
      TABLE_LIST *save_next=tables->next;
      tables->next=0;
      if (check_access(thd, privilege,
hf@deer.(none)'s avatar
hf@deer.(none) committed
2625
		       tables->db,&tables->grant.privilege,0,0) ||
2626 2627
	  (grant_option && check_grant(thd, privilege, tables)))
	goto error;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2628

2629
      tables->next=save_next;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2630
      if ((res=check_table_access(thd, SELECT_ACL, save_next,0)))
2631 2632
	goto error;
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2633
#endif
2634 2635
    /* Don't unlock tables until command is written to binary log */
    select_lex->options|= SELECT_NO_UNLOCK;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2636 2637

    select_result *result;
2638 2639 2640 2641
    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
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2642

2643
    if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
2644
    {
2645 2646
      /* Using same table for INSERT and SELECT */
      select_lex->options |= OPTION_BUFFER_RESULT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2647
    }
2648 2649 2650 2651

    /* 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);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2652 2653
    lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE;

2654 2655 2656
    if (!(res=open_and_lock_tables(thd, tables)))
    {
      if ((result=new select_insert(tables->table,&lex->field_list,
2657
				    lex->duplicates)))
2658
	res=handle_select(thd,lex,result);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2659 2660
      if (thd->net.report_error)
	res= -1;
2661 2662 2663
    }
    else
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2664 2665
    break;
  }
2666
  case SQLCOM_TRUNCATE:
hf@deer.(none)'s avatar
hf@deer.(none) committed
2667 2668
#ifndef NO_EMBEDDED_ACCESS_CHECKS
    if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege,0,0))
2669
      goto error; /* purecov: inspected */
2670 2671
    if (grant_option && check_grant(thd,DELETE_ACL,tables))
      goto error;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2672
#endif
2673 2674 2675 2676 2677 2678
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
    if (thd->locked_tables || thd->active_transaction())
    {
2679
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
2680 2681 2682 2683
      goto error;
    }
    res=mysql_truncate(thd,tables);
    break;
2684
  case SQLCOM_DELETE:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2685
  {
hf@deer.(none)'s avatar
hf@deer.(none) committed
2686
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2687 2688
    if (single_table_command_access(thd, DELETE_ACL, tables, &res))
      goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2689 2690
    // Set privilege for the WHERE clause
    tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
hf@deer.(none)'s avatar
hf@deer.(none) committed
2691
#endif
serg@serg.mysql.com's avatar
serg@serg.mysql.com committed
2692 2693
    res = mysql_delete(thd,tables, select_lex->where,
                       (ORDER*) select_lex->order_list.first,
2694
                       select_lex->select_limit, select_lex->options);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2695 2696
    if (thd->net.report_error)
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2697 2698
    break;
  }
2699
  case SQLCOM_DELETE_MULTI:
2700
  {
2701
    TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
2702 2703 2704
    TABLE_LIST *auxi;
    uint table_count=0;
    multi_delete *result;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2705

2706 2707
    /* sql_yacc guarantees that tables and aux_tables are not zero */
    if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
hf@deer.(none)'s avatar
hf@deer.(none) committed
2708 2709
	check_table_access(thd,SELECT_ACL, tables,0) ||
	check_table_access(thd,DELETE_ACL, aux_tables,0))
2710 2711
      goto error;
    if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
2712
    {
2713
      send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728
      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)
      {
2729
	net_printf(thd,ER_NONUNIQ_TABLE,auxi->real_name);
2730 2731
	goto error;
      }
2732
      walk->lock_type= auxi->lock_type;
2733
      auxi->table_list=  walk;		// Remember corresponding table
2734
    }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2735
    if (add_item_to_list(thd, new Item_null()))
2736
    {
2737
      res= -1;
2738
      break;
2739 2740 2741 2742 2743 2744
    }
    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)
2745
      auxi->table= auxi->table_list->table;
2746
    if (&lex->select_lex != lex->all_selects_list)
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2747
    {
2748 2749 2750 2751 2752
      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))
	{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2753
	  my_error(ER_UPDATE_TABLE_USED, MYF(0), t->real_name);
2754 2755 2756 2757
	  res= -1;
	  break;
	}
      }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2758
    }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2759
    fix_tables_pointers(lex->all_selects_list);
2760 2761
    if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
							  table_count)))
2762
    {
2763 2764 2765
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
2766
			select_lex->item_list,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2767
			select_lex->where,
2768
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2769 2770
			(ORDER *)NULL,
			select_lex->options | thd->options |
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2771
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
2772
			result, unit, select_lex);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2773 2774
      if (thd->net.report_error)
	res= -1;
2775
      delete result;
2776 2777 2778 2779 2780 2781
    }
    else
      res= -1;					// Error is not sent
    close_thread_tables(thd);
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2782
  case SQLCOM_DROP_TABLE:
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2783
  {
2784 2785
    if (!lex->drop_temporary)
    {
hf@deer.(none)'s avatar
hf@deer.(none) committed
2786
      if (check_table_access(thd,DROP_ACL,tables,0))
2787 2788 2789 2790 2791 2792 2793
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2794
    else
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806
    {
      /*
	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;
    }
2807
    res= mysql_rm_table(thd,tables,lex->drop_if_exists, lex->drop_temporary);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2808 2809
  }
  break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2810 2811 2812
  case SQLCOM_DROP_INDEX:
    if (!tables->db)
      tables->db=thd->db;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2813 2814
#ifndef NO_EMBEDDED_ACCESS_CHECKS
    if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege,0,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2815 2816 2817
      goto error;				/* purecov: inspected */
    if (grant_option && check_grant(thd,INDEX_ACL,tables))
      goto error;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2818
#endif
2819 2820 2821 2822
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_drop_index(thd, tables, lex->drop_list);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2823 2824
    break;
  case SQLCOM_SHOW_DATABASES:
2825
#if defined(DONT_ALLOW_SHOW_COMMANDS)
2826
    send_error(thd,ER_NOT_ALLOWED_COMMAND);   /* purecov: inspected */
2827
    goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2828 2829
#else
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
2830
	check_global_access(thd, SHOW_DB_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2831 2832 2833 2834 2835
      goto error;
    res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
    break;
#endif
  case SQLCOM_SHOW_PROCESSLIST:
hf@deer.(none)'s avatar
hf@deer.(none) committed
2836
#ifndef NO_EMBEDDED_ACCESS_CHECKS
2837
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2838
      break;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2839
#endif
hf@deer.(none)'s avatar
hf@deer.(none) committed
2840 2841 2842 2843 2844 2845 2846 2847
    mysqld_list_processes(thd,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
			  thd->master_access & PROCESS_ACL ? NullS :
			  thd->priv_user
#else
			  NullS
#endif
			  ,lex->verbose);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2848
    break;
2849 2850 2851 2852 2853 2854 2855 2856 2857
  case SQLCOM_SHOW_TABLE_TYPES:
    res= mysqld_show_table_types(thd);
    break;
  case SQLCOM_SHOW_PRIVILEGES:
    res= mysqld_show_privileges(thd);
    break;
  case SQLCOM_SHOW_COLUMN_TYPES:
    res= mysqld_show_column_types(thd);
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2858
  case SQLCOM_SHOW_STATUS:
2859
    res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
2860
		     OPT_GLOBAL, &LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2861 2862 2863
    break;
  case SQLCOM_SHOW_VARIABLES:
    res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
2864 2865
		     init_vars, lex->option_type,
		     &LOCK_global_system_variables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2866
    break;
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
2867 2868
  case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2869
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
2870
    goto error;
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
2871 2872
#else
    {
hf@deer.(none)'s avatar
hf@deer.(none) committed
2873 2874
#ifndef NO_EMBEDDED_ACCESS_CHECKS
      if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0))
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
2875
	goto error;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2876
#endif
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
2877 2878 2879 2880
      res= mysqld_show_logs(thd);
      break;
    }
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2881
  case SQLCOM_SHOW_TABLES:
2882
    /* FALL THROUGH */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2883
#ifdef DONT_ALLOW_SHOW_COMMANDS
2884
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
2885
    goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2886 2887
#else
    {
2888
      char *db=select_lex->db ? select_lex->db : thd->db;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2889 2890
      if (!db)
      {
2891
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2892 2893 2894
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);				// Fix escaped '_'
2895
      if (check_db_name(db))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2896
      {
2897
        net_printf(thd,ER_WRONG_DB_NAME, db);
2898
        goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2899
      }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2900 2901
#ifndef NO_EMBEDDED_ACCESS_CHECKS
      if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2902
	goto error;				/* purecov: inspected */
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2903
      if (!thd->col_access && check_grant_db(thd,db))
2904
      {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2905
	net_printf(thd, ER_DBACCESS_DENIED_ERROR,
2906 2907 2908 2909 2910
		   thd->priv_user,
		   thd->priv_host,
		   db);
	goto error;
      }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2911
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2912
      /* grant is checked in mysqld_show_tables */
2913
      if (select_lex->options & SELECT_DESCRIBE)
2914
        res= mysqld_extend_show_tables(thd,db,
2915
				       (lex->wild ? lex->wild->ptr() : NullS));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2916 2917 2918 2919 2920 2921
      else
	res= mysqld_show_tables(thd,db,
				(lex->wild ? lex->wild->ptr() : NullS));
      break;
    }
#endif
2922 2923 2924
  case SQLCOM_SHOW_OPEN_TABLES:
    res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
2925 2926
  case SQLCOM_SHOW_CHARSETS:
    res= mysqld_show_charsets(thd,(lex->wild ? lex->wild->ptr() : NullS));
2927
    break;
2928 2929 2930
  case SQLCOM_SHOW_COLLATIONS:
    res= mysqld_show_collations(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2931 2932
  case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2933
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
2934
    goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2935 2936
#else
    {
2937 2938
      char *db=tables->db;
      if (!*db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2939
      {
2940
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2941 2942 2943
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);			// Fix escaped '_'
2944
      remove_escape(tables->real_name);
hf@deer.(none)'s avatar
hf@deer.(none) committed
2945 2946
#ifndef NO_EMBEDDED_ACCESS_CHECKS
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access,0,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2947 2948 2949 2950
	goto error;				/* purecov: inspected */
      tables->grant.privilege=thd->col_access;
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
	goto error;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2951
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2952
      res= mysqld_show_fields(thd,tables,
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2953 2954
			      (lex->wild ? lex->wild->ptr() : NullS),
			      lex->verbose);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2955 2956 2957 2958 2959
      break;
    }
#endif
  case SQLCOM_SHOW_KEYS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2960
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
2961
    goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2962 2963
#else
    {
2964
      char *db=tables->db;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2965 2966
      if (!db)
      {
2967
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2968 2969 2970
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);			// Fix escaped '_'
2971
      remove_escape(tables->real_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2972 2973
      if (!tables->db)
	tables->db=thd->db;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2974 2975
#ifndef NO_EMBEDDED_ACCESS_CHECKS
      if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2976 2977 2978 2979
	goto error; /* purecov: inspected */
      tables->grant.privilege=thd->col_access;
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
	goto error;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2980
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2981 2982 2983 2984 2985
      res= mysqld_show_keys(thd,tables);
      break;
    }
#endif
  case SQLCOM_CHANGE_DB:
2986
    mysql_change_db(thd,select_lex->db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2987
    break;
2988

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2989 2990
  case SQLCOM_LOAD:
  {
hf@deer.(none)'s avatar
hf@deer.(none) committed
2991
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2992
    uint privilege= (lex->duplicates == DUP_REPLACE ?
2993
		     INSERT_ACL | DELETE_ACL : INSERT_ACL);
2994 2995

    if (!lex->local_file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2996
    {
hf@deer.(none)'s avatar
hf@deer.(none) committed
2997
      if (check_access(thd,privilege | FILE_ACL,tables->db,0,0,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2998 2999 3000 3001
	goto error;
    }
    else
    {
3002
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
3003
	  ! opt_local_infile)
3004
      {
3005
	send_error(thd,ER_NOT_ALLOWED_COMMAND);
3006 3007
	goto error;
      }
hf@deer.(none)'s avatar
hf@deer.(none) committed
3008
      if (check_access(thd,privilege,tables->db,&tables->grant.privilege,0,0) ||
3009
	  grant_option && check_grant(thd,privilege,tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3010 3011
	goto error;
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
3012
#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3013 3014 3015 3016
    res=mysql_load(thd, lex->exchange, tables, lex->field_list,
		   lex->duplicates, (bool) lex->local_file, lex->lock_option);
    break;
  }
3017

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3018
  case SQLCOM_SET_OPTION:
hf@deer.(none)'s avatar
hf@deer.(none) committed
3019
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
3020 3021 3022 3023
		   (res= open_and_lock_tables(thd,tables))))
      break;
    fix_tables_pointers(lex->all_selects_list);
    if (!(res= sql_set_variables(thd, &lex->var_list)))
3024
      send_ok(thd);
3025 3026
    if (thd->net.report_error)
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3027
    break;
3028

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3029
  case SQLCOM_UNLOCK_TABLES:
3030
    unlock_locked_tables(thd);
3031 3032
    if (thd->options & OPTION_TABLE_LOCK)
    {
3033
      end_active_trans(thd);
3034
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3035 3036
    }
    if (thd->global_read_lock)
3037
      unlock_global_read_lock(thd);
3038
    send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3039 3040
    break;
  case SQLCOM_LOCK_TABLES:
3041
    unlock_locked_tables(thd);
3042
    if (check_db_used(thd,tables) || end_active_trans(thd))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3043
      goto error;
hf@deer.(none)'s avatar
hf@deer.(none) committed
3044
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables,0))
3045
      goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3046
    thd->in_lock_tables=1;
3047
    thd->options|= OPTION_TABLE_LOCK;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3048 3049 3050 3051
    if (!(res=open_and_lock_tables(thd,tables)))
    {
      thd->locked_tables=thd->lock;
      thd->lock=0;
3052
      send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3053
    }
3054 3055
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3056 3057 3058
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
3059
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3060
    if (!strip_sp(lex->name) || check_db_name(lex->name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3061
    {
3062
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3063 3064
      break;
    }
3065 3066 3067 3068 3069 3070 3071
    /*
      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.
    */
3072
#ifdef HAVE_REPLICATION
3073 3074 3075
    if (thd->slave_thread && 
	(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(lex->name)))
guilhem@mysql.com's avatar
guilhem@mysql.com committed
3076 3077
    {
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
3078
      break;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
3079
    }
3080
#endif
hf@deer.(none)'s avatar
hf@deer.(none) committed
3081
    if (check_access(thd,CREATE_ACL,lex->name,0,1,0))
3082
      break;
3083
    res=mysql_create_db(thd,lex->name,&lex->create_info,0);
3084 3085
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3086
  case SQLCOM_DROP_DB:
3087
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3088
    if (!strip_sp(lex->name) || check_db_name(lex->name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3089
    {
3090
      net_printf(thd, ER_WRONG_DB_NAME, lex->name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3091 3092
      break;
    }
3093 3094 3095 3096 3097 3098 3099
    /*
      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.
    */
3100
#ifdef HAVE_REPLICATION
3101 3102 3103
    if (thd->slave_thread && 
	(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(lex->name)))
guilhem@mysql.com's avatar
guilhem@mysql.com committed
3104 3105
    {
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
3106
      break;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
3107
    }
3108
#endif
hf@deer.(none)'s avatar
hf@deer.(none) committed
3109
    if (check_access(thd,DROP_ACL,lex->name,0,1,0))
3110
      break;
3111 3112
    if (thd->locked_tables || thd->active_transaction())
    {
3113
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
3114 3115
      goto error;
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3116
    res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0);
3117 3118
    break;
  }
3119 3120 3121 3122
  case SQLCOM_ALTER_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
3123
      net_printf(thd, ER_WRONG_DB_NAME, lex->name);
3124 3125
      break;
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
3126
    if (check_access(thd,ALTER_ACL,lex->name,0,1,0))
3127 3128 3129
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
3130
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
3131 3132
      goto error;
    }
3133
    res=mysql_alter_db(thd,lex->name,&lex->create_info);
3134 3135
    break;
  }
3136 3137 3138 3139
  case SQLCOM_SHOW_CREATE_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
3140
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
3141 3142
      break;
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
3143
    if (check_access(thd,DROP_ACL,lex->name,0,1,0))
3144 3145 3146
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
3147
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
3148 3149
      goto error;
    }
3150
    res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
3151 3152
    break;
  }
3153 3154
  case SQLCOM_CREATE_FUNCTION:	// UDF function
    {
pem@mysql.com's avatar
pem@mysql.com committed
3155
      if (check_access(thd,INSERT_ACL,"mysql",0,1,0))
3156
	break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3157
#ifdef HAVE_DLOPEN
3158 3159 3160 3161 3162 3163 3164 3165
      sp_head *sph= sp_find_function(thd, &lex->udf.name);
      if (sph)
      {
	net_printf(thd, ER_UDF_EXISTS, lex->udf.name.str);
	goto error;
      }
      if (!(res = mysql_create_function(thd,&lex->udf)))
	send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3166
#else
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
3167
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3168 3169
#endif
    break;
3170
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
3171
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3172 3173
  case SQLCOM_DROP_USER:
  {
hf@deer.(none)'s avatar
hf@deer.(none) committed
3174
    if (check_access(thd, GRANT_ACL,"mysql",0,1,0))
3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188
      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:
  {
hf@deer.(none)'s avatar
hf@deer.(none) committed
3189
    if (check_access(thd, GRANT_ACL ,"mysql",0,1,0))
3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201
      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;
  }
3202 3203 3204 3205 3206 3207
  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,
hf@deer.(none)'s avatar
hf@deer.(none) committed
3208
		     tables ? 0 : 1,0))
3209 3210
      goto error;

3211 3212 3213 3214
    /*
      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
    */
3215 3216 3217 3218 3219 3220 3221 3222 3223 3224

    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 &&
3225
	     my_strcasecmp(&my_charset_latin1,
3226
                           user->host.str, thd->host_or_ip)))
3227
	{
hf@deer.(none)'s avatar
hf@deer.(none) committed
3228
	  if (check_access(thd, UPDATE_ACL, "mysql",0,1,0))
3229 3230 3231 3232 3233
	    goto error;
	  break;			// We are allowed to do changes
	}
      }
    }
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246
    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);
      }
    }
3247 3248 3249 3250 3251 3252 3253
    if (tables)
    {
      if (grant_option && check_grant(thd,
				      (lex->grant | lex->grant_tot_col |
				       GRANT_ACL),
				      tables))
	goto error;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3254 3255
      if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
				    lex->grant,
3256 3257
				    lex->sql_command == SQLCOM_REVOKE)) &&
          mysql_bin_log.is_open())
3258
      {
3259 3260
        Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
        mysql_bin_log.write(&qinfo);
3261 3262 3263 3264 3265 3266
      }
    }
    else
    {
      if (lex->columns.elements)
      {
3267
	send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE);
3268 3269 3270 3271 3272 3273 3274 3275 3276
	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())
	{
3277
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
3278 3279
	  mysql_bin_log.write(&qinfo);
	}
3280
	if (mqh_used && lex->sql_command == SQLCOM_GRANT)
3281
	{
3282 3283 3284
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
3285
	    reset_mqh(thd,user);
3286
	}
3287 3288 3289 3290
      }
    }
    break;
  }
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
3291
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3292
  case SQLCOM_RESET:
3293 3294 3295 3296 3297 3298 3299
    /* 
       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:
  {
3300
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3301
      goto error;
3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324
    /*
      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);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3325
    break;
3326
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3327
  case SQLCOM_KILL:
hf@genie.(none)'s avatar
SCRUM  
hf@genie.(none) committed
3328
    kill_one_thread(thd,lex->thread_id, lex->type & ONLY_KILL_QUERY);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3329
    break;
hf@deer.(none)'s avatar
hf@deer.(none) committed
3330
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3331 3332
  case SQLCOM_SHOW_GRANTS:
    res=0;
3333 3334
    if ((thd->priv_user &&
	 !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
hf@deer.(none)'s avatar
hf@deer.(none) committed
3335
	!check_access(thd, SELECT_ACL, "mysql",0,1,0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3336 3337 3338 3339
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
hf@deer.(none)'s avatar
hf@deer.(none) committed
3340
#endif
3341
  case SQLCOM_HA_OPEN:
3342
    if (check_db_used(thd,tables) ||
hf@deer.(none)'s avatar
hf@deer.(none) committed
3343
	check_table_access(thd,SELECT_ACL, tables,0))
3344 3345 3346 3347 3348 3349 3350 3351 3352
      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:
3353 3354 3355 3356 3357
    /*
      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.
    */
serg@serg.mylan's avatar
serg@serg.mylan committed
3358
    if (check_db_used(thd,tables))
3359
      goto error;
serg@serg.mysql.com's avatar
serg@serg.mysql.com committed
3360
    res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
3361 3362
			lex->insert_list, lex->ha_rkey_mode, select_lex->where,
			select_lex->select_limit, select_lex->offset_limit);
3363 3364
    break;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3365
  case SQLCOM_BEGIN:
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3366 3367 3368 3369 3370 3371
    if (thd->locked_tables)
    {
      thd->lock=thd->locked_tables;
      thd->locked_tables=0;			// Will be automaticly closed
      close_thread_tables(thd);			// Free tables
    }
3372 3373 3374 3375 3376 3377
    if (end_active_trans(thd))
    {
      res= -1;
    }
    else
    {
3378
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
3379 3380
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
3381
      send_ok(thd);
3382
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3383 3384
    break;
  case SQLCOM_COMMIT:
3385 3386 3387 3388 3389
    /*
      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...)
    */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3390
  {
3391
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3392 3393
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3394
    {
3395
      send_ok(thd);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3396
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3397 3398 3399
    else
      res= -1;
    break;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3400
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3401 3402 3403
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
3404
    {
guilhem@mysql.com's avatar
guilhem@mysql.com committed
3405 3406 3407 3408 3409 3410 3411 3412 3413 3414
      /*
        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)
3415
	send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
3416
      else
3417
	send_ok(thd);
3418
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3419 3420
    else
      res= -1;
3421
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3422
    break;
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
3423 3424 3425
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
    if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
    {
guilhem@mysql.com's avatar
guilhem@mysql.com committed
3426
      if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3427
	send_warning(thd, ER_WARNING_NOT_COMPLETE_ROLLBACK, 0);
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
3428
      else
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3429
	send_ok(thd);
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
3430 3431 3432 3433
    }
    else
      res= -1;
    break;
3434
  case SQLCOM_SAVEPOINT:
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
3435
    if (!ha_savepoint(thd, lex->savepoint_name))
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3436
      send_ok(thd);
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
3437 3438
    else
      res= -1;
3439
    break;
3440 3441
  case SQLCOM_CREATE_PROCEDURE:
  case SQLCOM_CREATE_SPFUNCTION:
3442
    if (!lex->sphead)
3443
    {
3444 3445
      res= -1;			// Shouldn't happen
      break;
3446
    }
3447 3448
    else
    {
3449 3450
      uint namelen;
      char *name= lex->sphead->name(&namelen);
3451
#ifdef HAVE_DLOPEN
3452
      if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
3453
      {
3454 3455 3456 3457 3458 3459 3460
	udf_func *udf = find_udf(name, namelen);

	if (udf)
	{
	  net_printf(thd, ER_UDF_EXISTS, name);
	  goto error;
	}
3461
      }
3462
#endif
3463 3464 3465 3466 3467 3468 3469
      if (lex->sphead->m_type == TYPE_ENUM_FUNCTION &&
	  !lex->sphead->m_has_return)
      {
	net_printf(thd, ER_SP_NORETURN, name);
	goto error;
      }

3470
      res= lex->sphead->create(thd);
3471

3472
      switch (res)
3473
      {
3474 3475 3476 3477
      case SP_OK:
	send_ok(thd);
	break;
      case SP_WRITE_ROW_FAILED:
3478
	net_printf(thd, ER_SP_ALREADY_EXISTS, SP_TYPE_STRING(lex), name);
3479
	goto error;
3480
      default:
3481
	net_printf(thd, ER_SP_STORE_FAILED, SP_TYPE_STRING(lex), name);
3482
	goto error;
3483
      }
3484
      break;
3485 3486 3487 3488 3489
    }
  case SQLCOM_CALL:
    {
      sp_head *sp;

3490
      sp= sp_find_procedure(thd, &lex->udf.name);
3491 3492
      if (! sp)
      {
3493
	net_printf(thd, ER_SP_DOES_NOT_EXIST, "PROCEDURE", lex->udf.name);
3494
	goto error;
3495 3496 3497
      }
      else
      {
3498
	st_sp_security_context save_ctx;
3499 3500 3501
	uint smrx;
	LINT_INIT(smrx);

pem@mysql.com's avatar
pem@mysql.com committed
3502
	// In case the arguments are subselects...
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
3503
	if (tables && ((res= check_table_access(thd, SELECT_ACL, tables, 0)) ||
pem@mysql.com's avatar
pem@mysql.com committed
3504 3505
		       (res= open_and_lock_tables(thd, tables))))
	{
3506
	  break;
pem@mysql.com's avatar
pem@mysql.com committed
3507
	}
3508 3509
	fix_tables_pointers(lex->all_selects_list);

3510
#ifndef EMBEDDED_LIBRARY
3511 3512 3513 3514
	// 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;
3515
#endif
3516
	if (sp->m_multi_results)
3517
	{
3518
	  if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529
	  {
	    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;
	}

3530 3531
	sp_change_security_context(thd, sp, &save_ctx);

3532
	res= sp->execute_procedure(thd, &lex->value_list);
3533

3534 3535
	sp_restore_security_context(thd, sp, &save_ctx);

3536
#ifndef EMBEDDED_LIBRARY
3537
	thd->net.no_send_ok= nsok;
3538
#endif
3539
	if (sp->m_multi_results)
3540 3541 3542 3543
	{
	  if (! smrx)
	    thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
	}
3544

3545 3546
	if (res == 0)
	  send_ok(thd);
3547 3548
	else
	  goto error;		// Substatement should already have sent error
3549
      }
3550
      break;
3551 3552
    }
  case SQLCOM_ALTER_PROCEDURE:
3553
  case SQLCOM_ALTER_FUNCTION:
3554
    {
3555 3556 3557 3558 3559
      res= -1;
      uint newname_len= 0;
      if (lex->name)
	newname_len= strlen(lex->name);
      if (newname_len > NAME_LEN)
3560
      {
3561
	net_printf(thd, ER_TOO_LONG_IDENT, lex->name);
3562
	goto error;
3563
      }
3564 3565
      if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
	res= sp_update_procedure(thd, lex->udf.name.str, lex->udf.name.length,
3566
				 lex->name, newname_len, &lex->sp_chistics);
3567
      else
3568
	res= sp_update_function(thd, lex->udf.name.str, lex->udf.name.length,
3569
				lex->name, newname_len,	&lex->sp_chistics);
3570
      switch (res)
3571
      {
3572
      case SP_OK:
3573
	send_ok(thd);
3574 3575 3576 3577 3578 3579 3580
	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;
3581
      }
3582
      break;
3583 3584
    }
  case SQLCOM_DROP_PROCEDURE:
3585
  case SQLCOM_DROP_FUNCTION:
3586
    {
3587 3588
      if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
	res= sp_drop_procedure(thd, lex->udf.name.str, lex->udf.name.length);
3589 3590
      else
      {
3591 3592 3593
	res= sp_drop_function(thd, lex->udf.name.str, lex->udf.name.length);
#ifdef HAVE_DLOPEN
	if (res == SP_KEY_NOT_FOUND)
3594
	{
3595 3596 3597
	  udf_func *udf = find_udf(lex->udf.name.str, lex->udf.name.length);
	  if (udf)
	  {
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
3598
	    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0))
3599 3600 3601 3602 3603 3604 3605
	      goto error;
	    if (!(res = mysql_drop_function(thd,&lex->udf.name)))
	    {
	      send_ok(thd);
	      break;
	    }
	  }
3606
	}
3607 3608 3609 3610 3611
#endif
      }
      switch (res)
      {
      case SP_OK:
3612
	send_ok(thd);
3613 3614
	break;
      case SP_KEY_NOT_FOUND:
3615 3616 3617 3618 3619 3620 3621 3622 3623
	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;
	}
3624 3625
	net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex),
		   lex->udf.name.str);
3626 3627
	goto error;
      default:
3628 3629
	net_printf(thd, ER_SP_DROP_FAILED, SP_COM_STRING(lex),
		   lex->udf.name.str);
3630
	goto error;
3631
      }
3632
      break;
3633
    }
3634 3635 3636 3637 3638 3639 3640 3641 3642
  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);
3643 3644 3645
      if (res != SP_OK)
      {			/* We don't distinguish between errors for now */
	net_printf(thd, ER_SP_DOES_NOT_EXIST,
3646
		   SP_COM_STRING(lex), lex->udf.name.str);
3647
	res= 0;
3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659
	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);
3660 3661
      if (res != SP_OK)
      {			/* We don't distinguish between errors for now */
3662 3663
	net_printf(thd, ER_SP_DOES_NOT_EXIST,
		   SP_COM_STRING(lex), lex->udf.name.str);
3664
	res= 0;
3665 3666 3667 3668 3669 3670
	goto error;
      }
      break;
    }
  case SQLCOM_SHOW_STATUS_PROC:
    {
3671
      res= sp_show_status_procedure(thd, (lex->wild ?
3672 3673 3674 3675 3676
					  lex->wild->ptr() : NullS));
      break;
    }
  case SQLCOM_SHOW_STATUS_FUNC:
    {
3677
      res= sp_show_status_function(thd, (lex->wild ? 
3678 3679 3680
					 lex->wild->ptr() : NullS));
      break;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3681
  default:					/* Impossible */
3682
    send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3683 3684 3685
    break;
  }
  thd->proc_info="query end";			// QQ
3686 3687 3688

  // We end up here if res == 0 and send_ok() has been done,
  // or res != 0 and no send_error() has yet been done.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3689
  if (res < 0)
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
3690
    send_error(thd,thd->killed_errno());
3691
  DBUG_RETURN(res);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3692 3693

error:
3694
  // We end up here if send_error() has already been done.
3695
  DBUG_RETURN(-1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3696 3697 3698
}


hf@deer.(none)'s avatar
hf@deer.(none) committed
3699
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3700 3701 3702 3703
/*
  Check grants for commands which work only with one table and all other
  tables belong to subselects.

3704
  SYNOPSIS
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715
    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
*/

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3716
static bool single_table_command_access(THD *thd, ulong privilege,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3717 3718 3719
					TABLE_LIST *tables, int *res)
					 
{
hf@deer.(none)'s avatar
hf@deer.(none) committed
3720
    if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3721 3722 3723 3724 3725 3726 3727 3728 3729
      return 1;

    // Show only 1 table for check_grant
    TABLE_LIST *subselects_tables= tables->next;
    tables->next= 0;
    if (grant_option && check_grant(thd,  privilege, tables))
      return 1;

    // check rights on tables of subselect (if exists)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3730 3731 3732
    if (subselects_tables)
    {
      tables->next= subselects_tables;
hf@deer.(none)'s avatar
hf@deer.(none) committed
3733
      if ((*res= check_table_access(thd, SELECT_ACL, subselects_tables,0)))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3734 3735
	return 1;
    }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3736 3737 3738 3739
    return 0;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
3740
/****************************************************************************
3741
  Get the user (global) and database privileges for all used tables
3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754

  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
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3755 3756
                is enough to satisfy the request and the global grants contains
                a SELECT grant.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3757 3758 3759
****************************************************************************/

bool
3760
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
3761
	     bool dont_check_global_grants, bool no_errors)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3762
{
3763 3764 3765 3766
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("want_access: %lu  master_access: %lu", want_access,
		      thd->master_access));
  ulong db_access,dummy;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3767 3768 3769 3770 3771
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

3772
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3773
  {
3774
    if (!no_errors)
3775
      send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
3776
    DBUG_RETURN(TRUE);				/* purecov: tested */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3777 3778 3779 3780
  }

  if ((thd->master_access & want_access) == want_access)
  {
3781 3782 3783 3784 3785 3786 3787 3788
    /*
      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))))
3789
      db_access=acl_get(thd->host, thd->ip,
3790
			thd->priv_user, db, test(want_access & GRANT_ACL));
3791
    *save_priv=thd->master_access | db_access;
3792
    DBUG_RETURN(FALSE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3793
  }
3794
  if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
3795
      ! db && dont_check_global_grants)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3796
  {						// We can never grant this
3797
    if (!no_errors)
3798
      net_printf(thd,ER_ACCESS_DENIED_ERROR,
3799
		 thd->priv_user,
3800
		 thd->priv_host,
3801
		 thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
3802
    DBUG_RETURN(TRUE);				/* purecov: tested */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3803 3804 3805
  }

  if (db == any_db)
3806
    DBUG_RETURN(FALSE);				// Allow select on anything
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3807

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3808
  if (db && (!thd->db || strcmp(db,thd->db)))
3809
    db_access=acl_get(thd->host, thd->ip,
3810
		      thd->priv_user, db, test(want_access & GRANT_ACL));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3811 3812
  else
    db_access=thd->db_access;
3813 3814
  // Remove SHOW attribute and access rights we already have
  want_access &= ~(thd->master_access | EXTRA_ACL);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3815
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
3816 3817

  /* grant_option is set if there exists a single table or column grant */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3818
  if (db_access == want_access ||
3819
      ((grant_option && !dont_check_global_grants) &&
3820
       !(want_access & ~(db_access | TABLE_ACLS))))
3821
    DBUG_RETURN(FALSE);				/* Ok */
3822
  if (!no_errors)
3823
    net_printf(thd,ER_DBACCESS_DENIED_ERROR,
3824
	       thd->priv_user,
3825
	       thd->priv_host,
3826
	       db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
3827
  DBUG_RETURN(TRUE);				/* purecov: tested */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3828 3829 3830
}


3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848
/*
  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
*/
3849 3850

bool check_global_access(THD *thd, ulong want_access)
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3851
{
3852
  char command[128];
3853
  if ((thd->master_access & want_access))
3854 3855
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
3856
  net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
3857 3858
	     command);
  return 1;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3859 3860 3861
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
3862
/*
3863 3864
  Check the privilege for all used tables.  Table privileges are cached
  in the table list for GRANT checking
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3865 3866
*/

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

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

hf@deer.(none)'s avatar
hf@deer.(none) committed
3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3941 3942 3943 3944 3945 3946 3947 3948 3949 3950
/****************************************************************************
	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

3951
#ifndef EMBEDDED_LIBRARY
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3952 3953 3954 3955 3956 3957 3958 3959
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));
3960
    thd->fatal_error();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3961 3962 3963 3964
    return 1;
  }
  return 0;
}
3965
#endif /* EMBEDDED_LIBRARY */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999

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


/****************************************************************************
4000
  Initialize global thd variables needed for query
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4001 4002
****************************************************************************/

4003
void
4004
mysql_init_query(THD *thd, bool lexonly)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4005 4006
{
  DBUG_ENTER("mysql_init_query");
4007
  LEX *lex=thd->lex;
4008 4009
  lex->unit.init_query();
  lex->unit.init_select();
4010
  lex->unit.thd= thd;
4011 4012 4013
  lex->select_lex.init_query();
  lex->value_list.empty();
  lex->param_list.empty();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4014 4015
  lex->unit.next= lex->unit.master= 
    lex->unit.link_next= lex->unit.return_to=0;
4016
  lex->unit.prev= lex->unit.link_prev= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4017
  lex->unit.slave= lex->unit.global_parameters= lex->current_select=
4018
    lex->all_selects_list= &lex->select_lex;
4019 4020
  lex->select_lex.master= &lex->unit;
  lex->select_lex.prev= &lex->unit.slave;
4021
  lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
4022
  lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
4023
  lex->select_lex.options=0;
4024 4025
  lex->select_lex.init_order();
  lex->select_lex.group_list.empty();
4026 4027
  lex->describe= 0;
  lex->derived_tables= FALSE;
4028 4029
  lex->lock_option= TL_READ;
  lex->found_colon= 0;
4030
  lex->safe_to_cache_query= 1;
4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044
  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;
    thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
    thd->tmp_table_used= 0;
    if (opt_bin_log)
      reset_dynamic(&thd->user_var_events);
    thd->clear_error();
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4045 4046 4047
  DBUG_VOID_RETURN;
}

4048

4049 4050 4051
void
mysql_init_select(LEX *lex)
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4052
  SELECT_LEX *select_lex= lex->current_select;
4053
  select_lex->init_select();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4054
  select_lex->select_limit= lex->thd->variables.select_limit;
4055 4056 4057 4058 4059 4060
  if (select_lex == &lex->select_lex)
  {
    lex->exchange= 0;
    lex->result= 0;
    lex->proc_list.first= 0;
  }
4061 4062
}

4063

4064
bool
4065
mysql_new_select(LEX *lex, bool move_down)
4066
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4067
  SELECT_LEX *select_lex = new(&lex->thd->mem_root) SELECT_LEX();
4068 4069
  if (!select_lex)
    return 1;
4070
  select_lex->select_number= ++lex->thd->select_number;
4071 4072 4073 4074 4075
  select_lex->init_query();
  select_lex->init_select();
  if (move_down)
  {
    /* first select_lex of subselect or derived table */
4076
    SELECT_LEX_UNIT *unit= new(&lex->thd->mem_root) SELECT_LEX_UNIT();
4077 4078 4079 4080
    if (!unit)
      return 1;
    unit->init_query();
    unit->init_select();
4081
    unit->thd= lex->thd;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4082
    unit->include_down(lex->current_select);
4083 4084
    unit->link_next= 0;
    unit->link_prev= 0;
4085
    unit->return_to= lex->current_select;
4086
    select_lex->include_down(unit);
4087
    // TODO: assign resolve_mode for fake subquery after merging with new tree
4088 4089
  }
  else
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4090
  {
4091
    select_lex->include_neighbour(lex->current_select);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4092 4093 4094 4095 4096 4097 4098 4099
    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
      */
4100
      fake= unit->fake_select_lex= new(&lex->thd->mem_root) SELECT_LEX();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4101 4102 4103 4104 4105 4106 4107 4108
      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;
    }
  }
peter@mysql.com's avatar
peter@mysql.com committed
4109

4110
  select_lex->master_unit()->global_parameters= select_lex;
4111
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
4112
  lex->current_select= select_lex;
4113
  select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
4114
  return 0;
4115
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4116

4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131
/*
  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)
{
4132
  THD *thd;
4133
  LEX *lex;
4134
  LEX_STRING tmp, null_lex_string;
4135
  DBUG_ENTER("create_select_for_variable");
4136 4137

  thd= current_thd;
pem@mysql.telia.com's avatar
pem@mysql.telia.com committed
4138
  lex= thd->lex;
4139 4140 4141 4142
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
4143 4144 4145
  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));
4146 4147 4148
  DBUG_VOID_RETURN;
}

4149

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4150 4151
void mysql_init_multi_delete(LEX *lex)
{
4152
  lex->sql_command=  SQLCOM_DELETE_MULTI;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4153
  mysql_init_select(lex);
4154
  lex->select_lex.select_limit= lex->unit.select_limit_cnt=
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
4155
    HA_POS_ERROR;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4156
  lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4157
}
4158

4159

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4160
void
4161
mysql_parse(THD *thd, char *inBuf, uint length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4162 4163 4164 4165
{
  DBUG_ENTER("mysql_parse");

  mysql_init_query(thd);
4166
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4167 4168
  {
    LEX *lex=lex_start(thd, (uchar*) inBuf, length);
4169
    if (!yyparse((void *)thd) && ! thd->is_fatal_error)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4170
    {
hf@deer.(none)'s avatar
hf@deer.(none) committed
4171
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4172
      if (mqh_used && thd->user_connect &&
4173
	  check_mqh(thd, lex->sql_command))
4174 4175 4176 4177
      {
	thd->net.error = 0;
      }
      else
hf@deer.(none)'s avatar
hf@deer.(none) committed
4178
#endif
4179
      {
4180
	if (thd->net.report_error)
4181
	{
4182
	  send_error(thd, 0, NullS);
4183
	  if (thd->lex->sphead)
4184 4185 4186 4187 4188 4189
	  {
	    if (lex != thd->lex)
	      thd->lex->sphead->restore_lex(thd);
	    delete thd->lex->sphead;
	    thd->lex->sphead= NULL;
	  }
4190
	}
4191 4192 4193
	else
	{
	  mysql_execute_command(thd);
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
4194
#ifndef EMBEDDED_LIBRARY  /* TODO query cache in embedded library*/
4195
	  query_cache_end_of_result(&thd->net);
4196
#endif
4197
	}
4198
      }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4199 4200
    }
    else
4201 4202
    {
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
4203
			 thd->is_fatal_error));
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
4204
#ifndef EMBEDDED_LIBRARY   /* TODO query cache in embedded library*/
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4205
      query_cache_abort(&thd->net);
4206
      if (thd->lex->sphead)
4207 4208 4209 4210 4211 4212
      {
	if (lex != thd->lex)
	  thd->lex->sphead->restore_lex(thd);
	delete thd->lex->sphead;
	thd->lex->sphead= NULL;
      }
4213
#endif
4214
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4215
    thd->proc_info="freeing items";
4216
    free_items(thd->free_list);  /* Free strings used by items */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4217 4218
    lex_end(lex);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4219 4220 4221 4222 4223 4224 4225 4226 4227
  DBUG_VOID_RETURN;
}


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

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4228
bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4229
		       char *length, char *decimals,
4230
		       uint type_modifier,
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4231
		       Item *default_value, LEX_STRING *comment,
4232 4233
		       char *change, TYPELIB *interval, CHARSET_INFO *cs,
		       uint uint_geom_type)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4234 4235
{
  register create_field *new_field;
4236
  LEX  *lex= thd->lex;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4237
  uint allowed_type_modifier=0;
4238
  char warn_buff[MYSQL_ERRMSG_SIZE];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4239 4240 4241 4242
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
4243
    net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4244 4245 4246 4247 4248
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
4249
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4250 4251 4252 4253 4254 4255
				    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));
4256
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4257 4258 4259 4260
				    lex->col_list));
    lex->col_list.empty();
  }

4261
  if (default_value)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4262
  {
4263
    if (default_value->type() == Item::NULL_ITEM)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4264
    {
4265 4266 4267 4268
      default_value=0;
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4269
	net_printf(thd,ER_INVALID_DEFAULT,field_name);
4270 4271 4272 4273 4274
	DBUG_RETURN(1);
      }
    }
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4275
      net_printf(thd, ER_INVALID_DEFAULT, field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4276 4277 4278 4279 4280 4281 4282
      DBUG_RETURN(1);
    }
  }
  if (!(new_field=new create_field()))
    DBUG_RETURN(1);
  new_field->field=0;
  new_field->field_name=field_name;
4283
  new_field->def= default_value;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4284 4285 4286 4287 4288 4289 4290 4291 4292 4293
  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;
4294
  new_field->charset=cs;
4295
  new_field->geom_type= (Field::geometry_type) uint_geom_type;
4296

4297 4298 4299 4300 4301 4302 4303 4304
  if (!comment)
  {
    new_field->comment.str=0;
    new_field->comment.length=0;
  }
  else
  {
    /* In this case comment is always of type Item_string */
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4305 4306
    new_field->comment.str=   (char*) comment->str;
    new_field->comment.length=comment->length;
4307
  }
4308 4309
  if (length && !(new_field->length= (uint) atoi(length)))
    length=0; /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4310 4311 4312
  uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;

  if (new_field->length && new_field->decimals &&
4313
      new_field->length < new_field->decimals+1 &&
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4314
      new_field->decimals != NOT_FIXED_DEC)
4315
    new_field->length=new_field->decimals+1; /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341

  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)
4342 4343 4344 4345 4346 4347 4348
      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++;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4349
    break;
4350 4351
  case FIELD_TYPE_STRING:
  case FIELD_TYPE_VAR_STRING:
4352
    if (new_field->length <= MAX_FIELD_CHARLENGTH || default_value)
4353 4354 4355 4356
      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",
4357
	    (cs == &my_charset_bin) ? "BLOB" : "TEXT");
4358 4359 4360
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_AUTO_CONVERT,
		 warn_buff);
    /* fall through */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4361 4362 4363 4364
  case FIELD_TYPE_BLOB:
  case FIELD_TYPE_TINY_BLOB:
  case FIELD_TYPE_LONG_BLOB:
  case FIELD_TYPE_MEDIUM_BLOB:
4365
  case FIELD_TYPE_GEOMETRY:
4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379
    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;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4380 4381 4382 4383 4384 4385
    if (default_value)				// Allow empty as default value
    {
      String str,*res;
      res=default_value->val_str(&str);
      if (res->length())
      {
4386
	net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405
	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)
      {
4406
	net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459
	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)
      {
4460
	net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4461 4462 4463 4464 4465 4466 4467 4468
	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++)
4469 4470 4471
      {
	new_field->length+=(uint) strip_sp((char*) *pos)+1;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4472 4473 4474 4475
      new_field->length--;
      set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
      if (default_value)
      {
4476 4477
	char *not_used;
	uint not_used2;
4478
	bool not_used3;
4479

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4480 4481 4482
	thd->cuted_fields=0;
	String str,*res;
	res=default_value->val_str(&str);
4483
	(void) find_set(interval, res->ptr(), res->length(), &not_used,
4484
			&not_used2, &not_used3);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4485 4486
	if (thd->cuted_fields)
	{
4487
	  net_printf(thd,ER_INVALID_DEFAULT,field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4488 4489 4490 4491 4492 4493 4494 4495 4496
	  DBUG_RETURN(1);
	}
      }
    }
    break;
  case FIELD_TYPE_ENUM:
    {
      new_field->interval=interval;
      new_field->pack_length=interval->count < 256 ? 1 : 2; // Should be safe
4497
      new_field->length=(uint) strip_sp((char*) interval->type_names[0]);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4498 4499
      for (const char **pos=interval->type_names+1; *pos ; pos++)
      {
4500
	uint length=(uint) strip_sp((char*) *pos);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4501 4502 4503 4504 4505 4506 4507
	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);
4508 4509
	res->strip_sp();
	if (!find_type(interval, res->ptr(), res->length(), 0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4510
	{
4511
	  net_printf(thd,ER_INVALID_DEFAULT,field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4512 4513 4514 4515 4516 4517 4518
	  DBUG_RETURN(1);
	}
      }
      break;
    }
  }

4519 4520
  if ((new_field->length > MAX_FIELD_CHARLENGTH && type != FIELD_TYPE_SET && 
       type != FIELD_TYPE_ENUM) ||
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4521
      (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
4522
       type != FIELD_TYPE_STRING &&
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
4523
       type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4524
  {
4525
    net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
4526
	       MAX_FIELD_CHARLENGTH);		/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4527 4528 4529 4530 4531
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
4532
    net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553
    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
4554
add_proc_to_list(THD* thd, Item *item)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4555 4556 4557 4558
{
  ORDER *order;
  Item	**item_ptr;

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4559
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4560 4561 4562 4563 4564
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
4565
  thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4566 4567 4568 4569 4570 4571 4572 4573
  return 0;
}


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

static void remove_escape(char *name)
{
4574 4575
  if (!*name)					// For empty DB names
    return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4576 4577
  char *to;
#ifdef USE_MB
4578
  char *strend=name+(uint) strlen(name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4579 4580 4581 4582 4583 4584
#endif
  for (to=name; *name ; name++)
  {
#ifdef USE_MB
    int l;
/*    if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
4585 4586
    if (use_mb(system_charset_info) &&
        (l = my_ismbchar(system_charset_info, name, strend)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4587 4588 4589 4590 4591 4592 4593 4594
    {
	while (l--)
	    *to++ = *name++;
	name--;
	continue;
    }
#endif
    if (*name == '\\' && name[1])
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4595
      name++;					// Skip '\\'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4596 4597 4598 4599 4600 4601 4602 4603 4604 4605
    *to++= *name;
  }
  *to=0;
}

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


monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4606
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4607 4608 4609 4610
{
  ORDER *order;
  Item	**item_ptr;
  DBUG_ENTER("add_to_list");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4611
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4612 4613 4614 4615 4616 4617 4618
    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;
4619
  list.link_in_list((byte*) order,(byte**) &order->next);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4620 4621 4622 4623
  DBUG_RETURN(0);
}


monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642
/*
  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
*/

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4643 4644
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
4645
					     LEX_STRING *alias,
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4646 4647
					     ulong table_options,
					     thr_lock_type lock_type,
4648 4649
					     List<String> *use_index_arg,
					     List<String> *ignore_index_arg,
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
4650
                                             LEX_STRING *option)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4651 4652 4653 4654 4655 4656 4657 4658
{
  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;
4659
  if (check_table_name(table->table.str,table->table.length) ||
4660
      table->db.str && check_db_name(table->db.str))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4661
  {
4662
    net_printf(thd, ER_WRONG_TABLE_NAME, table->table.str);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4663 4664 4665 4666
    DBUG_RETURN(0);
  }

  if (!alias)					/* Alias is case sensitive */
4667 4668 4669 4670 4671 4672
  {
    if (table->sel)
    {
      net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
      DBUG_RETURN(0);
    }
4673
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4674
      DBUG_RETURN(0);
4675
  }
4676
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4677
    DBUG_RETURN(0);				/* purecov: inspected */
peter@mysql.com's avatar
peter@mysql.com committed
4678
  if (table->db.str)
4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689
  {
    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
  {
4690 4691
    /* The following can't be "" as we may do 'casedn_str()' on it */
    ptr->db= empty_c_string;
4692 4693
    ptr->db_length= 0;
  }
peter@mysql.com's avatar
peter@mysql.com committed
4694

4695
  ptr->alias= alias_str;
4696 4697
  if (lower_case_table_names && table->table.length)
    my_casedn_str(files_charset_info, table->table.str);
4698
  ptr->real_name=table->table.str;
4699
  ptr->real_name_length=table->table.length;
4700
  ptr->lock_type=   lock_type;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4701 4702
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
4703
  ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
4704
  ptr->derived=	    table->sel;
4705 4706 4707 4708 4709 4710
  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));
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
4711
  ptr->option= option ? option->str : 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4712
  /* check that used name is unique */
4713
  if (lock_type != TL_IGNORE)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4714
  {
4715
    for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
4716
	 tables ;
4717
	 tables=tables->next)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4718
    {
4719
      if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db))
4720
      {
4721
	net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
4722 4723
	DBUG_RETURN(0);				/* purecov: tested */
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4724 4725
    }
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4726
  table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4727 4728 4729
  DBUG_RETURN(ptr);
}

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
4730

4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743
/*
  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
*/

4744
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
4745 4746 4747 4748 4749 4750
{
  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));

4751
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
4752 4753 4754 4755 4756 4757 4758 4759 4760
       tables ;
       tables=tables->next)
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
4761

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4762 4763
void add_join_on(TABLE_LIST *b,Item *expr)
{
4764
  if (expr)
4765
  {
4766 4767 4768 4769 4770 4771 4772 4773
    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();
4774
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4775 4776 4777
}


4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795
/*
  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 ... )
*/

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4796 4797 4798 4799 4800
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
{
  b->natural_join=a;
}

4801
/*
4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818
  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
4819 4820
*/

4821 4822
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
                          bool *write_to_binlog)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4823 4824 4825
{
  bool result=0;
  select_errors=0;				/* Write if more errors */
4826
  bool tmp_write_to_binlog= 1;
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
4827
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4828 4829
  if (options & REFRESH_GRANT)
  {
4830
    acl_reload(thd);
4831
    grant_reload(thd);
4832
    if (mqh_used)
4833
      reset_mqh(thd,(LEX_USER *) NULL,true);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4834
  }
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
4835
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4836 4837
  if (options & REFRESH_LOG)
  {
4838
    /*
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4839 4840
      Flush the normal query log, the update log, the binary log,
      the slow query log, and the relay log (if it exists).
4841
    */
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4842

4843 4844 4845 4846 4847 4848
    /* 
     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;
4849 4850 4851
    mysql_log.new_file(1);
    mysql_bin_log.new_file(1);
    mysql_slow_log.new_file(1);
4852
#ifdef HAVE_REPLICATION
4853
    if (expire_logs_days)
4854 4855 4856
    {
      long purge_time= time(0) - expire_logs_days*24*60*60;
      if (purge_time >= 0)
4857
	mysql_bin_log.purge_logs_before_date(purge_time);
4858
    }
4859 4860 4861
    LOCK_ACTIVE_MI;
    rotate_relay_log(active_mi);
    UNLOCK_ACTIVE_MI;
4862
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4863 4864
    if (ha_flush_logs())
      result=1;
4865 4866
    if (flush_error_log())
      result=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4867
  }
4868
#ifdef HAVE_QUERY_CACHE
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4869 4870
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
4871
    query_cache.pack();				// FLUSH QUERY CACHE
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4872 4873 4874 4875
    options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
4876
    query_cache.flush();			// RESET QUERY CACHE
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
4877
  }
4878
#endif /*HAVE_QUERY_CACHE*/
4879 4880 4881 4882 4883
  /*
    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)) 
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4884
  {
4885
    if ((options & REFRESH_READ_LOCK) && thd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4886
    {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4887 4888 4889 4890
      /*
	Writing to the binlog could cause deadlocks, as we don't log
	UNLOCK TABLES
      */
4891
      tmp_write_to_binlog= 0;
4892 4893
      if (lock_global_read_lock(thd))
	return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4894
    }
4895
    result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4896 4897 4898 4899 4900 4901 4902
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
  if (options & REFRESH_STATUS)
    refresh_status();
  if (options & REFRESH_THREADS)
    flush_thread_cache();
4903
#ifdef HAVE_REPLICATION
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4904
  if (options & REFRESH_MASTER)
4905 4906
  {
    tmp_write_to_binlog= 0;
4907 4908
    if (reset_master(thd))
      result=1;
4909
  }
4910
#endif
4911
#ifdef OPENSSL
4912 4913 4914 4915 4916 4917
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
4918
#ifdef HAVE_REPLICATION
4919 4920
 if (options & REFRESH_SLAVE)
 {
4921
   tmp_write_to_binlog= 0;
4922
   LOCK_ACTIVE_MI;
4923
   if (reset_slave(thd, active_mi))
4924 4925 4926
     result=1;
   UNLOCK_ACTIVE_MI;
 }
4927
#endif
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
4928
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4929
 if (options & REFRESH_USER_RESOURCES)
4930
   reset_mqh(thd,(LEX_USER *) NULL);
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
4931
#endif
4932 4933
 if (write_to_binlog)
   *write_to_binlog= tmp_write_to_binlog;
4934
 return result;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4935 4936
}

4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948
/*
  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
*/

hf@genie.(none)'s avatar
SCRUM  
hf@genie.(none) committed
4949
void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4950 4951 4952
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
4953 4954
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4955 4956 4957 4958
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
4959 4960
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4961 4962 4963
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
4964 4965
  if (tmp)
  {
hf@deer.(none)'s avatar
hf@deer.(none) committed
4966
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4967 4968
    if ((thd->master_access & SUPER_ACL) ||
	!strcmp(thd->user,tmp->user))
hf@deer.(none)'s avatar
hf@deer.(none) committed
4969
#endif
4970
    {
hf@genie.(none)'s avatar
SCRUM  
hf@genie.(none) committed
4971
      tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
4972 4973
      error=0;
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
4974
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4975 4976
    else
      error=ER_KILL_DENIED_ERROR;
hf@deer.(none)'s avatar
hf@deer.(none) committed
4977
#endif
4978 4979 4980
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4981
  if (!error)
4982
    send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4983
  else
4984
    net_printf(thd,error,id);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4985 4986 4987 4988 4989 4990 4991 4992 4993 4994
}

/* 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)
4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006
      *(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;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5007 5008 5009
  }
  pthread_mutex_unlock(&LOCK_status);
}
5010 5011 5012 5013


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

5014
static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
5015
{
5016
  char buff[FN_REFLEN],*ptr, *end;
5017 5018 5019 5020 5021 5022 5023
  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))
  {
5024
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
5025 5026 5027 5028
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
5029
  end=convert_dirname(buff, *filename_ptr, NullS);
5030
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
5031 5032
    return 1;					// End of memory
  *filename_ptr=ptr;
5033
  strxmov(ptr,buff,table_name,NullS);
5034 5035
  return 0;
}
5036

5037

5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051
/*
  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;
5052
  if (thd->lex->current_select != &thd->lex->select_lex)
5053 5054
  {
    char command[80];
5055 5056
    strmake(command, thd->lex->yylval->symbol.str,
	    min(thd->lex->yylval->symbol.length, sizeof(command)-1));
5057
    net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
5058 5059 5060 5061
    return 1;
  }
  return 0;
}
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5062

5063

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5064
Comp_creator *comp_eq_creator(bool invert)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5065
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5066
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5067 5068
}

5069

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5070
Comp_creator *comp_ge_creator(bool invert)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5071
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5072
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5073 5074
}

5075

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5076
Comp_creator *comp_gt_creator(bool invert)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5077
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5078
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5079 5080
}

5081

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5082
Comp_creator *comp_le_creator(bool invert)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5083
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5084
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5085 5086
}

5087

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5088
Comp_creator *comp_lt_creator(bool invert)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5089
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5090
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5091 5092
}

5093

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5094
Comp_creator *comp_ne_creator(bool invert)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5095
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5096
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
5097
}
5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117


/*
  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)
{
serg@serg.mylan's avatar
serg@serg.mylan committed
5118
  if ((cmp == &comp_eq_creator) && !all)       //  = ANY <=> IN
5119
    return new Item_in_subselect(left_expr, select_lex);
serg@serg.mylan's avatar
serg@serg.mylan committed
5120 5121

  if ((cmp == &comp_ne_creator) && all)        // <> ALL <=> NOT IN
5122 5123 5124
    return new Item_func_not(new Item_in_subselect(left_expr, select_lex));

  Item_allany_subselect *it=
5125
    new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all);
5126 5127 5128 5129 5130
  if (all)
    return it->upper_not= new Item_func_not_all(it);	/* ALL */

  return it;						/* ANY/SOME */
}