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

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

30
#include "sp_head.h"
31
#include "sp.h"
32

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

51 52 53 54
#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
55

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

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

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

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
77
  "Binlog Dump","Table Dump",  "Connect Out", "Register Slave",
unknown's avatar
unknown committed
78
  "Prepare", "Prepare Execute", "Long Data", "Close stmt"
unknown's avatar
unknown committed
79 80
};

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

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

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


127 128 129
static HASH hash_user_connections;
extern  pthread_mutex_t LOCK_user_conn;

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

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

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

182
}
183 184 185


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

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

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

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

  /* in case we're going to retry we should not send error message at this point */
unknown's avatar
unknown committed
224 225
  if (thd->master_access & NO_ACCESS)
  {
226 227 228 229
    if (do_send_error)
    {
      net_printf(thd, ER_ACCESS_DENIED_ERROR,
      	       thd->user,
230
	       thd->host_or_ip,
231 232
	       had_password ? ER(ER_YES) : ER(ER_NO));
      mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
unknown's avatar
unknown committed
233
		    thd->user,
234
		    thd->host_or_ip,
235 236
		    had_password ? ER(ER_YES) : ER(ER_NO));
      return(1);					// Error already given
unknown's avatar
unknown committed
237 238
    }
    else
239
      return(-1); // do not report error in special handshake
unknown's avatar
unknown committed
240
  }
unknown's avatar
unknown committed
241

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

unknown's avatar
unknown committed
270
  if (db && db[0])
unknown's avatar
unknown committed
271 272
  {
    bool error=test(mysql_change_db(thd,db));
273 274
    if (error && thd->user_connect)
      decrease_user_connections(thd->user_connect);
unknown's avatar
unknown committed
275
    return error;
unknown's avatar
unknown committed
276
  }
unknown's avatar
unknown committed
277
  else
278
    send_ok(thd);				// Ready to handle questions
unknown's avatar
unknown committed
279 280 281
  return 0;					// ok
}

282

unknown's avatar
unknown committed
283
/*
unknown's avatar
unknown committed
284 285
  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
286 287
*/

288 289
extern "C" byte *get_key_conn(user_conn *buff, uint *length,
			      my_bool not_used __attribute__((unused)))
unknown's avatar
unknown committed
290 291 292 293 294
{
  *length=buff->len;
  return (byte*) buff->user;
}

295
extern "C" void free_user(struct user_conn *uc)
unknown's avatar
unknown committed
296 297 298 299
{
  my_free((char*) uc,MYF(0));
}

unknown's avatar
unknown committed
300
void init_max_user_conn(void)
unknown's avatar
unknown committed
301
{
unknown's avatar
unknown committed
302 303
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
		   0,0,
304
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
305
		   0);
unknown's avatar
unknown committed
306 307 308
}


309
static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
unknown's avatar
unknown committed
310
{
311
  int error=0;
312
  DBUG_ENTER("check_for_max_user_connections");
unknown's avatar
unknown committed
313

314 315
  if (max_user_connections &&
      (max_user_connections <=  (uint) uc->connections))
unknown's avatar
unknown committed
316
  {
317
    net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user);
318 319
    error=1;
    goto end;
unknown's avatar
unknown committed
320
  }
unknown's avatar
unknown committed
321
  uc->connections++;
322 323
  if (uc->user_resources.connections &&
      uc->conn_per_hour++ >= uc->user_resources.connections)
324
  {
325
    net_printf(thd, ER_USER_LIMIT_REACHED, uc->user,
326
	       "max_connections",
327 328 329
	       (long) uc->user_resources.connections);
    error=1;
  }
330 331
end:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
332 333 334
}


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

348

unknown's avatar
unknown committed
349 350 351 352 353
void free_max_user_conn(void)
{
  hash_free(&hash_user_connections);
}

unknown's avatar
unknown committed
354

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


unknown's avatar
unknown committed
387 388 389
/*
  Check if maximum queries per hour limit has been reached
  returns 0 if OK.
unknown's avatar
unknown committed
390

391 392 393
  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
394 395
*/

396

397
static bool check_mqh(THD *thd, uint check_command)
unknown's avatar
unknown committed
398 399
{
  bool error=0;
unknown's avatar
unknown committed
400
  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
401
  USER_CONN *uc=thd->user_connect;
unknown's avatar
unknown committed
402
  DBUG_ENTER("check_mqh");
403
  DBUG_ASSERT(uc != 0);
unknown's avatar
unknown committed
404

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

unknown's avatar
unknown committed
440

unknown's avatar
unknown committed
441
static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
442 443
{

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

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

unknown's avatar
unknown committed
478

unknown's avatar
unknown committed
479
/*
unknown's avatar
unknown committed
480 481
  Check connnetion and get priviliges
  Returns 0 on ok, -1 < if error is given > 0 on error.
unknown's avatar
unknown committed
482 483 484 485 486 487 488
*/

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

unknown's avatar
unknown committed
498 499 500 501
    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);
502
    thd->host_or_ip=thd->ip;
unknown's avatar
unknown committed
503 504 505
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
    /* Fast local hostname resolve for Win32 */
    if (!strcmp(thd->ip,"127.0.0.1"))
506
      thd->host=(char*) localhost;
unknown's avatar
unknown committed
507 508 509 510 511 512 513 514 515
    else
#endif
    if (!(specialflag & SPECIAL_NO_RESOLVE))
    {
      vio_in_addr(net->vio,&thd->remote.sin_addr);
      thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
      if (connect_errors > max_connect_errors)
	return(ER_HOST_IS_BLOCKED);
    }
unknown's avatar
unknown committed
516 517 518
    DBUG_PRINT("info",("Host: %s  ip: %s",
		       thd->host ? thd->host : "unknown host",
		       thd->ip ? thd->ip : "unknown ip"));
unknown's avatar
unknown committed
519 520 521
    if (acl_check_host(thd->host,thd->ip))
      return(ER_HOST_NOT_PRIVILEGED);
  }
522
  else /* Hostname given means that the connection was on a socket */
unknown's avatar
unknown committed
523
  {
unknown's avatar
unknown committed
524
    DBUG_PRINT("info",("Host: %s",thd->host));
525
    thd->host_or_ip=thd->host;
unknown's avatar
unknown committed
526 527 528 529 530
    thd->ip=0;
    bzero((char*) &thd->remote,sizeof(struct sockaddr));
  }
  vio_keepalive(net->vio, TRUE);

unknown's avatar
unknown committed
531
  ulong pkt_len=0;
unknown's avatar
unknown committed
532
  {
unknown's avatar
unknown committed
533
    /* buff[] needs to big enough to hold the server_version variable */
unknown's avatar
unknown committed
534
    char buff[SERVER_VERSION_LENGTH +
535
    SCRAMBLE_LENGTH+64],*end;
unknown's avatar
unknown committed
536
    int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
537
                       CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION;
unknown's avatar
unknown committed
538

539 540 541 542 543
    if (opt_using_transactions)
      client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
    client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
unknown's avatar
unknown committed
544 545 546 547
#ifdef HAVE_OPENSSL
    if (ssl_acceptor_fd)
      client_flags |= CLIENT_SSL;       /* Wow, SSL is avalaible! */
#endif /* HAVE_OPENSSL */
unknown's avatar
unknown committed
548

unknown's avatar
unknown committed
549
    end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1;
unknown's avatar
unknown committed
550 551 552 553 554
    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
555
    end[2]=(char) MY_CHARSET_CURRENT;
unknown's avatar
unknown committed
556 557 558
    int2store(end+3,thd->server_status);
    bzero(end+5,13);
    end+=18;
unknown's avatar
unknown committed
559

560
    // At this point we write connection message and read reply
561
    if (net_write_command(net,(uchar) protocol_version, "", 0, buff,
unknown's avatar
unknown committed
562
			  (uint) (end-buff)) ||
unknown's avatar
unknown committed
563
       (pkt_len= my_net_read(net)) == packet_error ||
unknown's avatar
unknown committed
564 565 566 567 568 569 570 571 572 573 574
	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
575
  if (thd->packet.alloc(thd->variables.net_buffer_length))
unknown's avatar
unknown committed
576 577 578
    return(ER_OUT_OF_RESOURCES);

  thd->client_capabilities=uint2korr(net->read_pos);
579 580
  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
    thd->sql_mode|= MODE_IGNORE_SPACE;
unknown's avatar
unknown committed
581
#ifdef HAVE_OPENSSL
unknown's avatar
unknown committed
582
  DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
unknown's avatar
unknown committed
583 584 585 586
  if (thd->client_capabilities & CLIENT_SSL)
  {
    /* Do the SSL layering. */
    DBUG_PRINT("info", ("IO layer change in progress..."));
unknown's avatar
unknown committed
587 588 589 590 591
    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
592
      return(ER_HANDSHAKE_ERROR);
unknown's avatar
unknown committed
593
    }
unknown's avatar
unknown committed
594 595 596 597
    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
598 599
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
unknown's avatar
unknown committed
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
  }
  else
  {
    DBUG_PRINT("info", ("Leaving IO layer intact"));
    if (pkt_len < NORMAL_HANDSHAKE_SIZE)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return ER_HANDSHAKE_ERROR;
    }
  }
#endif

unknown's avatar
unknown committed
615
  thd->max_client_packet_length=uint3korr(net->read_pos+2);
unknown's avatar
unknown committed
616 617 618
  char *user=   (char*) net->read_pos+5;
  char *passwd= strend(user)+1;
  char *db=0;
unknown's avatar
unknown committed
619 620 621
  if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
     db=strend(passwd)+1;

622
  /* We can get only old hash at this point */
unknown's avatar
unknown committed
623
  if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
624
      return ER_HANDSHAKE_ERROR;
unknown's avatar
unknown committed
625

unknown's avatar
unknown committed
626
  if (thd->client_capabilities & CLIENT_INTERACTIVE)
627
     thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
628
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
629 630
       opt_using_transactions)
  thd->net.return_status= &thd->server_status;
unknown's avatar
unknown committed
631
  net->read_timeout=(uint) thd->variables.net_read_timeout;
unknown's avatar
unknown committed
632

633
  char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble and hash */
unknown's avatar
unknown committed
634

635
  ACL_USER* cached_user=NULL; /* Initialise to NULL as first stage indication */
unknown's avatar
unknown committed
636
  uint cur_priv_version;
unknown's avatar
unknown committed
637

638 639
  /* 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
640

641 642 643 644
  /* 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 */
  if (check_user(thd,COM_CONNECT, user, passwd, db, 1, simple_connect,
645
      prepared_scramble,using_password,&cur_priv_version,&cached_user)<0)
