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

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

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

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

#include "mysql_priv.h"
#include "sql_acl.h"
19
#include "sql_repl.h"
20
#include "repl_failsafe.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
21 22 23
#include <m_ctype.h>
#include <myisam.h>
#include <my_dir.h>
24
#include <assert.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
25

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

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

49 50 51 52
#define MEM_ROOT_BLOCK_SIZE       8192
#define MEM_ROOT_PREALLOC         8192
#define TRANS_MEM_ROOT_BLOCK_SIZE 4096
#define TRANS_MEM_ROOT_PREALLOC   4096
53

bk@work.mysql.com's avatar
bk@work.mysql.com committed
54 55
extern int yyparse(void);
extern "C" pthread_mutex_t THR_LOCK_keycache;
56 57 58
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
59

60 61
static int check_for_max_user_connections(USER_CONN *uc);
static void decrease_user_connections(USER_CONN *uc);
62
static bool check_db_used(THD *thd,TABLE_LIST *tables);
63
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
64
static bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
65 66 67
static void mysql_init_query(THD *thd);
static void remove_escape(char *name);
static void refresh_status(void);
68 69
static bool append_file_to_dir(THD *thd, char **filename_ptr,
			       char *table_name);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
70
static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
71

72
const char *any_db="*any*";	// Special symbol for check_access
bk@work.mysql.com's avatar
bk@work.mysql.com committed
73 74 75 76 77

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",
78 79
  "Binlog Dump","Table Dump",  "Connect Out", "Register Slave",
  "Error"					// Last command number
bk@work.mysql.com's avatar
bk@work.mysql.com committed
80 81 82 83 84 85 86
};

bool volatile abort_slave = 0;

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

103 104 105 106 107 108 109 110 111 112 113
static void unlock_locked_tables(THD *thd)
{
  if (thd->locked_tables)
  {
    thd->lock=thd->locked_tables;
    thd->locked_tables=0;			// Will be automaticly closed
    close_thread_tables(thd);			// Free tables
  }
}

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


128 129 130
static HASH hash_user_connections;
extern  pthread_mutex_t LOCK_user_conn;

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

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

143 144 145
  user_len=strlen(user);
  host_len=strlen(host);
  temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
146
  (void) pthread_mutex_lock(&LOCK_user_conn);
147 148
  if (!(uc = (struct  user_conn *) hash_search(&hash_user_connections,
					       (byte*) temp_user, temp_len)))
149
  {
150 151 152
    /* First connection for user; Create a user connection object */
    if (!(uc= ((struct user_conn*)
	       my_malloc(sizeof(struct user_conn) + temp_len+1,
153 154
			 MYF(MY_WME)))))
    {
155 156 157
      send_error(&current_thd->net, 0, NullS);	// Out of memory
      return_val=1;
      goto end;
158
    }
159 160
    uc->user=(char*) (uc+1);
    memcpy(uc->user,temp_user,temp_len+1);
161 162
    uc->user_len= user_len;
    uc->host=uc->user + uc->user_len +  1;
163
    uc->len = temp_len;
164 165 166
    uc->connections = 1;
    uc->questions=uc->updates=uc->conn_per_hour=0;
    uc->user_resources=*mqh;
167
    if (max_user_connections && mqh->connections > max_user_connections) 
168
      uc->user_resources.connections = max_user_connections;
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
    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;
end:
  (void) pthread_mutex_unlock(&LOCK_user_conn);
  return return_val;
 
}
184 185 186


/*
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
187 188
  Check if user is ok
  Updates:
189
  thd->{user,master_access,priv_user,priv_host,db,db_access}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
190 191 192 193 194 195 196
*/

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;
197
  thd->db_length=0;
198
  USER_RESOURCES ur;
199
  char tmp_passwd[SCRAMBLE_LENGTH + 1];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
200

201 202
  if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH)
    return 1;
203 204 205 206 207 208 209
  /*
    Move password to temporary buffer as it may be stored in communication
    buffer
  */
  strmov(tmp_passwd, passwd);
  passwd= tmp_passwd;				// Use local copy

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

280

281
/*
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
282 283
  Check for maximum allowable user connections, if the mysqld server is
  started with corresponding variable that is greater then 0.
284 285
*/

286 287
extern "C" byte *get_key_conn(user_conn *buff, uint *length,
			      my_bool not_used __attribute__((unused)))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
288 289 290 291 292
{
  *length=buff->len;
  return (byte*) buff->user;
}

293
extern "C" void free_user(struct user_conn *uc)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
294 295 296 297
{
  my_free((char*) uc,MYF(0));
}

298 299
void init_max_user_conn(void) 
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
300
  (void) hash_init(&hash_user_connections,max_connections,0,0,
301
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
302
		   0);
303 304 305
}


306
static int check_for_max_user_connections(USER_CONN *uc)
307
{
308
  int error=0;
309
  DBUG_ENTER("check_for_max_user_connections");
310
  
311
  if (max_user_connections &&
312
      (max_user_connections <  (uint) uc->connections))
313
  {
314 315 316
    net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, uc->user);
    error=1;
    goto end;
317
  }
318
  uc->connections++; 
319 320
  if (uc->user_resources.connections &&
      uc->conn_per_hour++ >= uc->user_resources.connections)
321
  {
322 323
    net_printf(&current_thd->net, ER_USER_LIMIT_REACHED, uc->user,
	       "max_connections",
324 325 326 327
	       (long) uc->user_resources.connections);
    error=1;
    goto end;
  }
328 329
end:
  DBUG_RETURN(error);
330 331 332
}


333
static void decrease_user_connections(USER_CONN *uc)
334
{
335
  DBUG_ENTER("decrease_user_connections");
336
  if ((uc->connections && !--uc->connections) && !mqh_used)
337 338
  {
    /* Last connection for user; Delete it */
339
    (void) pthread_mutex_lock(&LOCK_user_conn);
340
    (void) hash_delete(&hash_user_connections,(byte*) uc);
341
    (void) pthread_mutex_unlock(&LOCK_user_conn);
342
  }
343
  DBUG_VOID_RETURN;
344 345
}

346

347 348 349 350 351
void free_max_user_conn(void)
{
  hash_free(&hash_user_connections);
}

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
352

353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
/*
  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;
}


monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
385 386 387
/*
  Check if maximum queries per hour limit has been reached
  returns 0 if OK.
388

389 390 391
  In theory we would need a mutex in the USER_CONN structure for this to
  be 100 % safe, but as the worst scenario is that we would miss counting
  a couple of queries, this isn't critical.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
392 393
*/

394

395
static bool check_mqh(THD *thd, uint check_command)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
396 397
{
  bool error=0;
398
  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
399
  USER_CONN *uc=thd->user_connect;
400
  DBUG_ENTER("check_mqh");
401
  DBUG_ASSERT(uc != 0);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
402

403
  /* If more than a hour since last check, reset resource checking */
404 405 406 407 408 409 410 411 412
  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);
  }
413
  /* Check that we have not done too many questions / hour */
414 415 416 417 418 419 420 421
  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;
  }
422
  if (check_command < (uint) SQLCOM_END)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
423
  {
424 425 426 427 428 429 430 431 432
    /* 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;
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
433 434
  }
end:
435
  DBUG_RETURN(error);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
436 437
}

438

439
static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
440 441
{

442
  (void) pthread_mutex_lock(&LOCK_user_conn);
443 444
  if (lu)  // for GRANT 
  {
445
    USER_CONN *uc;
446
    uint temp_len=lu->user.length+lu->host.length+2;
447 448
    char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];

449 450
    memcpy(temp_user,lu->user.str,lu->user.length);
    memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
451
    temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
452
    if ((uc = (struct  user_conn *) hash_search(&hash_user_connections,
453
						(byte*) temp_user, temp_len)))
454 455
    {
      uc->questions=0;
456
      get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
457 458
      uc->updates=0;
      uc->conn_per_hour=0;
459 460
    }
  }
461
  else // for FLUSH PRIVILEGES and FLUSH USER_RESOURCES
462
  {
463
    for (uint idx=0;idx < hash_user_connections.records; idx++)
464
    {
465 466 467 468 469 470
      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;
471 472
    }
  }
473
  (void) pthread_mutex_unlock(&LOCK_user_conn);
474
}
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
475

476

bk@work.mysql.com's avatar
bk@work.mysql.com committed
477
/*
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
478 479
  Check connnetion and get priviliges
  Returns 0 on ok, -1 < if error is given > 0 on error.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
480 481 482 483 484 485 486
*/

static int
check_connections(THD *thd)
{
  uint connect_errors=0;
  NET *net= &thd->net;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
487
  /* Store the connection details */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
488 489
  DBUG_PRINT("info", (("check_connections called by thread %d"),
	     thd->thread_id));
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
490
  DBUG_PRINT("info",("New connection received on %s",
bk@work.mysql.com's avatar
bk@work.mysql.com committed
491 492 493
			vio_description(net->vio)));
  if (!thd->host)                           // If TCP/IP connection
  {
494
    char ip[30];
495

496
    if (vio_peer_addr(net->vio, ip, &thd->peer_port))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
497 498 499
      return (ER_BAD_HOST_ERROR);
    if (!(thd->ip = my_strdup(ip,MYF(0))))
      return (ER_OUT_OF_RESOURCES);
500
    thd->host_or_ip=thd->ip;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
501 502 503
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
    /* Fast local hostname resolve for Win32 */
    if (!strcmp(thd->ip,"127.0.0.1"))
504 505 506 507
    {
      thd->host= (char*) localhost;
      thd->host_or_ip= localhost;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
508 509 510 511 512 513
    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);
514
      /* Cut very long hostnames to avoid possible overflows */
515
      if (thd->host)
516
      {
517
	thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
518 519
	thd->host_or_ip= thd->host;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
520 521 522
      if (connect_errors > max_connect_errors)
	return(ER_HOST_IS_BLOCKED);
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
523 524 525
    DBUG_PRINT("info",("Host: %s  ip: %s",
		       thd->host ? thd->host : "unknown host",
		       thd->ip ? thd->ip : "unknown ip"));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
526 527 528
    if (acl_check_host(thd->host,thd->ip))
      return(ER_HOST_NOT_PRIVILEGED);
  }
529
  else /* Hostname given means that the connection was on a socket */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
530
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
531
    DBUG_PRINT("info",("Host: %s",thd->host));
532 533
    thd->host_or_ip= thd->host;
    thd->ip= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
534 535
    bzero((char*) &thd->remote,sizeof(struct sockaddr));
  }
536
  /* Ensure that wrong hostnames doesn't cause buffer overflows */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
537 538
  vio_keepalive(net->vio, TRUE);

539
  ulong pkt_len=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
540
  {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
541 542
    /* buff[] needs to big enough to hold the server_version variable */
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+32],*end;
543
    int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB;
544

545 546 547 548 549
    if (opt_using_transactions)
      client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
    client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
550 551 552 553
#ifdef HAVE_OPENSSL
    if (ssl_acceptor_fd)
      client_flags |= CLIENT_SSL;       /* Wow, SSL is avalaible! */
#endif /* HAVE_OPENSSL */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
554

555
    end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
556 557 558 559 560
    int4store((uchar*) end,thd->thread_id);
    end+=4;
    memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
    end+=SCRAMBLE_LENGTH +1;
    int2store(end,client_flags);
561
    end[2]=(char) MY_CHARSET_CURRENT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
562 563 564
    int2store(end+3,thd->server_status);
    bzero(end+5,13);
    end+=18;
565
    if (net_write_command(net,(uchar) protocol_version, buff,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
566
			  (uint) (end-buff)) ||
567
       (pkt_len= my_net_read(net)) == packet_error ||
bk@work.mysql.com's avatar
bk@work.mysql.com committed
568 569 570 571 572 573 574 575 576 577 578
	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);
579
  if (thd->packet.alloc(thd->variables.net_buffer_length))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
580 581 582
    return(ER_OUT_OF_RESOURCES);

  thd->client_capabilities=uint2korr(net->read_pos);
583 584
  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
    thd->sql_mode|= MODE_IGNORE_SPACE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
585
#ifdef HAVE_OPENSSL
586
  DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
587 588 589
  if (thd->client_capabilities & CLIENT_SSL)
  {
    /* Do the SSL layering. */
590 591 592 593 594
    if (!ssl_acceptor_fd)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
595
    DBUG_PRINT("info", ("IO layer change in progress..."));
596 597 598 599 600 601 602
    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);    
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
603 604 605 606
    DBUG_PRINT("info", ("Reading user information over SSL layer"));
    if ((pkt_len=my_net_read(net)) == packet_error ||
	pkt_len < NORMAL_HANDSHAKE_SIZE)
    {
607 608
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
      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

624
  thd->max_client_packet_length=uint3korr(net->read_pos+2);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
625 626 627 628 629 630
  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)
631
    thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
632 633
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
      opt_using_transactions)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
634
    thd->net.return_status= &thd->server_status;
635
  net->read_timeout=(uint) thd->variables.net_read_timeout;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
636 637 638 639 640 641 642 643 644 645
  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  =
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
646
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
647 648 649 650 651
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status );

  pthread_detach_this_thread();

