sql_parse.cc 111 KB
Newer Older
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1
/* Copyright (C) 2000 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

26 27
#define files_charset_info system_charset_info

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

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

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

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

61
static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
62
static void decrease_user_connections(USER_CONN *uc);
63
static bool check_db_used(THD *thd,TABLE_LIST *tables);
64
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
65 66
static void remove_escape(char *name);
static void refresh_status(void);
67 68
static bool append_file_to_dir(THD *thd, char **filename_ptr,
			       char *table_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
69

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

const char *command_name[]={
  "Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
  "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
  "Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
76
  "Binlog Dump","Table Dump",  "Connect Out", "Register Slave",
77
  "Prepare", "Prepare Execute", "Long Data", "Close stmt"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
78 79
};

80
static char empty_c_string[1]= {0};		// Used for not defined 'db'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
81 82 83 84

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

101 102 103 104 105 106 107 108 109 110 111
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)
112
{
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
113
  int error=0;
114
  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
115
		      OPTION_TABLE_LOCK))
116
  {
117 118
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
119
    if (ha_commit(thd))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
120
      error=1;
121
  }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
122
  return error;
123 124 125
}


126 127 128
static HASH hash_user_connections;
extern  pthread_mutex_t LOCK_user_conn;

129 130
static int get_or_create_user_conn(THD *thd, const char *user,
				   const char *host,
peter@mysql.com's avatar
peter@mysql.com committed
131
				   USER_RESOURCES *mqh)
132 133
{
  int return_val=0;
134
  uint temp_len, user_len, host_len;
135 136 137 138 139 140
  char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
  struct  user_conn *uc;

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

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

181
}
182 183 184


/*
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
185 186 187
  Check if user is ok
  Updates:
  thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access
bk@work.mysql.com's avatar
bk@work.mysql.com committed
188 189
*/

peter@mysql.com's avatar
peter@mysql.com committed
190
static int check_user(THD *thd,enum_server_command command, const char *user,
peter@mysql.com's avatar
peter@mysql.com committed
191
		       const char *passwd, const char *db, bool check_count,
192 193 194
                       bool simple_connect, bool do_send_error, 
                       char* crypted_scramble, bool had_password,
                       uint *cur_priv_version, ACL_USER** hint_user)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
195 196
{
  thd->db=0;
197
  thd->db_length=0;
198
  USER_RESOURCES ur;
peter@mysql.com's avatar
peter@mysql.com committed
199 200

  /* We shall avoid dupplicate user allocations here */
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
201
  if (!thd->user && !(thd->user = my_strdup(user, MYF(0))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
202
  {
203
    send_error(thd,ER_OUT_OF_RESOURCES);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
204 205
    return 1;
  }
206
  thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
207 208 209
				 passwd, thd->scramble, &thd->priv_user,
				 protocol_version == 9 ||
				 !(thd->client_capabilities &
peter@mysql.com's avatar
peter@mysql.com committed
210
				   CLIENT_LONG_PASSWORD),&ur,crypted_scramble,
211
                                   cur_priv_version,hint_user);
peter@mysql.com's avatar
peter@mysql.com committed
212

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
213
  DBUG_PRINT("info",
bk@work.mysql.com's avatar
bk@work.mysql.com committed
214
	     ("Capabilities: %d  packet_length: %d  Host: '%s'  User: '%s'  Using password: %s  Access: %u  db: '%s'",
215
	      thd->client_capabilities, thd->max_client_packet_length,
216
	      thd->host_or_ip, thd->priv_user,
217
	      had_password ? "yes": "no",
bk@work.mysql.com's avatar
bk@work.mysql.com committed
218
	      thd->master_access, thd->db ? thd->db : "*none*"));
peter@mysql.com's avatar
peter@mysql.com committed
219 220

  /* in case we're going to retry we should not send error message at this point */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
221 222
  if (thd->master_access & NO_ACCESS)
  {
223 224
    if (do_send_error)
    {
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
      /* Old client should get nicer error message if password version is not supported*/
      if (simple_connect && *hint_user && (*hint_user)->pversion)
      {
        net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
        mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
      }
      else
      {
        net_printf(thd, ER_ACCESS_DENIED_ERROR,
      	         thd->user,
	         thd->host_or_ip,
	         had_password ? ER(ER_YES) : ER(ER_NO));
        mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
	              thd->user,
                      thd->host_or_ip,
	              had_password ? ER(ER_YES) : ER(ER_NO));
      }                
242
      return(1);					// Error already given
peter@mysql.com's avatar
peter@mysql.com committed
243 244
    }
    else
245
      return(-1); // do not report error in special handshake
bk@work.mysql.com's avatar
bk@work.mysql.com committed
246
  }
peter@mysql.com's avatar
peter@mysql.com committed
247

bk@work.mysql.com's avatar
bk@work.mysql.com committed
248 249 250 251
  if (check_count)
  {
    VOID(pthread_mutex_lock(&LOCK_thread_count));
    bool tmp=(thread_count - delayed_insert_threads >= max_connections &&
252
	      !(thd->master_access & SUPER_ACL));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
253 254 255
    VOID(pthread_mutex_unlock(&LOCK_thread_count));
    if (tmp)
    {						// Too many connections
256
      send_error(thd, ER_CON_COUNT_ERROR);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
257 258 259
      return(1);
    }
  }
260
  mysql_log.write(thd,command,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
261 262 263 264
		  (thd->priv_user == thd->user ?
		   (char*) "%s@%s on %s" :
		   (char*) "%s@%s as anonymous on %s"),
		  user,
265
		  thd->host_or_ip,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
266 267
		  db ? db : (char*) "");
  thd->db_access=0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
268
  /* Don't allow user to connect if he has done too many queries */
269 270
  if ((ur.questions || ur.updates || ur.connections) &&
      get_or_create_user_conn(thd,user,thd->host_or_ip,&ur))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
271
    return -1;
peter@mysql.com's avatar
peter@mysql.com committed
272
  if (thd->user_connect && thd->user_connect->user_resources.connections &&
273
      check_for_max_user_connections(thd, thd->user_connect))
274
    return -1;
peter@mysql.com's avatar
peter@mysql.com committed
275

bk@work.mysql.com's avatar
bk@work.mysql.com committed
276
  if (db && db[0])
277 278
  {
    bool error=test(mysql_change_db(thd,db));
279 280
    if (error && thd->user_connect)
      decrease_user_connections(thd->user_connect);
peter@mysql.com's avatar
peter@mysql.com committed
281
    return error;
282
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
283
  else
284
    send_ok(thd);				// Ready to handle questions
bk@work.mysql.com's avatar
bk@work.mysql.com committed
285 286 287
  return 0;					// ok
}

288

289
/*
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
290 291
  Check for maximum allowable user connections, if the mysqld server is
  started with corresponding variable that is greater then 0.
292 293
*/

294 295
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
296 297 298 299 300
{
  *length=buff->len;
  return (byte*) buff->user;
}

301
extern "C" void free_user(struct user_conn *uc)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
302 303 304 305
{
  my_free((char*) uc,MYF(0));
}

peter@mysql.com's avatar
peter@mysql.com committed
306
void init_max_user_conn(void)
307
{
308 309
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
		   0,0,
310
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
311
		   0);
312 313 314
}


315
static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
316
{
317
  int error=0;
318
  DBUG_ENTER("check_for_max_user_connections");
peter@mysql.com's avatar
peter@mysql.com committed
319

320 321
  if (max_user_connections &&
      (max_user_connections <=  (uint) uc->connections))
322
  {
323
    net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user);
324 325
    error=1;
    goto end;
326
  }
peter@mysql.com's avatar
peter@mysql.com committed
327
  uc->connections++;
328 329
  if (uc->user_resources.connections &&
      uc->conn_per_hour++ >= uc->user_resources.connections)
330
  {
331
    net_printf(thd, ER_USER_LIMIT_REACHED, uc->user,
332
	       "max_connections",
333 334 335
	       (long) uc->user_resources.connections);
    error=1;
  }
336 337
end:
  DBUG_RETURN(error);
338 339 340
}


341
static void decrease_user_connections(USER_CONN *uc)
342
{
343
  DBUG_ENTER("decrease_user_connections");
344
  if ((uc->connections && !--uc->connections) && !mqh_used)
345 346
  {
    /* Last connection for user; Delete it */
347
    (void) pthread_mutex_lock(&LOCK_user_conn);
348
    (void) hash_delete(&hash_user_connections,(byte*) uc);
349
    (void) pthread_mutex_unlock(&LOCK_user_conn);
350
  }
351
  DBUG_VOID_RETURN;
352 353
}

354

355 356 357 358 359
void free_max_user_conn(void)
{
  hash_free(&hash_user_connections);
}

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
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 385 386 387 388
/*
  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;
389
  uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
390 391 392
}


monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
393 394 395
/*
  Check if maximum queries per hour limit has been reached
  returns 0 if OK.
396

397 398 399
  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
400 401
*/

402

403
static bool check_mqh(THD *thd, uint check_command)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
404 405
{
  bool error=0;
406
  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
407
  USER_CONN *uc=thd->user_connect;
408
  DBUG_ENTER("check_mqh");
409
  DBUG_ASSERT(uc != 0);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
410

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

446

447
static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
448 449
{

450
  (void) pthread_mutex_lock(&LOCK_user_conn);
peter@mysql.com's avatar
peter@mysql.com committed
451
  if (lu)  // for GRANT
452
  {
453
    USER_CONN *uc;
454
    uint temp_len=lu->user.length+lu->host.length+2;
455 456
    char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];

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

484

bk@work.mysql.com's avatar
bk@work.mysql.com committed
485
/*
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
486 487
  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
488 489 490 491 492 493 494
*/

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
495
  /* Store the connection details */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
496 497
  DBUG_PRINT("info", (("check_connections called by thread %d"),
	     thd->thread_id));
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
498
  DBUG_PRINT("info",("New connection received on %s",
bk@work.mysql.com's avatar
bk@work.mysql.com committed
499 500 501
			vio_description(net->vio)));
  if (!thd->host)                           // If TCP/IP connection
  {
502
    char ip[30];
503

bk@work.mysql.com's avatar
bk@work.mysql.com committed
504 505 506 507
    if (vio_peer_addr(net->vio,ip))
      return (ER_BAD_HOST_ERROR);
    if (!(thd->ip = my_strdup(ip,MYF(0))))
      return (ER_OUT_OF_RESOURCES);
508
    thd->host_or_ip=thd->ip;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
509 510 511
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
    /* Fast local hostname resolve for Win32 */
    if (!strcmp(thd->ip,"127.0.0.1"))
512
      thd->host=(char*) localhost;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
513 514 515 516 517 518 519 520 521
    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);
      if (connect_errors > max_connect_errors)
	return(ER_HOST_IS_BLOCKED);
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
522 523 524
    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
525 526 527
    if (acl_check_host(thd->host,thd->ip))
      return(ER_HOST_NOT_PRIVILEGED);
  }
528
  else /* Hostname given means that the connection was on a socket */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
529
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
530
    DBUG_PRINT("info",("Host: %s",thd->host));
531
    thd->host_or_ip=thd->host;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
532 533 534 535 536
    thd->ip=0;
    bzero((char*) &thd->remote,sizeof(struct sockaddr));
  }
  vio_keepalive(net->vio, TRUE);

537
  ulong pkt_len=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
538
  {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
539
    /* buff[] needs to big enough to hold the server_version variable */
peter@mysql.com's avatar
peter@mysql.com committed
540
    char buff[SERVER_VERSION_LENGTH +
541
    SCRAMBLE_LENGTH+64],*end;
peter@mysql.com's avatar
peter@mysql.com committed
542
    int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
543
                       CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION;
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;
peter@mysql.com's avatar
peter@mysql.com committed
565

566
    // At this point we write connection message and read reply
567
    if (net_write_command(net,(uchar) protocol_version, "", 0, buff,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
568
			  (uint) (end-buff)) ||
569
       (pkt_len= my_net_read(net)) == packet_error ||
bk@work.mysql.com's avatar
bk@work.mysql.com committed
570 571 572 573 574 575 576 577 578 579 580
	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);
581
  if (thd->packet.alloc(thd->variables.net_buffer_length))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
582 583 584
    return(ER_OUT_OF_RESOURCES);

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

621
  thd->max_client_packet_length=uint3korr(net->read_pos+2);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
622 623 624
  char *user=   (char*) net->read_pos+5;
  char *passwd= strend(user)+1;
  char *db=0;
peter@mysql.com's avatar
peter@mysql.com committed
625 626 627
  if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
     db=strend(passwd)+1;

628
  /* We can get only old hash at this point */
peter@mysql.com's avatar
peter@mysql.com committed
629
  if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
630
      return ER_HANDSHAKE_ERROR;
peter@mysql.com's avatar
peter@mysql.com committed
631

bk@work.mysql.com's avatar
bk@work.mysql.com committed
632
  if (thd->client_capabilities & CLIENT_INTERACTIVE)
633
     thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
634
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
635 636
       opt_using_transactions)
  thd->net.return_status= &thd->server_status;