unknown's avatar
unknown committed
646
  {
647 648
    /* If The client is old we just have to return error */
    if (simple_connect)
unknown's avatar
unknown committed
649 650
      return -1;

651
    /* Store current used and database as they are erased with next packet */
unknown's avatar
unknown committed
652

653 654 655
    char tmp_user[USERNAME_LENGTH+1];
    char tmp_db[NAME_LEN+1];

unknown's avatar
unknown committed
656
    tmp_user[0]=0;
657
    if (user)
unknown's avatar
unknown committed
658 659
      strmake(tmp_user,user,USERNAME_LENGTH);

660
    tmp_db[0]=0;
661
    if (db)
unknown's avatar
unknown committed
662 663
      strmake(tmp_db,db,NAME_LEN);

664
    /* Write hash and encrypted scramble to client */
665 666
    if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
        net_flush(net))
667 668 669
      {
        inc_host_errors(&thd->remote.sin_addr);
        return ER_HANDSHAKE_ERROR;
unknown's avatar
unknown committed
670 671 672
      }
    /* Reading packet back */
    if ((pkt_len=my_net_read(net)) == packet_error)
673 674 675 676
      {
        inc_host_errors(&thd->remote.sin_addr);
        return ER_HANDSHAKE_ERROR;
      }
unknown's avatar
unknown committed
677 678
    /* We have to get very specific packet size  */
    if (pkt_len!=SCRAMBLE41_LENGTH)
679 680
      {
        inc_host_errors(&thd->remote.sin_addr);
unknown's avatar
unknown committed
681
        return ER_HANDSHAKE_ERROR;
682
      }
unknown's avatar
unknown committed
683 684
    /* Final attempt to check the user based on reply */
    if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos,
685
        tmp_db, 1, 1,prepared_scramble,using_password,&cur_priv_version,
unknown's avatar
unknown committed
686
        &cached_user))
687 688 689
      return -1;
  }
  thd->password=using_password;
unknown's avatar
unknown committed
690 691 692 693 694 695 696 697
  return 0;
}


pthread_handler_decl(handle_one_connection,arg)
{
  THD *thd=(THD*) arg;
  uint launch_time  =
unknown's avatar
unknown committed
698
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
unknown's avatar
unknown committed
699 700 701 702 703
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status );

  pthread_detach_this_thread();

704 705
#if !defined( __WIN__) && !defined(OS2)	// Win32 calls this in pthread_create
  // The following calls needs to be done before we call DBUG_ macros
706
  if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
unknown's avatar
unknown committed
707 708
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
709
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
710 711 712 713 714
    end_thread(thd,0);
    return 0;
  }
#endif

715 716 717 718 719 720 721
  /*
    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
722 723 724 725
  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
726
#if defined(__WIN__)
unknown's avatar
unknown committed
727
  init_signals();				// IRENA; testing ?
unknown's avatar
unknown committed
728
#elif !defined(OS2)
unknown's avatar
unknown committed
729 730 731 732 733 734 735
  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);
736
    statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
737 738 739 740 741 742 743 744 745 746 747 748 749
    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)
750
	net_printf(thd,error,thd->host_or_ip);
unknown's avatar
unknown committed
751 752 753 754
#ifdef __NT__
      if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
	sleep(1);				/* must wait after eof() */
#endif
755
      statistic_increment(aborted_connects,&LOCK_status);
unknown's avatar
unknown committed
756 757 758
      goto end_thread;
    }

759
    if ((ulong) thd->variables.max_join_size == (ulonglong) HA_POS_ERROR)
unknown's avatar
unknown committed
760 761 762 763
      thd->options |= OPTION_BIG_SELECTS;
    if (thd->client_capabilities & CLIENT_COMPRESS)
      net->compress=1;				// Use compression

unknown's avatar
unknown committed
764
    thd->proc_info=0;				// Remove 'login'
765
    thd->command=COM_SLEEP;
unknown's avatar
unknown committed
766 767
    thd->version=refresh_version;
    thd->set_time();
768 769 770
    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
771 772 773 774 775
    while (!net->error && net->vio != 0 && !thd->killed)
    {
      if (do_command(thd))
	break;
    }
776 777
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
778
    free_root(&thd->mem_root,MYF(0));
unknown's avatar
unknown committed
779
    if (net->error && net->vio != 0 && net->report_error)
unknown's avatar
unknown committed
780
    {
unknown's avatar
unknown committed
781
      if (!thd->killed && thd->variables.log_warnings)
782 783 784 785 786 787
	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)));
788
      send_error(thd,net->last_errno,NullS);
unknown's avatar
unknown committed
789
      statistic_increment(aborted_threads,&LOCK_status);
unknown's avatar
unknown committed
790
    }
unknown's avatar
unknown committed
791

unknown's avatar
unknown committed
792 793 794 795 796 797 798 799 800 801 802 803 804
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 */
}

805 806 807 808
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
unknown's avatar
unknown committed
809

810
extern "C" pthread_handler_decl(handle_bootstrap,arg)
unknown's avatar
unknown committed
811
{
812 813 814
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
unknown's avatar
unknown committed
815

816
  /* The following must be called before DBUG_ENTER */
817
  if (my_thread_init() || thd->store_globals())
unknown's avatar
unknown committed
818 819
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
820 821
    thd->fatal_error=1;
    goto end;
unknown's avatar
unknown committed
822
  }
823 824 825 826
  DBUG_ENTER("handle_bootstrap");

  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
827
#if !defined(__WIN__) && !defined(OS2)
unknown's avatar
unknown committed
828
  sigset_t set;
829 830 831 832
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));


unknown's avatar
unknown committed
833 834
#endif

835
  if ((ulong) thd->variables.max_join_size == (ulonglong) HA_POS_ERROR)
unknown's avatar
unknown committed
836 837 838 839
    thd->options |= OPTION_BIG_SELECTS;

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

842
  buff= (char*) thd->net.buff;
843 844 845
  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
