sql_parse.cc 112 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
#include <m_ctype.h>
#include <myisam.h>
#include <my_dir.h>
unknown's avatar
unknown committed
24
#include <assert.h>
unknown's avatar
unknown committed
25

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

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

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

55 56
static int check_for_max_user_connections(USER_CONN *uc);
static void decrease_user_connections(USER_CONN *uc);
unknown's avatar
unknown committed
57
static bool check_db_used(THD *thd,TABLE_LIST *tables);
58
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
unknown's avatar
unknown committed
59 60 61
static void mysql_init_query(THD *thd);
static void remove_escape(char *name);
static void refresh_status(void);
unknown's avatar
unknown committed
62 63
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
			       const char *table_name);
64 65
static bool create_total_list(THD *thd, LEX *lex,
			      TABLE_LIST **result, bool skip_first);
66 67
static bool check_one_table_access(THD *thd, ulong want_access,
				   TABLE_LIST *table, bool no_errors);
68

unknown's avatar
unknown committed
69

70
const char *any_db="*any*";	// Special symbol for check_access
unknown's avatar
unknown committed
71 72 73 74 75

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",
76 77
  "Binlog Dump","Table Dump",  "Connect Out", "Register Slave",
  "Error"					// Last command number
unknown's avatar
unknown committed
78 79 80 81 82 83 84
};

bool volatile abort_slave = 0;

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

unknown's avatar
unknown committed
101 102 103 104 105 106 107 108 109 110
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
  }
}

111

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


127 128 129 130 131 132 133 134
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
{
  return (table_rules_on && tables && !tables_ok(thd,tables) &&
          ((thd->lex.sql_command != SQLCOM_DELETE_MULTI) ||
           !tables_ok(thd,(TABLE_LIST *)thd->lex.auxilliary_table_list.first)));
}


135 136 137
static HASH hash_user_connections;
extern  pthread_mutex_t LOCK_user_conn;

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

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

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


/*
unknown's avatar
unknown committed
195 196
  Check if user is ok
  Updates:
197
  thd->{user,master_access,priv_user,priv_host,db,db_access}
unknown's avatar
unknown committed
198 199 200 201 202 203 204
*/

static bool check_user(THD *thd,enum_server_command command, const char *user,
		       const char *passwd, const char *db, bool check_count)
{
  NET *net= &thd->net;
  thd->db=0;
unknown's avatar
unknown committed
205
  thd->db_length=0;
206
  USER_RESOURCES ur;
unknown's avatar
unknown committed
207
  char tmp_passwd[SCRAMBLE_LENGTH + 1];
unknown's avatar
unknown committed
208

209 210
  if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH)
    return 1;
211 212 213 214 215 216 217
  /*
    Move password to temporary buffer as it may be stored in communication
    buffer
  */
  strmov(tmp_passwd, passwd);
  passwd= tmp_passwd;				// Use local copy

unknown's avatar
unknown committed
218 219 220 221 222
  if (!(thd->user = my_strdup(user, MYF(0))))
  {
    send_error(net,ER_OUT_OF_RESOURCES);
    return 1;
  }
223
  thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
224
				 passwd, thd->scramble,
225
                                 &thd->priv_user, thd->priv_host,
unknown's avatar
unknown committed
226 227
				 protocol_version == 9 ||
				 !(thd->client_capabilities &
228
				   CLIENT_LONG_PASSWORD),&ur);
unknown's avatar
unknown committed
229
  DBUG_PRINT("info",
230
	     ("Capabilities: %d  packet_length: %ld  Host: '%s'  Login user: '%s'  Priv_user: '%s'  Using password: %s  Access: %u  db: '%s'",
unknown's avatar
unknown committed
231
	      thd->client_capabilities, thd->max_client_packet_length,
232
	      thd->host_or_ip, thd->user, thd->priv_user,
unknown's avatar
unknown committed
233 234 235 236 237 238
	      passwd[0] ? "yes": "no",
	      thd->master_access, thd->db ? thd->db : "*none*"));
  if (thd->master_access & NO_ACCESS)
  {
    net_printf(net, ER_ACCESS_DENIED_ERROR,
	       thd->user,
239
	       thd->host_or_ip,
unknown's avatar
unknown committed
240
	       passwd[0] ? ER(ER_YES) : ER(ER_NO));
241
    mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
unknown's avatar
unknown committed
242
		    thd->user,
243
		    thd->host_or_ip,
unknown's avatar
unknown committed
244 245 246 247 248 249 250
		    passwd[0] ? ER(ER_YES) : ER(ER_NO));
    return(1);					// Error already given
  }
  if (check_count)
  {
    VOID(pthread_mutex_lock(&LOCK_thread_count));
    bool tmp=(thread_count - delayed_insert_threads >= max_connections &&
unknown's avatar
unknown committed
251
	      !(thd->master_access & SUPER_ACL));
unknown's avatar
unknown committed
252 253 254 255 256 257 258
    VOID(pthread_mutex_unlock(&LOCK_thread_count));
    if (tmp)
    {						// Too many connections
      send_error(net, ER_CON_COUNT_ERROR);
      return(1);
    }
  }
259
  mysql_log.write(thd,command,
unknown's avatar
unknown committed
260 261 262 263
		  (thd->priv_user == thd->user ?
		   (char*) "%s@%s on %s" :
		   (char*) "%s@%s as anonymous on %s"),
		  user,
264
		  thd->host_or_ip,
unknown's avatar
unknown committed
265 266
		  db ? db : (char*) "");
  thd->db_access=0;
unknown's avatar
unknown committed
267
  /* Don't allow user to connect if he has done too many queries */
unknown's avatar
unknown committed
268
  if ((ur.questions || ur.updates || ur.connections || max_user_connections) &&
269
      get_or_create_user_conn(thd,user,thd->host_or_ip,&ur))
unknown's avatar
unknown committed
270
    return -1;
271 272
  if (thd->user_connect && (thd->user_connect->user_resources.connections ||
			    max_user_connections) &&
273
      check_for_max_user_connections(thd->user_connect))
unknown's avatar
unknown committed
274
    return -1;
unknown's avatar
unknown committed
275
  if (db && db[0])
unknown's avatar
unknown committed
276 277
  {
    bool error=test(mysql_change_db(thd,db));
278 279
    if (error && thd->user_connect)
      decrease_user_connections(thd->user_connect);
unknown's avatar
unknown committed
280 281
    return error;
  }
282
  send_ok(net);                                 // Ready to handle questions
283
  thd->password= test(passwd[0]);		// Remember for error messages
unknown's avatar
unknown committed
284 285 286
  return 0;					// ok
}

287

unknown's avatar
unknown committed
288
/*
unknown's avatar
unknown committed
289 290
  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
291 292
*/

293 294
extern "C" byte *get_key_conn(user_conn *buff, uint *length,
			      my_bool not_used __attribute__((unused)))
unknown's avatar
unknown committed
295 296 297 298 299
{
  *length=buff->len;
  return (byte*) buff->user;
}

300
extern "C" void free_user(struct user_conn *uc)
unknown's avatar
unknown committed
301 302 303 304
{
  my_free((char*) uc,MYF(0));
}

unknown's avatar
unknown committed
305 306
void init_max_user_conn(void) 
{
unknown's avatar
unknown committed
307
  (void) hash_init(&hash_user_connections,max_connections,0,0,
308
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
309
		   0);
unknown's avatar
unknown committed
310 311 312
}


313
static int check_for_max_user_connections(USER_CONN *uc)
unknown's avatar
unknown committed
314
{
315
  int error=0;
316
  DBUG_ENTER("check_for_max_user_connections");
317

318
  (void) pthread_mutex_lock(&LOCK_user_conn);
319
  if (max_user_connections &&
320
      max_user_connections < uc->connections)
unknown's avatar
unknown committed
321
  {
322 323 324
    net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, uc->user);
    error=1;
    goto end;
unknown's avatar
unknown committed
325
  }
326
  if (uc->user_resources.connections &&
327
      uc->user_resources.connections <= uc->conn_per_hour)
328
  {
329 330
    net_printf(&current_thd->net, ER_USER_LIMIT_REACHED, uc->user,
	       "max_connections",
331 332 333 334
	       (long) uc->user_resources.connections);
    error=1;
    goto end;
  }
335
  uc->conn_per_hour++;
336
end:
337 338
  if (error)
    uc->connections--; // no need for decrease_user_connections() here
339
  (void) pthread_mutex_unlock(&LOCK_user_conn);
340
  DBUG_RETURN(error);
unknown's avatar
unknown committed
341 342 343
}


344
static void decrease_user_connections(USER_CONN *uc)
unknown's avatar
unknown committed
345
{
346
  DBUG_ENTER("decrease_user_connections");
347 348 349
  (void) pthread_mutex_lock(&LOCK_user_conn);
  DBUG_ASSERT(uc->connections);
  if (!--uc->connections && !mqh_used)
unknown's avatar
unknown committed
350 351
  {
    /* Last connection for user; Delete it */
unknown's avatar
unknown committed
352
    (void) hash_delete(&hash_user_connections,(byte*) uc);
unknown's avatar
unknown committed
353
  }
354
  (void) pthread_mutex_unlock(&LOCK_user_conn);
355
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
356 357
}

358

unknown's avatar
unknown committed
359 360 361 362 363
void free_max_user_conn(void)
{
  hash_free(&hash_user_connections);
}

unknown's avatar
unknown committed
364

365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
/*
  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;
  uc_update_queries[SQLCOM_MULTI_UPDATE]=1;
}


unknown's avatar
unknown committed
397 398 399
/*
  Check if maximum queries per hour limit has been reached
  returns 0 if OK.
unknown's avatar
unknown committed
400

401 402 403
  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
404 405
*/

406

407
static bool check_mqh(THD *thd, uint check_command)
unknown's avatar
unknown committed
408 409
{
  bool error=0;
unknown's avatar
unknown committed
410
  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
411
  USER_CONN *uc=thd->user_connect;
unknown's avatar
unknown committed
412
  DBUG_ENTER("check_mqh");
413
  DBUG_ASSERT(uc != 0);
unknown's avatar
unknown committed
414

unknown's avatar
unknown committed
415
  /* If more than a hour since last check, reset resource checking */
416 417 418 419 420 421 422 423 424
  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
425
  /* Check that we have not done too many questions / hour */
426 427 428 429 430 431 432 433
  if (uc->user_resources.questions &&
      uc->questions++ >= uc->user_resources.questions)
  {
    net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
	       (long) uc->user_resources.questions);
    error=1;
    goto end;
  }
434
  if (check_command < (uint) SQLCOM_END)
unknown's avatar
unknown committed
435
  {
unknown's avatar
unknown committed
436 437 438 439 440 441 442 443 444
    /* 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)
    {
      net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
		 (long) uc->user_resources.updates);
      error=1;
      goto end;
    }
unknown's avatar
unknown committed
445 446
  }
end:
447
  DBUG_RETURN(error);
unknown's avatar
unknown committed
448 449
}

unknown's avatar
unknown committed
450

unknown's avatar
unknown committed
451
static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
452 453
{

unknown's avatar
unknown committed
454
  (void) pthread_mutex_lock(&LOCK_user_conn);
455 456
  if (lu)  // for GRANT 
  {
457
    USER_CONN *uc;
458
    uint temp_len=lu->user.length+lu->host.length+2;
459 460
    char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];

unknown's avatar
unknown committed
461 462
    memcpy(temp_user,lu->user.str,lu->user.length);
    memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
463
    temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
unknown's avatar
unknown committed
464
    if ((uc = (struct  user_conn *) hash_search(&hash_user_connections,
465
						(byte*) temp_user, temp_len)))
466 467
    {
      uc->questions=0;
468
      get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
469 470
      uc->updates=0;
      uc->conn_per_hour=0;
471 472
    }
  }
473
  else // for FLUSH PRIVILEGES and FLUSH USER_RESOURCES
474
  {
unknown's avatar
unknown committed
475
    for (uint idx=0;idx < hash_user_connections.records; idx++)
476
    {
477 478 479 480 481 482
      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;
483 484
    }
  }
unknown's avatar
unknown committed
485
  (void) pthread_mutex_unlock(&LOCK_user_conn);
486
}
unknown's avatar
unknown committed
487

unknown's avatar
unknown committed
488

unknown's avatar
unknown committed
489
/*
unknown's avatar
unknown committed
490 491
  Check connnetion and get priviliges
  Returns 0 on ok, -1 < if error is given > 0 on error.
unknown's avatar
unknown committed
492 493 494 495 496 497 498
*/

static int
check_connections(THD *thd)
{
  uint connect_errors=0;
  NET *net= &thd->net;
unknown's avatar
unknown committed
499
  /* Store the connection details */
unknown's avatar
unknown committed
500 501
  DBUG_PRINT("info", (("check_connections called by thread %d"),
	     thd->thread_id));
unknown's avatar
unknown committed
502
  DBUG_PRINT("info",("New connection received on %s",
unknown's avatar
unknown committed
503 504 505
			vio_description(net->vio)));
  if (!thd->host)                           // If TCP/IP connection
  {
506
    char ip[30];
507

508
    if (vio_peer_addr(net->vio, ip, &thd->peer_port))
unknown's avatar
unknown committed
509 510 511
      return (ER_BAD_HOST_ERROR);
    if (!(thd->ip = my_strdup(ip,MYF(0))))
      return (ER_OUT_OF_RESOURCES);
512
    thd->host_or_ip=thd->ip;
unknown's avatar
unknown committed
513 514 515
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
    /* Fast local hostname resolve for Win32 */
    if (!strcmp(thd->ip,"127.0.0.1"))
unknown's avatar
unknown committed
516 517 518 519
    {
      thd->host= (char*) localhost;
      thd->host_or_ip= localhost;
    }
unknown's avatar
unknown committed
520 521 522 523 524 525
    else
#endif
    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);
unknown's avatar
unknown committed
526
      /* Cut very long hostnames to avoid possible overflows */
527
      if (thd->host)
528
      {
529
	thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
530 531
	thd->host_or_ip= thd->host;
      }
unknown's avatar
unknown committed
532 533 534
      if (connect_errors > max_connect_errors)
	return(ER_HOST_IS_BLOCKED);
    }
unknown's avatar
unknown committed
535 536 537
    DBUG_PRINT("info",("Host: %s  ip: %s",
		       thd->host ? thd->host : "unknown host",
		       thd->ip ? thd->ip : "unknown ip"));
unknown's avatar
unknown committed
538 539 540
    if (acl_check_host(thd->host,thd->ip))
      return(ER_HOST_NOT_PRIVILEGED);
  }
541
  else /* Hostname given means that the connection was on a socket */