637
  net->read_timeout=(uint) thd->variables.net_read_timeout;
peter@mysql.com's avatar
peter@mysql.com committed
638

639
  char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble and hash */
peter@mysql.com's avatar
peter@mysql.com committed
640

641
  ACL_USER* cached_user=NULL; /* Initialise to NULL as first stage indication */
peter@mysql.com's avatar
peter@mysql.com committed
642
  uint cur_priv_version;
peter@mysql.com's avatar
peter@mysql.com committed
643

644 645
  /* Simple connect only for old clients. New clients always use secure auth */
  bool simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
peter@mysql.com's avatar
peter@mysql.com committed
646

647 648 649
  /* Store information if we used password. passwd will be dammaged */
  bool using_password=test(passwd[0]);
  /* Check user permissions. If password failure we'll get scramble back */
650 651 652
  if (check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect,
      simple_connect, prepared_scramble, using_password, &cur_priv_version,
      &cached_user)<0)
peter@mysql.com's avatar
peter@mysql.com committed
653
  {
654 655
    /* If The client is old we just have to return error */
    if (simple_connect)
peter@mysql.com's avatar
peter@mysql.com committed
656 657
      return -1;

658
    /* Store current used and database as they are erased with next packet */
peter@mysql.com's avatar
peter@mysql.com committed
659

660 661 662
    char tmp_user[USERNAME_LENGTH+1];
    char tmp_db[NAME_LEN+1];

peter@mysql.com's avatar
peter@mysql.com committed
663
    tmp_user[0]=0;
664
    if (user)
peter@mysql.com's avatar
peter@mysql.com committed
665 666
      strmake(tmp_user,user,USERNAME_LENGTH);

667
    tmp_db[0]=0;
668
    if (db)
peter@mysql.com's avatar
peter@mysql.com committed
669 670
      strmake(tmp_db,db,NAME_LEN);

671
    /* Write hash and encrypted scramble to client */
672 673
    if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
        net_flush(net))
674 675 676
      {
        inc_host_errors(&thd->remote.sin_addr);
        return ER_HANDSHAKE_ERROR;
peter@mysql.com's avatar
peter@mysql.com committed
677 678 679
      }
    /* Reading packet back */
    if ((pkt_len=my_net_read(net)) == packet_error)
680 681 682 683
      {
        inc_host_errors(&thd->remote.sin_addr);
        return ER_HANDSHAKE_ERROR;
      }
peter@mysql.com's avatar
peter@mysql.com committed
684 685
    /* We have to get very specific packet size  */
    if (pkt_len!=SCRAMBLE41_LENGTH)
686 687
      {
        inc_host_errors(&thd->remote.sin_addr);
peter@mysql.com's avatar
peter@mysql.com committed
688
        return ER_HANDSHAKE_ERROR;
689
      }
peter@mysql.com's avatar
peter@mysql.com committed
690 691
    /* Final attempt to check the user based on reply */
    if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos,
692
        tmp_db, 1, 0, 1, prepared_scramble, using_password, &cur_priv_version,
peter@mysql.com's avatar
peter@mysql.com committed
693
        &cached_user))
694 695 696
      return -1;
  }
  thd->password=using_password;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
697 698 699 700 701 702 703 704
  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
705
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
706 707 708 709 710
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status );

  pthread_detach_this_thread();

711 712
#if !defined( __WIN__) && !defined(OS2)	// Win32 calls this in pthread_create
  // The following calls needs to be done before we call DBUG_ macros
713
  if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
714 715
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
716
    statistic_increment(aborted_connects,&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
717 718 719 720 721
    end_thread(thd,0);
    return 0;
  }
#endif

722 723 724 725 726 727 728
  /*
    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
729 730 731 732
  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
733
#if defined(__WIN__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
734
  init_signals();				// IRENA; testing ?
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
735
#elif !defined(OS2)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
736 737 738 739 740 741 742
  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);
743
    statistic_increment(aborted_connects,&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
744 745 746 747 748 749 750 751 752 753 754 755 756
    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)
757
	net_printf(thd,error,thd->host_or_ip);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
758 759 760 761
#ifdef __NT__
      if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
	sleep(1);				/* must wait after eof() */
#endif
762
      statistic_increment(aborted_connects,&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
763 764 765
      goto end_thread;
    }

766
    if ((ulong) thd->variables.max_join_size == (ulonglong) HA_POS_ERROR)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
767 768 769 770
      thd->options |= OPTION_BIG_SELECTS;
    if (thd->client_capabilities & CLIENT_COMPRESS)
      net->compress=1;				// Use compression

771
    thd->proc_info=0;				// Remove 'login'
772
    thd->command=COM_SLEEP;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
773 774
    thd->version=refresh_version;
    thd->set_time();
775 776 777
    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
778 779 780 781 782
    while (!net->error && net->vio != 0 && !thd->killed)
    {
      if (do_command(thd))
	break;
    }
783 784
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
785
    free_root(&thd->mem_root,MYF(0));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
786
    if (net->error && net->vio != 0 && net->report_error)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
787
    {
788
      if (!thd->killed && thd->variables.log_warnings)
789 790 791 792 793 794
	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)));
795
      send_error(thd,net->last_errno,NullS);
796
      statistic_increment(aborted_threads,&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
797
    }
peter@mysql.com's avatar
peter@mysql.com committed
798

bk@work.mysql.com's avatar
bk@work.mysql.com committed
799 800 801 802 803 804 805 806 807 808 809 810 811
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 */
}

812 813 814 815
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
816

817
extern "C" pthread_handler_decl(handle_bootstrap,arg)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
818
{
819 820 821
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
822

823
  /* The following must be called before DBUG_ENTER */
824
  if (my_thread_init() || thd->store_globals())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
825 826
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
827 828
    thd->fatal_error=1;
    goto end;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
829
  }
830 831 832 833
  DBUG_ENTER("handle_bootstrap");

  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
834
#if !defined(__WIN__) && !defined(OS2)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
835
  sigset_t set;
836 837 838 839
  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
840 841
#endif

842
  if ((ulong) thd->variables.max_join_size == (ulonglong) HA_POS_ERROR)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
843 844 845 846
    thd->options |= OPTION_BIG_SELECTS;

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

849
  buff= (char*) thd->net.buff;
850 851 852
  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
853 854
  while (fgets(buff, thd->net.max_packet, file))
  {
855
    uint length=(uint) strlen(buff);
peter@mysql.com's avatar
peter@mysql.com committed
856
    while (length && (my_isspace(system_charset_info, buff[length-1]) ||
857
           buff[length-1] == ';'))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
858 859 860
      length--;
    buff[length]=0;
    thd->current_tablenr=0;
861
    thd->query_length=length;
862 863
    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
864
    thd->query_id=query_id++;
865
    if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
866 867 868 869 870 871
    {
      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
872 873 874
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
    if (thd->fatal_error)
875
      break;
876
    free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
877
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
878
  }
879 880 881 882 883 884

  /* 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);
885
  (void) pthread_cond_broadcast(&COND_thread_count);
886 887 888
  my_thread_end();
  pthread_exit(0);
  DBUG_RETURN(0);				// Never reached
bk@work.mysql.com's avatar
bk@work.mysql.com committed
889 890
}

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

893
void free_items(Item *item)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
894
{
895
  for (; item ; item=item->next)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
896 897 898 899 900 901 902 903 904 905
    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;
906
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
907
    DBUG_RETURN(1); // out of memory
bk@work.mysql.com's avatar
bk@work.mysql.com committed
908
  table_list->db = db;
909
  table_list->real_name = table_list->alias = tbl_name;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
910 911 912
  table_list->lock_type = TL_READ_NO_INSERT;
  table_list->next = 0;
  remove_escape(table_list->real_name);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
913

914
  if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
915 916
    DBUG_RETURN(1);

917 918
  if (!db || check_db_name(db))
  {
919
    net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
920 921
    goto err;
  }
922
  if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
923
    goto err;
924
  if (grant_option && check_grant(thd, SELECT_ACL, table_list))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
925 926 927
    goto err;

  thd->free_list = 0;
928
  thd->query_length=(uint) strlen(tbl_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
929
  thd->query = tbl_name;
930 931 932 933 934
  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
935
  net_flush(&thd->net);
936 937
  if ((error = table->file->dump(thd,fd)))
    my_error(ER_GET_ERRNO, MYF(0));
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
938

bk@work.mysql.com's avatar
bk@work.mysql.com committed
939 940
err:
  close_thread_tables(thd);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
941
  DBUG_RETURN(error);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
942 943 944 945 946 947 948 949
}


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

bool do_command(THD *thd)
{
  char *packet;
950 951
  uint old_timeout;
  ulong packet_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
952 953 954 955 956 957 958 959
  NET *net;
  enum enum_server_command command;
  DBUG_ENTER("do_command");

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

  packet=0;
960 961 962
  old_timeout=net->read_timeout;
  // Wait max for 8 hours
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
963
  thd->clear_error();				// Clear error message
bk@work.mysql.com's avatar
bk@work.mysql.com committed
964 965 966 967

  net_new_transaction(net);
  if ((packet_length=my_net_read(net)) == packet_error)
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
968 969
     DBUG_PRINT("info",("Got error reading command from socket %s",
			vio_description(net->vio) ));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
970 971 972 973 974 975
    return TRUE;
  }
  else
  {
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
976 977 978
    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
979
  }
980
  net->read_timeout=old_timeout;		// restore it
981
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
982 983 984 985 986 987 988 989
}


bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
  bool	error=0;
990 991 992 993
  /*
    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
  */
994 995 996
  bool slow_command=FALSE;
  DBUG_ENTER("dispatch_command");

bk@work.mysql.com's avatar
bk@work.mysql.com committed
997
  thd->command=command;
998
  thd->set_time();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
999 1000 1001 1002 1003 1004
  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));
1005

1006
  thd->lex.select_lex.options=0;		// We store status here
1007
  switch (command) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1008
  case COM_INIT_DB:
1009
    statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
1010
    if (!mysql_change_db(thd,packet))