846 847
  while (fgets(buff, thd->net.max_packet, file))
  {
unknown's avatar
unknown committed
848
    uint length=(uint) strlen(buff);
unknown's avatar
unknown committed
849
    while (length && (my_isspace(system_charset_info, buff[length-1]) ||
850
           buff[length-1] == ';'))
unknown's avatar
unknown committed
851 852 853
      length--;
    buff[length]=0;
    thd->current_tablenr=0;
854
    thd->query_length=length;
unknown's avatar
unknown committed
855 856
    thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
    thd->query[length] = '\0';
unknown's avatar
unknown committed
857
    thd->query_id=query_id++;
858
    if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
859 860 861 862 863 864
    {
      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
865 866 867
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
    if (thd->fatal_error)
868
      break;
869
    free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
870
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
871
  }
872 873 874 875 876 877

  /* 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);
878
  (void) pthread_cond_broadcast(&COND_thread_count);
879 880 881
  my_thread_end();
  pthread_exit(0);
  DBUG_RETURN(0);				// Never reached
unknown's avatar
unknown committed
882 883
}

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

886
void free_items(Item *item)
unknown's avatar
unknown committed
887
{
888
  for (; item ; item=item->next)
unknown's avatar
unknown committed
889 890 891 892 893 894 895 896 897 898
    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;
899
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
900
    DBUG_RETURN(1); // out of memory
unknown's avatar
unknown committed
901
  table_list->db = db;
902
  table_list->real_name = table_list->alias = tbl_name;
unknown's avatar
unknown committed
903 904 905
  table_list->lock_type = TL_READ_NO_INSERT;
  table_list->next = 0;
  remove_escape(table_list->real_name);
unknown's avatar
unknown committed
906

907
  if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
unknown's avatar
unknown committed
908 909
    DBUG_RETURN(1);

910 911
  if (!db || check_db_name(db))
  {
912
    net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
913 914
    goto err;
  }
915
  if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege))
unknown's avatar
unknown committed
916
    goto err;
917
  if (grant_option && check_grant(thd, SELECT_ACL, table_list))
unknown's avatar
unknown committed
918 919 920
    goto err;

  thd->free_list = 0;
unknown's avatar
unknown committed
921
  thd->query_length=(uint) strlen(tbl_name);
unknown's avatar
unknown committed
922
  thd->query = tbl_name;
923 924 925 926 927
  if ((error = mysqld_dump_create_info(thd, table, -1)))
  {
    my_error(ER_GET_ERRNO, MYF(0));
    goto err;
  }
unknown's avatar
unknown committed
928
  net_flush(&thd->net);
929 930
  if ((error = table->file->dump(thd,fd)))
    my_error(ER_GET_ERRNO, MYF(0));
unknown's avatar
unknown committed
931

unknown's avatar
unknown committed
932 933
err:
  close_thread_tables(thd);
unknown's avatar
unknown committed
934
  DBUG_RETURN(error);
unknown's avatar
unknown committed
935 936 937 938 939 940 941 942
}


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

bool do_command(THD *thd)
{
  char *packet;
unknown's avatar
unknown committed
943 944
  uint old_timeout;
  ulong packet_length;
unknown's avatar
unknown committed
945 946 947 948 949 950 951 952
  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
953 954 955
  old_timeout=net->read_timeout;
  // Wait max for 8 hours
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
unknown's avatar
unknown committed
956
  thd->clear_error();				// Clear error message
unknown's avatar
unknown committed
957 958 959 960

  net_new_transaction(net);
  if ((packet_length=my_net_read(net)) == packet_error)
  {
unknown's avatar
unknown committed
961 962
     DBUG_PRINT("info",("Got error reading command from socket %s",
			vio_description(net->vio) ));
unknown's avatar
unknown committed
963 964 965 966 967 968
    return TRUE;
  }
  else
  {
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
unknown's avatar
unknown committed
969 970 971
    DBUG_PRINT("info",("Command on %s = %d (%s)",
		       vio_description(net->vio), command,
		       command_name[command]));
unknown's avatar
unknown committed
972
  }
unknown's avatar
unknown committed
973
  net->read_timeout=old_timeout;		// restore it
unknown's avatar
unknown committed
974
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
975 976 977 978 979 980 981 982
}


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
983 984 985 986
  /*
    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
  */
987 988 989
  bool slow_command=FALSE;
  DBUG_ENTER("dispatch_command");

unknown's avatar
unknown committed
990
  thd->command=command;
unknown's avatar
unknown committed
991
  thd->set_time();
unknown's avatar
unknown committed
992 993 994 995 996 997
  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
998

999
  thd->lex.select_lex.options=0;		// We store status here
1000
  switch (command) {
unknown's avatar
unknown committed
1001
  case COM_INIT_DB:
unknown's avatar
unknown committed
1002
    statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
1003
    if (!mysql_change_db(thd,packet))
1004
      mysql_log.write(thd,command,"%s",thd->db);
unknown's avatar
unknown committed
1005
    break;
1006 1007
  case COM_REGISTER_SLAVE:
  {
1008
    if (!register_slave(thd, (uchar*)packet, packet_length))
1009
      send_ok(thd);
1010 1011
    break;
  }
unknown's avatar
unknown committed
1012 1013
  case COM_TABLE_DUMP:
    {
unknown's avatar
unknown committed
1014
      statistic_increment(com_other, &LOCK_status);
1015
      slow_command = TRUE;
1016 1017
      uint db_len = *(uchar*)packet;
      uint tbl_len = *(uchar*)(packet + db_len + 1);
1018
      char* db = thd->alloc(db_len + tbl_len + 2);
1019
      memcpy(db, packet + 1, db_len);
unknown's avatar
unknown committed
1020 1021
      char* tbl_name = db + db_len;
      *tbl_name++ = 0;
1022
      memcpy(tbl_name, packet + db_len + 2, tbl_len);
unknown's avatar
unknown committed
1023
      tbl_name[tbl_len] = 0;
unknown's avatar
unknown committed
1024
      if (mysql_table_dump(thd, db, tbl_name, -1))
1025
	send_error(thd); // dump to NET
unknown's avatar
unknown committed
1026

unknown's avatar
unknown committed
1027 1028 1029 1030
      break;
    }
  case COM_CHANGE_USER:
  {
unknown's avatar
unknown committed
1031 1032 1033 1034
    thd->change_user();
    clear_error_message(thd);			// If errors from rollback

    statistic_increment(com_other,&LOCK_status);
1035
    char *user=   (char*) packet;
unknown's avatar
unknown committed
1036 1037
    char *passwd= strend(user)+1;
    char *db=     strend(passwd)+1;
unknown's avatar
unknown committed
1038

unknown's avatar
unknown committed
1039 1040 1041
    /* Save user and privileges */
    uint save_master_access=thd->master_access;
    uint save_db_access=    thd->db_access;
unknown's avatar
unknown committed
1042
    uint save_db_length=    thd->db_length;
unknown's avatar
unknown committed
1043
    char *save_user=	    thd->user;
unknown's avatar
unknown committed
1044
    thd->user=NULL; /* Needed for check_user to allocate new user */
unknown's avatar
unknown committed
1045 1046
    char *save_priv_user=   thd->priv_user;
    char *save_db=	    thd->db;
unknown's avatar
unknown committed
1047 1048 1049
    USER_CONN *save_uc=     thd->user_connect;
    bool simple_connect;
    bool using_password;
unknown's avatar
unknown committed
1050

unknown's avatar
unknown committed
1051
    ulong pkt_len=0; /* Length of reply packet */
unknown's avatar
unknown committed
1052

unknown's avatar
unknown committed
1053
    /* Small check for incomming packet */
unknown's avatar
unknown committed
1054 1055

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

unknown's avatar
unknown committed
1058
    /* Now we shall basically perform authentication again */
unknown's avatar
unknown committed
1059

unknown's avatar
unknown committed
1060
     /* We can get only old hash at this point */
unknown's avatar
unknown committed
1061
    if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
unknown's avatar
unknown committed
1062
      goto restore_user_err;
unknown's avatar
unknown committed
1063 1064

    char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */
1065 1066
    ACL_USER* cached_user     ;                 /* Cached user */
    cached_user= NULL;
unknown's avatar
unknown committed
1067
    uint cur_priv_version;                      /* Cached grant version */
unknown's avatar
unknown committed
1068

unknown's avatar
unknown committed
1069 1070
    /* 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
1071

unknown's avatar
unknown committed
1072 1073
    /* Store information if we used password. passwd will be dammaged */
    using_password=test(passwd[0]);
unknown's avatar
unknown committed
1074 1075 1076 1077 1078 1079 1080 1081

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

    /*
     Check user permissions. If password failure we'll get scramble back
     Do not retry if we already have sent error (result>0)
    */
unknown's avatar
unknown committed
1082
    if (check_user(thd,COM_CHANGE_USER, user, passwd, db, 0, simple_connect,
1083
        prepared_scramble,using_password,&cur_priv_version,&cached_user)<0)
unknown's avatar
unknown committed
1084 1085 1086 1087
    {
      /* 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
1088

unknown's avatar
unknown committed
1089
      /* Store current used and database as they are erased with next packet */
unknown's avatar
unknown committed
1090

unknown's avatar
unknown committed
1091 1092
      char tmp_user[USERNAME_LENGTH+1];
      char tmp_db[NAME_LEN+1];
1093 1094
     
      tmp_user[0]=0;
unknown's avatar
unknown committed
1095
      if (user)
1096 1097 1098
        strmake(tmp_user,user,USERNAME_LENGTH);

      tmp_db[0]=0;
unknown's avatar
unknown committed
1099
      if (db)
1100 1101
        strmake(tmp_db,db,NAME_LEN);

unknown's avatar
unknown committed
1102

unknown's avatar
unknown committed
1103
      /* Write hash and encrypted scramble to client */
1104 1105
      if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
          net_flush(net))
unknown's avatar
unknown committed
1106
        goto restore_user_err;
unknown's avatar
unknown committed
1107 1108 1109 1110 1111 1112 1113

      /* 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
1114
        goto restore_user;
unknown's avatar
unknown committed
1115 1116

      /* Final attempt to check the user based on reply */
1117 1118
      if (check_user(thd,COM_CHANGE_USER, tmp_user, (char*)net->read_pos,
          tmp_db, 0, 1,prepared_scramble,using_password,&cur_priv_version,
unknown's avatar
unknown committed
1119 1120
          &cached_user))
        goto restore_user;
unknown's avatar
unknown committed
1121
    }
unknown's avatar
unknown committed
1122
    /* Finally we've authenticated new user */
1123
    if (max_connections && save_uc)
unknown's avatar
unknown committed
1124
      decrease_user_connections(save_uc);
unknown's avatar
unknown committed
1125 1126
    x_free((gptr) save_db);
    x_free((gptr) save_user);
unknown's avatar
unknown committed
1127 1128
    thd->password=using_password;
    break;
unknown's avatar
unknown committed
1129

unknown's avatar
unknown committed
1130 1131 1132
    /* Bad luck  we shall restore old user */
    restore_user_err:
    send_error(thd, ER_UNKNOWN_COM_ERROR);
unknown's avatar
unknown committed
1133

unknown's avatar
unknown committed
1134 1135 1136 1137 1138 1139 1140 1141
    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
1142
    thd->priv_user=save_priv_user;
unknown's avatar
unknown committed
1143 1144
    break;
  }
unknown's avatar
unknown committed
1145

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

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

unknown's avatar
unknown committed
1266 1267
      ulong pos;
      ushort flags;
1268
      uint32 slave_server_id;
1269
      /* TODO: The following has to be changed to an 8 byte integer */
1270 1271
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
1272
      thd->server_id=0; /* avoid suicide */
1273
      kill_zombie_dump_threads(slave_server_id = uint4korr(packet+6));
1274
      thd->server_id = slave_server_id;
1275
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1276
      unregister_slave(thd,1,1);
1277 1278 1279
      // fake COM_QUIT -- if we get here, the thread needs to terminate
      error = TRUE;
      net->error = 0;
unknown's avatar
unknown committed
1280 1281 1282 1283
      break;
    }
  case COM_REFRESH:
    {
unknown's avatar
unknown committed
1284
      statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
unknown's avatar
unknown committed
1285
      ulong options= (ulong) (uchar) packet[0];
unknown's avatar
unknown committed
1286
      if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1287
	break;
1288
      mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1289
      if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0))
1290
	send_error(thd,0);
unknown's avatar
unknown committed
1291
      else
1292
	send_eof(thd);
unknown's avatar
unknown committed
1293 1294 1295
      break;
    }
  case COM_SHUTDOWN:
unknown's avatar
unknown committed
1296
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1297
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1298 1299
      break; /* purecov: inspected */
    DBUG_PRINT("quit",("Got shutdown command"));
1300
    mysql_log.write(thd,command,NullS);
1301
    send_eof(thd);
unknown's avatar
unknown committed
1302 1303 1304
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
unknown's avatar
unknown committed
1305
#ifndef OS2
1306
    send_eof(thd);				// This is for 'quit request'
unknown's avatar
unknown committed
1307
#endif
unknown's avatar
unknown committed
1308 1309
    close_connection(net);
    close_thread_tables(thd);			// Free before kill
1310
    free_root(&thd->mem_root,MYF(0));
1311
    free_root(&thd->transaction.mem_root,MYF(0));
unknown's avatar
unknown committed
1312 1313 1314 1315 1316 1317
    kill_mysql();
    error=TRUE;
    break;

  case COM_STATISTICS:
  {
1318
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1319
    statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
unknown's avatar
unknown committed
1320
    char buff[200];
1321
    ulong uptime = (ulong) (thd->start_time - start_time);
unknown's avatar
unknown committed
1322
    sprintf((char*) buff,
1323
	    "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
1324 1325 1326 1327 1328 1329 1330 1331 1332
	    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
1333
    VOID(my_net_write(net, buff,(uint) strlen(buff)));
unknown's avatar
unknown committed
1334 1335 1336 1337
    VOID(net_flush(net));
    break;
  }
  case COM_PING:
unknown's avatar
unknown committed
1338
    statistic_increment(com_other,&LOCK_status);
1339
    send_ok(thd);				// Tell client we are alive
unknown's avatar
unknown committed
1340 1341
    break;
  case COM_PROCESS_INFO:
unknown's avatar
unknown committed
1342
    statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
unknown's avatar
unknown committed
1343
    if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
1344
      break;
1345
    mysql_log.write(thd,command,NullS);
unknown's avatar
unknown committed
1346 1347 1348 1349 1350
    mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
			  thd->priv_user,0);
    break;
  case COM_PROCESS_KILL:
  {
unknown's avatar
unknown committed
1351
    statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
1352
    ulong id=(ulong) uint4korr(packet);
unknown's avatar
unknown committed
1353 1354 1355 1356
    kill_one_thread(thd,id);
    break;
  }
  case COM_DEBUG:
unknown's avatar
unknown committed
1357
    statistic_increment(com_other,&LOCK_status);
unknown's avatar
unknown committed
1358
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1359 1360
      break;					/* purecov: inspected */
    mysql_print_status(thd);
1361
    mysql_log.write(thd,command,NullS);
1362
    send_eof(thd);
unknown's avatar
unknown committed
1363 1364 1365 1366 1367 1368
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
  default:
1369
    send_error(thd, ER_UNKNOWN_COM_ERROR);
unknown's avatar
unknown committed
1370 1371 1372 1373 1374 1375 1376 1377 1378
    break;
  }
  if (thd->lock || thd->open_tables)
  {
    thd->proc_info="closing tables";
    close_thread_tables(thd);			/* Free tables */
  }

  if (thd->fatal_error)
1379
    send_error(thd,0);				// End of memory ?
unknown's avatar
unknown committed
1380 1381

  time_t start_of_query=thd->start_time;
1382
  thd->end_time();				// Set start time
1383

1384
  /* If not reading from backup and if the query took too long */
1385
  if (!slow_command && !thd->user_time) // do not log 'slow_command' queries