652 653
#if !defined( __WIN__) && !defined(OS2)	// Win32 calls this in pthread_create
  // The following calls needs to be done before we call DBUG_ macros
654
  if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
655 656
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
657
    statistic_increment(aborted_connects,&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
658 659 660 661 662
    end_thread(thd,0);
    return 0;
  }
#endif

663 664 665 666 667 668 669
  /*
    handle_one_connection() is the only way a thread would start
    and would always be on top of the stack, therefore, the thread
    stack always starts at the address of the first local variable
    of handle_one_connection, which is thd. We need to know the
    start of the stack so that we could check for stack overruns.
  */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
670 671 672 673
  DBUG_PRINT("info", ("handle_one_connection called by thread %d\n",
		      thd->thread_id));
  // now that we've called my_thread_init(), it is safe to call DBUG_*

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

714
    thd->proc_info=0;				// Remove 'login'
715
    thd->command=COM_SLEEP;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
716 717
    thd->version=refresh_version;
    thd->set_time();
718 719 720
    init_sql_alloc(&thd->mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
    init_sql_alloc(&thd->transaction.mem_root,
		   TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
721 722 723 724 725
    while (!net->error && net->vio != 0 && !thd->killed)
    {
      if (do_command(thd))
	break;
    }
726 727
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
728
    free_root(&thd->mem_root,MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
729 730
    if (net->error && net->vio != 0)
    {
731
      if (!thd->killed && thd->variables.log_warnings)
732 733 734 735 736 737
	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)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
738
      send_error(net,net->last_errno,NullS);
739
      statistic_increment(aborted_threads,&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
740
    }
741 742 743 744
    else if (thd->killed)
    {
      statistic_increment(aborted_threads,&LOCK_status);
    }
745
    
bk@work.mysql.com's avatar
bk@work.mysql.com committed
746 747 748 749 750 751 752 753 754 755 756 757 758
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 */
}

759 760 761 762
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
763

764
extern "C" pthread_handler_decl(handle_bootstrap,arg)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
765
{
766 767 768
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
769

770
  /* The following must be called before DBUG_ENTER */
771
  if (my_thread_init() || thd->store_globals())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
772 773
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
774 775
    thd->fatal_error=1;
    goto end;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
776
  }
777 778 779 780
  DBUG_ENTER("handle_bootstrap");

  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
781
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
782
  sigset_t set;
783 784
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
785 786
#endif

787
  if (thd->variables.max_join_size == HA_POS_ERROR)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
788 789 790 791
    thd->options |= OPTION_BIG_SELECTS;

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

794
  buff= (char*) thd->net.buff;
795 796 797
  init_sql_alloc(&thd->mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
  init_sql_alloc(&thd->transaction.mem_root,
		 TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
798 799
  while (fgets(buff, thd->net.max_packet, file))
  {
800
    uint length=(uint) strlen(buff);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
801 802 803 804
    while (length && (isspace(buff[length-1]) || buff[length-1] == ';'))
      length--;
    buff[length]=0;
    thd->current_tablenr=0;
805
    thd->query_length=length;
806 807
    thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
    thd->query[length] = '\0';
bk@work.mysql.com's avatar
bk@work.mysql.com committed
808
    thd->query_id=query_id++;
809
    if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
810 811 812 813 814 815
    {
      thd->net.error = 0;
      close_thread_tables(thd);			// Free tables
      free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
      break;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
816 817 818
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
    if (thd->fatal_error)
819
      break;
820
    free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
821
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
822
  }
823 824 825 826 827 828

  /* 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);
829
  (void) pthread_cond_broadcast(&COND_thread_count);
830 831 832
  my_thread_end();
  pthread_exit(0);
  DBUG_RETURN(0);				// Never reached
bk@work.mysql.com's avatar
bk@work.mysql.com committed
833 834 835
}


836
inline void free_items(THD *thd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
837 838 839 840 841 842 843 844 845 846 847 848 849
{
    /* 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;
850
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
851
    DBUG_RETURN(1); // out of memory
bk@work.mysql.com's avatar
bk@work.mysql.com committed
852
  table_list->db = db;
853
  table_list->real_name = table_list->alias = tbl_name;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
854 855 856
  table_list->lock_type = TL_READ_NO_INSERT;
  table_list->next = 0;

857 858 859 860 861
  if (!db || check_db_name(db))
  {
    net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
    goto err;
  }
862 863 864 865 866 867 868
  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);

869
  if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
870
    goto err;
871
  if (grant_option && check_grant(thd, SELECT_ACL, table_list))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
872 873 874
    goto err;

  thd->free_list = 0;
875
  thd->query_length=(uint) strlen(tbl_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
876
  thd->query = tbl_name;
877 878 879 880 881
  if ((error = mysqld_dump_create_info(thd, table, -1)))
  {
    my_error(ER_GET_ERRNO, MYF(0));
    goto err;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
882
  net_flush(&thd->net);
883
  if ((error= table->file->dump(thd,fd)))
884
    my_error(ER_GET_ERRNO, MYF(0));
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
885

bk@work.mysql.com's avatar
bk@work.mysql.com committed
886 887
err:
  close_thread_tables(thd);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
888
  DBUG_RETURN(error);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
889 890 891 892 893 894 895 896
}


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

bool do_command(THD *thd)
{
  char *packet;
897 898
  uint old_timeout;
  ulong packet_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
899 900 901 902 903 904 905 906
  NET *net;
  enum enum_server_command command;
  DBUG_ENTER("do_command");

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

  packet=0;
907 908 909
  old_timeout=net->read_timeout;
  // Wait max for 8 hours
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
910 911 912 913 914 915
  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)
  {
916 917 918 919 920
    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)
921 922
    {
      statistic_increment(aborted_threads,&LOCK_status);
923
      DBUG_RETURN(TRUE);			// We have to close it.
924
    }
925
    send_error(net,net->last_errno,NullS);
926
    net->error= 0;
927 928
    DBUG_RETURN(FALSE);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
929 930 931 932
  else
  {
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
933 934
    if (command >= COM_END)
      command= COM_END;				// Wrong command
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
935 936 937
    DBUG_PRINT("info",("Command on %s = %d (%s)",
		       vio_description(net->vio), command,
		       command_name[command]));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
938
  }
939
  net->read_timeout=old_timeout;		// restore it
940
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
941 942 943 944 945 946 947 948
}


bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
  bool	error=0;
949 950 951 952
  /*
    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
  */
953 954 955
  bool slow_command=FALSE;
  DBUG_ENTER("dispatch_command");

bk@work.mysql.com's avatar
bk@work.mysql.com committed
956
  thd->command=command;
957
  thd->set_time();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
958 959 960 961 962 963
  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));
964

965
  thd->lex.select_lex.options=0;		// We store status here
966
  switch (command) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
967
  case COM_INIT_DB:
968
    statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
969
    if (!mysql_change_db(thd,packet))
970
      mysql_log.write(thd,command,"%s",thd->db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
971
    break;
972 973
  case COM_REGISTER_SLAVE:
  {
974
    if (!register_slave(thd, (uchar*)packet, packet_length))
975 976 977
      send_ok(&thd->net);
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
978 979
  case COM_TABLE_DUMP:
    {
980
      statistic_increment(com_other, &LOCK_status);
981
      slow_command = TRUE;
982 983
      uint db_len = *(uchar*)packet;
      uint tbl_len = *(uchar*)(packet + db_len + 1);
984
      char* db = thd->alloc(db_len + tbl_len + 2);
985
      memcpy(db, packet + 1, db_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
986 987
      char* tbl_name = db + db_len;
      *tbl_name++ = 0;
988
      memcpy(tbl_name, packet + db_len + 2, tbl_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
989
      tbl_name[tbl_len] = 0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
990
      if (mysql_table_dump(thd, db, tbl_name, -1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
991 992 993 994 995
	send_error(&thd->net); // dump to NET
      break;
    }
  case COM_CHANGE_USER:
  {
996 997 998 999
    thd->change_user();
    clear_error_message(thd);			// If errors from rollback

    statistic_increment(com_other,&LOCK_status);
1000
    char *user=   (char*) packet;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1001 1002 1003 1004 1005 1006
    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;
1007
    uint save_db_length=    thd->db_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1008 1009 1010
    char *save_user=	    thd->user;
    char *save_priv_user=   thd->priv_user;
    char *save_db=	    thd->db;
1011
    thd->user=0;
1012
    USER_CONN *save_uc=            thd->user_connect;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1013 1014 1015 1016 1017 1018

    if ((uint) ((uchar*) db - net->read_pos) > packet_length)
    {						// Check if protocol is ok
      send_error(net, ER_UNKNOWN_COM_ERROR);
      break;
    }
1019
    if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1020 1021 1022 1023 1024
    {						// Restore old user
      x_free(thd->user);
      thd->master_access=save_master_access;
      thd->db_access=save_db_access;
      thd->db=save_db;
1025
      thd->db_length=save_db_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1026 1027 1028 1029
      thd->user=save_user;
      thd->priv_user=save_priv_user;
      break;
    }
1030
    if (max_connections && save_uc)
1031
      decrease_user_connections(save_uc);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1032 1033 1034 1035 1036 1037 1038
    x_free((gptr) save_db);
    x_free((gptr) save_user);
    break;
  }

  case COM_QUERY:
  {
1039 1040 1041 1042 1043 1044 1045 1046
    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
1047
    while (packet_length > 0 && (pos[-1] == ';' || isspace(pos[-1])))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1048 1049 1050 1051
    {
      pos--;
      packet_length--;
    }
1052
    /* We must allocate some extra memory for query cache */
1053
    if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
1054
						packet_length,
1055 1056
						thd->db_length+2+
						sizeof(ha_rows))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1057
      break;
1058
    thd->query[packet_length]=0;
1059
    thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1060 1061
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),QUERY_PRIOR);
1062
    mysql_log.write(thd,command,"%s",thd->query);
1063
    DBUG_PRINT("query",("%-.4096s",thd->query));
1064 1065
    /* thd->query_length is set by mysql_parse() */
    mysql_parse(thd,thd->query,packet_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1066 1067 1068 1069 1070
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1071
  case COM_FIELD_LIST:				// This isn't actually needed
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1072 1073 1074 1075 1076 1077 1078
#ifdef DONT_ALLOW_SHOW_COMMANDS
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
    break;
#else
  {
    char *fields;
    TABLE_LIST table_list;
1079
    statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1080 1081 1082 1083 1084 1085 1086
    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;
1087
    table_list.alias= table_list.real_name= thd->strdup(packet);
1088
    packet=strend(packet)+1;
1089
    // command not cachable => no gap for data base name
1090 1091
    if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
      break;
1092
    mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
1093 1094
    if (lower_case_table_names)
      casedn_str(table_list.real_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
    remove_escape(table_list.real_name);	// This can't have wildcards

    if (check_access(thd,SELECT_ACL,table_list.db,&thd->col_access))
      break;
    table_list.grant.privilege=thd->col_access;
    if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2))
      break;
    mysqld_list_fields(thd,&table_list,fields);
    free_items(thd);
    break;
  }
#endif
  case COM_QUIT:
1108
    /* We don't calculate statistics for this command */
1109
    mysql_log.write(thd,command,NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1110 1111 1112 1113
    net->error=0;				// Don't give 'abort' message
    error=TRUE;					// End server
    break;

1114
  case COM_CREATE_DB:				// QQ: To be removed
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1115
    {
1116
      statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
1117
      char *db=thd->strdup(packet);
1118
      // null test to handle EOM
1119
      if (!db || !strip_sp(db) || check_db_name(db))
1120 1121 1122 1123
      {
	net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
	break;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1124 1125
      if (check_access(thd,CREATE_ACL,db,0,1))
	break;
1126
      mysql_log.write(thd,command,packet);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1127
      mysql_create_db(thd,db,0,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1128 1129
      break;
    }
1130
  case COM_DROP_DB:				// QQ: To be removed
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1131
    {
1132
      statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
1133
      char *db=thd->strdup(packet);
1134
      // null test to handle EOM
1135
      if (!db || !strip_sp(db) || check_db_name(db))
1136 1137 1138 1139
      {
	net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
	break;
      }
1140 1141
      if (check_access(thd,DROP_ACL,db,0,1))
	break;
1142 1143 1144
      if (thd->locked_tables || thd->active_transaction())
      {
	send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1145
	break;
1146
      }
1147
      mysql_log.write(thd,command,db);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1148
      mysql_rm_db(thd,db,0,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1149 1150 1151 1152
      break;
    }
  case COM_BINLOG_DUMP:
    {
1153
      statistic_increment(com_other,&LOCK_status);
1154
      slow_command = TRUE;
1155
      if (check_global_access(thd, REPL_SLAVE_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1156
	break;
1157
      mysql_log.write(thd,command, 0);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1158

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1159 1160
      ulong pos;
      ushort flags;
1161
      uint32 slave_server_id;
1162
      /* TODO: The following has to be changed to an 8 byte integer */
1163 1164
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
1165
      thd->server_id=0; /* avoid suicide */
1166
      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
vva@eagle.mysql.r18.ru's avatar
vva@eagle.mysql.r18.ru committed
1167
	kill_zombie_dump_threads(slave_server_id);
1168
      thd->server_id = slave_server_id;
1169
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
1170
      unregister_slave(thd,1,1);
1171 1172 1173
      // fake COM_QUIT -- if we get here, the thread needs to terminate
      error = TRUE;
      net->error = 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1174 1175 1176 1177
      break;
    }
  case COM_REFRESH:
    {
1178
      statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
1179
      ulong options= (ulong) (uchar) packet[0];
1180
      if (check_global_access(thd,RELOAD_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1181
	break;
1182
      mysql_log.write(thd,command,NullS);
1183 1184
      /* error sending is deferred to reload_acl_and_cache */
      reload_acl_and_cache(thd, options, (TABLE_LIST*) 0) ;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1185 1186 1187
      break;
    }
  case COM_SHUTDOWN:
1188
    statistic_increment(com_other,&LOCK_status);
1189
    if (check_global_access(thd,SHUTDOWN_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1190 1191
      break; /* purecov: inspected */
    DBUG_PRINT("quit",("Got shutdown command"));
1192
    mysql_log.write(thd,command,NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1193 1194 1195 1196
    send_eof(net);
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1197
#ifndef OS2
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1198
    send_eof(net);				// This is for 'quit request'
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1199
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1200 1201
    close_connection(net);
    close_thread_tables(thd);			// Free before kill
1202
    free_root(&thd->mem_root,MYF(0));
1203
    free_root(&thd->transaction.mem_root,MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1204 1205 1206 1207 1208 1209
    kill_mysql();
    error=TRUE;
    break;

  case COM_STATISTICS:
  {
1210
    mysql_log.write(thd,command,NullS);
1211
    statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1212
    char buff[200];
1213
    ulong uptime = (ulong) (thd->start_time - start_time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1214
    sprintf((char*) buff,
1215
	    "Uptime: %ld  Threads: %d  Questions: %lu  Slow queries: %ld  Opens: %ld  Flush tables: %ld  Open tables: %u  Queries per second avg: %.3f",
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1216 1217 1218 1219 1220
	    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
1221
    if (sf_malloc_cur_memory)				// Using SAFEMALLOC
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1222
      sprintf(strend(buff), "  Memory in use: %ldK  Max memory used: %ldK",
1223 1224
	      (sf_malloc_cur_memory+1023L)/1024L,
	      (sf_malloc_max_memory+1023L)/1024L);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1225
 #endif
1226
    VOID(my_net_write(net, buff,(uint) strlen(buff)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1227 1228 1229 1230
    VOID(net_flush(net));
    break;
  }
  case COM_PING:
1231
    statistic_increment(com_other,&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1232 1233 1234
    send_ok(net);				// Tell client we are alive
    break;
  case COM_PROCESS_INFO:
1235
    statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
1236
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1237
      break;
1238
    mysql_log.write(thd,command,NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1239 1240 1241 1242 1243
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
			  thd->priv_user,0);
    break;
  case COM_PROCESS_KILL:
  {
1244
    statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
1245
    ulong id=(ulong) uint4korr(packet);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1246 1247 1248 1249
    kill_one_thread(thd,id);
    break;
  }
  case COM_DEBUG:
1250
    statistic_increment(com_other,&LOCK_status);
1251
    if (check_global_access(thd, SUPER_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1252 1253
      break;					/* purecov: inspected */
    mysql_print_status(thd);
1254
    mysql_log.write(thd,command,NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1255 1256 1257 1258 1259 1260
    send_eof(net);
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
1261
  case COM_END:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275
  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;
1276
  thd->end_time();				// Set start time
1277

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

1283 1284
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
1285
	((thd->lex.select_lex.options &
1286
	  (QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED)) &&
1287
	 (specialflag & SPECIAL_LONG_LOG_FORMAT)))
1288 1289 1290 1291
    {
      long_query_count++;
      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1292
  }
1293
  thd->proc_info="cleaning up";
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1294 1295 1296 1297 1298 1299
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
  thd->proc_info=0;
  thd->command=COM_SLEEP;
  thd->query=0;
  thread_running--;
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
1300
  thd->packet.shrink(thd->variables.net_buffer_length);	// Reclaim some memory
1301
  free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314
  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;
1315
  LEX	*lex= &thd->lex;
1316
  TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first;
1317
  SELECT_LEX *select_lex = lex->select;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1318 1319
  DBUG_ENTER("mysql_execute_command");

1320 1321
  if (thd->slave_thread)
  {
monty@hundin.mysql.fi's avatar
merge  
monty@hundin.mysql.fi committed
1322 1323 1324 1325 1326
    /* 
      Skip if we are in the slave thread, some table rules have been
      given and the table list says the query should not be replicated
    */
    if (table_rules_on && tables && !tables_ok(thd,tables))
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1327 1328 1329
    {
      /* we warn the slave SQL thread */
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
1330
      DBUG_VOID_RETURN;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1331
    }
monty@hundin.mysql.fi's avatar
merge  
monty@hundin.mysql.fi committed
1332 1333 1334 1335 1336 1337
#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()
    */
1338 1339 1340
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
1341
      lex->insert_list = &select_lex->item_list;
1342
    }
monty@hundin.mysql.fi's avatar
merge  
monty@hundin.mysql.fi committed
1343
#endif
1344
  }
1345
  
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1346
  if (lex->select_lex.next && create_total_list(thd,lex,&tables))
1347
    DBUG_VOID_RETURN;
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359
  
  /*
    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;
  }
1360

1361
  statistic_increment(com_stat[lex->sql_command],&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1362 1363 1364 1365
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
    select_result *result;
1366
    if (select_lex->options & SELECT_DESCRIBE)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
      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
    }

1384 1385 1386
    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)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1387
      thd->select_limit= HA_POS_ERROR;		// no limit
1388
    if (thd->select_limit == HA_POS_ERROR)
1389
      select_lex->options&= ~OPTION_FOUND_ROWS;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413

    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
1414 1415
      delete select_lex->having;
      delete select_lex->where;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1416 1417 1418
#endif
      break;
    }
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1419
    else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1420
    {
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1421 1422 1423 1424
      /*
	Normal select:
	Change lock if we are using SELECT HIGH PRIORITY,
	FOR UPDATE or IN SHARE MODE
1425 1426

	TODO: Delete the following loop when locks is set by sql_yacc
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1427
      */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1428 1429
      TABLE_LIST *table;
      for (table = tables ; table ; table=table->next)
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1430
	table->lock_type= lex->lock_option;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1431 1432 1433
    }

    if (!(res=open_and_lock_tables(thd,tables)))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1434
    {
1435
      query_cache_store_query(thd, tables);
1436
      res=handle_select(thd, lex, result);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1437
    }
1438 1439
    else
      delete result;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1440 1441
    break;
  }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1442 1443 1444 1445
  case SQLCOM_DO:
    res=mysql_do(thd, *lex->insert_list);
    break;

1446 1447 1448 1449
  case SQLCOM_EMPTY_QUERY:
    send_ok(&thd->net);
    break;

1450
  case SQLCOM_PURGE:
1451
  {
1452
    if (check_global_access(thd, SUPER_ACL))
1453 1454 1455 1456
      goto error;
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
1457 1458
  case SQLCOM_SHOW_NEW_MASTER:
  {
1459
    if (check_global_access(thd, REPL_SLAVE_ACL))
1460
      goto error;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1461 1462 1463 1464
#ifndef WORKING_NEW_MASTER
    net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
    res= 1;
#else
1465
    res = show_new_master(thd);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1466
#endif
1467 1468
    break;
  }
1469 1470
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
1471
    if (check_global_access(thd, REPL_SLAVE_ACL))
1472 1473 1474 1475
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
1476 1477
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
1478
    if (check_global_access(thd, REPL_SLAVE_ACL))
1479 1480 1481 1482
      goto error;
    res = show_binlog_events(thd);
    break;
  }
1483
  case SQLCOM_BACKUP_TABLE:
1484 1485 1486
  {
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables) ||
1487
	check_global_access(thd, FILE_ACL))
1488 1489
      goto error; /* purecov: inspected */
    res = mysql_backup_table(thd, tables);
1490

1491 1492
    break;
  }
1493
  case SQLCOM_RESTORE_TABLE:
1494 1495
  {
    if (check_db_used(thd,tables) ||
1496 1497
	check_table_access(thd, INSERT_ACL, tables) ||
	check_global_access(thd, FILE_ACL))
1498 1499 1500 1501
      goto error; /* purecov: inspected */
    res = mysql_restore_table(thd, tables);
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1502
  case SQLCOM_CHANGE_MASTER:
1503
  {
1504
    if (check_global_access(thd, SUPER_ACL))
1505
      goto error;
1506 1507 1508
    LOCK_ACTIVE_MI;
    res = change_master(thd,active_mi);
    UNLOCK_ACTIVE_MI;
1509 1510
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1511
  case SQLCOM_SHOW_SLAVE_STAT:
1512
  {
1513 1514
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
1515
      goto error;
1516 1517 1518
    LOCK_ACTIVE_MI;
    res = show_master_info(thd,active_mi);
    UNLOCK_ACTIVE_MI;
1519 1520
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1521
  case SQLCOM_SHOW_MASTER_STAT:
1522
  {
1523 1524
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
1525 1526 1527 1528
      goto error;
    res = show_binlog_info(thd);
    break;
  }
1529 1530
    
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
1531
    if (check_global_access(thd, SUPER_ACL))
1532
      goto error;
1533 1534 1535 1536
    if (end_active_trans(thd))
      res= -1;
    else
      res = load_master_data(thd);
1537 1538
    break;
    
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
1539 1540 1541
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
1542
      if (check_global_access(thd, SUPER_ACL))
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
1543 1544 1545 1546 1547
	goto error;
      res = innodb_show_status(thd);
      break;
    }
#endif
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1548

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1549
  case SQLCOM_LOAD_MASTER_TABLE:
1550
  {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
    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)
1563
	goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1564
    }
1565 1566 1567 1568 1569 1570 1571 1572
    LOCK_ACTIVE_MI;
    // fetch_master_table will send the error to the client on failure
    if (!fetch_master_table(thd, tables->db, tables->real_name,
			    active_mi, 0))
    {
      send_ok(&thd->net);
    }
    UNLOCK_ACTIVE_MI;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1573
    break;
1574
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1575
  case SQLCOM_CREATE_TABLE:
1576 1577 1578
  {
    ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
		      CREATE_TMP_ACL : CREATE_ACL);
1579 1580
    if (!tables->db)
      tables->db=thd->db;
1581
    if (check_access(thd,want_priv,tables->db,&tables->grant.privilege) ||
1582 1583 1584
	check_merge_table_access(thd, tables->db,
				 (TABLE_LIST *)
				 lex->create_info.merge_list.first))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1585
      goto error;				/* purecov: inspected */
1586
    if (grant_option && want_priv != CREATE_TMP_ACL)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1587 1588 1589 1590
    {
      /* Check that the first table has CREATE privilege */
      TABLE_LIST *tmp_table_list=tables->next;
      tables->next=0;
1591
      bool error=check_grant(thd, want_priv, tables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1592 1593 1594 1595
      tables->next=tmp_table_list;
      if (error)
	goto error;
    }
1596
    if (strlen(tables->real_name) > NAME_LEN)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1597
    {
1598
      net_printf(&thd->net, ER_WRONG_TABLE_NAME, tables->alias);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1599 1600 1601
      res=0;
      break;
    }
1602 1603 1604
#ifndef HAVE_READLINK
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
1605
    /* Fix names if symlinked tables */
1606
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
1607
			   tables->real_name) ||
1608
	append_file_to_dir(thd,&lex->create_info.index_file_name,
1609
			   tables->real_name))
1610 1611 1612 1613
    {
      res=-1;
      break;
    }
1614
#endif
1615
    if (select_lex->item_list.elements)		// With select
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1616 1617 1618 1619
    {
      select_result *result;

      if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
1620
	  check_dup(tables->db, tables->real_name, tables->next))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1621 1622 1623 1624 1625 1626
      {
	net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
	DBUG_VOID_RETURN;
      }
      if (tables->next)
      {
1627
	TABLE_LIST *table;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1628 1629
	if (check_table_access(thd, SELECT_ACL, tables->next))
	  goto error;				// Error message is given
1630
	/* TODO: Delete the following loop when locks is set by sql_yacc */
1631 1632
	for (table = tables->next ; table ; table=table->next)
	  table->lock_type= lex->lock_option;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1633
      }
1634
      select_lex->options|= SELECT_NO_UNLOCK;
1635 1636 1637
      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)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1638
	thd->select_limit= HA_POS_ERROR;		// No limit
1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654

      /* Skip first table, which is the table we are creating */
      lex->select_lex.table_list.first=
	(byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
      if (!(res=open_and_lock_tables(thd,tables->next)))
      {
        if ((result=new select_create(tables->db ? tables->db : thd->db,
                                      tables->real_name, &lex->create_info,
                                      lex->create_list,
                                      lex->key_list,
                                      select_lex->item_list,lex->duplicates)))
          res=handle_select(thd, lex, result);
	else
	  res= -1;
      }
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664
    else // regular create
    {
      res = mysql_create_table(thd,tables->db ? tables->db : thd->db,
			       tables->real_name, &lex->create_info,
			       lex->create_list,
			       lex->key_list,0, 0); // do logging
      if (!res)
	send_ok(&thd->net);
    }
    break;
1665
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1666 1667 1668 1669 1670 1671 1672
  case SQLCOM_CREATE_INDEX:
    if (!tables->db)
      tables->db=thd->db;
    if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege))
      goto error; /* purecov: inspected */
    if (grant_option && check_grant(thd,INDEX_ACL,tables))
      goto error;
1673 1674 1675 1676
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_create_index(thd, tables, lex->key_list);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1677 1678 1679
    break;

  case SQLCOM_SLAVE_START:
1680 1681 1682 1683
  {
    LOCK_ACTIVE_MI;
    start_slave(thd,active_mi,1 /* net report*/);
    UNLOCK_ACTIVE_MI;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1684
    break;
1685
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1686
  case SQLCOM_SLAVE_STOP:
1687 1688 1689 1690 1691 1692
  /*
    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,
1693
      so it waits for the client thread because t is locked by it.
1694
    - then the client thread does SLAVE STOP.
1695 1696
      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.
1697 1698 1699 1700 1701 1702
    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);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1703
    break;
1704
  }
1705 1706 1707 1708
  {
    LOCK_ACTIVE_MI;
    stop_slave(thd,active_mi,1/* net report*/);
    UNLOCK_ACTIVE_MI;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1709
    break;
1710
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1711 1712 1713 1714 1715 1716
  case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
    break;
#else
    {
1717
      ulong priv=0;
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1718
      if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1719 1720 1721 1722 1723
      {
	net_printf(&thd->net,ER_WRONG_TABLE_NAME,lex->name);
	res=0;
	break;
      }
1724 1725
      if (!tables->db)
	tables->db=thd->db;
1726 1727
      if (!select_lex->db)
	select_lex->db=tables->db;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1728
      if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege) ||
1729
	  check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv) ||
1730 1731 1732 1733
	  check_merge_table_access(thd, tables->db, 
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744
      if (!tables->db)
	tables->db=thd->db;
      if (grant_option)
      {
	if (check_grant(thd,ALTER_ACL,tables))
	  goto error;
	if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
	{					// Rename of table
	  TABLE_LIST tmp_table;
	  bzero((char*) &tmp_table,sizeof(tmp_table));
	  tmp_table.real_name=lex->name;
1745
	  tmp_table.db=select_lex->db;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1746 1747 1748 1749 1750
	  tmp_table.grant.privilege=priv;
	  if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables))
	    goto error;
	}
      }
1751 1752
      /* Don't yet allow changing of symlinks with ALTER TABLE */
      lex->create_info.data_file_name=lex->create_info.index_file_name=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1753
      /* ALTER TABLE ends previous transaction */
1754
      if (end_active_trans(thd))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1755 1756
	res= -1;
      else
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1757
      {
1758
	res= mysql_alter_table(thd, select_lex->db, lex->name,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1759 1760 1761
			       &lex->create_info,
			       tables, lex->create_list,
			       lex->key_list, lex->drop_list, lex->alter_list,
1762
                               (ORDER *) select_lex->order_list.first,
1763 1764
			       lex->drop_primary, lex->duplicates,
			       lex->alter_keys_onoff, lex->simple_alter);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1765
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1766 1767 1768
      break;
    }
#endif
1769
  case SQLCOM_RENAME_TABLE:
1770 1771 1772
  {
    TABLE_LIST *table;
    if (check_db_used(thd,tables))
1773
      goto error;
1774 1775
    for (table=tables ; table ; table=table->next->next)
    {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1776 1777
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
		       &table->grant.privilege) ||
1778 1779 1780 1781 1782
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next->db,
		       &table->next->grant.privilege))
	goto error;
      if (grant_option)
      {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1783 1784 1785 1786 1787
	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) ||
1788
	    (!test_all_bits(table->next->grant.privilege,
1789
			    INSERT_ACL | CREATE_ACL) &&
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1790
	     check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list)))
1791 1792 1793
	  goto error;
      }
    }
1794
    query_cache_invalidate3(thd, tables, 0);
1795 1796 1797
    if (end_active_trans(thd))
      res= -1;
    else if (mysql_rename_tables(thd,tables))
1798 1799
      res= -1;
    break;
1800
  }
1801 1802 1803 1804 1805 1806
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
    DBUG_VOID_RETURN;
#else
    {
1807
      if (check_global_access(thd, SUPER_ACL))
1808 1809 1810 1811 1812
	goto error;
      res = show_binlogs(thd);
      break;
    }
#endif    
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1813
  case SQLCOM_SHOW_CREATE:
1814
#ifdef DONT_ALLOW_SHOW_COMMANDS
1815
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
1816 1817
    DBUG_VOID_RETURN;
#else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1818
    {
1819 1820 1821 1822
      if (check_db_used(thd, tables) ||
	  check_access(thd, SELECT_ACL | EXTRA_ACL, tables->db,
		       &tables->grant.privilege))
	goto error;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1823
      res = mysqld_show_create(thd, tables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1824 1825
      break;
    }
1826
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1827
  case SQLCOM_REPAIR:
1828 1829 1830 1831 1832 1833 1834
  {
    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;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1835
  case SQLCOM_CHECK:
1836 1837 1838 1839 1840 1841 1842
  {
    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;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1843 1844
  case SQLCOM_ANALYZE:
  {
1845 1846
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1847
      goto error; /* purecov: inspected */
1848
    res = mysql_analyze_table(thd, tables, &lex->check_opt);
1849
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1850
  }
1851

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1852 1853 1854
  case SQLCOM_OPTIMIZE:
  {
    HA_CREATE_INFO create_info;
1855 1856
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1857
      goto error; /* purecov: inspected */
1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
    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,
1872
                             (ORDER *) 0,
1873 1874 1875 1876
			     0,DUP_ERROR);
    }
    else
      res = mysql_optimize_table(thd, tables, &lex->check_opt);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1877 1878 1879
    break;
  }
  case SQLCOM_UPDATE:
1880 1881
    TABLE_LIST *table;
    if (check_db_used(thd,tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1882
      goto error;
1883 1884 1885 1886 1887
    for (table=tables ; table ; table=table->next)
    {
      if (check_access(thd,UPDATE_ACL,table->db,&table->grant.privilege))
	goto error;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1888 1889
    if (grant_option && check_grant(thd,UPDATE_ACL,tables))
      goto error;
1890
    if (select_lex->item_list.elements != lex->value_list.elements)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1891 1892 1893 1894
    {
      send_error(&thd->net,ER_WRONG_VALUE_COUNT);
      DBUG_VOID_RETURN;
    }
1895 1896
    if (select_lex->table_list.elements == 1)
    {
1897 1898 1899 1900 1901 1902 1903
      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);
1904
    }
1905
    else
1906
    {
1907 1908
      const char *msg= 0;
      lex->sql_command= SQLCOM_MULTI_UPDATE;
1909 1910 1911 1912 1913 1914
      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)
1915
      {
1916 1917 1918
	net_printf(&thd->net, ER_WRONG_USAGE, "UPDATE", msg);
	res= 1;
	break;
1919
      }
1920 1921 1922 1923 1924 1925
      res= mysql_multi_update(thd,tables,
			      &select_lex->item_list,
			      &lex->value_list,
			      select_lex->where,
			      select_lex->options,
			      lex->duplicates);
1926
    }
1927
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1928 1929 1930 1931 1932 1933
  case SQLCOM_INSERT:
    if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege))
      goto error; /* purecov: inspected */
    if (grant_option && check_grant(thd,INSERT_ACL,tables))
      goto error;
    res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
1934
		       lex->duplicates);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1935 1936
    break;
  case SQLCOM_REPLACE:
1937
    if (check_access(thd,INSERT_ACL | DELETE_ACL,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1938 1939
		     tables->db,&tables->grant.privilege))
      goto error; /* purecov: inspected */
1940
    if (grant_option && check_grant(thd,INSERT_ACL | DELETE_ACL,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1941 1942 1943 1944
				    tables))

      goto error;
    res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
1945
		       DUP_REPLACE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1946 1947 1948 1949
    break;
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
1950

1951 1952 1953 1954
    /*
      Check that we have modify privileges for the first table and
      select privileges for the rest
    */
1955
    {
1956
      ulong privilege= (lex->sql_command == SQLCOM_INSERT_SELECT ?
1957
			INSERT_ACL : INSERT_ACL | DELETE_ACL);
1958 1959 1960 1961 1962 1963 1964 1965 1966 1967
      TABLE_LIST *save_next=tables->next;
      tables->next=0;
      if (check_access(thd, privilege,
		       tables->db,&tables->grant.privilege) ||
	  (grant_option && check_grant(thd, privilege, tables)))
	goto error;
      tables->next=save_next;
      if ((res=check_table_access(thd, SELECT_ACL, save_next)))
	goto error;
    }
1968 1969
    /* Don't unlock tables until command is written to binary log */
    select_lex->options|= SELECT_NO_UNLOCK;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1970 1971

    select_result *result;
1972 1973 1974
    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)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1975 1976
      thd->select_limit= HA_POS_ERROR;		// No limit

1977 1978 1979 1980 1981
    if (check_dup(tables->db, tables->real_name, tables->next))
    {
      /* Using same table for INSERT and SELECT */
      select_lex->options |= OPTION_BUFFER_RESULT;
    }
1982
    {
1983
      /* TODO: Delete the following loop when locks is set by sql_yacc */
1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994
      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,
1995
				    lex->duplicates)))
1996 1997 1998 1999
	res=handle_select(thd,lex,result);
    }
    else
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2000 2001
    break;
  }
2002
  case SQLCOM_TRUNCATE:
2003 2004
    if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
      goto error; /* purecov: inspected */
2005 2006
    if (grant_option && check_grant(thd,DELETE_ACL,tables))
      goto error;
2007 2008 2009 2010 2011 2012
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
    if (thd->locked_tables || thd->active_transaction())
    {
2013
      send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
2014 2015 2016 2017
      goto error;
    }
    res=mysql_truncate(thd,tables);
    break;
2018
  case SQLCOM_DELETE:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2019 2020 2021 2022 2023 2024 2025
  {
    if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
      goto error; /* purecov: inspected */
    if (grant_option && check_grant(thd,DELETE_ACL,tables))
      goto error;
    // Set privilege for the WHERE clause
    tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
serg@serg.mysql.com's avatar
serg@serg.mysql.com committed
2026 2027
    res = mysql_delete(thd,tables, select_lex->where,
                       (ORDER*) select_lex->order_list.first,
2028
                       select_lex->select_limit, select_lex->options);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2029 2030
    break;
  }
2031
  case SQLCOM_DELETE_MULTI:
2032 2033 2034 2035 2036
  {
    TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first;
    TABLE_LIST *auxi;
    uint table_count=0;
    multi_delete *result;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2037

2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063
    /* 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;
      }
2064
      walk->lock_type= auxi->lock_type;
2065 2066
      // Store address to table as we need it later
      auxi->table= my_reinterpret_cast(TABLE *) (walk);
2067 2068 2069
    }
    if (add_item_to_list(new Item_null()))
    {
2070
      res= -1;
2071
      break;
2072 2073 2074 2075 2076 2077 2078
    }
    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)
2079 2080
      auxi->table= (my_reinterpret_cast(TABLE_LIST*) (auxi->table))->table;

2081 2082
    if (!thd->fatal_error && (result= new multi_delete(thd,aux_tables,
						       table_count)))
2083 2084
    {
      res=mysql_select(thd,tables,select_lex->item_list,
2085
		       select_lex->where,
2086 2087 2088
		       (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
		       (ORDER *)NULL,
		       select_lex->options | thd->options |
lenz@mysql.com's avatar
lenz@mysql.com committed
2089
		       SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
2090
		       result);
2091
      delete result;
2092 2093 2094 2095 2096 2097
    }
    else
      res= -1;					// Error is not sent
    close_thread_tables(thd);
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2098
  case SQLCOM_DROP_TABLE:
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2099 2100 2101
  {
    if (check_table_access(thd,DROP_ACL,tables))
      goto error;				/* purecov: inspected */
2102 2103 2104 2105 2106 2107 2108 2109 2110 2111
    /*
      If this is a slave thread, we may sometimes execute some 
      DROP / * 40005 TEMPORARY * / TABLE
      that come from parts of binlogs (likely if we use RESET SLAVE or CHANGE
      MASTER TO), while the temporary table has already been dropped.
      To not generate such irrelevant "table does not exist errors", we silently
      add IF EXISTS if TEMPORARY was used.
    */
    if (thd->slave_thread && lex->drop_temporary)
      lex->drop_if_exists= 1;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2112 2113 2114 2115 2116 2117
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_rm_table(thd,tables,lex->drop_if_exists);
  }
  break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2118 2119 2120 2121 2122 2123 2124
  case SQLCOM_DROP_INDEX:
    if (!tables->db)
      tables->db=thd->db;
    if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege))
      goto error;				/* purecov: inspected */
    if (grant_option && check_grant(thd,INDEX_ACL,tables))
      goto error;
2125 2126 2127 2128
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_drop_index(thd, tables, lex->drop_list);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2129 2130
    break;
  case SQLCOM_SHOW_DATABASES:
2131
#if defined(DONT_ALLOW_SHOW_COMMANDS)
2132
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);   /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2133 2134 2135
    DBUG_VOID_RETURN;
#else
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
2136
	check_global_access(thd, SHOW_DB_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2137 2138 2139 2140 2141
      goto error;
    res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
    break;
#endif
  case SQLCOM_SHOW_PROCESSLIST:
2142
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2143 2144 2145 2146 2147
      break;
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
			  thd->priv_user,lex->verbose);
    break;
  case SQLCOM_SHOW_STATUS:
2148
    res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
2149
		     OPT_GLOBAL);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2150 2151 2152
    break;
  case SQLCOM_SHOW_VARIABLES:
    res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
2153
		     init_vars, lex->option_type);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2154
    break;
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
2155
  case SQLCOM_SHOW_LOGS:
2156 2157 2158 2159
  {
    res= mysqld_show_logs(thd);
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2160
  case SQLCOM_SHOW_TABLES:
2161
    /* FALL THROUGH */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2162 2163 2164 2165 2166
#ifdef DONT_ALLOW_SHOW_COMMANDS
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
    DBUG_VOID_RETURN;
#else
    {
2167
      char *db=select_lex->db ? select_lex->db : thd->db;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2168 2169 2170 2171 2172 2173
      if (!db)
      {
	send_error(&thd->net,ER_NO_DB_ERROR);	/* purecov: inspected */
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);				// Fix escaped '_'
2174
      if (check_db_name(db))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2175
      {
2176 2177
        net_printf(&thd->net,ER_WRONG_DB_NAME, db);
        goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2178 2179 2180
      }
      if (check_access(thd,SELECT_ACL,db,&thd->col_access))
	goto error;				/* purecov: inspected */
2181 2182 2183 2184 2185 2186 2187 2188
      if (!thd->col_access && grant_option && check_grant_db(thd,db))
      {
	net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
		   thd->priv_user,
		   thd->priv_host,
		   db);
	goto error;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2189
      /* grant is checked in mysqld_show_tables */
2190
      if (select_lex->options & SELECT_DESCRIBE)
2191
        res= mysqld_extend_show_tables(thd,db,
2192
				       (lex->wild ? lex->wild->ptr() : NullS));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2193 2194 2195 2196 2197 2198
      else
	res= mysqld_show_tables(thd,db,
				(lex->wild ? lex->wild->ptr() : NullS));
      break;
    }
#endif
2199 2200 2201
  case SQLCOM_SHOW_OPEN_TABLES:
    res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2202 2203 2204 2205 2206 2207
  case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
    send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
    DBUG_VOID_RETURN;
#else
    {
2208 2209
      char *db=tables->db;
      if (!*db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2210 2211 2212 2213 2214
      {
	send_error(&thd->net,ER_NO_DB_ERROR);	/* purecov: inspected */
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);			// Fix escaped '_'
2215
      remove_escape(tables->real_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2216 2217 2218 2219 2220 2221
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access))
	goto error;				/* purecov: inspected */
      tables->grant.privilege=thd->col_access;
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
	goto error;
      res= mysqld_show_fields(thd,tables,
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2222 2223
			      (lex->wild ? lex->wild->ptr() : NullS),
			      lex->verbose);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2224 2225 2226 2227 2228 2229 2230 2231 2232
      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
    {
2233
      char *db=tables->db;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2234 2235 2236 2237 2238 2239
      if (!db)
      {
	send_error(&thd->net,ER_NO_DB_ERROR);	/* purecov: inspected */
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);			// Fix escaped '_'
2240
      remove_escape(tables->real_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252
      if (!tables->db)
	tables->db=thd->db;
      if (check_access(thd,SELECT_ACL,db,&thd->col_access))
	goto error; /* purecov: inspected */
      tables->grant.privilege=thd->col_access;
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
	goto error;
      res= mysqld_show_keys(thd,tables);
      break;
    }
#endif
  case SQLCOM_CHANGE_DB:
2253
    mysql_change_db(thd,select_lex->db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2254 2255 2256 2257 2258
    break;
  case SQLCOM_LOAD:
  {
    uint privilege= (lex->duplicates == DUP_REPLACE ?
		     INSERT_ACL | UPDATE_ACL | DELETE_ACL : INSERT_ACL);
2259 2260

    if (!lex->local_file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2261 2262 2263 2264 2265 2266
    {
      if (check_access(thd,privilege | FILE_ACL,tables->db))
	goto error;
    }
    else
    {
2267
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
2268
	  ! opt_local_infile)
2269 2270 2271 2272
      {
	send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);
	goto error;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2273
      if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
2274
	  grant_option && check_grant(thd,privilege,tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2275 2276 2277 2278 2279 2280 2281
	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:
2282
    if (!(res=sql_set_variables(thd, &lex->var_list)))
2283
      send_ok(&thd->net);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2284 2285
    break;
  case SQLCOM_UNLOCK_TABLES:
2286
    unlock_locked_tables(thd);
2287 2288
    if (thd->options & OPTION_TABLE_LOCK)
    {
2289
      end_active_trans(thd);
2290
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2291 2292
    }
    if (thd->global_read_lock)
2293
      unlock_global_read_lock(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2294 2295 2296
    send_ok(&thd->net);
    break;
  case SQLCOM_LOCK_TABLES:
2297
    unlock_locked_tables(thd);
2298
    if (check_db_used(thd,tables) || end_active_trans(thd))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2299
      goto error;
2300
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables))
2301
      goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2302
    thd->in_lock_tables=1;
2303
    thd->options|= OPTION_TABLE_LOCK;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2304 2305 2306 2307 2308 2309
    if (!(res=open_and_lock_tables(thd,tables)))
    {
      thd->locked_tables=thd->lock;
      thd->lock=0;
      send_ok(&thd->net);
    }
2310 2311
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2312 2313 2314
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
2315
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2316
    if (!strip_sp(lex->name) || check_db_name(lex->name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2317
    {
2318
      net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2319 2320
      break;
    }
2321 2322 2323 2324 2325 2326 2327 2328 2329 2330
    /*
      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)))
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2331 2332
    {
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
2333
      break;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2334
    }
2335

2336 2337
    if (check_access(thd,CREATE_ACL,lex->name,0,1))
      break;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2338
    res=mysql_create_db(thd,lex->name,lex->create_info.options,0);
2339 2340
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2341
  case SQLCOM_DROP_DB:
2342
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2343
    if (!strip_sp(lex->name) || check_db_name(lex->name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2344
    {
2345
      net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2346 2347
      break;
    }
2348 2349 2350 2351 2352 2353 2354 2355 2356 2357
    /*
      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)))
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2358 2359
    {
      my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
2360
      break;
guilhem@mysql.com's avatar
guilhem@mysql.com committed
2361
    }
2362
    if (check_access(thd,DROP_ACL,lex->name,0,1))
2363
      break;
2364 2365
    if (thd->locked_tables || thd->active_transaction())
    {
2366
      send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
2367 2368
      goto error;
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2369
    res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0);
2370 2371
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391
  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;
2392 2393 2394 2395 2396 2397 2398 2399 2400
  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;

2401 2402 2403 2404
    /*
      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
    */
2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429

    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;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2430 2431 2432
      if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
				    lex->grant,
				    lex->sql_command == SQLCOM_REVOKE)))
2433
      {
2434
	mysql_update_log.write(thd, thd->query, thd->query_length);
2435 2436
	if (mysql_bin_log.is_open())
	{
2437
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
2438 2439 2440 2441 2442 2443 2444 2445
	  mysql_bin_log.write(&qinfo);
	}
      }
    }
    else
    {
      if (lex->columns.elements)
      {
2446
	send_error(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
2447 2448 2449 2450 2451 2452 2453
	res=1;
      }
      else
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
2454
	mysql_update_log.write(thd, thd->query, thd->query_length);
2455 2456
	if (mysql_bin_log.is_open())
	{
2457
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
2458 2459
	  mysql_bin_log.write(&qinfo);
	}
2460
	if (mqh_used && lex->sql_command == SQLCOM_GRANT)
2461
	{
2462 2463 2464
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
2465
	    reset_mqh(thd,user);
2466
	}
2467 2468 2469 2470
      }
    }
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2471
  case SQLCOM_FLUSH:
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2472
  case SQLCOM_RESET:
2473
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2474
      goto error;
2475 2476
    /* error sending is deferred to reload_acl_and_cache */
    reload_acl_and_cache(thd, lex->type, tables) ;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2477 2478 2479 2480 2481 2482
    break;
  case SQLCOM_KILL:
    kill_one_thread(thd,lex->thread_id);
    break;
  case SQLCOM_SHOW_GRANTS:
    res=0;
2483 2484
    if ((thd->priv_user &&
	 !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
2485
	!check_access(thd, SELECT_ACL, "mysql",0,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2486 2487 2488 2489
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
2490
  case SQLCOM_HA_OPEN:
2491 2492
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables))
2493 2494 2495 2496 2497 2498 2499 2500 2501
      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:
2502 2503 2504 2505 2506
    /*
      There is no need to check for table permissions here, because
      if a user has no permissions to read a table, he won't be
      able to open it (with SQLCOM_HA_OPEN) in the first place.
    */
serg@serg.mylan's avatar
serg@serg.mylan committed
2507
    if (check_db_used(thd,tables))
2508
      goto error;
serg@serg.mysql.com's avatar
serg@serg.mysql.com committed
2509
    res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
2510 2511
			lex->insert_list, lex->ha_rkey_mode, select_lex->where,
			select_lex->select_limit, select_lex->offset_limit);
2512 2513
    break;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2514
  case SQLCOM_BEGIN:
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2515 2516 2517 2518 2519 2520
    if (thd->locked_tables)
    {
      thd->lock=thd->locked_tables;
      thd->locked_tables=0;			// Will be automaticly closed
      close_thread_tables(thd);			// Free tables
    }
2521 2522 2523 2524 2525 2526
    if (end_active_trans(thd))
    {
      res= -1;
    }
    else
    {
2527
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
2528 2529 2530 2531
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
      send_ok(&thd->net);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2532 2533
    break;
  case SQLCOM_COMMIT:
2534 2535 2536 2537 2538
    /*
      We don't use end_active_trans() here to ensure that this works
      even if there is a problem with the OPTION_AUTO_COMMIT flag
      (Which of course should never happen...)
    */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2539
  {
2540
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2541 2542
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2543
    {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2544
      send_ok(&thd->net);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2545
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2546 2547 2548
    else
      res= -1;
    break;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2549
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2550 2551 2552
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
2553 2554 2555 2556 2557 2558
    {
      if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
	send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
      else
	send_ok(&thd->net);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2559 2560
    else
      res= -1;
2561
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2562
    break;
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
    if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
    {
      if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
	send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
      else
	send_ok(&thd->net);
    }
    else
      res= -1;
    break;
2574
  case SQLCOM_SAVEPOINT:
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
2575 2576 2577 2578
    if (!ha_savepoint(thd, lex->savepoint_name))
      send_ok(&thd->net);
    else
      res= -1;
2579
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593
  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;
}


/****************************************************************************
2594
  Get the user (global) and database privileges for all used tables
2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607

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

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

    save_priv	In this we store global and db level grants for the table
		Note that we don't store db level grants if the global grants
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2608 2609
                is enough to satisfy the request and the global grants contains
                a SELECT grant.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2610 2611 2612
****************************************************************************/

bool
2613
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
2614
	     bool dont_check_global_grants, bool no_errors)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2615
{
2616 2617 2618 2619
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("want_access: %lu  master_access: %lu", want_access,
		      thd->master_access));
  ulong db_access,dummy;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2620 2621 2622 2623 2624
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

2625
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2626
  {
2627 2628
    if (!no_errors)
      send_error(&thd->net,ER_NO_DB_ERROR);	/* purecov: tested */
2629
    DBUG_RETURN(TRUE);				/* purecov: tested */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2630 2631 2632 2633
  }

  if ((thd->master_access & want_access) == want_access)
  {
2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644
    /*
      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,
			thd->priv_user, db); /* purecov: inspected */
    *save_priv=thd->master_access | db_access;
2645
    DBUG_RETURN(FALSE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2646
  }
2647
  if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
2648
      ! db && dont_check_global_grants)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2649
  {						// We can never grant this
2650 2651 2652
    if (!no_errors)
      net_printf(&thd->net,ER_ACCESS_DENIED_ERROR,
		 thd->priv_user,
2653
		 thd->priv_host,
2654
		 thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
2655
    DBUG_RETURN(TRUE);				/* purecov: tested */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2656 2657 2658
  }

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2661 2662 2663 2664 2665
  if (db && (!thd->db || strcmp(db,thd->db)))
    db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
		      thd->priv_user, db); /* purecov: inspected */
  else
    db_access=thd->db_access;
2666 2667
  // Remove SHOW attribute and access rights we already have
  want_access &= ~(thd->master_access | EXTRA_ACL);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2668
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
2669 2670

  /* grant_option is set if there exists a single table or column grant */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2671
  if (db_access == want_access ||
2672 2673
      ((grant_option && !dont_check_global_grants) &&
       !(want_access & ~TABLE_ACLS)))
2674
    DBUG_RETURN(FALSE);				/* Ok */
2675 2676 2677
  if (!no_errors)
    net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
	       thd->priv_user,
2678
	       thd->priv_host,
2679
	       db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
2680
  DBUG_RETURN(TRUE);				/* purecov: tested */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2681 2682 2683
}


2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701
/*
  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
*/
2702 2703

bool check_global_access(THD *thd, ulong want_access)
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2704
{
2705
  char command[128];
2706
  if ((thd->master_access & want_access))
2707 2708 2709 2710 2711
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
  net_printf(&thd->net,ER_SPECIFIC_ACCESS_DENIED_ERROR,
	     command);
  return 1;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2712 2713 2714
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2715
/*
2716 2717
  Check the privilege for all used tables.  Table privileges are cached
  in the table list for GRANT checking
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2718 2719
*/

2720
bool
2721
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
2722
		   bool no_errors)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2723
{
2724 2725
  uint found=0;
  ulong found_access=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2726 2727 2728
  TABLE_LIST *org_tables=tables;
  for (; tables ; tables=tables->next)
  {
2729 2730
    if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
	thd->db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2731
      tables->grant.privilege= want_access;
2732
    else if (tables->db && tables->db == thd->db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2733 2734 2735 2736 2737
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
2738 2739
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
			 0, no_errors))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2740 2741
	  return TRUE;				// Access denied
	found_access=tables->grant.privilege;
2742
	found=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2743 2744
      }
    }
2745
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
2746
			  0, no_errors))
2747
      return TRUE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2748 2749
  }
  if (grant_option)
2750
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
2751
		       test(want_access & EXTRA_ACL), no_errors);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2752 2753 2754 2755
  return FALSE;
}


