You need to sign in or sign up before continuing.
sql_parse.cc 110 KB
Newer Older
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1
/* Copyright (C) 2000 MySQL AB
2

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

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

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

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

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

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

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

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

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

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

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",
74
  "Binlog Dump","Table Dump",  "Connect Out", "Register Slave",
75
  "Prepare", "Prepare Execute", "Long Data", "Close stmt"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
76 77
};

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

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

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


124 125 126
static HASH hash_user_connections;
extern  pthread_mutex_t LOCK_user_conn;

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

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

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

179
}
180 181 182


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

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

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

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

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

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
266
  if (db && db[0])
267 268
  {
    bool error=test(mysql_change_db(thd,db));
269 270
    if (error && thd->user_connect)
      decrease_user_connections(thd->user_connect);
peter@mysql.com's avatar
peter@mysql.com committed
271
    return error;
272
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
273
  else
274
    send_ok(thd);				// Ready to handle questions
bk@work.mysql.com's avatar
bk@work.mysql.com committed
275 276 277
  return 0;					// ok
}

278

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

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

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

peter@mysql.com's avatar
peter@mysql.com committed
296
void init_max_user_conn(void)
297
{
298 299
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
		   0,0,
300
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
301
		   0);
302 303 304
}


305
static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
306
{
307
  int error=0;
308
  DBUG_ENTER("check_for_max_user_connections");
peter@mysql.com's avatar
peter@mysql.com committed
309

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


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

344

345 346 347 348 349
void free_max_user_conn(void)
{
  hash_free(&hash_user_connections);
}

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

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


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

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

392

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

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

436

437
static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them=false)
438 439
{

440
  (void) pthread_mutex_lock(&LOCK_user_conn);
peter@mysql.com's avatar
peter@mysql.com committed
441
  if (lu)  // for GRANT
442
  {
443
    USER_CONN *uc;
444
    uint temp_len=lu->user.length+lu->host.length+2;
445 446
    char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];

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

474

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

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

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

527
  ulong pkt_len=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
528
  {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
529
    /* buff[] needs to big enough to hold the server_version variable */
peter@mysql.com's avatar
peter@mysql.com committed
530
    char buff[SERVER_VERSION_LENGTH +
531
    SCRAMBLE_LENGTH+64],*end;
peter@mysql.com's avatar
peter@mysql.com committed
532
    int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
533
                       CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION;
534

535 536 537 538 539
    if (opt_using_transactions)
      client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
    client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
540 541 542 543
#ifdef HAVE_OPENSSL
    if (ssl_acceptor_fd)
      client_flags |= CLIENT_SSL;       /* Wow, SSL is avalaible! */
#endif /* HAVE_OPENSSL */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
544

545
    end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
546 547 548 549 550
    int4store((uchar*) end,thd->thread_id);
    end+=4;
    memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
    end+=SCRAMBLE_LENGTH +1;
    int2store(end,client_flags);
551
    end[2]=(char) MY_CHARSET_CURRENT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
552 553 554
    int2store(end+3,thd->server_status);
    bzero(end+5,13);
    end+=18;
peter@mysql.com's avatar
peter@mysql.com committed
555

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

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

611
  thd->max_client_packet_length=uint3korr(net->read_pos+2);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
612 613 614
  char *user=   (char*) net->read_pos+5;
  char *passwd= strend(user)+1;
  char *db=0;
peter@mysql.com's avatar
peter@mysql.com committed
615 616 617
  if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
     db=strend(passwd)+1;

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
622
  if (thd->client_capabilities & CLIENT_INTERACTIVE)
623
     thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
624
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
625 626
       opt_using_transactions)
  thd->net.return_status= &thd->server_status;
627
  net->read_timeout=(uint) thd->variables.net_read_timeout;
peter@mysql.com's avatar
peter@mysql.com committed
628

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

peter@mysql.com's avatar
peter@mysql.com committed
631 632
  ACL_USER* cached_user;
  uint cur_priv_version;
peter@mysql.com's avatar
peter@mysql.com committed
633

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

637 638
  /* Store information if we used password. passwd will be dammaged */
  bool using_password=test(passwd[0]);
peter@mysql.com's avatar
peter@mysql.com committed
639

640 641
  /* Check user permissions. If password failure we'll get scramble back */
  if (check_user(thd,COM_CONNECT, user, passwd, db, 1, simple_connect,
peter@mysql.com's avatar
peter@mysql.com committed
642
      prepared_scramble,0,using_password,&cur_priv_version,&cached_user)<0)