unknown's avatar
unknown committed
1386
  {
1387 1388
    thd->proc_info="logging slow query";

1389 1390
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
1391
	((thd->lex.select_lex.options &
1392
	  (QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED)) &&
1393
	 (specialflag & SPECIAL_LONG_LOG_FORMAT)))
1394 1395 1396 1397
    {
      long_query_count++;
      mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
    }
unknown's avatar
unknown committed
1398
  }
1399
  thd->proc_info="cleaning up";
unknown's avatar
unknown committed
1400 1401 1402 1403 1404 1405
  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
1406
  thd->packet.shrink(thd->variables.net_buffer_length);	// Reclaim some memory
1407
  free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
unknown's avatar
unknown committed
1408 1409 1410
  DBUG_RETURN(error);
}

1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435

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

  DESCRIPTION
    Sets the following THD variables:
      query
      query_length

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

bool alloc_query(THD *thd, char *packet, ulong packet_length)
{
  packet_length--;				// Remove end null
  /* Remove garage at start and end of query */
  while (my_isspace(system_charset_info,packet[0]) && packet_length > 0)
  {
    packet++;
    packet_length--;
  }
  char *pos=packet+packet_length;		// Point at end null
unknown's avatar
unknown committed
1436
  while (packet_length > 0 &&
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455
	 (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
1456 1457 1458 1459 1460 1461
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/

void
1462
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
1463
{
1464
  int	res= 0;
1465
  LEX	*lex= &thd->lex;
1466
  TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first;
1467
  TABLE_LIST *cursor;
unknown's avatar
unknown committed
1468
  SELECT_LEX *select_lex= &lex->select_lex;
1469
  SELECT_LEX_UNIT *unit= &lex->unit;
unknown's avatar
unknown committed
1470 1471
  DBUG_ENTER("mysql_execute_command");

1472 1473 1474 1475 1476 1477
  /*
    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.
  */
1478
  if (tables || &lex->select_lex != lex->all_selects_list)
1479 1480 1481 1482 1483 1484 1485
    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;

1486 1487
  if (thd->slave_thread)
  {
unknown's avatar
unknown committed
1488
    /*
unknown's avatar
merge  
unknown committed
1489 1490 1491 1492
      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))
1493
      DBUG_VOID_RETURN;
unknown's avatar
merge  
unknown committed
1494 1495 1496 1497 1498 1499
#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()
    */
1500 1501 1502
    if (lex->sql_command == SQLCOM_SELECT)
    {
      lex->sql_command = SQLCOM_DO;
unknown's avatar
unknown committed
1503
      lex->insert_list = &select_lex->item_list;
1504
    }
unknown's avatar
merge  
unknown committed
1505
#endif
1506
  }
unknown's avatar
unknown committed
1507

1508
  /*
unknown's avatar
unknown committed
1509 1510
    TODO: make derived tables processing 'inside' SELECT processing.
    TODO: solve problem with depended derived tables in subselects
1511
  */
unknown's avatar
unknown committed
1512
  if (lex->derived_tables)
unknown's avatar
unknown committed
1513
  {
1514 1515 1516 1517 1518 1519 1520 1521 1522 1523
    for (SELECT_LEX *sl= lex->all_selects_list;
	 sl;
	 sl= sl->next_select_in_list())
      for (TABLE_LIST *cursor= sl->get_table_list();
	   cursor;
	   cursor= cursor->next)
	if (cursor->derived && (res=mysql_derived(thd, lex,
						  (SELECT_LEX_UNIT *)
						  cursor->derived,
						  cursor)))
unknown's avatar
unknown committed
1524
	{
1525 1526 1527 1528 1529
	  if (res < 0 || thd->net.report_error)
	    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
	  DBUG_VOID_RETURN;
	}
  }
unknown's avatar
unknown committed
1530
  if ((&lex->select_lex != lex->all_selects_list &&
1531
       lex->unit.create_total_list(thd, lex, &tables)) ||
unknown's avatar
unknown committed
1532 1533
      (table_rules_on && tables && thd->slave_thread &&
       !tables_ok(thd,tables)))
1534
    DBUG_VOID_RETURN;
1535

unknown's avatar
unknown committed
1536
  statistic_increment(com_stat[lex->sql_command],&LOCK_status);
unknown's avatar
unknown committed
1537 1538 1539
  switch (lex->sql_command) {
  case SQLCOM_SELECT:
  {
1540
    select_result *result=lex->result;
unknown's avatar
unknown committed
1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556
    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
    }

1557 1558 1559
    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
1560
    if (unit->select_limit_cnt <
1561
	(ha_rows) unit->global_parameters->select_limit)
1562 1563
      unit->select_limit_cnt= HA_POS_ERROR;		// no limit
    if (unit->select_limit_cnt == HA_POS_ERROR)
1564
      select_lex->options&= ~OPTION_FOUND_ROWS;
unknown's avatar
unknown committed
1565 1566

    if (!(res=open_and_lock_tables(thd,tables)))
unknown's avatar
unknown committed
1567
    {
unknown's avatar
unknown committed
1568
      if (lex->describe)
unknown's avatar
unknown committed
1569
      {
1570 1571 1572 1573 1574 1575 1576
	if (!(result= new select_send()))
	{
	  send_error(thd, ER_OUT_OF_RESOURCES);
	  DBUG_VOID_RETURN;
	}
	else
	  thd->send_explain_fields(result);
1577
	fix_tables_pointers(lex->all_selects_list);
1578
	res= mysql_explain_union(thd, &thd->lex.unit, result);
unknown's avatar
unknown committed
1579 1580
	MYSQL_LOCK *save_lock= thd->lock;
	thd->lock= (MYSQL_LOCK *)0;
1581
	result->send_eof();
unknown's avatar
unknown committed
1582 1583 1584 1585
	thd->lock= save_lock;
      }
      else
      {
unknown's avatar
unknown committed
1586 1587
	if (!result)
	{
unknown's avatar
unknown committed
1588
	  if (!(result=new select_send()))
unknown's avatar
unknown committed
1589 1590 1591 1592 1593 1594 1595 1596 1597
	  {
	    res= -1;
#ifdef DELETE_ITEMS
	    delete select_lex->having;
	    delete select_lex->where;
#endif
	    break;
	  }
	}
unknown's avatar
unknown committed
1598 1599 1600
	query_cache_store_query(thd, tables);
	res=handle_select(thd, lex, result);
      }
unknown's avatar
unknown committed
1601
    }
unknown's avatar
unknown committed
1602 1603
    break;
  }
unknown's avatar
unknown committed
1604 1605 1606 1607
  case SQLCOM_DO:
    res=mysql_do(thd, *lex->insert_list);
    break;

1608
  case SQLCOM_EMPTY_QUERY:
1609
    send_ok(thd);
1610 1611
    break;

unknown's avatar
unknown committed
1612 1613 1614 1615
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

unknown's avatar
unknown committed
1616
  case SQLCOM_PURGE:
1617
  {
unknown's avatar
unknown committed
1618
    if (check_global_access(thd, SUPER_ACL))
1619 1620 1621 1622
      goto error;
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
unknown's avatar
unknown committed
1623 1624
  case SQLCOM_SHOW_WARNS:
  {
1625 1626 1627
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN)));
unknown's avatar
unknown committed
1628 1629 1630 1631
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
1632 1633
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
1634 1635
    break;
  }
unknown's avatar
unknown committed
1636 1637
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
1638
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1639
      goto error;
unknown's avatar
unknown committed
1640
#ifndef WORKING_NEW_MASTER
1641
    net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
unknown's avatar
unknown committed
1642 1643
    res= 1;
#else
unknown's avatar
unknown committed
1644
    res = show_new_master(thd);
unknown's avatar
unknown committed
1645
#endif
unknown's avatar
unknown committed
1646 1647
    break;
  }
1648 1649
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
1650
    if (check_global_access(thd, REPL_SLAVE_ACL))
1651 1652 1653 1654
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
1655 1656
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
1657
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1658 1659 1660 1661
      goto error;
    res = show_binlog_events(thd);
    break;
  }
unknown's avatar
unknown committed
1662
  case SQLCOM_BACKUP_TABLE:
1663 1664 1665
  {
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables) ||
unknown's avatar
unknown committed
1666
	check_global_access(thd, FILE_ACL))
1667 1668
      goto error; /* purecov: inspected */
    res = mysql_backup_table(thd, tables);
unknown's avatar
unknown committed
1669

1670 1671
    break;
  }
unknown's avatar
unknown committed
1672
  case SQLCOM_RESTORE_TABLE:
1673 1674
  {
    if (check_db_used(thd,tables) ||
unknown's avatar
unknown committed
1675 1676
	check_table_access(thd, INSERT_ACL, tables) ||
	check_global_access(thd, FILE_ACL))
1677 1678 1679 1680
      goto error; /* purecov: inspected */
    res = mysql_restore_table(thd, tables);
    break;
  }
unknown's avatar
unknown committed
1681
  case SQLCOM_CHANGE_MASTER:
1682
  {
unknown's avatar
unknown committed
1683
    if (check_global_access(thd, SUPER_ACL))
1684
      goto error;
1685 1686 1687
    LOCK_ACTIVE_MI;
    res = change_master(thd,active_mi);
    UNLOCK_ACTIVE_MI;
1688 1689
    break;
  }
unknown's avatar
unknown committed
1690
  case SQLCOM_SHOW_SLAVE_STAT:
1691
  {
unknown's avatar
unknown committed
1692
    if (check_global_access(thd, SUPER_ACL))
1693
      goto error;
1694 1695 1696
    LOCK_ACTIVE_MI;
    res = show_master_info(thd,active_mi);
    UNLOCK_ACTIVE_MI;
1697 1698
    break;
  }
unknown's avatar
unknown committed
1699
  case SQLCOM_SHOW_MASTER_STAT:
1700
  {
unknown's avatar
unknown committed
1701
    if (check_global_access(thd, SUPER_ACL))
1702 1703 1704 1705
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
1706

1707
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
1708
    if (check_global_access(thd, SUPER_ACL))
1709
      goto error;
1710 1711 1712 1713
    if (end_active_trans(thd))
      res= -1;
    else
      res = load_master_data(thd);
1714
    break;
unknown's avatar
unknown committed
1715

unknown's avatar
unknown committed
1716 1717 1718
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
1719
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1720 1721 1722 1723 1724
	goto error;
      res = innodb_show_status(thd);
      break;
    }
#endif
unknown's avatar
unknown committed
1725

unknown's avatar
unknown committed
1726
  case SQLCOM_LOAD_MASTER_TABLE:
1727
  {
unknown's avatar
unknown committed
1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739
    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)
1740
	goto error;
unknown's avatar
unknown committed
1741
    }
1742
    if (strlen(tables->real_name) > NAME_LEN)
unknown's avatar
unknown committed
1743
    {
unknown's avatar
unknown committed
1744
      net_printf(thd,ER_WRONG_TABLE_NAME,tables->real_name);
unknown's avatar
unknown committed
1745 1746
      break;
    }
