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

unknown's avatar
unknown committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
7

unknown's avatar
unknown committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
12

unknown's avatar
unknown committed
13 14 15 16 17 18
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "mysql_priv.h"
#include "sql_acl.h"
19
#include "sql_repl.h"
20
#include "repl_failsafe.h"
unknown's avatar
unknown committed
21 22 23 24
#include <m_ctype.h>
#include <myisam.h>
#include <my_dir.h>

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

unknown's avatar
unknown committed
29 30 31 32 33 34 35 36 37 38 39
#ifdef HAVE_OPENSSL
/*
  Without SSL the handshake consists of one packet. This packet
  has both client capabilites and scrambled password.
  With SSL the handshake might consist of two packets. If the first
  packet (client capabilities) has CLIENT_SSL flag set, we have to
  switch to SSL and read the second packet. The scrambled password
  is in the second packet and client_capabilites field will be ignored.
  Maybe it is better to accept flags other than CLIENT_SSL from the
  second packet?
*/
unknown's avatar
unknown committed
40 41 42
#define SSL_HANDSHAKE_SIZE      2
#define NORMAL_HANDSHAKE_SIZE   6
#define MIN_HANDSHAKE_SIZE      2
unknown's avatar
unknown committed
43
#else
unknown's avatar
unknown committed
44
#define MIN_HANDSHAKE_SIZE      6
unknown's avatar
unknown committed
45
#endif /* HAVE_OPENSSL */
unknown's avatar
unknown committed
46

47
extern int yyparse(void *thd);
unknown's avatar
unknown committed
48
extern "C" pthread_mutex_t THR_LOCK_keycache;
49 50 51
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#endif
unknown's avatar
unknown committed
52

53
static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
54
static void decrease_user_connections(USER_CONN *uc);
unknown's avatar
unknown committed
55
static bool check_db_used(THD *thd,TABLE_LIST *tables);
56
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
unknown's avatar
unknown committed
57 58
static void remove_escape(char *name);
static void refresh_status(void);
unknown's avatar
unknown committed
59 60
static bool append_file_to_dir(THD *thd, char **filename_ptr,
			       char *table_name);
unknown's avatar
unknown committed
61

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

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

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

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

unknown's avatar
unknown committed
94 95 96 97 98 99 100 101 102 103 104
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)
105
{
unknown's avatar
unknown committed
106
  int error=0;
unknown's avatar
unknown committed
107
  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
unknown's avatar
unknown committed
108
		      OPTION_TABLE_LOCK))
109
  {
110 111
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
112
    if (ha_commit(thd))
unknown's avatar
unknown committed
113
      error=1;
114
  }
unknown's avatar
unknown committed
115
  return error;
116 117 118
}


119 120 121
static HASH hash_user_connections;
extern  pthread_mutex_t LOCK_user_conn;

unknown's avatar
unknown committed
122 123
static int get_or_create_user_conn(THD *thd, const char *user,
				   const char *host,
unknown's avatar
unknown committed
124
				   USER_RESOURCES *mqh)
125 126
{
  int return_val=0;
127
  uint temp_len, user_len, host_len;
128 129 130 131 132 133
  char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
  struct  user_conn *uc;

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

134 135 136
  user_len=strlen(user);
  host_len=strlen(host);
  temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
137
  (void) pthread_mutex_lock(&LOCK_user_conn);
unknown's avatar
unknown committed
138 139
  if (!(uc = (struct  user_conn *) hash_search(&hash_user_connections,
					       (byte*) temp_user, temp_len)))
140
  {
unknown's avatar
unknown committed
141 142 143
    /* First connection for user; Create a user connection object */
    if (!(uc= ((struct user_conn*)
	       my_malloc(sizeof(struct user_conn) + temp_len+1,
unknown's avatar
unknown committed
144 145
			 MYF(MY_WME)))))
    {
146
      send_error(thd, 0, NullS);		// Out of memory
147 148
      return_val=1;
      goto end;
unknown's avatar
unknown committed
149
    }
150 151
    uc->user=(char*) (uc+1);
    memcpy(uc->user,temp_user,temp_len+1);
152 153
    uc->user_len= user_len;
    uc->host=uc->user + uc->user_len +  1;
154
    uc->len = temp_len;
155 156 157
    uc->connections = 1;
    uc->questions=uc->updates=uc->conn_per_hour=0;
    uc->user_resources=*mqh;
unknown's avatar
unknown committed
158
    if (max_user_connections && mqh->connections > max_user_connections)
159
      uc->user_resources.connections = max_user_connections;
160 161 162 163
    uc->intime=thd->thr_create_time;
    if (hash_insert(&hash_user_connections, (byte*) uc))
    {
      my_free((char*) uc,0);
164
      send_error(thd, 0, NullS);		// Out of memory
165 166 167 168 169 170 171 172
      return_val=1;
      goto end;
    }
  }
  thd->user_connect=uc;
end:
  (void) pthread_mutex_unlock(&LOCK_user_conn);
  return return_val;
unknown's avatar
unknown committed
173

174
}
175 176 177


/*
unknown's avatar
unknown committed
178
  Check if user is ok
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204

  SYNOPSIS
    check_user()
    thd			Thread handle
    command		Command for connection (for log)
    user		Name of user trying to connect
    passwd		Scrambled password sent from client
    db			Database to connect to
    check_count		If set to 1, don't allow too many connection
    simple_connect	If 1 then client is of old type and we should connect
			using the old method (no challange)
    do_send_error	Set to 1 if we should send error to user
    prepared_scramble	Buffer to store hash password of new connection
    had_password	Set to 1 if the user gave a password
    cur_priv_version	Check flag to know if someone flushed the privileges
			since last code
    hint_user	        Pointer used by acl_getroot() to remmeber user for
			next call

  RETURN
    0		ok
		thd->user, thd->master_access, thd->priv_user, thd->db and
		thd->db_access are updated
    1		Access denied;  Error sent to client
    -1		If do_send_error == 1:  Failed connect, error sent to client
		If do_send_error == 0:	Prepare for stage of connect
unknown's avatar
unknown committed
205 206
*/

unknown's avatar
unknown committed
207
static int check_user(THD *thd,enum_server_command command, const char *user,
unknown's avatar
unknown committed
208
		       const char *passwd, const char *db, bool check_count,
209
                       bool simple_connect, bool do_send_error, 
210
                       char *prepared_scramble, bool had_password,
211
                       uint *cur_priv_version, ACL_USER** hint_user)
unknown's avatar
unknown committed
212 213
{
  thd->db=0;
unknown's avatar
unknown committed
214
  thd->db_length=0;
215
  USER_RESOURCES ur;
216
  DBUG_ENTER("check_user");
unknown's avatar
unknown committed
217 218

  /* We shall avoid dupplicate user allocations here */
unknown's avatar
unknown committed
219
  if (!thd->user && !(thd->user = my_strdup(user, MYF(0))))
unknown's avatar
unknown committed
220
  {
221
    send_error(thd,ER_OUT_OF_RESOURCES);
222
    DBUG_RETURN(1);
unknown's avatar
unknown committed
223
  }
224
  thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
unknown's avatar
unknown committed
225
				 passwd, thd->scramble, &thd->priv_user,
226 227 228
				 (protocol_version == 9 ||
				  !(thd->client_capabilities &
				    CLIENT_LONG_PASSWORD)),
229
				 &ur,prepared_scramble,
230
				 cur_priv_version,hint_user);
unknown's avatar
unknown committed
231

unknown's avatar
unknown committed
232
  DBUG_PRINT("info",
233
	     ("Capabilities: %d  packet_length: %ld  Host: '%s'  User: '%s'  Using password: %s  Access: %u  db: '%s'",
unknown's avatar
unknown committed
234
	      thd->client_capabilities, thd->max_client_packet_length,
235
	      thd->host_or_ip, thd->priv_user,
236
	      had_password ? "yes": "no",
unknown's avatar
unknown committed
237
	      thd->master_access, thd->db ? thd->db : "*none*"));
unknown's avatar
unknown committed
238

239 240 241 242
  /*
    In case we're going to retry we should not send error message at this
    point
  */
unknown's avatar
unknown committed
243 244
  if (thd->master_access & NO_ACCESS)
  {
245
    if (do_send_error || !had_password || !*hint_user)
246
    {
247
      DBUG_PRINT("info",("Access denied"));
248 249 250 251
      /*
	Old client should get nicer error message if password version is
	not supported
      */
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
      if (simple_connect && *hint_user && (*hint_user)->pversion)
      {
        net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
        mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
      }
      else
      {
        net_printf(thd, ER_ACCESS_DENIED_ERROR,
      	         thd->user,
	         thd->host_or_ip,
	         had_password ? ER(ER_YES) : ER(ER_NO));
        mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
	              thd->user,
                      thd->host_or_ip,
	              had_password ? ER(ER_YES) : ER(ER_NO));
      }                
268
      DBUG_RETURN(1);			// Error already given
unknown's avatar
unknown committed
269
    }
270 271
    DBUG_PRINT("info",("Prepare for second part of handshake"));
    DBUG_RETURN(-1);			// no report error in special handshake
unknown's avatar
unknown committed
272
  }
unknown's avatar
unknown committed
273

unknown's avatar
unknown committed
274 275 276 277
  if (check_count)
  {
    VOID(pthread_mutex_lock(&LOCK_thread_count));
    bool tmp=(thread_count - delayed_insert_threads >= max_connections &&
unknown's avatar
unknown committed
278
	      !(thd->master_access & SUPER_ACL));
unknown's avatar
unknown committed
279 280 281
    VOID(pthread_mutex_unlock(&LOCK_thread_count));
    if (tmp)
    {						// Too many connections
282
      send_error(thd, ER_CON_COUNT_ERROR);
283
      DBUG_RETURN(1);
unknown's avatar
unknown committed
284 285
    }
  }
286
  mysql_log.write(thd,command,
unknown's avatar
unknown committed
287 288 289 290
		  (thd->priv_user == thd->user ?
		   (char*) "%s@%s on %s" :
		   (char*) "%s@%s as anonymous on %s"),
		  user,
291
		  thd->host_or_ip,
unknown's avatar
unknown committed
292 293
		  db ? db : (char*) "");
  thd->db_access=0;
unknown's avatar
unknown committed
294
  /* Don't allow user to connect if he has done too many queries */
295 296
  if ((ur.questions || ur.updates || ur.connections) &&
      get_or_create_user_conn(thd,user,thd->host_or_ip,&ur))
297
    DBUG_RETURN(1);
unknown's avatar
unknown committed
298
  if (thd->user_connect && thd->user_connect->user_resources.connections &&
299
      check_for_max_user_connections(thd, thd->user_connect))
300
    DBUG_RETURN(1);
unknown's avatar
unknown committed
301

unknown's avatar
unknown committed
302
  if (db && db[0])
unknown's avatar
unknown committed
303
  {
304
    int error= test(mysql_change_db(thd,db));
305 306
    if (error && thd->user_connect)
      decrease_user_connections(thd->user_connect);
307
    DBUG_RETURN(error);
unknown's avatar
unknown committed
308
  }
309 310
  send_ok(thd);					// Ready to handle questions
  DBUG_RETURN(0);				// ok
unknown's avatar
unknown committed
311 312
}

313

unknown's avatar
unknown committed
314
/*
unknown's avatar
unknown committed
315 316
  Check for maximum allowable user connections, if the mysqld server is
  started with corresponding variable that is greater then 0.
unknown's avatar
unknown committed
317 318
*/

319 320
extern "C" byte *get_key_conn(user_conn *buff, uint *length,
			      my_bool not_used __attribute__((unused)))
unknown's avatar
unknown committed
321 322 323 324 325
{
  *length=buff->len;
  return (byte*) buff->user;
}

326
extern "C" void free_user(struct user_conn *uc)
unknown's avatar
unknown committed
327 328 329 330
{
  my_free((char*) uc,MYF(0));
}

unknown's avatar
unknown committed
331
void init_max_user_conn(void)
unknown's avatar
unknown committed
332
{
unknown's avatar
unknown committed
333 334
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
		   0,0,
335
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
336
		   0);
unknown's avatar
unknown committed
337 338 339
}


340
static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
unknown's avatar
unknown committed
341
{
342
  int error=0;
343
  DBUG_ENTER("check_for_max_user_connections");
unknown's avatar
unknown committed
344

345 346
  if (max_user_connections &&
      (max_user_connections <=  (uint) uc->connections))
unknown's avatar
unknown committed
347
  {
348
    net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user);
349 350
    error=1;
    goto end;
unknown's avatar
unknown committed
351
  }
unknown's avatar
unknown committed
352
  uc->connections++;
353 354
  if (uc->user_resources.connections &&
      uc->conn_per_hour++ >= uc->user_resources.connections)
355
  {
356
    net_printf(thd, ER_USER_LIMIT_REACHED, uc->user,
357
	       "max_connections",
358 359 360
	       (long) uc->user_resources.connections);
    error=1;
  }
361 362
end:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
363 364 365
}


366
static void decrease_user_connections(USER_CONN *uc)
unknown's avatar
unknown committed
367
{
368
  DBUG_ENTER("decrease_user_connections");
369
  if ((uc->connections && !--uc->connections) && !mqh_used)
unknown's avatar
unknown committed
370 371
  {
    /* Last connection for user; Delete it */
372
    (void) pthread_mutex_lock(&LOCK_user_conn);
unknown's avatar
unknown committed
373
    (void) hash_delete(&hash_user_connections,(byte*) uc);
374
    (void) pthread_mutex_unlock(&LOCK_user_conn);
unknown's avatar
unknown committed
375
  }
376
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
377 378
}

379

unknown's avatar
unknown committed
380 381 382 383 384
void free_max_user_conn(void)
{
  hash_free(&hash_user_connections);
}

unknown's avatar
unknown committed
385

386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
/*
  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;
414
  uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
415 416
}

unknown's avatar
unknown committed
417 418 419 420
bool is_update_query(enum enum_sql_command command)
{
  return uc_update_queries[command];
}
421

unknown's avatar
unknown committed
422 423 424
/*
  Check if maximum queries per hour limit has been reached
  returns 0 if OK.
unknown's avatar
unknown committed
425

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

431

432
static bool check_mqh(THD *thd, uint check_command)
unknown's avatar
unknown committed
433 434
{
  bool error=0;
unknown's avatar
unknown committed
435
  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
436
  USER_CONN *uc=thd->user_connect;
unknown's avatar
unknown committed
437
  DBUG_ENTER("check_mqh");
438
  DBUG_ASSERT(uc != 0);
unknown's avatar
unknown committed
439

unknown's avatar
unknown committed
440
  /* If more than a hour since last check, reset resource checking */
441 442 443 444 445 446 447 448 449
  if (check_time  - uc->intime >= 3600)
  {
    (void) pthread_mutex_lock(&LOCK_user_conn);
    uc->questions=1;
    uc->updates=0;
    uc->conn_per_hour=0;
    uc->intime=check_time;
    (void) pthread_mutex_unlock(&LOCK_user_conn);
  }
unknown's avatar
unknown committed
450
  /* Check that we have not done too many questions / hour */
451 452 453
  if (uc->user_resources.questions &&
      uc->questions++ >= uc->user_resources.questions)
  {
454
    net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
455 456 457 458
	       (long) uc->user_resources.questions);
    error=1;
    goto end;
  }
459
  if (check_command < (uint) SQLCOM_END)