1011
      mysql_log.write(thd,command,"%s",thd->db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1012
    break;
1013 1014
  case COM_REGISTER_SLAVE:
  {
1015
    if (!register_slave(thd, (uchar*)packet, packet_length))
1016
      send_ok(thd);
1017 1018
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1019 1020
  case COM_TABLE_DUMP:
    {
1021
      statistic_increment(com_other, &LOCK_status);
1022
      slow_command = TRUE;
1023 1024
      uint db_len = *(uchar*)packet;
      uint tbl_len = *(uchar*)(packet + db_len + 1);
1025
      char* db = thd->alloc(db_len + tbl_len + 2);
1026
      memcpy(db, packet + 1, db_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1027 1028
      char* tbl_name = db + db_len;
      *tbl_name++ = 0;
1029
      memcpy(tbl_name, packet + db_len + 2, tbl_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1030
      tbl_name[tbl_len] = 0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1031
      if (mysql_table_dump(thd, db, tbl_name, -1))
1032
	send_error(thd); // dump to NET
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1033

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1034 1035 1036 1037
      break;
    }
  case COM_CHANGE_USER:
  {
1038 1039 1040 1041
    thd->change_user();
    clear_error_message(thd);			// If errors from rollback

    statistic_increment(com_other,&LOCK_status);
1042
    char *user=   (char*) packet;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1043 1044
    char *passwd= strend(user)+1;
    char *db=     strend(passwd)+1;
peter@mysql.com's avatar
peter@mysql.com committed
1045

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1046 1047 1048
    /* Save user and privileges */
    uint save_master_access=thd->master_access;
    uint save_db_access=    thd->db_access;
1049
    uint save_db_length=    thd->db_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1050
    char *save_user=	    thd->user;
peter@mysql.com's avatar
peter@mysql.com committed
1051
    thd->user=NULL; /* Needed for check_user to allocate new user */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1052 1053
    char *save_priv_user=   thd->priv_user;
    char *save_db=	    thd->db;
peter@mysql.com's avatar
peter@mysql.com committed
1054 1055 1056
    USER_CONN *save_uc=     thd->user_connect;
    bool simple_connect;
    bool using_password;
peter@mysql.com's avatar
peter@mysql.com committed
1057

peter@mysql.com's avatar
peter@mysql.com committed
1058
    ulong pkt_len=0; /* Length of reply packet */
peter@mysql.com's avatar
peter@mysql.com committed
1059

peter@mysql.com's avatar
peter@mysql.com committed
1060
    /* Small check for incomming packet */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1061 1062

    if ((uint) ((uchar*) db - net->read_pos) > packet_length)
peter@mysql.com's avatar
peter@mysql.com committed
1063
      goto restore_user_err;
peter@mysql.com's avatar
peter@mysql.com committed
1064

peter@mysql.com's avatar
peter@mysql.com committed
1065
    /* Now we shall basically perform authentication again */
peter@mysql.com's avatar
peter@mysql.com committed
1066

peter@mysql.com's avatar
peter@mysql.com committed
1067
     /* We can get only old hash at this point */
peter@mysql.com's avatar
peter@mysql.com committed
1068
    if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
peter@mysql.com's avatar
peter@mysql.com committed
1069
      goto restore_user_err;
peter@mysql.com's avatar
peter@mysql.com committed
1070 1071

    char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */
1072 1073
    ACL_USER* cached_user     ;                 /* Cached user */
    cached_user= NULL;
peter@mysql.com's avatar
peter@mysql.com committed
1074
    uint cur_priv_version;                      /* Cached grant version */
peter@mysql.com's avatar
peter@mysql.com committed
1075

peter@mysql.com's avatar
peter@mysql.com committed
1076 1077
    /* Simple connect only for old clients. New clients always use sec. auth*/
    simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
peter@mysql.com's avatar
peter@mysql.com committed
1078

peter@mysql.com's avatar
peter@mysql.com committed
1079 1080
    /* Store information if we used password. passwd will be dammaged */
    using_password=test(passwd[0]);
peter@mysql.com's avatar
peter@mysql.com committed
1081 1082 1083 1084 1085 1086 1087 1088

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

    /*
     Check user permissions. If password failure we'll get scramble back
     Do not retry if we already have sent error (result>0)
    */
peter@mysql.com's avatar
peter@mysql.com committed
1089
    if (check_user(thd,COM_CHANGE_USER, user, passwd, db, 0, simple_connect,
1090 1091
        simple_connect, prepared_scramble, using_password, &cur_priv_version,
        &cached_user)<0)
peter@mysql.com's avatar
peter@mysql.com committed
1092 1093 1094 1095
    {
      /* If The client is old we just have to have auth failure */
      if (simple_connect)
        goto restore_user; /* Error is already reported */
peter@mysql.com's avatar
peter@mysql.com committed
1096

peter@mysql.com's avatar
peter@mysql.com committed
1097
      /* Store current used and database as they are erased with next packet */
peter@mysql.com's avatar
peter@mysql.com committed
1098

peter@mysql.com's avatar
peter@mysql.com committed
1099 1100
      char tmp_user[USERNAME_LENGTH+1];
      char tmp_db[NAME_LEN+1];
1101 1102
     
      tmp_user[0]=0;
peter@mysql.com's avatar
peter@mysql.com committed
1103
      if (user)
1104 1105 1106
        strmake(tmp_user,user,USERNAME_LENGTH);

      tmp_db[0]=0;
peter@mysql.com's avatar
peter@mysql.com committed
1107
      if (db)
1108 1109
        strmake(tmp_db,db,NAME_LEN);

peter@mysql.com's avatar
peter@mysql.com committed
1110

peter@mysql.com's avatar
peter@mysql.com committed
1111
      /* Write hash and encrypted scramble to client */
1112 1113
      if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
          net_flush(net))
peter@mysql.com's avatar
peter@mysql.com committed
1114
        goto restore_user_err;
peter@mysql.com's avatar
peter@mysql.com committed
1115 1116 1117 1118 1119 1120 1121

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

      /* We have to get very specific packet size  */
      if (pkt_len!=SCRAMBLE41_LENGTH)
peter@mysql.com's avatar
peter@mysql.com committed
1122
        goto restore_user;
peter@mysql.com's avatar
peter@mysql.com committed
1123 1124

      /* Final attempt to check the user based on reply */
1125
      if (check_user(thd,COM_CHANGE_USER, tmp_user, (char*)net->read_pos,
1126
          tmp_db, 0, 0, 1, prepared_scramble, using_password, &cur_priv_version,
peter@mysql.com's avatar
peter@mysql.com committed
1127 1128
          &cached_user))
        goto restore_user;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1129
    }
peter@mysql.com's avatar
peter@mysql.com committed
1130
    /* Finally we've authenticated new user */
1131
    if (max_connections && save_uc)
1132
      decrease_user_connections(save_uc);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1133 1134
    x_free((gptr) save_db);
    x_free((gptr) save_user);
peter@mysql.com's avatar
peter@mysql.com committed
1135 1136
    thd->password=using_password;
    break;
peter@mysql.com's avatar
peter@mysql.com committed
1137

peter@mysql.com's avatar
peter@mysql.com committed
1138 1139 1140
    /* Bad luck  we shall restore old user */
    restore_user_err:
    send_error(thd, ER_UNKNOWN_COM_ERROR);
peter@mysql.com's avatar
peter@mysql.com committed
1141

peter@mysql.com's avatar
peter@mysql.com committed
1142 1143 1144 1145 1146 1147 1148 1149
    restore_user:
    x_free(thd->user);
    x_free(thd->db);
    thd->master_access=save_master_access;
    thd->db_access=save_db_access;
    thd->db=save_db;
    thd->db_length=save_db_length;
    thd->user=save_user;
peter@mysql.com's avatar
peter@mysql.com committed
1150
    thd->priv_user=save_priv_user;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1151 1152
    break;
  }
peter@mysql.com's avatar
peter@mysql.com committed
1153

1154 1155
  case COM_EXECUTE:
  {
1156
    mysql_stmt_execute(thd, packet);
1157 1158 1159 1160
    break;
  }
  case COM_LONG_DATA:
  {
1161
    mysql_stmt_get_longdata(thd, packet, packet_length);
1162 1163 1164 1165
    break;
  }
  case COM_PREPARE:
  {
1166
    mysql_stmt_prepare(thd, packet, packet_length);
1167 1168
    break;
  }
1169 1170 1171 1172 1173
  case COM_CLOSE_STMT:
  {
    mysql_stmt_free(thd, packet);
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1174 1175
  case COM_QUERY:
  {
1176 1177
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
1178
    mysql_log.write(thd,command,"%s",thd->query);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1179
    DBUG_PRINT("query",("%s",thd->query));
1180
    mysql_parse(thd,thd->query, thd->query_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1181 1182 1183 1184 1185
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1186
  case COM_FIELD_LIST:				// This isn't actually needed
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1187
#ifdef DONT_ALLOW_SHOW_COMMANDS
1188
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1189 1190 1191 1192 1193
    break;
#else
  {
    char *fields;
    TABLE_LIST table_list;
1194
    statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1195 1196 1197
    bzero((char*) &table_list,sizeof(table_list));
    if (!(table_list.db=thd->db))
    {
1198
      send_error(thd,ER_NO_DB_ERROR);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1199 1200 1201
      break;
    }
    thd->free_list=0;
1202
    table_list.alias= table_list.real_name= thd->strdup(packet);
1203
    packet=strend(packet)+1;
1204
    // command not cachable => no gap for data base name
1205 1206
    if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
      break;
1207
    mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1208 1209 1210 1211 1212 1213 1214 1215
    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);
1216
    free_items(thd->free_list);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1217 1218 1219 1220
    break;
  }
#endif
  case COM_QUIT:
1221
    /* We don't calculate statistics for this command */
1222
    mysql_log.write(thd,command,NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1223 1224 1225 1226
    net->error=0;				// Don't give 'abort' message
    error=TRUE;					// End server
    break;

1227
  case COM_CREATE_DB:				// QQ: To be removed
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1228
    {
1229
      statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
1230
      char *db=thd->strdup(packet);
1231
      // null test to handle EOM
1232
      if (!db || !strip_sp(db) || check_db_name(db))
1233
      {
1234
	net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
1235 1236
	break;
      }
1237
      if (lower_case_table_names)
1238
	my_casedn_str(files_charset_info, db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1239 1240
      if (check_access(thd,CREATE_ACL,db,0,1))
	break;
1241
      mysql_log.write(thd,command,packet);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1242
      mysql_create_db(thd,db,0,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1243 1244
      break;
    }
1245
  case COM_DROP_DB:				// QQ: To be removed
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1246
    {
1247
      statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
1248
      char *db=thd->strdup(packet);
1249
      // null test to handle EOM
1250
      if (!db || !strip_sp(db) || check_db_name(db))
1251
      {
1252
	net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
1253 1254
	break;
      }
1255
      if (lower_case_table_names)
1256
	my_casedn_str(files_charset_info, db);
1257 1258
      if (thd->locked_tables || thd->active_transaction())
      {
1259
	send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1260
	break;
1261
      }
1262
      mysql_log.write(thd,command,db);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1263
      mysql_rm_db(thd,db,0,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1264 1265 1266 1267
      break;
    }
  case COM_BINLOG_DUMP:
    {
1268
      statistic_increment(com_other,&LOCK_status);
1269
      slow_command = TRUE;
1270
      if (check_global_access(thd, REPL_SLAVE_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1271
	break;
1272
      mysql_log.write(thd,command, 0);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1273

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1274 1275
      ulong pos;
      ushort flags;
1276
      uint32 slave_server_id;
1277
      /* TODO: The following has to be changed to an 8 byte integer */
1278 1279
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
1280
      thd->server_id=0; /* avoid suicide */
1281
      kill_zombie_dump_threads(slave_server_id = uint4korr(packet+6));
1282
      thd->server_id = slave_server_id;
1283
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
1284
      unregister_slave(thd,1,1);
1285 1286 1287
      // 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
1288 1289 1290 1291
      break;
    }
  case COM_REFRESH:
    {
1292
      statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
1293
      ulong options= (ulong) (uchar) packet[0];
1294
      if (check_global_access(thd,RELOAD_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1295
	break;
1296
      mysql_log.write(thd,command,NullS);
1297
      if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0))
1298
	send_error(thd,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1299
      else
1300
	send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1301 1302 1303
      break;
    }
  case COM_SHUTDOWN:
1304
    statistic_increment(com_other,&LOCK_status);
1305
    if (check_global_access(thd,SHUTDOWN_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1306 1307
      break; /* purecov: inspected */
    DBUG_PRINT("quit",("Got shutdown command"));
1308
    mysql_log.write(thd,command,NullS);
1309
    send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1310 1311 1312
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1313
#ifndef OS2
1314
    send_eof(thd);				// This is for 'quit request'
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1315
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1316 1317
    close_connection(net);
    close_thread_tables(thd);			// Free before kill
1318
    free_root(&thd->mem_root,MYF(0));
1319
    free_root(&thd->transaction.mem_root,MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1320 1321 1322 1323 1324 1325
    kill_mysql();
    error=TRUE;
    break;

  case COM_STATISTICS:
  {
1326
    mysql_log.write(thd,command,NullS);
1327
    statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1328
    char buff[200];
1329
    ulong uptime = (ulong) (thd->start_time - start_time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1330
    sprintf((char*) buff,
1331
	    "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
1332 1333 1334 1335 1336 1337 1338 1339 1340
	    uptime,
	    (int) thread_count,thd->query_id,long_query_count,
	    opened_tables,refresh_version, cached_tables(),
	    uptime ? (float)thd->query_id/(float)uptime : 0);
#ifdef SAFEMALLOC
    if (lCurMemory)				// Using SAFEMALLOC
      sprintf(strend(buff), "  Memory in use: %ldK  Max memory used: %ldK",
	      (lCurMemory+1023L)/1024L,(lMaxMemory+1023L)/1024L);
 #endif
1341
    VOID(my_net_write(net, buff,(uint) strlen(buff)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1342 1343 1344 1345
    VOID(net_flush(net));
    break;
  }
  case COM_PING:
1346
    statistic_increment(com_other,&LOCK_status);
1347
    send_ok(thd);				// Tell client we are alive
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1348 1349
    break;
  case COM_PROCESS_INFO:
1350
    statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
1351
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1352
      break;
1353
    mysql_log.write(thd,command,NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1354 1355 1356 1357 1358
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
			  thd->priv_user,0);
    break;
  case COM_PROCESS_KILL:
  {
1359
    statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
1360
    ulong id=(ulong) uint4korr(packet);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1361 1362 1363 1364
    kill_one_thread(thd,id);
    break;
  }
  case COM_DEBUG:
1365
    statistic_increment(com_other,&LOCK_status);
1366
    if (check_global_access(thd, SUPER_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1367 1368
      break;					/* purecov: inspected */
    mysql_print_status(thd);
1369
    mysql_log.write(thd,command,NullS);
1370
    send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1371 1372 1373 1374 1375 1376
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
  default:
1377
    send_error(thd, ER_UNKNOWN_COM_ERROR);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1378 1379 1380 1381 1382 1383 1384 1385 1386
    break;
  }
  if (thd->lock || thd->open_tables)
  {
    thd->proc_info="closing tables";
    close_thread_tables(thd);			/* Free tables */
  }

  if (thd->fatal_error)
1387
    send_error(thd,0);				// End of memory ?
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1388 1389

  time_t start_of_query=thd->start_time;
1390
  thd->end_time();				// Set start time
1391

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

1397 1398
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
1399
	((thd->lex.select_lex.options &
1400
	  (QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED)) &&
1401
	 (specialflag & SPECIAL_LONG_LOG_FORMAT)))
1402 1403 1404 1405
    {
      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
1406
  }
1407
  thd->proc_info="cleaning up";
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1408 1409 1410 1411 1412 1413
  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));
1414
  thd->packet.shrink(thd->variables.net_buffer_length);	// Reclaim some memory
1415
  free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1416 1417 1418
  DBUG_RETURN(error);
}

1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443

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

  DESCRIPTION
    Sets the following THD variables:
      query
      query_length

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

bool alloc_query(THD *thd, char *packet, ulong packet_length)
{
  packet_length--;				// Remove end null
  /* Remove garage at start and end of query */
  while (my_isspace(system_charset_info,packet[0]) && packet_length > 0)
  {
    packet++;
    packet_length--;
  }
  char *pos=packet+packet_length;		// Point at end null
peter@mysql.com's avatar
peter@mysql.com committed
1444
  while (packet_length > 0 &&
1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463
	 (pos[-1] == ';' || my_isspace(system_charset_info,pos[-1])))
  {
    pos--;
    packet_length--;
  }
  /* We must allocate some extra memory for query cache */
  if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
					      packet_length,
					      thd->db_length+2)))
    return 1;
  thd->query[packet_length]=0;
  thd->query_length= packet_length;
  thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1464 1465 1466 1467 1468 1469
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/

void
1470
mysql_execute_command(THD *thd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1471
{
1472
  int	res= 0;
1473
  LEX	*lex= &thd->lex;
1474
  TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1475
  SELECT_LEX *select_lex= &lex->select_lex;
1476
  SELECT_LEX_UNIT *unit= &lex->unit;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1477 1478
  DBUG_ENTER("mysql_execute_command");

1479 1480 1481 1482 1483 1484
  /*
    Reset warning count for each query that uses tables
    A better approach would be to reset this for any commands
    that is not a SHOW command or a select that only access local
    variables, but for now this is probably good enough.
  */
1485
  if (tables || &lex->select_lex != lex->all_selects_list)
1486 1487 1488 1489 1490 1491 1492
    mysql_reset_errors(thd);
  /*
    Save old warning count to be able to send to client how many warnings we
    got
  */
  thd->old_total_warn_count= thd->total_warn_count;

1493 1494
  if (thd->slave_thread)
  {
peter@mysql.com's avatar
peter@mysql.com committed
1495
    /*
monty@hundin.mysql.fi's avatar
merge  
monty@hundin.mysql.fi committed
1496 1497 1498 1499
      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))
1500
      DBUG_VOID_RETURN;
monty@hundin.mysql.fi's avatar
merge  
monty@hundin.mysql.fi committed
1501 1502 1503 1504 1505 1506
#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()
    */
1507 1508 1509
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
1510
      lex->insert_list = &select_lex->item_list;
1511
    }
monty@hundin.mysql.fi's avatar
merge  
monty@hundin.mysql.fi committed
1512
#endif
1513
  }
peter@mysql.com's avatar
peter@mysql.com committed
1514

1515
  /*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1516 1517
    TODO: make derived tables processing 'inside' SELECT processing.
    TODO: solve problem with depended derived tables in subselects
1518
  */
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1519
  if (lex->derived_tables)
1520
  {
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530
    for (SELECT_LEX *sl= lex->all_selects_list;
	 sl;
	 sl= sl->next_select_in_list())
      for (TABLE_LIST *cursor= sl->get_table_list();
	   cursor;
	   cursor= cursor->next)
	if (cursor->derived && (res=mysql_derived(thd, lex,
						  (SELECT_LEX_UNIT *)
						  cursor->derived,
						  cursor)))
peter@mysql.com's avatar
peter@mysql.com committed
1531
	{
1532 1533 1534 1535 1536
	  if (res < 0 || thd->net.report_error)
	    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
	  DBUG_VOID_RETURN;
	}
  }
peter@mysql.com's avatar
peter@mysql.com committed
1537
  if ((&lex->select_lex != lex->all_selects_list &&
1538
       lex->unit.create_total_list(thd, lex, &tables)) ||
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1539 1540
      (table_rules_on && tables && thd->slave_thread &&
       !tables_ok(thd,tables)))
1541
    DBUG_VOID_RETURN;
1542

1543
  statistic_increment(com_stat[lex->sql_command],&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1544 1545 1546
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
1547
    select_result *result=lex->result;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
    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
    }

1564 1565 1566
    unit->offset_limit_cnt= (ha_rows) unit->global_parameters->offset_limit;
    unit->select_limit_cnt= (ha_rows) (unit->global_parameters->select_limit+
      unit->global_parameters->offset_limit);
peter@mysql.com's avatar
peter@mysql.com committed
1567
    if (unit->select_limit_cnt <
1568
	(ha_rows) unit->global_parameters->select_limit)
1569 1570
      unit->select_limit_cnt= HA_POS_ERROR;		// no limit
    if (unit->select_limit_cnt == HA_POS_ERROR)
1571
      select_lex->options&= ~OPTION_FOUND_ROWS;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1572 1573

    if (!(res=open_and_lock_tables(thd,tables)))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1574
    {
1575
      if (lex->describe)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1576
      {
1577 1578 1579 1580 1581 1582 1583
	if (!(result= new select_send()))
	{
	  send_error(thd, ER_OUT_OF_RESOURCES);
	  DBUG_VOID_RETURN;
	}
	else
	  thd->send_explain_fields(result);
1584
	fix_tables_pointers(lex->all_selects_list);
1585
	res= mysql_explain_union(thd, &thd->lex.unit, result);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1586 1587
	MYSQL_LOCK *save_lock= thd->lock;
	thd->lock= (MYSQL_LOCK *)0;
1588
	result->send_eof();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1589 1590 1591 1592
	thd->lock= save_lock;
      }
      else
      {
1593 1594
	if (!result)
	{
1595
	  if (!(result=new select_send()))
1596 1597 1598 1599 1600 1601 1602 1603 1604
	  {
	    res= -1;
#ifdef DELETE_ITEMS
	    delete select_lex->having;
	    delete select_lex->where;
#endif
	    break;
	  }
	}
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1605 1606 1607
	query_cache_store_query(thd, tables);
	res=handle_select(thd, lex, result);
      }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1608
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1609 1610
    break;
  }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1611
  case SQLCOM_DO:
1612 1613 1614 1615 1616 1617 1618 1619
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
		   (res= open_and_lock_tables(thd,tables))))
	break;

    fix_tables_pointers(lex->all_selects_list);
    res= mysql_do(thd, *lex->insert_list);
    if (thd->net.report_error)
      res= -1;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1620 1621
    break;

1622
  case SQLCOM_EMPTY_QUERY:
1623
    send_ok(thd);
1624 1625
    break;

1626 1627 1628 1629
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

1630
  case SQLCOM_PURGE:
1631
  {
1632
    if (check_global_access(thd, SUPER_ACL))
1633 1634 1635 1636
      goto error;
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
1637 1638
  case SQLCOM_SHOW_WARNS:
  {
1639 1640 1641
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN)));
1642 1643 1644 1645
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
1646 1647
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
1648 1649
    break;
  }
1650 1651
  case SQLCOM_SHOW_NEW_MASTER:
  {
1652
    if (check_global_access(thd, REPL_SLAVE_ACL))
1653
      goto error;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1654
#ifndef WORKING_NEW_MASTER
1655
    net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1656 1657
    res= 1;
#else
1658
    res = show_new_master(thd);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1659
#endif
1660 1661
    break;
  }
1662 1663
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
1664
    if (check_global_access(thd, REPL_SLAVE_ACL))
1665 1666 1667 1668
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
1669 1670
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
1671
    if (check_global_access(thd, REPL_SLAVE_ACL))
1672 1673 1674 1675
      goto error;
    res = show_binlog_events(thd);
    break;
  }
1676
  case SQLCOM_BACKUP_TABLE:
1677 1678 1679
  {
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables) ||
1680
	check_global_access(thd, FILE_ACL))
1681 1682
      goto error; /* purecov: inspected */
    res = mysql_backup_table(thd, tables);
1683

1684 1685
    break;
  }
1686
  case SQLCOM_RESTORE_TABLE:
1687 1688
  {
    if (check_db_used(thd,tables) ||
1689 1690
	check_table_access(thd, INSERT_ACL, tables) ||
	check_global_access(thd, FILE_ACL))
1691 1692 1693 1694
      goto error; /* purecov: inspected */
    res = mysql_restore_table(thd, tables);
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1695
  case SQLCOM_CHANGE_MASTER:
1696
  {
1697
    if (check_global_access(thd, SUPER_ACL))
1698
      goto error;
1699 1700 1701
    LOCK_ACTIVE_MI;
    res = change_master(thd,active_mi);
    UNLOCK_ACTIVE_MI;
1702 1703
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1704
  case SQLCOM_SHOW_SLAVE_STAT:
1705
  {
1706
    if (check_global_access(thd, SUPER_ACL))
1707
      goto error;
1708 1709 1710
    LOCK_ACTIVE_MI;
    res = show_master_info(thd,active_mi);
    UNLOCK_ACTIVE_MI;
1711 1712
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1713
  case SQLCOM_SHOW_MASTER_STAT:
1714
  {
1715
    if (check_global_access(thd, SUPER_ACL))
1716 1717 1718 1719
      goto error;
    res = show_binlog_info(thd);
    break;
  }
peter@mysql.com's avatar
peter@mysql.com committed
1720

1721
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
1722
    if (check_global_access(thd, SUPER_ACL))
1723
      goto error;
1724 1725 1726 1727
    if (end_active_trans(thd))
      res= -1;
    else
      res = load_master_data(thd);
1728
    break;
peter@mysql.com's avatar
peter@mysql.com committed
1729

heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
1730 1731 1732
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
1733
      if (check_global_access(thd, SUPER_ACL))
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
1734 1735 1736 1737 1738
	goto error;
      res = innodb_show_status(thd);
      break;
    }
#endif
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1739

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1740
  case SQLCOM_LOAD_MASTER_TABLE:
1741
  {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753
    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)
1754
	goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1755
    }
1756
    if (strlen(tables->real_name) > NAME_LEN)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1757
    {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1758
      net_printf(thd,ER_WRONG_TABLE_NAME,tables->real_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1759 1760
      break;
    }
1761 1762 1763 1764 1765
    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))
    {
1766
      send_ok(thd);
1767 1768
    }
    UNLOCK_ACTIVE_MI;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1769
    break;
1770
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1771
  case SQLCOM_CREATE_TABLE:
1772 1773 1774
  {
    ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
		      CREATE_TMP_ACL : CREATE_ACL);
1775 1776
    if (!tables->db)
      tables->db=thd->db;
1777
    if (check_access(thd,want_priv,tables->db,&tables->grant.privilege) ||
1778 1779 1780
	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
1781
      goto error;				/* purecov: inspected */
1782
    if (grant_option && want_priv != CREATE_TMP_ACL)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1783 1784 1785 1786
    {
      /* Check that the first table has CREATE privilege */
      TABLE_LIST *tmp_table_list=tables->next;
      tables->next=0;
1787
      bool error=check_grant(thd, want_priv, tables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1788 1789 1790 1791
      tables->next=tmp_table_list;
      if (error)
	goto error;
    }
1792
    if (strlen(tables->real_name) > NAME_LEN)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1793
    {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1794
      net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1795 1796 1797
      res=0;
      break;
    }
1798 1799 1800
#ifndef HAVE_READLINK
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
1801
    /* Fix names if symlinked tables */
1802
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
1803
			   tables->real_name) ||
1804
	append_file_to_dir(thd,&lex->create_info.index_file_name,
1805
			   tables->real_name))
1806 1807 1808 1809
    {
      res=-1;
      break;
    }
1810
#endif
1811
    if (select_lex->item_list.elements)		// With select
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1812 1813 1814 1815
    {
      select_result *result;

      if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
1816
	  find_real_table_in_list(tables->next, tables->db, tables->real_name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1817
      {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1818
	net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1819 1820 1821 1822 1823 1824 1825
	DBUG_VOID_RETURN;
      }
      if (tables->next)
      {
	if (check_table_access(thd, SELECT_ACL, tables->next))
	  goto error;				// Error message is given
      }
1826 1827 1828 1829 1830
      unit->offset_limit_cnt= select_lex->offset_limit;
      unit->select_limit_cnt= select_lex->select_limit+
	select_lex->offset_limit;
      if (unit->select_limit_cnt < select_lex->select_limit)
	unit->select_limit_cnt= HA_POS_ERROR;		// No limit
1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846

      /* 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
1847 1848
    else // regular create
    {
venu@myvenu.com's avatar
venu@myvenu.com committed
1849 1850 1851 1852 1853 1854 1855 1856
      if (lex->name)
        res= mysql_create_like_table(thd, tables, &lex->create_info, 
                                     (Table_ident *)lex->name); 
      else
        res= mysql_create_table(thd,tables->db ? tables->db : thd->db,
			         tables->real_name, &lex->create_info,
			         lex->create_list,
			         lex->key_list,0,0,0); // do logging
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1857
      if (!res)
1858
	send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1859 1860
    }
    break;
1861
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1862 1863 1864 1865 1866 1867 1868
  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;
1869 1870 1871 1872
    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
1873 1874 1875
    break;

  case SQLCOM_SLAVE_START:
1876 1877 1878 1879
  {
    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
1880
    break;
1881
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1882
  case SQLCOM_SLAVE_STOP:
1883 1884 1885 1886
  {
    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
1887
    break;
1888
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1889 1890
  case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
1891
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1892 1893 1894
    break;
#else
    {
1895
      ulong priv=0;
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1896
      if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1897
      {
1898
	net_printf(thd,ER_WRONG_TABLE_NAME,lex->name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1899 1900 1901
	res=0;
	break;
      }
1902 1903
      if (!tables->db)
	tables->db=thd->db;
1904 1905
      if (!select_lex->db)
	select_lex->db=tables->db;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1906
      if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege) ||
1907
	  check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv) ||
peter@mysql.com's avatar
peter@mysql.com committed
1908
	  check_merge_table_access(thd, tables->db,
1909 1910 1911
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922
      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;
1923
	  tmp_table.db=select_lex->db;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1924 1925 1926 1927 1928
	  tmp_table.grant.privilege=priv;
	  if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables))
	    goto error;
	}
      }
1929 1930
      /* 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
1931
      /* ALTER TABLE ends previous transaction */
1932
      if (end_active_trans(thd))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1933 1934
	res= -1;
      else
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1935
      {
1936
	res= mysql_alter_table(thd, select_lex->db, lex->name,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1937 1938 1939
			       &lex->create_info,
			       tables, lex->create_list,
			       lex->key_list, lex->drop_list, lex->alter_list,
1940
                               (ORDER *) select_lex->order_list.first,
1941 1942
			       lex->drop_primary, lex->duplicates,
			       lex->alter_keys_onoff, lex->simple_alter);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1943
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1944 1945 1946
      break;
    }
#endif
1947
  case SQLCOM_RENAME_TABLE:
1948 1949 1950
  {
    TABLE_LIST *table;
    if (check_db_used(thd,tables))
1951
      goto error;
1952 1953
    for (table=tables ; table ; table=table->next->next)
    {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1954 1955
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
		       &table->grant.privilege) ||
1956 1957 1958 1959 1960
	  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
1961 1962 1963 1964 1965
	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) ||
1966
	    (!test_all_bits(table->next->grant.privilege,
1967
			    INSERT_ACL | CREATE_ACL) &&
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1968
	     check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list)))
1969 1970 1971
	  goto error;
      }
    }
1972
    query_cache_invalidate3(thd, tables, 0);
1973 1974 1975
    if (end_active_trans(thd))
      res= -1;
    else if (mysql_rename_tables(thd,tables))
1976 1977
      res= -1;
    break;
1978
  }
1979 1980
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
1981
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
1982 1983 1984
    DBUG_VOID_RETURN;
#else
    {
1985
      if (check_global_access(thd, SUPER_ACL))
1986 1987 1988 1989
	goto error;
      res = show_binlogs(thd);
      break;
    }
peter@mysql.com's avatar
peter@mysql.com committed
1990
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1991
  case SQLCOM_SHOW_CREATE:
1992
#ifdef DONT_ALLOW_SHOW_COMMANDS
1993
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
1994 1995
    DBUG_VOID_RETURN;
#else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1996
    {
1997 1998 1999 2000
      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
2001
      res = mysqld_show_create(thd, tables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2002 2003
      break;
    }
2004
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2005
  case SQLCOM_REPAIR:
2006 2007 2008 2009 2010 2011 2012
  {
    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
2013
  case SQLCOM_CHECK:
2014 2015 2016 2017 2018 2019 2020
  {
    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
2021 2022
  case SQLCOM_ANALYZE:
  {
2023 2024
    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
2025
      goto error; /* purecov: inspected */
2026
    res = mysql_analyze_table(thd, tables, &lex->check_opt);
2027
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2028
  }
2029

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2030 2031 2032
  case SQLCOM_OPTIMIZE:
  {
    HA_CREATE_INFO create_info;
2033 2034
    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
2035
      goto error; /* purecov: inspected */
2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046
    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;
2047
      create_info.table_charset=default_charset_info;
2048 2049 2050
      res= mysql_alter_table(thd, NullS, NullS, &create_info,
			     tables, lex->create_list,
			     lex->key_list, lex->drop_list, lex->alter_list,
2051
                             (ORDER *) 0,
2052 2053 2054 2055
			     0,DUP_ERROR);
    }
    else
      res = mysql_optimize_table(thd, tables, &lex->check_opt);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2056 2057 2058 2059 2060 2061 2062
    break;
  }
  case SQLCOM_UPDATE:
    if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege))
      goto error;
    if (grant_option && check_grant(thd,UPDATE_ACL,tables))
      goto error;
2063
    if (select_lex->item_list.elements != lex->value_list.elements)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2064
    {
2065
      send_error(thd,ER_WRONG_VALUE_COUNT);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2066 2067
      DBUG_VOID_RETURN;
    }
2068 2069 2070 2071 2072 2073 2074
    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);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2075 2076
    if (thd->net.report_error)
      res= -1;
2077 2078 2079 2080 2081 2082 2083
    break;
  case SQLCOM_UPDATE_MULTI:
    if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege))
      goto error;
    if (grant_option && check_grant(thd,UPDATE_ACL,tables))
      goto error;
    if (select_lex->item_list.elements != lex->value_list.elements)
2084
    {
2085 2086
      send_error(thd,ER_WRONG_VALUE_COUNT);
      DBUG_VOID_RETURN;
2087 2088
    }
    {
2089
      const char *msg= 0;
2090
      if (select_lex->order_list.elements)
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2091
	msg= "ORDER BY";
2092 2093
      else if (select_lex->select_limit && select_lex->select_limit !=
	       HA_POS_ERROR)
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2094
	msg= "LIMIT";
2095
      if (msg)
2096
      {
2097
	net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg);
2098 2099
	res= 1;
	break;
2100
      }
2101 2102 2103 2104 2105
      res= mysql_multi_update(thd,tables,
			      &select_lex->item_list,
			      &lex->value_list,
			      select_lex->where,
			      select_lex->options,
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2106
			      lex->duplicates, unit, select_lex);
2107
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2108 2109
    break;
  case SQLCOM_REPLACE:
2110 2111
  case SQLCOM_INSERT:
  {
2112
    my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
2113
    ulong privilege= (lex->duplicates == DUP_REPLACE ?
2114
                      INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
2115
    if (check_access(thd,privilege,tables->db,&tables->grant.privilege))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2116
      goto error; /* purecov: inspected */
2117
    if (grant_option && check_grant(thd,privilege,tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2118
      goto error;
2119 2120 2121 2122 2123
    if (select_lex->item_list.elements != lex->value_list.elements)
    {
      send_error(thd,ER_WRONG_VALUE_COUNT);
      DBUG_VOID_RETURN;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2124
    res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
2125
                       select_lex->item_list, lex->value_list,
serg@serg.mysql.com's avatar
serg@serg.mysql.com committed
2126
                       (update ? DUP_UPDATE : lex->duplicates));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2127 2128
    if (thd->net.report_error)
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2129
    break;
2130
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2131 2132 2133
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
2134

2135 2136 2137 2138
    /*
      Check that we have modify privileges for the first table and
      select privileges for the rest
    */
2139
    {
2140 2141
      ulong privilege= (lex->duplicates == DUP_REPLACE ?
                        INSERT_ACL | DELETE_ACL : INSERT_ACL);
2142 2143 2144 2145 2146 2147 2148 2149 2150 2151
      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;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2152 2153

    select_result *result;
2154 2155 2156 2157
    unit->offset_limit_cnt= select_lex->offset_limit;
    unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit;
    if (unit->select_limit_cnt < select_lex->select_limit)
      unit->select_limit_cnt= HA_POS_ERROR;		// No limit
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2158

2159
    if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
2160
    {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2161
      net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
2162
      DBUG_VOID_RETURN;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2163
    }
2164 2165 2166 2167 2168 2169 2170

    /* 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,
2171
				    lex->duplicates)))
2172
	res=handle_select(thd,lex,result);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2173 2174
      if (thd->net.report_error)
	res= -1;
2175 2176 2177
    }
    else
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2178 2179
    break;
  }
2180
  case SQLCOM_TRUNCATE:
2181 2182 2183 2184 2185 2186 2187 2188
    if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
      goto error; /* purecov: inspected */
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
    if (thd->locked_tables || thd->active_transaction())
    {
2189
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
2190 2191 2192 2193
      goto error;
    }
    res=mysql_truncate(thd,tables);
    break;
2194
  case SQLCOM_DELETE:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2195 2196 2197 2198 2199 2200 2201
  {
    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
2202 2203
    res = mysql_delete(thd,tables, select_lex->where,
                       (ORDER*) select_lex->order_list.first,
2204
                       select_lex->select_limit, select_lex->options);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2205 2206
    if (thd->net.report_error)
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2207 2208
    break;
  }
2209
  case SQLCOM_DELETE_MULTI:
2210 2211 2212 2213 2214
  {
    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
2215

2216 2217
    /* sql_yacc guarantees that tables and aux_tables are not zero */
    if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
2218
	check_table_access(thd,SELECT_ACL, tables) ||
2219 2220 2221
	check_table_access(thd,DELETE_ACL, aux_tables))
      goto error;
    if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
2222
    {
2223
      send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238
      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)
      {
2239
	net_printf(thd,ER_NONUNIQ_TABLE,auxi->real_name);
2240 2241
	goto error;
      }
2242
      walk->lock_type= auxi->lock_type;
2243
      auxi->table_list=  walk;		// Remember corresponding table
2244
    }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2245
    if (add_item_to_list(thd, new Item_null()))
2246
    {
2247
      res= -1;
2248
      break;
2249 2250 2251 2252 2253 2254
    }
    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)
2255
      auxi->table= auxi->table_list->table;
2256 2257 2258 2259 2260 2261
    if (&lex->select_lex != lex->all_selects_list)
      for (TABLE_LIST *t= select_lex->get_table_list();
	   t; t= t->next)
      {
	if (find_real_table_in_list(t->table_list->next, t->db, t->real_name))
	{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2262
	  my_error(ER_UPDATE_TABLE_USED, MYF(0), t->real_name);
2263 2264 2265 2266
	  res= -1;
	  break;
	}
      }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2267
    fix_tables_pointers(lex->all_selects_list);
2268 2269
    if (!thd->fatal_error && (result= new multi_delete(thd,aux_tables,
						       table_count)))
2270
    {
2271 2272
      res= mysql_select(thd,select_lex->get_table_list(),
			select_lex->item_list,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2273 2274 2275 2276 2277
			select_lex->where,
			(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
			(ORDER *)NULL,
			select_lex->options | thd->options |
			SELECT_NO_JOIN_CACHE,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2278
			result, unit, select_lex, 0);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2279 2280
      if (thd->net.report_error)
	res= -1;
2281
      delete result;
2282 2283 2284 2285 2286 2287
    }
    else
      res= -1;					// Error is not sent
    close_thread_tables(thd);
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2288
  case SQLCOM_DROP_TABLE:
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2289 2290 2291 2292 2293 2294 2295 2296 2297
  {
    if (check_table_access(thd,DROP_ACL,tables))
      goto error;				/* purecov: inspected */
    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
2298 2299 2300 2301 2302 2303 2304
  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;
2305 2306 2307 2308
    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
2309 2310
    break;
  case SQLCOM_SHOW_DATABASES:
2311
#if defined(DONT_ALLOW_SHOW_COMMANDS)
2312
    send_error(thd,ER_NOT_ALLOWED_COMMAND);   /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2313 2314 2315
    DBUG_VOID_RETURN;
#else
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
2316
	check_global_access(thd, SHOW_DB_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2317 2318 2319 2320 2321
      goto error;
    res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
    break;
#endif
  case SQLCOM_SHOW_PROCESSLIST:
2322
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2323 2324 2325 2326
      break;
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
			  thd->priv_user,lex->verbose);
    break;
2327 2328 2329 2330 2331 2332 2333 2334 2335
  case SQLCOM_SHOW_TABLE_TYPES:
    res= mysqld_show_table_types(thd);
    break;
  case SQLCOM_SHOW_PRIVILEGES:
    res= mysqld_show_privileges(thd);
    break;
  case SQLCOM_SHOW_COLUMN_TYPES:
    res= mysqld_show_column_types(thd);
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2336
  case SQLCOM_SHOW_STATUS:
2337
    res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
2338
		     OPT_GLOBAL);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2339 2340 2341
    break;
  case SQLCOM_SHOW_VARIABLES:
    res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
2342
		     init_vars, lex->option_type);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2343
    break;
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
2344 2345
  case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2346
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
2347 2348 2349 2350 2351 2352 2353 2354 2355
    DBUG_VOID_RETURN;
#else
    {
      if (grant_option && check_access(thd, FILE_ACL, any_db))
	goto error;
      res= mysqld_show_logs(thd);
      break;
    }
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2356
  case SQLCOM_SHOW_TABLES:
2357
    /* FALL THROUGH */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2358
#ifdef DONT_ALLOW_SHOW_COMMANDS
2359
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2360 2361 2362
    DBUG_VOID_RETURN;
#else
    {
2363
      char *db=select_lex->db ? select_lex->db : thd->db;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2364 2365
      if (!db)
      {
2366
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2367 2368 2369
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);				// Fix escaped '_'
2370
      if (check_db_name(db))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2371
      {
2372
        net_printf(thd,ER_WRONG_DB_NAME, db);
2373
        goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2374 2375 2376 2377
      }
      if (check_access(thd,SELECT_ACL,db,&thd->col_access))
	goto error;				/* purecov: inspected */
      /* grant is checked in mysqld_show_tables */
2378
      if (select_lex->options & SELECT_DESCRIBE)
2379
        res= mysqld_extend_show_tables(thd,db,
2380
				       (lex->wild ? lex->wild->ptr() : NullS));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2381 2382 2383 2384 2385 2386
      else
	res= mysqld_show_tables(thd,db,
				(lex->wild ? lex->wild->ptr() : NullS));
      break;
    }
#endif
2387 2388 2389
  case SQLCOM_SHOW_OPEN_TABLES:
    res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
2390 2391
  case SQLCOM_SHOW_CHARSETS:
    res= mysqld_show_charsets(thd,(lex->wild ? lex->wild->ptr() : NullS));
2392
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2393 2394
  case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2395
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2396 2397 2398
    DBUG_VOID_RETURN;
#else
    {
2399 2400
      char *db=tables->db;
      if (!*db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2401
      {
2402
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2403 2404 2405
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);			// Fix escaped '_'
2406
      remove_escape(tables->real_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2407 2408 2409 2410 2411 2412
      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
2413 2414
			      (lex->wild ? lex->wild->ptr() : NullS),
			      lex->verbose);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2415 2416 2417 2418 2419
      break;
    }
#endif
  case SQLCOM_SHOW_KEYS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2420
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2421 2422 2423
    DBUG_VOID_RETURN;
#else
    {
2424
      char *db=tables->db;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2425 2426
      if (!db)
      {
2427
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2428 2429 2430
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);			// Fix escaped '_'
2431
      remove_escape(tables->real_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443
      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:
2444
    mysql_change_db(thd,select_lex->db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2445 2446 2447 2448
    break;
  case SQLCOM_LOAD:
  {
    uint privilege= (lex->duplicates == DUP_REPLACE ?
2449
		     INSERT_ACL | DELETE_ACL : INSERT_ACL);
2450 2451

    if (!lex->local_file)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2452 2453 2454 2455 2456 2457
    {
      if (check_access(thd,privilege | FILE_ACL,tables->db))
	goto error;
    }
    else
    {
2458
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
2459
	  ! opt_local_infile)
2460
      {
2461
	send_error(thd,ER_NOT_ALLOWED_COMMAND);
2462 2463
	goto error;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2464
      if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
2465
	  grant_option && check_grant(thd,privilege,tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2466 2467 2468 2469 2470 2471 2472
	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:
2473 2474 2475 2476 2477
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
		   (res= open_and_lock_tables(thd,tables))))
      break;
    fix_tables_pointers(lex->all_selects_list);
    if (!(res= sql_set_variables(thd, &lex->var_list)))
2478
      send_ok(thd);
2479 2480
    if (thd->net.report_error)
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2481
    break;
2482

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2483
  case SQLCOM_UNLOCK_TABLES:
2484
    unlock_locked_tables(thd);
2485 2486
    if (thd->options & OPTION_TABLE_LOCK)
    {
2487
      end_active_trans(thd);
2488
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2489 2490
    }
    if (thd->global_read_lock)
2491
      unlock_global_read_lock(thd);
2492
    send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2493 2494
    break;
  case SQLCOM_LOCK_TABLES:
2495
    unlock_locked_tables(thd);
2496
    if (check_db_used(thd,tables) || end_active_trans(thd))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2497
      goto error;
2498
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables))
2499
      goto error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2500
    thd->in_lock_tables=1;
2501
    thd->options|= OPTION_TABLE_LOCK;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2502 2503 2504 2505
    if (!(res=open_and_lock_tables(thd,tables)))
    {
      thd->locked_tables=thd->lock;
      thd->lock=0;
2506
      send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2507
    }
2508 2509
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2510 2511 2512
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
2513
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2514
    if (!strip_sp(lex->name) || check_db_name(lex->name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2515
    {
2516
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2517 2518
      break;
    }
2519
    if (lower_case_table_names)
2520
      my_casedn_str(files_charset_info, lex->name);
2521 2522
    if (check_access(thd,CREATE_ACL,lex->name,0,1))
      break;
2523
    res=mysql_create_db(thd,lex->name,&lex->create_info,0);
2524 2525
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2526
  case SQLCOM_DROP_DB:
2527
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2528
    if (!strip_sp(lex->name) || check_db_name(lex->name))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2529
    {
2530
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2531 2532
      break;
    }
2533
    if (lower_case_table_names)
2534
      my_casedn_str(files_charset_info, lex->name);
2535
    if (check_access(thd,DROP_ACL,lex->name,0,1))
2536
      break;
2537 2538
    if (thd->locked_tables || thd->active_transaction())
    {
2539
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
2540 2541
      goto error;
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2542
    res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0);
2543 2544
    break;
  }
2545 2546 2547 2548
  case SQLCOM_ALTER_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
2549
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
2550 2551
      break;
    }
2552
    if (check_access(thd,ALTER_ACL,lex->name,0,1))
2553 2554 2555
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
2556
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
2557 2558
      goto error;
    }
2559
    res=mysql_alter_db(thd,lex->name,&lex->create_info);
2560 2561
    break;
  }
2562 2563 2564 2565
  case SQLCOM_SHOW_CREATE_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
2566
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
2567 2568 2569 2570 2571 2572
      break;
    }
    if (check_access(thd,DROP_ACL,lex->name,0,1))
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
2573
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
2574 2575
      goto error;
    }
2576
    res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
2577 2578
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2579 2580 2581 2582 2583
  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)))