unknown's avatar
unknown committed
542
  {
unknown's avatar
unknown committed
543
    DBUG_PRINT("info",("Host: %s",thd->host));
544 545
    thd->host_or_ip= thd->host;
    thd->ip= 0;
unknown's avatar
unknown committed
546 547 548 549
    bzero((char*) &thd->remote,sizeof(struct sockaddr));
  }
  vio_keepalive(net->vio, TRUE);

unknown's avatar
unknown committed
550
  ulong pkt_len=0;
unknown's avatar
unknown committed
551
  {
unknown's avatar
unknown committed
552 553
    /* buff[] needs to big enough to hold the server_version variable */
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+32],*end;
554
    int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB;
unknown's avatar
unknown committed
555

556 557 558 559 560
    if (opt_using_transactions)
      client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
    client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
unknown's avatar
unknown committed
561 562 563 564
#ifdef HAVE_OPENSSL
    if (ssl_acceptor_fd)
      client_flags |= CLIENT_SSL;       /* Wow, SSL is avalaible! */
#endif /* HAVE_OPENSSL */
unknown's avatar
unknown committed
565

unknown's avatar
unknown committed
566
    end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1;
unknown's avatar
unknown committed
567 568 569 570 571
    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
572
    end[2]=(char) MY_CHARSET_CURRENT;
unknown's avatar
unknown committed
573 574 575
    int2store(end+3,thd->server_status);
    bzero(end+5,13);
    end+=18;
unknown's avatar
unknown committed
576
    if (net_write_command(net,(uchar) protocol_version, buff,
unknown's avatar
unknown committed
577
			  (uint) (end-buff)) ||
unknown's avatar
unknown committed
578
       (pkt_len= my_net_read(net)) == packet_error ||
unknown's avatar
unknown committed
579 580 581 582 583 584 585 586 587 588 589
	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
590
  if (thd->packet.alloc(thd->variables.net_buffer_length))
unknown's avatar
unknown committed
591 592 593
    return(ER_OUT_OF_RESOURCES);

  thd->client_capabilities=uint2korr(net->read_pos);
594 595
  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
    thd->sql_mode|= MODE_IGNORE_SPACE;
unknown's avatar
unknown committed
596
#ifdef HAVE_OPENSSL
unknown's avatar
unknown committed
597
  DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
unknown's avatar
unknown committed
598 599 600
  if (thd->client_capabilities & CLIENT_SSL)
  {
    /* Do the SSL layering. */
601 602 603 604 605
    if (!ssl_acceptor_fd)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
unknown's avatar
unknown committed
606
    DBUG_PRINT("info", ("IO layer change in progress..."));
unknown's avatar
unknown committed
607 608 609 610 611 612 613
    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);
      return(ER_HANDSHAKE_ERROR);    
    }
unknown's avatar
unknown committed
614 615 616 617
    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
618 619
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
unknown's avatar
unknown committed
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
  }
  else
  {
    DBUG_PRINT("info", ("Leaving IO layer intact"));
    if (pkt_len < NORMAL_HANDSHAKE_SIZE)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return ER_HANDSHAKE_ERROR;
    }
  }
#endif

unknown's avatar
unknown committed
635
  thd->max_client_packet_length=uint3korr(net->read_pos+2);
unknown's avatar
unknown committed
636 637 638 639 640 641
  char *user=   (char*) net->read_pos+5;
  char *passwd= strend(user)+1;
  char *db=0;
  if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
    db=strend(passwd)+1;
  if (thd->client_capabilities & CLIENT_INTERACTIVE)
unknown's avatar
unknown committed
642
    thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
643 644
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
      opt_using_transactions)
unknown's avatar
unknown committed
645
    thd->net.return_status= &thd->server_status;
unknown's avatar
unknown committed
646
  net->read_timeout=(uint) thd->variables.net_read_timeout;
unknown's avatar
unknown committed
647 648 649 650 651 652 653 654 655 656
  if (check_user(thd,COM_CONNECT, user, passwd, db, 1))
    return (-1);
  return 0;
}


pthread_handler_decl(handle_one_connection,arg)
{
  THD *thd=(THD*) arg;
  uint launch_time  =
unknown's avatar
unknown committed
657
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
unknown's avatar
unknown committed
658 659 660 661 662
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status );

  pthread_detach_this_thread();

663 664
#if !defined( __WIN__) && !defined(OS2)	// Win32 calls this in pthread_create
  // The following calls needs to be done before we call DBUG_ macros
665
  if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
unknown's avatar
unknown committed
666 667
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
668
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
669 670 671 672 673
    end_thread(thd,0);
    return 0;
  }
#endif

674 675 676 677 678 679 680
  /*
    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
681 682 683 684
  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
685
#if defined(__WIN__)
unknown's avatar
unknown committed
686
  init_signals();				// IRENA; testing ?
unknown's avatar
unknown committed
687
#elif !defined(OS2) && !defined(__NETWARE__)
unknown's avatar
unknown committed
688 689 690 691 692 693 694
  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);
695
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
696 697 698 699 700 701 702 703 704 705 706 707 708
    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)
709
	net_printf(net,error,thd->host_or_ip);
unknown's avatar
unknown committed
710 711 712 713
#ifdef __NT__
      if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
	sleep(1);				/* must wait after eof() */
#endif
714
      statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
715 716
      goto end_thread;
    }
unknown's avatar
unknown committed
717 718 719
#ifdef __NETWARE__
    netware_reg_user(thd->ip, thd->user, "MySQL");
#endif
720
    if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
721 722 723 724
      thd->options |= OPTION_BIG_SELECTS;
    if (thd->client_capabilities & CLIENT_COMPRESS)
      net->compress=1;				// Use compression

unknown's avatar
unknown committed
725
    thd->proc_info=0;				// Remove 'login'
726
    thd->command=COM_SLEEP;
unknown's avatar
unknown committed
727 728
    thd->version=refresh_version;
    thd->set_time();
729 730
    init_sql_alloc(&thd->mem_root, thd->variables.query_alloc_block_size,
		   thd->variables.query_prealloc_size);
731
    init_sql_alloc(&thd->transaction.mem_root,
732 733 734
		   thd->variables.trans_alloc_block_size,
		   thd->variables.trans_prealloc_size);

unknown's avatar
unknown committed
735 736 737 738 739
    while (!net->error && net->vio != 0 && !thd->killed)
    {
      if (do_command(thd))
	break;
    }
740 741
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
742
    free_root(&thd->mem_root,MYF(0));
unknown's avatar
unknown committed
743 744
    if (net->error && net->vio != 0)
    {
745
      if (!thd->killed && thd->variables.log_warnings > 1)
746 747 748 749 750 751
	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)));
unknown's avatar
unknown committed
752
      send_error(net,net->last_errno,NullS);
unknown's avatar
unknown committed
753
      statistic_increment(aborted_threads,&LOCK_status);
unknown's avatar
unknown committed
754
    }
755 756 757 758
    else if (thd->killed)
    {
      statistic_increment(aborted_threads,&LOCK_status);
    }
759
    
unknown's avatar
unknown committed
760 761 762 763 764 765 766 767 768 769 770 771 772
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 */
}

773 774 775 776
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
unknown's avatar
unknown committed
777

778
extern "C" pthread_handler_decl(handle_bootstrap,arg)
unknown's avatar
unknown committed
779
{
780 781 782
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
unknown's avatar
unknown committed
783

784
  /* The following must be called before DBUG_ENTER */
785
  if (my_thread_init() || thd->store_globals())
unknown's avatar
unknown committed
786 787
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
788 789
    thd->fatal_error=1;
    goto end;
unknown's avatar
unknown committed
790
  }
791 792 793 794
  DBUG_ENTER("handle_bootstrap");

  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
795
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
unknown's avatar
unknown committed
796
  sigset_t set;
797 798
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
unknown's avatar
unknown committed
799 800
#endif

801
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
802 803 804 805
    thd->options |= OPTION_BIG_SELECTS;

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

808
  buff= (char*) thd->net.buff;
809 810
  init_sql_alloc(&thd->mem_root, thd->variables.query_alloc_block_size,
		 thd->variables.query_prealloc_size);
811
  init_sql_alloc(&thd->transaction.mem_root,
812 813
		 thd->variables.trans_alloc_block_size,
		 thd->variables.trans_prealloc_size);
unknown's avatar
unknown committed
814 815
  while (fgets(buff, thd->net.max_packet, file))
  {
unknown's avatar
unknown committed
816
    uint length=(uint) strlen(buff);
unknown's avatar
unknown committed
817 818 819 820
    while (length && (isspace(buff[length-1]) || buff[length-1] == ';'))
      length--;
    buff[length]=0;
    thd->current_tablenr=0;
821
    thd->query_length=length;
unknown's avatar
unknown committed
822 823
    thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
    thd->query[length] = '\0';
unknown's avatar
unknown committed
824
    thd->query_id=query_id++;
825
    if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
826 827 828 829 830 831
    {
      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
832 833 834
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
    if (thd->fatal_error)
835
      break;
836
    free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
837
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
838
  }
839 840 841 842 843 844

  /* 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);
845
  (void) pthread_cond_broadcast(&COND_thread_count);
846 847 848
  my_thread_end();
  pthread_exit(0);
  DBUG_RETURN(0);				// Never reached
unknown's avatar
unknown committed
849 850 851
}


unknown's avatar
unknown committed
852
inline void free_items(THD *thd)
unknown's avatar
unknown committed
853 854 855 856 857 858 859 860 861 862 863 864 865
{
    /* This works because items are allocated with sql_alloc() */
  for (Item *item=thd->free_list ; item ; item=item->next)
    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;
866
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
867
    DBUG_RETURN(1); // out of memory
unknown's avatar
unknown committed
868
  table_list->db = db;
869
  table_list->real_name = table_list->alias = tbl_name;
unknown's avatar
unknown committed
870 871 872
  table_list->lock_type = TL_READ_NO_INSERT;
  table_list->next = 0;

873 874 875 876 877
  if (!db || check_db_name(db))
  {
    net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
    goto err;
  }
878 879 880 881 882 883 884
  if (lower_case_table_names)
    casedn_str(tbl_name);
  remove_escape(tbl_name);

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

885
  if (check_one_table_access(thd, SELECT_ACL, table_list, 0))
unknown's avatar
unknown committed
886 887
    goto err;
  thd->free_list = 0;
unknown's avatar
unknown committed
888
  thd->query_length=(uint) strlen(tbl_name);
unknown's avatar
unknown committed
889
  thd->query = tbl_name;
890 891 892 893 894
  if ((error = mysqld_dump_create_info(thd, table, -1)))
  {
    my_error(ER_GET_ERRNO, MYF(0));
    goto err;
  }
unknown's avatar
unknown committed
895
  net_flush(&thd->net);
896
  if ((error= table->file->dump(thd,fd)))
897
    my_error(ER_GET_ERRNO, MYF(0));
unknown's avatar
unknown committed
898

unknown's avatar
unknown committed
899 900
err:
  close_thread_tables(thd);
unknown's avatar
unknown committed
901
  DBUG_RETURN(error);
unknown's avatar
unknown committed
902 903 904 905 906 907 908 909
}


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

bool do_command(THD *thd)
{
  char *packet;
unknown's avatar
unknown committed
910 911
  uint old_timeout;
  ulong packet_length;
unknown's avatar
unknown committed
912 913 914 915 916 917 918 919
  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
920 921 922
  old_timeout=net->read_timeout;
  // Wait max for 8 hours
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
unknown's avatar
unknown committed
923 924 925 926 927 928
  net->last_error[0]=0;				// Clear error message
  net->last_errno=0;

  net_new_transaction(net);
  if ((packet_length=my_net_read(net)) == packet_error)
  {
929 930 931 932 933
    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)
934 935
    {
      statistic_increment(aborted_threads,&LOCK_status);
936
      DBUG_RETURN(TRUE);			// We have to close it.
937
    }
938
    send_error(net,net->last_errno,NullS);
939
    net->error= 0;
940 941
    DBUG_RETURN(FALSE);
  }
unknown's avatar
unknown committed
942 943 944 945
  else
  {
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
946 947
    if (command >= COM_END)
      command= COM_END;				// Wrong command
unknown's avatar
unknown committed
948 949 950
    DBUG_PRINT("info",("Command on %s = %d (%s)",
		       vio_description(net->vio), command,
		       command_name[command]));
unknown's avatar
unknown committed
951
  }
unknown's avatar
unknown committed
952
  net->read_timeout=old_timeout;		// restore it
unknown's avatar
unknown committed
953
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
954 955 956 957 958 959 960 961
}


bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
  bool	error=0;
unknown's avatar
unknown committed
962 963 964 965
  /*
    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
  */
966 967 968
  bool slow_command=FALSE;
  DBUG_ENTER("dispatch_command");

unknown's avatar
unknown committed
969
  thd->command=command;
unknown's avatar
unknown committed
970
  thd->set_time();
unknown's avatar
unknown committed
971 972 973 974 975 976
  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
977

978
  thd->lex.select_lex.options=0;		// We store status here
979
  switch (command) {
unknown's avatar
unknown committed
980
  case COM_INIT_DB:
unknown's avatar
unknown committed
981
    statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
982
    if (!mysql_change_db(thd,packet))
983
      mysql_log.write(thd,command,"%s",thd->db);
unknown's avatar
unknown committed
984
    break;
985 986
  case COM_REGISTER_SLAVE:
  {
987
    if (!register_slave(thd, (uchar*)packet, packet_length))
988 989 990
      send_ok(&thd->net);
    break;
  }
unknown's avatar
unknown committed
991 992
  case COM_TABLE_DUMP:
    {
unknown's avatar
unknown committed
993
      statistic_increment(com_other, &LOCK_status);
994
      slow_command = TRUE;
995 996
      uint db_len = *(uchar*)packet;
      uint tbl_len = *(uchar*)(packet + db_len + 1);
997
      char* db = thd->alloc(db_len + tbl_len + 2);
998
      memcpy(db, packet + 1, db_len);
unknown's avatar
unknown committed
999 1000
      char* tbl_name = db + db_len;
      *tbl_name++ = 0;
1001
      memcpy(tbl_name, packet + db_len + 2, tbl_len);
unknown's avatar
unknown committed
1002
      tbl_name[tbl_len] = 0;
unknown's avatar
unknown committed
1003
      if (mysql_table_dump(thd, db, tbl_name, -1))
unknown's avatar
unknown committed
1004 1005 1006 1007 1008
	send_error(&thd->net); // dump to NET
      break;
    }
  case COM_CHANGE_USER:
  {
unknown's avatar
unknown committed
1009 1010 1011 1012
    thd->change_user();
    clear_error_message(thd);			// If errors from rollback

    statistic_increment(com_other,&LOCK_status);
1013
    char *user=   (char*) packet;
unknown's avatar
unknown committed
1014 1015 1016 1017 1018 1019
    char *passwd= strend(user)+1;
    char *db=     strend(passwd)+1;

    /* Save user and privileges */
    uint save_master_access=thd->master_access;
    uint save_db_access=    thd->db_access;
unknown's avatar
unknown committed
1020
    uint save_db_length=    thd->db_length;
unknown's avatar
unknown committed
1021 1022 1023
    char *save_user=	    thd->user;
    char *save_priv_user=   thd->priv_user;
    char *save_db=	    thd->db;
unknown's avatar
unknown committed
1024
    USER_CONN *save_user_connect= thd->user_connect;
unknown's avatar
unknown committed
1025 1026 1027 1028 1029 1030

    if ((uint) ((uchar*) db - net->read_pos) > packet_length)
    {						// Check if protocol is ok
      send_error(net, ER_UNKNOWN_COM_ERROR);
      break;
    }
unknown's avatar
unknown committed
1031 1032 1033 1034

    /* Clear variables that are allocated */
    thd->user= 0;
    thd->user_connect= 0;
unknown's avatar
unknown committed
1035
    if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0))