2756
static bool check_db_used(THD *thd,TABLE_LIST *tables)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772
{
  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;
}


2773 2774
static bool check_merge_table_access(THD *thd, char *db,
				     TABLE_LIST *table_list)
2775 2776 2777 2778
{
  int error=0;
  if (table_list)
  {
2779
    /* Check that all tables use the current database */
2780 2781
    TABLE_LIST *tmp;
    for (tmp=table_list; tmp ; tmp=tmp->next)
2782 2783 2784
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
2785
      else if (strcmp(tmp->db,db))
2786 2787 2788 2789 2790
      {
	send_error(&thd->net,ER_UNION_TABLES_IN_DIFFERENT_DIR);
	return 1;
      }
    }
2791 2792 2793 2794 2795 2796 2797
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
			     table_list);
  }
  return error;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2798 2799 2800 2801 2802 2803 2804 2805 2806 2807
/****************************************************************************
	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

2808
#ifndef EMBEDDED_LIBRARY
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821
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;
}
2822
#endif /* EMBEDDED_LIBRARY */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856

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

bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize)
{
  LEX	*lex=current_lex;
  int  old_info=0;
  if ((uint) *yystacksize >= MY_YACC_MAX)
    return 1;
  if (!lex->yacc_yyvs)
    old_info= *yystacksize;
  *yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX);
  if (!(lex->yacc_yyvs= (char*)
	my_realloc((gptr) lex->yacc_yyvs,
		   *yystacksize*sizeof(**yyvs),
		   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
      !(lex->yacc_yyss= (char*)
	my_realloc((gptr) lex->yacc_yyss,
		   *yystacksize*sizeof(**yyss),
		   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
    return 1;
  if (old_info)
  {						// Copy old info from stack
    memcpy(lex->yacc_yyss, (gptr) *yyss, old_info*sizeof(**yyss));
    memcpy(lex->yacc_yyvs, (gptr) *yyvs, old_info*sizeof(**yyvs));
  }
  *yyss=(short*) lex->yacc_yyss;
  *yyvs=(YYSTYPE*) lex->yacc_yyvs;
  return 0;
}


/****************************************************************************
2857
	Initialize global thd variables needed for query
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2858 2859 2860 2861 2862 2863
****************************************************************************/

static void
mysql_init_query(THD *thd)
{
  DBUG_ENTER("mysql_init_query");
2864
  thd->lex.select_lex.item_list.empty();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2865
  thd->lex.value_list.empty();
2866
  thd->lex.select_lex.table_list.elements=0;
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
2867
  thd->free_list=0;  thd->lex.union_option=0;
2868 2869 2870
  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;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2871
  thd->lex.select_lex.next=0;
2872
  thd->lex.olap=0;
2873
  thd->lex.select->olap= UNSPECIFIED_OLAP_TYPE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2874 2875
  thd->fatal_error=0;				// Safety
  thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
nick@mysql.com's avatar
nick@mysql.com committed
2876
  thd->rand_used=0;
2877
  thd->sent_row_count=thd->examined_row_count=0;
2878
  thd->safe_to_cache_query=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2879 2880 2881
  DBUG_VOID_RETURN;
}

2882 2883 2884
void
mysql_init_select(LEX *lex)
{
2885 2886
  SELECT_LEX *select_lex = lex->select;
  select_lex->where=select_lex->having=0;
2887
  select_lex->select_limit= lex->thd->variables.select_limit;
2888
  select_lex->offset_limit=0;
2889 2890
  select_lex->options=0;
  select_lex->linkage=UNSPECIFIED_TYPE;
2891
  select_lex->olap=   UNSPECIFIED_OLAP_TYPE;
2892
  lex->exchange = 0;
2893
  lex->proc_list.first=0;
2894 2895
  select_lex->order_list.empty();
  select_lex->group_list.empty();
2896
  select_lex->next = (SELECT_LEX *)NULL; 
2897 2898
}

2899

2900
bool
2901 2902
mysql_new_select(LEX *lex)
{
2903
  SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX));
2904 2905
  if (!select_lex)
    return 1;
2906
  lex->select->next=select_lex; 
2907
  lex->select=select_lex;
2908
  select_lex->table_list.next= (byte**) &select_lex->table_list.first;
2909 2910 2911 2912 2913 2914 2915
  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;
2916
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2917

2918

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2919 2920 2921 2922
void mysql_init_multi_delete(LEX *lex)
{
  lex->sql_command =  SQLCOM_DELETE_MULTI;
  mysql_init_select(lex);
2923
  lex->select->select_limit=lex->thd->select_limit=HA_POS_ERROR;
2924
  lex->select->table_list.save_and_clear(&lex->auxilliary_table_list);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2925
}
2926

2927

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2928 2929 2930 2931 2932 2933 2934
void
mysql_parse(THD *thd,char *inBuf,uint length)
{
  DBUG_ENTER("mysql_parse");

  mysql_init_query(thd);
  thd->query_length = length;
2935
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2936 2937 2938 2939
  {
    LEX *lex=lex_start(thd, (uchar*) inBuf, length);
    if (!yyparse() && ! thd->fatal_error)
    {
2940 2941
      if (mqh_used && thd->user_connect &&
	  check_mqh(thd, thd->lex.sql_command))
2942 2943 2944 2945 2946 2947 2948 2949
      {
	thd->net.error = 0;
      }
      else
      {
	mysql_execute_command();
	query_cache_end_of_result(&thd->net);
      }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2950 2951
    }
    else
2952 2953 2954
    {
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
			 thd->fatal_error));
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2955
      query_cache_abort(&thd->net);
2956
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2957 2958 2959 2960
    thd->proc_info="freeing items";
    free_items(thd);  /* Free strings used by items */
    lex_end(lex);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000
  DBUG_VOID_RETURN;
}


/*****************************************************************************
** 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();
  }

3001
  if (default_value)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3002
  {
3003
    if (default_value->type() == Item::NULL_ITEM)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3004
    {
3005 3006 3007 3008 3009 3010 3011 3012
      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);
      }
    }
3013
#ifdef MYSQL41000
3014 3015 3016
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
      net_printf(&thd->net, ER_INVALID_DEFAULT, field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3017 3018
      DBUG_RETURN(1);
    }
3019
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3020 3021 3022 3023 3024
  }
  if (!(new_field=new create_field()))
    DBUG_RETURN(1);
  new_field->field=0;
  new_field->field_name=field_name;
3025
#ifdef MYSQL41000
3026
  new_field->def= default_value;
3027 3028 3029
#else
  new_field->def= (type_modifier & AUTO_INCREMENT_FLAG ? 0 : default_value);
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3030 3031 3032 3033 3034 3035 3036 3037 3038 3039
  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;
3040 3041
  if (length && !(new_field->length= (uint) atoi(length)))
    length=0; /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3042 3043 3044
  uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;

  if (new_field->length && new_field->decimals &&
3045
      new_field->length < new_field->decimals+1 &&
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3046
      new_field->decimals != NOT_FIXED_DEC)
3047
    new_field->length=new_field->decimals+1; /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072

  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:
3073
  case FIELD_TYPE_GEOMETRY:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3074 3075 3076
    break;
  case FIELD_TYPE_DECIMAL:
    if (!length)
3077 3078 3079 3080 3081 3082 3083
      new_field->length= 10;			// Default length for DECIMAL
    if (new_field->length < MAX_FIELD_WIDTH)	// Skip wrong argument
    {
      new_field->length+=sign_len;
      if (new_field->decimals)
	new_field->length++;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177
    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:
    if (!length)
      new_field->length= 14;			// Full date YYYYMMDDHHMMSS
    else
    {
      new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
      new_field->length= min(new_field->length,14); /* purecov: inspected */
    }
    new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG | NOT_NULL_FLAG;
    break;
  case FIELD_TYPE_DATE:				// Old date type
    if (protocol_version != PROTOCOL_VERSION-1)
      new_field->sql_type=FIELD_TYPE_NEWDATE;
    /* fall trough */
  case FIELD_TYPE_NEWDATE:
    new_field->length=10;
    break;
  case FIELD_TYPE_TIME:
    new_field->length=10;
    break;
  case FIELD_TYPE_DATETIME:
    new_field->length=19;
    break;
  case FIELD_TYPE_SET:
    {
      if (interval->count > sizeof(longlong)*8)
      {
	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++)
3178 3179 3180
      {
	new_field->length+=(uint) strip_sp((char*) *pos)+1;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200
      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
3201
      new_field->length=(uint) strip_sp((char*) interval->type_names[0]);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3202 3203
      for (const char **pos=interval->type_names+1; *pos ; pos++)
      {
3204
	uint length=(uint) strip_sp((char*) *pos);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223
	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) &&
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3224
       type != FIELD_TYPE_STRING && type != FIELD_TYPE_VAR_STRING))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
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 3254
  {
    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
3255
add_proc_to_list(THD* thd, Item *item)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3256 3257 3258 3259 3260 3261 3262 3263 3264 3265
{
  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;
3266
  thd->lex.proc_list.link_in_list((byte*) order,(byte**) &order->next);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3267 3268 3269 3270 3271 3272 3273 3274
  return 0;
}


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

static void remove_escape(char *name)
{
3275 3276
  if (!*name)					// For empty DB names
    return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3277 3278
  char *to;
#ifdef USE_MB
3279
  char *strend=name+(uint) strlen(name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295
#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])
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3296
      name++;					// Skip '\\'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319
    *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;
3320
  list.link_in_list((byte*) order,(byte**) &order->next);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3321 3322 3323 3324
  DBUG_RETURN(0);
}


3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343
/*
  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
*/

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3344
TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
3345 3346
			      ulong table_options,
			      thr_lock_type lock_type,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3347
			      List<String> *use_index,
3348
			      List<String> *ignore_index)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3349 3350 3351 3352 3353 3354 3355 3356 3357
{
  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;
3358
  if (check_table_name(table->table.str,table->table.length) ||
3359
      table->db.str && check_db_name(table->db.str))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3360 3361 3362 3363 3364 3365
  {
    net_printf(&thd->net,ER_WRONG_TABLE_NAME,table->table.str);
    DBUG_RETURN(0);
  }

  if (!alias)					/* Alias is case sensitive */
3366
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3367
      DBUG_RETURN(0);
3368
    
3369
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3370
    DBUG_RETURN(0);				/* purecov: inspected */
3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386
  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;
  }
    
3387
  ptr->alias= alias_str;
3388 3389 3390
  if (lower_case_table_names)
    casedn_str(table->table.str);
  ptr->real_name=table->table.str;
3391
  ptr->real_name_length=table->table.length;
3392 3393 3394
  ptr->lock_type= lock_type;
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3395
  if (use_index)
3396
    ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3397 3398
					       sizeof(*use_index));
  if (ignore_index)
3399 3400
    ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index,
						   sizeof(*ignore_index));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3401 3402

  /* check that used name is unique */
3403
  if (lock_type != TL_IGNORE)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3404
  {
3405 3406
    for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ;
	 tables ;
3407
	 tables=tables->next)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3408
    {
3409
      if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db))