unknown's avatar
unknown committed
460
  {
unknown's avatar
unknown committed
461 462 463 464
    /* 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)
    {
465
      net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
unknown's avatar
unknown committed
466 467 468 469
		 (long) uc->user_resources.updates);
      error=1;
      goto end;
    }
unknown's avatar
unknown committed
470 471
  }
end:
472
  DBUG_RETURN(error);
unknown's avatar
unknown committed
473 474
}

unknown's avatar
unknown committed
475

unknown's avatar
unknown committed
476
static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
477 478
{

unknown's avatar
unknown committed
479
  (void) pthread_mutex_lock(&LOCK_user_conn);
unknown's avatar
unknown committed
480
  if (lu)  // for GRANT
481
  {
482
    USER_CONN *uc;
483
    uint temp_len=lu->user.length+lu->host.length+2;
484 485
    char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];

unknown's avatar
unknown committed
486 487
    memcpy(temp_user,lu->user.str,lu->user.length);
    memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
488
    temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
unknown's avatar
unknown committed
489
    if ((uc = (struct  user_conn *) hash_search(&hash_user_connections,
490
						(byte*) temp_user, temp_len)))
491 492
    {
      uc->questions=0;
493
      get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
494 495
      uc->updates=0;
      uc->conn_per_hour=0;
496 497
    }
  }
498
  else // for FLUSH PRIVILEGES and FLUSH USER_RESOURCES
499
  {
unknown's avatar
unknown committed
500
    for (uint idx=0;idx < hash_user_connections.records; idx++)
501
    {
502 503 504 505 506 507
      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;
508 509
    }
  }
unknown's avatar
unknown committed
510
  (void) pthread_mutex_unlock(&LOCK_user_conn);
511
}
unknown's avatar
unknown committed
512

unknown's avatar
unknown committed
513

unknown's avatar
unknown committed
514
/*
515 516 517 518 519 520 521 522 523 524
  Check connnectionn and get priviliges

  SYNOPSIS
    check_connections
    thd		Thread handle

  RETURN
    0	ok
    -1	Error, which is sent to user
    > 0	 Error code (not sent to user)
unknown's avatar
unknown committed
525 526
*/

527
#ifndef EMBEDDED_LIBRARY  
unknown's avatar
unknown committed
528 529 530
static int
check_connections(THD *thd)
{
531
  int res;
unknown's avatar
unknown committed
532
  uint connect_errors=0;
533 534
  uint cur_priv_version;
  bool using_password;
unknown's avatar
unknown committed
535
  NET *net= &thd->net;
536 537 538
  char *end, *user, *passwd, *db;
  char prepared_scramble[SCRAMBLE41_LENGTH+4];  /* Buffer for scramble&hash */
  ACL_USER* cached_user=NULL; /* Initialise to NULL for first stage */
unknown's avatar
unknown committed
539
  DBUG_PRINT("info",("New connection received on %s",
540
		     vio_description(net->vio)));
541

542
  /* Remove warning from valgrind.  TODO:  Fix it in password.c */
543
  bzero((char*) &prepared_scramble[0], sizeof(prepared_scramble));
unknown's avatar
unknown committed
544 545
  if (!thd->host)                           // If TCP/IP connection
  {
546
    char ip[30];
547

548
    if (vio_peer_addr(net->vio, ip, &thd->peer_port))
unknown's avatar
unknown committed
549 550 551
      return (ER_BAD_HOST_ERROR);
    if (!(thd->ip = my_strdup(ip,MYF(0))))
      return (ER_OUT_OF_RESOURCES);
552
    thd->host_or_ip=thd->ip;
unknown's avatar
unknown committed
553 554 555
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
    /* Fast local hostname resolve for Win32 */
    if (!strcmp(thd->ip,"127.0.0.1"))
556
      thd->host=(char*) localhost;
unknown's avatar
unknown committed
557 558 559
    else
#endif
    {
560 561 562 563 564 565 566 567 568 569
      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)
	  thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
	if (connect_errors > max_connect_errors)
	  return(ER_HOST_IS_BLOCKED);
      }
unknown's avatar
unknown committed
570
    }
unknown's avatar
unknown committed
571 572 573
    DBUG_PRINT("info",("Host: %s  ip: %s",
		       thd->host ? thd->host : "unknown host",
		       thd->ip ? thd->ip : "unknown ip"));
unknown's avatar
unknown committed
574 575 576
    if (acl_check_host(thd->host,thd->ip))
      return(ER_HOST_NOT_PRIVILEGED);
  }
577
  else /* Hostname given means that the connection was on a socket */
unknown's avatar
unknown committed
578
  {
unknown's avatar
unknown committed
579
    DBUG_PRINT("info",("Host: %s",thd->host));
580 581 582
    thd->host_or_ip= thd->host;
    thd->ip= 0;
    thd->peer_port= 0;
unknown's avatar
unknown committed
583 584
    bzero((char*) &thd->remote,sizeof(struct sockaddr));
  }
585
  /* Ensure that wrong hostnames doesn't cause buffer overflows */
unknown's avatar
unknown committed
586 587
  vio_keepalive(net->vio, TRUE);

unknown's avatar
unknown committed
588
  ulong pkt_len=0;
unknown's avatar
unknown committed
589
  {
unknown's avatar
unknown committed
590
    /* buff[] needs to big enough to hold the server_version variable */
591
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+64];
592 593
    int client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
			CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
unknown's avatar
unknown committed
594

595 596 597 598 599
    if (opt_using_transactions)
      client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
    client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
unknown's avatar
unknown committed
600 601 602 603
#ifdef HAVE_OPENSSL
    if (ssl_acceptor_fd)
      client_flags |= CLIENT_SSL;       /* Wow, SSL is avalaible! */
#endif /* HAVE_OPENSSL */
unknown's avatar
unknown committed
604

unknown's avatar
unknown committed
605
    end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1;
unknown's avatar
unknown committed
606 607 608 609 610
    int4store((uchar*) end,thd->thread_id);
    end+=4;
    memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
    end+=SCRAMBLE_LENGTH +1;
    int2store(end,client_flags);
unknown's avatar
unknown committed
611
    end[2]=(char) MY_CHARSET_CURRENT;
unknown's avatar
unknown committed
612 613 614
    int2store(end+3,thd->server_status);
    bzero(end+5,13);
    end+=18;
unknown's avatar
unknown committed
615

616
    // At this point we write connection message and read reply
617
    if (net_write_command(net,(uchar) protocol_version, "", 0, buff,
unknown's avatar
unknown committed
618
			  (uint) (end-buff)) ||
619
	(pkt_len= my_net_read(net)) == packet_error ||
unknown's avatar
unknown committed
620 621 622 623 624 625 626 627 628 629 630
	pkt_len < MIN_HANDSHAKE_SIZE)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
  }
#ifdef _CUSTOMCONFIG_
#include "_cust_sql_parse.h"
#endif
  if (connect_errors)
    reset_host_errors(&thd->remote.sin_addr);
unknown's avatar
unknown committed
631
  if (thd->packet.alloc(thd->variables.net_buffer_length))
unknown's avatar
unknown committed
632 633 634
    return(ER_OUT_OF_RESOURCES);

  thd->client_capabilities=uint2korr(net->read_pos);
635 636 637 638 639 640 641 642 643 644 645 646
  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);
    end= (char*) net->read_pos+8;
  }
  else
  {
    thd->max_client_packet_length= uint3korr(net->read_pos+2);
    end= (char*) net->read_pos+5;
  }

647
  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
648
    thd->variables.sql_mode|= MODE_IGNORE_SPACE;
unknown's avatar
unknown committed
649
#ifdef HAVE_OPENSSL
unknown's avatar
unknown committed
650
  DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
unknown's avatar
unknown committed
651 652 653 654
  if (thd->client_capabilities & CLIENT_SSL)
  {
    /* Do the SSL layering. */
    DBUG_PRINT("info", ("IO layer change in progress..."));
unknown's avatar
unknown committed
655 656 657 658 659
    if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
    {
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
      inc_host_errors(&thd->remote.sin_addr);
unknown's avatar
unknown committed
660
      return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
661
    }
unknown's avatar
unknown committed
662 663 664 665
    DBUG_PRINT("info", ("Reading user information over SSL layer"));
    if ((pkt_len=my_net_read(net)) == packet_error ||
	pkt_len < NORMAL_HANDSHAKE_SIZE)
    {
unknown's avatar
unknown committed
666 667
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
unknown's avatar
unknown committed
668 669 670 671
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
  }
672 673 674
#endif

  if (end >= (char*) net->read_pos+ pkt_len +2)
unknown's avatar
unknown committed
675
  {
676 677
    inc_host_errors(&thd->remote.sin_addr);
    return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
678 679
  }

680 681 682
  user=   end;
  passwd= strend(user)+1;
  db=0;
683
  using_password= test(passwd[0]);
unknown's avatar
unknown committed
684
  if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
685
    db=strend(passwd)+1;
unknown's avatar
unknown committed
686

687
  /* We can get only old hash at this point */
688
  if (using_password && strlen(passwd) != SCRAMBLE_LENGTH)
689
    return ER_HANDSHAKE_ERROR;
unknown's avatar
unknown committed
690

unknown's avatar
unknown committed
691
  if (thd->client_capabilities & CLIENT_INTERACTIVE)
692
    thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
693
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
694 695
      opt_using_transactions)
    net->return_status= &thd->server_status;
unknown's avatar
unknown committed
696
  net->read_timeout=(uint) thd->variables.net_read_timeout;
unknown's avatar
unknown committed
697

698 699
  /* Simple connect only for old clients. New clients always use secure auth */
  bool simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
unknown's avatar
unknown committed
700

701
  /* Check user permissions. If password failure we'll get scramble back */
702 703 704 705
  if ((res=check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect,
		      simple_connect, prepared_scramble, using_password,
		      &cur_priv_version,
		      &cached_user)) < 0)
unknown's avatar
unknown committed
706
  {
707 708 709 710
    /* Store current used and database as they are erased with next packet */
    char tmp_user[USERNAME_LENGTH+1];
    char tmp_db[NAME_LEN+1];

711
    /* If the client is old we just have to return error */
712 713 714
    if (simple_connect)
      return -1;

715 716 717
    DBUG_PRINT("info",("password challenge"));

    tmp_user[0]= tmp_db[0]= 0;
718
    if (user)
unknown's avatar
unknown committed
719
      strmake(tmp_user,user,USERNAME_LENGTH);
720
    if (db)
unknown's avatar
unknown committed
721 722
      strmake(tmp_db,db,NAME_LEN);

723
    /* Write hash and encrypted scramble to client */
724 725
    if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
        net_flush(net))
726 727 728 729
    {
      inc_host_errors(&thd->remote.sin_addr);
      return ER_HANDSHAKE_ERROR;
    }
unknown's avatar
unknown committed
730
    /* Reading packet back */
731 732 733 734 735
    if ((pkt_len= my_net_read(net)) == packet_error)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return ER_HANDSHAKE_ERROR;
    }
unknown's avatar
unknown committed
736
    /* We have to get very specific packet size  */
737 738 739 740 741
    if (pkt_len != SCRAMBLE41_LENGTH)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return ER_HANDSHAKE_ERROR;
    }
unknown's avatar
unknown committed
742 743
    /* Final attempt to check the user based on reply */
    if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos,
744 745 746
		   tmp_db, 1, 0, 1, prepared_scramble, using_password,
		   &cur_priv_version,
		   &cached_user))
747 748
      return -1;
  }
749 750
  else if (res)
    return -1;					// Error sent from check_user()
751
  thd->password=using_password;
unknown's avatar
unknown committed
752 753 754
  return 0;
}

755

unknown's avatar
unknown committed
756 757 758 759
pthread_handler_decl(handle_one_connection,arg)
{
  THD *thd=(THD*) arg;
  uint launch_time  =
unknown's avatar
unknown committed
760
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
unknown's avatar
unknown committed
761 762 763 764 765
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status );

  pthread_detach_this_thread();

766 767
#if !defined( __WIN__) && !defined(OS2)	// Win32 calls this in pthread_create
  // The following calls needs to be done before we call DBUG_ macros
768
  if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
unknown's avatar
unknown committed
769 770
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
771
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
772 773 774 775 776
    end_thread(thd,0);
    return 0;
  }
#endif

777 778 779 780 781 782 783
  /*
    handle_one_connection() is the only way a thread would start
    and would always be on top of the stack, therefore, the thread
    stack always starts at the address of the first local variable
    of handle_one_connection, which is thd. We need to know the
    start of the stack so that we could check for stack overruns.
  */
unknown's avatar
unknown committed
784 785 786 787
  DBUG_PRINT("info", ("handle_one_connection called by thread %d\n",
		      thd->thread_id));
  // now that we've called my_thread_init(), it is safe to call DBUG_*

unknown's avatar
unknown committed
788
#if defined(__WIN__)
unknown's avatar
unknown committed
789
  init_signals();				// IRENA; testing ?
unknown's avatar
unknown committed
790
#elif !defined(OS2) && !defined(__NETWARE__)
unknown's avatar
unknown committed
791 792 793 794 795 796 797
  sigset_t set;
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
  if (thd->store_globals())
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
798
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
799 800 801 802 803 804 805 806 807 808 809 810 811
    end_thread(thd,0);
    return 0;
  }

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

    if ((error=check_connections(thd)))
    {						// Wrong permissions
      if (error > 0)
812
	net_printf(thd,error,thd->host_or_ip);
unknown's avatar
unknown committed
813 814
#ifdef __NT__
      if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
815
	my_sleep(1000);				/* must wait after eof() */
unknown's avatar
unknown committed
816
#endif
817
      statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
818 819
      goto end_thread;
    }
unknown's avatar
unknown committed
820 821 822
#ifdef __NETWARE__
    netware_reg_user(thd->ip, thd->user, "MySQL");
#endif
823
    if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
824 825 826 827
      thd->options |= OPTION_BIG_SELECTS;
    if (thd->client_capabilities & CLIENT_COMPRESS)
      net->compress=1;				// Use compression

unknown's avatar
unknown committed
828
    thd->proc_info=0;				// Remove 'login'
829
    thd->command=COM_SLEEP;
unknown's avatar
unknown committed
830 831
    thd->version=refresh_version;
    thd->set_time();
832
    thd->init_for_queries();
unknown's avatar
unknown committed
833 834 835 836 837
    while (!net->error && net->vio != 0 && !thd->killed)
    {
      if (do_command(thd))
	break;
    }
838 839
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
840
    free_root(&thd->mem_root,MYF(0));
unknown's avatar
unknown committed
841
    if (net->error && net->vio != 0 && net->report_error)
unknown's avatar
unknown committed
842
    {
unknown's avatar
unknown committed
843
      if (!thd->killed && thd->variables.log_warnings)
844 845 846 847 848 849
	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)));
850
      send_error(thd,net->last_errno,NullS);
unknown's avatar
unknown committed
851
      statistic_increment(aborted_threads,&LOCK_status);
unknown's avatar
unknown committed
852
    }
unknown's avatar
unknown committed
853

unknown's avatar
unknown committed
854 855 856 857 858 859 860 861 862 863 864 865 866
end_thread:
    close_connection(net);
    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 */
}

867 868 869 870
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
unknown's avatar
unknown committed
871

872
extern "C" pthread_handler_decl(handle_bootstrap,arg)
unknown's avatar
unknown committed
873
{
874 875 876
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
unknown's avatar
unknown committed
877

878
  /* The following must be called before DBUG_ENTER */
879
  if (my_thread_init() || thd->store_globals())
unknown's avatar
unknown committed
880 881
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
882
    thd->fatal_error();
883
    goto end;
unknown's avatar
unknown committed
884
  }
885 886 887 888
  DBUG_ENTER("handle_bootstrap");

  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
889
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
unknown's avatar
unknown committed
890
  sigset_t set;
891 892
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
unknown's avatar
unknown committed
893 894
#endif

895
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
896 897 898 899
    thd->options |= OPTION_BIG_SELECTS;

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

902
  buff= (char*) thd->net.buff;
903
  thd->init_for_queries();
unknown's avatar
unknown committed
904 905
  while (fgets(buff, thd->net.max_packet, file))
  {
unknown's avatar
unknown committed
906
    uint length=(uint) strlen(buff);
unknown's avatar
unknown committed
907
    while (length && (my_isspace(thd->charset(), buff[length-1]) ||
908
           buff[length-1] == ';'))
unknown's avatar
unknown committed
909 910 911
      length--;
    buff[length]=0;
    thd->current_tablenr=0;
912
    thd->query_length=length;
unknown's avatar
unknown committed
913 914
    thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
    thd->query[length] = '\0';
unknown's avatar
unknown committed
915
    thd->query_id=query_id++;
916
    if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
917 918 919 920 921 922
    {
      thd->net.error = 0;
      close_thread_tables(thd);			// Free tables
      free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
      break;
    }
unknown's avatar
unknown committed
923 924
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
925
    if (thd->is_fatal_error)
926
      break;
927
    free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
928
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
929
  }
930 931 932 933 934 935

  /* thd->fatal_error should be set in case something went wrong */
end:
  (void) pthread_mutex_lock(&LOCK_thread_count);
  thread_count--;
  (void) pthread_mutex_unlock(&LOCK_thread_count);
936
  (void) pthread_cond_broadcast(&COND_thread_count);
937 938 939
  my_thread_end();
  pthread_exit(0);
  DBUG_RETURN(0);				// Never reached
unknown's avatar
unknown committed
940 941
}

942 943
#endif /* EMBEDDED_LIBRARY */

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

946
void free_items(Item *item)
unknown's avatar
unknown committed
947
{
948
  for (; item ; item=item->next)
unknown's avatar
unknown committed
949 950 951 952 953 954 955 956 957 958
    delete item;
}

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;
959
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
960
    DBUG_RETURN(1); // out of memory
unknown's avatar
unknown committed
961
  table_list->db = db;
962
  table_list->real_name = table_list->alias = tbl_name;
unknown's avatar
unknown committed
963 964 965
  table_list->lock_type = TL_READ_NO_INSERT;
  table_list->next = 0;

966 967
  if (!db || check_db_name(db))
  {
968
    net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
969 970
    goto err;
  }
971
  if (lower_case_table_names)
972
    my_casedn_str(files_charset_info, tbl_name);
unknown's avatar
unknown committed
973
  remove_escape(table_list->real_name);
974 975 976 977

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

978
  if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege))
unknown's avatar
unknown committed
979
    goto err;
980
  if (grant_option && check_grant(thd, SELECT_ACL, table_list))
unknown's avatar
unknown committed
981 982 983
    goto err;

  thd->free_list = 0;
unknown's avatar
unknown committed
984
  thd->query_length=(uint) strlen(tbl_name);
unknown's avatar
unknown committed
985
  thd->query = tbl_name;
986 987
  if ((error = mysqld_dump_create_info(thd, table, -1)))
  {
988
    my_error(ER_GET_ERRNO, MYF(0), my_errno);
989 990
    goto err;
  }
unknown's avatar
unknown committed
991
  net_flush(&thd->net);
992
  if ((error= table->file->dump(thd,fd)))
993
    my_error(ER_GET_ERRNO, MYF(0));
unknown's avatar
unknown committed
994

unknown's avatar
unknown committed
995 996
err:
  close_thread_tables(thd);
unknown's avatar
unknown committed
997
  DBUG_RETURN(error);
unknown's avatar
unknown committed
998 999 1000
}