1747 1748 1749 1750 1751
    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))
    {
1752
      send_ok(thd);
1753 1754
    }
    UNLOCK_ACTIVE_MI;
unknown's avatar
unknown committed
1755
    break;
1756
  }
unknown's avatar
unknown committed
1757
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
1758 1759 1760
  {
    ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
		      CREATE_TMP_ACL : CREATE_ACL);
1761 1762
    if (!tables->db)
      tables->db=thd->db;
unknown's avatar
unknown committed
1763
    if (check_access(thd,want_priv,tables->db,&tables->grant.privilege) ||
1764 1765 1766
	check_merge_table_access(thd, tables->db,
				 (TABLE_LIST *)
				 lex->create_info.merge_list.first))
unknown's avatar
unknown committed
1767
      goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
1768
    if (grant_option && want_priv != CREATE_TMP_ACL)
unknown's avatar
unknown committed
1769 1770 1771 1772
    {
      /* Check that the first table has CREATE privilege */
      TABLE_LIST *tmp_table_list=tables->next;
      tables->next=0;
unknown's avatar
unknown committed
1773
      bool error=check_grant(thd, want_priv, tables);
unknown's avatar
unknown committed
1774 1775 1776 1777
      tables->next=tmp_table_list;
      if (error)
	goto error;
    }
1778
    if (strlen(tables->real_name) > NAME_LEN)
unknown's avatar
unknown committed
1779
    {
unknown's avatar
unknown committed
1780
      net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias);
unknown's avatar
unknown committed
1781 1782 1783
      res=0;
      break;
    }
1784 1785 1786
#ifndef HAVE_READLINK
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
1787
    /* Fix names if symlinked tables */
unknown's avatar
unknown committed
1788
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
1789
			   tables->real_name) ||
unknown's avatar
unknown committed
1790
	append_file_to_dir(thd,&lex->create_info.index_file_name,
1791
			   tables->real_name))
1792 1793 1794 1795
    {
      res=-1;
      break;
    }
1796
#endif
1797
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
1798 1799 1800 1801
    {
      select_result *result;

      if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
1802
	  find_real_table_in_list(tables->next, tables->db, tables->real_name))
unknown's avatar
unknown committed
1803
      {
unknown's avatar
unknown committed
1804
	net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
unknown's avatar
unknown committed
1805 1806 1807 1808
	DBUG_VOID_RETURN;
      }
      if (tables->next)
      {
1809
	TABLE_LIST *table;
unknown's avatar
unknown committed
1810 1811 1812
	if (check_table_access(thd, SELECT_ACL, tables->next))
	  goto error;				// Error message is given
      }
1813 1814 1815 1816 1817
      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
1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833

      /* 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
1834 1835 1836 1837 1838
    else // regular create
    {
      res = mysql_create_table(thd,tables->db ? tables->db : thd->db,
			       tables->real_name, &lex->create_info,
			       lex->create_list,
1839
			       lex->key_list,0,0,0); // do logging
unknown's avatar
unknown committed
1840
      if (!res)
1841
	send_ok(thd);
unknown's avatar
unknown committed
1842 1843
    }
    break;
unknown's avatar
unknown committed
1844
  }
unknown's avatar
unknown committed
1845 1846 1847 1848 1849 1850 1851
  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;
1852 1853 1854 1855
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_create_index(thd, tables, lex->key_list);
unknown's avatar
unknown committed
1856 1857 1858
    break;

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

unknown's avatar
unknown committed
2013 2014 2015
  case SQLCOM_OPTIMIZE:
  {
    HA_CREATE_INFO create_info;
2016 2017
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
unknown's avatar
unknown committed
2018
      goto error; /* purecov: inspected */
2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029
    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
2030
      create_info.table_charset=default_charset_info;
2031 2032 2033
      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
2034
                             (ORDER *) 0,
2035 2036 2037 2038
			     0,DUP_ERROR);
    }
    else
      res = mysql_optimize_table(thd, tables, &lex->check_opt);
unknown's avatar
unknown committed
2039 2040 2041 2042 2043 2044 2045
    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;
2046
    if (select_lex->item_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
2047
    {
2048
      send_error(thd,ER_WRONG_VALUE_COUNT);
unknown's avatar
unknown committed
2049 2050
      DBUG_VOID_RETURN;
    }
2051 2052 2053 2054 2055 2056 2057
    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
2058 2059
    if (thd->net.report_error)
      res= -1;
2060 2061 2062 2063 2064 2065 2066
    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)
2067
    {
2068 2069
      send_error(thd,ER_WRONG_VALUE_COUNT);
      DBUG_VOID_RETURN;
2070 2071
    }
    {
unknown's avatar
unknown committed
2072
      const char *msg= 0;
unknown's avatar
unknown committed
2073
      if (select_lex->order_list.elements)
unknown's avatar
unknown committed
2074
	msg= "ORDER BY";
unknown's avatar
unknown committed
2075 2076
      else if (select_lex->select_limit && select_lex->select_limit !=
	       HA_POS_ERROR)
unknown's avatar
unknown committed
2077
	msg= "LIMIT";
unknown's avatar
unknown committed
2078
      if (msg)
2079
      {
2080
	net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg);
unknown's avatar
unknown committed
2081 2082
	res= 1;
	break;
2083
      }
unknown's avatar
unknown committed
2084 2085 2086 2087 2088
      res= mysql_multi_update(thd,tables,
			      &select_lex->item_list,
			      &lex->value_list,
			      select_lex->where,
			      select_lex->options,
unknown's avatar
unknown committed
2089
			      lex->duplicates, unit, select_lex);
2090
    }
unknown's avatar
unknown committed
2091 2092
    break;
  case SQLCOM_REPLACE:
2093 2094
  case SQLCOM_INSERT:
  {
2095
    my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
2096
    ulong privilege= (lex->duplicates == DUP_REPLACE ?
2097
                      INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
2098
    if (check_access(thd,privilege,tables->db,&tables->grant.privilege))
unknown's avatar
unknown committed
2099
      goto error; /* purecov: inspected */
2100
    if (grant_option && check_grant(thd,privilege,tables))
unknown's avatar
unknown committed
2101
      goto error;
2102 2103 2104 2105 2106
    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
2107
    res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
2108
                       select_lex->item_list, lex->value_list,
unknown's avatar
unknown committed
2109
                       (update ? DUP_UPDATE : lex->duplicates));
unknown's avatar
unknown committed
2110 2111
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2112
    break;
2113
  }
unknown's avatar
unknown committed
2114 2115 2116
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
2117

unknown's avatar
unknown committed
2118 2119 2120 2121
    /*
      Check that we have modify privileges for the first table and
      select privileges for the rest
    */
2122
    {
2123 2124
      ulong privilege= (lex->duplicates == DUP_REPLACE ?
                        INSERT_ACL | DELETE_ACL : INSERT_ACL);
2125 2126 2127 2128 2129 2130 2131 2132 2133 2134
      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
2135 2136

    select_result *result;
2137 2138 2139 2140
    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
2141

2142
    if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
2143
    {
unknown's avatar
unknown committed
2144
      net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
2145
      DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2146
    }
2147 2148 2149 2150 2151 2152 2153

    /* 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,
2154
				    lex->duplicates)))
2155
	res=handle_select(thd,lex,result);
unknown's avatar
unknown committed
2156 2157
      if (thd->net.report_error)
	res= -1;
2158 2159 2160
    }
    else
      res= -1;
unknown's avatar
unknown committed
2161 2162
    break;
  }
2163
  case SQLCOM_TRUNCATE:
2164 2165 2166 2167 2168 2169 2170 2171
    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())
    {
2172
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
2173 2174 2175 2176
      goto error;
    }
    res=mysql_truncate(thd,tables);
    break;
unknown's avatar
unknown committed
2177
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
2178 2179 2180 2181 2182 2183 2184
  {
    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
2185 2186
    res = mysql_delete(thd,tables, select_lex->where,
                       (ORDER*) select_lex->order_list.first,
unknown's avatar
unknown committed
2187
                       select_lex->select_limit, select_lex->options);
unknown's avatar
unknown committed
2188 2189
    if (thd->net.report_error)
      res= -1;
unknown's avatar
unknown committed
2190 2191
    break;
  }
2192
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
2193 2194 2195 2196 2197
  {
    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
2198

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

    if (!lex->local_file)
unknown's avatar
unknown committed
2435 2436 2437 2438 2439 2440
    {
      if (check_access(thd,privilege | FILE_ACL,tables->db))
	goto error;
    }
    else
    {
2441
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
unknown's avatar
unknown committed
2442
	  ! opt_local_infile)
2443
      {
2444
	send_error(thd,ER_NOT_ALLOWED_COMMAND);
2445 2446
	goto error;
      }
unknown's avatar
unknown committed
2447
      if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
2448
	  grant_option && check_grant(thd,privilege,tables))
unknown's avatar
unknown committed
2449 2450 2451 2452 2453 2454 2455
	goto error;
    }
    res=mysql_load(thd, lex->exchange, tables, lex->field_list,
		   lex->duplicates, (bool) lex->local_file, lex->lock_option);
    break;
  }
  case SQLCOM_SET_OPTION:
2456
    if (!(res=sql_set_variables(thd, &lex->var_list)))
2457
      send_ok(thd);
unknown's avatar
unknown committed
2458 2459
    break;
  case SQLCOM_UNLOCK_TABLES:
unknown's avatar
unknown committed
2460
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
2461 2462
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
2463
      end_active_trans(thd);
unknown's avatar
unknown committed
2464
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
2465 2466
    }
    if (thd->global_read_lock)
2467
      unlock_global_read_lock(thd);
2468
    send_ok(thd);
unknown's avatar
unknown committed
2469 2470
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
2471
    unlock_locked_tables(thd);
2472
    if (check_db_used(thd,tables) || end_active_trans(thd))
unknown's avatar
unknown committed
2473
      goto error;
unknown's avatar
unknown committed
2474
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables))
2475
      goto error;
unknown's avatar
unknown committed
2476
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
2477
    thd->options|= OPTION_TABLE_LOCK;
unknown's avatar
unknown committed
2478 2479 2480 2481
    if (!(res=open_and_lock_tables(thd,tables)))
    {
      thd->locked_tables=thd->lock;
      thd->lock=0;
2482
      send_ok(thd);
unknown's avatar
unknown committed
2483
    }
unknown's avatar
unknown committed
2484 2485
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
2486 2487 2488
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
2489
  {
unknown's avatar
unknown committed
2490
    if (!strip_sp(lex->name) || check_db_name(lex->name))
unknown's avatar
unknown committed
2491
    {
2492
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
2493 2494
      break;
    }
2495
    if (lower_case_table_names)
2496
      my_casedn_str(system_charset_info, lex->name);
2497 2498
    if (check_access(thd,CREATE_ACL,lex->name,0,1))
      break;
2499
    res=mysql_create_db(thd,lex->name,&lex->create_info,0);
2500 2501
    break;
  }
unknown's avatar
unknown committed
2502
  case SQLCOM_DROP_DB:
2503
  {
unknown's avatar
unknown committed
2504
    if (!strip_sp(lex->name) || check_db_name(lex->name))
unknown's avatar
unknown committed
2505
    {
2506
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
2507 2508
      break;
    }
2509
    if (lower_case_table_names)
2510
      my_casedn_str(system_charset_info, lex->name);
2511
    if (check_access(thd,DROP_ACL,lex->name,0,1))
2512
      break;
2513 2514
    if (thd->locked_tables || thd->active_transaction())
    {
2515
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
2516 2517
      goto error;
    }
unknown's avatar
unknown committed
2518
    res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0);
2519 2520
    break;
  }
2521 2522 2523 2524
  case SQLCOM_ALTER_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
2525
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
2526 2527
      break;
    }
unknown's avatar
unknown committed
2528
    if (check_access(thd,ALTER_ACL,lex->name,0,1))
2529 2530 2531
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
2532
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
2533 2534
      goto error;
    }
2535
    res=mysql_alter_db(thd,lex->name,&lex->create_info);
2536 2537
    break;
  }
unknown's avatar
unknown committed
2538 2539 2540 2541
  case SQLCOM_SHOW_CREATE_DB:
  {
    if (!strip_sp(lex->name) || check_db_name(lex->name))
    {
2542
      net_printf(thd,ER_WRONG_DB_NAME, lex->name);
unknown's avatar
unknown committed
2543 2544 2545 2546 2547 2548
      break;
    }
    if (check_access(thd,DROP_ACL,lex->name,0,1))
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
2549
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
unknown's avatar
unknown committed
2550 2551
      goto error;
    }
unknown's avatar
unknown committed
2552
    res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
unknown's avatar
unknown committed
2553 2554
    break;
  }
unknown's avatar
unknown committed
2555 2556 2557 2558 2559
  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)))
2560
      send_ok(thd);
unknown's avatar
unknown committed
2561 2562 2563 2564 2565 2566 2567 2568 2569
#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)))
2570
      send_ok(thd);
unknown's avatar
unknown committed
2571 2572 2573 2574
#else
    res= -1;
#endif
    break;
2575 2576 2577 2578 2579 2580 2581 2582 2583
  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
2584 2585 2586 2587
    /*
      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
    */
2588 2589 2590 2591 2592 2593 2594 2595 2596 2597

    if (thd->user)				// If not replication
    {
      LEX_USER *user;
      List_iterator <LEX_USER> user_list(lex->users_list);
      while ((user=user_list++))
      {
	if (user->password.str &&
	    (strcmp(thd->user,user->user.str) ||
	     user->host.str &&
unknown's avatar
unknown committed
2598
	     my_strcasecmp(system_charset_info,
2599
                           user->host.str, thd->host_or_ip)))
2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613
	{
	  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
2614 2615 2616
      if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
				    lex->grant,
				    lex->sql_command == SQLCOM_REVOKE)))
2617
      {
2618
	mysql_update_log.write(thd, thd->query, thd->query_length);
2619 2620
	if (mysql_bin_log.is_open())
	{
2621
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
2622 2623 2624 2625 2626 2627 2628 2629
	  mysql_bin_log.write(&qinfo);
	}
      }
    }
    else
    {
      if (lex->columns.elements)
      {
2630
	send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE);
2631 2632 2633 2634 2635 2636 2637
	res=1;
      }
      else
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
2638
	mysql_update_log.write(thd, thd->query, thd->query_length);