unknown's avatar
unknown committed
1036 1037 1038 1039 1040
    {						// Restore old user
      x_free(thd->user);
      thd->master_access=save_master_access;
      thd->db_access=save_db_access;
      thd->db=save_db;
unknown's avatar
unknown committed
1041
      thd->db_length=save_db_length;
unknown's avatar
unknown committed
1042 1043
      thd->user=save_user;
      thd->priv_user=save_priv_user;
unknown's avatar
unknown committed
1044
      thd->user_connect= save_user_connect;
unknown's avatar
unknown committed
1045 1046
      break;
    }
unknown's avatar
unknown committed
1047 1048
    if (save_user_connect)
      decrease_user_connections(save_user_connect);
unknown's avatar
unknown committed
1049 1050 1051 1052 1053 1054 1055
    x_free((gptr) save_db);
    x_free((gptr) save_user);
    break;
  }

  case COM_QUERY:
  {
1056 1057 1058 1059 1060 1061 1062 1063
    packet_length--;				// Remove end null
    /* Remove garage at start and end of query */
    while (isspace(packet[0]) && packet_length > 0)
    {
      packet++;
      packet_length--;
    }
    char *pos=packet+packet_length;		// Point at end null
1064
    while (packet_length > 0 && (pos[-1] == ';' || isspace(pos[-1])))
unknown's avatar
unknown committed
1065 1066 1067 1068
    {
      pos--;
      packet_length--;
    }
1069
    /* We must allocate some extra memory for query cache */
1070
    thd->query_length= 0;                       // Extra safety: Avoid races
unknown's avatar
unknown committed
1071
    if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
1072
						packet_length,
1073 1074
						thd->db_length+2+
						sizeof(ha_rows))))
unknown's avatar
unknown committed
1075
      break;
unknown's avatar
unknown committed
1076
    thd->query[packet_length]=0;
unknown's avatar
unknown committed
1077
    thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory
unknown's avatar
unknown committed
1078 1079
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),QUERY_PRIOR);
1080
    mysql_log.write(thd,command,"%s",thd->query);
1081
    DBUG_PRINT("query",("%-.4096s",thd->query));
1082 1083
    /* thd->query_length is set by mysql_parse() */
    mysql_parse(thd,thd->query,packet_length);
unknown's avatar
unknown committed
1084 1085 1086 1087 1088
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1089
  case COM_FIELD_LIST:				// This isn't actually needed
unknown's avatar
unknown committed
1090 1091 1092 1093 1094 1095 1096
#ifdef DONT_ALLOW_SHOW_COMMANDS
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
    break;
#else
  {
    char *fields;
    TABLE_LIST table_list;
unknown's avatar
unknown committed
1097
    statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
unknown's avatar
unknown committed
1098 1099 1100 1101 1102 1103 1104
    bzero((char*) &table_list,sizeof(table_list));
    if (!(table_list.db=thd->db))
    {
      send_error(net,ER_NO_DB_ERROR);
      break;
    }
    thd->free_list=0;
1105
    table_list.alias= table_list.real_name= thd->strdup(packet);
unknown's avatar
unknown committed
1106
    packet=strend(packet)+1;
1107
    thd->query_length= strlen(packet);       // for simplicity: don't optimize
unknown's avatar
unknown committed
1108 1109
    if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
      break;
1110
    mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
1111 1112
    if (lower_case_table_names)
      casedn_str(table_list.real_name);
unknown's avatar
unknown committed
1113 1114
    remove_escape(table_list.real_name);	// This can't have wildcards

1115
    if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege))
unknown's avatar
unknown committed
1116 1117 1118 1119 1120 1121 1122 1123 1124
      break;
    if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2))
      break;
    mysqld_list_fields(thd,&table_list,fields);
    free_items(thd);
    break;
  }
#endif
  case COM_QUIT:
1125
    /* We don't calculate statistics for this command */
1126
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1127 1128 1129 1130
    net->error=0;				// Don't give 'abort' message
    error=TRUE;					// End server
    break;

unknown's avatar
unknown committed
1131
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1132
    {
unknown's avatar
unknown committed
1133 1134
      char *db=thd->strdup(packet), *alias;

unknown's avatar
unknown committed
1135
      statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
1136
      // null test to handle EOM
unknown's avatar
unknown committed
1137
      if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
1138 1139 1140 1141
      {
	net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
	break;
      }
unknown's avatar
unknown committed
1142 1143
      if (check_access(thd,CREATE_ACL,db,0,1))
	break;
1144
      mysql_log.write(thd,command,packet);
1145 1146 1147
      if (mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
                          0, 0) < 0)
        send_error(&thd->net, thd->killed ? ER_SERVER_SHUTDOWN : 0);
unknown's avatar
unknown committed
1148 1149
      break;
    }
unknown's avatar
unknown committed
1150
  case COM_DROP_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1151
    {
unknown's avatar
unknown committed
1152
      statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
unknown's avatar
unknown committed
1153
      char *db=thd->strdup(packet), *alias;
1154
      // null test to handle EOM
unknown's avatar
unknown committed
1155
      if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
1156 1157 1158 1159
      {
	net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
	break;
      }
1160 1161
      if (check_access(thd,DROP_ACL,db,0,1))
	break;
unknown's avatar
unknown committed
1162 1163 1164
      if (thd->locked_tables || thd->active_transaction())
      {
	send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
1165
	break;
unknown's avatar
unknown committed
1166
      }
1167
      mysql_log.write(thd,command,db);
1168 1169 1170
      if (mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : db),
                      0, 0) < 0)
        send_error(&thd->net, thd->killed ? ER_SERVER_SHUTDOWN : 0);
unknown's avatar
unknown committed
1171 1172 1173 1174
      break;
    }
  case COM_BINLOG_DUMP:
    {
unknown's avatar
unknown committed
1175
      statistic_increment(com_other,&LOCK_status);
1176
      slow_command = TRUE;
unknown's avatar
unknown committed
1177
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1178
	break;
1179
      mysql_log.write(thd,command, 0);
unknown's avatar
unknown committed
1180

unknown's avatar
unknown committed
1181 1182
      ulong pos;
      ushort flags;
1183
      uint32 slave_server_id;
1184
      /* TODO: The following has to be changed to an 8 byte integer */
1185 1186
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
1187
      thd->server_id=0; /* avoid suicide */
unknown's avatar
unknown committed
1188
      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
unknown's avatar
unknown committed
1189
	kill_zombie_dump_threads(slave_server_id);
1190
      thd->server_id = slave_server_id;
1191
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1192
      unregister_slave(thd,1,1);
1193 1194 1195
      // fake COM_QUIT -- if we get here, the thread needs to terminate
      error = TRUE;
      net->error = 0;
unknown's avatar
unknown committed
1196 1197 1198 1199
      break;
    }
  case COM_REFRESH:
    {
unknown's avatar
unknown committed
1200
      statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
unknown's avatar
unknown committed
1201
      ulong options= (ulong) (uchar) packet[0];
unknown's avatar
unknown committed
1202
      if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1203
	break;
1204
      mysql_log.write(thd,command,NullS);
1205 1206
      /* error sending is deferred to reload_acl_and_cache */
      reload_acl_and_cache(thd, options, (TABLE_LIST*) 0) ;
unknown's avatar
unknown committed
1207 1208 1209
      break;
    }
  case COM_SHUTDOWN:
unknown's avatar
unknown committed
1210
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1211
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1212 1213
      break; /* purecov: inspected */
    DBUG_PRINT("quit",("Got shutdown command"));
1214
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1215 1216 1217 1218
    send_eof(net);
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
unknown's avatar
unknown committed
1219
#ifndef OS2
unknown's avatar
unknown committed
1220
    send_eof(net);				// This is for 'quit request'
unknown's avatar
unknown committed
1221
#endif
unknown's avatar
unknown committed
1222 1223
    close_connection(net);
    close_thread_tables(thd);			// Free before kill
1224
    free_root(&thd->mem_root,MYF(0));
1225
    free_root(&thd->transaction.mem_root,MYF(0));
unknown's avatar
unknown committed
1226 1227 1228 1229 1230 1231
    kill_mysql();
    error=TRUE;
    break;

  case COM_STATISTICS:
  {
1232
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1233
    statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
unknown's avatar
unknown committed
1234
    char buff[200];
1235
    ulong uptime = (ulong) (thd->start_time - start_time);
unknown's avatar
unknown committed
1236
    sprintf((char*) buff,
1237
	    "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
1238 1239 1240 1241 1242
	    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
1243
    if (sf_malloc_cur_memory)				// Using SAFEMALLOC
unknown's avatar
unknown committed
1244
      sprintf(strend(buff), "  Memory in use: %ldK  Max memory used: %ldK",
1245 1246
	      (sf_malloc_cur_memory+1023L)/1024L,
	      (sf_malloc_max_memory+1023L)/1024L);
unknown's avatar
unknown committed
1247
 #endif
unknown's avatar
unknown committed
1248
    VOID(my_net_write(net, buff,(uint) strlen(buff)));
unknown's avatar
unknown committed
1249 1250 1251 1252
    VOID(net_flush(net));
    break;
  }
  case COM_PING:
unknown's avatar
unknown committed
1253
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1254 1255 1256
    send_ok(net);				// Tell client we are alive
    break;
  case COM_PROCESS_INFO:
unknown's avatar
unknown committed
1257
    statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
unknown's avatar
unknown committed
1258
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
1259
      break;
1260
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1261 1262 1263 1264 1265
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
			  thd->priv_user,0);
    break;
  case COM_PROCESS_KILL:
  {
unknown's avatar
unknown committed
1266
    statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
1267
    ulong id=(ulong) uint4korr(packet);
unknown's avatar
unknown committed
1268 1269 1270 1271
    kill_one_thread(thd,id);
    break;
  }
  case COM_DEBUG:
unknown's avatar
unknown committed
1272
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1273
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1274 1275
      break;					/* purecov: inspected */
    mysql_print_status(thd);
1276
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1277 1278 1279 1280 1281 1282
    send_eof(net);
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
1283
  case COM_END:
unknown's avatar
unknown committed
1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
  default:
    send_error(net, ER_UNKNOWN_COM_ERROR);
    break;
  }
  if (thd->lock || thd->open_tables)
  {
    thd->proc_info="closing tables";
    close_thread_tables(thd);			/* Free tables */
  }

  if (thd->fatal_error)
    send_error(net,0);				// End of memory ?

  time_t start_of_query=thd->start_time;
1298
  thd->end_time();				// Set start time
1299

1300
  /* If not reading from backup and if the query took too long */
1301
  if (!slow_command && !thd->user_time) // do not log 'slow_command' queries
unknown's avatar
unknown committed
1302
  {
1303 1304
    thd->proc_info="logging slow query";

1305 1306
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
1307
	((thd->lex.select_lex.options &
1308
	  (QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED)) &&
1309
	 (specialflag & SPECIAL_LONG_LOG_FORMAT)))
1310 1311 1312 1313
    {
      long_query_count++;
      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
    }
unknown's avatar
unknown committed
1314
  }
1315
  thd->proc_info="cleaning up";
unknown's avatar
unknown committed
1316 1317 1318 1319
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
  thd->proc_info=0;
  thd->command=COM_SLEEP;
  thd->query=0;
unknown's avatar
unknown committed
1320
  thd->query_length=0;
unknown's avatar
unknown committed
1321 1322
  thread_running--;
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1323
  thd->packet.shrink(thd->variables.net_buffer_length);	// Reclaim some memory
1324
  free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
  DBUG_RETURN(error);
}

/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/

void
mysql_execute_command(void)
{
  int	res=0;
  THD	*thd=current_thd;
1338
  LEX	*lex= &thd->lex;
1339
  TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first;
1340
  SELECT_LEX *select_lex = lex->select;
unknown's avatar
unknown committed
1341 1342
  DBUG_ENTER("mysql_execute_command");

1343 1344
  if (thd->slave_thread)
  {
unknown's avatar
merge  
unknown committed
1345 1346 1347 1348
    /* 
      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
    */
1349
    if (all_tables_not_ok(thd,tables))
unknown's avatar
unknown committed
1350 1351 1352
    {
      /* we warn the slave SQL thread */
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
1353
      DBUG_VOID_RETURN;
unknown's avatar
unknown committed
1354
    }
unknown's avatar
merge  
unknown committed
1355 1356 1357 1358 1359 1360
#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()
    */
1361 1362 1363
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
unknown's avatar
unknown committed
1364
      lex->insert_list = &select_lex->item_list;
1365
    }
unknown's avatar
merge  
unknown committed
1366
#endif
1367
  }
1368
  
1369 1370 1371
  if (lex->select_lex.next &&
      create_total_list(thd,lex,&tables,
			(lex->sql_command == SQLCOM_CREATE_TABLE)))
1372
    DBUG_VOID_RETURN;
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
  
  /*
    When option readonly is set deny operations which change tables.
    Except for the replication thread and the 'super' users.
  */
  if (opt_readonly &&
      !(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
      (uc_update_queries[lex->sql_command] > 0))
  {
    send_error(&thd->net,ER_CANT_UPDATE_WITH_READLOCK);
    DBUG_VOID_RETURN;
  }
1385

unknown's avatar
unknown committed
1386
  statistic_increment(com_stat[lex->sql_command],&LOCK_status);
unknown's avatar
unknown committed
1387 1388 1389 1390
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
    select_result *result;
1391
    if (select_lex->options & SELECT_DESCRIBE)
unknown's avatar
unknown committed
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
      lex->exchange=0;
    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
    }