3410
      {
3411 3412
	net_printf(&thd->net,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
	DBUG_RETURN(0);				/* purecov: tested */
3413
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3414 3415
    }
  }
3416
  thd->lex.select->table_list.link_in_list((byte*) ptr,(byte**) &ptr->next);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3417 3418 3419
  DBUG_RETURN(ptr);
}

3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450
/*
  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;
}

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3451 3452 3453 3454 3455 3456 3457

/*
** 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.
*/

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3458
static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result)
3459
{
3460 3461 3462 3463 3464 3465 3466
  /* 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;
  }

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3467 3468
  SELECT_LEX *sl;
  TABLE_LIST **new_table_list= result, *aux;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3469

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3470
  *new_table_list=0;				// end result list
3471
  for (sl= &lex->select_lex; sl; sl=sl->next)
3472
  {
3473
    if (sl->order_list.first && sl->next && !sl->braces)
3474
    {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3475 3476
      net_printf(&thd->net,ER_WRONG_USAGE,"UNION","ORDER BY");
      return 1;
3477
    }
3478
    if ((aux= (TABLE_LIST*) sl->table_list.first))
3479
    {
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3480 3481
      TABLE_LIST *next;
      for (; aux; aux=next)
3482
      {
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3483 3484 3485 3486
	TABLE_LIST *cursor;
	next= aux->next;
	for (cursor= *result; cursor; cursor=cursor->next)
	  if (!strcmp(cursor->db,aux->db) &&
3487
	      !strcmp(cursor->real_name,aux->real_name) &&
3488
	      !strcmp(cursor->alias, aux->alias))
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3489 3490 3491 3492
	    break;
	if (!cursor)
	{
	  /* Add not used table to the total table list */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3493
	  if (!(cursor = (TABLE_LIST *) thd->memdup((char*) aux,
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3494
						    sizeof(*aux))))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3495 3496 3497 3498
	  {
	    send_error(&thd->net,0);
	    return 1;
	  }
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3499 3500
	  *new_table_list= cursor;
	  new_table_list= &cursor->next;
3501
	  *new_table_list=0;			// end result list
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3502
	}