2639 2640
	if (mysql_bin_log.is_open())
	{
2641
	  Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
2642 2643
	  mysql_bin_log.write(&qinfo);
	}
2644
	if (mqh_used && lex->sql_command == SQLCOM_GRANT)
2645
	{
unknown's avatar
unknown committed
2646 2647 2648
	  List_iterator <LEX_USER> str_list(lex->users_list);
	  LEX_USER *user;
	  while ((user=str_list++))
2649
	    reset_mqh(thd,user);
2650
	}
2651 2652 2653 2654
      }
    }
    break;
  }
unknown's avatar
unknown committed
2655
  case SQLCOM_FLUSH:
unknown's avatar
unknown committed
2656
  case SQLCOM_RESET:
unknown's avatar
unknown committed
2657
    if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
unknown's avatar
unknown committed
2658
      goto error;
unknown's avatar
unknown committed
2659
    if (reload_acl_and_cache(thd, lex->type, tables))
2660
      send_error(thd,0);
unknown's avatar
unknown committed
2661
    else
2662
      send_ok(thd);
unknown's avatar
unknown committed
2663 2664 2665 2666 2667 2668
    break;
  case SQLCOM_KILL:
    kill_one_thread(thd,lex->thread_id);
    break;
  case SQLCOM_SHOW_GRANTS:
    res=0;
2669 2670
    if ((thd->priv_user &&
	 !strcmp(thd->priv_user,lex->grant_user->user.str)) ||
2671
	!check_access(thd, SELECT_ACL, "mysql",0,1))
unknown's avatar
unknown committed
2672 2673 2674 2675
    {
      res = mysql_show_grants(thd,lex->grant_user);
    }
    break;
2676
  case SQLCOM_HA_OPEN:
2677 2678
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables))
2679 2680 2681 2682 2683 2684 2685 2686 2687
      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:
2688 2689
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL, tables))
2690
      goto error;
unknown's avatar
unknown committed
2691
    res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
2692 2693
			lex->insert_list, lex->ha_rkey_mode, select_lex->where,
			select_lex->select_limit, select_lex->offset_limit);
2694 2695
    break;

unknown's avatar
unknown committed
2696
  case SQLCOM_BEGIN:
unknown's avatar
unknown committed
2697 2698 2699 2700 2701 2702
    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
2703 2704 2705 2706 2707 2708
    if (end_active_trans(thd))
    {
      res= -1;
    }
    else
    {
2709
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
unknown's avatar
unknown committed
2710 2711
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
2712
      send_ok(thd);
unknown's avatar
unknown committed
2713
    }
unknown's avatar
unknown committed
2714 2715
    break;
  case SQLCOM_COMMIT:
2716 2717 2718 2719 2720
    /*
      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
2721
  {
2722
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
2723 2724
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
unknown's avatar
unknown committed
2725
    {
2726
      send_ok(thd);
unknown's avatar
unknown committed
2727
    }
unknown's avatar
unknown committed
2728 2729 2730
    else
      res= -1;
    break;
unknown's avatar
unknown committed
2731
  }
unknown's avatar
unknown committed
2732 2733 2734
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
2735 2736
    {
      if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
2737
	send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
2738
      else
2739
	send_ok(thd);
2740
    }
unknown's avatar
unknown committed
2741 2742
    else
      res= -1;
2743
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
unknown's avatar
unknown committed
2744
    break;
2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822
  case SQLCOM_CREATE_PROCEDURE:
    if (!lex->sphead)
      res= -1;
    else
    {
      res= lex->sphead->create(thd);
      if (res < 0)
      {
	// QQ Error!
      }
      send_ok(thd);
    }
    break;
  case SQLCOM_CALL:
    {
      Item_string *s;
      sp_head *sp;

      s= (Item_string*)lex->value_list.head();
      sp= sp_find(thd, s);
      if (! sp)
      {
	// QQ Error!
	res= -1;
      }
      else
      {
	res= sp->execute(thd);
	if (res == 0)
	  send_ok(thd);
      }
    }
    break;
  case SQLCOM_ALTER_PROCEDURE:
    {
      Item_string *s;
      sp_head *sp;

      s= (Item_string*)lex->value_list.head();
      sp= sp_find(thd, s);
      if (! sp)
      {
	// QQ Error!
	res= -1;
      }
      else
      {
	/* QQ This is an no-op right now, since we haven't
	      put the characteristics in yet. */
	send_ok(thd);
      }
    }
    break;
  case SQLCOM_DROP_PROCEDURE:
    {
      Item_string *s;
      sp_head *sp;

      s = (Item_string*)lex->value_list.head();
      sp = sp_find(thd, s);
      if (! sp)
      {
	// QQ Error!
	res= -1;
      }
      else
      {
	String *name = s->const_string();

	res= sp_drop(thd, name->c_ptr(), name->length());
	if (res < 0)
	{
	  // QQ Error!
	}
	send_ok(thd);
      }
    }
    break;
unknown's avatar
unknown committed
2823
  default:					/* Impossible */
2824
    send_ok(thd);
unknown's avatar
unknown committed
2825 2826 2827 2828
    break;
  }
  thd->proc_info="query end";			// QQ
  if (res < 0)
2829
    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
unknown's avatar
unknown committed
2830 2831 2832 2833 2834 2835 2836

error:
  DBUG_VOID_RETURN;
}


/****************************************************************************
unknown's avatar
unknown committed
2837 2838 2839 2840 2841 2842 2843
  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
2844 2845 2846
****************************************************************************/

bool
unknown's avatar
unknown committed
2847
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
2848
	     bool dont_check_global_grants, bool no_errors)
unknown's avatar
unknown committed
2849
{
unknown's avatar
unknown committed
2850 2851 2852 2853
  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
2854 2855 2856 2857 2858
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

2859
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
2860
  {
2861
    if (!no_errors)
2862
      send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
unknown's avatar
unknown committed
2863
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
2864 2865 2866 2867 2868
  }

  if ((thd->master_access & want_access) == want_access)
  {
    *save_priv=thd->master_access;
unknown's avatar
unknown committed
2869
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
2870
  }
2871
  if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
2872
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
2873
  {						// We can never grant this
2874
    if (!no_errors)
2875
      net_printf(thd,ER_ACCESS_DENIED_ERROR,
2876 2877 2878
		 thd->priv_user,
		 thd->host_or_ip,
		 thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
unknown's avatar
unknown committed
2879
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
2880 2881 2882
  }

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

unknown's avatar
unknown committed
2885 2886 2887 2888 2889
  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;
2890 2891
  // Remove SHOW attribute and access rights we already have
  want_access &= ~(thd->master_access | EXTRA_ACL);
unknown's avatar
unknown committed
2892
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
2893 2894

  /* grant_option is set if there exists a single table or column grant */
unknown's avatar
unknown committed
2895
  if (db_access == want_access ||
2896 2897
      ((grant_option && !dont_check_global_grants) &&
       !(want_access & ~TABLE_ACLS)))
unknown's avatar
unknown committed
2898
    DBUG_RETURN(FALSE);				/* Ok */
2899
  if (!no_errors)
2900
    net_printf(thd,ER_DBACCESS_DENIED_ERROR,
2901 2902 2903
	       thd->priv_user,
	       thd->host_or_ip,
	       db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
unknown's avatar
unknown committed
2904
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
2905 2906 2907
}


unknown's avatar
unknown committed
2908 2909 2910
/* 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
2911
{
unknown's avatar
unknown committed
2912 2913 2914 2915
  char command[128];
  if ((thd->master_access & want_access) == want_access)
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
2916
  net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
unknown's avatar
unknown committed
2917 2918
	     command);
  return 1;
unknown's avatar
unknown committed
2919 2920 2921
}


unknown's avatar
unknown committed
2922
/*
unknown's avatar
unknown committed
2923 2924
  Check the privilege for all used tables.  Table privileges are cached
  in the table list for GRANT checking
unknown's avatar
unknown committed
2925 2926
*/

2927
bool
unknown's avatar
unknown committed
2928
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
2929
		   bool no_errors)
unknown's avatar
unknown committed
2930
{
unknown's avatar
unknown committed
2931 2932
  uint found=0;
  ulong found_access=0;
unknown's avatar
unknown committed
2933 2934 2935
  TABLE_LIST *org_tables=tables;
  for (; tables ; tables=tables->next)
  {
2936
    if (tables->derived || (tables->table && (int)tables->table->tmp_table))
unknown's avatar
unknown committed
2937
      continue;
unknown's avatar
unknown committed
2938 2939
    if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
	thd->db)
unknown's avatar
unknown committed
2940
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
2941
    else if (tables->db && tables->db == thd->db)
unknown's avatar
unknown committed
2942 2943 2944 2945 2946
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
2947 2948
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
			 0, no_errors))