2584
      send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2585 2586 2587 2588 2589 2590 2591 2592 2593
#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)))
2594
      send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2595 2596 2597 2598
#else
    res= -1;
#endif
    break;
2599 2600 2601 2602 2603 2604 2605 2606 2607
  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;

2608 2609 2610 2611
    /*
      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
    */
2612 2613 2614 2615 2616 2617 2618 2619 2620 2621

    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 &&
2622
	     my_strcasecmp(my_charset_latin1,
2623
                           user->host.str, thd->host_or_ip)))
2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637
	{
	  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
2638 2639 2640
      if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
				    lex->grant,
				    lex->sql_command == SQLCOM_REVOKE)))
2641
      {
2642
	mysql_update_log.write(thd, thd->query, thd->query_length);
2643 2644
	if (mysql_bin_log.is_open())
	{
2645
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
2646 2647 2648 2649 2650 2651 2652 2653
	  mysql_bin_log.write(&qinfo);
	}
      }
    }
    else
    {
      if (lex->columns.elements)
      {
2654
	send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE);
2655 2656 2657 2658 2659 2660 2661
	res=1;
      }
      else
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
2662
	mysql_update_log.write(thd, thd->query, thd->query_length);
2663 2664
	if (mysql_bin_log.is_open())
	{
2665
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
2666 2667
	  mysql_bin_log.write(&qinfo);
	}
