sql_parse.cc 115 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000 MySQL AB
2

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

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

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

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

25 26
#define files_charset_info system_charset_info

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

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

49 50 51 52
#define MEM_ROOT_BLOCK_SIZE       8192
#define MEM_ROOT_PREALLOC         8192
#define TRANS_MEM_ROOT_BLOCK_SIZE 4096
#define TRANS_MEM_ROOT_PREALLOC   4096
unknown's avatar
unknown committed
53

54
extern int yyparse(void *thd);
unknown's avatar
unknown committed
55
extern "C" pthread_mutex_t THR_LOCK_keycache;
56 57 58
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#endif
unknown's avatar
unknown committed
59

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

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

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

80
static char empty_c_string[1]= {0};		// Used for not defined 'db'
unknown's avatar
unknown committed
81 82 83 84

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

unknown's avatar
unknown committed
101 102 103 104 105 106 107 108 109 110 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
{
unknown's avatar
unknown committed
113
  int error=0;
unknown's avatar
unknown committed
114
  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
unknown's avatar
unknown committed
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))
unknown's avatar
unknown committed
120
      error=1;
121
  }
unknown's avatar
unknown committed
122
  return error;
123 124 125
}


126 127 128
static HASH hash_user_connections;
extern  pthread_mutex_t LOCK_user_conn;

unknown's avatar
unknown committed
129 130
static int get_or_create_user_conn(THD *thd, const char *user,
				   const char *host,
unknown's avatar
unknown 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);
unknown's avatar
unknown committed
145 146
  if (!(uc = (struct  user_conn *) hash_search(&hash_user_connections,
					       (byte*) temp_user, temp_len)))
147
  {
unknown's avatar
unknown committed
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,
unknown's avatar
unknown committed
151 152
			 MYF(MY_WME)))))
    {
153
      send_error(thd, 0, NullS);		// Out of memory
154 155
      return_val=1;
      goto end;
unknown's avatar
unknown committed
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;
unknown's avatar
unknown 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;
unknown's avatar
unknown committed
180

181
}
182 183 184


/*
unknown's avatar
unknown committed
185 186 187
  Check if user is ok
  Updates:
  thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access
unknown's avatar
unknown committed
188 189
*/

unknown's avatar
unknown committed
190
static int check_user(THD *thd,enum_server_command command, const char *user,
unknown's avatar
unknown 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)
unknown's avatar
unknown committed
195 196
{
  thd->db=0;
unknown's avatar
unknown committed
197
  thd->db_length=0;
198
  USER_RESOURCES ur;
unknown's avatar
unknown committed
199 200

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

unknown's avatar
unknown committed
214
  DBUG_PRINT("info",
215
	     ("Capabilities: %d  packet_length: %ld  Host: '%s'  User: '%s'  Using password: %s  Access: %u  db: '%s'",
unknown's avatar
unknown committed
216
	      thd->client_capabilities, thd->max_client_packet_length,
217
	      thd->host_or_ip, thd->priv_user,
218
	      had_password ? "yes": "no",
unknown's avatar
unknown committed
219
	      thd->master_access, thd->db ? thd->db : "*none*"));
unknown's avatar
unknown committed
220

221 222 223 224
  /*
    In case we're going to retry we should not send error message at this
    point
  */
unknown's avatar
unknown committed
225 226
  if (thd->master_access & NO_ACCESS)
  {
227 228
    if (do_send_error)
    {
229 230 231 232
      /*
	Old client should get nicer error message if password version is
	not supported
      */
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
      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));
      }                
249
      return(1);					// Error already given
unknown's avatar
unknown committed
250 251
    }
    else
252
      return(-1); // do not report error in special handshake
unknown's avatar
unknown committed
253
  }
unknown's avatar
unknown committed
254

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

unknown's avatar
unknown committed
283
  if (db && db[0])
unknown's avatar
unknown committed
284 285
  {
    bool error=test(mysql_change_db(thd,db));
286 287
    if (error && thd->user_connect)
      decrease_user_connections(thd->user_connect);
unknown's avatar
unknown committed
288
    return error;
unknown's avatar
unknown committed
289
  }
unknown's avatar
unknown committed
290
  else
291
    send_ok(thd);				// Ready to handle questions
unknown's avatar
unknown committed
292 293 294
  return 0;					// ok
}

295

unknown's avatar
unknown committed
296
/*
unknown's avatar
unknown committed
297 298
  Check for maximum allowable user connections, if the mysqld server is
  started with corresponding variable that is greater then 0.
unknown's avatar
unknown committed
299 300
*/

301 302
extern "C" byte *get_key_conn(user_conn *buff, uint *length,
			      my_bool not_used __attribute__((unused)))
unknown's avatar
unknown committed
303 304 305 306 307
{
  *length=buff->len;
  return (byte*) buff->user;
}

308
extern "C" void free_user(struct user_conn *uc)
unknown's avatar
unknown committed
309 310 311 312
{
  my_free((char*) uc,MYF(0));
}

unknown's avatar
unknown committed
313
void init_max_user_conn(void)
unknown's avatar
unknown committed
314
{
unknown's avatar
unknown committed
315 316
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
		   0,0,
317
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
318
		   0);
unknown's avatar
unknown committed
319 320 321
}


322
static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
unknown's avatar
unknown committed
323
{
324
  int error=0;
325
  DBUG_ENTER("check_for_max_user_connections");
unknown's avatar
unknown committed
326

327 328
  if (max_user_connections &&
      (max_user_connections <=  (uint) uc->connections))
unknown's avatar
unknown committed
329
  {
330
    net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user);
331 332
    error=1;
    goto end;
unknown's avatar
unknown committed
333
  }
unknown's avatar
unknown committed
334
  uc->connections++;
335 336
  if (uc->user_resources.connections &&
      uc->conn_per_hour++ >= uc->user_resources.connections)
337
  {
338
    net_printf(thd, ER_USER_LIMIT_REACHED, uc->user,
339
	       "max_connections",
340 341 342
	       (long) uc->user_resources.connections);
    error=1;
  }
343 344
end:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
345 346 347
}


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

361

unknown's avatar
unknown committed
362 363 364 365 366
void free_max_user_conn(void)
{
  hash_free(&hash_user_connections);
}

unknown's avatar
unknown committed
367

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


unknown's avatar
unknown committed
400 401 402
/*
  Check if maximum queries per hour limit has been reached
  returns 0 if OK.
unknown's avatar
unknown committed
403

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

409

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

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

unknown's avatar
unknown committed
453

unknown's avatar
unknown committed
454
static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
455 456
{

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

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

unknown's avatar
unknown committed
491

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

497
#ifndef EMBEDDED_LIBRARY  
unknown's avatar
unknown committed
498 499 500 501 502
static int
check_connections(THD *thd)
{
  uint connect_errors=0;
  NET *net= &thd->net;
503 504 505 506
  char *end, *user, *passwd, *db;
  char prepared_scramble[SCRAMBLE41_LENGTH+4];  /* Buffer for scramble&hash */
  ACL_USER* cached_user=NULL; /* Initialise to NULL for first stage */
  uint cur_priv_version;
unknown's avatar
unknown committed
507
  DBUG_PRINT("info", (("check_connections called by thread %d"),
508
		      thd->thread_id));
unknown's avatar
unknown committed
509
  DBUG_PRINT("info",("New connection received on %s",
510
		     vio_description(net->vio)));
unknown's avatar
unknown committed
511 512
  if (!thd->host)                           // If TCP/IP connection
  {
513
    char ip[30];
514

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

unknown's avatar
unknown committed
552
  ulong pkt_len=0;
unknown's avatar
unknown committed
553
  {
unknown's avatar
unknown committed
554
    /* buff[] needs to big enough to hold the server_version variable */
555
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+64];
unknown's avatar
unknown committed
556
    int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
557
                       CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION;
unknown's avatar
unknown committed
558

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

unknown's avatar
unknown committed
569
    end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1;
unknown's avatar
unknown committed
570 571 572 573 574
    int4store((uchar*) end,thd->thread_id);
    end+=4;
    memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
    end+=SCRAMBLE_LENGTH +1;
    int2store(end,client_flags);
unknown's avatar
unknown committed
575
    end[2]=(char) MY_CHARSET_CURRENT;
unknown's avatar
unknown committed
576 577 578
    int2store(end+3,thd->server_status);
    bzero(end+5,13);
    end+=18;
unknown's avatar
unknown committed
579

580
    // At this point we write connection message and read reply
581
    if (net_write_command(net,(uchar) protocol_version, "", 0, buff,
unknown's avatar
unknown committed
582
			  (uint) (end-buff)) ||
unknown's avatar
unknown committed
583
       (pkt_len= my_net_read(net)) == packet_error ||
unknown's avatar
unknown committed
584 585 586 587 588 589 590 591 592 593 594
	pkt_len < MIN_HANDSHAKE_SIZE)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
  }
#ifdef _CUSTOMCONFIG_
#include "_cust_sql_parse.h"
#endif
  if (connect_errors)
    reset_host_errors(&thd->remote.sin_addr);
unknown's avatar
unknown committed
595
  if (thd->packet.alloc(thd->variables.net_buffer_length))
unknown's avatar
unknown committed
596 597 598
    return(ER_OUT_OF_RESOURCES);

  thd->client_capabilities=uint2korr(net->read_pos);
599 600 601 602 603 604 605 606 607 608 609 610
  if (thd->client_capabilities & CLIENT_PROTOCOL_41)
  {
    thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
    thd->max_client_packet_length= uint4korr(net->read_pos+4);
    end= (char*) net->read_pos+8;
  }
  else
  {
    thd->max_client_packet_length= uint3korr(net->read_pos+2);
    end= (char*) net->read_pos+5;
  }

611
  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
612
    thd->variables.sql_mode|= MODE_IGNORE_SPACE;
unknown's avatar
unknown committed
613
#ifdef HAVE_OPENSSL
unknown's avatar
unknown committed
614
  DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
unknown's avatar
unknown committed
615 616 617 618
  if (thd->client_capabilities & CLIENT_SSL)
  {
    /* Do the SSL layering. */
    DBUG_PRINT("info", ("IO layer change in progress..."));
unknown's avatar
unknown committed
619 620 621 622 623
    if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
    {
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
      inc_host_errors(&thd->remote.sin_addr);
unknown's avatar
unknown committed
624
      return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
625
    }
unknown's avatar
unknown committed
626 627 628 629
    DBUG_PRINT("info", ("Reading user information over SSL layer"));
    if ((pkt_len=my_net_read(net)) == packet_error ||
	pkt_len < NORMAL_HANDSHAKE_SIZE)
    {
unknown's avatar
unknown committed
630 631
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
unknown's avatar
unknown committed
632 633 634 635
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
  }
636 637 638
#endif

  if (end >= (char*) net->read_pos+ pkt_len +2)
unknown's avatar
unknown committed
639
  {
640 641
    inc_host_errors(&thd->remote.sin_addr);
    return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
642 643
  }

644 645 646
  user=   end;
  passwd= strend(user)+1;
  db=0;
unknown's avatar
unknown committed
647 648 649
  if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
     db=strend(passwd)+1;

650
  /* We can get only old hash at this point */
unknown's avatar
unknown committed
651
  if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
652
      return ER_HANDSHAKE_ERROR;
unknown's avatar
unknown committed
653

unknown's avatar
unknown committed
654
  if (thd->client_capabilities & CLIENT_INTERACTIVE)
655
     thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
656
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
657
       opt_using_transactions)
658
  net->return_status= &thd->server_status;
unknown's avatar
unknown committed
659
  net->read_timeout=(uint) thd->variables.net_read_timeout;
unknown's avatar
unknown committed
660

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

664 665 666
  /* 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 */
667 668 669
  if (check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect,
      simple_connect, prepared_scramble, using_password, &cur_priv_version,
      &cached_user)<0)
unknown's avatar
unknown committed
670
  {
671 672 673 674
    /* Store current used and database as they are erased with next packet */
    char tmp_user[USERNAME_LENGTH+1];
    char tmp_db[NAME_LEN+1];

675 676 677 678
    /* If The client is old we just have to return error */
    if (simple_connect)
      return -1;

unknown's avatar
unknown committed
679
    tmp_user[0]=0;
680
    if (user)
unknown's avatar
unknown committed
681 682
      strmake(tmp_user,user,USERNAME_LENGTH);

683
    tmp_db[0]=0;
684
    if (db)
unknown's avatar
unknown committed
685 686
      strmake(tmp_db,db,NAME_LEN);

687
    /* Write hash and encrypted scramble to client */
688 689
    if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
        net_flush(net))
690 691 692
      {
        inc_host_errors(&thd->remote.sin_addr);
        return ER_HANDSHAKE_ERROR;
unknown's avatar
unknown committed
693 694
      }
    /* Reading packet back */
695 696 697 698 699
    if ((pkt_len= my_net_read(net)) == packet_error)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return ER_HANDSHAKE_ERROR;
    }
unknown's avatar
unknown committed
700
    /* We have to get very specific packet size  */
701 702 703 704 705
    if (pkt_len != SCRAMBLE41_LENGTH)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return ER_HANDSHAKE_ERROR;
    }
unknown's avatar
unknown committed
706 707
    /* Final attempt to check the user based on reply */
    if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos,
708
        tmp_db, 1, 0, 1, prepared_scramble, using_password, &cur_priv_version,
unknown's avatar
unknown committed
709
        &cached_user))
710 711 712
      return -1;
  }
  thd->password=using_password;
unknown's avatar
unknown committed
713 714 715 716 717 718 719
  return 0;
}

pthread_handler_decl(handle_one_connection,arg)
{
  THD *thd=(THD*) arg;
  uint launch_time  =
unknown's avatar
unknown committed
720
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
unknown's avatar
unknown committed
721 722 723 724 725
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status );

  pthread_detach_this_thread();

726 727
#if !defined( __WIN__) && !defined(OS2)	// Win32 calls this in pthread_create
  // The following calls needs to be done before we call DBUG_ macros
728
  if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
unknown's avatar
unknown committed
729 730
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
731
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
732 733 734 735 736
    end_thread(thd,0);
    return 0;
  }
#endif

737 738 739 740 741 742 743
  /*
    handle_one_connection() is the only way a thread would start
    and would always be on top of the stack, therefore, the thread
    stack always starts at the address of the first local variable
    of handle_one_connection, which is thd. We need to know the
    start of the stack so that we could check for stack overruns.
  */
unknown's avatar
unknown committed
744 745 746 747
  DBUG_PRINT("info", ("handle_one_connection called by thread %d\n",
		      thd->thread_id));
  // now that we've called my_thread_init(), it is safe to call DBUG_*

unknown's avatar
unknown committed
748
#if defined(__WIN__)
unknown's avatar
unknown committed
749
  init_signals();				// IRENA; testing ?