1001
	/* Execute one command from socket (query or simple command) */
1002 1003

#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1004 1005 1006
bool do_command(THD *thd)
{
  char *packet;
unknown's avatar
unknown committed
1007 1008
  uint old_timeout;
  ulong packet_length;
unknown's avatar
unknown committed
1009 1010 1011 1012 1013 1014 1015 1016
  NET *net;
  enum enum_server_command command;
  DBUG_ENTER("do_command");

  net= &thd->net;
  thd->current_tablenr=0;

  packet=0;
unknown's avatar
unknown committed
1017 1018 1019
  old_timeout=net->read_timeout;
  // Wait max for 8 hours
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
unknown's avatar
unknown committed
1020
  thd->clear_error();				// Clear error message
unknown's avatar
unknown committed
1021 1022 1023 1024

  net_new_transaction(net);
  if ((packet_length=my_net_read(net)) == packet_error)
  {
1025 1026 1027 1028 1029 1030
    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)
      DBUG_RETURN(TRUE);			// We have to close it.
1031
    send_error(thd,net->last_errno,NullS);
1032
    net->error= 0;
1033
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
1034 1035 1036 1037 1038
  }
  else
  {
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
1039 1040
    if (command >= COM_END)
      command= COM_END;				// Wrong command
unknown's avatar
unknown committed
1041 1042 1043
    DBUG_PRINT("info",("Command on %s = %d (%s)",
		       vio_description(net->vio), command,
		       command_name[command]));
unknown's avatar
unknown committed
1044
  }
unknown's avatar
unknown committed
1045
  net->read_timeout=old_timeout;		// restore it
unknown's avatar
unknown committed
1046
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
1047
}
1048
#endif  /* EMBEDDED_LIBRARY */
1049

1050

1051 1052 1053 1054
bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
1055
  bool error= 0;
unknown's avatar
unknown committed
1056 1057 1058 1059
  /*
    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
  */
1060 1061 1062
  bool slow_command=FALSE;
  DBUG_ENTER("dispatch_command");

unknown's avatar
unknown committed
1063
  thd->command=command;
unknown's avatar
unknown committed
1064
  thd->set_time();
unknown's avatar
unknown committed
1065 1066 1067 1068 1069 1070
  VOID(pthread_mutex_lock(&LOCK_thread_count));
  thd->query_id=query_id;
  if (command != COM_STATISTICS && command != COM_PING)
    query_id++;
  thread_running++;
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1071

1072
  thd->lex.select_lex.options=0;		// We store status here
1073
  switch (command) {
unknown's avatar
unknown committed
1074
  case COM_INIT_DB:
unknown's avatar
unknown committed
1075
    statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
1076
    if (!mysql_change_db(thd,packet))
1077
      mysql_log.write(thd,command,"%s",thd->db);
unknown's avatar
unknown committed
1078
    break;
1079
#ifndef EMBEDDED_LIBRARY
1080 1081
  case COM_REGISTER_SLAVE:
  {
1082
    if (!register_slave(thd, (uchar*)packet, packet_length))
1083
      send_ok(thd);
1084 1085
    break;
  }
1086
#endif
unknown's avatar
unknown committed
1087 1088
  case COM_TABLE_DUMP:
    {
unknown's avatar
unknown committed
1089
      statistic_increment(com_other, &LOCK_status);
1090
      slow_command = TRUE;
1091 1092
      uint db_len = *(uchar*)packet;
      uint tbl_len = *(uchar*)(packet + db_len + 1);
1093
      char* db = thd->alloc(db_len + tbl_len + 2);
1094
      memcpy(db, packet + 1, db_len);
unknown's avatar
unknown committed
1095 1096
      char* tbl_name = db + db_len;
      *tbl_name++ = 0;
1097
      memcpy(tbl_name, packet + db_len + 2, tbl_len);
unknown's avatar
unknown committed
1098
      tbl_name[tbl_len] = 0;
unknown's avatar
unknown committed
1099
      if (mysql_table_dump(thd, db, tbl_name, -1))
1100
	send_error(thd); // dump to NET
unknown's avatar
unknown committed
1101 1102
      break;
    }
1103
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1104 1105
  case COM_CHANGE_USER:
  {
unknown's avatar
unknown committed
1106
    thd->change_user();
1107
    thd->clear_error();			// If errors from rollback
unknown's avatar
unknown committed
1108 1109

    statistic_increment(com_other,&LOCK_status);
1110
    char *user=   (char*) packet;
unknown's avatar
unknown committed
1111 1112
    char *passwd= strend(user)+1;
    char *db=     strend(passwd)+1;
unknown's avatar
unknown committed
1113

unknown's avatar
unknown committed
1114 1115 1116
    /* Save user and privileges */
    uint save_master_access=thd->master_access;
    uint save_db_access=    thd->db_access;
unknown's avatar
unknown committed
1117
    uint save_db_length=    thd->db_length;
unknown's avatar
unknown committed
1118
    char *save_user=	    thd->user;
unknown's avatar
unknown committed
1119
    thd->user=NULL; /* Needed for check_user to allocate new user */
unknown's avatar
unknown committed
1120 1121
    char *save_priv_user=   thd->priv_user;
    char *save_db=	    thd->db;
unknown's avatar
unknown committed
1122 1123 1124
    USER_CONN *save_uc=     thd->user_connect;
    bool simple_connect;
    bool using_password;
1125 1126 1127 1128 1129
    char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */
    char tmp_user[USERNAME_LENGTH+1];
    char tmp_db[NAME_LEN+1];
    ACL_USER* cached_user     ;                 /* Cached user */
    uint cur_priv_version;                      /* Cached grant version */
1130 1131
    int res;
    ulong pkt_len= 0;				/* Length of reply packet */
unknown's avatar
unknown committed
1132

1133
    bzero((char*) prepared_scramble, sizeof(prepared_scramble));
unknown's avatar
unknown committed
1134
    /* Small check for incomming packet */
unknown's avatar
unknown committed
1135 1136

    if ((uint) ((uchar*) db - net->read_pos) > packet_length)
unknown's avatar
unknown committed
1137
      goto restore_user_err;
unknown's avatar
unknown committed
1138

unknown's avatar
unknown committed
1139
    /* Now we shall basically perform authentication again */
unknown's avatar
unknown committed
1140

unknown's avatar
unknown committed
1141
     /* We can get only old hash at this point */
unknown's avatar
unknown committed
1142
    if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
unknown's avatar
unknown committed
1143
      goto restore_user_err;
unknown's avatar
unknown committed
1144

1145
    cached_user= NULL;
unknown's avatar
unknown committed
1146

unknown's avatar
unknown committed
1147 1148
    /* Simple connect only for old clients. New clients always use sec. auth*/
    simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
unknown's avatar
unknown committed
1149

unknown's avatar
unknown committed
1150 1151
    /* Store information if we used password. passwd will be dammaged */
    using_password=test(passwd[0]);
unknown's avatar
unknown committed
1152 1153 1154 1155 1156

    if (simple_connect) /* Restore scramble for old clients */
      memcpy(thd->scramble,thd->old_scramble,9);

    /*
1157 1158
      Check user permissions. If password failure we'll get scramble back
      Do not retry if we already have sent error (result>0)
unknown's avatar
unknown committed
1159
    */
1160 1161 1162
    if ((res=check_user(thd,COM_CHANGE_USER, user, passwd, db, 0,
			simple_connect, simple_connect, prepared_scramble,
			using_password, &cur_priv_version, &cached_user)) < 0)
unknown's avatar
unknown committed
1163
    {
1164
      /* If the client is old we just have to have auth failure */
unknown's avatar
unknown committed
1165
      if (simple_connect)
1166
        goto restore_user;			/* Error is already reported */
unknown's avatar
unknown committed
1167

unknown's avatar
unknown committed
1168
      /* Store current used and database as they are erased with next packet */
1169
      tmp_user[0]= tmp_db[0]= 0;
unknown's avatar
unknown committed
1170
      if (user)
1171
        strmake(tmp_user,user,USERNAME_LENGTH);
unknown's avatar
unknown committed
1172
      if (db)
1173 1174
        strmake(tmp_db,db,NAME_LEN);

unknown's avatar
unknown committed
1175
      /* Write hash and encrypted scramble to client */
1176 1177
      if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
          net_flush(net))
unknown's avatar
unknown committed
1178
        goto restore_user_err;
unknown's avatar
unknown committed
1179 1180 1181 1182 1183 1184

      /* Reading packet back */
      if ((pkt_len=my_net_read(net)) == packet_error)
        goto restore_user_err;

      /* We have to get very specific packet size  */
1185
      if (pkt_len != SCRAMBLE41_LENGTH)
unknown's avatar
unknown committed
1186
        goto restore_user;
unknown's avatar
unknown committed
1187 1188

      /* Final attempt to check the user based on reply */
1189
      if (check_user(thd,COM_CHANGE_USER, tmp_user, (char*) net->read_pos,
1190 1191
		     tmp_db, 0, 0, 1, prepared_scramble, using_password,
		     &cur_priv_version, &cached_user))
unknown's avatar
unknown committed
1192
        goto restore_user;
unknown's avatar
unknown committed
1193
    }
1194 1195 1196
    else if (res)
      goto restore_user;

unknown's avatar
unknown committed
1197
    /* Finally we've authenticated new user */
1198
    if (max_connections && save_uc)
unknown's avatar
unknown committed
1199
      decrease_user_connections(save_uc);
unknown's avatar
unknown committed
1200 1201
    x_free((gptr) save_db);
    x_free((gptr) save_user);
unknown's avatar
unknown committed
1202 1203
    thd->password=using_password;
    break;
unknown's avatar
unknown committed
1204

unknown's avatar
unknown committed
1205
    /* Bad luck  we shall restore old user */
1206
restore_user_err:
unknown's avatar
unknown committed
1207
    send_error(thd, ER_UNKNOWN_COM_ERROR);
unknown's avatar
unknown committed
1208

1209
restore_user:
unknown's avatar
unknown committed
1210 1211 1212 1213 1214 1215
    x_free(thd->user);
    thd->master_access=save_master_access;
    thd->db_access=save_db_access;
    thd->db=save_db;
    thd->db_length=save_db_length;
    thd->user=save_user;
unknown's avatar
unknown committed
1216
    thd->priv_user=save_priv_user;
unknown's avatar
unknown committed
1217 1218
    break;
  }
1219
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
1220 1221
  case COM_EXECUTE:
  {
1222
    mysql_stmt_execute(thd, packet);
unknown's avatar
unknown committed
1223 1224 1225 1226
    break;
  }
  case COM_LONG_DATA:
  {
1227
    mysql_stmt_get_longdata(thd, packet, packet_length);
unknown's avatar
unknown committed
1228 1229 1230 1231
    break;
  }
  case COM_PREPARE:
  {
1232
    mysql_stmt_prepare(thd, packet, packet_length);
unknown's avatar
unknown committed
1233 1234
    break;
  }
unknown's avatar
unknown committed
1235 1236 1237 1238 1239
  case COM_CLOSE_STMT:
  {
    mysql_stmt_free(thd, packet);
    break;
  }
unknown's avatar
unknown committed
1240 1241
  case COM_QUERY:
  {
1242 1243
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
1244
    mysql_log.write(thd,command,"%s",thd->query);
1245
    DBUG_PRINT("query",("%-.4096s",thd->query));
1246
    mysql_parse(thd,thd->query, thd->query_length);
1247

unknown's avatar
unknown committed
1248
    while (!thd->killed && !thd->is_fatal_error && thd->lex.found_colon)
1249
    {
1250
      char *packet= thd->lex.found_colon;
1251 1252 1253 1254 1255 1256
      /* 
        Multiple queries exits, execute them individually
      */
      if (thd->lock || thd->open_tables || thd->derived_tables)
        close_thread_tables(thd);		

1257
      ulong length= thd->query_length-(ulong)(thd->lex.found_colon-thd->query);
1258 1259
      
      /* Remove garbage at start of query */
unknown's avatar
unknown committed
1260
      while (my_isspace(thd->charset(), *packet) && length > 0)
1261 1262 1263 1264 1265
      {
        packet++;
        length--;
      }
      thd->query_length= length;
1266 1267 1268 1269
      thd->query= packet;
      VOID(pthread_mutex_lock(&LOCK_thread_count));
      thd->query_id= query_id++;
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
1270 1271 1272
      mysql_parse(thd, packet, length);
    }

unknown's avatar
unknown committed
1273 1274 1275 1276 1277
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1278
  case COM_FIELD_LIST:				// This isn't actually needed
unknown's avatar
unknown committed
1279
#ifdef DONT_ALLOW_SHOW_COMMANDS
1280
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
1281 1282 1283 1284 1285
    break;
#else
  {
    char *fields;
    TABLE_LIST table_list;
unknown's avatar
unknown committed
1286
    statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
unknown's avatar
unknown committed
1287 1288 1289
    bzero((char*) &table_list,sizeof(table_list));
    if (!(table_list.db=thd->db))
    {
1290
      send_error(thd,ER_NO_DB_ERROR);
unknown's avatar
unknown committed
1291 1292 1293
      break;
    }
    thd->free_list=0;
1294
    table_list.alias= table_list.real_name= thd->strdup(packet);
unknown's avatar
unknown committed
1295
    packet=strend(packet)+1;
unknown's avatar
unknown committed
1296
    // command not cachable => no gap for data base name
unknown's avatar
unknown committed
1297 1298
    if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
      break;
1299
    mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
1300
    if (lower_case_table_names)
unknown's avatar
unknown committed
1301
      my_casedn_str(files_charset_info, table_list.real_name);
unknown's avatar
unknown committed
1302 1303 1304 1305 1306 1307 1308 1309
    remove_escape(table_list.real_name);	// This can't have wildcards

    if (check_access(thd,SELECT_ACL,table_list.db,&thd->col_access))
      break;
    table_list.grant.privilege=thd->col_access;
    if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2))
      break;
    mysqld_list_fields(thd,&table_list,fields);
1310
    free_items(thd->free_list);
unknown's avatar
unknown committed
1311 1312 1313 1314
    break;
  }
#endif
  case COM_QUIT:
1315
    /* We don't calculate statistics for this command */
1316
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1317 1318 1319 1320
    net->error=0;				// Don't give 'abort' message
    error=TRUE;					// End server
    break;

unknown's avatar
unknown committed
1321
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1322
    {
unknown's avatar
unknown committed
1323
      statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
1324
      char *db=thd->strdup(packet);
1325
      // null test to handle EOM
unknown's avatar
unknown committed
1326
      if (!db || !strip_sp(db) || check_db_name(db))
1327
      {
1328
	net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
1329 1330
	break;
      }
unknown's avatar
unknown committed
1331 1332
      if (check_access(thd,CREATE_ACL,db,0,1))
	break;
1333
      mysql_log.write(thd,command,packet);
unknown's avatar
unknown committed
1334
      mysql_create_db(thd,db,0,0);
unknown's avatar
unknown committed
1335 1336
      break;
    }
unknown's avatar
unknown committed
1337
  case COM_DROP_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1338
    {
unknown's avatar
unknown committed
1339
      statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
1340
      char *db=thd->strdup(packet);
1341
      // null test to handle EOM
unknown's avatar
unknown committed
1342
      if (!db || !strip_sp(db) || check_db_name(db))
1343
      {
1344
	net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
1345 1346
	break;
      }
1347 1348
      if (check_access(thd,DROP_ACL,db,0,1))
	break;
unknown's avatar
unknown committed
1349 1350
      if (thd->locked_tables || thd->active_transaction())
      {
1351
	send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
1352
	break;
unknown's avatar
unknown committed
1353
      }
1354
      mysql_log.write(thd,command,db);
unknown's avatar
unknown committed
1355
      mysql_rm_db(thd,db,0,0);
unknown's avatar
unknown committed
1356 1357
      break;
    }
1358
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1359 1360
  case COM_BINLOG_DUMP:
    {
unknown's avatar
unknown committed
1361
      statistic_increment(com_other,&LOCK_status);
1362
      slow_command = TRUE;
unknown's avatar
unknown committed
1363
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1364
	break;
1365
      mysql_log.write(thd,command, 0);
unknown's avatar
unknown committed
1366

unknown's avatar
unknown committed
1367 1368
      ulong pos;
      ushort flags;
1369
      uint32 slave_server_id;
1370
      /* TODO: The following has to be changed to an 8 byte integer */
1371 1372
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
1373
      thd->server_id=0; /* avoid suicide */
1374
      kill_zombie_dump_threads(slave_server_id = uint4korr(packet+6));
1375
      thd->server_id = slave_server_id;
1376
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1377
      unregister_slave(thd,1,1);
1378 1379 1380
      // fake COM_QUIT -- if we get here, the thread needs to terminate
      error = TRUE;
      net->error = 0;
unknown's avatar
unknown committed
1381 1382
      break;
    }
1383
#endif
unknown's avatar
unknown committed
1384 1385
  case COM_REFRESH:
    {
unknown's avatar
unknown committed
1386
      statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
unknown's avatar
unknown committed
1387
      ulong options= (ulong) (uchar) packet[0];
unknown's avatar
unknown committed
1388
      if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1389
	break;
1390
      mysql_log.write(thd,command,NullS);
1391 1392
      /* error sending is deferred to reload_acl_and_cache */
      reload_acl_and_cache(thd, options, (TABLE_LIST*) 0) ;
unknown's avatar
unknown committed
1393 1394
      break;
    }