2668
	if (mqh_used && lex->sql_command == SQLCOM_GRANT)
2669
	{
2670 2671 2672
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
2673
	    reset_mqh(thd,user);
2674
	}
2675 2676 2677 2678
      }
    }
    break;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2679
  case SQLCOM_FLUSH:
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2680
  case SQLCOM_RESET:
2681
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2682
      goto error;
2683
    if (reload_acl_and_cache(thd, lex->type, tables))
2684
      send_error(thd,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2685
    else
2686
      send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2687 2688 2689 2690 2691 2692
    break;
  case SQLCOM_KILL:
    kill_one_thread(thd,lex->thread_id);
    break;
  case SQLCOM_SHOW_GRANTS:
    res=0;
2693 2694
    if ((thd->priv_user &&
	 !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
2695
	!check_access(thd, SELECT_ACL, "mysql",0,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2696 2697 2698 2699
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
2700
  case SQLCOM_HA_OPEN:
2701 2702
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables))
2703 2704 2705 2706 2707 2708 2709 2710 2711
      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:
2712 2713
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables))
2714
      goto error;
serg@serg.mysql.com's avatar
serg@serg.mysql.com committed
2715
    res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
2716 2717
			lex->insert_list, lex->ha_rkey_mode, select_lex->where,
			select_lex->select_limit, select_lex->offset_limit);