unknown's avatar
unknown committed
750
#elif !defined(OS2)
unknown's avatar
unknown committed
751 752 753 754 755 756 757
  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);
758
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
759 760 761 762 763 764 765 766 767 768 769 770 771
    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)
772
	net_printf(thd,error,thd->host_or_ip);
unknown's avatar
unknown committed
773 774 775 776
#ifdef __NT__
      if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
	sleep(1);				/* must wait after eof() */
#endif
777
      statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
778 779 780
      goto end_thread;
    }

781
    if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
782 783 784 785
      thd->options |= OPTION_BIG_SELECTS;
    if (thd->client_capabilities & CLIENT_COMPRESS)
      net->compress=1;				// Use compression

unknown's avatar
unknown committed
786
    thd->proc_info=0;				// Remove 'login'
787
    thd->command=COM_SLEEP;
unknown's avatar
unknown committed
788 789
    thd->version=refresh_version;
    thd->set_time();
790 791 792
    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);
unknown's avatar
unknown committed
793 794 795 796 797
    while (!net->error && net->vio != 0 && !thd->killed)
    {
      if (do_command(thd))
	break;
    }
798 799
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
800
    free_root(&thd->mem_root,MYF(0));
unknown's avatar
unknown committed
801
    if (net->error && net->vio != 0 && net->report_error)
unknown's avatar
unknown committed
802
    {
unknown's avatar
unknown committed
803
      if (!thd->killed && thd->variables.log_warnings)
804 805 806 807 808 809
	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)));
810
      send_error(thd,net->last_errno,NullS);
unknown's avatar
unknown committed
811
      statistic_increment(aborted_threads,&LOCK_status);
unknown's avatar
unknown committed
812
    }
unknown's avatar
unknown committed
813

unknown's avatar
unknown committed
814 815 816 817 818 819 820 821 822 823 824 825 826
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 */
}

827 828 829 830
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
unknown's avatar
unknown committed
831

832
extern "C" pthread_handler_decl(handle_bootstrap,arg)
unknown's avatar
unknown committed
833
{
834 835 836
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
unknown's avatar
unknown committed
837

838
  /* The following must be called before DBUG_ENTER */
839
  if (my_thread_init() || thd->store_globals())
unknown's avatar
unknown committed
840 841
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
842 843
    thd->fatal_error=1;
    goto end;
unknown's avatar
unknown committed
844
  }
845 846 847 848
  DBUG_ENTER("handle_bootstrap");

  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
849
#if !defined(__WIN__) && !defined(OS2)
unknown's avatar
unknown committed
850
  sigset_t set;
851 852 853 854
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));


unknown's avatar
unknown committed
855 856
#endif

857
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
858 859 860 861
    thd->options |= OPTION_BIG_SELECTS;

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

864
  buff= (char*) thd->net.buff;
865 866 867
  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);
unknown's avatar
unknown committed
868 869
  while (fgets(buff, thd->net.max_packet, file))
  {
unknown's avatar
unknown committed
870
    uint length=(uint) strlen(buff);
unknown's avatar
unknown committed
871
    while (length && (my_isspace(system_charset_info, buff[length-1]) ||
872
           buff[length-1] == ';'))
unknown's avatar
unknown committed
873 874 875
      length--;
    buff[length]=0;
    thd->current_tablenr=0;
876
    thd->query_length=length;
unknown's avatar
unknown committed
877 878
    thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
    thd->query[length] = '\0';
unknown's avatar
unknown committed
879
    thd->query_id=query_id++;
880
    if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
881 882 883 884 885 886
    {
      thd->net.error = 0;
      close_thread_tables(thd);			// Free tables
      free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
      break;
    }
unknown's avatar
unknown committed
887 888 889
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
    if (thd->fatal_error)
890
      break;
891
    free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
892
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
893
  }
894 895 896 897 898 899

  /* 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);
900
  (void) pthread_cond_broadcast(&COND_thread_count);
901 902 903
  my_thread_end();
  pthread_exit(0);
  DBUG_RETURN(0);				// Never reached
unknown's avatar
unknown committed
904 905
}

906 907
#endif /* EMBEDDED_LIBRARY */

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

910
void free_items(Item *item)
unknown's avatar
unknown committed
911
{
912
  for (; item ; item=item->next)
unknown's avatar
unknown committed
913 914 915 916 917 918 919 920 921 922
    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;
923
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
924
    DBUG_RETURN(1); // out of memory
unknown's avatar
unknown committed
925
  table_list->db = db;
926
  table_list->real_name = table_list->alias = tbl_name;
unknown's avatar
unknown committed
927 928 929
  table_list->lock_type = TL_READ_NO_INSERT;
  table_list->next = 0;
  remove_escape(table_list->real_name);
unknown's avatar
unknown committed
930

931
  if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
unknown's avatar
unknown committed
932 933
    DBUG_RETURN(1);

934 935
  if (!db || check_db_name(db))
  {
936
    net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
937 938
    goto err;
  }
939
  if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege))
unknown's avatar
unknown committed
940
    goto err;
941
  if (grant_option && check_grant(thd, SELECT_ACL, table_list))
unknown's avatar
unknown committed
942 943 944
    goto err;

  thd->free_list = 0;
unknown's avatar
unknown committed
945
  thd->query_length=(uint) strlen(tbl_name);
unknown's avatar
unknown committed
946
  thd->query = tbl_name;
947 948 949 950 951
  if ((error = mysqld_dump_create_info(thd, table, -1)))
  {
    my_error(ER_GET_ERRNO, MYF(0));
    goto err;
  }
unknown's avatar
unknown committed
952
  net_flush(&thd->net);
953
  if ((error= table->file->dump(thd,fd)))
954
    my_error(ER_GET_ERRNO, MYF(0));
unknown's avatar
unknown committed
955

unknown's avatar
unknown committed
956 957
err:
  close_thread_tables(thd);
unknown's avatar
unknown committed
958
  DBUG_RETURN(error);
unknown's avatar
unknown committed
959 960 961
}


962
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
963

964
	/* Execute one command from socket (query or simple command) */
unknown's avatar
unknown committed
965 966 967
bool do_command(THD *thd)
{
  char *packet;
unknown's avatar
unknown committed
968 969
  uint old_timeout;
  ulong packet_length;
unknown's avatar
unknown committed
970 971 972 973 974 975 976 977
  NET *net;
  enum enum_server_command command;
  DBUG_ENTER("do_command");

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

  packet=0;
unknown's avatar
unknown committed
978 979 980
  old_timeout=net->read_timeout;
  // Wait max for 8 hours
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
unknown's avatar
unknown committed
981
  thd->clear_error();				// Clear error message
unknown's avatar
unknown committed
982 983 984 985

  net_new_transaction(net);
  if ((packet_length=my_net_read(net)) == packet_error)
  {
986 987 988 989 990 991
    DBUG_PRINT("info",("Got error %d reading command from socket %s",
		       net->error,
		       vio_description(net->vio)));
    /* Check if we can continue without closing the connection */
    if (net->error != 3)
      DBUG_RETURN(TRUE);			// We have to close it.
992
    send_error(thd,net->last_errno,NullS);
993
    net->error= 0;
994
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
995 996 997 998 999
  }
  else
  {
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
1000 1001
    if (command >= COM_END)
      command= COM_END;				// Wrong command
unknown's avatar
unknown committed
1002 1003 1004
    DBUG_PRINT("info",("Command on %s = %d (%s)",
		       vio_description(net->vio), command,
		       command_name[command]));
unknown's avatar
unknown committed
1005
  }
unknown's avatar
unknown committed
1006
  net->read_timeout=old_timeout;		// restore it
unknown's avatar
unknown committed
1007
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
1008 1009
}

1010
#endif  /* EMBEDDED_LIBRARY */
1011 1012 1013 1014 1015 1016

bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
  bool	error=0;
unknown's avatar
unknown committed
1017 1018 1019 1020
  /*
    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
  */
1021 1022 1023
  bool slow_command=FALSE;
  DBUG_ENTER("dispatch_command");

unknown's avatar
unknown committed
1024
  thd->command=command;
unknown's avatar
unknown committed
1025
  thd->set_time();
unknown's avatar
unknown committed
1026 1027 1028 1029 1030 1031
  VOID(pthread_mutex_lock(&LOCK_thread_count));
  thd->query_id=query_id;
  if (command != COM_STATISTICS && command != COM_PING)
    query_id++;
  thread_running++;
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1032

1033
  thd->lex.select_lex.options=0;		// We store status here
1034
  switch (command) {
unknown's avatar
unknown committed
1035
  case COM_INIT_DB:
unknown's avatar
unknown committed
1036
    statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
1037
    if (!mysql_change_db(thd,packet))
1038
      mysql_log.write(thd,command,"%s",thd->db);
unknown's avatar
unknown committed
1039
    break;
1040
#ifndef EMBEDDED_LIBRARY
1041 1042
  case COM_REGISTER_SLAVE:
  {
1043
    if (!register_slave(thd, (uchar*)packet, packet_length))
1044
      send_ok(thd);
1045 1046
    break;
  }
1047
#endif
unknown's avatar
unknown committed
1048 1049
  case COM_TABLE_DUMP:
    {
unknown's avatar
unknown committed
1050
      statistic_increment(com_other, &LOCK_status);
1051
      slow_command = TRUE;
1052 1053
      uint db_len = *(uchar*)packet;
      uint tbl_len = *(uchar*)(packet + db_len + 1);
1054
      char* db = thd->alloc(db_len + tbl_len + 2);
1055
      memcpy(db, packet + 1, db_len);
unknown's avatar
unknown committed
1056 1057
      char* tbl_name = db + db_len;
      *tbl_name++ = 0;
1058
      memcpy(tbl_name, packet + db_len + 2, tbl_len);
unknown's avatar
unknown committed
1059
      tbl_name[tbl_len] = 0;
unknown's avatar
unknown committed
1060
      if (mysql_table_dump(thd, db, tbl_name, -1))
1061
	send_error(thd); // dump to NET
unknown's avatar
unknown committed
1062 1063
      break;
    }
1064
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1065 1066
  case COM_CHANGE_USER:
  {
unknown's avatar
unknown committed
1067 1068 1069 1070
    thd->change_user();
    clear_error_message(thd);			// If errors from rollback

    statistic_increment(com_other,&LOCK_status);
1071
    char *user=   (char*) packet;
unknown's avatar
unknown committed
1072 1073
    char *passwd= strend(user)+1;
    char *db=     strend(passwd)+1;
unknown's avatar
unknown committed
1074

unknown's avatar
unknown committed
1075 1076 1077
    /* Save user and privileges */
    uint save_master_access=thd->master_access;
    uint save_db_access=    thd->db_access;
unknown's avatar
unknown committed
1078
    uint save_db_length=    thd->db_length;
unknown's avatar
unknown committed
1079
    char *save_user=	    thd->user;
unknown's avatar
unknown committed
1080
    thd->user=NULL; /* Needed for check_user to allocate new user */
unknown's avatar
unknown committed
1081 1082
    char *save_priv_user=   thd->priv_user;
    char *save_db=	    thd->db;
unknown's avatar
unknown committed
1083 1084 1085
    USER_CONN *save_uc=     thd->user_connect;
    bool simple_connect;
    bool using_password;
1086 1087 1088 1089 1090
    char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */
    char tmp_user[USERNAME_LENGTH+1];
    char tmp_db[NAME_LEN+1];
    ACL_USER* cached_user     ;                 /* Cached user */
    uint cur_priv_version;                      /* Cached grant version */
unknown's avatar
unknown committed
1091
    ulong pkt_len=0; /* Length of reply packet */
unknown's avatar
unknown committed
1092

unknown's avatar
unknown committed
1093
    /* Small check for incomming packet */
unknown's avatar
unknown committed
1094 1095

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

unknown's avatar
unknown committed
1098
    /* Now we shall basically perform authentication again */
unknown's avatar
unknown committed
1099

unknown's avatar
unknown committed
1100
     /* We can get only old hash at this point */
unknown's avatar
unknown committed
1101
    if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
unknown's avatar
unknown committed
1102
      goto restore_user_err;
unknown's avatar
unknown committed
1103

1104
    cached_user= NULL;
unknown's avatar
unknown committed
1105

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

unknown's avatar
unknown committed
1109 1110
    /* Store information if we used password. passwd will be dammaged */
    using_password=test(passwd[0]);
unknown's avatar
unknown committed
1111 1112 1113 1114 1115

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

    /*
1116 1117
      Check user permissions. If password failure we'll get scramble back
      Do not retry if we already have sent error (result>0)
unknown's avatar
unknown committed
1118
    */
unknown's avatar
unknown committed
1119
    if (check_user(thd,COM_CHANGE_USER, user, passwd, db, 0, simple_connect,
1120 1121
        simple_connect, prepared_scramble, using_password, &cur_priv_version,
        &cached_user)<0)
unknown's avatar
unknown committed
1122 1123 1124 1125
    {
      /* If The client is old we just have to have auth failure */
      if (simple_connect)
        goto restore_user; /* Error is already reported */
unknown's avatar
unknown committed
1126

unknown's avatar
unknown committed
1127
      /* Store current used and database as they are erased with next packet */
1128
      tmp_user[0]=0;
unknown's avatar
unknown committed
1129
      if (user)
1130 1131 1132
        strmake(tmp_user,user,USERNAME_LENGTH);

      tmp_db[0]=0;
unknown's avatar
unknown committed
1133
      if (db)
1134 1135
        strmake(tmp_db,db,NAME_LEN);

unknown's avatar
unknown committed
1136

unknown's avatar
unknown committed
1137
      /* Write hash and encrypted scramble to client */
1138 1139
      if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
          net_flush(net))
unknown's avatar
unknown committed
1140
        goto restore_user_err;
unknown's avatar
unknown committed
1141 1142 1143 1144 1145 1146 1147

      /* 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)
unknown's avatar
unknown committed
1148
        goto restore_user;
unknown's avatar
unknown committed
1149 1150

      /* Final attempt to check the user based on reply */
1151 1152 1153
      if (check_user(thd,COM_CHANGE_USER, tmp_user, (char*) net->read_pos,
          tmp_db, 0, 0, 1, prepared_scramble, using_password,
		     &cur_priv_version,
unknown's avatar
unknown committed
1154 1155
          &cached_user))
        goto restore_user;
unknown's avatar
unknown committed
1156
    }
unknown's avatar
unknown committed
1157
    /* Finally we've authenticated new user */
1158
    if (max_connections && save_uc)
unknown's avatar
unknown committed
1159
      decrease_user_connections(save_uc);
unknown's avatar
unknown committed
1160 1161
    x_free((gptr) save_db);
    x_free((gptr) save_user);
unknown's avatar
unknown committed
1162 1163
    thd->password=using_password;
    break;
unknown's avatar
unknown committed
1164

unknown's avatar
unknown committed
1165 1166 1167
    /* Bad luck  we shall restore old user */
    restore_user_err:
    send_error(thd, ER_UNKNOWN_COM_ERROR);
unknown's avatar
unknown committed
1168

unknown's avatar
unknown committed
1169 1170 1171 1172 1173 1174 1175 1176
    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;
unknown's avatar
unknown committed
1177
    thd->priv_user=save_priv_user;
unknown's avatar
unknown committed
1178 1179
    break;
  }