peter@mysql.com's avatar
peter@mysql.com committed
643
  {
644 645
    /* If The client is old we just have to return error */
    if (simple_connect)
peter@mysql.com's avatar
peter@mysql.com committed
646 647
      return -1;

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

650 651 652
    char tmp_user[USERNAME_LENGTH+1];
    char tmp_db[NAME_LEN+1];

peter@mysql.com's avatar
peter@mysql.com committed
653
    tmp_user[0]=0;
654
    if (user)
peter@mysql.com's avatar
peter@mysql.com committed
655 656 657
      strmake(tmp_user,user,USERNAME_LENGTH);

    tmp_db[0]=0;  
658
    if (db)
peter@mysql.com's avatar
peter@mysql.com committed
659 660
      strmake(tmp_db,db,NAME_LEN);

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


pthread_handler_decl(handle_one_connection,arg)
{
  THD *thd=(THD*) arg;
  uint launch_time  =
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
695
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
696 697 698 699 700
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status );

  pthread_detach_this_thread();

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

712 713 714 715 716 717 718
  /*
    handle_one_connection() is the only way a thread would start
    and would always be on top of the stack, therefore, the thread
    stack always starts at the address of the first local variable
    of handle_one_connection, which is thd. We need to know the
    start of the stack so that we could check for stack overruns.
  */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
719 720 721 722
  DBUG_PRINT("info", ("handle_one_connection called by thread %d\n",
		      thd->thread_id));
  // now that we've called my_thread_init(), it is safe to call DBUG_*

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

756
    if ((ulong) thd->variables.max_join_size == (ulonglong) HA_POS_ERROR)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
757 758 759 760
      thd->options |= OPTION_BIG_SELECTS;
    if (thd->client_capabilities & CLIENT_COMPRESS)
      net->compress=1;				// Use compression

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
761
    thd->proc_info=0;				// Remove 'login'
762
    thd->command=COM_SLEEP;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
763 764
    thd->version=refresh_version;
    thd->set_time();
765 766 767
    init_sql_alloc(&thd->mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
    init_sql_alloc(&thd->transaction.mem_root,
		   TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
768 769 770 771 772
    while (!net->error && net->vio != 0 && !thd->killed)
    {
      if (do_command(thd))
	break;
    }
773 774
    if (thd->user_connect)
      decrease_user_connections(thd->user_connect);
775
    free_root(&thd->mem_root,MYF(0));
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
776
    if (net->error && net->vio != 0 && net->report_error)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
777
    {
778
      if (!thd->killed && thd->variables.log_warnings)
779 780 781 782 783 784
	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)));
785
      send_error(thd,net->last_errno,NullS);
786
      statistic_increment(aborted_threads,&LOCK_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
787
    }
peter@mysql.com's avatar
peter@mysql.com committed
788

bk@work.mysql.com's avatar
bk@work.mysql.com committed
789 790 791 792 793 794 795 796 797 798 799 800 801
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 */
}

802 803 804 805
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
806

807
extern "C" pthread_handler_decl(handle_bootstrap,arg)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
808
{
809 810 811
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
812

813
  /* The following must be called before DBUG_ENTER */
814
  if (my_thread_init() || thd->store_globals())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
815 816
  {
    close_connection(&thd->net,ER_OUT_OF_RESOURCES);
817 818
    thd->fatal_error=1;
    goto end;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
819
  }
820 821 822 823
  DBUG_ENTER("handle_bootstrap");

  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
824
#if !defined(__WIN__) && !defined(OS2)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
825
  sigset_t set;
826 827 828 829
  VOID(sigemptyset(&set));			// Get mask in use
  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));


bk@work.mysql.com's avatar
bk@work.mysql.com committed
830 831
#endif

832
  if ((ulong) thd->variables.max_join_size == (ulonglong) HA_POS_ERROR)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
833 834 835 836
    thd->options |= OPTION_BIG_SELECTS;

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

839
  buff= (char*) thd->net.buff;