1409 1410 1411
    thd->offset_limit=select_lex->offset_limit;
    thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
    if (thd->select_limit < select_lex->select_limit)
unknown's avatar
unknown committed
1412
      thd->select_limit= HA_POS_ERROR;		// no limit
1413
    if (thd->select_limit == HA_POS_ERROR)
1414
      select_lex->options&= ~OPTION_FOUND_ROWS;
unknown's avatar
unknown committed
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438

    if (lex->exchange)
    {
      if (lex->exchange->dumpfile)
      {
	if (!(result=new select_dump(lex->exchange)))
	{
	  res= -1;
	  break;
	}
      }
      else
      {
	if (!(result=new select_export(lex->exchange)))
	{
	  res= -1;
	  break;
	}
      }
    }
    else if (!(result=new select_send()))
    {
      res= -1;
#ifdef DELETE_ITEMS
1439 1440
      delete select_lex->having;
      delete select_lex->where;
unknown's avatar
unknown committed
1441 1442 1443
#endif
      break;
    }
unknown's avatar
unknown committed
1444
    else
unknown's avatar
unknown committed
1445
    {
unknown's avatar
unknown committed
1446 1447 1448 1449
      /*
	Normal select:
	Change lock if we are using SELECT HIGH PRIORITY,
	FOR UPDATE or IN SHARE MODE
unknown's avatar
unknown committed
1450 1451

	TODO: Delete the following loop when locks is set by sql_yacc
unknown's avatar
unknown committed
1452
      */
unknown's avatar
unknown committed
1453 1454
      TABLE_LIST *table;
      for (table = tables ; table ; table=table->next)
unknown's avatar
unknown committed
1455
	table->lock_type= lex->lock_option;
unknown's avatar
unknown committed
1456 1457 1458
    }

    if (!(res=open_and_lock_tables(thd,tables)))
unknown's avatar
unknown committed
1459
    {
unknown's avatar
unknown committed
1460
      query_cache_store_query(thd, tables);
1461
      res=handle_select(thd, lex, result);
unknown's avatar
unknown committed
1462
    }
1463 1464
    else
      delete result;
unknown's avatar
unknown committed
1465 1466
    break;
  }
unknown's avatar
unknown committed
1467 1468 1469 1470
  case SQLCOM_DO:
    res=mysql_do(thd, *lex->insert_list);
    break;

1471 1472 1473 1474
  case SQLCOM_EMPTY_QUERY:
    send_ok(&thd->net);
    break;

unknown's avatar
unknown committed
1475
  case SQLCOM_PURGE:
1476
  {
unknown's avatar
unknown committed
1477
    if (check_global_access(thd, SUPER_ACL))
1478 1479 1480 1481
      goto error;
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
unknown's avatar
unknown committed
1482 1483
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
1484
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1485
      goto error;
1486
    /* This query don't work now. See comment in repl_failsafe.cc */
unknown's avatar
unknown committed
1487 1488 1489 1490
#ifndef WORKING_NEW_MASTER
    net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
    res= 1;
#else
unknown's avatar
unknown committed
1491
    res = show_new_master(thd);
unknown's avatar
unknown committed
1492
#endif
unknown's avatar
unknown committed
1493 1494
    break;
  }
1495 1496
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
1497
    if (check_global_access(thd, REPL_SLAVE_ACL))
1498 1499 1500 1501
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
1502 1503
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
1504
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1505 1506 1507 1508
      goto error;
    res = show_binlog_events(thd);
    break;
  }
unknown's avatar
unknown committed
1509
  case SQLCOM_BACKUP_TABLE:
1510 1511 1512
  {
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables) ||
unknown's avatar
unknown committed
1513
	check_global_access(thd, FILE_ACL))
1514 1515
      goto error; /* purecov: inspected */
    res = mysql_backup_table(thd, tables);
unknown's avatar
unknown committed
1516

1517 1518
    break;
  }
unknown's avatar
unknown committed
1519
  case SQLCOM_RESTORE_TABLE:
1520 1521
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
1522 1523
	check_table_access(thd, INSERT_ACL, tables) ||
	check_global_access(thd, FILE_ACL))
1524 1525 1526 1527
      goto error; /* purecov: inspected */
    res = mysql_restore_table(thd, tables);
    break;
  }
unknown's avatar
unknown committed
1528

unknown's avatar
unknown committed
1529
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
1530
  case SQLCOM_CHANGE_MASTER:
1531
  {
unknown's avatar
unknown committed
1532
    if (check_global_access(thd, SUPER_ACL))
1533
      goto error;
1534
    pthread_mutex_lock(&LOCK_active_mi);
1535
    res = change_master(thd,active_mi);
1536
    pthread_mutex_unlock(&LOCK_active_mi);
1537 1538
    break;
  }
unknown's avatar
unknown committed
1539
  case SQLCOM_SHOW_SLAVE_STAT:
1540
  {
1541 1542
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
1543
      goto error;
1544
    pthread_mutex_lock(&LOCK_active_mi);
1545
    res = show_master_info(thd,active_mi);
1546
    pthread_mutex_unlock(&LOCK_active_mi);
1547 1548
    break;
  }
unknown's avatar
unknown committed
1549
  case SQLCOM_SHOW_MASTER_STAT:
1550
  {
1551 1552
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
1553 1554 1555 1556
      goto error;
    res = show_binlog_info(thd);
    break;
  }
1557 1558
    
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
1559
    if (check_global_access(thd, SUPER_ACL))
1560
      goto error;
1561 1562 1563 1564
    if (end_active_trans(thd))
      res= -1;
    else
      res = load_master_data(thd);
1565
    break;
unknown's avatar
unknown committed
1566

unknown's avatar
unknown committed
1567
#endif /* HAVE_REPLICATION */
1568
    
unknown's avatar
unknown committed
1569 1570 1571
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
1572
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1573 1574 1575 1576 1577
	goto error;
      res = innodb_show_status(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
1578

unknown's avatar
unknown committed
1579
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
1580
  case SQLCOM_LOAD_MASTER_TABLE:
1581
  {
unknown's avatar
unknown committed
1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593
    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)
1594
	goto error;
unknown's avatar
unknown committed
1595
    }
1596
    pthread_mutex_lock(&LOCK_active_mi);
1597 1598 1599 1600
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
1601
    if (!fetch_master_table(thd, tables->db, tables->real_name,
1602
			    active_mi, 0, 0))
1603 1604 1605
    {
      send_ok(&thd->net);
    }
1606
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
1607
    break;
1608
  }
unknown's avatar
unknown committed
1609
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
1610

unknown's avatar
unknown committed
1611
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
1612 1613 1614
  {
    ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
		      CREATE_TMP_ACL : CREATE_ACL);
1615 1616
    if (!tables->db)
      tables->db=thd->db;
unknown's avatar
unknown committed
1617
    lex->create_info.alias= tables->alias;
unknown's avatar
unknown committed
1618
    if (check_access(thd,want_priv,tables->db,&tables->grant.privilege) ||
1619 1620 1621
	check_merge_table_access(thd, tables->db,
				 (TABLE_LIST *)
				 lex->create_info.merge_list.first))
unknown's avatar
unknown committed
1622
      goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
1623
    if (grant_option && want_priv != CREATE_TMP_ACL)
unknown's avatar
unknown committed
1624 1625 1626 1627
    {
      /* Check that the first table has CREATE privilege */
      TABLE_LIST *tmp_table_list=tables->next;
      tables->next=0;
unknown's avatar
unknown committed
1628
      bool error=check_grant(thd, want_priv, tables);
unknown's avatar
unknown committed
1629 1630 1631 1632
      tables->next=tmp_table_list;
      if (error)
	goto error;
    }
1633
    if (strlen(tables->real_name) > NAME_LEN)
unknown's avatar
unknown committed
1634
    {
1635
      net_printf(&thd->net, ER_WRONG_TABLE_NAME, tables->alias);
unknown's avatar
unknown committed
1636 1637 1638
      res=0;
      break;
    }
1639 1640 1641
#ifndef HAVE_READLINK
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
1642
    /* Fix names if symlinked tables */
unknown's avatar
unknown committed
1643
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
1644
			   tables->real_name) ||
unknown's avatar
unknown committed
1645
	append_file_to_dir(thd,&lex->create_info.index_file_name,
1646
			   tables->real_name))
1647 1648 1649 1650
    {
      res=-1;
      break;
    }
1651
#endif
1652
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
1653 1654 1655 1656
    {
      select_result *result;

      if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
unknown's avatar
unknown committed
1657
	  check_dup(tables->db, tables->real_name, tables->next))
unknown's avatar
unknown committed
1658 1659 1660 1661
      {
	net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
	DBUG_VOID_RETURN;
      }
1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674
      if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
      {
        TABLE_LIST *tab;
        for (tab= tables; tab; tab= tab->next)
        {
          if (check_dup(tables->db, tab->real_name,
                        (TABLE_LIST*)lex->create_info.merge_list.first))
          {
            net_printf(&thd->net, ER_INSERT_TABLE_USED, tab->real_name);
            DBUG_VOID_RETURN;
          }
        }  
      }    
unknown's avatar
unknown committed
1675 1676
      if (tables->next)
      {
1677
	TABLE_LIST *table;
unknown's avatar
unknown committed
1678 1679
	if (check_table_access(thd, SELECT_ACL, tables->next))
	  goto error;				// Error message is given
unknown's avatar
unknown committed
1680
	/* TODO: Delete the following loop when locks is set by sql_yacc */
1681 1682
	for (table = tables->next ; table ; table=table->next)
	  table->lock_type= lex->lock_option;
unknown's avatar
unknown committed
1683
      }
1684
      select_lex->options|= SELECT_NO_UNLOCK;
1685 1686 1687
      thd->offset_limit=select_lex->offset_limit;
      thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
      if (thd->select_limit < select_lex->select_limit)
unknown's avatar
unknown committed
1688
	thd->select_limit= HA_POS_ERROR;		// No limit
1689 1690 1691 1692 1693 1694 1695

      /* 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,
unknown's avatar
unknown committed
1696 1697
                                      tables->real_name,
				      &lex->create_info,
1698 1699 1700 1701 1702 1703 1704 1705
                                      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
1706 1707 1708
    else // regular create
    {
      res = mysql_create_table(thd,tables->db ? tables->db : thd->db,
unknown's avatar
unknown committed
1709 1710
			       tables->real_name,
			       &lex->create_info,
unknown's avatar
unknown committed
1711
			       lex->create_list,
1712
			       lex->key_list,0);
unknown's avatar
unknown committed
1713 1714 1715 1716
      if (!res)
	send_ok(&thd->net);
    }
    break;
unknown's avatar
unknown committed
1717
  }
unknown's avatar
unknown committed
1718
  case SQLCOM_CREATE_INDEX:
1719
    if (check_one_table_access(thd, INDEX_ACL, tables, 0))
unknown's avatar
unknown committed
1720
      goto error; /* purecov: inspected */
1721 1722 1723 1724
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_create_index(thd, tables, lex->key_list);
unknown's avatar
unknown committed
1725 1726
    break;

unknown's avatar
unknown committed
1727
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
1728
  case SQLCOM_SLAVE_START:
1729
  {
1730
    pthread_mutex_lock(&LOCK_active_mi);
1731
    start_slave(thd,active_mi,1 /* net report*/);
1732
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
1733
    break;
1734
  }
unknown's avatar
unknown committed
1735
  case SQLCOM_SLAVE_STOP:
1736 1737 1738 1739 1740 1741
  /*
    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,
1742
      so it waits for the client thread because t is locked by it.
1743
    - then the client thread does SLAVE STOP.
1744 1745
      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.
1746 1747 1748 1749 1750 1751
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
  if (thd->locked_tables || thd->active_transaction())
  {
    send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
1752
    break;
1753
  }
1754
  {
1755
    pthread_mutex_lock(&LOCK_active_mi);
1756
    stop_slave(thd,active_mi,1/* net report*/);
1757
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
1758
    break;
1759
  }
unknown's avatar
unknown committed
1760
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
1761

unknown's avatar
unknown committed
1762 1763 1764 1765 1766 1767
  case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
    break;
#else
    {
unknown's avatar
unknown committed
1768
      ulong priv=0;
unknown's avatar
unknown committed
1769
      if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
unknown's avatar
unknown committed
1770 1771
      {
	net_printf(&thd->net,ER_WRONG_TABLE_NAME,lex->name);
unknown's avatar
unknown committed
1772
	res= 1;
unknown's avatar
unknown committed
1773 1774
	break;
      }
1775 1776
      if (!select_lex->db)
	select_lex->db=tables->db;
unknown's avatar
unknown committed
1777
      if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege) ||
1778
	  check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv) ||
1779 1780 1781 1782
	  check_merge_table_access(thd, tables->db, 
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
1783 1784 1785 1786 1787 1788 1789 1790 1791
      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;
1792
	  tmp_table.db=select_lex->db;
unknown's avatar
unknown committed
1793
	  tmp_table.grant.privilege=priv;
1794
	  if (check_grant(thd,INSERT_ACL | CREATE_ACL, &tmp_table))
unknown's avatar
unknown committed
1795 1796 1797
	    goto error;
	}
      }
1798 1799
      /* 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
1800
      /* ALTER TABLE ends previous transaction */
1801
      if (end_active_trans(thd))
unknown's avatar
unknown committed
1802 1803
	res= -1;
      else
unknown's avatar
unknown committed
1804
      {
1805
	res= mysql_alter_table(thd, select_lex->db, lex->name,
unknown's avatar
unknown committed
1806 1807 1808
			       &lex->create_info,
			       tables, lex->create_list,
			       lex->key_list, lex->drop_list, lex->alter_list,
1809
                               (ORDER *) select_lex->order_list.first,
1810 1811
			       lex->drop_primary, lex->duplicates,
			       lex->alter_keys_onoff, lex->simple_alter);
unknown's avatar
unknown committed
1812
      }
unknown's avatar
unknown committed
1813 1814 1815
      break;
    }
#endif
unknown's avatar
unknown committed
1816
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
1817 1818 1819
  {
    TABLE_LIST *table;
    if (check_db_used(thd,tables))
unknown's avatar
unknown committed
1820
      goto error;
unknown's avatar
unknown committed
1821 1822
    for (table=tables ; table ; table=table->next->next)
    {
unknown's avatar
unknown committed
1823 1824
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
		       &table->grant.privilege) ||
unknown's avatar
unknown committed
1825 1826 1827 1828 1829
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next->db,
		       &table->next->grant.privilege))
	goto error;
      if (grant_option)
      {
unknown's avatar
unknown committed
1830 1831 1832 1833 1834
	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
1835
	    (!test_all_bits(table->next->grant.privilege,
1836
			    INSERT_ACL | CREATE_ACL) &&
unknown's avatar
unknown committed
1837
	     check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list)))