1395
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1396
  case COM_SHUTDOWN:
unknown's avatar
unknown committed
1397
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1398
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1399 1400
      break; /* purecov: inspected */
    DBUG_PRINT("quit",("Got shutdown command"));
1401
    mysql_log.write(thd,command,NullS);
1402
    send_eof(thd);
unknown's avatar
unknown committed
1403 1404 1405
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
unknown's avatar
unknown committed
1406
#ifndef OS2
1407
    send_eof(thd);				// This is for 'quit request'
unknown's avatar
unknown committed
1408
#endif
unknown's avatar
unknown committed
1409 1410
    close_connection(net);
    close_thread_tables(thd);			// Free before kill
1411
    free_root(&thd->mem_root,MYF(0));
1412
    free_root(&thd->transaction.mem_root,MYF(0));
unknown's avatar
unknown committed
1413 1414 1415
    kill_mysql();
    error=TRUE;
    break;
1416 1417
#endif
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1418 1419
  case COM_STATISTICS:
  {
1420
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1421
    statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
unknown's avatar
unknown committed
1422
    char buff[200];
1423
    ulong uptime = (ulong) (thd->start_time - start_time);
unknown's avatar
unknown committed
1424
    sprintf((char*) buff,
1425
	    "Uptime: %ld  Threads: %d  Questions: %lu  Slow queries: %ld  Opens: %ld  Flush tables: %ld  Open tables: %u  Queries per second avg: %.3f",
unknown's avatar
unknown committed
1426 1427 1428 1429 1430 1431 1432 1433 1434
	    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
    if (lCurMemory)				// Using SAFEMALLOC
      sprintf(strend(buff), "  Memory in use: %ldK  Max memory used: %ldK",
	      (lCurMemory+1023L)/1024L,(lMaxMemory+1023L)/1024L);
 #endif
unknown's avatar
unknown committed
1435
    VOID(my_net_write(net, buff,(uint) strlen(buff)));
unknown's avatar
unknown committed
1436 1437 1438
    VOID(net_flush(net));
    break;
  }
1439
#endif
unknown's avatar
unknown committed
1440
  case COM_PING:
unknown's avatar
unknown committed
1441
    statistic_increment(com_other,&LOCK_status);
1442
    send_ok(thd);				// Tell client we are alive
unknown's avatar
unknown committed
1443 1444
    break;
  case COM_PROCESS_INFO:
unknown's avatar
unknown committed
1445
    statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
unknown's avatar
unknown committed
1446
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
1447
      break;
1448
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1449 1450 1451 1452 1453
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
			  thd->priv_user,0);
    break;
  case COM_PROCESS_KILL:
  {
unknown's avatar
unknown committed
1454
    statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
1455
    ulong id=(ulong) uint4korr(packet);
unknown's avatar
unknown committed
1456 1457 1458 1459
    kill_one_thread(thd,id);
    break;
  }
  case COM_DEBUG:
unknown's avatar
unknown committed
1460
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1461
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1462 1463
      break;					/* purecov: inspected */
    mysql_print_status(thd);
1464
    mysql_log.write(thd,command,NullS);
1465
    send_eof(thd);
unknown's avatar
unknown committed
1466 1467 1468 1469 1470
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
1471
  case COM_END:
unknown's avatar
unknown committed
1472
  default:
1473
    send_error(thd, ER_UNKNOWN_COM_ERROR);
unknown's avatar
unknown committed
1474 1475
    break;
  }
1476
  if (thd->lock || thd->open_tables || thd->derived_tables)
unknown's avatar
unknown committed
1477 1478 1479 1480 1481
  {
    thd->proc_info="closing tables";
    close_thread_tables(thd);			/* Free tables */
  }

1482
  if (thd->is_fatal_error)
1483
    send_error(thd,0);				// End of memory ?
unknown's avatar
unknown committed
1484 1485

  time_t start_of_query=thd->start_time;
1486
  thd->end_time();				// Set start time
1487

1488
  /* If not reading from backup and if the query took too long */
1489
  if (!slow_command && !thd->user_time) // do not log 'slow_command' queries
unknown's avatar
unknown committed
1490
  {
1491 1492
    thd->proc_info="logging slow query";

1493 1494
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
1495
	((thd->lex.select_lex.options &
1496
	  (QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED)) &&
1497
	 (specialflag & SPECIAL_LONG_LOG_FORMAT)))
1498 1499 1500 1501
    {
      long_query_count++;
      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
    }
unknown's avatar
unknown committed
1502
  }
1503
  thd->proc_info="cleaning up";
unknown's avatar
unknown committed
1504 1505 1506 1507 1508 1509
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
  thd->proc_info=0;
  thd->command=COM_SLEEP;
  thd->query=0;
  thread_running--;
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1510
  thd->packet.shrink(thd->variables.net_buffer_length);	// Reclaim some memory
1511
  free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1512 1513 1514
  DBUG_RETURN(error);
}

1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532

/*
  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
1533
  /* Remove garbage at start and end of query */
unknown's avatar
unknown committed
1534
  while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
1535 1536 1537 1538 1539
  {
    packet++;
    packet_length--;
  }
  char *pos=packet+packet_length;		// Point at end null
unknown's avatar
unknown committed
1540
  while (packet_length > 0 &&
unknown's avatar
unknown committed
1541
	 (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
  {
    pos--;
    packet_length--;
  }
  /* We must allocate some extra memory for query cache */
  if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
					      packet_length,
					      thd->db_length+2)))
    return 1;
  thd->query[packet_length]=0;
  thd->query_length= packet_length;
  thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory

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

unknown's avatar
unknown committed
1560 1561 1562 1563 1564 1565
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/

void
1566
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
1567
{
1568
  int	res= 0;
1569
  LEX	*lex= &thd->lex;
1570
  TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first;
unknown's avatar
unknown committed
1571
  SELECT_LEX *select_lex= &lex->select_lex;
1572
  SELECT_LEX_UNIT *unit= &lex->unit;
unknown's avatar
unknown committed
1573 1574
  DBUG_ENTER("mysql_execute_command");

1575 1576 1577 1578 1579 1580
  /*
    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.
  */
1581
  if (tables || &lex->select_lex != lex->all_selects_list)
1582 1583 1584 1585 1586 1587 1588
    mysql_reset_errors(thd);
  /*
    Save old warning count to be able to send to client how many warnings we
    got
  */
  thd->old_total_warn_count= thd->total_warn_count;

1589
#ifndef EMBEDDED_LIBRARY
1590 1591
  if (thd->slave_thread)
  {
unknown's avatar
unknown committed
1592
    /*
unknown's avatar
merge  
unknown committed
1593 1594 1595 1596
      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))
1597
      DBUG_VOID_RETURN;
unknown's avatar
merge  
unknown committed
1598 1599 1600 1601 1602 1603
#ifndef TO_BE_DELETED
    /*
       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()
    */
1604 1605 1606
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
unknown's avatar
unknown committed
1607
      lex->insert_list = &select_lex->item_list;
1608
    }
unknown's avatar
merge  
unknown committed
1609
#endif
1610
  }
1611
#endif /* EMBEDDED_LIBRARY */
1612
  /*
unknown's avatar
unknown committed
1613 1614
    TODO: make derived tables processing 'inside' SELECT processing.
    TODO: solve problem with depended derived tables in subselects
1615
  */
unknown's avatar
unknown committed
1616
  if (lex->derived_tables)
unknown's avatar
unknown committed
1617
  {
1618 1619 1620
    for (SELECT_LEX *sl= lex->all_selects_list;
	 sl;
	 sl= sl->next_select_in_list())
1621
    {
1622 1623 1624
      for (TABLE_LIST *cursor= sl->get_table_list();
	   cursor;
	   cursor= cursor->next)
1625
      {
1626 1627 1628
	if (cursor->derived && (res=mysql_derived(thd, lex,
						  cursor->derived,
						  cursor)))
unknown's avatar
unknown committed
1629
	{
1630 1631 1632 1633
	  if (res < 0 || thd->net.report_error)
	    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
	  DBUG_VOID_RETURN;
	}
1634 1635
      }
    }
1636
  }
unknown's avatar
unknown committed
1637
  if ((&lex->select_lex != lex->all_selects_list &&
1638
       lex->unit.create_total_list(thd, lex, &tables, 0)) 
1639
#ifdef HAVE_REPLICATION
1640
      ||
unknown's avatar
unknown committed
1641
      (table_rules_on && tables && thd->slave_thread &&
1642 1643 1644
       !tables_ok(thd,tables))
#endif
      )
1645
    DBUG_VOID_RETURN;
1646

unknown's avatar
unknown committed
1647
  statistic_increment(com_stat[lex->sql_command],&LOCK_status);
unknown's avatar
unknown committed
1648 1649 1650
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
1651
    select_result *result=lex->result;
unknown's avatar
unknown committed
1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
    if (tables)
    {
      res=check_table_access(thd,
			     lex->exchange ? SELECT_ACL | FILE_ACL :
			     SELECT_ACL,
			     tables);
    }
    else
      res=check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
		       any_db);
    if (res)
    {
      res=0;
      break;					// Error message is given
    }

1668 1669 1670
    unit->offset_limit_cnt= (ha_rows) unit->global_parameters->offset_limit;
    unit->select_limit_cnt= (ha_rows) (unit->global_parameters->select_limit+
      unit->global_parameters->offset_limit);
unknown's avatar
unknown committed
1671
    if (unit->select_limit_cnt <
1672
	(ha_rows) unit->global_parameters->select_limit)
1673 1674
      unit->select_limit_cnt= HA_POS_ERROR;		// no limit
    if (unit->select_limit_cnt == HA_POS_ERROR)
1675
      select_lex->options&= ~OPTION_FOUND_ROWS;
unknown's avatar
unknown committed
1676 1677

    if (!(res=open_and_lock_tables(thd,tables)))
unknown's avatar
unknown committed
1678
    {
unknown's avatar
unknown committed
1679
      if (lex->describe)
unknown's avatar
unknown committed
1680
      {
1681 1682 1683 1684 1685 1686 1687
	if (!(result= new select_send()))
	{
	  send_error(thd, ER_OUT_OF_RESOURCES);
	  DBUG_VOID_RETURN;
	}
	else
	  thd->send_explain_fields(result);
1688
	fix_tables_pointers(lex->all_selects_list);
1689
	res= mysql_explain_union(thd, &thd->lex.unit, result);
unknown's avatar
unknown committed
1690 1691
	MYSQL_LOCK *save_lock= thd->lock;
	thd->lock= (MYSQL_LOCK *)0;
1692
	result->send_eof();
unknown's avatar
unknown committed
1693 1694 1695 1696
	thd->lock= save_lock;
      }
      else
      {
unknown's avatar
unknown committed
1697 1698
	if (!result)
	{
unknown's avatar
unknown committed
1699
	  if (!(result=new select_send()))
unknown's avatar
unknown committed
1700 1701 1702 1703 1704 1705 1706 1707 1708
	  {
	    res= -1;
#ifdef DELETE_ITEMS
	    delete select_lex->having;
	    delete select_lex->where;
#endif
	    break;
	  }
	}
unknown's avatar
unknown committed
1709 1710 1711
	query_cache_store_query(thd, tables);
	res=handle_select(thd, lex, result);
      }
unknown's avatar
unknown committed
1712
    }
unknown's avatar
unknown committed
1713 1714
    break;
  }
unknown's avatar
unknown committed
1715
  case SQLCOM_DO:
unknown's avatar
unknown committed
1716 1717 1718 1719 1720 1721 1722 1723
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
		   (res= open_and_lock_tables(thd,tables))))
	break;

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

1726
  case SQLCOM_EMPTY_QUERY:
1727
    send_ok(thd);
1728 1729
    break;

unknown's avatar
unknown committed
1730 1731 1732 1733
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

1734
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1735
  case SQLCOM_PURGE:
1736
  {
unknown's avatar
unknown committed
1737
    if (check_global_access(thd, SUPER_ACL))
1738
      goto error;
1739
    // PURGE MASTER LOGS TO 'file'
1740 1741 1742
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
1743 1744 1745 1746 1747 1748 1749 1750
  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;
  }
1751 1752
#endif

unknown's avatar
unknown committed
1753 1754
  case SQLCOM_SHOW_WARNS:
  {
1755 1756
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
1757 1758 1759
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
unknown's avatar
unknown committed
1760 1761 1762 1763
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
1764 1765
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
1766 1767
    break;
  }
unknown's avatar
unknown committed
1768 1769
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
1770
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1771
      goto error;
unknown's avatar
unknown committed
1772
#ifndef WORKING_NEW_MASTER
1773
    net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
unknown's avatar
unknown committed
1774 1775
    res= 1;
#else
unknown's avatar
unknown committed
1776
    res = show_new_master(thd);
unknown's avatar
unknown committed
1777
#endif
unknown's avatar
unknown committed
1778 1779
    break;
  }
1780 1781

#ifndef EMBEDDED_LIBRARY
1782 1783
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
1784
    if (check_global_access(thd, REPL_SLAVE_ACL))
1785 1786 1787 1788
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
1789 1790
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
1791
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1792 1793 1794 1795
      goto error;
    res = show_binlog_events(thd);
    break;
  }
1796 1797
#endif

unknown's avatar
unknown committed
1798
  case SQLCOM_BACKUP_TABLE:
1799 1800 1801
  {
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables) ||
unknown's avatar
unknown committed
1802
	check_global_access(thd, FILE_ACL))
1803 1804
      goto error; /* purecov: inspected */
    res = mysql_backup_table(thd, tables);
unknown's avatar
unknown committed
1805

1806 1807
    break;
  }
unknown's avatar
unknown committed
1808
  case SQLCOM_RESTORE_TABLE:
1809 1810
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
1811 1812
	check_table_access(thd, INSERT_ACL, tables) ||
	check_global_access(thd, FILE_ACL))
1813 1814 1815 1816
      goto error; /* purecov: inspected */
    res = mysql_restore_table(thd, tables);
    break;
  }
1817 1818

#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1819
  case SQLCOM_CHANGE_MASTER:
1820
  {
unknown's avatar
unknown committed
1821
    if (check_global_access(thd, SUPER_ACL))
1822
      goto error;
1823 1824 1825
    LOCK_ACTIVE_MI;
    res = change_master(thd,active_mi);
    UNLOCK_ACTIVE_MI;
1826 1827
    break;
  }
unknown's avatar
unknown committed
1828
  case SQLCOM_SHOW_SLAVE_STAT:
1829
  {
unknown's avatar
unknown committed
1830
    if (check_global_access(thd, SUPER_ACL))
1831
      goto error;
1832 1833 1834
    LOCK_ACTIVE_MI;
    res = show_master_info(thd,active_mi);
    UNLOCK_ACTIVE_MI;
1835 1836
    break;
  }
unknown's avatar
unknown committed
1837
  case SQLCOM_SHOW_MASTER_STAT:
1838
  {
unknown's avatar
unknown committed
1839
    if (check_global_access(thd, SUPER_ACL))
1840 1841 1842 1843
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
1844

1845
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
1846
    if (check_global_access(thd, SUPER_ACL))
1847
      goto error;
1848 1849 1850 1851
    if (end_active_trans(thd))
      res= -1;
    else
      res = load_master_data(thd);
1852
    break;
1853
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
1854

unknown's avatar
unknown committed
1855 1856 1857
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
1858
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1859 1860 1861 1862 1863
	goto error;
      res = innodb_show_status(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
1864

1865
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1866
  case SQLCOM_LOAD_MASTER_TABLE:
1867
  {
unknown's avatar
unknown committed
1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879
    if (!tables->db)
      tables->db=thd->db;
    if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege))
      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)
1880
	goto error;
unknown's avatar
unknown committed
1881
    }
1882
    if (strlen(tables->real_name) > NAME_LEN)
unknown's avatar
unknown committed
1883
    {
unknown's avatar
unknown committed
1884
      net_printf(thd,ER_WRONG_TABLE_NAME,tables->real_name);
unknown's avatar
unknown committed
1885 1886
      break;
    }
1887 1888 1889 1890 1891
    LOCK_ACTIVE_MI;
    // fetch_master_table will send the error to the client on failure
    if (!fetch_master_table(thd, tables->db, tables->real_name,
			    active_mi, 0))
    {
1892
      send_ok(thd);
1893 1894
    }
    UNLOCK_ACTIVE_MI;
unknown's avatar
unknown committed
1895
    break;
1896
  }
1897 1898
#endif /* EMBEDDED_LIBRARY */

unknown's avatar
unknown committed
1899
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
1900 1901 1902
  {
    ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
		      CREATE_TMP_ACL : CREATE_ACL);
1903 1904
    if (!tables->db)
      tables->db=thd->db;
unknown's avatar
unknown committed
1905
    if (check_access(thd,want_priv,tables->db,&tables->grant.privilege) ||
1906 1907 1908
	check_merge_table_access(thd, tables->db,
				 (TABLE_LIST *)
				 lex->create_info.merge_list.first))
unknown's avatar
unknown committed
1909
      goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
1910
    if (grant_option && want_priv != CREATE_TMP_ACL)
unknown's avatar
unknown committed
1911 1912 1913 1914
    {
      /* Check that the first table has CREATE privilege */
      TABLE_LIST *tmp_table_list=tables->next;
      tables->next=0;
unknown's avatar
unknown committed
1915
      bool error=check_grant(thd, want_priv, tables);
unknown's avatar
unknown committed
1916 1917 1918 1919
      tables->next=tmp_table_list;
      if (error)
	goto error;
    }