840 841 842
  init_sql_alloc(&thd->mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
  init_sql_alloc(&thd->transaction.mem_root,
		 TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
843 844
  while (fgets(buff, thd->net.max_packet, file))
  {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
845
    uint length=(uint) strlen(buff);
peter@mysql.com's avatar
peter@mysql.com committed
846
    while (length && (my_isspace(system_charset_info, buff[length-1]) ||
847
           buff[length-1] == ';'))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
848 849 850
      length--;
    buff[length]=0;
    thd->current_tablenr=0;
851
    thd->query_length=length;
852 853
    thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
    thd->query[length] = '\0';
bk@work.mysql.com's avatar
bk@work.mysql.com committed
854
    thd->query_id=query_id++;
855
    if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
856 857 858 859 860 861
    {
      thd->net.error = 0;
      close_thread_tables(thd);			// Free tables
      free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
      break;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
862 863 864
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
    if (thd->fatal_error)
865
      break;
866
    free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
867
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
868
  }
869 870 871 872 873 874

  /* 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);
875
  (void) pthread_cond_broadcast(&COND_thread_count);
876 877 878
  my_thread_end();
  pthread_exit(0);
  DBUG_RETURN(0);				// Never reached
bk@work.mysql.com's avatar
bk@work.mysql.com committed
879 880
}

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

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

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

907 908
  if (!db || check_db_name(db))
  {
909
    net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
910 911
    goto err;
  }
912
  if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
913
    goto err;
914
  if (grant_option && check_grant(thd, SELECT_ACL, table_list))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
915 916 917
    goto err;

  thd->free_list = 0;
918
  thd->query_length=(uint) strlen(tbl_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
919
  thd->query = tbl_name;
920 921 922 923 924
  if ((error = mysqld_dump_create_info(thd, table, -1)))
  {
    my_error(ER_GET_ERRNO, MYF(0));
    goto err;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
925
  net_flush(&thd->net);
926 927
  if ((error = table->file->dump(thd,fd)))
    my_error(ER_GET_ERRNO, MYF(0));
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
928

bk@work.mysql.com's avatar
bk@work.mysql.com committed
929 930
err:
  close_thread_tables(thd);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
931
  DBUG_RETURN(error);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
932 933 934 935 936 937 938 939
}


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

bool do_command(THD *thd)
{
  char *packet;
940 941
  uint old_timeout;
  ulong packet_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
942 943 944 945 946 947 948 949
  NET *net;
  enum enum_server_command command;
  DBUG_ENTER("do_command");

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

  packet=0;
950 951 952
  old_timeout=net->read_timeout;
  // Wait max for 8 hours
  net->read_timeout=(uint) thd->variables.net_wait_timeout;
953
  thd->clear_error();				// Clear error message
bk@work.mysql.com's avatar
bk@work.mysql.com committed
954 955 956 957

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


bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
  bool	error=0;
980 981 982 983
  /*
    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
  */
984 985 986
  bool slow_command=FALSE;
  DBUG_ENTER("dispatch_command");

bk@work.mysql.com's avatar
bk@work.mysql.com committed
987
  thd->command=command;
988
  thd->set_time();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
989 990 991 992 993 994
  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));
995

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1024 1025 1026 1027
      break;
    }
  case COM_CHANGE_USER:
  {
1028 1029 1030 1031
    thd->change_user();
    clear_error_message(thd);			// If errors from rollback

    statistic_increment(com_other,&LOCK_status);
1032
    char *user=   (char*) packet;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1033 1034
    char *passwd= strend(user)+1;
    char *db=     strend(passwd)+1;
peter@mysql.com's avatar
peter@mysql.com committed
1035

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1036 1037 1038
    /* Save user and privileges */
    uint save_master_access=thd->master_access;
    uint save_db_access=    thd->db_access;
1039
    uint save_db_length=    thd->db_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1040
    char *save_user=	    thd->user;
peter@mysql.com's avatar
peter@mysql.com committed
1041
    thd->user=NULL; /* Needed for check_user to allocate new user */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1042 1043
    char *save_priv_user=   thd->priv_user;
    char *save_db=	    thd->db;
peter@mysql.com's avatar
peter@mysql.com committed
1044 1045 1046
    USER_CONN *save_uc=     thd->user_connect;
    bool simple_connect;
    bool using_password;
peter@mysql.com's avatar
peter@mysql.com committed
1047

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

peter@mysql.com's avatar
peter@mysql.com committed
1050
    /* Small check for incomming packet */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1051 1052

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

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

peter@mysql.com's avatar
peter@mysql.com committed
1057
     /* We can get only old hash at this point */
peter@mysql.com's avatar
peter@mysql.com committed
1058
    if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
peter@mysql.com's avatar
peter@mysql.com committed
1059
      goto restore_user_err;
peter@mysql.com's avatar
peter@mysql.com committed
1060 1061

    char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */
peter@mysql.com's avatar
peter@mysql.com committed
1062 1063
    ACL_USER* cached_user;                      /* Cached user */
    uint cur_priv_version;                      /* Cached grant version */
peter@mysql.com's avatar
peter@mysql.com committed
1064

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

peter@mysql.com's avatar
peter@mysql.com committed
1068 1069
    /* Store information if we used password. passwd will be dammaged */
    using_password=test(passwd[0]);
peter@mysql.com's avatar
peter@mysql.com committed
1070 1071 1072 1073 1074 1075 1076 1077

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

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

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

peter@mysql.com's avatar
peter@mysql.com committed
1087 1088 1089 1090 1091 1092 1093
      char tmp_user[USERNAME_LENGTH+1];
      char tmp_db[NAME_LEN+1];

      if (user)
      {
        strncpy(tmp_user,user,USERNAME_LENGTH+1);
        /* Extra safety if we have too long data */
peter@mysql.com's avatar
peter@mysql.com committed
1094 1095
        tmp_user[USERNAME_LENGTH]=0;
      }
peter@mysql.com's avatar
peter@mysql.com committed
1096
      else
peter@mysql.com's avatar
peter@mysql.com committed
1097
        tmp_user[0]=0;
peter@mysql.com's avatar
peter@mysql.com committed
1098 1099 1100 1101
      if (db)
      {
        strncpy(tmp_db,db,NAME_LEN+1);
        tmp_db[NAME_LEN]=0;
peter@mysql.com's avatar
peter@mysql.com committed
1102 1103
      }
      else
peter@mysql.com's avatar
peter@mysql.com committed
1104
        tmp_db[0]=0;
peter@mysql.com's avatar
peter@mysql.com committed
1105

peter@mysql.com's avatar
peter@mysql.com committed
1106
      /* Write hash and encrypted scramble to client */
peter@mysql.com's avatar
peter@mysql.com committed
1107 1108
      if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4)
        || net_flush(net))