2718 2719
    break;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2720
  case SQLCOM_BEGIN:
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2721 2722 2723 2724 2725 2726
    if (thd->locked_tables)
    {
      thd->lock=thd->locked_tables;
      thd->locked_tables=0;			// Will be automaticly closed
      close_thread_tables(thd);			// Free tables
    }
2727 2728 2729 2730 2731 2732
    if (end_active_trans(thd))
    {
      res= -1;
    }
    else
    {
2733
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
2734 2735
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
2736
      send_ok(thd);
2737
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2738 2739
    break;
  case SQLCOM_COMMIT:
2740 2741 2742 2743 2744
    /*
      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
2745
  {
2746
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2747 2748
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2749
    {
2750
      send_ok(thd);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2751
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2752 2753 2754
    else
      res= -1;
    break;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2755
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2756 2757 2758
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
2759 2760
    {
      if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
2761
	send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
2762
      else
2763
	send_ok(thd);
2764
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2765 2766
    else
      res= -1;
2767
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2768 2769
    break;
  default:					/* Impossible */
2770
    send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2771 2772 2773 2774
    break;
  }
  thd->proc_info="query end";			// QQ
  if (res < 0)
2775
    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2776 2777 2778 2779 2780 2781 2782

error:
  DBUG_VOID_RETURN;
}