1180
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
1181 1182
  case COM_EXECUTE:
  {
1183
    mysql_stmt_execute(thd, packet);
unknown's avatar
unknown committed
1184 1185 1186 1187
    break;
  }
  case COM_LONG_DATA:
  {
1188
    mysql_stmt_get_longdata(thd, packet, packet_length);
unknown's avatar
unknown committed
1189 1190 1191 1192
    break;
  }
  case COM_PREPARE:
  {
1193
    mysql_stmt_prepare(thd, packet, packet_length);
unknown's avatar
unknown committed
1194 1195
    break;
  }
unknown's avatar
unknown committed
1196 1197 1198 1199 1200
  case COM_CLOSE_STMT:
  {
    mysql_stmt_free(thd, packet);
    break;
  }
unknown's avatar
unknown committed
1201 1202
  case COM_QUERY:
  {
1203 1204
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
1205
    mysql_log.write(thd,command,"%s",thd->query);
1206
    DBUG_PRINT("query",("%-.4096s",thd->query));
1207
    mysql_parse(thd,thd->query, thd->query_length);
1208 1209 1210

    while (!thd->fatal_error && thd->lex.found_colon)
    {
1211
      char *packet= thd->lex.found_colon;
1212 1213 1214 1215 1216 1217
      /* 
        Multiple queries exits, execute them individually
      */
      if (thd->lock || thd->open_tables || thd->derived_tables)
        close_thread_tables(thd);		

1218
      ulong length= thd->query_length-(ulong)(thd->lex.found_colon-thd->query);
1219 1220
      
      /* Remove garbage at start of query */
1221
      while (my_isspace(system_charset_info, *packet) && length > 0)
1222 1223 1224 1225 1226
      {
        packet++;
        length--;
      }
      thd->query_length= length;
1227 1228 1229 1230
      thd->query= packet;
      VOID(pthread_mutex_lock(&LOCK_thread_count));
      thd->query_id= query_id++;
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
1231 1232 1233
      mysql_parse(thd, packet, length);
    }

unknown's avatar
unknown committed
1234 1235 1236 1237 1238
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1239
  case COM_FIELD_LIST:				// This isn't actually needed
unknown's avatar
unknown committed
1240
#ifdef DONT_ALLOW_SHOW_COMMANDS
1241
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
1242 1243 1244 1245 1246
    break;
#else
  {
    char *fields;
    TABLE_LIST table_list;
unknown's avatar
unknown committed
1247
    statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
unknown's avatar
unknown committed
1248 1249 1250
    bzero((char*) &table_list,sizeof(table_list));
    if (!(table_list.db=thd->db))
    {
1251
      send_error(thd,ER_NO_DB_ERROR);
unknown's avatar
unknown committed
1252 1253 1254
      break;
    }
    thd->free_list=0;
1255
    table_list.alias= table_list.real_name= thd->strdup(packet);
unknown's avatar
unknown committed
1256
    packet=strend(packet)+1;
unknown's avatar
unknown committed
1257
    // command not cachable => no gap for data base name
unknown's avatar
unknown committed
1258 1259
    if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
      break;
1260
    mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
unknown's avatar
unknown committed
1261 1262 1263 1264 1265 1266 1267 1268
    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);
1269
    free_items(thd->free_list);
unknown's avatar
unknown committed
1270 1271 1272 1273
    break;
  }
#endif
  case COM_QUIT:
1274
    /* We don't calculate statistics for this command */
1275
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1276 1277 1278 1279
    net->error=0;				// Don't give 'abort' message
    error=TRUE;					// End server
    break;

unknown's avatar
unknown committed
1280
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1281
    {
unknown's avatar
unknown committed
1282
      statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
1283
      char *db=thd->strdup(packet);
1284
      // null test to handle EOM
unknown's avatar
unknown committed
1285
      if (!db || !strip_sp(db) || check_db_name(db))
1286
      {
1287
	net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
1288 1289
	break;
      }
1290
      if (lower_case_table_names)
1291
	my_casedn_str(files_charset_info, db);
unknown's avatar
unknown committed
1292 1293
      if (check_access(thd,CREATE_ACL,db,0,1))
	break;
1294
      mysql_log.write(thd,command,packet);
unknown's avatar
unknown committed
1295
      mysql_create_db(thd,db,0,0);
unknown's avatar
unknown committed
1296 1297
      break;
    }
unknown's avatar
unknown committed
1298
  case COM_DROP_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1299
    {
unknown's avatar
unknown committed
1300
      statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
1301
      char *db=thd->strdup(packet);
1302
      // null test to handle EOM
unknown's avatar
unknown committed
1303
      if (!db || !strip_sp(db) || check_db_name(db))
1304
      {
1305
	net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
1306 1307
	break;
      }
1308
      if (lower_case_table_names)
1309
	my_casedn_str(files_charset_info, db);
1310 1311
      if (check_access(thd,DROP_ACL,db,0,1))
	break;
unknown's avatar
unknown committed
1312 1313
      if (thd->locked_tables || thd->active_transaction())
      {
1314
	send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
1315
	break;
unknown's avatar
unknown committed
1316
      }
1317
      mysql_log.write(thd,command,db);
unknown's avatar
unknown committed
1318
      mysql_rm_db(thd,db,0,0);
unknown's avatar
unknown committed
1319 1320
      break;
    }
1321
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1322 1323
  case COM_BINLOG_DUMP:
    {
unknown's avatar
unknown committed
1324
      statistic_increment(com_other,&LOCK_status);
1325
      slow_command = TRUE;
unknown's avatar
unknown committed
1326
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1327
	break;
1328
      mysql_log.write(thd,command, 0);
unknown's avatar
unknown committed
1329

unknown's avatar
unknown committed
1330 1331
      ulong pos;
      ushort flags;
1332
      uint32 slave_server_id;
1333
      /* TODO: The following has to be changed to an 8 byte integer */
1334 1335
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
1336
      thd->server_id=0; /* avoid suicide */
1337
      kill_zombie_dump_threads(slave_server_id = uint4korr(packet+6));
1338
      thd->server_id = slave_server_id;
1339
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1340
      unregister_slave(thd,1,1);
1341 1342 1343
      // fake COM_QUIT -- if we get here, the thread needs to terminate
      error = TRUE;
      net->error = 0;
unknown's avatar
unknown committed
1344 1345
      break;
    }
1346
#endif
unknown's avatar
unknown committed
1347 1348
  case COM_REFRESH:
    {
unknown's avatar
unknown committed
1349
      statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
unknown's avatar
unknown committed
1350
      ulong options= (ulong) (uchar) packet[0];
unknown's avatar
unknown committed
1351
      if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1352
	break;
1353
      mysql_log.write(thd,command,NullS);
1354 1355
      /* error sending is deferred to reload_acl_and_cache */
      reload_acl_and_cache(thd, options, (TABLE_LIST*) 0) ;
unknown's avatar
unknown committed
1356 1357
      break;
    }
1358
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1359
  case COM_SHUTDOWN:
unknown's avatar
unknown committed
1360
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1361
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1362 1363
      break; /* purecov: inspected */
    DBUG_PRINT("quit",("Got shutdown command"));
1364
    mysql_log.write(thd,command,NullS);
1365
    send_eof(thd);
unknown's avatar
unknown committed
1366 1367 1368
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
unknown's avatar
unknown committed
1369
#ifndef OS2
1370
    send_eof(thd);				// This is for 'quit request'
unknown's avatar
unknown committed
1371
#endif
unknown's avatar
unknown committed
1372 1373
    close_connection(net);
    close_thread_tables(thd);			// Free before kill
1374
    free_root(&thd->mem_root,MYF(0));
1375
    free_root(&thd->transaction.mem_root,MYF(0));
unknown's avatar
unknown committed
1376 1377 1378
    kill_mysql();
    error=TRUE;
    break;
1379 1380
#endif
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1381 1382
  case COM_STATISTICS:
  {
1383
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1384
    statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
unknown's avatar
unknown committed
1385
    char buff[200];
1386
    ulong uptime = (ulong) (thd->start_time - start_time);
unknown's avatar
unknown committed
1387
    sprintf((char*) buff,
1388
	    "Uptime: %ld  Threads: %d  Questions: %lu  Slow queries: %ld  Opens: %ld  Flush tables: %ld  Open tables: %u  Queries per second avg: %.3f",
unknown's avatar
unknown committed
1389 1390 1391 1392 1393 1394 1395 1396 1397
	    uptime,
	    (int) thread_count,thd->query_id,long_query_count,
	    opened_tables,refresh_version, cached_tables(),
	    uptime ? (float)thd->query_id/(float)uptime : 0);
#ifdef SAFEMALLOC
    if (lCurMemory)				// Using SAFEMALLOC
      sprintf(strend(buff), "  Memory in use: %ldK  Max memory used: %ldK",
	      (lCurMemory+1023L)/1024L,(lMaxMemory+1023L)/1024L);
 #endif
unknown's avatar
unknown committed
1398
    VOID(my_net_write(net, buff,(uint) strlen(buff)));
unknown's avatar
unknown committed
1399 1400 1401
    VOID(net_flush(net));
    break;
  }
1402
#endif
unknown's avatar
unknown committed
1403
  case COM_PING:
unknown's avatar
unknown committed
1404
    statistic_increment(com_other,&LOCK_status);
1405
    send_ok(thd);				// Tell client we are alive
unknown's avatar
unknown committed
1406 1407
    break;
  case COM_PROCESS_INFO:
unknown's avatar
unknown committed
1408
    statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
unknown's avatar
unknown committed
1409
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
1410
      break;
1411
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1412 1413 1414 1415 1416
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
			  thd->priv_user,0);
    break;
  case COM_PROCESS_KILL:
  {
unknown's avatar
unknown committed
1417
    statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
1418
    ulong id=(ulong) uint4korr(packet);
unknown's avatar
unknown committed
1419 1420 1421 1422
    kill_one_thread(thd,id);
    break;
  }
  case COM_DEBUG:
unknown's avatar
unknown committed
1423
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1424
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1425 1426
      break;					/* purecov: inspected */
    mysql_print_status(thd);
1427
    mysql_log.write(thd,command,NullS);
1428
    send_eof(thd);
unknown's avatar
unknown committed
1429 1430 1431 1432 1433
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
1434
  case COM_END:
unknown's avatar
unknown committed
1435
  default:
1436
    send_error(thd, ER_UNKNOWN_COM_ERROR);
unknown's avatar
unknown committed
1437 1438
    break;
  }
1439
  if (thd->lock || thd->open_tables || thd->derived_tables)
unknown's avatar
unknown committed
1440 1441 1442 1443 1444 1445
  {
    thd->proc_info="closing tables";
    close_thread_tables(thd);			/* Free tables */
  }

  if (thd->fatal_error)
1446
    send_error(thd,0);				// End of memory ?
unknown's avatar
unknown committed
1447 1448

  time_t start_of_query=thd->start_time;
1449
  thd->end_time();				// Set start time
1450

1451
  /* If not reading from backup and if the query took too long */
1452
  if (!slow_command && !thd->user_time) // do not log 'slow_command' queries
unknown's avatar
unknown committed
1453
  {
1454 1455
    thd->proc_info="logging slow query";

1456 1457
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
1458
	((thd->lex.select_lex.options &
1459
	  (QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED)) &&
1460
	 (specialflag & SPECIAL_LONG_LOG_FORMAT)))
1461 1462 1463 1464
    {
      long_query_count++;
      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
    }
unknown's avatar
unknown committed
1465
  }
1466
  thd->proc_info="cleaning up";
unknown's avatar
unknown committed
1467 1468 1469 1470 1471 1472
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
  thd->proc_info=0;
  thd->command=COM_SLEEP;
  thd->query=0;
  thread_running--;
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1473
  thd->packet.shrink(thd->variables.net_buffer_length);	// Reclaim some memory
1474
  free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1475 1476 1477
  DBUG_RETURN(error);
}

1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495

/*
  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
1496
  /* Remove garbage at start and end of query */
1497 1498 1499 1500 1501 1502
  while (my_isspace(system_charset_info,packet[0]) && packet_length > 0)
  {
    packet++;
    packet_length--;
  }
  char *pos=packet+packet_length;		// Point at end null
unknown's avatar
unknown committed
1503
  while (packet_length > 0 &&
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522
	 (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;
}

unknown's avatar
unknown committed
1523 1524 1525 1526 1527 1528
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/

void
1529
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
1530
{
1531
  int	res= 0;
1532
  LEX	*lex= &thd->lex;
1533
  TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first;
unknown's avatar
unknown committed
1534
  SELECT_LEX *select_lex= &lex->select_lex;
1535
  SELECT_LEX_UNIT *unit= &lex->unit;
unknown's avatar
unknown committed
1536 1537
  DBUG_ENTER("mysql_execute_command");

1538 1539 1540 1541 1542 1543
  /*
    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.
  */
1544
  if (tables || &lex->select_lex != lex->all_selects_list)
1545 1546 1547 1548 1549 1550 1551
    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;

1552
#ifndef EMBEDDED_LIBRARY
1553 1554
  if (thd->slave_thread)
  {
unknown's avatar
unknown committed
1555
    /*
unknown's avatar
merge  
unknown committed
1556 1557 1558 1559
      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))
1560
      DBUG_VOID_RETURN;
unknown's avatar
merge  
unknown committed
1561 1562 1563 1564 1565 1566
#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()
    */
1567 1568 1569
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
unknown's avatar
unknown committed
1570
      lex->insert_list = &select_lex->item_list;
1571
    }
unknown's avatar
merge  
unknown committed
1572
#endif
1573
  }
1574
#endif /* EMBEDDED_LIBRARY */
1575
  /*
unknown's avatar
unknown committed
1576 1577
    TODO: make derived tables processing 'inside' SELECT processing.
    TODO: solve problem with depended derived tables in subselects
1578
  */
unknown's avatar
unknown committed
1579
  if (lex->derived_tables)
unknown's avatar
unknown committed
1580
  {
1581 1582 1583
    for (SELECT_LEX *sl= lex->all_selects_list;
	 sl;
	 sl= sl->next_select_in_list())
1584
    {
1585 1586 1587
      for (TABLE_LIST *cursor= sl->get_table_list();
	   cursor;
	   cursor= cursor->next)
1588
      {
1589 1590 1591 1592
	if (cursor->derived && (res=mysql_derived(thd, lex,
						  (SELECT_LEX_UNIT *)
						  cursor->derived,
						  cursor)))
unknown's avatar
unknown committed
1593
	{
1594 1595 1596 1597
	  if (res < 0 || thd->net.report_error)
	    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
	  DBUG_VOID_RETURN;
	}
1598 1599
      }
    }
1600
  }
unknown's avatar
unknown committed
1601
  if ((&lex->select_lex != lex->all_selects_list &&
1602 1603 1604
       lex->unit.create_total_list(thd, lex, &tables)) 
#ifndef EMBEDDED_LIBRARY
      ||
unknown's avatar
unknown committed
1605
      (table_rules_on && tables && thd->slave_thread &&
1606 1607 1608
       !tables_ok(thd,tables))
#endif
      )
1609
    DBUG_VOID_RETURN;
1610

unknown's avatar
unknown committed
1611
  statistic_increment(com_stat[lex->sql_command],&LOCK_status);
unknown's avatar
unknown committed
1612 1613 1614
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
1615
    select_result *result=lex->result;
unknown's avatar
unknown committed
1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631
    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
    }