peter@mysql.com's avatar
peter@mysql.com committed
1109
        goto restore_user_err;
peter@mysql.com's avatar
peter@mysql.com committed
1110 1111 1112 1113 1114 1115 1116

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

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

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

peter@mysql.com's avatar
peter@mysql.com committed
1133 1134 1135
    /* Bad luck  we shall restore old user */
    restore_user_err:
    send_error(thd, ER_UNKNOWN_COM_ERROR);
peter@mysql.com's avatar
peter@mysql.com committed
1136

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

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

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

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

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

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

  time_t start_of_query=thd->start_time;
1385
  thd->end_time();				// Set start time
1386

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

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

1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438

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

  DESCRIPTION
    Sets the following THD variables:
      query
      query_length

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

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

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1459 1460 1461 1462 1463 1464
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/

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

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

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

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

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

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

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

1611
  case SQLCOM_EMPTY_QUERY:
1612
    send_ok(thd);
1613 1614
    break;

1615 1616 1617 1618
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

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

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

1710
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
1711
    if (check_global_access(thd, SUPER_ACL))
1712
      goto error;
1713 1714 1715 1716
    if (end_active_trans(thd))
      res= -1;
    else
      res = load_master_data(thd);
1717
    break;
peter@mysql.com's avatar
peter@mysql.com committed
1718

heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
1719 1720 1721
#ifdef HAVE_INNOBASE_DB
  case SQLCOM_SHOW_INNODB_STATUS:
    {
1722
      if (check_global_access(thd, SUPER_ACL))
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
1723 1724 1725 1726 1727
	goto error;
      res = innodb_show_status(thd);
      break;
    }