/****************************************************************************
2783 2784 2785 2786 2787 2788 2789
  Get the user (global) and database privileges for all used tables
  Returns true (error) if we can't get the privileges and we don't use
  table/column grants.
  The idea of EXTRA_ACL is that one will be granted access to the table if
  one has the asked privilege on any column combination of the table; For
  example to be able to check a table one needs to have SELECT privilege on
  any column of the table.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2790 2791 2792
****************************************************************************/

bool
2793
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
2794
	     bool dont_check_global_grants, bool no_errors)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2795
{
2796 2797 2798 2799
  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
2800 2801 2802 2803 2804
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

2805
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2806
  {
2807
    if (!no_errors)
2808
      send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
2809
    DBUG_RETURN(TRUE);				/* purecov: tested */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2810 2811 2812 2813 2814
  }

  if ((thd->master_access & want_access) == want_access)
  {
    *save_priv=thd->master_access;
2815
    DBUG_RETURN(FALSE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2816
  }
2817
  if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
2818
      ! db && dont_check_global_grants)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2819
  {						// We can never grant this
2820
    if (!no_errors)
2821
      net_printf(thd,ER_ACCESS_DENIED_ERROR,
2822 2823 2824
		 thd->priv_user,
		 thd->host_or_ip,
		 thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
2825
    DBUG_RETURN(TRUE);				/* purecov: tested */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2826 2827 2828
  }

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2831 2832 2833 2834 2835
  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;
2836 2837
  // 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
2838
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
2839 2840

  /* grant_option is set if there exists a single table or column grant */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2841
  if (db_access == want_access ||
2842 2843
      ((grant_option && !dont_check_global_grants) &&
       !(want_access & ~TABLE_ACLS)))
2844
    DBUG_RETURN(FALSE);				/* Ok */
2845
  if (!no_errors)
2846
    net_printf(thd,ER_DBACCESS_DENIED_ERROR,
2847 2848 2849
	       thd->priv_user,
	       thd->host_or_ip,
	       db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
2850
  DBUG_RETURN(TRUE);				/* purecov: tested */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2851 2852 2853
}


2854 2855 2856
/* check for global access and give descriptive error message if it fails */

bool check_global_access(THD *thd, ulong want_access)
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2857
{
2858 2859 2860 2861
  char command[128];
  if ((thd->master_access & want_access) == want_access)
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
2862
  net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
2863 2864
	     command);
  return 1;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2865 2866 2867
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2868
/*
2869 2870
  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
2871 2872
*/

2873
bool
2874
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
2875
		   bool no_errors)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2876
{
2877 2878
  uint found=0;
  ulong found_access=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2879 2880 2881
  TABLE_LIST *org_tables=tables;
  for (; tables ; tables=tables->next)
  {
2882
    if (tables->derived || (tables->table && (int)tables->table->tmp_table))
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
2883
      continue;
2884 2885
    if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
	thd->db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2886
      tables->grant.privilege= want_access;
2887
    else if (tables->db && tables->db == thd->db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2888 2889 2890 2891 2892
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
2893 2894
	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
2895 2896
	  return TRUE;				// Access denied
	found_access=tables->grant.privilege;
2897
	found=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2898 2899
      }
    }
2900
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
2901
			  0, no_errors))
2902
      return TRUE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2903 2904
  }
  if (grant_option)
2905
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
2906
		       test(want_access & EXTRA_ACL), no_errors);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2907 2908 2909 2910
  return FALSE;
}


2911
static bool check_db_used(THD *thd,TABLE_LIST *tables)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2912 2913 2914 2915 2916 2917 2918
{
  for (; tables ; tables=tables->next)
  {
    if (!tables->db)
    {
      if (!(tables->db=thd->db))
      {
2919
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2920 2921 2922 2923 2924 2925 2926 2927
	return TRUE;				/* purecov: tested */
      }
    }
  }
  return FALSE;
}


2928 2929
static bool check_merge_table_access(THD *thd, char *db,
				     TABLE_LIST *table_list)
2930 2931 2932 2933
{
  int error=0;
  if (table_list)
  {
2934
    /* Check that all tables use the current database */
2935 2936
    TABLE_LIST *tmp;
    for (tmp=table_list; tmp ; tmp=tmp->next)
2937 2938 2939
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
2940
      else if (strcmp(tmp->db,db))
2941
      {
2942
	send_error(thd,ER_UNION_TABLES_IN_DIFFERENT_DIR);
2943 2944 2945
	return 1;
      }
    }
2946 2947 2948 2949 2950 2951 2952
    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
2953 2954 2955 2956 2957 2958 2959 2960 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 3001 3002 3003 3004 3005 3006 3007 3008 3009
/****************************************************************************
	Check stack size; Send error if there isn't enough stack to continue
****************************************************************************/

#if STACK_DIRECTION < 0
#define used_stack(A,B) (long) (A - B)
#else
#define used_stack(A,B) (long) (B - A)
#endif

bool check_stack_overrun(THD *thd,char *buf __attribute__((unused)))
{
  long stack_used;
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
      (long) thread_stack_min)
  {
    sprintf(errbuff[0],ER(ER_STACK_OVERRUN),stack_used,thread_stack);
    my_message(ER_STACK_OVERRUN,errbuff[0],MYF(0));
    thd->fatal_error=1;
    return 1;
  }
  return 0;
}

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

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


/****************************************************************************
3010
	Initialize global thd variables needed for query
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3011 3012
****************************************************************************/

3013
void
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3014 3015 3016
mysql_init_query(THD *thd)
{
  DBUG_ENTER("mysql_init_query");
3017 3018 3019 3020 3021 3022
  LEX *lex=&thd->lex;
  lex->unit.init_query();
  lex->unit.init_select();
  lex->select_lex.init_query();
  lex->value_list.empty();
  lex->param_list.empty();
3023 3024
  lex->unit.next= lex->unit.master= lex->unit.link_next= 0;
  lex->unit.prev= lex->unit.link_prev= 0;
peter@mysql.com's avatar
peter@mysql.com committed
3025
  lex->unit.global_parameters= lex->unit.slave= lex->current_select=
3026
    lex->all_selects_list= &lex->select_lex;
3027 3028
  lex->select_lex.master= &lex->unit;
  lex->select_lex.prev= &lex->unit.slave;
3029
  lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
3030
  lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
3031 3032
  lex->olap=lex->describe=0;
  lex->derived_tables= false;
3033
  lex->lock_option=TL_READ;
peter@mysql.com's avatar
peter@mysql.com committed
3034
  thd->check_loops_counter= thd->select_number=
3035
    lex->select_lex.select_number= 1;
3036
  thd->free_list= 0;
3037
  thd->total_warn_count=0;			// Warnings for this query
3038 3039
  thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
  thd->sent_row_count= thd->examined_row_count= 0;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3040
  thd->fatal_error= thd->rand_used= 0;
3041
  thd->possible_loops= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3042 3043 3044
  DBUG_VOID_RETURN;
}

3045

3046 3047 3048
void
mysql_init_select(LEX *lex)
{
3049
  SELECT_LEX *select_lex= lex->current_select->select_lex();
3050
  select_lex->init_select();
peter@mysql.com's avatar
peter@mysql.com committed
3051
  select_lex->master_unit()->select_limit= select_lex->select_limit=
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3052
    lex->thd->variables.select_limit;
3053 3054 3055 3056 3057 3058
  if (select_lex == &lex->select_lex)
  {
    lex->exchange= 0;
    lex->result= 0;
    lex->proc_list.first= 0;
  }
3059 3060
}

3061

3062
bool
3063
mysql_new_select(LEX *lex, bool move_down)
3064
{
3065
  SELECT_LEX *select_lex = new SELECT_LEX();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3066
  select_lex->select_number= ++lex->thd->select_number;
3067 3068
  if (!select_lex)
    return 1;
3069 3070 3071 3072 3073
  select_lex->init_query();
  select_lex->init_select();
  if (move_down)
  {
    /* first select_lex of subselect or derived table */
3074
    SELECT_LEX_UNIT *unit= new SELECT_LEX_UNIT();
3075 3076 3077 3078
    if (!unit)
      return 1;
    unit->init_query();
    unit->init_select();
3079
    unit->include_down(lex->current_select);
3080 3081
    unit->link_next= 0;
    unit->link_prev= 0;
3082 3083 3084
    select_lex->include_down(unit);
  }
  else
3085
    select_lex->include_neighbour(lex->current_select);
peter@mysql.com's avatar
peter@mysql.com committed
3086

3087
  select_lex->master_unit()->global_parameters= select_lex;
3088
  DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE);
3089
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
3090
  lex->current_select= select_lex;
3091
  return 0;
3092
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3093

3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116
/*
  Create a select to return the same output as 'SELECT @@var_name'.

  SYNOPSIS
    create_select_for_variable()
    var_name		Variable name

  DESCRIPTION
    Used for SHOW COUNT(*) [ WARNINGS | ERROR]

    This will crash with a core dump if the variable doesn't exists
*/

void create_select_for_variable(const char *var_name)
{
  LEX *lex;
  LEX_STRING tmp;
  DBUG_ENTER("create_select_for_variable");
  lex= current_lex;
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3117
  add_item_to_list(lex->thd, get_system_var(OPT_SESSION, tmp));
3118 3119 3120
  DBUG_VOID_RETURN;
}

3121

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3122 3123
void mysql_init_multi_delete(LEX *lex)
{
3124
  lex->sql_command=  SQLCOM_DELETE_MULTI;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3125
  mysql_init_select(lex);
3126
  lex->select_lex.select_limit= lex->unit.select_limit_cnt=
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3127
    HA_POS_ERROR;
3128
  lex->auxilliary_table_list= lex->select_lex.table_list;
3129
  lex->select_lex.init_query();
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3130
}
3131

3132

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3133
void
3134
mysql_parse(THD *thd, char *inBuf, uint length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3135 3136 3137 3138 3139
{
  DBUG_ENTER("mysql_parse");

  mysql_init_query(thd);
  thd->query_length = length;
3140 3141
  thd->net.report_error= 0;

3142
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3143 3144
  {
    LEX *lex=lex_start(thd, (uchar*) inBuf, length);
3145
    if (!yyparse((void *)thd) && ! thd->fatal_error)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3146
    {
3147
      if (mqh_used && thd->user_connect &&
3148
	  check_mqh(thd, lex->sql_command))
3149 3150 3151 3152 3153
      {
	thd->net.error = 0;
      }
      else
      {
3154 3155 3156 3157 3158 3159 3160
	if (thd->net.report_error)
	  send_error(thd, 0, NullS);
	else
	{
	  mysql_execute_command(thd);
	  query_cache_end_of_result(&thd->net);
	}
3161
      }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3162 3163
    }
    else
3164 3165 3166
    {
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
			 thd->fatal_error));
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3167
      query_cache_abort(&thd->net);
3168
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3169
    thd->proc_info="freeing items";
3170
    free_items(thd->free_list);  /* Free strings used by items */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3171 3172
    lex_end(lex);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3173 3174 3175 3176 3177 3178 3179 3180 3181
  DBUG_VOID_RETURN;
}


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

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3182
bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3183
		       char *length, char *decimals,
3184 3185
		       uint type_modifier,
		       Item *default_value, Item *comment,
3186
		       char *change, TYPELIB *interval, CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3187 3188 3189 3190
{
  register create_field *new_field;
  LEX  *lex= &thd->lex;
  uint allowed_type_modifier=0;
3191
  char warn_buff[MYSQL_ERRMSG_SIZE];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3192 3193 3194 3195
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
3196
    net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3197 3198 3199 3200 3201
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
3202
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3203 3204 3205 3206 3207 3208
				    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));
3209
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3210 3211 3212 3213 3214 3215 3216 3217 3218
				    lex->col_list));
    lex->col_list.empty();
  }

  if (default_value && default_value->type() == Item::NULL_ITEM)
  {
    if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	NOT_NULL_FLAG)
    {
3219
      net_printf(thd,ER_INVALID_DEFAULT,field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238
      DBUG_RETURN(1);
    }
    default_value=0;
  }
  if (!(new_field=new create_field()))
    DBUG_RETURN(1);
  new_field->field=0;
  new_field->field_name=field_name;
  new_field->def= (type_modifier & AUTO_INCREMENT_FLAG ? 0 : default_value);
  new_field->flags= type_modifier;
  new_field->unireg_check= (type_modifier & AUTO_INCREMENT_FLAG ?
			    Field::NEXT_NUMBER : Field::NONE);
  new_field->decimals= decimals ? (uint) set_zone(atoi(decimals),0,
						  NOT_FIXED_DEC-1) : 0;
  new_field->sql_type=type;
  new_field->length=0;
  new_field->change=change;
  new_field->interval=0;
  new_field->pack_length=0;