1632 1633 1634
    unit->offset_limit_cnt= (ha_rows) unit->global_parameters->offset_limit;
    unit->select_limit_cnt= (ha_rows) (unit->global_parameters->select_limit+
      unit->global_parameters->offset_limit);
unknown's avatar
unknown committed
1635
    if (unit->select_limit_cnt <
1636
	(ha_rows) unit->global_parameters->select_limit)
1637 1638
      unit->select_limit_cnt= HA_POS_ERROR;		// no limit
    if (unit->select_limit_cnt == HA_POS_ERROR)
1639
      select_lex->options&= ~OPTION_FOUND_ROWS;
unknown's avatar
unknown committed
1640 1641

    if (!(res=open_and_lock_tables(thd,tables)))
unknown's avatar
unknown committed
1642
    {
unknown's avatar
unknown committed
1643
      if (lex->describe)
unknown's avatar
unknown committed
1644
      {
1645 1646 1647 1648 1649 1650 1651
	if (!(result= new select_send()))
	{
	  send_error(thd, ER_OUT_OF_RESOURCES);
	  DBUG_VOID_RETURN;
	}
	else
	  thd->send_explain_fields(result);
1652
	fix_tables_pointers(lex->all_selects_list);
1653
	res= mysql_explain_union(thd, &thd->lex.unit, result);
unknown's avatar
unknown committed
1654 1655
	MYSQL_LOCK *save_lock= thd->lock;
	thd->lock= (MYSQL_LOCK *)0;
1656
	result->send_eof();
unknown's avatar
unknown committed
1657 1658 1659 1660
	thd->lock= save_lock;
      }
      else
      {
unknown's avatar
unknown committed
1661 1662
	if (!result)
	{
unknown's avatar
unknown committed
1663
	  if (!(result=new select_send()))
unknown's avatar
unknown committed
1664 1665 1666 1667 1668 1669 1670 1671 1672
	  {
	    res= -1;
#ifdef DELETE_ITEMS
	    delete select_lex->having;
	    delete select_lex->where;
#endif
	    break;
	  }
	}
unknown's avatar
unknown committed
1673 1674 1675
	query_cache_store_query(thd, tables);
	res=handle_select(thd, lex, result);
      }
unknown's avatar
unknown committed
1676
    }
unknown's avatar
unknown committed
1677 1678
    break;
  }
unknown's avatar
unknown committed
1679
  case SQLCOM_DO:
unknown's avatar
unknown committed
1680 1681 1682 1683 1684 1685 1686 1687
    if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
		   (res= open_and_lock_tables(thd,tables))))
	break;

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

1690
  case SQLCOM_EMPTY_QUERY:
1691
    send_ok(thd);
1692 1693
    break;

unknown's avatar
unknown committed
1694 1695 1696 1697
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

1698
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1699
  case SQLCOM_PURGE:
1700
  {
unknown's avatar
unknown committed
1701
    if (check_global_access(thd, SUPER_ACL))
1702 1703 1704 1705
      goto error;
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
1706 1707
#endif

unknown's avatar
unknown committed
1708 1709
  case SQLCOM_SHOW_WARNS:
  {
1710 1711
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
1712 1713 1714
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
unknown's avatar
unknown committed
1715 1716 1717 1718
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
1719 1720
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
1721 1722
    break;
  }
unknown's avatar
unknown committed
1723 1724
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
1725
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1726
      goto error;
unknown's avatar
unknown committed
1727
#ifndef WORKING_NEW_MASTER
1728
    net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
unknown's avatar
unknown committed
1729 1730
    res= 1;
#else
unknown's avatar
unknown committed
1731
    res = show_new_master(thd);
unknown's avatar
unknown committed
1732
#endif
unknown's avatar
unknown committed
1733 1734
    break;
  }
1735 1736

#ifndef EMBEDDED_LIBRARY
1737 1738
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
1739
    if (check_global_access(thd, REPL_SLAVE_ACL))
1740 1741 1742 1743
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
1744 1745
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
1746
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1747 1748 1749 1750
      goto error;
    res = show_binlog_events(thd);
    break;
  }
1751 1752
#endif

unknown's avatar
unknown committed
1753
  case SQLCOM_BACKUP_TABLE:
1754 1755 1756
  {
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables) ||
unknown's avatar
unknown committed
1757
	check_global_access(thd, FILE_ACL))
1758 1759
      goto error; /* purecov: inspected */
    res = mysql_backup_table(thd, tables);
unknown's avatar
unknown committed
1760

1761 1762
    break;
  }
unknown's avatar
unknown committed
1763
  case SQLCOM_RESTORE_TABLE:
1764 1765
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
1766 1767
	check_table_access(thd, INSERT_ACL, tables) ||
	check_global_access(thd, FILE_ACL))
1768 1769 1770 1771
      goto error; /* purecov: inspected */
    res = mysql_restore_table(thd, tables);
    break;
  }
1772 1773

#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1774
  case SQLCOM_CHANGE_MASTER:
1775
  {
unknown's avatar
unknown committed
1776
    if (check_global_access(thd, SUPER_ACL))
1777
      goto error;
1778 1779 1780
    LOCK_ACTIVE_MI;
    res = change_master(thd,active_mi);
    UNLOCK_ACTIVE_MI;
1781 1782
    break;
  }
unknown's avatar
unknown committed
1783
  case SQLCOM_SHOW_SLAVE_STAT:
1784
  {
unknown's avatar
unknown committed
1785
    if (check_global_access(thd, SUPER_ACL))
1786
      goto error;
1787 1788 1789
    LOCK_ACTIVE_MI;
    res = show_master_info(thd,active_mi);
    UNLOCK_ACTIVE_MI;
1790 1791
    break;
  }
unknown's avatar
unknown committed
1792
  case SQLCOM_SHOW_MASTER_STAT:
1793
  {
unknown's avatar
unknown committed
1794
    if (check_global_access(thd, SUPER_ACL))
1795 1796 1797 1798
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
1799

1800
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
1801
    if (check_global_access(thd, SUPER_ACL))
1802
      goto error;
1803 1804 1805 1806
    if (end_active_trans(thd))
      res= -1;
    else
      res = load_master_data(thd);
1807
    break;
1808
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
1809

unknown's avatar
unknown committed
1810 1811 1812
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
1813
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1814 1815 1816 1817 1818
	goto error;
      res = innodb_show_status(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
1819

1820
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1821
  case SQLCOM_LOAD_MASTER_TABLE:
1822
  {
unknown's avatar
unknown committed
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834
    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)
1835
	goto error;
unknown's avatar
unknown committed
1836
    }
1837
    if (strlen(tables->real_name) > NAME_LEN)
unknown's avatar
unknown committed
1838
    {
unknown's avatar
unknown committed
1839
      net_printf(thd,ER_WRONG_TABLE_NAME,tables->real_name);
unknown's avatar
unknown committed
1840 1841
      break;
    }
1842 1843 1844 1845 1846
    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))
    {
1847
      send_ok(thd);
1848 1849
    }
    UNLOCK_ACTIVE_MI;
unknown's avatar
unknown committed
1850
    break;
1851
  }
1852 1853
#endif /* EMBEDDED_LIBRARY */

unknown's avatar
unknown committed
1854
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
1855 1856 1857
  {
    ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
		      CREATE_TMP_ACL : CREATE_ACL);
1858 1859
    if (!tables->db)
      tables->db=thd->db;
unknown's avatar
unknown committed
1860
    if (check_access(thd,want_priv,tables->db,&tables->grant.privilege) ||
1861 1862 1863
	check_merge_table_access(thd, tables->db,
				 (TABLE_LIST *)
				 lex->create_info.merge_list.first))
unknown's avatar
unknown committed
1864
      goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
1865
    if (grant_option && want_priv != CREATE_TMP_ACL)
unknown's avatar
unknown committed
1866 1867 1868 1869
    {
      /* Check that the first table has CREATE privilege */
      TABLE_LIST *tmp_table_list=tables->next;
      tables->next=0;
unknown's avatar
unknown committed
1870
      bool error=check_grant(thd, want_priv, tables);
unknown's avatar
unknown committed
1871 1872 1873 1874
      tables->next=tmp_table_list;
      if (error)
	goto error;
    }
1875
    if (strlen(tables->real_name) > NAME_LEN)
unknown's avatar
unknown committed
1876
    {
unknown's avatar
unknown committed
1877
      net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias);
unknown's avatar
unknown committed
1878 1879 1880
      res=0;
      break;
    }
1881 1882 1883
#ifndef HAVE_READLINK
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
1884
    /* Fix names if symlinked tables */
unknown's avatar
unknown committed
1885
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
1886
			   tables->real_name) ||
unknown's avatar
unknown committed
1887
	append_file_to_dir(thd,&lex->create_info.index_file_name,
1888
			   tables->real_name))
1889 1890 1891 1892
    {
      res=-1;
      break;
    }
1893
#endif
1894
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
1895 1896 1897 1898
    {
      select_result *result;

      if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
1899
	  find_real_table_in_list(tables->next, tables->db, tables->real_name))
unknown's avatar
unknown committed
1900
      {
unknown's avatar
unknown committed
1901
	net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
unknown's avatar
unknown committed
1902 1903 1904 1905 1906 1907 1908
	DBUG_VOID_RETURN;
      }
      if (tables->next)
      {
	if (check_table_access(thd, SELECT_ACL, tables->next))
	  goto error;				// Error message is given
      }
1909 1910 1911 1912 1913
      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
1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929

      /* Skip first table, which is the table we are creating */
      lex->select_lex.table_list.first=
	(byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
      if (!(res=open_and_lock_tables(thd,tables->next)))
      {
        if ((result=new select_create(tables->db ? tables->db : thd->db,
                                      tables->real_name, &lex->create_info,
                                      lex->create_list,
                                      lex->key_list,
                                      select_lex->item_list,lex->duplicates)))
          res=handle_select(thd, lex, result);
	else
	  res= -1;
      }
    }
unknown's avatar
unknown committed
1930 1931
    else // regular create
    {
unknown's avatar
unknown committed
1932 1933 1934 1935 1936 1937 1938 1939
      if (lex->name)
        res= mysql_create_like_table(thd, tables, &lex->create_info, 
                                     (Table_ident *)lex->name); 
      else
        res= mysql_create_table(thd,tables->db ? tables->db : thd->db,
			         tables->real_name, &lex->create_info,
			         lex->create_list,
			         lex->key_list,0,0,0); // do logging
unknown's avatar
unknown committed
1940
      if (!res)
1941
	send_ok(thd);
unknown's avatar
unknown committed
1942 1943
    }
    break;
unknown's avatar
unknown committed
1944
  }
unknown's avatar
unknown committed
1945 1946 1947 1948 1949 1950 1951
  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;
1952 1953 1954 1955
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_create_index(thd, tables, lex->key_list);
unknown's avatar
unknown committed
1956 1957
    break;

1958
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1959
  case SQLCOM_SLAVE_START:
1960 1961 1962 1963
  {
    LOCK_ACTIVE_MI;
    start_slave(thd,active_mi,1 /* net report*/);
    UNLOCK_ACTIVE_MI;
unknown's avatar
unknown committed
1964
    break;
1965
  }
unknown's avatar
unknown committed
1966
  case SQLCOM_SLAVE_STOP:
1967 1968 1969 1970 1971 1972
  /*
    If the client thread has locked tables, a deadlock is possible.
    Assume that
    - the client thread does LOCK TABLE t READ.
    - then the master updates t.
    - then the SQL slave thread wants to update t,
1973
      so it waits for the client thread because t is locked by it.
1974
    - then the client thread does SLAVE STOP.
1975 1976
      SLAVE STOP waits for the SQL slave thread to terminate its
      update t, which waits for the client thread because t is locked by it.
1977 1978 1979 1980 1981
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
  if (thd->locked_tables || thd->active_transaction())
  {
1982
    send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
1983
    break;
1984
  }
1985 1986 1987 1988
  {
    LOCK_ACTIVE_MI;
    stop_slave(thd,active_mi,1/* net report*/);
    UNLOCK_ACTIVE_MI;
unknown's avatar
unknown committed
1989
    break;
1990
  }
1991 1992
#endif

unknown's avatar
unknown committed
1993 1994
  case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
1995
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
1996 1997 1998
    break;
#else
    {
unknown's avatar
unknown committed
1999
      ulong priv=0;
unknown's avatar
unknown committed
2000
      if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
unknown's avatar
unknown committed
2001
      {
2002
	net_printf(thd,ER_WRONG_TABLE_NAME,lex->name);
unknown's avatar
unknown committed
2003 2004 2005
	res=0;
	break;
      }
2006 2007
      if (!tables->db)
	tables->db=thd->db;
2008 2009
      if (!select_lex->db)
	select_lex->db=tables->db;
unknown's avatar
unknown committed
2010
      if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege) ||
2011
	  check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv) ||
unknown's avatar
unknown committed
2012
	  check_merge_table_access(thd, tables->db,
2013 2014 2015
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026
      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;
2027
	  tmp_table.db=select_lex->db;
unknown's avatar
unknown committed
2028 2029 2030 2031 2032
	  tmp_table.grant.privilege=priv;
	  if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables))
	    goto error;
	}
      }
2033 2034
      /* Don't yet allow changing of symlinks with ALTER TABLE */
      lex->create_info.data_file_name=lex->create_info.index_file_name=0;
unknown's avatar
unknown committed
2035
      /* ALTER TABLE ends previous transaction */
2036
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2037 2038
	res= -1;
      else