#endif
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1728

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

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

      /* Skip first table, which is the table we are creating */
      lex->select_lex.table_list.first=
	(byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
      if (!(res=open_and_lock_tables(thd,tables->next)))
      {
        if ((result=new select_create(tables->db ? tables->db : thd->db,
                                      tables->real_name, &lex->create_info,
                                      lex->create_list,
                                      lex->key_list,
                                      select_lex->item_list,lex->duplicates)))
          res=handle_select(thd, lex, result);
	else
	  res= -1;
      }
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1837 1838 1839 1840 1841
    else // regular create
    {
      res = mysql_create_table(thd,tables->db ? tables->db : thd->db,
			       tables->real_name, &lex->create_info,
			       lex->create_list,
1842
			       lex->key_list,0,0,0); // do logging
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1843
      if (!res)
1844
	send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1845 1846
    }
    break;
1847
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1848 1849 1850 1851 1852 1853 1854
  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;
1855 1856 1857 1858
    if (end_active_trans(thd))
      res= -1;
    else
      res = mysql_create_index(thd, tables, lex->key_list);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1859 1860 1861
    break;

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2016 2017 2018
  case SQLCOM_OPTIMIZE:
  {
    HA_CREATE_INFO create_info;
2019 2020
    if (check_db_used(thd,tables) ||
	check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2021
      goto error; /* purecov: inspected */
2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032
    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;
2033
      create_info.table_charset=default_charset_info;
2034 2035 2036
      res= mysql_alter_table(thd, NullS, NullS, &create_info,
			     tables, lex->create_list,
			     lex->key_list, lex->drop_list, lex->alter_list,
2037
                             (ORDER *) 0,
2038 2039 2040 2041
			     0,DUP_ERROR);
    }
    else
      res = mysql_optimize_table(thd, tables, &lex->check_opt);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2042 2043 2044 2045 2046 2047 2048
    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;
2049
    if (select_lex->item_list.elements != lex->value_list.elements)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2050
    {
2051
      send_error(thd,ER_WRONG_VALUE_COUNT);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2052 2053
      DBUG_VOID_RETURN;
    }
2054 2055 2056 2057 2058 2059 2060
    res= mysql_update(thd,tables,
                      select_lex->item_list,
                      lex->value_list,
                      select_lex->where,
                      (ORDER *) select_lex->order_list.first,
                      select_lex->select_limit,
                      lex->duplicates);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2061 2062
    if (thd->net.report_error)
      res= -1;
2063 2064 2065 2066 2067 2068 2069
    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)
2070
    {
2071 2072
      send_error(thd,ER_WRONG_VALUE_COUNT);
      DBUG_VOID_RETURN;
2073 2074 2075 2076 2077
    }
    {
      multi_update  *result;
      uint table_count;
      TABLE_LIST *auxi;
2078 2079
      const char *msg=0;

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2080
      for (auxi= (TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
2081
	table_count++;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2082

2083 2084 2085 2086 2087 2088
      if (select_lex->order_list.elements)
	msg="ORDER BY";
      else if (select_lex->select_limit && select_lex->select_limit !=
	       HA_POS_ERROR)
	msg="LIMIT";
      if (msg)
2089
      {
2090
	net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg);
2091 2092
	res= 1;
	break;
2093
      }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2094

2095 2096 2097
      tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
      if ((res=open_and_lock_tables(thd,tables)))
	break;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2098
      unit->select_limit_cnt= HA_POS_ERROR;
2099 2100
      if (!setup_fields(thd,tables,select_lex->item_list,1,0,0) &&
	  !setup_fields(thd,tables,lex->value_list,0,0,0) &&
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2101
	  !thd->fatal_error &&
2102
	  (result=new multi_update(thd,tables,select_lex->item_list,
2103
				   lex->duplicates, table_count)))
2104 2105 2106 2107 2108 2109 2110 2111 2112
      {
	List <Item> total_list;
	List_iterator <Item> field_list(select_lex->item_list);
	List_iterator <Item> value_list(lex->value_list);
	Item *item;
	while ((item=field_list++))
	  total_list.push_back(item);
	while ((item=value_list++))
	  total_list.push_back(item);
2113

2114 2115 2116 2117 2118 2119
	res= mysql_select(thd, tables, total_list,
			  select_lex->where,
			  (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
			  (ORDER *)NULL,
			  select_lex->options | thd->options |
			  SELECT_NO_JOIN_CACHE,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2120
			  result, unit, select_lex, 0);
2121
	delete result;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2122 2123
	if (thd->net.report_error)
	  res= -1;
2124 2125 2126 2127 2128
      }
      else
	res= -1;					// Error is not sent
      close_thread_tables(thd);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2129 2130
    break;
  case SQLCOM_REPLACE:
2131 2132 2133 2134 2135
  case SQLCOM_INSERT:
  {
    ulong privilege= (lex->duplicates == DUP_REPLACE ?
                      INSERT_ACL | DELETE_ACL : INSERT_ACL);
    if (check_access(thd,privilege,tables->db,&tables->grant.privilege))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2136
      goto error; /* purecov: inspected */
2137
    if (grant_option && check_grant(thd,privilege,tables))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2138 2139
      goto error;
    res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
2140
		       lex->duplicates);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2141 2142
    if (thd->net.report_error)
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2143
    break;
2144
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2145 2146 2147
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
2148

2149 2150 2151 2152
    /*
      Check that we have modify privileges for the first table and
      select privileges for the rest
    */
2153
    {
2154 2155
      ulong privilege= (lex->duplicates == DUP_REPLACE ?
                        INSERT_ACL | DELETE_ACL : INSERT_ACL);
2156 2157 2158 2159 2160 2161 2162 2163 2164 2165
      TABLE_LIST *save_next=tables->next;
      tables->next=0;
      if (check_access(thd, privilege,
		       tables->db,&tables->grant.privilege) ||
	  (grant_option && check_grant(thd, privilege, tables)))
	goto error;
      tables->next=save_next;
      if ((res=check_table_access(thd, SELECT_ACL, save_next)))
	goto error;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2166 2167

    select_result *result;
2168 2169 2170 2171
    unit->offset_limit_cnt= select_lex->offset_limit;
    unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit;
    if (unit->select_limit_cnt < select_lex->select_limit)
      unit->select_limit_cnt= HA_POS_ERROR;		// No limit
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2172

2173
    if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
2174
    {
2175
      net_printf(thd,ER_INSERT_TABLE_USED,tables->real_name);
2176
      DBUG_VOID_RETURN;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2177
    }
2178 2179 2180 2181 2182 2183 2184

    /* 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,
2185
				    lex->duplicates)))
2186
	res=handle_select(thd,lex,result);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2187 2188
      if (thd->net.report_error)
	res= -1;
2189 2190 2191
    }
    else
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2192 2193
    break;
  }
2194
  case SQLCOM_TRUNCATE:
2195 2196 2197 2198 2199 2200 2201 2202
    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())
    {
2203
      send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
2204 2205 2206 2207
      goto error;
    }
    res=mysql_truncate(thd,tables);
    break;
2208
  case SQLCOM_DELETE:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2209 2210 2211 2212 2213 2214 2215
  {
    if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
      goto error; /* purecov: inspected */
    if (grant_option && check_grant(thd,DELETE_ACL,tables))
      goto error;
    // Set privilege for the WHERE clause
    tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
serg@serg.mysql.com's avatar
serg@serg.mysql.com committed
2216 2217
    res = mysql_delete(thd,tables, select_lex->where,
                       (ORDER*) select_lex->order_list.first,
2218
                       select_lex->select_limit, select_lex->options);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2219 2220
    if (thd->net.report_error)
      res= -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2221 2222
    break;
  }
2223
  case SQLCOM_DELETE_MULTI:
2224 2225 2226 2227 2228
  {
    TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first;
    TABLE_LIST *auxi;
    uint table_count=0;
    multi_delete *result;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2229

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

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

2615 2616 2617 2618
    /*
      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
    */
2619 2620 2621 2622 2623 2624 2625 2626 2627 2628

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2727
  case SQLCOM_BEGIN:
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2728 2729 2730 2731 2732 2733
    if (thd->locked_tables)
    {
      thd->lock=thd->locked_tables;
      thd->locked_tables=0;			// Will be automaticly closed
      close_thread_tables(thd);			// Free tables
    }
2734 2735 2736 2737 2738 2739
    if (end_active_trans(thd))
    {
      res= -1;
    }
    else
    {
2740
      thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
2741 2742
		     OPTION_BEGIN);
      thd->server_status|= SERVER_STATUS_IN_TRANS;
2743
      send_ok(thd);
2744
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2745 2746
    break;
  case SQLCOM_COMMIT:
2747 2748 2749 2750 2751
    /*
      We don't use end_active_trans() here to ensure that this works
      even if there is a problem with the OPTION_AUTO_COMMIT flag
      (Which of course should never happen...)
    */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2752
  {
2753
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2754 2755
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_commit(thd))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2756
    {
2757
      send_ok(thd);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2758
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2759 2760 2761
    else
      res= -1;
    break;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2762
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2763 2764 2765
  case SQLCOM_ROLLBACK:
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
    if (!ha_rollback(thd))
2766 2767
    {
      if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
2768
	send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
2769
      else
2770
	send_ok(thd);
2771
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2772 2773
    else
      res= -1;
2774
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2775 2776
    break;
  default:					/* Impossible */
2777
    send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2778 2779 2780 2781
    break;
  }
  thd->proc_info="query end";			// QQ
  if (res < 0)
2782
    send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2783 2784 2785 2786 2787 2788 2789

error:
  DBUG_VOID_RETURN;
}


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

bool
2800
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
2801
	     bool dont_check_global_grants, bool no_errors)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2802
{
2803 2804 2805 2806
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("want_access: %lu  master_access: %lu", want_access,
		      thd->master_access));
  ulong db_access,dummy;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2807 2808 2809 2810 2811
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

2812
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2813
  {
2814
    if (!no_errors)
2815
      send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
2816
    DBUG_RETURN(TRUE);				/* purecov: tested */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2817 2818 2819 2820 2821
  }

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

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2838 2839 2840 2841 2842
  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;
2843 2844
  // Remove SHOW attribute and access rights we already have
  want_access &= ~(thd->master_access | EXTRA_ACL);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2845
  db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
2846 2847

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


2861 2862 2863
/* check for global access and give descriptive error message if it fails */

bool check_global_access(THD *thd, ulong want_access)
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2864
{
2865 2866 2867 2868
  char command[128];
  if ((thd->master_access & want_access) == want_access)
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
2869
  net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
2870 2871
	     command);
  return 1;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
2872 2873 2874
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2875
/*
2876 2877
  Check the privilege for all used tables.  Table privileges are cached
  in the table list for GRANT checking
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2878 2879
*/

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


monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2918
static bool check_db_used(THD *thd,TABLE_LIST *tables)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2919 2920 2921 2922 2923 2924 2925
{
  for (; tables ; tables=tables->next)
  {
    if (!tables->db)
    {
      if (!(tables->db=thd->db))
      {
2926
	send_error(thd,ER_NO_DB_ERROR);	/* purecov: tested */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2927 2928 2929 2930 2931 2932 2933 2934
	return TRUE;				/* purecov: tested */
      }
    }
  }
  return FALSE;
}


2935 2936
static bool check_merge_table_access(THD *thd, char *db,
				     TABLE_LIST *table_list)
2937 2938 2939 2940
{
  int error=0;
  if (table_list)
  {
2941
    /* Check that all tables use the current database */
2942 2943
    TABLE_LIST *tmp;
    for (tmp=table_list; tmp ; tmp=tmp->next)
2944 2945 2946
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
2947
      else if (strcmp(tmp->db,db))
2948
      {
2949
	send_error(thd,ER_UNION_TABLES_IN_DIFFERENT_DIR);
2950 2951 2952
	return 1;
      }
    }
2953 2954 2955 2956 2957 2958 2959
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
			     table_list);
  }
  return error;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016
/****************************************************************************
	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;
}


/****************************************************************************
3017
	Initialize global thd variables needed for query
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3018 3019
****************************************************************************/

3020
void
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3021 3022 3023
mysql_init_query(THD *thd)
{
  DBUG_ENTER("mysql_init_query");
3024 3025 3026 3027 3028 3029
  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();
peter@mysql.com's avatar
peter@mysql.com committed
3030
  lex->unit.global_parameters= lex->unit.slave= lex->current_select=
3031
    lex->all_selects_list= &lex->select_lex;
3032 3033
  lex->select_lex.master= &lex->unit;
  lex->select_lex.prev= &lex->unit.slave;
3034 3035
  lex->select_lex.link_next= 0;
  lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
3036 3037
  lex->olap=lex->describe=0;
  lex->derived_tables= false;
peter@mysql.com's avatar
peter@mysql.com committed
3038
  thd->check_loops_counter= thd->select_number=
3039
    lex->select_lex.select_number= 1;
3040
  thd->free_list= 0;
3041
  thd->total_warn_count=0;			// Warnings for this query
3042 3043
  thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
  thd->sent_row_count= thd->examined_row_count= 0;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
3044
  thd->fatal_error= thd->rand_used= 0;
3045
  thd->possible_loops= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3046 3047 3048
  DBUG_VOID_RETURN;
}

3049 3050 3051
void
mysql_init_select(LEX *lex)
{
3052
  SELECT_LEX *select_lex= lex->current_select->select_lex();
3053
  DBUG_ASSERT(select_lex->linkage != GLOBAL_OPTIONS_TYPE);
3054
  select_lex->init_select();
peter@mysql.com's avatar
peter@mysql.com committed
3055
  select_lex->master_unit()->select_limit= select_lex->select_limit=
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3056
    lex->thd->variables.select_limit;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3057
  lex->exchange= 0;
3058
  lex->result= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
3059
  lex->proc_list.first= 0;
3060 3061
}

3062

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

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

3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119
/*
  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);
  add_item_to_list(get_system_var(OPT_SESSION, tmp));
  DBUG_VOID_RETURN;
}

3120

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

3131

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

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

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


inline static void
link_in_list(SQL_LIST *list,byte *element,byte **next)
{
  list->elements++;
  (*list->next)=element;
  list->next=next;
  *next=0;
}


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

bool add_field_to_list(char *field_name, enum_field_types type,
		       char *length, char *decimals,
3193 3194
		       uint type_modifier,
		       Item *default_value, Item *comment,
3195
		       char *change, TYPELIB *interval, CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3196 3197 3198 3199 3200
{
  register create_field *new_field;
  THD	*thd=current_thd;
  LEX  *lex= &thd->lex;
  uint allowed_type_modifier=0;
3201
  char warn_buff[MYSQL_ERRMSG_SIZE];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3202 3203 3204 3205
  DBUG_ENTER("add_field_to_list");

  if (strlen(field_name) > NAME_LEN)
  {
3206
    net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3207 3208 3209 3210 3211
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
    lex->col_list.push_back(new key_part_spec(field_name,0));
3212
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3213 3214 3215 3216 3217 3218
				    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));
3219
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3220 3221 3222 3223 3224 3225 3226 3227 3228
				    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)
    {
3229
      net_printf(thd,ER_INVALID_DEFAULT,field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248
      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;
3249
  new_field->charset=cs;
3250

3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261
  if (!comment)
  {
    new_field->comment.str=0;
    new_field->comment.length=0;
  }
  else
  {
    /* In this case comment is always of type Item_string */
    new_field->comment.str=   (char*) comment->str_value.ptr();
    new_field->comment.length=comment->str_value.length();
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3262 3263 3264 3265 3266 3267
  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 &&
3268
      new_field->length < new_field->decimals+1 &&
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3269
      new_field->decimals != NOT_FIXED_DEC)
3270
    new_field->length=new_field->decimals+1; /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293

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

  if (new_field->length >= MAX_FIELD_WIDTH ||
      (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3467
       type != FIELD_TYPE_STRING && type != FIELD_TYPE_VAR_STRING))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3468
  {
3469
    net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3470 3471 3472 3473 3474 3475
	       MAX_FIELD_WIDTH-1);		/* purecov: inspected */
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  type_modifier&= AUTO_INCREMENT_FLAG;
  if ((~allowed_type_modifier) & type_modifier)
  {
3476
    net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517
    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
add_proc_to_list(Item *item)
{
  ORDER *order;
  Item	**item_ptr;

  if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
  link_in_list(&current_lex->proc_list,(byte*) order,(byte**) &order->next);
  return 0;
}


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

static void remove_escape(char *name)
{
3518 3519
  if (!*name)					// For empty DB names
    return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3520 3521
  char *to;
#ifdef USE_MB
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3522
  char *strend=name+(uint) strlen(name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3523 3524 3525 3526 3527 3528
#endif
  for (to=name; *name ; name++)
  {
#ifdef USE_MB
    int l;
/*    if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
3529 3530
    if (use_mb(system_charset_info) &&
        (l = my_ismbchar(system_charset_info, name, strend)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3531 3532 3533 3534 3535 3536 3537 3538
    {
	while (l--)
	    *to++ = *name++;
	name--;
	continue;
    }
#endif
    if (*name == '\\' && name[1])
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3539
      name++;					// Skip '\\'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567
    *to++= *name;
  }
  *to=0;
}

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


bool add_to_list(SQL_LIST &list,Item *item,bool asc)
{
  ORDER *order;
  Item	**item_ptr;
  DBUG_ENTER("add_to_list");
  if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
    DBUG_RETURN(1);
  item_ptr = (Item**) (order+1);
  *item_ptr=item;
  order->item= item_ptr;
  order->asc = asc;
  order->free_me=0;
  order->used=0;
  link_in_list(&list,(byte*) order,(byte**) &order->next);
  DBUG_RETURN(0);
}


3568 3569 3570 3571 3572 3573
TABLE_LIST *st_select_lex::add_table_to_list(Table_ident *table,
					     LEX_STRING *alias,
					     bool updating,
					     thr_lock_type flags,
					     List<String> *use_index,
					     List<String> *ignore_index)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3574 3575 3576 3577 3578 3579 3580 3581 3582 3583
{
  register TABLE_LIST *ptr;
  THD	*thd=current_thd;
  char *alias_str;
  DBUG_ENTER("add_table_to_list");

  if (!table)
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? alias->str : table->table.str;
  if (table->table.length > NAME_LEN ||
3584 3585
      (table->table.length &&
       check_table_name(table->table.str,table->table.length)) ||
3586
      table->db.str && check_db_name(table->db.str))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3587
  {
3588
    net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3589 3590 3591 3592
    DBUG_RETURN(0);
  }

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

3621
  ptr->alias= alias_str;
3622 3623
  if (lower_case_table_names)
  {
3624 3625
    my_casedn_str(system_charset_info,ptr->db);
    my_casedn_str(system_charset_info,table->table.str);
3626 3627
  }
  ptr->real_name=table->table.str;
3628
  ptr->real_name_length=table->table.length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3629
  ptr->lock_type=flags;
3630
  ptr->updating=updating;
3631
  ptr->derived= (SELECT_LEX_UNIT *) table->sel;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3632
  if (use_index)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3633
    ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3634 3635
					       sizeof(*use_index));
  if (ignore_index)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3636 3637
    ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index,
						   sizeof(*ignore_index));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3638 3639

  /* check that used name is unique */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3640
  if (flags != TL_IGNORE)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3641
  {
3642
    for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
3643
	 tables ;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3644
	 tables=tables->next)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3645
    {
3646
      if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3647
      {
3648
	net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3649 3650
	DBUG_RETURN(0);				/* purecov: tested */
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3651 3652
    }
  }
3653
  link_in_list(&table_list, (byte*) ptr, (byte**) &ptr->next);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3654 3655 3656
  DBUG_RETURN(ptr);
}

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

3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670
/*
  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
*/

3671
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
3672 3673 3674 3675 3676 3677
{
  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));

3678
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
3679 3680 3681 3682 3683 3684 3685 3686 3687
       tables ;
       tables=tables->next)
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3689 3690
void add_join_on(TABLE_LIST *b,Item *expr)
{
3691
  if (expr)
3692
  {
3693 3694 3695 3696 3697 3698 3699 3700
    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();
3701
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3702 3703 3704 3705 3706 3707 3708 3709
}


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

3710
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3711 3712 3713 3714 3715 3716
{
  bool result=0;

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


3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791
/*
  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
*/

3792
void kill_one_thread(THD *thd, ulong id)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3793 3794 3795
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
3796 3797
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3798 3799 3800 3801
  while ((tmp=it++))
  {
    if (tmp->thread_id == id)
    {
3802 3803
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3804 3805 3806
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819
  if (tmp)
  {
    if ((thd->master_access & SUPER_ACL) ||
	!strcmp(thd->user,tmp->user))
    {
      tmp->awake(1 /*prepare to die*/);
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3820
  if (!error)
3821
    send_ok(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3822
  else
3823
    net_printf(thd,error,id);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839
}

/* 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);
}
3840 3841 3842 3843


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

3844
static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
3845
{
3846
  char buff[FN_REFLEN],*ptr, *end;
3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858
  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);
3859
  end=convert_dirname(buff, *filename_ptr, NullS);
3860
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
3861 3862
    return 1;					// End of memory
  *filename_ptr=ptr;
3863
  strxmov(ptr,buff,table_name,NullS);
3864 3865
  return 0;
}
3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880

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

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