unknown's avatar
unknown committed
1838 1839 1840
	  goto error;
      }
    }
unknown's avatar
unknown committed
1841
    query_cache_invalidate3(thd, tables, 0);
1842 1843 1844
    if (end_active_trans(thd))
      res= -1;
    else if (mysql_rename_tables(thd,tables))
unknown's avatar
unknown committed
1845 1846
      res= -1;
    break;
unknown's avatar
unknown committed
1847
  }
unknown's avatar
unknown committed
1848 1849 1850 1851 1852 1853
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
    DBUG_VOID_RETURN;
#else
    {
unknown's avatar
unknown committed
1854
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1855 1856 1857 1858 1859
	goto error;
      res = show_binlogs(thd);
      break;
    }
#endif    
unknown's avatar
unknown committed
1860
  case SQLCOM_SHOW_CREATE:
unknown's avatar
unknown committed
1861
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1862
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
1863 1864
    DBUG_VOID_RETURN;
#else
unknown's avatar
unknown committed
1865
    {
unknown's avatar
unknown committed
1866 1867 1868 1869
      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
1870
      res = mysqld_show_create(thd, tables);
unknown's avatar
unknown committed
1871 1872
      break;
    }
unknown's avatar
unknown committed
1873
#endif
unknown's avatar
unknown committed
1874
  case SQLCOM_REPAIR:
1875 1876 1877 1878 1879 1880 1881
  {
    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
1882
  case SQLCOM_CHECK:
1883 1884 1885 1886 1887 1888 1889
  {
    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
1890 1891
  case SQLCOM_ANALYZE:
  {
unknown's avatar
unknown committed
1892 1893
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
unknown's avatar
unknown committed
1894
      goto error; /* purecov: inspected */
1895
    res = mysql_analyze_table(thd, tables, &lex->check_opt);
unknown's avatar
unknown committed
1896
    break;
unknown's avatar
unknown committed
1897
  }
1898

unknown's avatar
unknown committed
1899 1900 1901
  case SQLCOM_OPTIMIZE:
  {
    HA_CREATE_INFO create_info;
1902 1903
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
unknown's avatar
unknown committed
1904
      goto error; /* purecov: inspected */
1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918
    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;
      res= mysql_alter_table(thd, NullS, NullS, &create_info,
			     tables, lex->create_list,
			     lex->key_list, lex->drop_list, lex->alter_list,
unknown's avatar
unknown committed
1919
                             (ORDER *) 0,
1920 1921 1922 1923
			     0,DUP_ERROR);
    }
    else
      res = mysql_optimize_table(thd, tables, &lex->check_opt);
unknown's avatar
unknown committed
1924 1925 1926
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
unknown committed
1927
    if (check_db_used(thd,tables))
unknown's avatar
unknown committed
1928
      goto error;
1929
    if (select_lex->item_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
1930 1931 1932 1933
    {
      send_error(&thd->net,ER_WRONG_VALUE_COUNT);
      DBUG_VOID_RETURN;
    }
1934 1935
    if (check_one_table_access(thd, UPDATE_ACL, tables, 0))
      goto error; /* purecov: inspected */
1936 1937


1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952
    res= mysql_update(thd,tables,
		      select_lex->item_list,
		      lex->value_list,
		      select_lex->where,
		      (ORDER *) select_lex->order_list.first,
		      select_lex->select_limit,
		      lex->duplicates);
    break;
  case SQLCOM_MULTI_UPDATE:
    if (check_db_used(thd,tables))
      goto error;
    if (select_lex->item_list.elements != lex->value_list.elements)
    {
      send_error(&thd->net,ER_WRONG_VALUE_COUNT);
      DBUG_VOID_RETURN;
1953 1954
    }
    {
unknown's avatar
unknown committed
1955
      const char *msg= 0;
1956
      TABLE_LIST *table;
unknown's avatar
unknown committed
1957
      lex->sql_command= SQLCOM_MULTI_UPDATE;
1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971

      /*
	Ensure that we have UPDATE or SELECT privilege for each table
	The exact privilege is checked in mysql_multi_update()
      */
      for (table= tables ; table ; table= table->next)
      {
	TABLE_LIST *save= table->next;
	table->next= 0;
	if (check_one_table_access(thd, UPDATE_ACL, table, 1) &&
	    check_one_table_access(thd, SELECT_ACL, table, 0))
	    goto error;
	table->next= save;
      }
unknown's avatar
unknown committed
1972 1973 1974 1975 1976 1977
      if (select_lex->order_list.elements)
	msg="ORDER BY";
      else if (select_lex->select_limit && select_lex->select_limit !=
	       HA_POS_ERROR)
	msg="LIMIT";
      if (msg)
1978
      {
unknown's avatar
unknown committed
1979 1980 1981
	net_printf(&thd->net, ER_WRONG_USAGE, "UPDATE", msg);
	res= 1;
	break;
1982
      }
unknown's avatar
unknown committed
1983 1984 1985 1986 1987 1988
      res= mysql_multi_update(thd,tables,
			      &select_lex->item_list,
			      &lex->value_list,
			      select_lex->where,
			      select_lex->options,
			      lex->duplicates);
1989
    }
unknown's avatar
unknown committed
1990
    break;
unknown's avatar
unknown committed
1991
  case SQLCOM_INSERT:
1992
    if (check_one_table_access(thd, INSERT_ACL, tables, 0))
unknown's avatar
unknown committed
1993 1994
      goto error; /* purecov: inspected */
    res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
unknown's avatar
unknown committed
1995
		       lex->duplicates);
unknown's avatar
unknown committed
1996 1997
    break;
  case SQLCOM_REPLACE:
1998
    if (check_one_table_access(thd, INSERT_ACL | DELETE_ACL, tables, 0))
unknown's avatar
unknown committed
1999 2000
      goto error; /* purecov: inspected */
    res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
unknown's avatar
unknown committed
2001
		       DUP_REPLACE);
unknown's avatar
unknown committed
2002 2003 2004 2005
    break;
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
2006
    {
2007 2008 2009 2010
      /*
	Check that we have modify privileges for the first table and
	select privileges for the rest
      */
unknown's avatar
unknown committed
2011
      ulong privilege= (lex->sql_command == SQLCOM_INSERT_SELECT ?
2012
			INSERT_ACL : INSERT_ACL | DELETE_ACL);
2013 2014
      TABLE_LIST *save_next=tables->next;
      tables->next=0;
2015
      if (check_one_table_access(thd, privilege, tables, 0))
2016 2017 2018 2019 2020
	goto error;
      tables->next=save_next;
      if ((res=check_table_access(thd, SELECT_ACL, save_next)))
	goto error;
    }
2021 2022
    /* Fix lock for first table */
    if (tables->lock_type == TL_WRITE_DELAYED)
2023
      tables->lock_type= TL_WRITE;
2024

2025 2026
    /* Don't unlock tables until command is written to binary log */
    select_lex->options|= SELECT_NO_UNLOCK;
unknown's avatar
unknown committed
2027 2028

    select_result *result;
2029 2030 2031
    thd->offset_limit=select_lex->offset_limit;
    thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
    if (thd->select_limit < select_lex->select_limit)
unknown's avatar
unknown committed
2032 2033
      thd->select_limit= HA_POS_ERROR;		// No limit

2034 2035 2036 2037 2038
    if (check_dup(tables->db, tables->real_name, tables->next))
    {
      /* Using same table for INSERT and SELECT */
      select_lex->options |= OPTION_BUFFER_RESULT;
    }
2039
    {
unknown's avatar
unknown committed
2040
      /* TODO: Delete the following loop when locks is set by sql_yacc */
2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051
      TABLE_LIST *table;
      for (table = tables->next ; table ; table=table->next)
	table->lock_type= lex->lock_option;
    }

    /* 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,
2052
				    lex->duplicates)))
2053 2054 2055 2056
	res=handle_select(thd,lex,result);
    }
    else
      res= -1;
unknown's avatar
unknown committed
2057 2058
    break;
  }
2059
  case SQLCOM_TRUNCATE:
2060
    if (check_one_table_access(thd, DELETE_ACL, tables, 0))
2061 2062 2063 2064 2065 2066 2067
      goto error; /* purecov: inspected */
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
2068
      send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
2069 2070
      goto error;
    }
2071
    res=mysql_truncate(thd, tables, 0);
2072
    break;
unknown's avatar
unknown committed
2073
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
2074
  {
2075
    if (check_one_table_access(thd, DELETE_ACL, tables, 0))
unknown's avatar
unknown committed
2076 2077 2078
      goto error;
    // Set privilege for the WHERE clause
    tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
2079 2080
    res = mysql_delete(thd,tables, select_lex->where,
                       (ORDER*) select_lex->order_list.first,
unknown's avatar
unknown committed
2081
                       select_lex->select_limit, select_lex->options);
unknown's avatar
unknown committed
2082 2083
    break;
  }
2084
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
2085 2086 2087 2088 2089
  {
    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
2090

unknown's avatar
unknown committed
2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116
    /* sql_yacc guarantees that tables and aux_tables are not zero */
    if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
	check_table_access(thd,SELECT_ACL, tables) || 
	check_table_access(thd,DELETE_ACL, aux_tables))
      goto error;
    if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
    {		
      send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
      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)
      {
	net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name);
	goto error;
      }
unknown's avatar
unknown committed
2117
      walk->lock_type= auxi->lock_type;
unknown's avatar
unknown committed
2118 2119
      // Store address to table as we need it later
      auxi->table= my_reinterpret_cast(TABLE *) (walk);
2120 2121 2122
    }
    if (add_item_to_list(new Item_null()))
    {
unknown's avatar
unknown committed
2123
      res= -1;
2124
      break;
unknown's avatar
unknown committed
2125 2126 2127 2128 2129 2130 2131
    }
    tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
    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)
unknown's avatar
unknown committed
2132 2133
      auxi->table= (my_reinterpret_cast(TABLE_LIST*) (auxi->table))->table;

2134 2135
    if (!thd->fatal_error && (result= new multi_delete(thd,aux_tables,
						       table_count)))
unknown's avatar
unknown committed
2136 2137
    {
      res=mysql_select(thd,tables,select_lex->item_list,
2138
		       select_lex->where,
unknown's avatar
unknown committed
2139 2140 2141
		       (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
		       (ORDER *)NULL,
		       select_lex->options | thd->options |
unknown's avatar
unknown committed
2142
		       SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
unknown's avatar
unknown committed
2143
		       result);
2144
      delete result;
unknown's avatar
unknown committed
2145 2146 2147 2148 2149 2150
    }
    else
      res= -1;					// Error is not sent
    close_thread_tables(thd);
    break;
  }
unknown's avatar
unknown committed
2151
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
2152 2153 2154
  {
    if (check_table_access(thd,DROP_ACL,tables))
      goto error;				/* purecov: inspected */
2155 2156 2157 2158 2159
    /*
      If this is a slave thread, we may sometimes execute some 
      DROP / * 40005 TEMPORARY * / TABLE
      that come from parts of binlogs (likely if we use RESET SLAVE or CHANGE
      MASTER TO), while the temporary table has already been dropped.
2160 2161
      To not generate such irrelevant "table does not exist errors",
      we silently add IF EXISTS if TEMPORARY was used.
2162 2163 2164
    */
    if (thd->slave_thread && lex->drop_temporary)
      lex->drop_if_exists= 1;
unknown's avatar
unknown committed
2165 2166 2167 2168 2169 2170
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_rm_table(thd,tables,lex->drop_if_exists);
  }
  break;
unknown's avatar
unknown committed
2171
  case SQLCOM_DROP_INDEX:
2172 2173
    if (check_one_table_access(thd, INDEX_ACL, tables, 0))
      goto error; /* purecov: inspected */
2174 2175 2176 2177
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_drop_index(thd, tables, lex->drop_list);
unknown's avatar
unknown committed
2178 2179
    break;
  case SQLCOM_SHOW_DATABASES:
2180
#if defined(DONT_ALLOW_SHOW_COMMANDS)
unknown's avatar
unknown committed
2181
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);   /* purecov: inspected */
unknown's avatar
unknown committed
2182 2183 2184
    DBUG_VOID_RETURN;
#else
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
unknown's avatar
unknown committed
2185
	check_global_access(thd, SHOW_DB_ACL))
unknown's avatar
unknown committed
2186 2187 2188 2189 2190
      goto error;
    res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
    break;
#endif
  case SQLCOM_SHOW_PROCESSLIST:
unknown's avatar
unknown committed
2191
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
2192 2193 2194 2195 2196
      break;
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
			  thd->priv_user,lex->verbose);
    break;
  case SQLCOM_SHOW_STATUS:
2197
    res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
2198
		     OPT_GLOBAL, &LOCK_status);
unknown's avatar
unknown committed
2199 2200 2201
    break;
  case SQLCOM_SHOW_VARIABLES:
    res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
2202 2203
		     init_vars, lex->option_type,
		     &LOCK_global_system_variables);
unknown's avatar
unknown committed
2204
    break;
unknown's avatar
unknown committed
2205
  case SQLCOM_SHOW_LOGS:
unknown's avatar
unknown committed
2206 2207 2208 2209
  {
    res= mysqld_show_logs(thd);
    break;
  }
unknown's avatar
unknown committed
2210
  case SQLCOM_SHOW_TABLES:
2211
    /* FALL THROUGH */
unknown's avatar
unknown committed
2212 2213 2214 2215 2216
#ifdef DONT_ALLOW_SHOW_COMMANDS
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
    DBUG_VOID_RETURN;
#else
    {
2217
      char *db=select_lex->db ? select_lex->db : thd->db;
unknown's avatar
unknown committed
2218 2219 2220 2221 2222 2223
      if (!db)
      {
	send_error(&thd->net,ER_NO_DB_ERROR);	/* purecov: inspected */
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);				// Fix escaped '_'
2224
      if (check_db_name(db))
unknown's avatar
unknown committed
2225
      {
2226 2227
        net_printf(&thd->net,ER_WRONG_DB_NAME, db);
        goto error;
unknown's avatar
unknown committed
2228 2229 2230
      }
      if (check_access(thd,SELECT_ACL,db,&thd->col_access))
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
2231
      if (!thd->col_access && check_grant_db(thd,db))
unknown's avatar
unknown committed
2232 2233 2234 2235 2236 2237 2238
      {
	net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
		   thd->priv_user,
		   thd->priv_host,
		   db);
	goto error;
      }
unknown's avatar
unknown committed
2239
      /* grant is checked in mysqld_show_tables */
2240
      if (select_lex->options & SELECT_DESCRIBE)