unknown's avatar
unknown committed
2039
      {
2040
	res= mysql_alter_table(thd, select_lex->db, lex->name,
unknown's avatar
unknown committed
2041 2042 2043
			       &lex->create_info,
			       tables, lex->create_list,
			       lex->key_list, lex->drop_list, lex->alter_list,
2044
                               (ORDER *) select_lex->order_list.first,
2045 2046
			       lex->drop_primary, lex->duplicates,
			       lex->alter_keys_onoff, lex->simple_alter);
unknown's avatar
unknown committed
2047
      }
unknown's avatar
unknown committed
2048 2049 2050
      break;
    }
#endif
unknown's avatar
unknown committed
2051
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
2052 2053 2054
  {
    TABLE_LIST *table;
    if (check_db_used(thd,tables))
unknown's avatar
unknown committed
2055
      goto error;
unknown's avatar
unknown committed
2056 2057
    for (table=tables ; table ; table=table->next->next)
    {
unknown's avatar
unknown committed
2058 2059
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
		       &table->grant.privilege) ||
unknown's avatar
unknown committed
2060 2061 2062 2063 2064
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next->db,
		       &table->next->grant.privilege))
	goto error;
      if (grant_option)
      {
unknown's avatar
unknown committed
2065 2066 2067 2068 2069
	TABLE_LIST old_list,new_list;
	old_list=table[0];
	new_list=table->next[0];
	old_list.next=new_list.next=0;
	if (check_grant(thd,ALTER_ACL,&old_list) ||
unknown's avatar
unknown committed
2070
	    (!test_all_bits(table->next->grant.privilege,
2071
			    INSERT_ACL | CREATE_ACL) &&
unknown's avatar
unknown committed
2072
	     check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list)))
unknown's avatar
unknown committed
2073 2074 2075
	  goto error;
      }
    }
unknown's avatar
unknown committed
2076
    query_cache_invalidate3(thd, tables, 0);
2077 2078 2079
    if (end_active_trans(thd))
      res= -1;
    else if (mysql_rename_tables(thd,tables))
unknown's avatar
unknown committed
2080 2081
      res= -1;
    break;
unknown's avatar
unknown committed
2082
  }
2083
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2084 2085
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2086
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
2087 2088 2089
    DBUG_VOID_RETURN;
#else
    {
unknown's avatar
unknown committed
2090
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2091 2092 2093 2094
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
2095
#endif
2096
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2097
  case SQLCOM_SHOW_CREATE:
unknown's avatar
unknown committed
2098
#ifdef DONT_ALLOW_SHOW_COMMANDS
2099
    send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
unknown's avatar
unknown committed
2100 2101
    DBUG_VOID_RETURN;
#else
unknown's avatar
unknown committed
2102
    {
unknown's avatar
unknown committed
2103 2104 2105 2106
      if (check_db_used(thd, tables) ||
	  check_access(thd, SELECT_ACL | EXTRA_ACL, tables->db,
		       &tables->grant.privilege))
	goto error;
unknown's avatar
unknown committed
2107
      res = mysqld_show_create(thd, tables);
unknown's avatar
unknown committed
2108 2109
      break;
    }
unknown's avatar
unknown committed
2110
#endif
unknown's avatar
unknown committed
2111
  case SQLCOM_REPAIR:
2112 2113 2114 2115 2116 2117 2118
  {
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
      goto error; /* purecov: inspected */
    res = mysql_repair_table(thd, tables, &lex->check_opt);
    break;
  }
unknown's avatar
unknown committed
2119
  case SQLCOM_CHECK:
2120 2121 2122 2123 2124 2125 2126
  {
    if (check_db_used(thd,tables) ||
	check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables))
      goto error; /* purecov: inspected */
    res = mysql_check_table(thd, tables, &lex->check_opt);
    break;
  }
unknown's avatar
unknown committed
2127 2128
  case SQLCOM_ANALYZE:
  {
unknown's avatar
unknown committed
2129 2130
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
unknown's avatar
unknown committed
2131
      goto error; /* purecov: inspected */
2132
    res = mysql_analyze_table(thd, tables, &lex->check_opt);
unknown's avatar
unknown committed
2133
    break;
unknown's avatar
unknown committed
2134
  }
2135

unknown's avatar
unknown committed
2136 2137 2138
  case SQLCOM_OPTIMIZE:
  {
    HA_CREATE_INFO create_info;
2139 2140
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
unknown's avatar
unknown committed
2141
      goto error; /* purecov: inspected */
2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152
    if (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC))
    {
      /* Use ALTER TABLE */
      lex->create_list.empty();
      lex->key_list.empty();
      lex->col_list.empty();
      lex->drop_list.empty();
      lex->alter_list.empty();
      bzero((char*) &create_info,sizeof(create_info));
      create_info.db_type=DB_TYPE_DEFAULT;
      create_info.row_type=ROW_TYPE_DEFAULT;
unknown's avatar
unknown committed
2153
      create_info.table_charset=default_charset_info;
2154 2155 2156
      res= mysql_alter_table(thd, NullS, NullS, &create_info,
			     tables, lex->create_list,
			     lex->key_list, lex->drop_list, lex->alter_list,
unknown's avatar
unknown committed
2157
                             (ORDER *) 0,
2158 2159 2160 2161
			     0,DUP_ERROR);
    }
    else
      res = mysql_optimize_table(thd, tables, &lex->check_opt);
unknown's avatar
unknown committed
2162 2163 2164 2165 2166 2167 2168
    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;
2169
    if (select_lex->item_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
2170
    {
2171
      send_error(thd,ER_WRONG_VALUE_COUNT);
unknown's avatar
unknown committed
2172 2173
      DBUG_VOID_RETURN;
    }
2174 2175 2176 2177 2178 2179 2180
    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);
unknown's avatar
unknown committed
2181 2182
    if (thd->net.report_error)
      res= -1;
2183 2184 2185 2186 2187 2188 2189
    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)
2190
    {
2191 2192
      send_error(thd,ER_WRONG_VALUE_COUNT);
      DBUG_VOID_RETURN;
2193 2194
    }
    {
unknown's avatar
unknown committed
2195
      const char *msg= 0;
unknown's avatar
unknown committed
2196
      if (select_lex->order_list.elements)
unknown's avatar
unknown committed
2197
	msg= "ORDER BY";
unknown's avatar
unknown committed
2198 2199
      else if (select_lex->select_limit && select_lex->select_limit !=
	       HA_POS_ERROR)
unknown's avatar
unknown committed
2200
	msg= "LIMIT";
unknown's avatar
unknown committed
2201
      if (msg)
2202
      {
2203
	net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg);
unknown's avatar
unknown committed
2204 2205
	res= 1;
	break;
2206
      }
unknown's avatar
unknown committed
2207 2208 2209 2210 2211
      res= mysql_multi_update(thd,tables,
			      &select_lex->item_list,
			      &lex->value_list,
			      select_lex->where,
			      select_lex->options,
unknown's avatar
unknown committed
2212
			      lex->duplicates, unit, select_lex);
2213
    }
unknown's avatar
unknown committed
2214 2215
    break;
  case SQLCOM_REPLACE:
2216 2217
  case SQLCOM_INSERT:
  {
2218
    my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
2219
    ulong privilege= (lex->duplicates == DUP_REPLACE ?
2220
                      INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
2221
    if (check_access(thd,privilege,tables->db,&tables->grant.privilege))
unknown's avatar
unknown committed
2222
      goto error; /* purecov: inspected */
2223
    if (grant_option && check_grant(thd,privilege,tables))
unknown's avatar
unknown committed
2224
      goto error;
2225 2226 2227 2228 2229
    if (select_lex->item_list.elements != lex->value_list.elements)
    {
      send_error(thd,ER_WRONG_VALUE_COUNT);
      DBUG_VOID_RETURN;
    }
unknown's avatar
unknown committed
2230
    res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
2231
                       select_lex->item_list, lex->value_list,
unknown's avatar
unknown committed
2232
                       (update ? DUP_UPDATE : lex->duplicates));
unknown's avatar
unknown committed
2233 2234
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2235
    break;
2236
  }
unknown's avatar
unknown committed
2237 2238 2239
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
2240

unknown's avatar
unknown committed
2241 2242 2243 2244
    /*
      Check that we have modify privileges for the first table and
      select privileges for the rest
    */
2245
    {
2246 2247
      ulong privilege= (lex->duplicates == DUP_REPLACE ?
                        INSERT_ACL | DELETE_ACL : INSERT_ACL);
2248 2249 2250 2251 2252 2253 2254 2255 2256 2257
      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;
    }
unknown's avatar
unknown committed
2258 2259

    select_result *result;
2260 2261 2262 2263
    unit->offset_limit_cnt= select_lex->offset_limit;
    unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit;
    if (unit->select_limit_cnt < select_lex->select_limit)
      unit->select_limit_cnt= HA_POS_ERROR;		// No limit
unknown's avatar
unknown committed
2264

2265
    if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
2266
    {
unknown's avatar
unknown committed
2267 2268
      net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
      DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2269
    }
2270 2271 2272 2273 2274 2275 2276

    /* 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,
2277
				    lex->duplicates)))
2278
	res=handle_select(thd,lex,result);
unknown's avatar
unknown committed
2279 2280
      if (thd->net.report_error)
	res= -1;
2281 2282 2283
    }
    else
      res= -1;
unknown's avatar
unknown committed
2284 2285
    break;
  }
2286
  case SQLCOM_TRUNCATE:
2287 2288 2289 2290 2291 2292 2293 2294
    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())
    {
2295
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
2296 2297 2298 2299
      goto error;
    }
    res=mysql_truncate(thd,tables);
    break;
unknown's avatar
unknown committed
2300
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
2301 2302 2303 2304 2305 2306 2307
  {
    if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
      goto error; /* purecov: inspected */
    if (grant_option && check_grant(thd,DELETE_ACL,tables))
      goto error;
    // Set privilege for the WHERE clause
    tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
2308 2309
    res = mysql_delete(thd,tables, select_lex->where,
                       (ORDER*) select_lex->order_list.first,
unknown's avatar
unknown committed
2310
                       select_lex->select_limit, select_lex->options);
unknown's avatar
unknown committed
2311 2312
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2313 2314
    break;
  }
2315
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
2316 2317 2318 2319 2320
  {
    TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first;
    TABLE_LIST *auxi;
    uint table_count=0;
    multi_delete *result;
unknown's avatar
unknown committed
2321

unknown's avatar
unknown committed
2322 2323
    /* sql_yacc guarantees that tables and aux_tables are not zero */
    if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
2324
	check_table_access(thd,SELECT_ACL, tables) ||
unknown's avatar
unknown committed
2325 2326 2327
	check_table_access(thd,DELETE_ACL, aux_tables))
      goto error;
    if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
2328
    {
2329
      send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
unknown's avatar
unknown committed
2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344
      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)
      {
2345
	net_printf(thd,ER_NONUNIQ_TABLE,auxi->real_name);
unknown's avatar
unknown committed
2346 2347
	goto error;
      }
unknown's avatar
unknown committed
2348
      walk->lock_type= auxi->lock_type;
2349
      auxi->table_list=  walk;		// Remember corresponding table
2350
    }
unknown's avatar
unknown committed
2351
    if (add_item_to_list(thd, new Item_null()))
2352
    {
unknown's avatar
unknown committed
2353
      res= -1;
2354
      break;
unknown's avatar
unknown committed
2355 2356 2357 2358 2359 2360
    }
    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)
2361
      auxi->table= auxi->table_list->table;
2362
    if (&lex->select_lex != lex->all_selects_list)
unknown's avatar
unknown committed
2363
    {
2364 2365 2366 2367 2368
      for (TABLE_LIST *t= select_lex->get_table_list();
	   t; t= t->next)
      {
	if (find_real_table_in_list(t->table_list->next, t->db, t->real_name))
	{
unknown's avatar
unknown committed
2369
	  my_error(ER_UPDATE_TABLE_USED, MYF(0), t->real_name);
2370 2371 2372 2373
	  res= -1;
	  break;
	}
      }
unknown's avatar
unknown committed
2374
    }
unknown's avatar
unknown committed
2375
    fix_tables_pointers(lex->all_selects_list);
2376 2377
    if (!thd->fatal_error && (result= new multi_delete(thd,aux_tables,
						       table_count)))
unknown's avatar
unknown committed
2378
    {
2379 2380
      res= mysql_select(thd,select_lex->get_table_list(),
			select_lex->item_list,
unknown's avatar
unknown committed
2381 2382 2383 2384 2385
			select_lex->where,
			(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
			(ORDER *)NULL,
			select_lex->options | thd->options |
			SELECT_NO_JOIN_CACHE,
unknown's avatar
unknown committed
2386
			result, unit, select_lex, 0);
unknown's avatar
unknown committed
2387 2388
      if (thd->net.report_error)
	res= -1;
2389
      delete result;
unknown's avatar
unknown committed
2390 2391 2392 2393 2394 2395
    }
    else
      res= -1;					// Error is not sent
    close_thread_tables(thd);
    break;
  }
unknown's avatar
unknown committed
2396
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
2397
  {
2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408
    if (!lex->drop_temporary)
    {
      if (check_table_access(thd,DROP_ACL,tables))
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
    res= mysql_rm_table(thd,tables,lex->drop_if_exists, lex->drop_temporary);
unknown's avatar
unknown committed
2409 2410
  }
  break;
unknown's avatar
unknown committed
2411 2412 2413 2414 2415 2416 2417
  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;
2418 2419 2420 2421
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_drop_index(thd, tables, lex->drop_list);
unknown's avatar
unknown committed
2422 2423
    break;
  case SQLCOM_SHOW_DATABASES:
2424
#if defined(DONT_ALLOW_SHOW_COMMANDS)
2425
    send_error(thd,ER_NOT_ALLOWED_COMMAND);   /* purecov: inspected */
unknown's avatar
unknown committed
2426 2427 2428
    DBUG_VOID_RETURN;
#else
    if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
unknown's avatar
unknown committed
2429
	check_global_access(thd, SHOW_DB_ACL))
unknown's avatar
unknown committed
2430 2431 2432 2433 2434
      goto error;
    res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
    break;
#endif
  case SQLCOM_SHOW_PROCESSLIST:
unknown's avatar
unknown committed
2435
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
2436 2437 2438 2439
      break;
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
			  thd->priv_user,lex->verbose);
    break;
unknown's avatar
unknown committed
2440 2441 2442 2443 2444 2445 2446 2447 2448
  case SQLCOM_SHOW_TABLE_TYPES:
    res= mysqld_show_table_types(thd);
    break;
  case SQLCOM_SHOW_PRIVILEGES:
    res= mysqld_show_privileges(thd);
    break;
  case SQLCOM_SHOW_COLUMN_TYPES:
    res= mysqld_show_column_types(thd);
    break;
unknown's avatar
unknown committed
2449
  case SQLCOM_SHOW_STATUS:
2450
    res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
unknown's avatar
unknown committed
2451
		     OPT_GLOBAL);
unknown's avatar
unknown committed
2452 2453 2454
    break;
  case SQLCOM_SHOW_VARIABLES:
    res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
unknown's avatar
unknown committed
2455
		     init_vars, lex->option_type);
unknown's avatar
unknown committed
2456
    break;
unknown's avatar
unknown committed
2457 2458
  case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2459
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
2460 2461 2462 2463 2464 2465 2466 2467 2468
    DBUG_VOID_RETURN;
#else
    {
      if (grant_option && check_access(thd, FILE_ACL, any_db))
	goto error;
      res= mysqld_show_logs(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
2469
  case SQLCOM_SHOW_TABLES:
2470
    /* FALL THROUGH */
unknown's avatar
unknown committed
2471
#ifdef DONT_ALLOW_SHOW_COMMANDS
2472
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
2473 2474 2475
    DBUG_VOID_RETURN;
#else
    {
2476
      char *db=select_lex->db ? select_lex->db : thd->db;
unknown's avatar
unknown committed
2477 2478
      if (!db)
      {
2479
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
unknown's avatar
unknown committed
2480 2481 2482
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);				// Fix escaped '_'
2483
      if (check_db_name(db))
unknown's avatar
unknown committed
2484
      {
2485
        net_printf(thd,ER_WRONG_DB_NAME, db);
2486
        goto error;
unknown's avatar
unknown committed
2487 2488 2489 2490
      }
      if (check_access(thd,SELECT_ACL,db,&thd->col_access))
	goto error;				/* purecov: inspected */
      /* grant is checked in mysqld_show_tables */
2491
      if (select_lex->options & SELECT_DESCRIBE)
2492
        res= mysqld_extend_show_tables(thd,db,
2493
				       (lex->wild ? lex->wild->ptr() : NullS));
unknown's avatar
unknown committed
2494 2495 2496 2497 2498 2499
      else
	res= mysqld_show_tables(thd,db,
				(lex->wild ? lex->wild->ptr() : NullS));
      break;
    }
#endif
2500 2501 2502
  case SQLCOM_SHOW_OPEN_TABLES:
    res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
    break;
2503 2504
  case SQLCOM_SHOW_CHARSETS:
    res= mysqld_show_charsets(thd,(lex->wild ? lex->wild->ptr() : NullS));
2505
    break;
unknown's avatar
unknown committed
2506 2507
  case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2508
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
2509 2510 2511
    DBUG_VOID_RETURN;
#else
    {
2512 2513
      char *db=tables->db;
      if (!*db)
unknown's avatar
unknown committed
2514
      {
2515
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
unknown's avatar
unknown committed
2516 2517 2518
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);			// Fix escaped '_'
2519
      remove_escape(tables->real_name);
unknown's avatar
unknown committed
2520 2521 2522 2523 2524 2525
      if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access))
	goto error;				/* purecov: inspected */
      tables->grant.privilege=thd->col_access;
      if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
	goto error;
      res= mysqld_show_fields(thd,tables,
unknown's avatar
unknown committed
2526 2527
			      (lex->wild ? lex->wild->ptr() : NullS),
			      lex->verbose);
unknown's avatar
unknown committed
2528 2529 2530 2531 2532
      break;
    }
#endif
  case SQLCOM_SHOW_KEYS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
2533
    send_error(thd,ER_NOT_ALLOWED_COMMAND);	/* purecov: inspected */
unknown's avatar
unknown committed
2534 2535 2536
    DBUG_VOID_RETURN;
#else
    {
2537
      char *db=tables->db;
unknown's avatar
unknown committed
2538 2539
      if (!db)
      {
2540
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: inspected */
unknown's avatar
unknown committed
2541 2542 2543
	goto error;				/* purecov: inspected */
      }
      remove_escape(db);			// Fix escaped '_'
2544
      remove_escape(tables->real_name);
unknown's avatar
unknown committed
2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556
      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:
2557
    mysql_change_db(thd,select_lex->db);
unknown's avatar
unknown committed
2558
    break;
2559
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2560 2561 2562
  case SQLCOM_LOAD:
  {
    uint privilege= (lex->duplicates == DUP_REPLACE ?
2563
		     INSERT_ACL | DELETE_ACL : INSERT_ACL);
2564 2565

    if (!lex->local_file)
unknown's avatar
unknown committed
2566 2567 2568 2569 2570 2571
    {
      if (check_access(thd,privilege | FILE_ACL,tables->db))
	goto error;
    }
    else
    {
2572
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
unknown's avatar
unknown committed
2573
	  ! opt_local_infile)
2574
      {
2575
	send_error(thd,ER_NOT_ALLOWED_COMMAND);
2576 2577
	goto error;
      }
unknown's avatar
unknown committed
2578
      if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
2579
	  grant_option && check_grant(thd,privilege,tables))
unknown's avatar
unknown committed
2580 2581 2582 2583 2584 2585
	goto error;
    }
    res=mysql_load(thd, lex->exchange, tables, lex->field_list,
		   lex->duplicates, (bool) lex->local_file, lex->lock_option);
    break;
  }
2586
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2587
  case SQLCOM_SET_OPTION:
unknown's avatar
unknown committed
2588 2589 2590 2591 2592
    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)))
2593
      send_ok(thd);
unknown's avatar
unknown committed
2594 2595
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2596
    break;
unknown's avatar
unknown committed
2597

unknown's avatar
unknown committed
2598
  case SQLCOM_UNLOCK_TABLES:
unknown's avatar
unknown committed
2599
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
2600 2601
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
2602
      end_active_trans(thd);
unknown's avatar
unknown committed
2603
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
2604 2605
    }
    if (thd->global_read_lock)
2606
      unlock_global_read_lock(thd);
2607
    send_ok(thd);
unknown's avatar
unknown committed
2608 2609
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
2610
    unlock_locked_tables(thd);
2611
    if (check_db_used(thd,tables) || end_active_trans(thd))
unknown's avatar
unknown committed
2612
      goto error;
unknown's avatar
unknown committed
2613
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables))
2614
      goto error;
unknown's avatar
unknown committed
2615
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
2616
    thd->options|= OPTION_TABLE_LOCK;
unknown's avatar
unknown committed
2617 2618 2619 2620
    if (!(res=open_and_lock_tables(thd,tables)))
    {
      thd->locked_tables=thd->lock;
      thd->lock=0;
2621
      send_ok(thd);
unknown's avatar
unknown committed
2622
    }
unknown's avatar
unknown committed
2623 2624
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
2625 2626 2627
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
2628
  {
unknown's avatar
unknown committed
2629
    if (!strip_sp(lex->name) || check_db_name(lex->name))
unknown's avatar
unknown committed
2630
    {
2631
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
2632 2633
      break;
    }
2634
    if (lower_case_table_names)
2635
      my_casedn_str(files_charset_info, lex->name);
2636 2637
    if (check_access(thd,CREATE_ACL,lex->name,0,1))
      break;
2638
    res=mysql_create_db(thd,lex->name,&lex->create_info,0);
2639 2640
    break;
  }
unknown's avatar
unknown committed
2641
  case SQLCOM_DROP_DB:
2642
  {
unknown's avatar
unknown committed
2643
    if (!strip_sp(lex->name) || check_db_name(lex->name))
unknown's avatar
unknown committed
2644
    {
2645
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
2646 2647
      break;
    }
2648
    if (lower_case_table_names)
2649
      my_casedn_str(files_charset_info, lex->name);
2650
    if (check_access(thd,DROP_ACL,lex->name,0,1))
2651
      break;
2652 2653
    if (thd->locked_tables || thd->active_transaction())
    {
2654
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
2655 2656
      goto error;
    }
unknown's avatar
unknown committed
2657
    res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0);
2658 2659
    break;
  }
2660 2661 2662 2663
  case SQLCOM_ALTER_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
2664
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
2665 2666
      break;
    }
unknown's avatar
unknown committed
2667
    if (check_access(thd,ALTER_ACL,lex->name,0,1))
2668 2669 2670
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
2671
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
2672 2673
      goto error;
    }
2674
    res=mysql_alter_db(thd,lex->name,&lex->create_info);
2675 2676
    break;
  }
unknown's avatar
unknown committed
2677 2678 2679 2680
  case SQLCOM_SHOW_CREATE_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
2681
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
2682 2683 2684 2685 2686 2687
      break;
    }
    if (check_access(thd,DROP_ACL,lex->name,0,1))
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
2688
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
2689 2690
      goto error;
    }
unknown's avatar
unknown committed
2691
    res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
unknown's avatar
unknown committed
2692 2693
    break;
  }
unknown's avatar
unknown committed
2694 2695 2696 2697 2698
  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)))
2699
      send_ok(thd);
unknown's avatar
unknown committed
2700 2701 2702 2703 2704 2705 2706 2707 2708
#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)))
2709
      send_ok(thd);
unknown's avatar
unknown committed
2710 2711 2712 2713
#else
    res= -1;
#endif
    break;
2714 2715 2716 2717 2718 2719 2720 2721 2722
  case SQLCOM_REVOKE:
  case SQLCOM_GRANT:
  {
    if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
		     tables && tables->db ? tables->db : select_lex->db,
		     tables ? &tables->grant.privilege : 0,
		     tables ? 0 : 1))
      goto error;

unknown's avatar
unknown committed
2723 2724 2725 2726
    /*
      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
    */
2727 2728 2729 2730 2731 2732 2733 2734 2735 2736

    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 &&
2737
	     my_strcasecmp(my_charset_latin1,
2738
                           user->host.str, thd->host_or_ip)))
2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752
	{
	  if (check_access(thd, UPDATE_ACL, "mysql",0,1))
	    goto error;
	  break;			// We are allowed to do changes
	}
      }
    }
    if (tables)
    {
      if (grant_option && check_grant(thd,
				      (lex->grant | lex->grant_tot_col |
				       GRANT_ACL),
				      tables))
	goto error;
unknown's avatar
unknown committed
2753 2754 2755
      if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
				    lex->grant,
				    lex->sql_command == SQLCOM_REVOKE)))
2756
      {
2757
	mysql_update_log.write(thd, thd->query, thd->query_length);
2758 2759
	if (mysql_bin_log.is_open())
	{
2760
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
2761 2762 2763 2764 2765 2766 2767 2768
	  mysql_bin_log.write(&qinfo);
	}
      }
    }
    else
    {
      if (lex->columns.elements)
      {
2769
	send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE);
2770 2771 2772 2773 2774 2775 2776
	res=1;
      }
      else
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
2777
	mysql_update_log.write(thd, thd->query, thd->query_length);
2778 2779
	if (mysql_bin_log.is_open())
	{
2780
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
2781 2782
	  mysql_bin_log.write(&qinfo);
	}
2783
	if (mqh_used && lex->sql_command == SQLCOM_GRANT)
2784
	{
unknown's avatar
unknown committed
2785 2786 2787
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
2788
	    reset_mqh(thd,user);
2789
	}
2790 2791 2792 2793
      }
    }
    break;
  }
unknown's avatar
unknown committed
2794
  case SQLCOM_FLUSH:
unknown's avatar
unknown committed
2795
  case SQLCOM_RESET:
unknown's avatar
unknown committed
2796
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
unknown's avatar
unknown committed
2797
      goto error;
2798 2799
    /* error sending is deferred to reload_acl_and_cache */
    reload_acl_and_cache(thd, lex->type, tables) ;
unknown's avatar
unknown committed
2800 2801 2802 2803 2804 2805
    break;
  case SQLCOM_KILL:
    kill_one_thread(thd,lex->thread_id);
    break;
  case SQLCOM_SHOW_GRANTS:
    res=0;
2806 2807
    if ((thd->priv_user &&
	 !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
2808
	!check_access(thd, SELECT_ACL, "mysql",0,1))
unknown's avatar
unknown committed
2809 2810 2811 2812
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
2813
  case SQLCOM_HA_OPEN:
2814 2815
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables))
2816 2817 2818 2819 2820 2821 2822 2823 2824
      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:
2825 2826
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables))
2827
      goto error;
unknown's avatar
unknown committed
2828
    res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
2829 2830
			lex->insert_list, lex->ha_rkey_mode, select_lex->where,
			select_lex->select_limit, select_lex->offset_limit);
2831 2832
    break;

unknown's avatar
unknown committed
2833
  case SQLCOM_BEGIN:
unknown's avatar
unknown committed
2834 2835 2836 2837 2838 2839
    if (thd->locked_tables)
    {
      thd->lock=thd->locked_tables;
      thd->locked_tables=0;			// Will be automaticly closed
      close_thread_tables(thd);			// Free tables
    }
unknown's avatar
unknown committed
2840 2841 2842 2843 2844 2845
    if (end_active_trans(thd))
    {
      res= -1;
    }
    else
    {
2846
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
unknown's avatar
unknown committed
2847 2848
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
2849
      send_ok(thd);
unknown's avatar
unknown committed
2850
    }
unknown's avatar
unknown committed
2851 2852
    break;
  case SQLCOM_COMMIT:
2853 2854 2855 2856 2857
    /*
      We don't use end_active_trans() here to ensure that this works
      even if there is a problem with the OPTION_AUTO_COMMIT flag
      (Which of course should never happen...)
    */
unknown's avatar
unknown committed
2858
  {
2859
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
2860 2861
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
unknown's avatar
unknown committed
2862
    {
2863
      send_ok(thd);
unknown's avatar
unknown committed
2864
    }
unknown's avatar
unknown committed
2865 2866 2867
    else
      res= -1;
    break;
unknown's avatar
unknown committed
2868
  }
unknown's avatar
unknown committed
2869 2870 2871
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
2872 2873
    {
      if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
2874
	send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
2875
      else
2876
	send_ok(thd);
2877
    }
unknown's avatar
unknown committed
2878 2879
    else
      res= -1;
2880
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
2881 2882
    break;
  default:					/* Impossible */
2883
    send_ok(thd);
unknown's avatar
unknown committed
2884 2885 2886 2887
    break;
  }
  thd->proc_info="query end";			// QQ
  if (res < 0)
2888
    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
unknown's avatar
unknown committed
2889 2890 2891 2892 2893 2894 2895

error:
  DBUG_VOID_RETURN;
}


/****************************************************************************
unknown's avatar
unknown committed
2896 2897 2898 2899 2900 2901 2902
  Get the user (global) and database privileges for all used tables
  Returns true (error) if we can't get the privileges and we don't use
  table/column grants.
  The idea of EXTRA_ACL is that one will be granted access to the table if
  one has the asked privilege on any column combination of the table; For
  example to be able to check a table one needs to have SELECT privilege on
  any column of the table.
unknown's avatar
unknown committed
2903 2904 2905
****************************************************************************/