1920
    if (strlen(tables->real_name) > NAME_LEN)
unknown's avatar
unknown committed
1921
    {
unknown's avatar
unknown committed
1922
      net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias);
unknown's avatar
unknown committed
1923 1924 1925
      res=0;
      break;
    }
1926 1927 1928
#ifndef HAVE_READLINK
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
1929
    /* Fix names if symlinked tables */
unknown's avatar
unknown committed
1930
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
1931
			   tables->real_name) ||
unknown's avatar
unknown committed
1932
	append_file_to_dir(thd,&lex->create_info.index_file_name,
1933
			   tables->real_name))
1934 1935 1936 1937
    {
      res=-1;
      break;
    }
1938
#endif
1939
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
1940 1941 1942 1943
    {
      select_result *result;

      if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
1944
	  find_real_table_in_list(tables->next, tables->db, tables->real_name))
unknown's avatar
unknown committed
1945
      {
unknown's avatar
unknown committed
1946
	net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
unknown's avatar
unknown committed
1947 1948 1949 1950 1951 1952 1953
	DBUG_VOID_RETURN;
      }
      if (tables->next)
      {
	if (check_table_access(thd, SELECT_ACL, tables->next))
	  goto error;				// Error message is given
      }
1954
      select_lex->options|= SELECT_NO_UNLOCK;
1955 1956 1957 1958 1959
      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
1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975

      /* 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;
      }
    }
unknown's avatar
unknown committed
1976 1977
    else // regular create
    {
unknown's avatar
unknown committed
1978 1979 1980 1981 1982 1983 1984 1985
      if (lex->name)
        res= mysql_create_like_table(thd, tables, &lex->create_info, 
                                     (Table_ident *)lex->name); 
      else
        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
unknown's avatar
unknown committed
1986
      if (!res)
1987
	send_ok(thd);
unknown's avatar
unknown committed
1988 1989
    }
    break;
unknown's avatar
unknown committed
1990
  }
unknown's avatar
unknown committed
1991 1992 1993 1994 1995 1996 1997
  case SQLCOM_CREATE_INDEX:
    if (!tables->db)
      tables->db=thd->db;
    if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege))
      goto error; /* purecov: inspected */
    if (grant_option && check_grant(thd,INDEX_ACL,tables))
      goto error;
1998 1999 2000 2001
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_create_index(thd, tables, lex->key_list);
unknown's avatar
unknown committed
2002 2003
    break;

2004
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2005
  case SQLCOM_SLAVE_START:
2006 2007 2008 2009
  {
    LOCK_ACTIVE_MI;
    start_slave(thd,active_mi,1 /* net report*/);
    UNLOCK_ACTIVE_MI;
unknown's avatar
unknown committed
2010
    break;
2011
  }
unknown's avatar
unknown committed
2012
  case SQLCOM_SLAVE_STOP:
2013 2014 2015 2016 2017 2018
  /*
    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,
2019
      so it waits for the client thread because t is locked by it.
2020
    - then the client thread does SLAVE STOP.
2021 2022
      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.
2023 2024 2025 2026 2027
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
  if (thd->locked_tables || thd->active_transaction())
  {
2028
    send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
2029
    break;
2030
  }
2031 2032 2033 2034
  {
    LOCK_ACTIVE_MI;
    stop_slave(thd,active_mi,1/* net report*/);
    UNLOCK_ACTIVE_MI;
unknown's avatar
unknown committed
2035
    break;
2036
  }
2037 2038
#endif

unknown's avatar
unknown committed
2039 2040
  case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
2041
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
2042 2043 2044
    break;
#else
    {
unknown's avatar
unknown committed
2045
      ulong priv=0;
unknown's avatar
unknown committed
2046
      if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
unknown's avatar
unknown committed
2047
      {
2048
	net_printf(thd,ER_WRONG_TABLE_NAME,lex->name);
unknown's avatar
unknown committed
2049 2050 2051
	res=0;
	break;
      }
2052 2053
      if (!tables->db)
	tables->db=thd->db;
2054 2055
      if (!select_lex->db)
	select_lex->db=tables->db;
unknown's avatar
unknown committed
2056
      if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege) ||
2057
	  check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv) ||
unknown's avatar
unknown committed
2058
	  check_merge_table_access(thd, tables->db,
2059 2060 2061
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072
      if (!tables->db)
	tables->db=thd->db;
      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;
2073
	  tmp_table.db=select_lex->db;
unknown's avatar
unknown committed
2074 2075 2076 2077 2078
	  tmp_table.grant.privilege=priv;
	  if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables))
	    goto error;
	}
      }
2079 2080
      /* Don't yet allow changing of symlinks with ALTER TABLE */
      lex->create_info.data_file_name=lex->create_info.index_file_name=0;
unknown's avatar
unknown committed
2081
      /* ALTER TABLE ends previous transaction */
2082
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2083 2084
	res= -1;
      else
unknown's avatar
unknown committed
2085
      {
2086
	res= mysql_alter_table(thd, select_lex->db, lex->name,
unknown's avatar
unknown committed
2087 2088 2089
			       &lex->create_info,
			       tables, lex->create_list,
			       lex->key_list, lex->drop_list, lex->alter_list,
2090
			       select_lex->order_list.elements,
2091
                               (ORDER *) select_lex->order_list.first,
2092 2093
			       lex->drop_primary, lex->duplicates,
			       lex->alter_keys_onoff, lex->simple_alter);
unknown's avatar
unknown committed
2094
      }
unknown's avatar
unknown committed
2095 2096 2097
      break;
    }
#endif
unknown's avatar
unknown committed
2098
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
2099 2100 2101
  {
    TABLE_LIST *table;
    if (check_db_used(thd,tables))
unknown's avatar
unknown committed
2102
      goto error;
unknown's avatar
unknown committed
2103 2104
    for (table=tables ; table ; table=table->next->next)
    {
unknown's avatar
unknown committed
2105 2106
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
		       &table->grant.privilege) ||
unknown's avatar
unknown committed
2107 2108 2109 2110 2111
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next->db,
		       &table->next->grant.privilege))
	goto error;
      if (grant_option)
      {
unknown's avatar
unknown committed
2112 2113 2114 2115 2116
	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) ||
unknown's avatar
unknown committed
2117
	    (!test_all_bits(table->next->grant.privilege,
2118
			    INSERT_ACL | CREATE_ACL) &&
unknown's avatar
unknown committed
2119
	     check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list)))
unknown's avatar
unknown committed
2120 2121 2122
	  goto error;
      }
    }
unknown's avatar
unknown committed
2123
    query_cache_invalidate3(thd, tables, 0);
2124 2125 2126
    if (end_active_trans(thd))
      res= -1;
    else if (mysql_rename_tables(thd,tables))
unknown's avatar
unknown committed
2127 2128
      res= -1;
    break;
unknown's avatar
unknown committed
2129
  }
2130
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2131 2132
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2133
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
2134 2135 2136
    DBUG_VOID_RETURN;
#else
    {
unknown's avatar
unknown committed
2137
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2138 2139 2140 2141
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
2142
#endif
2143
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2144
  case SQLCOM_SHOW_CREATE:
unknown's avatar
unknown committed
2145
#ifdef DONT_ALLOW_SHOW_COMMANDS
2146
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
2147 2148
    DBUG_VOID_RETURN;
#else
unknown's avatar
unknown committed
2149
    {
unknown's avatar
unknown committed
2150 2151 2152 2153
      if (check_db_used(thd, tables) ||
	  check_access(thd, SELECT_ACL | EXTRA_ACL, tables->db,
		       &tables->grant.privilege))
	goto error;
unknown's avatar
unknown committed
2154
      res = mysqld_show_create(thd, tables);
unknown's avatar
unknown committed
2155 2156
      break;
    }
unknown's avatar
unknown committed
2157
#endif
unknown's avatar
unknown committed
2158
  case SQLCOM_REPAIR:
2159 2160 2161 2162 2163 2164 2165
  {
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
      goto error; /* purecov: inspected */
    res = mysql_repair_table(thd, tables, &lex->check_opt);
    break;
  }
unknown's avatar
unknown committed
2166
  case SQLCOM_CHECK:
2167 2168 2169 2170 2171 2172 2173
  {
    if (check_db_used(thd,tables) ||
	check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables))
      goto error; /* purecov: inspected */
    res = mysql_check_table(thd, tables, &lex->check_opt);
    break;
  }
unknown's avatar
unknown committed
2174 2175
  case SQLCOM_ANALYZE:
  {
unknown's avatar
unknown committed
2176 2177
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
unknown's avatar
unknown committed
2178
      goto error; /* purecov: inspected */
2179
    res = mysql_analyze_table(thd, tables, &lex->check_opt);
unknown's avatar
unknown committed
2180
    break;
unknown's avatar
unknown committed
2181
  }
2182

unknown's avatar
unknown committed
2183 2184 2185
  case SQLCOM_OPTIMIZE:
  {
    HA_CREATE_INFO create_info;
2186 2187
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
unknown's avatar
unknown committed
2188
      goto error; /* purecov: inspected */
2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199
    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;
unknown's avatar
unknown committed
2200
      create_info.table_charset=default_charset_info;
2201 2202 2203
      res= mysql_alter_table(thd, NullS, NullS, &create_info,
			     tables, lex->create_list,
			     lex->key_list, lex->drop_list, lex->alter_list,
2204 2205
                             0, (ORDER *) 0,
			     0, DUP_ERROR);
2206 2207 2208
    }
    else
      res = mysql_optimize_table(thd, tables, &lex->check_opt);
unknown's avatar
unknown committed
2209 2210 2211
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
unknown committed
2212 2213
    TABLE_LIST *table;
    if (check_db_used(thd,tables))
unknown's avatar
unknown committed
2214
      goto error;
unknown's avatar
unknown committed
2215 2216 2217 2218 2219
    for (table=tables ; table ; table=table->next)
    {
      if (check_access(thd,UPDATE_ACL,table->db,&table->grant.privilege))
	goto error;
    }
unknown's avatar
unknown committed
2220 2221
    if (grant_option && check_grant(thd,UPDATE_ACL,tables))
      goto error;
2222
    if (select_lex->item_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
2223
    {
2224
      send_error(thd,ER_WRONG_VALUE_COUNT);
unknown's avatar
unknown committed
2225 2226
      DBUG_VOID_RETURN;
    }
2227 2228 2229 2230
    res= mysql_update(thd,tables,
                      select_lex->item_list,
                      lex->value_list,
                      select_lex->where,
2231
		      select_lex->order_list.elements,
2232 2233 2234
                      (ORDER *) select_lex->order_list.first,
                      select_lex->select_limit,
                      lex->duplicates);
unknown's avatar
unknown committed
2235 2236
    if (thd->net.report_error)
      res= -1;
2237 2238 2239 2240 2241 2242 2243
    break;
  case SQLCOM_UPDATE_MULTI:
    if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege))
      goto error;
    if (grant_option && check_grant(thd,UPDATE_ACL,tables))
      goto error;
    if (select_lex->item_list.elements != lex->value_list.elements)
2244
    {
2245 2246
      send_error(thd,ER_WRONG_VALUE_COUNT);
      DBUG_VOID_RETURN;
2247 2248
    }
    {
unknown's avatar
unknown committed
2249
      const char *msg= 0;
unknown's avatar
unknown committed
2250
      if (select_lex->order_list.elements)
unknown's avatar
unknown committed
2251
	msg= "ORDER BY";
unknown's avatar
unknown committed
2252 2253
      else if (select_lex->select_limit && select_lex->select_limit !=
	       HA_POS_ERROR)
unknown's avatar
unknown committed
2254
	msg= "LIMIT";
unknown's avatar
unknown committed
2255
      if (msg)
2256
      {
2257
	net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg);
unknown's avatar
unknown committed
2258 2259
	res= 1;
	break;
2260
      }
unknown's avatar
unknown committed
2261 2262 2263 2264 2265
      res= mysql_multi_update(thd,tables,
			      &select_lex->item_list,
			      &lex->value_list,
			      select_lex->where,
			      select_lex->options,
unknown's avatar
unknown committed
2266
			      lex->duplicates, unit, select_lex);
2267
    }
unknown's avatar
unknown committed
2268 2269
    break;
  case SQLCOM_REPLACE:
2270 2271
  case SQLCOM_INSERT:
  {
2272
    my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
2273
    ulong privilege= (lex->duplicates == DUP_REPLACE ?
2274
                      INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
2275
    if (check_access(thd,privilege,tables->db,&tables->grant.privilege))
unknown's avatar
unknown committed
2276
      goto error; /* purecov: inspected */
2277
    if (grant_option && check_grant(thd,privilege,tables))
unknown's avatar
unknown committed
2278
      goto error;
2279 2280 2281 2282 2283
    if (select_lex->item_list.elements != lex->value_list.elements)
    {
      send_error(thd,ER_WRONG_VALUE_COUNT);
      DBUG_VOID_RETURN;
    }
unknown's avatar
unknown committed
2284
    res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
2285
                       select_lex->item_list, lex->value_list,
unknown's avatar
unknown committed
2286
                       (update ? DUP_UPDATE : lex->duplicates));
unknown's avatar
unknown committed
2287 2288
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2289
    break;
2290
  }
unknown's avatar
unknown committed
2291 2292 2293
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
2294

unknown's avatar
unknown committed
2295 2296 2297 2298
    /*
      Check that we have modify privileges for the first table and
      select privileges for the rest
    */
2299
    {
2300 2301
      ulong privilege= (lex->duplicates == DUP_REPLACE ?
                        INSERT_ACL | DELETE_ACL : INSERT_ACL);
2302 2303 2304 2305 2306 2307 2308 2309 2310 2311
      TABLE_LIST *save_next=tables->next;
      tables->next=0;
      if (check_access(thd, privilege,
		       tables->db,&tables->grant.privilege) ||
	  (grant_option && check_grant(thd, privilege, tables)))
	goto error;
      tables->next=save_next;
      if ((res=check_table_access(thd, SELECT_ACL, save_next)))
	goto error;
    }
2312 2313
    /* Don't unlock tables until command is written to binary log */
    select_lex->options|= SELECT_NO_UNLOCK;
unknown's avatar
unknown committed
2314 2315

    select_result *result;
2316 2317 2318 2319
    unit->offset_limit_cnt= select_lex->offset_limit;
    unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit;
    if (unit->select_limit_cnt < select_lex->select_limit)
      unit->select_limit_cnt= HA_POS_ERROR;		// No limit
unknown's avatar
unknown committed
2320

2321
    if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
2322
    {
unknown's avatar
unknown committed
2323
      net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
2324
      DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2325
    }
2326 2327 2328 2329 2330 2331 2332

    /* 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);
    if (!(res=open_and_lock_tables(thd, tables)))
    {
      if ((result=new select_insert(tables->table,&lex->field_list,
2333
				    lex->duplicates)))
2334
	res=handle_select(thd,lex,result);
unknown's avatar
unknown committed
2335 2336
      if (thd->net.report_error)
	res= -1;
2337 2338 2339
    }
    else
      res= -1;
unknown's avatar
unknown committed
2340 2341
    break;
  }
2342
  case SQLCOM_TRUNCATE:
2343 2344
    if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
      goto error; /* purecov: inspected */
unknown's avatar
unknown committed
2345 2346
    if (grant_option && check_grant(thd,DELETE_ACL,tables))
      goto error;
2347 2348 2349 2350 2351 2352
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
    if (thd->locked_tables || thd->active_transaction())
    {
2353
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
2354 2355 2356 2357
      goto error;
    }
    res=mysql_truncate(thd,tables);
    break;
unknown's avatar
unknown committed
2358
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
2359 2360 2361 2362 2363 2364 2365
  {
    if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
      goto error; /* purecov: inspected */
    if (grant_option && check_grant(thd,DELETE_ACL,tables))
      goto error;
    // Set privilege for the WHERE clause
    tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
2366 2367
    res = mysql_delete(thd,tables, select_lex->where,
                       (ORDER*) select_lex->order_list.first,
unknown's avatar
unknown committed
2368
                       select_lex->select_limit, select_lex->options);
unknown's avatar
unknown committed
2369 2370
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2371 2372
    break;
  }
2373
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
2374 2375 2376 2377 2378
  {
    TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first;
    TABLE_LIST *auxi;
    uint table_count=0;
    multi_delete *result;
unknown's avatar
unknown committed
2379

unknown's avatar
unknown committed
2380 2381
    /* sql_yacc guarantees that tables and aux_tables are not zero */
    if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
2382
	check_table_access(thd,SELECT_ACL, tables) ||
unknown's avatar
unknown committed
2383 2384 2385
	check_table_access(thd,DELETE_ACL, aux_tables))
      goto error;
    if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
2386
    {
2387
      send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
unknown's avatar
unknown committed
2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402
      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)
      {
2403
	net_printf(thd,ER_NONUNIQ_TABLE,auxi->real_name);
unknown's avatar
unknown committed
2404 2405
	goto error;
      }
unknown's avatar
unknown committed
2406
      walk->lock_type= auxi->lock_type;
2407
      auxi->table_list=  walk;		// Remember corresponding table
2408
    }
unknown's avatar
unknown committed
2409
    if (add_item_to_list(thd, new Item_null()))