2241
        res= mysqld_extend_show_tables(thd,db,
2242
				       (lex->wild ? lex->wild->ptr() : NullS));
unknown's avatar
unknown committed
2243 2244 2245 2246 2247 2248
      else
	res= mysqld_show_tables(thd,db,
				(lex->wild ? lex->wild->ptr() : NullS));
      break;
    }
#endif
2249 2250 2251
  case SQLCOM_SHOW_OPEN_TABLES:
    res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
unknown's avatar
unknown committed
2252 2253 2254 2255 2256 2257
  case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
    DBUG_VOID_RETURN;
#else
    {
2258
      char *db=tables->db;
unknown's avatar
unknown committed
2259
      remove_escape(db);			// Fix escaped '_'
2260
      remove_escape(tables->real_name);
2261 2262
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
		       &tables->grant.privilege))
unknown's avatar
unknown committed
2263 2264 2265 2266
	goto error;				/* purecov: inspected */
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
	goto error;
      res= mysqld_show_fields(thd,tables,
unknown's avatar
unknown committed
2267 2268
			      (lex->wild ? lex->wild->ptr() : NullS),
			      lex->verbose);
unknown's avatar
unknown committed
2269 2270 2271 2272 2273 2274 2275 2276 2277
      break;
    }
#endif
  case SQLCOM_SHOW_KEYS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
    DBUG_VOID_RETURN;
#else
    {
2278
      char *db=tables->db;
unknown's avatar
unknown committed
2279
      remove_escape(db);			// Fix escaped '_'
2280
      remove_escape(tables->real_name);
2281
      if (check_access(thd,SELECT_ACL,db,&tables->grant.privilege))
unknown's avatar
unknown committed
2282 2283 2284 2285 2286 2287 2288 2289
	goto error; /* purecov: inspected */
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
	goto error;
      res= mysqld_show_keys(thd,tables);
      break;
    }
#endif
  case SQLCOM_CHANGE_DB:
2290
    mysql_change_db(thd,select_lex->db);
unknown's avatar
unknown committed
2291 2292 2293 2294 2295
    break;
  case SQLCOM_LOAD:
  {
    uint privilege= (lex->duplicates == DUP_REPLACE ?
		     INSERT_ACL | UPDATE_ACL | DELETE_ACL : INSERT_ACL);
2296 2297

    if (!lex->local_file)
unknown's avatar
unknown committed
2298 2299 2300 2301 2302 2303
    {
      if (check_access(thd,privilege | FILE_ACL,tables->db))
	goto error;
    }
    else
    {
2304
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
unknown's avatar
unknown committed
2305
	  ! opt_local_infile)
2306 2307 2308 2309
      {
	send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);
	goto error;
      }
2310
      if (check_one_table_access(thd, privilege, tables, 0))
unknown's avatar
unknown committed
2311 2312 2313 2314 2315 2316 2317
	goto error;
    }
    res=mysql_load(thd, lex->exchange, tables, lex->field_list,
		   lex->duplicates, (bool) lex->local_file, lex->lock_option);
    break;
  }
  case SQLCOM_SET_OPTION:
2318
    if (!(res=sql_set_variables(thd, &lex->var_list)))
unknown's avatar
unknown committed
2319
      send_ok(&thd->net);
unknown's avatar
unknown committed
2320 2321
    break;
  case SQLCOM_UNLOCK_TABLES:
unknown's avatar
unknown committed
2322
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
2323 2324
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
2325
      end_active_trans(thd);
unknown's avatar
unknown committed
2326
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
2327 2328
    }
    if (thd->global_read_lock)
2329
      unlock_global_read_lock(thd);
unknown's avatar
unknown committed
2330 2331 2332
    send_ok(&thd->net);
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
2333
    unlock_locked_tables(thd);
2334
    if (check_db_used(thd,tables) || end_active_trans(thd))
unknown's avatar
unknown committed
2335
      goto error;
unknown's avatar
unknown committed
2336
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables))
2337
      goto error;
unknown's avatar
unknown committed
2338
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
2339
    thd->options|= OPTION_TABLE_LOCK;
2340
    if (!(res= open_and_lock_tables(thd, tables)))
unknown's avatar
unknown committed
2341
    {
2342 2343 2344 2345
#ifdef HAVE_QUERY_CACHE
      if (thd->variables.query_cache_wlock_invalidate)
	query_cache.invalidate_locked_for_write(tables);
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
2346 2347 2348 2349
      thd->locked_tables=thd->lock;
      thd->lock=0;
      send_ok(&thd->net);
    }
unknown's avatar
unknown committed
2350 2351
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
2352 2353 2354
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
2355
  {
unknown's avatar
unknown committed
2356
    char *alias;
unknown's avatar
unknown committed
2357
    if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
unknown's avatar
unknown committed
2358
    {
2359
      net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
2360 2361
      break;
    }
2362 2363 2364 2365 2366 2367 2368 2369 2370 2371
    /*
      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.
    */
    if (thd->slave_thread && 
	(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(lex->name)))
unknown's avatar
unknown committed
2372 2373
    {
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
2374
      break;
unknown's avatar
unknown committed
2375
    }
2376

2377 2378
    if (check_access(thd,CREATE_ACL,lex->name,0,1))
      break;
unknown's avatar
unknown committed
2379 2380
    res=mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name),
			lex->create_info.options,0);
2381 2382
    break;
  }
unknown's avatar
unknown committed
2383
  case SQLCOM_DROP_DB:
2384
  {
unknown's avatar
unknown committed
2385
    char *alias;
unknown's avatar
unknown committed
2386
    if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
unknown's avatar
unknown committed
2387
    {
2388
      net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
2389 2390
      break;
    }
2391 2392 2393 2394 2395 2396 2397 2398 2399 2400
    /*
      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.
    */
    if (thd->slave_thread && 
	(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
	 !db_ok_with_wild_table(lex->name)))
unknown's avatar
unknown committed
2401 2402
    {
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
2403
      break;
unknown's avatar
unknown committed
2404
    }
2405
    if (check_access(thd,DROP_ACL,lex->name,0,1))
2406
      break;
2407 2408
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
2409
      send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
2410 2411
      goto error;
    }
2412 2413
    res=mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : lex->name),
                    lex->drop_if_exists, 0);
2414 2415
    break;
  }
unknown's avatar
unknown committed
2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435
  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)))
      send_ok(&thd->net);
#else
    res= -1;
#endif
    break;
  case SQLCOM_DROP_FUNCTION:
    if (check_access(thd,DELETE_ACL,"mysql",0,1))
      break;
#ifdef HAVE_DLOPEN
    if (!(res = mysql_drop_function(thd,lex->udf.name)))
      send_ok(&thd->net);
#else
    res= -1;
#endif
    break;
2436 2437 2438 2439 2440 2441 2442 2443 2444
  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
2445 2446 2447 2448
    /*
      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
    */
2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473

    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 &&
	     my_strcasecmp(user->host.str, thd->host_or_ip)))
	{
	  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
2474 2475 2476
      if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
				    lex->grant,
				    lex->sql_command == SQLCOM_REVOKE)))
2477
      {
2478
	mysql_update_log.write(thd, thd->query, thd->query_length);
2479 2480
	if (mysql_bin_log.is_open())
	{
unknown's avatar
unknown committed
2481
          thd->clear_error();
2482
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
2483 2484 2485 2486 2487 2488 2489 2490
	  mysql_bin_log.write(&qinfo);
	}
      }
    }
    else
    {
      if (lex->columns.elements)
      {
unknown's avatar
unknown committed
2491
	send_error(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
2492 2493 2494 2495 2496 2497 2498
	res=1;
      }
      else
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
2499
	mysql_update_log.write(thd, thd->query, thd->query_length);
2500 2501
	if (mysql_bin_log.is_open())
	{
unknown's avatar
unknown committed
2502
          thd->clear_error();
2503
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
2504 2505
	  mysql_bin_log.write(&qinfo);
	}
2506
	if (mqh_used && lex->sql_command == SQLCOM_GRANT)
2507
	{
unknown's avatar
unknown committed
2508 2509 2510
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
2511
	    reset_mqh(thd,user);
2512
	}
2513 2514 2515 2516
      }
    }
    break;
  }
unknown's avatar
unknown committed
2517
  case SQLCOM_FLUSH:
unknown's avatar
unknown committed
2518
  case SQLCOM_RESET:
unknown's avatar
unknown committed
2519
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
unknown's avatar
unknown committed
2520
      goto error;
2521 2522
    /* error sending is deferred to reload_acl_and_cache */
    reload_acl_and_cache(thd, lex->type, tables) ;
unknown's avatar
unknown committed
2523 2524 2525 2526 2527 2528
    break;
  case SQLCOM_KILL:
    kill_one_thread(thd,lex->thread_id);
    break;
  case SQLCOM_SHOW_GRANTS:
    res=0;
2529 2530
    if ((thd->priv_user &&
	 !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
2531
	!check_access(thd, SELECT_ACL, "mysql",0,1))
unknown's avatar
unknown committed
2532 2533 2534 2535
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
2536
  case SQLCOM_HA_OPEN:
2537 2538
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables))
2539 2540 2541 2542 2543 2544 2545 2546 2547
      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:
2548 2549 2550 2551 2552
    /*
      There is no need to check for table permissions here, because
      if a user has no permissions to read a table, he won't be
      able to open it (with SQLCOM_HA_OPEN) in the first place.
    */
unknown's avatar
unknown committed
2553
    if (check_db_used(thd,tables))
2554
      goto error;
unknown's avatar
unknown committed
2555
    res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
2556 2557
			lex->insert_list, lex->ha_rkey_mode, select_lex->where,
			select_lex->select_limit, select_lex->offset_limit);
2558 2559
    break;

unknown's avatar
unknown committed
2560
  case SQLCOM_BEGIN:
unknown's avatar
unknown committed
2561 2562 2563 2564 2565 2566
    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
2567 2568 2569 2570 2571 2572
    if (end_active_trans(thd))
    {
      res= -1;
    }
    else
    {
2573
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
unknown's avatar
unknown committed
2574 2575 2576 2577
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
      send_ok(&thd->net);
    }
unknown's avatar
unknown committed
2578 2579
    break;
  case SQLCOM_COMMIT:
2580 2581 2582 2583 2584
    /*
      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
2585
  {
2586
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
2587 2588
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
unknown's avatar
unknown committed
2589
    {
unknown's avatar
unknown committed
2590
      send_ok(&thd->net);
unknown's avatar
unknown committed
2591
    }
unknown's avatar
unknown committed
2592 2593 2594
    else
      res= -1;
    break;
unknown's avatar
unknown committed
2595
  }
unknown's avatar
unknown committed
2596 2597 2598
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
2599
    {
unknown's avatar
unknown committed
2600 2601 2602 2603 2604 2605 2606 2607 2608 2609
      /*
        If a non-transactional table was updated, warn; don't warn if this is a
        slave thread (because when a slave thread executes a ROLLBACK, it has
        been read from the binary log, so it's 100% sure and normal to produce
        error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
        slave SQL thread, it would not stop the thread but just be printed in
        the error log; but we don't want users to wonder why they have this
        message in the error log, so we don't send it.
      */
      if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
2610 2611 2612 2613
	send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
      else
	send_ok(&thd->net);
    }
unknown's avatar
unknown committed
2614 2615
    else
      res= -1;
2616
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
2617
    break;
unknown's avatar
unknown committed
2618 2619 2620
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
    if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
    {
unknown's avatar
unknown committed
2621
      if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
unknown's avatar
unknown committed
2622 2623 2624 2625 2626 2627 2628
	send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
      else
	send_ok(&thd->net);
    }
    else
      res= -1;
    break;
2629
  case SQLCOM_SAVEPOINT:
unknown's avatar
unknown committed
2630 2631 2632 2633
    if (!ha_savepoint(thd, lex->savepoint_name))
      send_ok(&thd->net);
    else
      res= -1;
2634
    break;
unknown's avatar
unknown committed
2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648
  default:					/* Impossible */
    send_ok(&thd->net);
    break;
  }
  thd->proc_info="query end";			// QQ
  if (res < 0)
    send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0);

error:
  DBUG_VOID_RETURN;
}


/****************************************************************************
unknown's avatar
unknown committed
2649
  Get the user (global) and database privileges for all used tables
unknown's avatar
unknown committed
2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662

  NOTES
    The idea of EXTRA_ACL is that one will be granted access to the table if
    one has the asked privilege on any column combination of the table; For
    example to be able to check a table one needs to have SELECT privilege on
    any column of the table.

  RETURN
    0  ok
    1  If we can't get the privileges and we don't use table/column grants.

    save_priv	In this we store global and db level grants for the table
		Note that we don't store db level grants if the global grants
unknown's avatar
unknown committed
2663 2664
                is enough to satisfy the request and the global grants contains
                a SELECT grant.
unknown's avatar
unknown committed
2665 2666 2667
****************************************************************************/

bool
unknown's avatar
unknown committed
2668
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
2669
	     bool dont_check_global_grants, bool no_errors)
unknown's avatar
unknown committed
2670
{
unknown's avatar
unknown committed
2671 2672 2673 2674
  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
2675 2676 2677 2678 2679
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

2680
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
2681
  {
2682 2683
    if (!no_errors)
      send_error(&thd->net,ER_NO_DB_ERROR);	/* purecov: tested */
unknown's avatar
unknown committed
2684
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
2685 2686 2687 2688
  }

  if ((thd->master_access & want_access) == want_access)
  {
2689 2690 2691 2692 2693 2694 2695 2696 2697
    /*
      If we don't have a global SELECT privilege, we have to get the database
      specific access rights to be able to handle queries of type
      UPDATE t1 SET a=1 WHERE b > 0
    */
    db_access= thd->db_access;
    if (!(thd->master_access & SELECT_ACL) &&
	(db && (!thd->db || strcmp(db,thd->db))))
      db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
2698
			thd->priv_user, db, 0); /* purecov: inspected */
2699
    *save_priv=thd->master_access | db_access;
unknown's avatar
unknown committed
2700
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
2701
  }
2702
  if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
2703
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
2704
  {						// We can never grant this
2705 2706 2707
    if (!no_errors)
      net_printf(&thd->net,ER_ACCESS_DENIED_ERROR,
		 thd->priv_user,
2708
		 thd->priv_host,
2709
		 thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
unknown's avatar
unknown committed
2710
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
2711 2712 2713
  }

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

unknown's avatar
unknown committed
2716 2717
  if (db && (!thd->db || strcmp(db,thd->db)))
    db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
2718
		      thd->priv_user, db, 0); /* purecov: inspected */
unknown's avatar
unknown committed
2719 2720
  else
    db_access=thd->db_access;