bool
unknown's avatar
unknown committed
2906
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
2907
	     bool dont_check_global_grants, bool no_errors)
unknown's avatar
unknown committed
2908
{
unknown's avatar
unknown committed
2909 2910 2911 2912
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("want_access: %lu  master_access: %lu", want_access,
		      thd->master_access));
  ulong db_access,dummy;
unknown's avatar
unknown committed
2913 2914 2915 2916 2917
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

2918
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
2919
  {
2920
    if (!no_errors)
2921
      send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
unknown's avatar
unknown committed
2922
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
2923 2924 2925 2926 2927
  }

  if ((thd->master_access & want_access) == want_access)
  {
    *save_priv=thd->master_access;
unknown's avatar
unknown committed
2928
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
2929
  }
2930
  if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
2931
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
2932
  {						// We can never grant this
2933
    if (!no_errors)
2934
      net_printf(thd,ER_ACCESS_DENIED_ERROR,
2935 2936 2937
		 thd->priv_user,
		 thd->host_or_ip,
		 thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
unknown's avatar
unknown committed
2938
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
2939 2940 2941
  }

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

unknown's avatar
unknown committed
2944 2945 2946 2947 2948
  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;
2949 2950
  // Remove SHOW attribute and access rights we already have
  want_access &= ~(thd->master_access | EXTRA_ACL);
unknown's avatar
unknown committed
2951
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
2952 2953

  /* grant_option is set if there exists a single table or column grant */
unknown's avatar
unknown committed
2954
  if (db_access == want_access ||
2955 2956
      ((grant_option && !dont_check_global_grants) &&
       !(want_access & ~TABLE_ACLS)))
unknown's avatar
unknown committed
2957
    DBUG_RETURN(FALSE);				/* Ok */
2958
  if (!no_errors)
2959
    net_printf(thd,ER_DBACCESS_DENIED_ERROR,
2960 2961 2962
	       thd->priv_user,
	       thd->host_or_ip,
	       db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
unknown's avatar
unknown committed
2963
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
2964 2965 2966
}


unknown's avatar
unknown committed
2967 2968 2969
/* check for global access and give descriptive error message if it fails */

bool check_global_access(THD *thd, ulong want_access)
unknown's avatar
unknown committed
2970
{
unknown's avatar
unknown committed
2971 2972 2973 2974
  char command[128];
  if ((thd->master_access & want_access) == want_access)
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
2975
  net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
unknown's avatar
unknown committed
2976 2977
	     command);
  return 1;
unknown's avatar
unknown committed
2978 2979 2980
}


unknown's avatar
unknown committed
2981
/*
unknown's avatar
unknown committed
2982 2983
  Check the privilege for all used tables.  Table privileges are cached
  in the table list for GRANT checking
unknown's avatar
unknown committed
2984 2985
*/

2986
bool
unknown's avatar
unknown committed
2987
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
2988
		   bool no_errors)
unknown's avatar
unknown committed
2989
{
unknown's avatar
unknown committed
2990 2991
  uint found=0;
  ulong found_access=0;
unknown's avatar
unknown committed
2992 2993 2994
  TABLE_LIST *org_tables=tables;
  for (; tables ; tables=tables->next)
  {
2995
    if (tables->derived || (tables->table && (int)tables->table->tmp_table))
unknown's avatar
unknown committed
2996
      continue;
unknown's avatar
unknown committed
2997 2998
    if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
	thd->db)
unknown's avatar
unknown committed
2999
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
3000
    else if (tables->db && tables->db == thd->db)
unknown's avatar
unknown committed
3001 3002 3003 3004 3005
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
3006 3007
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
			 0, no_errors))
unknown's avatar
unknown committed
3008 3009
	  return TRUE;				// Access denied
	found_access=tables->grant.privilege;
unknown's avatar
unknown committed
3010
	found=1;
unknown's avatar
unknown committed
3011 3012
      }
    }
3013
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
3014
			  0, no_errors))
3015
      return TRUE;
unknown's avatar
unknown committed
3016 3017
  }
  if (grant_option)
3018
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
3019
		       test(want_access & EXTRA_ACL), no_errors);
unknown's avatar
unknown committed
3020 3021 3022 3023
  return FALSE;
}


unknown's avatar
unknown committed
3024
static bool check_db_used(THD *thd,TABLE_LIST *tables)
unknown's avatar
unknown committed
3025 3026 3027 3028 3029 3030 3031
{
  for (; tables ; tables=tables->next)
  {
    if (!tables->db)
    {
      if (!(tables->db=thd->db))
      {
3032
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
unknown's avatar
unknown committed
3033 3034 3035 3036 3037 3038 3039 3040
	return TRUE;				/* purecov: tested */
      }
    }
  }
  return FALSE;
}


3041 3042
static bool check_merge_table_access(THD *thd, char *db,
				     TABLE_LIST *table_list)
3043 3044 3045 3046
{
  int error=0;
  if (table_list)
  {
3047
    /* Check that all tables use the current database */
3048 3049
    TABLE_LIST *tmp;
    for (tmp=table_list; tmp ; tmp=tmp->next)
3050 3051 3052
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
unknown's avatar
unknown committed
3053
      else if (strcmp(tmp->db,db))
3054
      {
3055
	send_error(thd,ER_UNION_TABLES_IN_DIFFERENT_DIR);
3056 3057 3058
	return 1;
      }
    }
3059 3060 3061 3062 3063 3064 3065
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
			     table_list);
  }
  return error;
}


unknown's avatar
unknown committed
3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122
/****************************************************************************
	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;
}


/****************************************************************************
3123
	Initialize global thd variables needed for query
unknown's avatar
unknown committed
3124 3125
****************************************************************************/

3126
void
unknown's avatar
unknown committed
3127 3128 3129
mysql_init_query(THD *thd)
{
  DBUG_ENTER("mysql_init_query");
3130 3131 3132 3133 3134 3135
  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();
unknown's avatar
unknown committed
3136 3137
  lex->unit.next= lex->unit.master= lex->unit.link_next= 0;
  lex->unit.prev= lex->unit.link_prev= 0;
unknown's avatar
unknown committed
3138
  lex->unit.global_parameters= lex->unit.slave= lex->current_select=
3139
    lex->all_selects_list= &lex->select_lex;
3140 3141
  lex->select_lex.master= &lex->unit;
  lex->select_lex.prev= &lex->unit.slave;
unknown's avatar
unknown committed
3142
  lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
3143
  lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
3144 3145
  lex->olap=lex->describe=0;
  lex->derived_tables= false;
3146
  lex->lock_option=TL_READ;
3147
  lex->found_colon=0;
unknown's avatar
unknown committed
3148
  thd->check_loops_counter= thd->select_number=
unknown's avatar
unknown committed
3149
    lex->select_lex.select_number= 1;
unknown's avatar
unknown committed
3150
  thd->free_list= 0;
3151
  thd->total_warn_count=0;			// Warnings for this query
unknown's avatar
unknown committed
3152 3153
  thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
  thd->sent_row_count= thd->examined_row_count= 0;
unknown's avatar
unknown committed
3154
  thd->fatal_error= thd->rand_used= 0;
3155
  thd->possible_loops= 0;
3156
  thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
unknown's avatar
unknown committed
3157 3158 3159
  DBUG_VOID_RETURN;
}

3160

3161 3162 3163
void
mysql_init_select(LEX *lex)
{
unknown's avatar
unknown committed
3164
  SELECT_LEX *select_lex= lex->current_select->select_lex();
unknown's avatar
unknown committed
3165
  select_lex->init_select();
unknown's avatar
unknown committed
3166
  select_lex->master_unit()->select_limit= select_lex->select_limit=
unknown's avatar
unknown committed
3167
    lex->thd->variables.select_limit;
3168 3169 3170 3171 3172 3173
  if (select_lex == &lex->select_lex)
  {
    lex->exchange= 0;
    lex->result= 0;
    lex->proc_list.first= 0;
  }
3174 3175
}

3176

unknown's avatar
unknown committed
3177
bool
unknown's avatar
unknown committed
3178
mysql_new_select(LEX *lex, bool move_down)
3179
{
3180
  SELECT_LEX *select_lex = new SELECT_LEX();
unknown's avatar
unknown committed
3181
  select_lex->select_number= ++lex->thd->select_number;
unknown's avatar
unknown committed
3182 3183
  if (!select_lex)
    return 1;
unknown's avatar
unknown committed
3184 3185 3186 3187 3188
  select_lex->init_query();
  select_lex->init_select();
  if (move_down)
  {
    /* first select_lex of subselect or derived table */
3189
    SELECT_LEX_UNIT *unit= new SELECT_LEX_UNIT();
unknown's avatar
unknown committed
3190 3191 3192 3193
    if (!unit)
      return 1;
    unit->init_query();
    unit->init_select();
3194
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
3195 3196
    unit->link_next= 0;
    unit->link_prev= 0;
unknown's avatar
unknown committed
3197 3198 3199
    select_lex->include_down(unit);
  }
  else
3200
    select_lex->include_neighbour(lex->current_select);
unknown's avatar
unknown committed
3201

3202
  select_lex->master_unit()->global_parameters= select_lex;
3203
  DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE);
3204
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
3205
  lex->current_select= select_lex;
unknown's avatar
unknown committed
3206
  return 0;
3207
}
unknown's avatar
unknown committed
3208

3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231
/*
  Create a select to return the same output as 'SELECT @@var_name'.

  SYNOPSIS
    create_select_for_variable()
    var_name		Variable name

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

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

void create_select_for_variable(const char *var_name)
{
  LEX *lex;
  LEX_STRING tmp;
  DBUG_ENTER("create_select_for_variable");
  lex= current_lex;
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
unknown's avatar
unknown committed
3232
  add_item_to_list(lex->thd, get_system_var(OPT_SESSION, tmp));
3233 3234 3235
  DBUG_VOID_RETURN;
}

3236

unknown's avatar
unknown committed
3237 3238
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
3239
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
3240
  mysql_init_select(lex);
3241
  lex->select_lex.select_limit= lex->unit.select_limit_cnt=
unknown's avatar
unknown committed
3242
    HA_POS_ERROR;
unknown's avatar
unknown committed
3243
  lex->auxilliary_table_list= lex->select_lex.table_list;
3244
  lex->select_lex.init_query();
unknown's avatar
unknown committed
3245
}
unknown's avatar
unknown committed
3246

3247

unknown's avatar
unknown committed
3248
void
unknown's avatar
unknown committed
3249
mysql_parse(THD *thd, char *inBuf, uint length)
unknown's avatar
unknown committed
3250 3251 3252 3253 3254
{
  DBUG_ENTER("mysql_parse");

  mysql_init_query(thd);
  thd->query_length = length;
unknown's avatar
unknown committed
3255 3256
  thd->net.report_error= 0;

unknown's avatar
unknown committed
3257
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
unknown's avatar
unknown committed
3258 3259
  {
    LEX *lex=lex_start(thd, (uchar*) inBuf, length);
3260
    if (!yyparse((void *)thd) && ! thd->fatal_error)
unknown's avatar
unknown committed
3261
    {
3262
      if (mqh_used && thd->user_connect &&
3263
	  check_mqh(thd, lex->sql_command))
3264 3265 3266 3267 3268
      {
	thd->net.error = 0;
      }
      else
      {
unknown's avatar
unknown committed
3269 3270 3271 3272 3273
	if (thd->net.report_error)
	  send_error(thd, 0, NullS);
	else
	{
	  mysql_execute_command(thd);
unknown's avatar
SCRUM  
unknown committed
3274
#ifndef EMBEDDED_LIBRARY  /* TODO query cache in embedded library*/
unknown's avatar
unknown committed
3275
	  query_cache_end_of_result(&thd->net);
3276
#endif
unknown's avatar
unknown committed
3277
	}
3278
      }
unknown's avatar
unknown committed
3279 3280
    }
    else
3281 3282 3283
    {
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
			 thd->fatal_error));
unknown's avatar
SCRUM  
unknown committed
3284
#ifndef EMBEDDED_LIBRARY   /* TODO query cache in embedded library*/
unknown's avatar
unknown committed
3285
      query_cache_abort(&thd->net);
3286
#endif
3287
    }
unknown's avatar
unknown committed
3288
    thd->proc_info="freeing items";
3289
    free_items(thd->free_list);  /* Free strings used by items */
unknown's avatar
unknown committed
3290 3291
    lex_end(lex);
  }
unknown's avatar
unknown committed
3292 3293 3294 3295 3296 3297 3298 3299 3300
  DBUG_VOID_RETURN;
}


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

unknown's avatar
unknown committed
3301
bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
unknown's avatar
unknown committed
3302
		       char *length, char *decimals,
3303 3304
		       uint type_modifier,
		       Item *default_value, Item *comment,
3305
		       char *change, TYPELIB *interval, CHARSET_INFO *cs)
unknown's avatar
unknown committed
3306 3307 3308 3309
{
  register create_field *new_field;
  LEX  *lex= &thd->lex;
  uint allowed_type_modifier=0;
3310
  char warn_buff[MYSQL_ERRMSG_SIZE];
unknown's avatar
unknown committed
3311 3312 3313 3314
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
3315
    net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
unknown's avatar
unknown committed
3316 3317 3318 3319 3320
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
3321
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
unknown's avatar
unknown committed
3322 3323 3324 3325 3326 3327
				    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));
3328
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF,
unknown's avatar
unknown committed
3329 3330 3331 3332 3333 3334 3335 3336 3337
				    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)
    {
3338
      net_printf(thd,ER_INVALID_DEFAULT,field_name);
unknown's avatar
unknown committed
3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357
      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;
3358
  new_field->charset=cs;
unknown's avatar
unknown committed
3359

3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370
  if (!comment)
  {
    new_field->comment.str=0;
    new_field->comment.length=0;
  }
  else
  {
    /* In this case comment is always of type Item_string */
    new_field->comment.str=   (char*) comment->str_value.ptr();
    new_field->comment.length=comment->str_value.length();
  }
unknown's avatar
unknown committed
3371 3372 3373 3374 3375 3376
  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 &&
3377
      new_field->length < new_field->decimals+1 &&
unknown's avatar
unknown committed
3378
      new_field->decimals != NOT_FIXED_DEC)
3379
    new_field->length=new_field->decimals+1; /* purecov: inspected */