2410
    {
unknown's avatar
unknown committed
2411
      res= -1;
2412
      break;
unknown's avatar
unknown committed
2413 2414 2415 2416 2417 2418
    }
    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)
2419
      auxi->table= auxi->table_list->table;
2420
    if (&lex->select_lex != lex->all_selects_list)
unknown's avatar
unknown committed
2421
    {
2422 2423 2424 2425 2426
      for (TABLE_LIST *t= select_lex->get_table_list();
	   t; t= t->next)
      {
	if (find_real_table_in_list(t->table_list->next, t->db, t->real_name))
	{
unknown's avatar
unknown committed
2427
	  my_error(ER_UPDATE_TABLE_USED, MYF(0), t->real_name);
2428 2429 2430 2431
	  res= -1;
	  break;
	}
      }
unknown's avatar
unknown committed
2432
    }
unknown's avatar
unknown committed
2433
    fix_tables_pointers(lex->all_selects_list);
2434 2435
    if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
							  table_count)))
unknown's avatar
unknown committed
2436
    {
2437 2438 2439
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
2440
			select_lex->item_list,
unknown's avatar
unknown committed
2441
			select_lex->where,
2442
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
unknown's avatar
unknown committed
2443 2444
			(ORDER *)NULL,
			select_lex->options | thd->options |
unknown's avatar
unknown committed
2445
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
2446
			result, unit, select_lex, 0);
unknown's avatar
unknown committed
2447 2448
      if (thd->net.report_error)
	res= -1;
2449
      delete result;
unknown's avatar
unknown committed
2450 2451 2452 2453 2454 2455
    }
    else
      res= -1;					// Error is not sent
    close_thread_tables(thd);
    break;
  }
unknown's avatar
unknown committed
2456
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
2457
  {
2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468
    if (!lex->drop_temporary)
    {
      if (check_table_access(thd,DROP_ACL,tables))
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
    res= mysql_rm_table(thd,tables,lex->drop_if_exists, lex->drop_temporary);
unknown's avatar
unknown committed
2469 2470
  }
  break;
unknown's avatar
unknown committed
2471 2472 2473 2474 2475 2476 2477
  case SQLCOM_DROP_INDEX:
    if (!tables->db)
      tables->db=thd->db;
    if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege))
      goto error;				/* purecov: inspected */
    if (grant_option && check_grant(thd,INDEX_ACL,tables))
      goto error;
2478 2479 2480 2481
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_drop_index(thd, tables, lex->drop_list);
unknown's avatar
unknown committed
2482 2483
    break;
  case SQLCOM_SHOW_DATABASES:
2484
#if defined(DONT_ALLOW_SHOW_COMMANDS)
2485
    send_error(thd,ER_NOT_ALLOWED_COMMAND);   /* purecov: inspected */
unknown's avatar
unknown committed
2486 2487 2488
    DBUG_VOID_RETURN;
#else
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
unknown's avatar
unknown committed
2489
	check_global_access(thd, SHOW_DB_ACL))
unknown's avatar
unknown committed
2490 2491 2492 2493 2494
      goto error;
    res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
    break;
#endif
  case SQLCOM_SHOW_PROCESSLIST:
unknown's avatar
unknown committed
2495
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
2496 2497 2498 2499
      break;
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
			  thd->priv_user,lex->verbose);
    break;
unknown's avatar
unknown committed
2500 2501 2502 2503 2504 2505 2506 2507 2508
  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;
unknown's avatar
unknown committed
2509
  case SQLCOM_SHOW_STATUS:
2510
    res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
unknown's avatar
unknown committed
2511
		     OPT_GLOBAL);
unknown's avatar
unknown committed
2512 2513 2514
    break;
  case SQLCOM_SHOW_VARIABLES:
    res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
unknown's avatar
unknown committed
2515
		     init_vars, lex->option_type);
unknown's avatar
unknown committed
2516
    break;
unknown's avatar
unknown committed
2517 2518
  case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2519
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
2520 2521 2522 2523 2524 2525 2526 2527 2528
    DBUG_VOID_RETURN;
#else
    {
      if (grant_option && check_access(thd, FILE_ACL, any_db))
	goto error;
      res= mysqld_show_logs(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
2529
  case SQLCOM_SHOW_TABLES:
2530
    /* FALL THROUGH */
unknown's avatar
unknown committed
2531
#ifdef DONT_ALLOW_SHOW_COMMANDS
2532
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
2533 2534 2535
    DBUG_VOID_RETURN;
#else
    {
2536
      char *db=select_lex->db ? select_lex->db : thd->db;
unknown's avatar
unknown committed
2537 2538
      if (!db)
      {
2539
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
unknown's avatar
unknown committed
2540 2541 2542
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);				// Fix escaped '_'
2543
      if (check_db_name(db))
unknown's avatar
unknown committed
2544
      {
2545
        net_printf(thd,ER_WRONG_DB_NAME, db);
2546
        goto error;
unknown's avatar
unknown committed
2547 2548 2549 2550
      }
      if (check_access(thd,SELECT_ACL,db,&thd->col_access))
	goto error;				/* purecov: inspected */
      /* grant is checked in mysqld_show_tables */
2551
      if (select_lex->options & SELECT_DESCRIBE)
2552
        res= mysqld_extend_show_tables(thd,db,
2553
				       (lex->wild ? lex->wild->ptr() : NullS));
unknown's avatar
unknown committed
2554 2555 2556 2557 2558 2559
      else
	res= mysqld_show_tables(thd,db,
				(lex->wild ? lex->wild->ptr() : NullS));
      break;
    }
#endif
2560 2561 2562
  case SQLCOM_SHOW_OPEN_TABLES:
    res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
2563 2564
  case SQLCOM_SHOW_CHARSETS:
    res= mysqld_show_charsets(thd,(lex->wild ? lex->wild->ptr() : NullS));
2565
    break;
unknown's avatar
unknown committed
2566 2567
  case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2568
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
2569 2570 2571
    DBUG_VOID_RETURN;
#else
    {
2572 2573
      char *db=tables->db;
      if (!*db)
unknown's avatar
unknown committed
2574
      {
2575
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
unknown's avatar
unknown committed
2576 2577 2578
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);			// Fix escaped '_'
2579
      remove_escape(tables->real_name);
unknown's avatar
unknown committed
2580 2581 2582 2583 2584 2585
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access))
	goto error;				/* purecov: inspected */
      tables->grant.privilege=thd->col_access;
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
	goto error;
      res= mysqld_show_fields(thd,tables,
unknown's avatar
unknown committed
2586 2587
			      (lex->wild ? lex->wild->ptr() : NullS),
			      lex->verbose);
unknown's avatar
unknown committed
2588 2589 2590 2591 2592
      break;
    }
#endif
  case SQLCOM_SHOW_KEYS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2593
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
2594 2595 2596
    DBUG_VOID_RETURN;
#else
    {
2597
      char *db=tables->db;
unknown's avatar
unknown committed
2598 2599
      if (!db)
      {
2600
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
unknown's avatar
unknown committed
2601 2602 2603
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);			// Fix escaped '_'
2604
      remove_escape(tables->real_name);
unknown's avatar
unknown committed
2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616
      if (!tables->db)
	tables->db=thd->db;
      if (check_access(thd,SELECT_ACL,db,&thd->col_access))
	goto error; /* purecov: inspected */
      tables->grant.privilege=thd->col_access;
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
	goto error;
      res= mysqld_show_keys(thd,tables);
      break;
    }
#endif
  case SQLCOM_CHANGE_DB:
2617
    mysql_change_db(thd,select_lex->db);
unknown's avatar
unknown committed
2618
    break;
2619
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2620 2621 2622
  case SQLCOM_LOAD:
  {
    uint privilege= (lex->duplicates == DUP_REPLACE ?
2623
		     INSERT_ACL | DELETE_ACL : INSERT_ACL);
2624 2625

    if (!lex->local_file)
unknown's avatar
unknown committed
2626 2627 2628 2629 2630 2631
    {
      if (check_access(thd,privilege | FILE_ACL,tables->db))
	goto error;
    }
    else
    {
2632
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
unknown's avatar
unknown committed
2633
	  ! opt_local_infile)
2634
      {
2635
	send_error(thd,ER_NOT_ALLOWED_COMMAND);
2636 2637
	goto error;
      }
unknown's avatar
unknown committed
2638
      if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
2639
	  grant_option && check_grant(thd,privilege,tables))
unknown's avatar
unknown committed
2640 2641 2642 2643 2644 2645
	goto error;
    }
    res=mysql_load(thd, lex->exchange, tables, lex->field_list,
		   lex->duplicates, (bool) lex->local_file, lex->lock_option);
    break;
  }
2646
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2647
  case SQLCOM_SET_OPTION:
unknown's avatar
unknown committed
2648 2649 2650 2651 2652
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
		   (res= open_and_lock_tables(thd,tables))))
      break;
    fix_tables_pointers(lex->all_selects_list);
    if (!(res= sql_set_variables(thd, &lex->var_list)))
2653
      send_ok(thd);
unknown's avatar
unknown committed
2654 2655
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2656
    break;
unknown's avatar
unknown committed
2657

unknown's avatar
unknown committed
2658
  case SQLCOM_UNLOCK_TABLES:
unknown's avatar
unknown committed
2659
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
2660 2661
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
2662
      end_active_trans(thd);
unknown's avatar
unknown committed
2663
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
2664 2665
    }
    if (thd->global_read_lock)
2666
      unlock_global_read_lock(thd);
2667
    send_ok(thd);
unknown's avatar
unknown committed
2668 2669
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
2670
    unlock_locked_tables(thd);
2671
    if (check_db_used(thd,tables) || end_active_trans(thd))
unknown's avatar
unknown committed
2672
      goto error;
unknown's avatar
unknown committed
2673
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables))
2674
      goto error;
unknown's avatar
unknown committed
2675
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
2676
    thd->options|= OPTION_TABLE_LOCK;
unknown's avatar
unknown committed
2677 2678 2679 2680
    if (!(res=open_and_lock_tables(thd,tables)))
    {
      thd->locked_tables=thd->lock;
      thd->lock=0;
2681
      send_ok(thd);
unknown's avatar
unknown committed
2682
    }
unknown's avatar
unknown committed
2683 2684
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
2685 2686 2687
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
2688
  {
unknown's avatar
unknown committed
2689
    if (!strip_sp(lex->name) || check_db_name(lex->name))
unknown's avatar
unknown committed
2690
    {
2691
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
2692 2693
      break;
    }
2694 2695 2696 2697 2698 2699 2700
    /*
      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.
    */
2701
#ifdef HAVE_REPLICATION
2702 2703 2704 2705
    if (thd->slave_thread && 
	(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(lex->name)))
      break;
2706
#endif
2707 2708
    if (check_access(thd,CREATE_ACL,lex->name,0,1))
      break;
2709
    res=mysql_create_db(thd,lex->name,&lex->create_info,0);
2710 2711
    break;
  }
unknown's avatar
unknown committed
2712
  case SQLCOM_DROP_DB:
2713
  {
unknown's avatar
unknown committed
2714
    if (!strip_sp(lex->name) || check_db_name(lex->name))
unknown's avatar
unknown committed
2715
    {
2716
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
2717 2718
      break;
    }
2719 2720 2721 2722 2723 2724 2725
    /*
      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.
    */
2726
#ifdef HAVE_REPLICATION
2727 2728 2729 2730
    if (thd->slave_thread && 
	(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(lex->name)))
      break;
2731
#endif
2732
    if (check_access(thd,DROP_ACL,lex->name,0,1))
2733
      break;
2734 2735
    if (thd->locked_tables || thd->active_transaction())
    {
2736
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
2737 2738
      goto error;
    }
unknown's avatar
unknown committed
2739
    res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0);
2740 2741
    break;
  }
2742 2743 2744 2745
  case SQLCOM_ALTER_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
2746
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
2747 2748
      break;
    }
unknown's avatar
unknown committed
2749
    if (check_access(thd,ALTER_ACL,lex->name,0,1))
2750 2751 2752
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
2753
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
2754 2755
      goto error;
    }
2756
    res=mysql_alter_db(thd,lex->name,&lex->create_info);
2757 2758
    break;
  }
unknown's avatar
unknown committed
2759 2760 2761 2762
  case SQLCOM_SHOW_CREATE_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
2763
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
2764 2765 2766 2767 2768 2769
      break;
    }
    if (check_access(thd,DROP_ACL,lex->name,0,1))
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
2770
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
2771 2772
      goto error;
    }
unknown's avatar
unknown committed
2773
    res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
unknown's avatar
unknown committed
2774 2775
    break;
  }
unknown's avatar
unknown committed
2776 2777 2778 2779 2780
  case SQLCOM_CREATE_FUNCTION:
    if (check_access(thd,INSERT_ACL,"mysql",0,1))
      break;
#ifdef HAVE_DLOPEN
    if (!(res = mysql_create_function(thd,&lex->udf)))
2781
      send_ok(thd);
unknown's avatar
unknown committed
2782 2783 2784 2785 2786 2787 2788 2789
#else
    res= -1;
#endif
    break;
  case SQLCOM_DROP_FUNCTION:
    if (check_access(thd,DELETE_ACL,"mysql",0,1))
      break;
#ifdef HAVE_DLOPEN
2790
    if (!(res = mysql_drop_function(thd,&lex->udf.name)))
2791
      send_ok(thd);
unknown's avatar
unknown committed
2792 2793 2794 2795
#else
    res= -1;
#endif
    break;
2796 2797 2798 2799 2800 2801 2802 2803 2804
  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,
		     tables ? 0 : 1))
      goto error;

unknown's avatar
unknown committed
2805 2806 2807 2808
    /*
      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
    */
2809 2810 2811 2812 2813 2814 2815 2816 2817 2818

    if (thd->user)				// If not replication
    {
      LEX_USER *user;
      List_iterator <LEX_USER> user_list(lex->users_list);
      while ((user=user_list++))
      {
	if (user->password.str &&
	    (strcmp(thd->user,user->user.str) ||
	     user->host.str &&
unknown's avatar
unknown committed
2819
	     my_strcasecmp(&my_charset_latin1,
2820
                           user->host.str, thd->host_or_ip)))
2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834
	{
	  if (check_access(thd, UPDATE_ACL, "mysql",0,1))
	    goto error;
	  break;			// We are allowed to do changes
	}
      }
    }
    if (tables)
    {
      if (grant_option && check_grant(thd,
				      (lex->grant | lex->grant_tot_col |
				       GRANT_ACL),
				      tables))
	goto error;
unknown's avatar
unknown committed
2835 2836 2837
      if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
				    lex->grant,
				    lex->sql_command == SQLCOM_REVOKE)))
2838
      {
2839
	mysql_update_log.write(thd, thd->query, thd->query_length);
2840 2841
	if (mysql_bin_log.is_open())
	{
2842
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
2843 2844 2845 2846 2847 2848 2849 2850
	  mysql_bin_log.write(&qinfo);
	}
      }
    }
    else
    {
      if (lex->columns.elements)
      {
2851
	send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE);
2852 2853 2854 2855 2856 2857 2858
	res=1;
      }
      else
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
2859
	mysql_update_log.write(thd, thd->query, thd->query_length);
2860 2861
	if (mysql_bin_log.is_open())
	{
2862
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
2863 2864
	  mysql_bin_log.write(&qinfo);
	}
2865
	if (mqh_used && lex->sql_command == SQLCOM_GRANT)
2866
	{
unknown's avatar
unknown committed
2867 2868 2869
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
2870
	    reset_mqh(thd,user);
2871
	}
2872 2873 2874 2875
      }
    }
    break;
  }
unknown's avatar
unknown committed
2876
  case SQLCOM_FLUSH:
unknown's avatar
unknown committed
2877
  case SQLCOM_RESET:
unknown's avatar
unknown committed
2878
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
unknown's avatar
unknown committed
2879
      goto error;
2880
    /* error sending is deferred to reload_acl_and_cache */
2881
    reload_acl_and_cache(thd, lex->type, tables);
unknown's avatar
unknown committed
2882 2883 2884 2885 2886 2887
    break;
  case SQLCOM_KILL:
    kill_one_thread(thd,lex->thread_id);
    break;
  case SQLCOM_SHOW_GRANTS:
    res=0;
2888 2889
    if ((thd->priv_user &&
	 !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
2890
	!check_access(thd, SELECT_ACL, "mysql",0,1))
unknown's avatar
unknown committed
2891 2892 2893 2894
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
2895
  case SQLCOM_HA_OPEN:
2896 2897
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables))
2898 2899 2900 2901 2902 2903 2904 2905 2906
      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:
2907 2908
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables))
2909
      goto error;
unknown's avatar
unknown committed
2910
    res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
2911 2912
			lex->insert_list, lex->ha_rkey_mode, select_lex->where,
			select_lex->select_limit, select_lex->offset_limit);
2913 2914
    break;

unknown's avatar
unknown committed
2915
  case SQLCOM_BEGIN:
unknown's avatar
unknown committed
2916 2917 2918 2919 2920 2921
    if (thd->locked_tables)
    {
      thd->lock=thd->locked_tables;
      thd->locked_tables=0;			// Will be automaticly closed
      close_thread_tables(thd);			// Free tables
    }
unknown's avatar
unknown committed
2922 2923 2924 2925 2926 2927
    if (end_active_trans(thd))
    {
      res= -1;
    }
    else
    {
2928
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
unknown's avatar
unknown committed
2929 2930
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
2931
      send_ok(thd);
unknown's avatar
unknown committed
2932
    }