2721 2722
  // Remove SHOW attribute and access rights we already have
  want_access &= ~(thd->master_access | EXTRA_ACL);
unknown's avatar
unknown committed
2723
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
2724 2725

  /* grant_option is set if there exists a single table or column grant */
unknown's avatar
unknown committed
2726
  if (db_access == want_access ||
2727
      ((grant_option && !dont_check_global_grants) &&
2728
       !(want_access & ~(db_access | TABLE_ACLS))))
unknown's avatar
unknown committed
2729
    DBUG_RETURN(FALSE);				/* Ok */
2730 2731 2732
  if (!no_errors)
    net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
	       thd->priv_user,
2733
	       thd->priv_host,
2734
	       db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
unknown's avatar
unknown committed
2735
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
2736 2737 2738
}


2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756
/*
  check for global access and give descriptive error message if it fails

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

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

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

bool check_global_access(THD *thd, ulong want_access)
unknown's avatar
unknown committed
2759
{
unknown's avatar
unknown committed
2760
  char command[128];
2761
  if ((thd->master_access & want_access))
unknown's avatar
unknown committed
2762 2763 2764 2765 2766
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
  net_printf(&thd->net,ER_SPECIFIC_ACCESS_DENIED_ERROR,
	     command);
  return 1;
unknown's avatar
unknown committed
2767 2768 2769
}


unknown's avatar
unknown committed
2770
/*
unknown's avatar
unknown committed
2771 2772
  Check the privilege for all used tables.  Table privileges are cached
  in the table list for GRANT checking
unknown's avatar
unknown committed
2773 2774
*/

2775
bool
unknown's avatar
unknown committed
2776
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
2777
		   bool no_errors)
unknown's avatar
unknown committed
2778
{
unknown's avatar
unknown committed
2779 2780
  uint found=0;
  ulong found_access=0;
unknown's avatar
unknown committed
2781 2782 2783
  TABLE_LIST *org_tables=tables;
  for (; tables ; tables=tables->next)
  {
unknown's avatar
unknown committed
2784 2785
    if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
	thd->db)
unknown's avatar
unknown committed
2786
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
2787
    else if (tables->db && tables->db == thd->db)
unknown's avatar
unknown committed
2788 2789 2790 2791 2792
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
2793 2794
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
			 0, no_errors))
unknown's avatar
unknown committed
2795 2796
	  return TRUE;				// Access denied
	found_access=tables->grant.privilege;
unknown's avatar
unknown committed
2797
	found=1;
unknown's avatar
unknown committed
2798 2799
      }
    }
2800
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
2801
			  0, no_errors))
2802
      return TRUE;
unknown's avatar
unknown committed
2803 2804
  }
  if (grant_option)
2805
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
2806
		       test(want_access & EXTRA_ACL), no_errors);
unknown's avatar
unknown committed
2807 2808 2809 2810
  return FALSE;
}


2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822
static bool
check_one_table_access(THD *thd, ulong want_access, TABLE_LIST *table,
		       bool no_errors)
{
  if (check_access(thd, want_access, table->db, &table->grant.privilege, 0,
		   no_errors))
    return 1;
  return (grant_option && check_grant(thd, want_access, table, 0,
				      no_errors));
}


unknown's avatar
unknown committed
2823
static bool check_db_used(THD *thd,TABLE_LIST *tables)
unknown's avatar
unknown committed
2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839
{
  for (; tables ; tables=tables->next)
  {
    if (!tables->db)
    {
      if (!(tables->db=thd->db))
      {
	send_error(&thd->net,ER_NO_DB_ERROR);	/* purecov: tested */
	return TRUE;				/* purecov: tested */
      }
    }
  }
  return FALSE;
}


2840 2841
static bool check_merge_table_access(THD *thd, char *db,
				     TABLE_LIST *table_list)
2842 2843 2844 2845
{
  int error=0;
  if (table_list)
  {
2846
    /* Check that all tables use the current database */
2847 2848
    TABLE_LIST *tmp;
    for (tmp=table_list; tmp ; tmp=tmp->next)
2849 2850 2851
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
unknown's avatar
unknown committed
2852
      else if (strcmp(tmp->db,db))
2853 2854 2855 2856 2857
      {
	send_error(&thd->net,ER_UNION_TABLES_IN_DIFFERENT_DIR);
	return 1;
      }
    }
2858 2859 2860 2861 2862 2863 2864
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
			     table_list);
  }
  return error;
}


unknown's avatar
unknown committed
2865 2866 2867 2868 2869 2870 2871 2872 2873 2874
/****************************************************************************
	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

2875
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888
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));
    thd->fatal_error=1;
    return 1;
  }
  return 0;
}
2889
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2890 2891 2892 2893

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

2894
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
unknown's avatar
unknown committed
2895 2896
{
  LEX	*lex=current_lex;
2897
  ulong old_info=0;
unknown's avatar
unknown committed
2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923
  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;
}


/****************************************************************************
2924
	Initialize global thd variables needed for query
unknown's avatar
unknown committed
2925 2926 2927 2928 2929 2930
****************************************************************************/

static void
mysql_init_query(THD *thd)
{
  DBUG_ENTER("mysql_init_query");
2931
  thd->lex.select_lex.item_list.empty();
unknown's avatar
unknown committed
2932
  thd->lex.value_list.empty();
2933
  thd->lex.select_lex.table_list.elements=0;
unknown's avatar
unknown committed
2934
  thd->free_list=0;  thd->lex.union_option=0;
2935 2936 2937
  thd->lex.select = &thd->lex.select_lex;
  thd->lex.select_lex.table_list.first=0;
  thd->lex.select_lex.table_list.next= (byte**) &thd->lex.select_lex.table_list.first;
unknown's avatar
unknown committed
2938
  thd->lex.select_lex.next=0;
2939 2940 2941 2942 2943 2944
  /*
    select_lex.options is also inited in dispatch_command(), but for
    replication (which bypasses dispatch_command() and calls mysql_parse()
    directly) we must do it here.
  */
  thd->lex.select_lex.options=0;
2945
  thd->lex.olap=0;
2946
  thd->lex.select->olap= UNSPECIFIED_OLAP_TYPE;
unknown's avatar
unknown committed
2947 2948
  thd->fatal_error=0;				// Safety
  thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
unknown's avatar
unknown committed
2949
  thd->rand_used=0;
2950
  thd->sent_row_count=thd->examined_row_count=0;
2951
  thd->safe_to_cache_query=1;
unknown's avatar
unknown committed
2952 2953 2954
  DBUG_VOID_RETURN;
}

2955 2956 2957
void
mysql_init_select(LEX *lex)
{
2958 2959
  SELECT_LEX *select_lex = lex->select;
  select_lex->where=select_lex->having=0;
unknown's avatar
unknown committed
2960
  select_lex->select_limit= lex->thd->variables.select_limit;
unknown's avatar
unknown committed
2961
  select_lex->offset_limit=0;
unknown's avatar
unknown committed
2962 2963
  select_lex->options=0;
  select_lex->linkage=UNSPECIFIED_TYPE;
2964
  select_lex->olap=   UNSPECIFIED_OLAP_TYPE;
2965
  lex->exchange = 0;
2966
  lex->proc_list.first=0;
unknown's avatar
unknown committed
2967 2968
  select_lex->order_list.empty();
  select_lex->group_list.empty();
2969
  select_lex->next = (SELECT_LEX *)NULL; 
2970 2971
}

2972

unknown's avatar
unknown committed
2973
bool
2974 2975
mysql_new_select(LEX *lex)
{
2976
  SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX));
unknown's avatar
unknown committed
2977 2978
  if (!select_lex)
    return 1;
2979
  lex->select->next=select_lex; 
2980
  lex->select=select_lex;
unknown's avatar
unknown committed
2981
  select_lex->table_list.next= (byte**) &select_lex->table_list.first;
unknown's avatar
unknown committed
2982 2983 2984 2985 2986 2987 2988
  select_lex->item_list.empty();
  select_lex->when_list.empty(); 
  select_lex->expr_list.empty();
  select_lex->interval_list.empty(); 
  select_lex->use_index.empty();
  select_lex->ftfunc_list.empty();
  return 0;
2989
}
unknown's avatar
unknown committed
2990

2991

unknown's avatar
unknown committed
2992 2993 2994 2995
void mysql_init_multi_delete(LEX *lex)
{
  lex->sql_command =  SQLCOM_DELETE_MULTI;
  mysql_init_select(lex);
2996
  lex->select->select_limit=lex->thd->select_limit=HA_POS_ERROR;
2997
  lex->select->table_list.save_and_clear(&lex->auxilliary_table_list);
unknown's avatar
unknown committed
2998
}
unknown's avatar
unknown committed
2999

3000

3001 3002 3003 3004 3005
/*
  When you modify mysql_parse(), you may need to mofify
  mysql_test_parse_for_slave() in this same file.
*/
void mysql_parse(THD *thd, char *inBuf, uint length)
unknown's avatar
unknown committed
3006 3007 3008 3009
{
  DBUG_ENTER("mysql_parse");

  thd->query_length = length;
3010
  mysql_init_query(thd);
unknown's avatar
unknown committed
3011
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
unknown's avatar
unknown committed
3012 3013 3014 3015
  {
    LEX *lex=lex_start(thd, (uchar*) inBuf, length);
    if (!yyparse() && ! thd->fatal_error)
    {
3016 3017
      if (mqh_used && thd->user_connect &&
	  check_mqh(thd, thd->lex.sql_command))
3018 3019 3020 3021 3022 3023 3024 3025
      {
	thd->net.error = 0;
      }
      else
      {
	mysql_execute_command();
	query_cache_end_of_result(&thd->net);
      }
unknown's avatar
unknown committed
3026 3027
    }
    else
3028 3029 3030
    {
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
			 thd->fatal_error));
unknown's avatar
unknown committed
3031
      query_cache_abort(&thd->net);
3032
    }
unknown's avatar
unknown committed
3033 3034 3035 3036
    thd->proc_info="freeing items";
    free_items(thd);  /* Free strings used by items */
    lex_end(lex);
  }
unknown's avatar
unknown committed
3037 3038 3039
  DBUG_VOID_RETURN;
}

3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064
/*
  Usable by the replication SQL thread only: just parse a query to know if it
  can be ignored because of replicate-*-table rules.

  RETURN VALUES
    0	cannot be ignored
    1	can be ignored
*/

bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
{
  LEX *lex;
  bool error= 0;

  mysql_init_query(thd);
  lex= lex_start(thd, (uchar*) inBuf, length);
  if (!yyparse() && ! thd->fatal_error &&
      all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
    error= 1;                /* Ignore question */
  free_items(thd);  /* Free strings used by items */
  lex_end(lex);

  return error;
}

unknown's avatar
unknown committed
3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101

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

bool add_field_to_list(char *field_name, enum_field_types type,
		       char *length, char *decimals,
		       uint type_modifier, Item *default_value,char *change,
		       TYPELIB *interval)
{
  register create_field *new_field;
  THD	*thd=current_thd;
  LEX  *lex= &thd->lex;
  uint allowed_type_modifier=0;
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
    net_printf(&thd->net, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
    lex->key_list.push_back(new Key(Key::PRIMARY,NullS,
				    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));
    lex->key_list.push_back(new Key(Key::UNIQUE,NullS,
				    lex->col_list));
    lex->col_list.empty();
  }

3102
  if (default_value)
unknown's avatar
unknown committed
3103
  {
3104 3105 3106 3107 3108 3109
    /*
      We allow specifying value for first TIMESTAMP column 
      altough it is silently ignored. This should be fixed in 4.1
      (by proper warning or real support for default values)
    */
    if (default_value->type() == Item::NULL_ITEM)
unknown's avatar
unknown committed
3110
    {
3111 3112 3113 3114 3115 3116 3117 3118
      default_value=0;
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
	net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
	DBUG_RETURN(1);
      }
    }
3119
#ifdef MYSQL41000
3120 3121 3122
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
      net_printf(&thd->net, ER_INVALID_DEFAULT, field_name);
unknown's avatar
unknown committed
3123 3124
      DBUG_RETURN(1);
    }
3125
#endif
unknown's avatar
unknown committed
3126 3127 3128 3129 3130
  }
  if (!(new_field=new create_field()))
    DBUG_RETURN(1);
  new_field->field=0;
  new_field->field_name=field_name;
3131
#ifdef MYSQL41000
3132
  new_field->def= default_value;
3133 3134 3135
#else
  new_field->def= (type_modifier & AUTO_INCREMENT_FLAG ? 0 : default_value);
#endif
unknown's avatar
unknown committed
3136 3137 3138 3139 3140 3141 3142 3143 3144 3145
  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;
3146 3147
  if (length && !(new_field->length= (uint) atoi(length)))
    length=0; /* purecov: inspected */
unknown's avatar
unknown committed
3148 3149 3150
  uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;

  if (new_field->length && new_field->decimals &&
3151
      new_field->length < new_field->decimals+1 &&
unknown's avatar
unknown committed
3152
      new_field->decimals != NOT_FIXED_DEC)
3153
    new_field->length=new_field->decimals+1; /* purecov: inspected */
unknown's avatar
unknown committed
3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178

  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_STRING:
  case FIELD_TYPE_VAR_STRING:
  case FIELD_TYPE_NULL:
unknown's avatar
unknown committed
3179
  case FIELD_TYPE_GEOMETRY:
unknown's avatar
unknown committed
3180 3181 3182
    break;
  case FIELD_TYPE_DECIMAL:
    if (!length)
unknown's avatar
unknown committed
3183 3184
    {
      if ((new_field->length= new_field->decimals))
3185 3186
        new_field->length++;
      else
unknown's avatar
unknown committed
3187 3188
        new_field->length= 10;                  // Default length for DECIMAL
    }
3189 3190 3191 3192 3193 3194
    if (new_field->length < MAX_FIELD_WIDTH)	// Skip wrong argument
    {
      new_field->length+=sign_len;
      if (new_field->decimals)
	new_field->length++;
    }