unknown's avatar
unknown committed
2949 2950
	  return TRUE;				// Access denied
	found_access=tables->grant.privilege;
unknown's avatar
unknown committed
2951
	found=1;
unknown's avatar
unknown committed
2952 2953
      }
    }
2954
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
2955
			  0, no_errors))
2956
      return TRUE;
unknown's avatar
unknown committed
2957 2958
  }
  if (grant_option)
2959
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
2960
		       test(want_access & EXTRA_ACL), no_errors);
unknown's avatar
unknown committed
2961 2962 2963 2964
  return FALSE;
}


unknown's avatar
unknown committed
2965
static bool check_db_used(THD *thd,TABLE_LIST *tables)
unknown's avatar
unknown committed
2966 2967 2968 2969 2970 2971 2972
{
  for (; tables ; tables=tables->next)
  {
    if (!tables->db)
    {
      if (!(tables->db=thd->db))
      {
2973
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
unknown's avatar
unknown committed
2974 2975 2976 2977 2978 2979 2980 2981
	return TRUE;				/* purecov: tested */
      }
    }
  }
  return FALSE;
}


2982 2983
static bool check_merge_table_access(THD *thd, char *db,
				     TABLE_LIST *table_list)
2984 2985 2986 2987
{
  int error=0;
  if (table_list)
  {
2988
    /* Check that all tables use the current database */
2989 2990
    TABLE_LIST *tmp;
    for (tmp=table_list; tmp ; tmp=tmp->next)
2991 2992 2993
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
unknown's avatar
unknown committed
2994
      else if (strcmp(tmp->db,db))
2995
      {
2996
	send_error(thd,ER_UNION_TABLES_IN_DIFFERENT_DIR);
2997 2998 2999
	return 1;
      }
    }
3000 3001 3002 3003 3004 3005 3006
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
			     table_list);
  }
  return error;
}


unknown's avatar
unknown committed
3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063
/****************************************************************************
	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;
}


/****************************************************************************
3064
	Initialize global thd variables needed for query
unknown's avatar
unknown committed
3065 3066
****************************************************************************/

3067
void
unknown's avatar
unknown committed
3068 3069 3070
mysql_init_query(THD *thd)
{
  DBUG_ENTER("mysql_init_query");
3071 3072 3073 3074 3075 3076
  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
3077
  lex->unit.global_parameters= lex->unit.slave= lex->current_select=
3078
    lex->all_selects_list= &lex->select_lex;
3079 3080
  lex->select_lex.master= &lex->unit;
  lex->select_lex.prev= &lex->unit.slave;
3081 3082
  lex->select_lex.link_next= 0;
  lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
3083 3084
  lex->olap=lex->describe=0;
  lex->derived_tables= false;
unknown's avatar
unknown committed
3085
  thd->check_loops_counter= thd->select_number=
unknown's avatar
unknown committed
3086
    lex->select_lex.select_number= 1;
unknown's avatar
unknown committed
3087
  thd->free_list= 0;
3088
  thd->total_warn_count=0;			// Warnings for this query
unknown's avatar
unknown committed
3089 3090
  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
3091
  thd->fatal_error= thd->rand_used= 0;
3092
  thd->possible_loops= 0;
unknown's avatar
unknown committed
3093 3094 3095
  DBUG_VOID_RETURN;
}

3096 3097 3098
void
mysql_init_select(LEX *lex)
{
unknown's avatar
unknown committed
3099
  SELECT_LEX *select_lex= lex->current_select->select_lex();
3100
  DBUG_ASSERT(select_lex->linkage != GLOBAL_OPTIONS_TYPE);
unknown's avatar
unknown committed
3101
  select_lex->init_select();
unknown's avatar
unknown committed
3102
  select_lex->master_unit()->select_limit= select_lex->select_limit=
unknown's avatar
unknown committed
3103
    lex->thd->variables.select_limit;
3104 3105 3106 3107 3108 3109
  if (select_lex == &lex->select_lex)
  {
    lex->exchange= 0;
    lex->result= 0;
    lex->proc_list.first= 0;
  }
3110 3111
}

3112

unknown's avatar
unknown committed
3113
bool
unknown's avatar
unknown committed
3114
mysql_new_select(LEX *lex, bool move_down)
3115
{
3116
  SELECT_LEX *select_lex = new SELECT_LEX();
unknown's avatar
unknown committed
3117
  select_lex->select_number= ++lex->thd->select_number;
unknown's avatar
unknown committed
3118 3119
  if (!select_lex)
    return 1;
unknown's avatar
unknown committed
3120 3121 3122 3123 3124
  select_lex->init_query();
  select_lex->init_select();
  if (move_down)
  {
    /* first select_lex of subselect or derived table */
3125
    SELECT_LEX_UNIT *unit= new SELECT_LEX_UNIT();
unknown's avatar
unknown committed
3126 3127 3128 3129
    if (!unit)
      return 1;
    unit->init_query();
    unit->init_select();
3130
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
3131 3132 3133
    select_lex->include_down(unit);
  }
  else
3134
    select_lex->include_neighbour(lex->current_select);
unknown's avatar
unknown committed
3135

3136
  select_lex->master_unit()->global_parameters= select_lex;
3137
  DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE);
3138
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
3139
  lex->current_select= select_lex;
unknown's avatar
unknown committed
3140
  return 0;
3141
}
unknown's avatar
unknown committed
3142

3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165
/*
  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
3166
  add_item_to_list(lex->thd, get_system_var(OPT_SESSION, tmp));
3167 3168 3169
  DBUG_VOID_RETURN;
}

3170

unknown's avatar
unknown committed
3171 3172
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
3173
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
3174
  mysql_init_select(lex);
3175
  lex->select_lex.select_limit= lex->unit.select_limit_cnt=
unknown's avatar
unknown committed
3176
    HA_POS_ERROR;
unknown's avatar
unknown committed
3177
  lex->auxilliary_table_list= lex->select_lex.table_list;
3178
  lex->select_lex.init_query();
unknown's avatar
unknown committed
3179
}
unknown's avatar
unknown committed
3180

3181

unknown's avatar
unknown committed
3182
void
unknown's avatar
unknown committed
3183
mysql_parse(THD *thd, char *inBuf, uint length)
unknown's avatar
unknown committed
3184 3185 3186 3187 3188
{
  DBUG_ENTER("mysql_parse");

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

unknown's avatar
unknown committed
3191
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
unknown's avatar
unknown committed
3192 3193
  {
    LEX *lex=lex_start(thd, (uchar*) inBuf, length);
3194
    if (!yyparse((void *)thd) && ! thd->fatal_error)
unknown's avatar
unknown committed
3195
    {
3196
      if (mqh_used && thd->user_connect &&
3197
	  check_mqh(thd, lex->sql_command))
3198 3199 3200 3201 3202
      {
	thd->net.error = 0;
      }
      else
      {
unknown's avatar
unknown committed
3203 3204 3205 3206 3207 3208 3209
	if (thd->net.report_error)
	  send_error(thd, 0, NullS);
	else
	{
	  mysql_execute_command(thd);
	  query_cache_end_of_result(&thd->net);
	}
3210
      }
unknown's avatar
unknown committed
3211 3212
    }
    else
3213 3214 3215
    {
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
			 thd->fatal_error));
unknown's avatar
unknown committed
3216
      query_cache_abort(&thd->net);
3217
    }
unknown's avatar
unknown committed
3218
    thd->proc_info="freeing items";
3219
    free_items(thd->free_list);  /* Free strings used by items */
unknown's avatar
unknown committed
3220 3221
    lex_end(lex);
  }
unknown's avatar
unknown committed
3222 3223 3224 3225 3226 3227 3228 3229 3230
  DBUG_VOID_RETURN;
}


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

unknown's avatar
unknown committed
3231
bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
unknown's avatar
unknown committed
3232
		       char *length, char *decimals,
3233 3234
		       uint type_modifier,
		       Item *default_value, Item *comment,
3235
		       char *change, TYPELIB *interval, CHARSET_INFO *cs)
unknown's avatar
unknown committed
3236 3237 3238 3239
{
  register create_field *new_field;
  LEX  *lex= &thd->lex;
  uint allowed_type_modifier=0;
3240
  char warn_buff[MYSQL_ERRMSG_SIZE];
unknown's avatar
unknown committed
3241 3242 3243 3244
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
3245
    net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
unknown's avatar
unknown committed
3246 3247 3248 3249 3250
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
3251
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
unknown's avatar
unknown committed
3252 3253 3254 3255 3256 3257
				    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));
3258
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF,
unknown's avatar
unknown committed
3259 3260 3261 3262 3263 3264 3265 3266 3267
				    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)
    {
3268
      net_printf(thd,ER_INVALID_DEFAULT,field_name);
unknown's avatar
unknown committed
3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287
      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;
3288
  new_field->charset=cs;
unknown's avatar
unknown committed
3289

3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300
  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
3301 3302 3303 3304 3305 3306
  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 &&
3307
      new_field->length < new_field->decimals+1 &&
unknown's avatar
unknown committed
3308
      new_field->decimals != NOT_FIXED_DEC)
3309
    new_field->length=new_field->decimals+1; /* purecov: inspected */
unknown's avatar
unknown committed
3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332

  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:
unknown's avatar
unknown committed
3333
  case FIELD_TYPE_GEOMETRY:
unknown's avatar
unknown committed
3334 3335 3336 3337 3338 3339 3340 3341
    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;
3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352
  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
3353 3354 3355 3356
  case FIELD_TYPE_BLOB:
  case FIELD_TYPE_TINY_BLOB:
  case FIELD_TYPE_LONG_BLOB:
  case FIELD_TYPE_MEDIUM_BLOB:
3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370
    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
3371 3372 3373 3374 3375 3376
    if (default_value)				// Allow empty as default value
    {
      String str,*res;
      res=default_value->val_str(&str);
      if (res->length())
      {
3377
	net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
unknown's avatar
unknown committed
3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396
	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)
      {
3397
	net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
unknown's avatar
unknown committed
3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450
	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)
      {
3451
	net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
unknown's avatar
unknown committed
3452 3453 3454 3455 3456 3457 3458 3459
	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
3460 3461 3462
      {
	new_field->length+=(uint) strip_sp((char*) *pos)+1;
      }
unknown's avatar
unknown committed
3463 3464 3465 3466 3467 3468 3469 3470 3471 3472
      new_field->length--;
      set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
      if (default_value)
      {
	thd->cuted_fields=0;
	String str,*res;
	res=default_value->val_str(&str);
	(void) find_set(interval,res->ptr(),res->length());
	if (thd->cuted_fields)
	{
3473
	  net_printf(thd,ER_INVALID_DEFAULT,field_name);
unknown's avatar
unknown committed
3474 3475 3476 3477 3478 3479 3480 3481 3482
	  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
3483
      new_field->length=(uint) strip_sp((char*) interval->type_names[0]);
unknown's avatar
unknown committed
3484 3485
      for (const char **pos=interval->type_names+1; *pos ; pos++)
      {
unknown's avatar
unknown committed
3486
	uint length=(uint) strip_sp((char*) *pos);
unknown's avatar
unknown committed
3487 3488 3489 3490 3491 3492 3493 3494 3495
	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()))
	{
3496
	  net_printf(thd,ER_INVALID_DEFAULT,field_name);
unknown's avatar
unknown committed
3497 3498 3499 3500 3501 3502 3503 3504 3505
	  DBUG_RETURN(1);
	}
      }
      break;
    }
  }

  if (new_field->length >= MAX_FIELD_WIDTH ||
      (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
unknown's avatar
unknown committed
3506
       type != FIELD_TYPE_STRING && type != FIELD_TYPE_VAR_STRING))
unknown's avatar
unknown committed
3507
  {
3508
    net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
unknown's avatar
unknown committed
3509 3510 3511 3512 3513 3514
	       MAX_FIELD_WIDTH-1);		/* purecov: inspected */
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
3515
    net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
unknown's avatar
unknown committed
3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536
    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
3537
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
3538 3539 3540 3541
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
3542
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
3543 3544 3545 3546 3547
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
unknown's avatar
unknown committed
3548
  thd->lex.proc_list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
3549 3550 3551 3552 3553 3554 3555 3556
  return 0;
}


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

static void remove_escape(char *name)
{
3557 3558
  if (!*name)					// For empty DB names
    return;
unknown's avatar
unknown committed
3559 3560
  char *to;
#ifdef USE_MB
unknown's avatar
unknown committed
3561
  char *strend=name+(uint) strlen(name);
unknown's avatar
unknown committed
3562 3563 3564 3565 3566 3567
#endif
  for (to=name; *name ; name++)
  {
#ifdef USE_MB
    int l;
/*    if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
3568 3569
    if (use_mb(system_charset_info) &&
        (l = my_ismbchar(system_charset_info, name, strend)))
unknown's avatar
unknown committed
3570 3571 3572 3573 3574 3575 3576 3577
    {
	while (l--)
	    *to++ = *name++;
	name--;
	continue;
    }
#endif
    if (*name == '\\' && name[1])
unknown's avatar
unknown committed
3578
      name++;					// Skip '\\'
unknown's avatar
unknown committed
3579 3580 3581 3582 3583 3584 3585 3586 3587 3588
    *to++= *name;
  }
  *to=0;
}

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


unknown's avatar
unknown committed
3589
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
3590 3591 3592 3593
{
  ORDER *order;
  Item	**item_ptr;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
3594
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
3595 3596 3597 3598 3599 3600 3601
    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
3602
  list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
3603 3604 3605 3606
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
3607 3608
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
3609 3610 3611 3612 3613
					     LEX_STRING *alias,
					     bool updating,
					     thr_lock_type flags,
					     List<String> *use_index,
					     List<String> *ignore_index)
unknown's avatar
unknown committed
3614 3615 3616 3617 3618 3619 3620 3621 3622
{
  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
3623 3624
      (table->table.length &&
       check_table_name(table->table.str,table->table.length)) ||
3625
      table->db.str && check_db_name(table->db.str))
unknown's avatar
unknown committed
3626
  {
3627
    net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str);
unknown's avatar
unknown committed
3628 3629 3630 3631
    DBUG_RETURN(0);
  }

  if (!alias)					/* Alias is case sensitive */
3632 3633 3634 3635 3636 3637
  {
    if (table->sel)
    {
      net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
      DBUG_RETURN(0);
    }
3638
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
3639
      DBUG_RETURN(0);
3640
  }
unknown's avatar
unknown committed
3641
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
3642
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
3643
  if (table->db.str)
3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654
  {
    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
  {
3655 3656
    /* The following can't be "" as we may do 'casedn_str()' on it */
    ptr->db= empty_c_string;
3657 3658
    ptr->db_length= 0;
  }
unknown's avatar
unknown committed
3659

3660
  ptr->alias= alias_str;
unknown's avatar
unknown committed
3661 3662
  if (lower_case_table_names)
  {
3663 3664
    my_casedn_str(system_charset_info,ptr->db);
    my_casedn_str(system_charset_info,table->table.str);
unknown's avatar
unknown committed
3665 3666
  }
  ptr->real_name=table->table.str;
3667
  ptr->real_name_length=table->table.length;
unknown's avatar
unknown committed
3668
  ptr->lock_type=flags;
3669
  ptr->updating=updating;
unknown's avatar
unknown committed
3670
  ptr->derived= (SELECT_LEX_UNIT *) table->sel;
unknown's avatar
unknown committed
3671
  if (use_index)
unknown's avatar
unknown committed
3672
    ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
unknown's avatar
unknown committed
3673 3674
					       sizeof(*use_index));
  if (ignore_index)
unknown's avatar
unknown committed
3675 3676
    ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index,
						   sizeof(*ignore_index));
unknown's avatar
unknown committed
3677 3678

  /* check that used name is unique */
unknown's avatar
unknown committed
3679
  if (flags != TL_IGNORE)
unknown's avatar
unknown committed
3680
  {
3681
    for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
3682
	 tables ;
unknown's avatar
unknown committed
3683
	 tables=tables->next)
unknown's avatar
unknown committed
3684
    {
3685
      if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
3686
      {
3687
	net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
unknown's avatar
unknown committed
3688 3689
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
3690 3691
    }
  }
unknown's avatar
unknown committed
3692
  table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
unknown's avatar
unknown committed
3693 3694 3695
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
3696

unknown's avatar
unknown committed
3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709
/*
  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
3710
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
3711 3712 3713 3714 3715 3716
{
  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
3717
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
unknown's avatar
unknown committed
3718 3719 3720 3721 3722 3723 3724 3725 3726
       tables ;
       tables=tables->next)
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
3727

unknown's avatar
unknown committed
3728 3729
void add_join_on(TABLE_LIST *b,Item *expr)
{
3730
  if (expr)
3731
  {
3732 3733 3734 3735 3736 3737 3738 3739
    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();
3740
  }
unknown's avatar
unknown committed
3741 3742 3743 3744 3745 3746 3747 3748
}


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

unknown's avatar
unknown committed
3749
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
unknown's avatar
unknown committed
3750 3751 3752 3753 3754 3755
{
  bool result=0;

  select_errors=0;				/* Write if more errors */
  if (options & REFRESH_GRANT)
  {
3756
    acl_reload(thd);
unknown's avatar
unknown committed
3757
    grant_reload(thd);
3758
    if (mqh_used)
3759
      reset_mqh(thd,(LEX_USER *) NULL,true);
unknown's avatar
unknown committed
3760 3761 3762
  }
  if (options & REFRESH_LOG)
  {
unknown's avatar
unknown committed
3763 3764 3765 3766
    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
3767 3768 3769
    if (ha_flush_logs())
      result=1;
  }
unknown's avatar
unknown committed
3770
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
3771 3772
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
3773
    query_cache.pack();				// FLUSH QUERY CACHE
unknown's avatar
unknown committed
3774 3775 3776 3777
    options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
3778
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
3779
  }
unknown's avatar
unknown committed
3780
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
3781 3782
  if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
  {
3783
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
3784
    {
3785 3786
      if (lock_global_read_lock(thd))
	return 1;
unknown's avatar
unknown committed
3787
    }
unknown's avatar
unknown committed
3788
    result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
unknown's avatar
unknown committed
3789 3790 3791 3792 3793 3794 3795 3796
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
  if (options & REFRESH_STATUS)
    refresh_status();
  if (options & REFRESH_THREADS)
    flush_thread_cache();
  if (options & REFRESH_MASTER)
3797 3798
    if (reset_master(thd))
      result=1;
unknown's avatar
unknown committed
3799
#ifdef OPENSSL
3800 3801 3802 3803 3804 3805
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
3806 3807 3808
 if (options & REFRESH_SLAVE)
 {
   LOCK_ACTIVE_MI;
3809
   if (reset_slave(thd, active_mi))
3810 3811 3812 3813
     result=1;
   UNLOCK_ACTIVE_MI;
 }
 if (options & REFRESH_USER_RESOURCES)
3814
   reset_mqh(thd,(LEX_USER *) NULL);
3815
 return result;
unknown's avatar
unknown committed
3816 3817 3818
}


3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830
/*
  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
*/

3831
void kill_one_thread(THD *thd, ulong id)
unknown's avatar
unknown committed
3832 3833 3834
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
3835 3836
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
3837 3838 3839 3840
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
3841 3842
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
3843 3844 3845
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858
  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
3859
  if (!error)
3860
    send_ok(thd);
unknown's avatar
unknown committed
3861
  else
3862
    net_printf(thd,error,id);
unknown's avatar
unknown committed
3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878
}

/* 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);
}
3879 3880 3881 3882


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

unknown's avatar
unknown committed
3883
static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
3884
{
3885
  char buff[FN_REFLEN],*ptr, *end;
3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897
  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);
3898
  end=convert_dirname(buff, *filename_ptr, NullS);
unknown's avatar
unknown committed
3899
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
3900 3901
    return 1;					// End of memory
  *filename_ptr=ptr;
3902
  strxmov(ptr,buff,table_name,NullS);
3903 3904
  return 0;
}
3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919

/*
  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;
3920
  if (thd->lex.current_select != &thd->lex.select_lex)
3921 3922 3923 3924
  {
    char command[80];
    strmake(command, thd->lex.yylval->symbol.str,
	    min(thd->lex.yylval->symbol.length, sizeof(command)-1));
3925
    net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
3926 3927 3928 3929
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959

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