unknown's avatar
unknown committed
2933 2934
    break;
  case SQLCOM_COMMIT:
2935 2936 2937 2938 2939
    /*
      We don't use end_active_trans() here to ensure that this works
      even if there is a problem with the OPTION_AUTO_COMMIT flag
      (Which of course should never happen...)
    */
unknown's avatar
unknown committed
2940
  {
2941
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
2942 2943
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
unknown's avatar
unknown committed
2944
    {
2945
      send_ok(thd);
unknown's avatar
unknown committed
2946
    }
unknown's avatar
unknown committed
2947 2948 2949
    else
      res= -1;
    break;
unknown's avatar
unknown committed
2950
  }
unknown's avatar
unknown committed
2951 2952 2953
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
2954 2955
    {
      if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
2956
	send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
2957
      else
2958
	send_ok(thd);
2959
    }
unknown's avatar
unknown committed
2960 2961
    else
      res= -1;
2962
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
2963 2964
    break;
  default:					/* Impossible */
2965
    send_ok(thd);
unknown's avatar
unknown committed
2966 2967 2968 2969
    break;
  }
  thd->proc_info="query end";			// QQ
  if (res < 0)
2970
    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
unknown's avatar
unknown committed
2971 2972 2973 2974 2975 2976 2977

error:
  DBUG_VOID_RETURN;
}


/****************************************************************************
unknown's avatar
unknown committed
2978 2979 2980 2981 2982 2983 2984
  Get the user (global) and database privileges for all used tables
  Returns true (error) if we can't get the privileges and we don't use
  table/column grants.
  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.
unknown's avatar
unknown committed
2985 2986 2987
****************************************************************************/

bool
unknown's avatar
unknown committed
2988
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
2989
	     bool dont_check_global_grants, bool no_errors)
unknown's avatar
unknown committed
2990
{
unknown's avatar
unknown committed
2991 2992 2993 2994
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("want_access: %lu  master_access: %lu", want_access,
		      thd->master_access));
  ulong db_access,dummy;
unknown's avatar
unknown committed
2995 2996 2997 2998 2999
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

3000
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
3001
  {
3002
    if (!no_errors)
3003
      send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
unknown's avatar
unknown committed
3004
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
3005 3006 3007 3008 3009
  }

  if ((thd->master_access & want_access) == want_access)
  {
    *save_priv=thd->master_access;
unknown's avatar
unknown committed
3010
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
3011
  }
3012
  if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
3013
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
3014
  {						// We can never grant this
3015
    if (!no_errors)
3016
      net_printf(thd,ER_ACCESS_DENIED_ERROR,
3017 3018 3019
		 thd->priv_user,
		 thd->host_or_ip,
		 thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
unknown's avatar
unknown committed
3020
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
3021 3022 3023
  }

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

unknown's avatar
unknown committed
3026 3027 3028 3029 3030
  if (db && (!thd->db || strcmp(db,thd->db)))
    db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
		      thd->priv_user, db); /* purecov: inspected */
  else
    db_access=thd->db_access;
3031 3032
  // Remove SHOW attribute and access rights we already have
  want_access &= ~(thd->master_access | EXTRA_ACL);
unknown's avatar
unknown committed
3033
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
3034 3035

  /* grant_option is set if there exists a single table or column grant */
unknown's avatar
unknown committed
3036
  if (db_access == want_access ||
3037 3038
      ((grant_option && !dont_check_global_grants) &&
       !(want_access & ~TABLE_ACLS)))
unknown's avatar
unknown committed
3039
    DBUG_RETURN(FALSE);				/* Ok */
3040
  if (!no_errors)
3041
    net_printf(thd,ER_DBACCESS_DENIED_ERROR,
3042 3043 3044
	       thd->priv_user,
	       thd->host_or_ip,
	       db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
unknown's avatar
unknown committed
3045
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
3046 3047 3048
}


unknown's avatar
unknown committed
3049 3050 3051
/* check for global access and give descriptive error message if it fails */

bool check_global_access(THD *thd, ulong want_access)
unknown's avatar
unknown committed
3052
{
unknown's avatar
unknown committed
3053 3054 3055 3056
  char command[128];
  if ((thd->master_access & want_access) == want_access)
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
3057
  net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
unknown's avatar
unknown committed
3058 3059
	     command);
  return 1;
unknown's avatar
unknown committed
3060 3061 3062
}


unknown's avatar
unknown committed
3063
/*
unknown's avatar
unknown committed
3064 3065
  Check the privilege for all used tables.  Table privileges are cached
  in the table list for GRANT checking
unknown's avatar
unknown committed
3066 3067
*/

3068
bool
unknown's avatar
unknown committed
3069
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
3070
		   bool no_errors)
unknown's avatar
unknown committed
3071
{
unknown's avatar
unknown committed
3072 3073
  uint found=0;
  ulong found_access=0;
unknown's avatar
unknown committed
3074 3075 3076
  TABLE_LIST *org_tables=tables;
  for (; tables ; tables=tables->next)
  {
3077
    if (tables->derived || (tables->table && (int)tables->table->tmp_table))
unknown's avatar
unknown committed
3078
      continue;
unknown's avatar
unknown committed
3079 3080
    if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
	thd->db)
unknown's avatar
unknown committed
3081
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
3082
    else if (tables->db && tables->db == thd->db)
unknown's avatar
unknown committed
3083 3084 3085 3086 3087
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
3088 3089
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
			 0, no_errors))
unknown's avatar
unknown committed
3090 3091
	  return TRUE;				// Access denied
	found_access=tables->grant.privilege;
unknown's avatar
unknown committed
3092
	found=1;
unknown's avatar
unknown committed
3093 3094
      }
    }
3095
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
3096
			  0, no_errors))
3097
      return TRUE;
unknown's avatar
unknown committed
3098 3099
  }
  if (grant_option)
3100
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
3101
		       test(want_access & EXTRA_ACL), no_errors);
unknown's avatar
unknown committed
3102 3103 3104 3105
  return FALSE;
}


unknown's avatar
unknown committed
3106
static bool check_db_used(THD *thd,TABLE_LIST *tables)
unknown's avatar
unknown committed
3107 3108 3109 3110 3111 3112 3113
{
  for (; tables ; tables=tables->next)
  {
    if (!tables->db)
    {
      if (!(tables->db=thd->db))
      {
3114
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
unknown's avatar
unknown committed
3115 3116 3117 3118 3119 3120 3121 3122
	return TRUE;				/* purecov: tested */
      }
    }
  }
  return FALSE;
}


3123 3124
static bool check_merge_table_access(THD *thd, char *db,
				     TABLE_LIST *table_list)
3125 3126 3127 3128
{
  int error=0;
  if (table_list)
  {
3129
    /* Check that all tables use the current database */
3130 3131
    TABLE_LIST *tmp;
    for (tmp=table_list; tmp ; tmp=tmp->next)
3132 3133 3134
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
unknown's avatar
unknown committed
3135
      else if (strcmp(tmp->db,db))
3136
      {
3137
	send_error(thd,ER_UNION_TABLES_IN_DIFFERENT_DIR);
3138 3139 3140
	return 1;
      }
    }
3141 3142 3143 3144 3145 3146 3147
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
			     table_list);
  }
  return error;
}


unknown's avatar
unknown committed
3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165
/****************************************************************************
	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

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));
3166
    thd->fatal_error();
unknown's avatar
unknown committed
3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204
    return 1;
  }
  return 0;
}

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


/****************************************************************************
3205
  Initialize global thd variables needed for query
unknown's avatar
unknown committed
3206 3207
****************************************************************************/

3208
void
unknown's avatar
unknown committed
3209 3210 3211
mysql_init_query(THD *thd)
{
  DBUG_ENTER("mysql_init_query");
3212 3213 3214
  LEX *lex=&thd->lex;
  lex->unit.init_query();
  lex->unit.init_select();
3215
  lex->unit.thd= thd;
3216 3217 3218
  lex->select_lex.init_query();
  lex->value_list.empty();
  lex->param_list.empty();
unknown's avatar
unknown committed
3219 3220
  lex->unit.next= lex->unit.master= lex->unit.link_next= 0;
  lex->unit.prev= lex->unit.link_prev= 0;
unknown's avatar
unknown committed
3221
  lex->unit.global_parameters= lex->unit.slave= lex->current_select=
3222
    lex->all_selects_list= &lex->select_lex;
3223 3224
  lex->select_lex.master= &lex->unit;
  lex->select_lex.prev= &lex->unit.slave;
unknown's avatar
unknown committed
3225
  lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
3226
  lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
3227 3228
  lex->describe= 0;
  lex->derived_tables= FALSE;
3229 3230
  lex->lock_option= TL_READ;
  lex->found_colon= 0;
3231
  lex->safe_to_cache_query= 1;
3232
  thd->select_number= lex->select_lex.select_number= 1;
unknown's avatar
unknown committed
3233
  thd->free_list= 0;
3234
  thd->total_warn_count=0;			// Warnings for this query
unknown's avatar
unknown committed
3235 3236
  thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
  thd->sent_row_count= thd->examined_row_count= 0;
3237
  thd->is_fatal_error= thd->rand_used= 0;
3238
  thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
unknown's avatar
unknown committed
3239
  thd->tmp_table_used= 0;
unknown's avatar
unknown committed
3240 3241
  if (opt_bin_log)
    reset_dynamic(&thd->user_var_events);
3242
  thd->clear_error();
unknown's avatar
unknown committed
3243 3244 3245
  DBUG_VOID_RETURN;
}

3246

3247 3248 3249
void
mysql_init_select(LEX *lex)
{
unknown's avatar
unknown committed
3250
  SELECT_LEX *select_lex= lex->current_select->select_lex();
unknown's avatar
unknown committed
3251
  select_lex->init_select();
unknown's avatar
unknown committed
3252
  select_lex->master_unit()->select_limit= select_lex->select_limit=
unknown's avatar
unknown committed
3253
    lex->thd->variables.select_limit;
3254 3255 3256 3257 3258 3259
  if (select_lex == &lex->select_lex)
  {
    lex->exchange= 0;
    lex->result= 0;
    lex->proc_list.first= 0;
  }
3260 3261
}

3262

unknown's avatar
unknown committed
3263
bool
unknown's avatar
unknown committed
3264
mysql_new_select(LEX *lex, bool move_down)
3265
{
3266
  SELECT_LEX *select_lex = new SELECT_LEX();
unknown's avatar
unknown committed
3267
  select_lex->select_number= ++lex->thd->select_number;
unknown's avatar
unknown committed
3268 3269
  if (!select_lex)
    return 1;
unknown's avatar
unknown committed
3270 3271 3272 3273 3274
  select_lex->init_query();
  select_lex->init_select();
  if (move_down)
  {
    /* first select_lex of subselect or derived table */
3275
    SELECT_LEX_UNIT *unit= new SELECT_LEX_UNIT();
unknown's avatar
unknown committed
3276 3277 3278 3279
    if (!unit)
      return 1;
    unit->init_query();
    unit->init_select();
3280
    unit->thd= lex->thd;
3281
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
3282 3283
    unit->link_next= 0;
    unit->link_prev= 0;
unknown's avatar
unknown committed
3284 3285 3286
    select_lex->include_down(unit);
  }
  else
3287
    select_lex->include_neighbour(lex->current_select);
unknown's avatar
unknown committed
3288

3289
  select_lex->master_unit()->global_parameters= select_lex;
3290
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
3291
  lex->current_select= select_lex;
unknown's avatar
unknown committed
3292
  return 0;
3293
}
unknown's avatar
unknown committed
3294

3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317
/*
  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)
{
  LEX *lex;
  LEX_STRING tmp;
  DBUG_ENTER("create_select_for_variable");
  lex= current_lex;
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
unknown's avatar
unknown committed
3318
  add_item_to_list(lex->thd, get_system_var(OPT_SESSION, tmp));
3319 3320 3321
  DBUG_VOID_RETURN;
}

3322

unknown's avatar
unknown committed
3323 3324
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
3325
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
3326
  mysql_init_select(lex);
3327
  lex->select_lex.select_limit= lex->unit.select_limit_cnt=
unknown's avatar
unknown committed
3328
    HA_POS_ERROR;
unknown's avatar
unknown committed
3329
  lex->auxilliary_table_list= lex->select_lex.table_list;
3330
  lex->select_lex.init_query();
unknown's avatar
unknown committed
3331
}
unknown's avatar
unknown committed
3332

3333

unknown's avatar
unknown committed
3334
void
unknown's avatar
unknown committed
3335
mysql_parse(THD *thd, char *inBuf, uint length)
unknown's avatar
unknown committed
3336 3337 3338 3339
{
  DBUG_ENTER("mysql_parse");

  mysql_init_query(thd);
unknown's avatar
unknown committed
3340
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
unknown's avatar
unknown committed
3341 3342
  {
    LEX *lex=lex_start(thd, (uchar*) inBuf, length);
3343
    if (!yyparse((void *)thd) && ! thd->is_fatal_error)
unknown's avatar
unknown committed
3344
    {
3345
      if (mqh_used && thd->user_connect &&
3346
	  check_mqh(thd, lex->sql_command))
3347 3348 3349 3350 3351
      {
	thd->net.error = 0;
      }
      else
      {
unknown's avatar
unknown committed
3352 3353 3354 3355 3356
	if (thd->net.report_error)
	  send_error(thd, 0, NullS);
	else
	{
	  mysql_execute_command(thd);
unknown's avatar
SCRUM  
unknown committed
3357
#ifndef EMBEDDED_LIBRARY  /* TODO query cache in embedded library*/
unknown's avatar
unknown committed
3358
	  query_cache_end_of_result(&thd->net);
3359
#endif
unknown's avatar
unknown committed
3360
	}
3361
      }
unknown's avatar
unknown committed
3362 3363
    }
    else
3364 3365
    {
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
3366
			 thd->is_fatal_error));
unknown's avatar
SCRUM  
unknown committed
3367
#ifndef EMBEDDED_LIBRARY   /* TODO query cache in embedded library*/
unknown's avatar
unknown committed
3368
      query_cache_abort(&thd->net);
3369
#endif
3370
    }
unknown's avatar
unknown committed
3371
    thd->proc_info="freeing items";
3372
    free_items(thd->free_list);  /* Free strings used by items */
unknown's avatar
unknown committed
3373 3374
    lex_end(lex);
  }
unknown's avatar
unknown committed
3375 3376 3377 3378 3379 3380 3381 3382 3383
  DBUG_VOID_RETURN;
}


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

unknown's avatar
unknown committed
3384
bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
unknown's avatar
unknown committed
3385
		       char *length, char *decimals,
3386 3387
		       uint type_modifier,
		       Item *default_value, Item *comment,
3388
		       char *change, TYPELIB *interval, CHARSET_INFO *cs)
unknown's avatar
unknown committed
3389 3390 3391 3392
{
  register create_field *new_field;
  LEX  *lex= &thd->lex;
  uint allowed_type_modifier=0;
3393
  char warn_buff[MYSQL_ERRMSG_SIZE];
unknown's avatar
unknown committed
3394 3395 3396 3397
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
3398
    net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
unknown's avatar
unknown committed
3399 3400 3401 3402 3403
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
3404
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
unknown's avatar
unknown committed
3405 3406 3407 3408 3409 3410
				    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));
3411
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF,
unknown's avatar
unknown committed
3412 3413 3414 3415 3416 3417 3418 3419 3420
				    lex->col_list));
    lex->col_list.empty();
  }

  if (default_value && default_value->type() == Item::NULL_ITEM)
  {
    if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	NOT_NULL_FLAG)
    {
3421
      net_printf(thd,ER_INVALID_DEFAULT,field_name);
unknown's avatar
unknown committed
3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440
      DBUG_RETURN(1);
    }
    default_value=0;
  }
  if (!(new_field=new create_field()))
    DBUG_RETURN(1);
  new_field->field=0;
  new_field->field_name=field_name;
  new_field->def= (type_modifier & AUTO_INCREMENT_FLAG ? 0 : default_value);
  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;
3441
  new_field->charset=cs;
unknown's avatar
unknown committed
3442

3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453
  if (!comment)
  {
    new_field->comment.str=0;
    new_field->comment.length=0;
  }
  else
  {
    /* In this case comment is always of type Item_string */
    new_field->comment.str=   (char*) comment->str_value.ptr();
    new_field->comment.length=comment->str_value.length();
  }
unknown's avatar
unknown committed
3454 3455 3456 3457 3458 3459
  if (length)
    if (!(new_field->length= (uint) atoi(length)))
      length=0; /* purecov: inspected */
  uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;

  if (new_field->length && new_field->decimals &&
3460
      new_field->length < new_field->decimals+1 &&
unknown's avatar
unknown committed
3461
      new_field->decimals != NOT_FIXED_DEC)
3462
    new_field->length=new_field->decimals+1; /* purecov: inspected */
unknown's avatar
unknown committed
3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493

  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)
      new_field->length = 10;			// Default length for DECIMAL
    new_field->length+=sign_len;
    if (new_field->decimals)
      new_field->length++;
    break;
3494 3495 3496 3497 3498 3499 3500
  case FIELD_TYPE_STRING:
  case FIELD_TYPE_VAR_STRING:
    if (new_field->length < MAX_FIELD_WIDTH || default_value)
      break;
    /* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */
    new_field->sql_type= FIELD_TYPE_BLOB;
    sprintf(warn_buff, ER(ER_AUTO_CONVERT), field_name, "CHAR",
unknown's avatar
unknown committed
3501
	    (cs == &my_charset_bin) ? "BLOB" : "TEXT");