3503 3504
	else
	  aux->shared=1;			// Mark that it's used twice
3505
	aux->table= my_reinterpret_cast(TABLE *) (cursor);
3506 3507 3508
      }
    }
  }
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
3509
  return 0;
3510 3511
}

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3513 3514
void add_join_on(TABLE_LIST *b,Item *expr)
{
3515
  if (expr)
3516
  {
3517 3518 3519 3520 3521 3522 3523 3524
    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();
3525
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3526 3527 3528
}


3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546
/*
  Mark that we have a NATURAL JOIN between two tables

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

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3547 3548 3549 3550 3551 3552 3553
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
{
  b->natural_join=a;
}

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

3554
static bool check_dup(const char *db, const char *name, TABLE_LIST *tables)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3555 3556
{
  for (; tables ; tables=tables->next)
3557
    if (!strcmp(name,tables->real_name) && !strcmp(db,tables->db))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3558 3559 3560 3561
      return 1;
  return 0;
}

3562 3563 3564 3565 3566

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

3567
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3568 3569
{
  bool result=0;
3570
  bool error_already_sent=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3571 3572 3573
  select_errors=0;				/* Write if more errors */
  if (options & REFRESH_GRANT)
  {
3574
    acl_reload(thd);
3575
    grant_reload(thd);
3576
    if (mqh_used)
3577
      reset_mqh(thd,(LEX_USER *) NULL,true);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3578 3579 3580
  }
  if (options & REFRESH_LOG)
  {
3581 3582 3583 3584
    /*
      Flush the normal query log, the update log, the binary log, the slow query
      log, and the relay log (if it exists).
    */
3585 3586 3587 3588
    mysql_log.new_file(1);
    mysql_update_log.new_file(1);
    mysql_bin_log.new_file(1);
    mysql_slow_log.new_file(1);
3589 3590 3591 3592
    LOCK_ACTIVE_MI;
    rotate_relay_log(active_mi);
    UNLOCK_ACTIVE_MI;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3593 3594
    if (ha_flush_logs())
      result=1;
3595 3596
    if (flush_error_log())
      result=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3597
  }
3598
#ifdef HAVE_QUERY_CACHE
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3599 3600
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
3601
    query_cache.pack();				// FLUSH QUERY CACHE
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3602 3603 3604 3605
    options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
3606
    query_cache.flush();			// RESET QUERY CACHE
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3607
  }