unknown's avatar
unknown committed
3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410

  switch (type) {
  case FIELD_TYPE_TINY:
    if (!length) new_field->length=3+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_SHORT:
    if (!length) new_field->length=5+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_INT24:
    if (!length) new_field->length=8+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONG:
    if (!length) new_field->length=10+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_LONGLONG:
    if (!length) new_field->length=20;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case FIELD_TYPE_NULL:
    break;
  case FIELD_TYPE_DECIMAL:
    if (!length)
      new_field->length = 10;			// Default length for DECIMAL
    new_field->length+=sign_len;
    if (new_field->decimals)
      new_field->length++;
    break;
3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421
  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 */
unknown's avatar
unknown committed
3422 3423 3424 3425
  case FIELD_TYPE_BLOB:
  case FIELD_TYPE_TINY_BLOB:
  case FIELD_TYPE_LONG_BLOB:
  case FIELD_TYPE_MEDIUM_BLOB:
unknown's avatar
unknown committed
3426
  case FIELD_TYPE_GEOMETRY:
3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440
    if (new_field->length)
    {
      /* The user has given a length to the blob column */
      if (new_field->length < 256)
	type= FIELD_TYPE_TINY_BLOB;
      if (new_field->length < 65536)
	type= FIELD_TYPE_BLOB;
      else if (new_field->length < 256L*256L*256L)
	type= FIELD_TYPE_MEDIUM_BLOB;
      else
	type= FIELD_TYPE_LONG_BLOB;
      new_field->length= 0;
    }
    new_field->sql_type= type;
unknown's avatar
unknown committed
3441 3442 3443 3444 3445 3446
    if (default_value)				// Allow empty as default value
    {
      String str,*res;
      res=default_value->val_str(&str);
      if (res->length())
      {
3447
	net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
unknown's avatar
unknown committed
3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466
	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)
      {
3467
	net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
unknown's avatar
unknown committed
3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520
	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)
      {
3521
	net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
unknown's avatar
unknown committed
3522 3523 3524 3525 3526 3527 3528 3529
	DBUG_RETURN(1);				/* purecov: inspected */
      }
      new_field->pack_length=(interval->count+7)/8;
      if (new_field->pack_length > 4)
	new_field->pack_length=8;
      new_field->interval=interval;
      new_field->length=0;
      for (const char **pos=interval->type_names; *pos ; pos++)
unknown's avatar
unknown committed
3530 3531 3532
      {
	new_field->length+=(uint) strip_sp((char*) *pos)+1;
      }
unknown's avatar
unknown committed
3533 3534 3535 3536
      new_field->length--;
      set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
      if (default_value)
      {
3537 3538 3539
	char *not_used;
	uint not_used2;

unknown's avatar
unknown committed
3540 3541 3542
	thd->cuted_fields=0;
	String str,*res;
	res=default_value->val_str(&str);
3543 3544
	(void) find_set(interval, res->ptr(), res->length(), &not_used,
			&not_used2);
unknown's avatar
unknown committed
3545 3546
	if (thd->cuted_fields)
	{
3547
	  net_printf(thd,ER_INVALID_DEFAULT,field_name);
unknown's avatar
unknown committed
3548 3549 3550 3551 3552 3553 3554 3555 3556
	  DBUG_RETURN(1);
	}
      }
    }
    break;
  case FIELD_TYPE_ENUM:
    {
      new_field->interval=interval;
      new_field->pack_length=interval->count < 256 ? 1 : 2; // Should be safe
unknown's avatar
unknown committed
3557
      new_field->length=(uint) strip_sp((char*) interval->type_names[0]);
unknown's avatar
unknown committed
3558 3559
      for (const char **pos=interval->type_names+1; *pos ; pos++)
      {
unknown's avatar
unknown committed
3560
	uint length=(uint) strip_sp((char*) *pos);
unknown's avatar
unknown committed
3561 3562 3563 3564 3565 3566 3567 3568 3569
	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()))
	{
3570
	  net_printf(thd,ER_INVALID_DEFAULT,field_name);
unknown's avatar
unknown committed
3571 3572 3573 3574 3575 3576 3577 3578 3579
	  DBUG_RETURN(1);
	}
      }
      break;
    }
  }

  if (new_field->length >= MAX_FIELD_WIDTH ||
      (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
unknown's avatar
SCRUM  
unknown committed
3580 3581
       type != FIELD_TYPE_STRING && 
       type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
unknown's avatar
unknown committed
3582
  {
3583
    net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
unknown's avatar
unknown committed
3584 3585 3586 3587 3588 3589
	       MAX_FIELD_WIDTH-1);		/* purecov: inspected */
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
3590
    net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
unknown's avatar
unknown committed
3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611
    DBUG_RETURN(1);
  }
  if (!new_field->pack_length)
    new_field->pack_length=calc_pack_length(new_field->sql_type ==
					    FIELD_TYPE_VAR_STRING ?
					    FIELD_TYPE_STRING :
					    new_field->sql_type,
					    new_field->length);
  lex->create_list.push_back(new_field);
  lex->last_field=new_field;
  DBUG_RETURN(0);
}

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

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

bool
unknown's avatar
unknown committed
3612
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
3613 3614 3615 3616
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
3617
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
3618 3619 3620 3621 3622
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
unknown's avatar
unknown committed
3623
  thd->lex.proc_list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
3624 3625 3626 3627 3628 3629 3630 3631
  return 0;
}


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

static void remove_escape(char *name)
{
3632 3633
  if (!*name)					// For empty DB names
    return;
unknown's avatar
unknown committed
3634 3635
  char *to;
#ifdef USE_MB
unknown's avatar
unknown committed
3636
  char *strend=name+(uint) strlen(name);
unknown's avatar
unknown committed
3637 3638 3639 3640 3641 3642
#endif
  for (to=name; *name ; name++)
  {
#ifdef USE_MB
    int l;
/*    if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
3643 3644
    if (use_mb(system_charset_info) &&
        (l = my_ismbchar(system_charset_info, name, strend)))
unknown's avatar
unknown committed
3645 3646 3647 3648 3649 3650 3651 3652
    {
	while (l--)
	    *to++ = *name++;
	name--;
	continue;
    }
#endif
    if (*name == '\\' && name[1])
unknown's avatar
unknown committed
3653
      name++;					// Skip '\\'
unknown's avatar
unknown committed
3654 3655 3656 3657 3658 3659 3660 3661 3662 3663
    *to++= *name;
  }
  *to=0;
}

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


unknown's avatar
unknown committed
3664
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
3665 3666 3667 3668
{
  ORDER *order;
  Item	**item_ptr;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
3669
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
3670 3671 3672 3673 3674 3675 3676
    DBUG_RETURN(1);
  item_ptr = (Item**) (order+1);
  *item_ptr=item;
  order->item= item_ptr;
  order->asc = asc;
  order->free_me=0;
  order->used=0;
unknown's avatar
unknown committed
3677
  list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
3678 3679 3680 3681
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700
/*
  Add a table to list of used tables

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

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

unknown's avatar
unknown committed
3701 3702
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
3703
					     LEX_STRING *alias,
unknown's avatar
unknown committed
3704 3705
					     ulong table_options,
					     thr_lock_type lock_type,
3706 3707
					     List<String> *use_index,
					     List<String> *ignore_index)
unknown's avatar
unknown committed
3708 3709 3710 3711 3712 3713 3714 3715 3716
{
  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 ||
unknown's avatar
unknown committed
3717 3718
      (table->table.length &&
       check_table_name(table->table.str,table->table.length)) ||
3719
      table->db.str && check_db_name(table->db.str))
unknown's avatar
unknown committed
3720
  {
3721
    net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str);
unknown's avatar
unknown committed
3722 3723 3724 3725
    DBUG_RETURN(0);
  }

  if (!alias)					/* Alias is case sensitive */
3726 3727 3728 3729 3730 3731
  {
    if (table->sel)
    {
      net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
      DBUG_RETURN(0);
    }
3732
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
3733
      DBUG_RETURN(0);
3734
  }
unknown's avatar
unknown committed
3735
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
3736
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
3737
  if (table->db.str)
3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748
  {
    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
  {
3749 3750
    /* The following can't be "" as we may do 'casedn_str()' on it */
    ptr->db= empty_c_string;
3751 3752
    ptr->db_length= 0;
  }
unknown's avatar
unknown committed
3753

3754
  ptr->alias= alias_str;
unknown's avatar
unknown committed
3755 3756
  if (lower_case_table_names)
  {
3757 3758
    my_casedn_str(files_charset_info,ptr->db);
    my_casedn_str(files_charset_info,table->table.str);
unknown's avatar
unknown committed
3759 3760
  }
  ptr->real_name=table->table.str;
3761
  ptr->real_name_length=table->table.length;
unknown's avatar
unknown committed
3762 3763 3764
  ptr->lock_type= lock_type;
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
3765
  ptr->derived= (SELECT_LEX_UNIT *) table->sel;
unknown's avatar
unknown committed
3766
  if (use_index)
unknown's avatar
unknown committed
3767
    ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
unknown's avatar
unknown committed
3768 3769
					       sizeof(*use_index));
  if (ignore_index)
unknown's avatar
unknown committed
3770 3771
    ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index,
						   sizeof(*ignore_index));
unknown's avatar
unknown committed
3772 3773

  /* check that used name is unique */
3774
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
3775
  {
3776
    for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
3777
	 tables ;
unknown's avatar
unknown committed
3778
	 tables=tables->next)
unknown's avatar
unknown committed
3779
    {
3780
      if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
3781
      {
3782
	net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
unknown's avatar
unknown committed
3783 3784
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
3785 3786
    }
  }
unknown's avatar
unknown committed
3787
  table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
unknown's avatar
unknown committed
3788 3789 3790
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
3791

unknown's avatar
unknown committed
3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804
/*
  Set lock for all tables in current select level

  SYNOPSIS:
    set_lock_for_tables()
    lock_type			Lock to set for tables

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

unknown's avatar
unknown committed
3805
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
3806 3807 3808 3809 3810 3811
{
  bool for_update= lock_type >= TL_READ_NO_INSERT;
  DBUG_ENTER("set_lock_for_tables");
  DBUG_PRINT("enter", ("lock_type: %d  for_update: %d", lock_type,
		       for_update));

unknown's avatar
unknown committed
3812
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
3813 3814 3815 3816 3817 3818 3819 3820 3821
       tables ;
       tables=tables->next)
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
3822

unknown's avatar
unknown committed
3823 3824
void add_join_on(TABLE_LIST *b,Item *expr)
{
3825
  if (expr)
3826
  {
3827 3828 3829 3830 3831 3832 3833 3834
    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();
3835
  }
unknown's avatar
unknown committed
3836 3837 3838 3839 3840 3841 3842 3843
}


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

3844 3845 3846 3847 3848

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

unknown's avatar
unknown committed
3849
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
unknown's avatar
unknown committed
3850 3851
{
  bool result=0;
3852
  bool error_already_sent=0;
unknown's avatar
unknown committed
3853 3854 3855
  select_errors=0;				/* Write if more errors */
  if (options & REFRESH_GRANT)
  {
3856
    acl_reload(thd);
unknown's avatar
unknown committed
3857
    grant_reload(thd);
3858
    if (mqh_used)
3859
      reset_mqh(thd,(LEX_USER *) NULL,true);
unknown's avatar
unknown committed
3860 3861 3862
  }
  if (options & REFRESH_LOG)
  {
unknown's avatar
unknown committed
3863 3864 3865 3866
    mysql_log.new_file(1);
    mysql_update_log.new_file(1);
    mysql_bin_log.new_file(1);
    mysql_slow_log.new_file(1);
unknown's avatar
unknown committed
3867 3868 3869
    if (ha_flush_logs())
      result=1;
  }
unknown's avatar
unknown committed
3870
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
3871 3872
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
3873
    query_cache.pack();				// FLUSH QUERY CACHE
unknown's avatar
unknown committed
3874 3875 3876 3877
    options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
3878
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
3879
  }
unknown's avatar
unknown committed
3880
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
3881 3882
  if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
  {
3883
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
3884
    {
3885 3886
      if (lock_global_read_lock(thd))
	return 1;
unknown's avatar
unknown committed
3887
    }
unknown's avatar
unknown committed
3888
    result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
unknown's avatar
unknown committed
3889 3890 3891 3892 3893 3894 3895
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
  if (options & REFRESH_STATUS)
    refresh_status();
  if (options & REFRESH_THREADS)
    flush_thread_cache();
3896
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
3897
  if (options & REFRESH_MASTER)
3898 3899
    if (reset_master(thd))
      result=1;
3900
#endif
unknown's avatar
unknown committed
3901
#ifdef OPENSSL
3902 3903 3904 3905 3906 3907
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
3908
#ifndef EMBEDDED_LIBRARY
3909 3910 3911
 if (options & REFRESH_SLAVE)
 {
   LOCK_ACTIVE_MI;
3912
   if (reset_slave(thd, active_mi))
3913
   {
3914
     result=1;
3915 3916 3917 3918 3919 3920 3921 3922
     /*
       reset_slave() sends error itself.
       If it didn't, one would either change reset_slave()'s prototype, to
       pass *errorcode and *errmsg to it when it's called or
       change reset_slave to use my_error() to register the error.
     */
     error_already_sent=1;
   }
3923 3924
   UNLOCK_ACTIVE_MI;
 }
3925
#endif
3926
 if (options & REFRESH_USER_RESOURCES)
3927
   reset_mqh(thd,(LEX_USER *) NULL);
3928 3929 3930 3931

 if (thd && !error_already_sent)
 {
   if (result)
3932
     send_error(thd,0);
3933
   else
3934
     send_ok(thd);
3935 3936
 }

3937
 return result;
unknown's avatar
unknown committed
3938 3939 3940
}


3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952
/*
  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
*/

3953
void kill_one_thread(THD *thd, ulong id)
unknown's avatar
unknown committed
3954 3955 3956
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
3957 3958
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
3959 3960 3961 3962
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
3963 3964
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
3965 3966 3967
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980
  if (tmp)
  {
    if ((thd->master_access & SUPER_ACL) ||
	!strcmp(thd->user,tmp->user))
    {
      tmp->awake(1 /*prepare to die*/);
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }

unknown's avatar
unknown committed
3981
  if (!error)
3982
    send_ok(thd);
unknown's avatar
unknown committed
3983
  else
3984
    net_printf(thd,error,id);
unknown's avatar
unknown committed
3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000
}

/* 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);
}
4001 4002 4003 4004


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

unknown's avatar
unknown committed
4005
static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
4006
{
4007
  char buff[FN_REFLEN],*ptr, *end;
4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019
  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);
4020
  end=convert_dirname(buff, *filename_ptr, NullS);
unknown's avatar
unknown committed
4021
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
4022 4023
    return 1;					// End of memory
  *filename_ptr=ptr;
4024
  strxmov(ptr,buff,table_name,NullS);
4025 4026
  return 0;
}
4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041

/*
  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;
4042
  if (thd->lex.current_select != &thd->lex.select_lex)
4043 4044 4045 4046
  {
    char command[80];
    strmake(command, thd->lex.yylval->symbol.str,
	    min(thd->lex.yylval->symbol.length, sizeof(command)-1));
4047
    net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
4048 4049 4050 4051
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081

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