3502 3503 3504
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_AUTO_CONVERT,
		 warn_buff);
    /* fall through */
unknown's avatar
unknown committed
3505 3506 3507 3508
  case FIELD_TYPE_BLOB:
  case FIELD_TYPE_TINY_BLOB:
  case FIELD_TYPE_LONG_BLOB:
  case FIELD_TYPE_MEDIUM_BLOB:
unknown's avatar
unknown committed
3509
  case FIELD_TYPE_GEOMETRY:
3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523
    if (new_field->length)
    {
      /* The user has given a length to the blob column */
      if (new_field->length < 256)
	type= FIELD_TYPE_TINY_BLOB;
      if (new_field->length < 65536)
	type= FIELD_TYPE_BLOB;
      else if (new_field->length < 256L*256L*256L)
	type= FIELD_TYPE_MEDIUM_BLOB;
      else
	type= FIELD_TYPE_LONG_BLOB;
      new_field->length= 0;
    }
    new_field->sql_type= type;
unknown's avatar
unknown committed
3524 3525 3526 3527 3528 3529
    if (default_value)				// Allow empty as default value
    {
      String str,*res;
      res=default_value->val_str(&str);
      if (res->length())
      {
3530
	net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
unknown's avatar
unknown committed
3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549
	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)
      {
3550
	net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
unknown's avatar
unknown committed
3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603
	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)
      {
3604
	net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
unknown's avatar
unknown committed
3605 3606 3607 3608 3609 3610 3611 3612
	DBUG_RETURN(1);				/* purecov: inspected */
      }
      new_field->pack_length=(interval->count+7)/8;
      if (new_field->pack_length > 4)
	new_field->pack_length=8;
      new_field->interval=interval;
      new_field->length=0;
      for (const char **pos=interval->type_names; *pos ; pos++)
unknown's avatar
unknown committed
3613 3614 3615
      {
	new_field->length+=(uint) strip_sp((char*) *pos)+1;
      }
unknown's avatar
unknown committed
3616 3617 3618 3619
      new_field->length--;
      set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
      if (default_value)
      {
3620 3621 3622
	char *not_used;
	uint not_used2;

unknown's avatar
unknown committed
3623 3624 3625
	thd->cuted_fields=0;
	String str,*res;
	res=default_value->val_str(&str);
3626 3627
	(void) find_set(interval, res->ptr(), res->length(), &not_used,
			&not_used2);
unknown's avatar
unknown committed
3628 3629
	if (thd->cuted_fields)
	{
3630
	  net_printf(thd,ER_INVALID_DEFAULT,field_name);
unknown's avatar
unknown committed
3631 3632 3633 3634 3635 3636 3637 3638 3639
	  DBUG_RETURN(1);
	}
      }
    }
    break;
  case FIELD_TYPE_ENUM:
    {
      new_field->interval=interval;
      new_field->pack_length=interval->count < 256 ? 1 : 2; // Should be safe
unknown's avatar
unknown committed
3640
      new_field->length=(uint) strip_sp((char*) interval->type_names[0]);
unknown's avatar
unknown committed
3641 3642
      for (const char **pos=interval->type_names+1; *pos ; pos++)
      {
unknown's avatar
unknown committed
3643
	uint length=(uint) strip_sp((char*) *pos);
unknown's avatar
unknown committed
3644 3645 3646 3647 3648 3649 3650 3651 3652
	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);
	if (!find_enum(interval,res->ptr(),res->length()))
	{
3653
	  net_printf(thd,ER_INVALID_DEFAULT,field_name);
unknown's avatar
unknown committed
3654 3655 3656 3657 3658 3659 3660 3661 3662
	  DBUG_RETURN(1);
	}
      }
      break;
    }
  }

  if (new_field->length >= MAX_FIELD_WIDTH ||
      (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
unknown's avatar
SCRUM  
unknown committed
3663 3664
       type != FIELD_TYPE_STRING && 
       type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
unknown's avatar
unknown committed
3665
  {
3666
    net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
unknown's avatar
unknown committed
3667 3668 3669 3670 3671 3672
	       MAX_FIELD_WIDTH-1);		/* purecov: inspected */
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
3673
    net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
unknown's avatar
unknown committed
3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694
    DBUG_RETURN(1);
  }
  if (!new_field->pack_length)
    new_field->pack_length=calc_pack_length(new_field->sql_type ==
					    FIELD_TYPE_VAR_STRING ?
					    FIELD_TYPE_STRING :
					    new_field->sql_type,
					    new_field->length);
  lex->create_list.push_back(new_field);
  lex->last_field=new_field;
  DBUG_RETURN(0);
}

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

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

bool
unknown's avatar
unknown committed
3695
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
3696 3697 3698 3699
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
3700
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
3701 3702 3703 3704 3705
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
unknown's avatar
unknown committed
3706
  thd->lex.proc_list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
3707 3708 3709 3710 3711 3712 3713 3714
  return 0;
}


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

static void remove_escape(char *name)
{
3715 3716
  if (!*name)					// For empty DB names
    return;
unknown's avatar
unknown committed
3717 3718
  char *to;
#ifdef USE_MB
unknown's avatar
unknown committed
3719
  char *strend=name+(uint) strlen(name);
unknown's avatar
unknown committed
3720 3721 3722 3723 3724 3725
#endif
  for (to=name; *name ; name++)
  {
#ifdef USE_MB
    int l;
/*    if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
3726 3727
    if (use_mb(system_charset_info) &&
        (l = my_ismbchar(system_charset_info, name, strend)))
unknown's avatar
unknown committed
3728 3729 3730 3731 3732 3733 3734 3735
    {
	while (l--)
	    *to++ = *name++;
	name--;
	continue;
    }
#endif
    if (*name == '\\' && name[1])
unknown's avatar
unknown committed
3736
      name++;					// Skip '\\'
unknown's avatar
unknown committed
3737 3738 3739 3740 3741 3742 3743 3744 3745 3746
    *to++= *name;
  }
  *to=0;
}

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


unknown's avatar
unknown committed
3747
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
3748 3749 3750 3751
{
  ORDER *order;
  Item	**item_ptr;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
3752
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
3753 3754 3755 3756 3757 3758 3759
    DBUG_RETURN(1);
  item_ptr = (Item**) (order+1);
  *item_ptr=item;
  order->item= item_ptr;
  order->asc = asc;
  order->free_me=0;
  order->used=0;
unknown's avatar
unknown committed
3760
  list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
3761 3762 3763 3764
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783
/*
  Add a table to list of used tables

  SYNOPSIS
    add_table_to_list()
    table		Table to add
    alias		alias for table (or null if no alias)
    table_options	A set of the following bits:
			TL_OPTION_UPDATING	Table will be updated
			TL_OPTION_FORCE_INDEX	Force usage of index
    lock_type		How table should be locked
    use_index		List of indexed used in USE INDEX
    ignore_index	List of indexed used in IGNORE INDEX

    RETURN
      0		Error
      #		Pointer to TABLE_LIST element added to the total table list
*/

unknown's avatar
unknown committed
3784 3785
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
3786
					     LEX_STRING *alias,
unknown's avatar
unknown committed
3787 3788
					     ulong table_options,
					     thr_lock_type lock_type,
3789 3790
					     List<String> *use_index,
					     List<String> *ignore_index)
unknown's avatar
unknown committed
3791 3792 3793 3794 3795 3796 3797 3798
{
  register TABLE_LIST *ptr;
  char *alias_str;
  DBUG_ENTER("add_table_to_list");

  if (!table)
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? alias->str : table->table.str;
unknown's avatar
unknown committed
3799
  if (check_table_name(table->table.str,table->table.length) ||
3800
      table->db.str && check_db_name(table->db.str))
unknown's avatar
unknown committed
3801
  {
3802
    net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str);
unknown's avatar
unknown committed
3803 3804 3805 3806
    DBUG_RETURN(0);
  }

  if (!alias)					/* Alias is case sensitive */
3807 3808 3809 3810 3811 3812
  {
    if (table->sel)
    {
      net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
      DBUG_RETURN(0);
    }
3813
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
3814
      DBUG_RETURN(0);
3815
  }
unknown's avatar
unknown committed
3816
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
3817
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
3818
  if (table->db.str)
3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829
  {
    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
  {
3830 3831
    /* The following can't be "" as we may do 'casedn_str()' on it */
    ptr->db= empty_c_string;
3832 3833
    ptr->db_length= 0;
  }
unknown's avatar
unknown committed
3834

3835
  ptr->alias= alias_str;
3836 3837
  if (lower_case_table_names && table->table.length)
    my_casedn_str(files_charset_info, table->table.str);
unknown's avatar
unknown committed
3838
  ptr->real_name=table->table.str;
3839
  ptr->real_name_length=table->table.length;
3840
  ptr->lock_type=   lock_type;
unknown's avatar
unknown committed
3841 3842
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
3843
  ptr->derived=	    table->sel;
unknown's avatar
unknown committed
3844
  if (use_index)
unknown's avatar
unknown committed
3845
    ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
unknown's avatar
unknown committed
3846 3847
					       sizeof(*use_index));
  if (ignore_index)
unknown's avatar
unknown committed
3848 3849
    ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index,
						   sizeof(*ignore_index));
unknown's avatar
unknown committed
3850 3851

  /* check that used name is unique */
3852
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
3853
  {
3854
    for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
3855
	 tables ;
unknown's avatar
unknown committed
3856
	 tables=tables->next)
unknown's avatar
unknown committed
3857
    {
3858
      if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
3859
      {
3860
	net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
unknown's avatar
unknown committed
3861 3862
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
3863 3864
    }
  }
unknown's avatar
unknown committed
3865
  table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
unknown's avatar
unknown committed
3866 3867 3868
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
3869

unknown's avatar
unknown committed
3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882
/*
  Set lock for all tables in current select level

  SYNOPSIS:
    set_lock_for_tables()
    lock_type			Lock to set for tables

  NOTE:
    If lock is a write lock, then tables->updating is set 1
    This is to get tables_ok to know that the table is updated by the
    query
*/

unknown's avatar
unknown committed
3883
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
3884 3885 3886 3887 3888 3889
{
  bool for_update= lock_type >= TL_READ_NO_INSERT;
  DBUG_ENTER("set_lock_for_tables");
  DBUG_PRINT("enter", ("lock_type: %d  for_update: %d", lock_type,
		       for_update));

unknown's avatar
unknown committed
3890
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
3891 3892 3893 3894 3895 3896 3897 3898 3899
       tables ;
       tables=tables->next)
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
3900

unknown's avatar
unknown committed
3901 3902
void add_join_on(TABLE_LIST *b,Item *expr)
{
3903
  if (expr)
3904
  {
3905 3906 3907 3908 3909 3910 3911 3912
    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();
3913
  }
unknown's avatar
unknown committed
3914 3915 3916 3917 3918 3919 3920 3921
}


void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
{
  b->natural_join=a;
}

3922 3923 3924 3925 3926

/*
  Reload/resets privileges and the different caches
*/

unknown's avatar
unknown committed
3927
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
unknown's avatar
unknown committed
3928 3929
{
  bool result=0;
3930
  bool error_already_sent=0;
unknown's avatar
unknown committed
3931 3932 3933
  select_errors=0;				/* Write if more errors */
  if (options & REFRESH_GRANT)
  {
3934
    acl_reload(thd);
unknown's avatar
unknown committed
3935
    grant_reload(thd);
3936
    if (mqh_used)
3937
      reset_mqh(thd,(LEX_USER *) NULL,true);
unknown's avatar
unknown committed
3938 3939 3940
  }
  if (options & REFRESH_LOG)
  {
unknown's avatar
unknown committed
3941 3942 3943
    mysql_log.new_file(1);
    mysql_update_log.new_file(1);
    mysql_bin_log.new_file(1);
unknown's avatar
unknown committed
3944
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
3945
    if (expire_logs_days)
3946 3947 3948 3949 3950
    {
      long purge_time= time(0) - expire_logs_days*24*60*60;
      if (purge_time >= 0)
	mysql_bin_log.purge_logs_before_date(thd, purge_time);
    }
unknown's avatar
unknown committed
3951
#endif
unknown's avatar
unknown committed
3952
    mysql_slow_log.new_file(1);
unknown's avatar
unknown committed
3953 3954
    if (ha_flush_logs())
      result=1;
unknown's avatar
unknown committed
3955 3956
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
3957
  }
unknown's avatar
unknown committed
3958
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
3959 3960
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
3961
    query_cache.pack();				// FLUSH QUERY CACHE
unknown's avatar
unknown committed
3962 3963 3964 3965
    options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
3966
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
3967
  }
unknown's avatar
unknown committed
3968
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
3969 3970
  if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
  {
3971
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
3972
    {
3973 3974
      if (lock_global_read_lock(thd))
	return 1;
unknown's avatar
unknown committed
3975
    }
unknown's avatar
unknown committed
3976
    result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
unknown's avatar
unknown committed
3977 3978 3979 3980 3981 3982 3983
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
  if (options & REFRESH_STATUS)
    refresh_status();
  if (options & REFRESH_THREADS)
    flush_thread_cache();
3984
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
3985
  if (options & REFRESH_MASTER)
3986 3987
    if (reset_master(thd))
      result=1;
3988
#endif
unknown's avatar
unknown committed
3989
#ifdef OPENSSL
3990 3991 3992 3993 3994 3995
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
3996
#ifndef EMBEDDED_LIBRARY
3997 3998 3999
 if (options & REFRESH_SLAVE)
 {
   LOCK_ACTIVE_MI;
4000
   if (reset_slave(thd, active_mi))
4001
   {
4002
     result=1;
4003 4004 4005 4006 4007 4008 4009 4010
     /*
       reset_slave() sends error itself.
       If it didn't, one would either change reset_slave()'s prototype, to
       pass *errorcode and *errmsg to it when it's called or
       change reset_slave to use my_error() to register the error.
     */
     error_already_sent=1;
   }
4011 4012
   UNLOCK_ACTIVE_MI;
 }
4013
#endif
4014
 if (options & REFRESH_USER_RESOURCES)
4015
   reset_mqh(thd,(LEX_USER *) NULL);
4016 4017 4018 4019

 if (thd && !error_already_sent)
 {
   if (result)
4020
     send_error(thd,0);
4021
   else
4022
     send_ok(thd);
4023 4024
 }

4025
 return result;
unknown's avatar
unknown committed
4026 4027 4028
}


4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040
/*
  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
*/

4041
void kill_one_thread(THD *thd, ulong id)
unknown's avatar
unknown committed
4042 4043 4044
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
4045 4046
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
4047 4048 4049 4050
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
4051 4052
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
4053 4054 4055
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068
  if (tmp)
  {
    if ((thd->master_access & SUPER_ACL) ||
	!strcmp(thd->user,tmp->user))
    {
      tmp->awake(1 /*prepare to die*/);
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }

unknown's avatar
unknown committed
4069
  if (!error)
4070
    send_ok(thd);
unknown's avatar
unknown committed
4071
  else
4072
    net_printf(thd,error,id);
unknown's avatar
unknown committed
4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088
}

/* Clear most status variables */

static void refresh_status(void)
{
  pthread_mutex_lock(&THR_LOCK_keycache);
  pthread_mutex_lock(&LOCK_status);
  for (struct show_var_st *ptr=status_vars; ptr->name; ptr++)
  {
    if (ptr->type == SHOW_LONG)
      *(ulong*) ptr->value=0;
  }
  pthread_mutex_unlock(&LOCK_status);
  pthread_mutex_unlock(&THR_LOCK_keycache);
}
4089 4090 4091 4092


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

unknown's avatar
unknown committed
4093
static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
4094
{
4095
  char buff[FN_REFLEN],*ptr, *end;
4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107
  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))
  {
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
4108
  end=convert_dirname(buff, *filename_ptr, NullS);
unknown's avatar
unknown committed
4109
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
4110 4111
    return 1;					// End of memory
  *filename_ptr=ptr;
4112
  strxmov(ptr,buff,table_name,NullS);
4113 4114
  return 0;
}
4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129

/*
  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;
4130
  if (thd->lex.current_select != &thd->lex.select_lex)
4131 4132 4133 4134
  {
    char command[80];
    strmake(command, thd->lex.yylval->symbol.str,
	    min(thd->lex.yylval->symbol.length, sizeof(command)-1));
4135
    net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
4136 4137 4138 4139
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169

compare_func_creator comp_eq_creator(bool invert)
{
  return invert?&Item_bool_func2::ne_creator:&Item_bool_func2::eq_creator;
}

compare_func_creator comp_ge_creator(bool invert)
{
  return invert?&Item_bool_func2::lt_creator:&Item_bool_func2::ge_creator;
}

compare_func_creator comp_gt_creator(bool invert)
{
  return invert?&Item_bool_func2::le_creator:&Item_bool_func2::gt_creator;
}

compare_func_creator comp_le_creator(bool invert)
{
  return invert?&Item_bool_func2::gt_creator:&Item_bool_func2::le_creator;
}

compare_func_creator comp_lt_creator(bool invert)
{
  return invert?&Item_bool_func2::ge_creator:&Item_bool_func2::lt_creator;
}

compare_func_creator comp_ne_creator(bool invert)
{
  return invert?&Item_bool_func2::eq_creator:&Item_bool_func2::ne_creator;
}