unknown's avatar
unknown committed
3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253
    break;
  case FIELD_TYPE_BLOB:
  case FIELD_TYPE_TINY_BLOB:
  case FIELD_TYPE_LONG_BLOB:
  case FIELD_TYPE_MEDIUM_BLOB:
    if (default_value)				// Allow empty as default value
    {
      String str,*res;
      res=default_value->val_str(&str);
      if (res->length())
      {
	net_printf(&thd->net,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
	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)
      {
	net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name);
	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:
3254 3255 3256 3257 3258 3259 3260 3261 3262 3263
#if MYSQL_VERSION_ID < 40100
    /*
      When in in --new mode, we should create TIMESTAMP(19) fields by default;
      otherwise we will have problems with ALTER TABLE changing lengths of
      existing TIMESTAMP fields to 19 and adding new fields with length 14.
    */
    if (thd->variables.new_mode)
      new_field->length= 19;
    else if (!length)
#else
unknown's avatar
unknown committed
3264
    if (!length)
3265
#endif
unknown's avatar
unknown committed
3266
      new_field->length= 14;			// Full date YYYYMMDDHHMMSS
3267
    else if (new_field->length != 19)
unknown's avatar
unknown committed
3268
    {
3269 3270 3271 3272
      /*
        We support only even TIMESTAMP lengths less or equal than 14
        and 19 as length of 4.1 compatible representation.
      */
unknown's avatar
unknown committed
3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303
      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)
      {
	net_printf(&thd->net,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
	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
3304 3305 3306
      {
	new_field->length+=(uint) strip_sp((char*) *pos)+1;
      }
unknown's avatar
unknown committed
3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326
      new_field->length--;
      set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
      if (default_value)
      {
	thd->cuted_fields=0;
	String str,*res;
	res=default_value->val_str(&str);
	(void) find_set(interval,res->ptr(),res->length());
	if (thd->cuted_fields)
	{
	  net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
	  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
3327
      new_field->length=(uint) strip_sp((char*) interval->type_names[0]);
unknown's avatar
unknown committed
3328 3329
      for (const char **pos=interval->type_names+1; *pos ; pos++)
      {
unknown's avatar
unknown committed
3330
	uint length=(uint) strip_sp((char*) *pos);
unknown's avatar
unknown committed
3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349
	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()))
	{
	  net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
	  DBUG_RETURN(1);
	}
      }
      break;
    }
  }

  if (new_field->length >= MAX_FIELD_WIDTH ||
      (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
unknown's avatar
unknown committed
3350
       type != FIELD_TYPE_STRING && type != FIELD_TYPE_VAR_STRING))
unknown's avatar
unknown committed
3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380
  {
    net_printf(&thd->net,ER_TOO_BIG_FIELDLENGTH,field_name,
	       MAX_FIELD_WIDTH-1);		/* purecov: inspected */
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
    net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name);
    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
3381
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
3382 3383 3384 3385 3386 3387 3388 3389 3390 3391
{
  ORDER *order;
  Item	**item_ptr;

  if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
unknown's avatar
unknown committed
3392
  thd->lex.proc_list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
3393 3394 3395 3396 3397 3398 3399 3400
  return 0;
}


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

static void remove_escape(char *name)
{
3401 3402
  if (!*name)					// For empty DB names
    return;
unknown's avatar
unknown committed
3403 3404
  char *to;
#ifdef USE_MB
unknown's avatar
unknown committed
3405
  char *strend=name+(uint) strlen(name);
unknown's avatar
unknown committed
3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421
#endif
  for (to=name; *name ; name++)
  {
#ifdef USE_MB
    int l;
/*    if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
    if (use_mb(default_charset_info) &&
        (l = my_ismbchar(default_charset_info, name, strend)))
    {
	while (l--)
	    *to++ = *name++;
	name--;
	continue;
    }
#endif
    if (*name == '\\' && name[1])
unknown's avatar
unknown committed
3422
      name++;					// Skip '\\'
unknown's avatar
unknown committed
3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445
    *to++= *name;
  }
  *to=0;
}

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


bool add_to_list(SQL_LIST &list,Item *item,bool asc)
{
  ORDER *order;
  Item	**item_ptr;
  DBUG_ENTER("add_to_list");
  if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
    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
3446
  list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
3447 3448 3449 3450
  DBUG_RETURN(0);
}


3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469
/*
  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
3470
TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
3471 3472
			      ulong table_options,
			      thr_lock_type lock_type,
unknown's avatar
unknown committed
3473
			      List<String> *use_index,
3474
			      List<String> *ignore_index)
unknown's avatar
unknown committed
3475 3476 3477 3478 3479 3480 3481 3482 3483
{
  register TABLE_LIST *ptr;
  THD	*thd=current_thd;
  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
3484
  if (check_table_name(table->table.str,table->table.length) ||
3485
      table->db.str && check_db_name(table->db.str))
unknown's avatar
unknown committed
3486 3487 3488 3489 3490 3491
  {
    net_printf(&thd->net,ER_WRONG_TABLE_NAME,table->table.str);
    DBUG_RETURN(0);
  }

  if (!alias)					/* Alias is case sensitive */
3492
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
3493
      DBUG_RETURN(0);
unknown's avatar
unknown committed
3494
    
unknown's avatar
unknown committed
3495
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
3496
    DBUG_RETURN(0);				/* purecov: inspected */
3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512
  if (table->db.str) 
  {
    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
  {
    ptr->db= (char*) "";
    ptr->db_length= 0;
  }
    
3513
  ptr->alias= alias_str;
3514
  table_case_convert(table->table.str, table->table.length);
unknown's avatar
unknown committed
3515
  ptr->real_name=table->table.str;
3516
  ptr->real_name_length=table->table.length;
3517 3518 3519
  ptr->lock_type= lock_type;
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
3520
  if (use_index)
unknown's avatar
unknown committed
3521
    ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
unknown's avatar
unknown committed
3522 3523
					       sizeof(*use_index));
  if (ignore_index)
unknown's avatar
unknown committed
3524 3525
    ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index,
						   sizeof(*ignore_index));
unknown's avatar
unknown committed
3526 3527

  /* check that used name is unique */
3528
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
3529
  {
unknown's avatar
unknown committed
3530 3531
    for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ;
	 tables ;
unknown's avatar
unknown committed
3532
	 tables=tables->next)
unknown's avatar
unknown committed
3533
    {
3534
      if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
3535
      {
3536 3537
	net_printf(&thd->net,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
	DBUG_RETURN(0);				/* purecov: tested */
unknown's avatar
unknown committed
3538
      }
unknown's avatar
unknown committed
3539 3540
    }
  }
unknown's avatar
unknown committed
3541
  thd->lex.select->table_list.link_in_list((byte*) ptr,(byte**) &ptr->next);
unknown's avatar
unknown committed
3542 3543 3544
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
3545 3546 3547 3548 3549 3550 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
/*
  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
*/

void set_lock_for_tables(thr_lock_type lock_type)
{
  THD	*thd=current_thd;
  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));

  for (TABLE_LIST *tables= (TABLE_LIST*) thd->lex.select->table_list.first ;
       tables ;
       tables=tables->next)
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
3576 3577 3578 3579 3580 3581 3582

/*
** This is used for UNION to create a new table list of all used tables
** The table_list->table entry in all used tables are set to point
** to the entries in this list.
*/

3583 3584
static bool create_total_list(THD *thd, LEX *lex,
			      TABLE_LIST **result, bool skip_first)
3585
{
3586 3587 3588 3589 3590 3591 3592
  /* Handle the case when we are not using union */
  if (!lex->select_lex.next)
  {
    *result= (TABLE_LIST*) lex->select_lex.table_list.first;
    return 0;
  }

3593
  /* We should skip first table if SQL command is SQLCOM_CREATE_TABLE */
unknown's avatar
unknown committed
3594 3595
  SELECT_LEX *sl;
  TABLE_LIST **new_table_list= result, *aux;
unknown's avatar
unknown committed
3596

unknown's avatar
unknown committed
3597
  *new_table_list=0;				// end result list
3598
  for (sl= &lex->select_lex; sl; sl=sl->next)
3599
  {
3600
    if (sl->order_list.first && sl->next && !sl->braces)
3601
    {
unknown's avatar
unknown committed
3602 3603
      net_printf(&thd->net,ER_WRONG_USAGE,"UNION","ORDER BY");
      return 1;
3604
    }
3605
    if ((aux= (TABLE_LIST*) sl->table_list.first))
3606
    {
unknown's avatar
unknown committed
3607 3608
      TABLE_LIST *next;
      for (; aux; aux=next)
3609
      {
3610
	TABLE_LIST *cursor= *result;
3611
	if (skip_first && cursor)
3612
	  cursor= cursor->next;
unknown's avatar
unknown committed
3613
	next= aux->next;
3614
	for ( ; cursor; cursor=cursor->next)
unknown's avatar
unknown committed
3615
	  if (!strcmp(cursor->db,aux->db) &&
3616
	      !strcmp(cursor->real_name,aux->real_name) &&
3617
	      !strcmp(cursor->alias, aux->alias))
unknown's avatar
unknown committed
3618 3619 3620 3621
	    break;
	if (!cursor)
	{
	  /* Add not used table to the total table list */
unknown's avatar
unknown committed
3622
	  if (!(cursor = (TABLE_LIST *) thd->memdup((char*) aux,
unknown's avatar
unknown committed
3623
						    sizeof(*aux))))
unknown's avatar
unknown committed
3624 3625 3626 3627
	  {
	    send_error(&thd->net,0);
	    return 1;
	  }
unknown's avatar
unknown committed
3628 3629
	  *new_table_list= cursor;
	  new_table_list= &cursor->next;
3630
	  *new_table_list=0;			// end result list
unknown's avatar
unknown committed
3631
	}
3632 3633
	else
	  aux->shared=1;			// Mark that it's used twice
unknown's avatar
unknown committed
3634
	aux->table= my_reinterpret_cast(TABLE *) (cursor);
3635 3636 3637
      }
    }
  }
unknown's avatar
unknown committed
3638
  return 0;
3639 3640
}

unknown's avatar
unknown committed
3641

unknown's avatar
unknown committed
3642 3643
void add_join_on(TABLE_LIST *b,Item *expr)
{
3644
  if (expr)
3645
  {
3646 3647 3648 3649 3650 3651 3652 3653
    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();
3654
  }
unknown's avatar
unknown committed
3655 3656 3657
}


3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675
/*
  Mark that we have a NATURAL JOIN between two tables

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

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

unknown's avatar
unknown committed
3676 3677 3678 3679 3680 3681 3682
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
{
  b->natural_join=a;
}

	/* Check if name is used in table list */

3683
bool check_dup(const char *db, const char *name, TABLE_LIST *tables)
unknown's avatar
unknown committed
3684 3685
{
  for (; tables ; tables=tables->next)
3686
    if (!strcmp(name,tables->real_name) && !strcmp(db,tables->db))
unknown's avatar
unknown committed
3687 3688 3689 3690
      return 1;
  return 0;
}

3691 3692 3693 3694 3695

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

unknown's avatar
unknown committed
3696
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
unknown's avatar
unknown committed
3697 3698
{
  bool result=0;
3699
  bool error_already_sent=0;
unknown's avatar
unknown committed
3700 3701 3702
  select_errors=0;				/* Write if more errors */
  if (options & REFRESH_GRANT)
  {
3703
    acl_reload(thd);
unknown's avatar
unknown committed
3704
    grant_reload(thd);
3705
    if (mqh_used)
3706
      reset_mqh(thd,(LEX_USER *) NULL,true);
unknown's avatar
unknown committed
3707 3708 3709
  }
  if (options & REFRESH_LOG)
  {
3710
    /*
3711 3712
      Flush the normal query log, the update log, the binary log,
      the slow query log, and the relay log (if it exists).
3713
    */
unknown's avatar
unknown committed
3714 3715 3716 3717
    mysql_log.new_file(1);
    mysql_update_log.new_file(1);
    mysql_bin_log.new_file(1);
    mysql_slow_log.new_file(1);
3718
    pthread_mutex_lock(&LOCK_active_mi);
3719
    rotate_relay_log(active_mi);
3720
    pthread_mutex_unlock(&LOCK_active_mi);
3721

unknown's avatar
unknown committed
3722 3723
    if (ha_flush_logs())
      result=1;
unknown's avatar
unknown committed
3724 3725
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
3726
  }
unknown's avatar
unknown committed
3727
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
3728 3729
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
3730
    query_cache.pack();				// FLUSH QUERY CACHE
unknown's avatar
unknown committed
3731 3732 3733 3734
    options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
3735
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
3736
  }
unknown's avatar
unknown committed
3737
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
3738 3739
  if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
  {
3740
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
3741
    {
3742 3743
      if (lock_global_read_lock(thd))
	return 1;
3744 3745 3746
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
                                 tables);
      make_global_read_lock_block_commit(thd);
unknown's avatar
unknown committed
3747
    }
3748 3749
    else
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
unknown's avatar
unknown committed
3750 3751 3752 3753 3754 3755 3756 3757
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
  if (options & REFRESH_STATUS)
    refresh_status();
  if (options & REFRESH_THREADS)
    flush_thread_cache();
  if (options & REFRESH_MASTER)
3758 3759
    if (reset_master(thd))
      result=1;
unknown's avatar
unknown committed
3760
#ifdef OPENSSL
3761 3762 3763 3764 3765 3766
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
3767 3768
 if (options & REFRESH_SLAVE)
 {
3769
   pthread_mutex_lock(&LOCK_active_mi);
3770
   if (reset_slave(thd, active_mi))
3771
   {
3772
     result=1;
3773 3774 3775 3776 3777 3778 3779 3780
     /*
       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;
   }
3781
   pthread_mutex_unlock(&LOCK_active_mi);
3782 3783
 }
 if (options & REFRESH_USER_RESOURCES)
3784
   reset_mqh(thd,(LEX_USER *) NULL);
3785 3786 3787 3788 3789 3790 3791 3792 3793

 if (thd && !error_already_sent)
 {
   if (result)
     send_error(&thd->net,0);
   else
     send_ok(&thd->net);
 }

3794
 return result;
unknown's avatar
unknown committed
3795 3796 3797
}


3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809
/*
  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
*/

3810
void kill_one_thread(THD *thd, ulong id)
unknown's avatar
unknown committed
3811 3812 3813
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
3814 3815
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
3816 3817 3818 3819
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
3820 3821
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
3822 3823 3824
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837
  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
3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857
  if (!error)
    send_ok(&thd->net);
  else
    net_printf(&thd->net,error,id);
}

/* 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);
}
3858 3859 3860 3861


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

unknown's avatar
unknown committed
3862 3863
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
			       const char *table_name)
3864
{
3865
  char buff[FN_REFLEN],*ptr, *end;
3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877
  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);
3878
  end=convert_dirname(buff, *filename_ptr, NullS);
unknown's avatar
unknown committed
3879
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
3880 3881
    return 1;					// End of memory
  *filename_ptr=ptr;
3882
  strxmov(ptr,buff,table_name,NullS);
3883 3884
  return 0;
}
3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909

/*
  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;
  if (thd->lex.select != &thd->lex.select_lex)
  {
    char command[80];
    strmake(command, thd->lex.yylval->symbol.str,
	    min(thd->lex.yylval->symbol.length, sizeof(command)-1));
    net_printf(&thd->net, ER_CANT_USE_OPTION_HERE, command);
    return 1;
  }
  return 0;
}