3608
#endif /*HAVE_QUERY_CACHE*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3609 3610
  if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
  {
3611
    if ((options & REFRESH_READ_LOCK) && thd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3612
    {
3613 3614
      if (lock_global_read_lock(thd))
	return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3615
    }
3616
    result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3617 3618 3619 3620 3621 3622 3623 3624
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
  if (options & REFRESH_STATUS)
    refresh_status();
  if (options & REFRESH_THREADS)
    flush_thread_cache();
  if (options & REFRESH_MASTER)
3625 3626
    if (reset_master(thd))
      result=1;
3627
#ifdef OPENSSL
3628 3629 3630 3631 3632 3633
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
3634 3635 3636
 if (options & REFRESH_SLAVE)
 {
   LOCK_ACTIVE_MI;
3637
   if (reset_slave(thd, active_mi))
3638
   {
3639
     result=1;
3640 3641 3642 3643 3644 3645 3646 3647
     /*
       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;
   }
3648 3649 3650
   UNLOCK_ACTIVE_MI;
 }
 if (options & REFRESH_USER_RESOURCES)
3651
   reset_mqh(thd,(LEX_USER *) NULL);
3652 3653 3654 3655 3656 3657 3658 3659 3660

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

3661
 return result;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3662 3663 3664
}


3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676
/*
  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
*/

3677
void kill_one_thread(THD *thd, ulong id)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3678 3679 3680
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
3681 3682
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3683 3684 3685 3686
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
3687 3688
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3689 3690 3691
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704
  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);
  }

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724
  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);
}
3725 3726 3727 3728


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

3729
static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
3730
{
3731
  char buff[FN_REFLEN],*ptr, *end;
3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743
  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);
3744
  end=convert_dirname(buff, *filename_ptr, NullS);
3745
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
3746 3747
    return 1;					// End of memory
  *filename_ptr=ptr;
3748
  strxmov(ptr,buff,table_name,NullS);
3749 3750
  return 0;
}
3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775

/*
  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;
}