3239
  new_field->charset=cs;
3240

3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251
  if (!comment)
  {
    new_field->comment.str=0;
    new_field->comment.length=0;
  }
  else
  {
    /* In this case comment is always of type Item_string */
    new_field->comment.str=   (char*) comment->str_value.ptr();
    new_field->comment.length=comment->str_value.length();
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3252 3253 3254 3255 3256 3257
  if (length)
    if (!(new_field->length= (uint) atoi(length)))
      length=0; /* purecov: inspected */
  uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;

  if (new_field->length && new_field->decimals &&
3258
      new_field->length < new_field->decimals+1 &&
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3259
      new_field->decimals != NOT_FIXED_DEC)
3260
    new_field->length=new_field->decimals+1; /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283

  switch (type) {
  case FIELD_TYPE_TINY:
    if (!length) new_field->length=3+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_SHORT:
    if (!length) new_field->length=5+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_INT24:
    if (!length) new_field->length=8+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONG:
    if (!length) new_field->length=10+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONGLONG:
    if (!length) new_field->length=20;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_NULL:
3284
  case FIELD_TYPE_GEOMETRY:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3285 3286 3287 3288 3289 3290 3291 3292
    break;
  case FIELD_TYPE_DECIMAL:
    if (!length)
      new_field->length = 10;			// Default length for DECIMAL
    new_field->length+=sign_len;
    if (new_field->decimals)
      new_field->length++;
    break;
3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303
  case FIELD_TYPE_STRING:
  case FIELD_TYPE_VAR_STRING:
    if (new_field->length < MAX_FIELD_WIDTH || default_value)
      break;
    /* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */
    new_field->sql_type= FIELD_TYPE_BLOB;
    sprintf(warn_buff, ER(ER_AUTO_CONVERT), field_name, "CHAR",
	    (cs == my_charset_bin) ? "BLOB" : "TEXT");
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_AUTO_CONVERT,
		 warn_buff);
    /* fall through */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3304 3305 3306 3307
  case FIELD_TYPE_BLOB:
  case FIELD_TYPE_TINY_BLOB:
  case FIELD_TYPE_LONG_BLOB:
  case FIELD_TYPE_MEDIUM_BLOB:
3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321
    if (new_field->length)
    {
      /* The user has given a length to the blob column */
      if (new_field->length < 256)
	type= FIELD_TYPE_TINY_BLOB;
      if (new_field->length < 65536)
	type= FIELD_TYPE_BLOB;
      else if (new_field->length < 256L*256L*256L)
	type= FIELD_TYPE_MEDIUM_BLOB;
      else
	type= FIELD_TYPE_LONG_BLOB;
      new_field->length= 0;
    }
    new_field->sql_type= type;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3322 3323 3324 3325 3326 3327
    if (default_value)				// Allow empty as default value
    {
      String str,*res;
      res=default_value->val_str(&str);
      if (res->length())
      {
3328
	net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347
	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)
      {
3348
	net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401
	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)
      {
3402
	net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3403 3404 3405 3406 3407 3408 3409 3410
	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++)
3411 3412 3413
      {
	new_field->length+=(uint) strip_sp((char*) *pos)+1;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3414 3415 3416 3417 3418 3419 3420 3421 3422 3423
      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)
	{
3424
	  net_printf(thd,ER_INVALID_DEFAULT,field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3425 3426 3427 3428 3429 3430 3431 3432 3433
	  DBUG_RETURN(1);
	}
      }
    }
    break;
  case FIELD_TYPE_ENUM:
    {
      new_field->interval=interval;
      new_field->pack_length=interval->count < 256 ? 1 : 2; // Should be safe
3434
      new_field->length=(uint) strip_sp((char*) interval->type_names[0]);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3435 3436
      for (const char **pos=interval->type_names+1; *pos ; pos++)
      {
3437
	uint length=(uint) strip_sp((char*) *pos);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3438 3439 3440 3441 3442 3443 3444 3445 3446
	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()))
	{
3447
	  net_printf(thd,ER_INVALID_DEFAULT,field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3448 3449 3450 3451 3452 3453 3454 3455 3456
	  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
3457
       type != FIELD_TYPE_STRING && type != FIELD_TYPE_VAR_STRING))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3458
  {
3459
    net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3460 3461 3462 3463 3464 3465
	       MAX_FIELD_WIDTH-1);		/* purecov: inspected */
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
3466
    net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487
    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
3488
add_proc_to_list(THD* thd, Item *item)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3489 3490 3491 3492
{
  ORDER *order;
  Item	**item_ptr;

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3493
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3494 3495 3496 3497 3498
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
3499
  thd->lex.proc_list.link_in_list((byte*) order,(byte**) &order->next);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3500 3501 3502 3503 3504 3505 3506 3507
  return 0;
}


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

static void remove_escape(char *name)
{
3508 3509
  if (!*name)					// For empty DB names
    return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3510 3511
  char *to;
#ifdef USE_MB
3512
  char *strend=name+(uint) strlen(name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3513 3514 3515 3516 3517 3518
#endif
  for (to=name; *name ; name++)
  {
#ifdef USE_MB
    int l;
/*    if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
3519 3520
    if (use_mb(system_charset_info) &&
        (l = my_ismbchar(system_charset_info, name, strend)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3521 3522 3523 3524 3525 3526 3527 3528
    {
	while (l--)
	    *to++ = *name++;
	name--;
	continue;
    }
#endif
    if (*name == '\\' && name[1])
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3529
      name++;					// Skip '\\'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3530 3531 3532 3533 3534 3535 3536 3537 3538 3539
    *to++= *name;
  }
  *to=0;
}

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


monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3540
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3541 3542 3543 3544
{
  ORDER *order;
  Item	**item_ptr;
  DBUG_ENTER("add_to_list");
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3545
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3546 3547 3548 3549 3550 3551 3552
    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;
3553
  list.link_in_list((byte*) order,(byte**) &order->next);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3554 3555 3556 3557
  DBUG_RETURN(0);
}


monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3558 3559
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
3560 3561 3562 3563 3564
					     LEX_STRING *alias,
					     bool updating,
					     thr_lock_type flags,
					     List<String> *use_index,
					     List<String> *ignore_index)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3565 3566 3567 3568 3569 3570 3571 3572 3573
{
  register TABLE_LIST *ptr;
  char *alias_str;
  DBUG_ENTER("add_table_to_list");

  if (!table)
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? alias->str : table->table.str;
  if (table->table.length > NAME_LEN ||
3574 3575
      (table->table.length &&
       check_table_name(table->table.str,table->table.length)) ||
3576
      table->db.str && check_db_name(table->db.str))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3577
  {
3578
    net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3579 3580 3581 3582
    DBUG_RETURN(0);
  }

  if (!alias)					/* Alias is case sensitive */
3583 3584 3585 3586 3587 3588
  {
    if (table->sel)
    {
      net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
      DBUG_RETURN(0);
    }
3589
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3590
      DBUG_RETURN(0);
3591
  }
3592
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3593
    DBUG_RETURN(0);				/* purecov: inspected */
peter@mysql.com's avatar
peter@mysql.com committed
3594
  if (table->db.str)
3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605
  {
    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
  {
3606 3607
    /* The following can't be "" as we may do 'casedn_str()' on it */
    ptr->db= empty_c_string;
3608 3609
    ptr->db_length= 0;
  }
peter@mysql.com's avatar
peter@mysql.com committed
3610

3611
  ptr->alias= alias_str;
3612 3613
  if (lower_case_table_names)
  {
3614 3615
    my_casedn_str(files_charset_info,ptr->db);
    my_casedn_str(files_charset_info,table->table.str);
3616 3617
  }
  ptr->real_name=table->table.str;
3618
  ptr->real_name_length=table->table.length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3619
  ptr->lock_type=flags;
3620
  ptr->updating=updating;
3621
  ptr->derived= (SELECT_LEX_UNIT *) table->sel;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3622
  if (use_index)
3623
    ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3624 3625
					       sizeof(*use_index));
  if (ignore_index)
3626 3627
    ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index,
						   sizeof(*ignore_index));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3628 3629

  /* check that used name is unique */
3630
  if (flags != TL_IGNORE)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3631
  {
3632
    for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
3633
	 tables ;
3634
	 tables=tables->next)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3635
    {
3636
      if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db))
3637
      {
3638
	net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
3639 3640
	DBUG_RETURN(0);				/* purecov: tested */
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3641 3642
    }
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3643
  table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3644 3645 3646
  DBUG_RETURN(ptr);
}

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

3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660
/*
  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
*/

3661
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
3662 3663 3664 3665 3666 3667
{
  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));

3668
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
3669 3670 3671 3672 3673 3674 3675 3676 3677
       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
3678

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3679 3680
void add_join_on(TABLE_LIST *b,Item *expr)
{
3681
  if (expr)
3682
  {
3683 3684 3685 3686 3687 3688 3689 3690
    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();
3691
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3692 3693 3694 3695 3696 3697 3698 3699
}


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

3700
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3701 3702 3703 3704 3705 3706
{
  bool result=0;

  select_errors=0;				/* Write if more errors */
  if (options & REFRESH_GRANT)
  {
3707
    acl_reload(thd);
3708
    grant_reload(thd);
3709
    if (mqh_used)
3710
      reset_mqh(thd,(LEX_USER *) NULL,true);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3711 3712 3713
  }
  if (options & REFRESH_LOG)
  {
3714 3715 3716 3717
    mysql_log.new_file(1);
    mysql_update_log.new_file(1);
    mysql_bin_log.new_file(1);
    mysql_slow_log.new_file(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3718 3719 3720
    if (ha_flush_logs())
      result=1;
  }
3721
#ifdef HAVE_QUERY_CACHE
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3722 3723
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
3724
    query_cache.pack();				// FLUSH QUERY CACHE
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3725 3726 3727 3728
    options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
3729
    query_cache.flush();			// RESET QUERY CACHE
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3730
  }
3731
#endif /*HAVE_QUERY_CACHE*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3732 3733
  if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
  {
3734
    if ((options & REFRESH_READ_LOCK) && thd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3735
    {
3736 3737
      if (lock_global_read_lock(thd))
	return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3738
    }
3739
    result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3740 3741 3742 3743 3744 3745 3746 3747
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
  if (options & REFRESH_STATUS)
    refresh_status();
  if (options & REFRESH_THREADS)
    flush_thread_cache();
  if (options & REFRESH_MASTER)
3748 3749
    if (reset_master(thd))
      result=1;
3750
#ifdef OPENSSL
3751 3752 3753 3754 3755 3756
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
3757 3758 3759
 if (options & REFRESH_SLAVE)
 {
   LOCK_ACTIVE_MI;
3760
   if (reset_slave(thd, active_mi))
3761 3762 3763 3764
     result=1;
   UNLOCK_ACTIVE_MI;
 }
 if (options & REFRESH_USER_RESOURCES)
3765
   reset_mqh(thd,(LEX_USER *) NULL);
3766
 return result;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3767 3768 3769
}


3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781
/*
  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
*/

3782
void kill_one_thread(THD *thd, ulong id)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3783 3784 3785
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
3786 3787
  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
3788 3789 3790 3791
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
3792 3793
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3794 3795 3796
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809
  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
3810
  if (!error)
3811
    send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3812
  else
3813
    net_printf(thd,error,id);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829
}

/* 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);
}
3830 3831 3832 3833


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

3834
static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
3835
{
3836
  char buff[FN_REFLEN],*ptr, *end;
3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848
  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);
3849
  end=convert_dirname(buff, *filename_ptr, NullS);
3850
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
3851 3852
    return 1;					// End of memory
  *filename_ptr=ptr;
3853
  strxmov(ptr,buff,table_name,NullS);
3854 3855
  return 0;
}
3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870

/*
  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;
3871
  if (thd->lex.current_select != &thd->lex.select_lex)
3872 3873 3874 3875
  {
    char command[80];
    strmake(command, thd->lex.yylval->symbol.str,
	    min(thd->lex.yylval->symbol.length, sizeof(command)-1));
3876
    net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
3877 3878 3879 3880
    return 1;
  }
  return 0;
}
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910

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

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

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

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

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

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