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

unknown's avatar
unknown committed
3 4
   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
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
6

unknown's avatar
unknown committed
7 8 9 10
   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.
11

unknown's avatar
unknown committed
12 13 14 15
   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 */

16
#define MYSQL_LEX 1
unknown's avatar
unknown committed
17
#include "mysql_priv.h"
18
#include "sql_repl.h"
unknown's avatar
unknown committed
19
#include "rpl_filter.h"
20
#include "repl_failsafe.h"
unknown's avatar
unknown committed
21 22 23 24
#include <m_ctype.h>
#include <myisam.h>
#include <my_dir.h>

25
#include "sp_head.h"
26
#include "sp.h"
27
#include "sp_cache.h"
28
#include "events.h"
29
#include "sql_trigger.h"
30

31 32 33 34 35 36
/* Used in error handling only */
#define SP_TYPE_STRING(LP) \
  ((LP)->sphead->m_type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE")
#define SP_COM_STRING(LP) \
  ((LP)->sql_command == SQLCOM_CREATE_SPFUNCTION || \
   (LP)->sql_command == SQLCOM_ALTER_FUNCTION || \
37
   (LP)->sql_command == SQLCOM_SHOW_CREATE_FUNC || \
38 39 40
   (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
   "FUNCTION" : "PROCEDURE")

41
static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
unknown's avatar
unknown committed
42

43
const char *any_db="*any*";	// Special symbol for check_access
unknown's avatar
unknown committed
44

unknown's avatar
unknown committed
45
const LEX_STRING command_name[]={
unknown's avatar
unknown committed
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
  { STRING_WITH_LEN("Sleep") },
  { STRING_WITH_LEN("Quit") },
  { STRING_WITH_LEN("Init DB") },
  { STRING_WITH_LEN("Query") },
  { STRING_WITH_LEN("Field List") },
  { STRING_WITH_LEN("Create DB") },
  { STRING_WITH_LEN("Drop DB") },
  { STRING_WITH_LEN("Refresh") },
  { STRING_WITH_LEN("Shutdown") },
  { STRING_WITH_LEN("Statistics") },
  { STRING_WITH_LEN("Processlist") },
  { STRING_WITH_LEN("Connect") },
  { STRING_WITH_LEN("Kill") },
  { STRING_WITH_LEN("Debug") },
  { STRING_WITH_LEN("Ping") },
  { STRING_WITH_LEN("Time") },
  { STRING_WITH_LEN("Delayed insert") },
  { STRING_WITH_LEN("Change user") },
  { STRING_WITH_LEN("Binlog Dump") },
  { STRING_WITH_LEN("Table Dump") },
  { STRING_WITH_LEN("Connect Out") },
  { STRING_WITH_LEN("Register Slave") },
  { STRING_WITH_LEN("Prepare") },
  { STRING_WITH_LEN("Execute") },
  { STRING_WITH_LEN("Long Data") },
  { STRING_WITH_LEN("Close stmt") },
  { STRING_WITH_LEN("Reset stmt") },
  { STRING_WITH_LEN("Set option") },
  { STRING_WITH_LEN("Fetch") },
  { STRING_WITH_LEN("Daemon") },
  { STRING_WITH_LEN("Error") }  // Last command number
unknown's avatar
unknown committed
77 78
};

unknown's avatar
unknown committed
79 80 81 82
const char *xa_state_names[]={
  "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
};

unknown's avatar
unknown committed
83

unknown's avatar
unknown committed
84 85 86 87 88
static void unlock_locked_tables(THD *thd)
{
  if (thd->locked_tables)
  {
    thd->lock=thd->locked_tables;
89
    thd->locked_tables=0;			// Will be automatically closed
unknown's avatar
unknown committed
90 91 92 93
    close_thread_tables(thd);			// Free tables
  }
}

94

95
bool end_active_trans(THD *thd)
96
{
unknown's avatar
unknown committed
97
  int error=0;
98
  DBUG_ENTER("end_active_trans");
99
  if (unlikely(thd->in_sub_stmt))
100 101 102 103
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    DBUG_RETURN(1);
  }
104 105 106 107 108 109
  if (thd->transaction.xid_state.xa_state != XA_NOTR)
  {
    my_error(ER_XAER_RMFAIL, MYF(0),
             xa_state_names[thd->transaction.xid_state.xa_state]);
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
110
  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
unknown's avatar
unknown committed
111
		      OPTION_TABLE_LOCK))
112
  {
113 114 115 116
    DBUG_PRINT("info",("options: 0x%lx", (ulong) thd->options));
    /* Safety if one did "drop table" on locked tables */
    if (!thd->locked_tables)
      thd->options&= ~OPTION_TABLE_LOCK;
117
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
118
    if (ha_commit(thd))
unknown's avatar
unknown committed
119
      error=1;
120
  }
121 122
  thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
  thd->no_trans_update.all= FALSE;
123
  DBUG_RETURN(error);
124 125
}

126

unknown's avatar
unknown committed
127
bool begin_trans(THD *thd)
unknown's avatar
unknown committed
128 129
{
  int error=0;
130
  if (unlikely(thd->in_sub_stmt))
131 132 133 134
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    return 1;
  }
unknown's avatar
unknown committed
135 136 137 138 139 140 141 142 143 144
  if (thd->locked_tables)
  {
    thd->lock=thd->locked_tables;
    thd->locked_tables=0;			// Will be automatically closed
    close_thread_tables(thd);			// Free tables
  }
  if (end_active_trans(thd))
    error= -1;
  else
  {
145
    LEX *lex= thd->lex;
146
    thd->options|= OPTION_BEGIN;
unknown's avatar
unknown committed
147 148
    thd->server_status|= SERVER_STATUS_IN_TRANS;
    if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
unknown's avatar
unknown committed
149
      error= ha_start_consistent_snapshot(thd);
unknown's avatar
unknown committed
150 151 152
  }
  return error;
}
153

unknown's avatar
unknown committed
154
#ifdef HAVE_REPLICATION
155 156 157
/*
  Returns true if all tables should be ignored
*/
158 159
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
{
unknown's avatar
unknown committed
160 161
  return rpl_filter->is_on() && tables && !thd->spcont &&
         !rpl_filter->tables_ok(thd->db, tables);
162
}
unknown's avatar
unknown committed
163
#endif
164 165


166 167 168 169 170 171 172 173 174 175 176 177
static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables)
{
  for (TABLE_LIST *table= tables; table; table= table->next_global)
  {
    DBUG_ASSERT(table->db && table->table_name);
    if (table->updating &&
        !find_temporary_table(thd, table->db, table->table_name))
      return 1;
  }
  return 0;
}

178

179 180 181
/*
  Mark all commands that somehow changes a table
  This is used to check number of updates / hour
unknown's avatar
unknown committed
182 183 184

  sql_command is actually set to SQLCOM_END sometimes
  so we need the +1 to include it in the array.
unknown's avatar
unknown committed
185

186
  See COMMAND_FLAG_xxx for different type of commands
unknown's avatar
unknown committed
187 188
     2  - query that returns meaningful ROW_COUNT() -
          a number of modified rows
189 190
*/

191
uint sql_command_flags[SQLCOM_END+1];
192 193 194

void init_update_queries(void)
{
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
  bzero((gptr) &sql_command_flags, sizeof(sql_command_flags));

  sql_command_flags[SQLCOM_CREATE_TABLE]=   CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_CREATE_INDEX]=   CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_ALTER_TABLE]=    CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_TRUNCATE]=       CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_DROP_TABLE]=     CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_LOAD]=           CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_CREATE_DB]=      CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_DROP_DB]=        CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_RENAME_TABLE]=   CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_BACKUP_TABLE]=   CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_RESTORE_TABLE]=  CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_DROP_INDEX]=     CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_CREATE_VIEW]=    CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_DROP_VIEW]=      CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_CREATE_EVENT]=   CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_ALTER_EVENT]=    CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_DROP_EVENT]=     CF_CHANGES_DATA;  

  sql_command_flags[SQLCOM_UPDATE]=	    CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
  sql_command_flags[SQLCOM_UPDATE_MULTI]=   CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
  sql_command_flags[SQLCOM_INSERT]=	    CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
  sql_command_flags[SQLCOM_INSERT_SELECT]=  CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
  sql_command_flags[SQLCOM_DELETE]=         CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
  sql_command_flags[SQLCOM_DELETE_MULTI]=   CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
  sql_command_flags[SQLCOM_REPLACE]=        CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
  sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;

  sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_STATUS]=      CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_DATABASES]=   CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_TRIGGERS]=    CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_EVENTS]=      CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_OPEN_TABLES]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_PLUGINS]=     CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_FIELDS]=      CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_KEYS]=        CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_VARIABLES]=   CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_CHARSETS]=    CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_COLLATIONS]=  CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND;

  sql_command_flags[SQLCOM_SHOW_TABLES]=       (CF_STATUS_COMMAND |
                                                CF_SHOW_TABLE_COMMAND);
  sql_command_flags[SQLCOM_SHOW_TABLE_STATUS]= (CF_STATUS_COMMAND |
                                                CF_SHOW_TABLE_COMMAND);

  /*
    The following is used to preserver CF_ROW_COUNT during the
    a CALL or EXECUTE statement, so the value generated by the
    last called (or executed) statement is preserved.
    See mysql_execute_command() for how CF_ROW_COUNT is used.
  */
  sql_command_flags[SQLCOM_CALL]= 		CF_HAS_ROW_COUNT;
  sql_command_flags[SQLCOM_EXECUTE]= 		CF_HAS_ROW_COUNT;
252 253
}

254

unknown's avatar
unknown committed
255 256
bool is_update_query(enum enum_sql_command command)
{
unknown's avatar
unknown committed
257
  DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
258
  return (sql_command_flags[command] & CF_CHANGES_DATA) != 0;
unknown's avatar
unknown committed
259
}
260

261

262 263
void execute_init_command(THD *thd, sys_var_str *init_command_var,
			  rw_lock_t *var_mutex)
unknown's avatar
unknown committed
264 265 266 267
{
  Vio* save_vio;
  ulong save_client_capabilities;

268 269 270 271 272 273 274 275 276
  thd->proc_info= "Execution of init_command";
  /*
    We need to lock init_command_var because
    during execution of init_command_var query
    values of init_command_var can't be changed
  */
  rw_rdlock(var_mutex);
  thd->query= init_command_var->value;
  thd->query_length= init_command_var->value_length;
unknown's avatar
unknown committed
277 278
  save_client_capabilities= thd->client_capabilities;
  thd->client_capabilities|= CLIENT_MULTI_QUERIES;
279 280 281 282
  /*
    We don't need return result of execution to client side.
    To forbid this we should set thd->net.vio to 0.
  */
unknown's avatar
unknown committed
283 284
  save_vio= thd->net.vio;
  thd->net.vio= 0;
285
  thd->net.no_send_error= 0;
unknown's avatar
unknown committed
286
  dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
287
  rw_unlock(var_mutex);
unknown's avatar
unknown committed
288 289 290 291 292
  thd->client_capabilities= save_client_capabilities;
  thd->net.vio= save_vio;
}


293 294 295 296
/*
  Execute commands from bootstrap_file.
  Used when creating the initial grant tables
*/
unknown's avatar
unknown committed
297

298
pthread_handler_t handle_bootstrap(void *arg)
unknown's avatar
unknown committed
299
{
300 301 302
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
unknown's avatar
unknown committed
303

304
  /* The following must be called before DBUG_ENTER */
305
  thd->thread_stack= (char*) &thd;
306
  if (my_thread_init() || thd->store_globals())
unknown's avatar
unknown committed
307
  {
unknown's avatar
unknown committed
308
#ifndef EMBEDDED_LIBRARY
309
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
unknown's avatar
unknown committed
310
#endif
311
    thd->fatal_error();
312
    goto end;
unknown's avatar
unknown committed
313
  }
314 315
  DBUG_ENTER("handle_bootstrap");

unknown's avatar
unknown committed
316
#ifndef EMBEDDED_LIBRARY
317 318
  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
319
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
320

321
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
322 323 324 325
    thd->options |= OPTION_BIG_SELECTS;

  thd->proc_info=0;
  thd->version=refresh_version;
326 327
  thd->security_ctx->priv_user=
    thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
unknown's avatar
unknown committed
328
  thd->security_ctx->priv_host[0]=0;
329 330 331 332 333 334
  /*
    Make the "client" handle multiple results. This is necessary
    to enable stored procedures with SELECTs and Dynamic SQL
    in init-file.
  */
  thd->client_capabilities|= CLIENT_MULTI_RESULTS;
unknown's avatar
unknown committed
335

336
  buff= (char*) thd->net.buff;
337
  thd->init_for_queries();
unknown's avatar
unknown committed
338 339
  while (fgets(buff, thd->net.max_packet, file))
  {
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
    /* strlen() can't be deleted because fgets() doesn't return length */
    ulong length= (ulong) strlen(buff);
    while (buff[length-1] != '\n' && !feof(file))
    {
      /*
        We got only a part of the current string. Will try to increase
        net buffer then read the rest of the current string.
      */
      /* purecov: begin tested */
      if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
      {
        net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS);
        thd->fatal_error();
        break;
      }
      buff= (char*) thd->net.buff;
      fgets(buff + length, thd->net.max_packet - length, file);
      length+= (ulong) strlen(buff + length);
      /* purecov: end */
    }
    if (thd->is_fatal_error)
      break;                                    /* purecov: inspected */
unknown's avatar
unknown committed
362

unknown's avatar
unknown committed
363
    while (length && (my_isspace(thd->charset(), buff[length-1]) ||
364
                      buff[length-1] == ';'))
unknown's avatar
unknown committed
365 366
      length--;
    buff[length]=0;
unknown's avatar
unknown committed
367 368 369 370 371

    /* Skip lines starting with delimiter */
    if (strncmp(buff, STRING_WITH_LEN("delimiter")) == 0)
      continue;

372
    thd->query_length=length;
unknown's avatar
unknown committed
373 374
    thd->query= thd->memdup_w_gap(buff, length+1, 
				  thd->db_length+1+QUERY_CACHE_FLAGS_SIZE);
unknown's avatar
unknown committed
375
    thd->query[length] = '\0';
376
    DBUG_PRINT("query",("%-.4096s",thd->query));
377 378 379 380
    /*
      We don't need to obtain LOCK_thread_count here because in bootstrap
      mode we have only one thread.
    */
381
    thd->query_id=next_query_id();
382
    thd->set_time();
unknown's avatar
unknown committed
383 384
    mysql_parse(thd,thd->query,length);
    close_thread_tables(thd);			// Free tables
385

386
    if (thd->is_fatal_error)
387
      break;
388 389 390 391 392 393 394 395 396

    if (thd->net.report_error)
    {
      /* The query failed, send error to log and abort bootstrap */
      net_send_error(thd);
      thd->fatal_error();
      break;
    }

unknown's avatar
unknown committed
397
    free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
398
#ifdef USING_TRANSACTIONS
399
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
400
#endif
unknown's avatar
unknown committed
401
  }
402 403

end:
404
  /* Remember the exit code of bootstrap */
405 406 407 408 409 410
  bootstrap_error= thd->is_fatal_error;

  net_end(&thd->net);
  thd->cleanup();
  delete thd;

unknown's avatar
unknown committed
411
#ifndef EMBEDDED_LIBRARY
412 413 414
  (void) pthread_mutex_lock(&LOCK_thread_count);
  thread_count--;
  (void) pthread_mutex_unlock(&LOCK_thread_count);
415
  (void) pthread_cond_broadcast(&COND_thread_count);
416 417
  my_thread_end();
  pthread_exit(0);
unknown's avatar
unknown committed
418
#endif
419
  DBUG_RETURN(0);
unknown's avatar
unknown committed
420 421 422
}


unknown's avatar
unknown committed
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
/* This works because items are allocated with sql_alloc() */

void free_items(Item *item)
{
  Item *next;
  DBUG_ENTER("free_items");
  for (; item ; item=next)
  {
    next=item->next;
    item->delete_self();
  }
  DBUG_VOID_RETURN;
}

/* This works because items are allocated with sql_alloc() */
438 439 440

void cleanup_items(Item *item)
{
unknown's avatar
unknown committed
441
  DBUG_ENTER("cleanup_items");  
442 443
  for (; item ; item=item->next)
    item->cleanup();
unknown's avatar
unknown committed
444
  DBUG_VOID_RETURN;
445 446
}

unknown's avatar
unknown committed
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
/*
  Handle COM_TABLE_DUMP command

  SYNOPSIS
    mysql_table_dump
      thd           thread handle
      db            database name or an empty string. If empty,
                    the current database of the connection is used
      tbl_name      name of the table to dump

  NOTES
    This function is written to handle one specific command only.

  RETURN VALUE
    0               success
    1               error, the error message is set in THD
*/

static
466
int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name)
unknown's avatar
unknown committed
467 468 469 470 471
{
  TABLE* table;
  TABLE_LIST* table_list;
  int error = 0;
  DBUG_ENTER("mysql_table_dump");
472 473 474 475 476
  if (db->length == 0)
  {
    db->str= thd->db;            /* purecov: inspected */
    db->length= thd->db_length;  /* purecov: inspected */
  }
477
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
478
    DBUG_RETURN(1); // out of memory
479
  table_list->db= db->str;
480
  table_list->table_name= table_list->alias= tbl_name;
unknown's avatar
VIEW  
unknown committed
481 482
  table_list->lock_type= TL_READ_NO_INSERT;
  table_list->prev_global= &table_list;	// can be removed after merge with 4.1
unknown's avatar
unknown committed
483

484
  if (check_db_name(db))
485
  {
486 487
    /* purecov: begin inspected */
    my_error(ER_WRONG_DB_NAME ,MYF(0), db->str ? db->str : "NULL");
488
    goto err;
489
    /* purecov: end */
490
  }
491
  if (lower_case_table_names)
492
    my_casedn_str(files_charset_info, tbl_name);
493 494 495 496

  if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
    DBUG_RETURN(1);

unknown's avatar
unknown committed
497
  if (check_one_table_access(thd, SELECT_ACL, table_list))
unknown's avatar
unknown committed
498 499
    goto err;
  thd->free_list = 0;
unknown's avatar
unknown committed
500
  thd->query_length=(uint) strlen(tbl_name);
unknown's avatar
unknown committed
501
  thd->query = tbl_name;
unknown's avatar
unknown committed
502
  if ((error = mysqld_dump_create_info(thd, table_list, -1)))
503
  {
504
    my_error(ER_GET_ERRNO, MYF(0), my_errno);
505 506
    goto err;
  }
unknown's avatar
unknown committed
507
  net_flush(&thd->net);
unknown's avatar
unknown committed
508
  if ((error= table->file->dump(thd,-1)))
509
    my_error(ER_GET_ERRNO, MYF(0), error);
unknown's avatar
unknown committed
510

unknown's avatar
unknown committed
511
err:
unknown's avatar
unknown committed
512
  DBUG_RETURN(error);
unknown's avatar
unknown committed
513 514
}

unknown's avatar
unknown committed
515 516 517 518
/*
  Ends the current transaction and (maybe) begin the next

  SYNOPSIS
519
    end_trans()
unknown's avatar
unknown committed
520 521 522 523 524 525 526
      thd            Current thread
      completion     Completion type

  RETURN
    0 - OK
*/

527
int end_trans(THD *thd, enum enum_mysql_completiontype completion)
unknown's avatar
unknown committed
528 529 530
{
  bool do_release= 0;
  int res= 0;
531
  DBUG_ENTER("end_trans");
unknown's avatar
unknown committed
532

533
  if (unlikely(thd->in_sub_stmt))
534 535 536 537
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    DBUG_RETURN(1);
  }
538 539 540 541 542 543
  if (thd->transaction.xid_state.xa_state != XA_NOTR)
  {
    my_error(ER_XAER_RMFAIL, MYF(0),
             xa_state_names[thd->transaction.xid_state.xa_state]);
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
544 545 546 547 548 549 550 551
  switch (completion) {
  case COMMIT:
    /*
     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...)
    */
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
552
    res= ha_commit(thd);
553
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_KEEP_LOG);
554
    thd->no_trans_update.all= FALSE;
unknown's avatar
unknown committed
555 556
    break;
  case COMMIT_RELEASE:
unknown's avatar
unknown committed
557
    do_release= 1; /* fall through */
unknown's avatar
unknown committed
558 559 560 561 562 563
  case COMMIT_AND_CHAIN:
    res= end_active_trans(thd);
    if (!res && completion == COMMIT_AND_CHAIN)
      res= begin_trans(thd);
    break;
  case ROLLBACK_RELEASE:
unknown's avatar
unknown committed
564
    do_release= 1; /* fall through */
unknown's avatar
unknown committed
565 566 567 568
  case ROLLBACK:
  case ROLLBACK_AND_CHAIN:
  {
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
unknown's avatar
unknown committed
569
    if (ha_rollback(thd))
unknown's avatar
unknown committed
570
      res= -1;
571
    thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_KEEP_LOG);
572
    thd->no_trans_update.all= FALSE;
unknown's avatar
unknown committed
573 574 575 576 577 578 579 580 581
    if (!res && (completion == ROLLBACK_AND_CHAIN))
      res= begin_trans(thd);
    break;
  }
  default:
    res= -1;
    my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
    DBUG_RETURN(-1);
  }
unknown's avatar
unknown committed
582

unknown's avatar
unknown committed
583 584 585
  if (res < 0)
    my_error(thd->killed_errno(), MYF(0));
  else if ((res == 0) && do_release)
unknown's avatar
unknown committed
586 587
    thd->killed= THD::KILL_CONNECTION;

unknown's avatar
unknown committed
588 589
  DBUG_RETURN(res);
}
unknown's avatar
unknown committed
590

591
#ifndef EMBEDDED_LIBRARY
592 593

/*
unknown's avatar
unknown committed
594
  Read one command from connection and execute it (query or simple command).
595 596 597 598 599 600 601 602
  This function is called in loop from thread function.
  SYNOPSIS
    do_command()
  RETURN VALUE
    0  success
    1  request of thread shutdown (see dispatch_command() description)
*/

unknown's avatar
unknown committed
603 604
bool do_command(THD *thd)
{
unknown's avatar
unknown committed
605
  char *packet= 0;
unknown's avatar
unknown committed
606
  ulong packet_length;
unknown's avatar
unknown committed
607
  NET *net= &thd->net;
unknown's avatar
unknown committed
608 609 610
  enum enum_server_command command;
  DBUG_ENTER("do_command");

unknown's avatar
unknown committed
611 612 613 614
  /*
    indicator of uninitialized lex => normal flow of errors handling
    (see my_message_sql)
  */
615
  thd->lex->current_select= 0;
unknown's avatar
unknown committed
616

unknown's avatar
unknown committed
617 618 619 620 621 622 623 624
  /*
    This thread will do a blocking read from the client which
    will be interrupted when the next command is received from
    the client, the connection is closed or "net_wait_timeout"
    number of seconds has passed
  */
  net_set_read_timeout(net, thd->variables.net_wait_timeout);

unknown's avatar
unknown committed
625
  thd->clear_error();				// Clear error message
unknown's avatar
unknown committed
626 627 628 629

  net_new_transaction(net);
  if ((packet_length=my_net_read(net)) == packet_error)
  {
630 631 632 633 634
    DBUG_PRINT("info",("Got error %d reading command from socket %s",
		       net->error,
		       vio_description(net->vio)));
    /* Check if we can continue without closing the connection */
    if (net->error != 3)
635 636
    {
      statistic_increment(aborted_threads,&LOCK_status);
637
      DBUG_RETURN(TRUE);			// We have to close it.
638
    }
639
    net_send_error(thd, net->last_errno, NullS);
640
    net->error= 0;
641
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
642 643 644 645 646
  }
  else
  {
    packet=(char*) net->read_pos;
    command = (enum enum_server_command) (uchar) packet[0];
647 648
    if (command >= COM_END)
      command= COM_END;				// Wrong command
unknown's avatar
unknown committed
649 650
    DBUG_PRINT("info",("Command on %s = %d (%s)",
		       vio_description(net->vio), command,
unknown's avatar
unknown committed
651
		       command_name[command].str));
unknown's avatar
unknown committed
652
  }
unknown's avatar
unknown committed
653 654 655 656

  /* Restore read timeout value */
  net_set_read_timeout(net, thd->variables.net_read_timeout);

657 658 659 660 661 662 663 664 665
  /*
    packet_length contains length of data, as it was stored in packet
    header. In case of malformed header, packet_length can be zero.
    If packet_length is not zero, my_net_read ensures that this number
    of bytes was actually read from network. Additionally my_net_read
    sets packet[packet_length]= 0 (thus if packet_length == 0,
    command == packet[0] == COM_SLEEP).
    In dispatch_command packet[packet_length] points beyond the end of packet.
  */
unknown's avatar
unknown committed
666
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
667
}
668
#endif  /* EMBEDDED_LIBRARY */
669

670

671 672
/*
   Perform one connection-level (COM_XXXX) command.
673

674 675 676 677 678 679 680 681 682 683 684 685 686
  SYNOPSIS
    dispatch_command()
    thd             connection handle
    command         type of command to perform 
    packet          data for the command, packet is always null-terminated
    packet_length   length of packet + 1 (to show that data is
                    null-terminated) except for COM_SLEEP, where it
                    can be zero.
  RETURN VALUE
    0   ok
    1   request of thread shutdown, i. e. if command is
        COM_QUIT/COM_SHUTDOWN
*/
687

688 689 690 691
bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
692
  bool error= 0;
693 694
  DBUG_ENTER("dispatch_command");

695
  if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
696
  {
697
    thd->killed= THD::NOT_KILLED;
698 699
    thd->mysys_var->abort= 0;
  }
700

701
  thd->command=command;
unknown's avatar
unknown committed
702
  /*
703 704
    Commands which always take a long time are logged into
    the slow log only if opt_log_slow_admin_statements is set.
unknown's avatar
unknown committed
705
  */
706
  thd->enable_slow_log= TRUE;
707
  thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
unknown's avatar
unknown committed
708
  thd->set_time();
unknown's avatar
unknown committed
709
  VOID(pthread_mutex_lock(&LOCK_thread_count));
unknown's avatar
unknown committed
710
  thd->query_id= global_query_id;
unknown's avatar
unknown committed
711
  if (command != COM_STATISTICS && command != COM_PING)
712
    next_query_id();
unknown's avatar
unknown committed
713
  thread_running++;
714
  /* TODO: set thd->lex->sql_command to SQLCOM_END here */
unknown's avatar
unknown committed
715
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
716

717 718
  thd->server_status&=
           ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
719
  switch (command) {
unknown's avatar
unknown committed
720
  case COM_INIT_DB:
unknown's avatar
unknown committed
721 722
  {
    LEX_STRING tmp;
723 724
    statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB],
			&LOCK_status);
unknown's avatar
unknown committed
725
    thd->convert_string(&tmp, system_charset_info,
726
			packet, packet_length-1, thd->charset());
unknown's avatar
unknown committed
727
    if (!mysql_change_db(thd, &tmp, FALSE))
728
    {
unknown's avatar
unknown committed
729
      general_log_print(thd, command, "%s",thd->db);
730 731
      send_ok(thd);
    }
unknown's avatar
unknown committed
732 733
    break;
  }
unknown's avatar
unknown committed
734
#ifdef HAVE_REPLICATION
735 736
  case COM_REGISTER_SLAVE:
  {
737
    if (!register_slave(thd, (uchar*)packet, packet_length))
738
      send_ok(thd);
739 740
    break;
  }
741
#endif
unknown's avatar
unknown committed
742
  case COM_TABLE_DUMP:
743
  {
744 745
    char *tbl_name;
    LEX_STRING db;
746
    uint db_len= *(uchar*) packet;
unknown's avatar
unknown committed
747
    if (db_len >= packet_length || db_len > NAME_LEN)
unknown's avatar
unknown committed
748
    {
unknown's avatar
unknown committed
749
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
750 751
      break;
    }
752
    uint tbl_len= *(uchar*) (packet + db_len + 1);
unknown's avatar
unknown committed
753 754
    if (db_len+tbl_len+2 > packet_length || tbl_len > NAME_LEN)
    {
unknown's avatar
unknown committed
755
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
756 757
      break;
    }
758

759
    statistic_increment(thd->status_var.com_other, &LOCK_status);
760
    thd->enable_slow_log= opt_log_slow_admin_statements;
761 762 763
    db.str= thd->alloc(db_len + tbl_len + 2);
    db.length= db_len;
    if (!db.str)
764 765 766 767
    {
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
      break;
    }
768
    tbl_name= strmake(db.str, packet + 1, db_len)+1;
769
    strmake(tbl_name, packet + db_len + 2, tbl_len);
770
    mysql_table_dump(thd, &db, tbl_name);
771 772
    break;
  }
unknown's avatar
unknown committed
773 774
  case COM_CHANGE_USER:
  {
775 776 777 778
    statistic_increment(thd->status_var.com_other, &LOCK_status);
    char *user= (char*) packet, *packet_end= packet+ packet_length;
    char *passwd= strend(user)+1;

unknown's avatar
unknown committed
779
    thd->change_user();
780
    thd->clear_error();                         // if errors from rollback
unknown's avatar
unknown committed
781

782
    /*
unknown's avatar
unknown committed
783 784 785 786
      Old clients send null-terminated string ('\0' for empty string) for
      password.  New clients send the size (1 byte) + string (not null
      terminated, so also '\0' for empty string).
    */
787
    char db_buff[NAME_LEN+1];                 // buffer to store db in utf8
unknown's avatar
unknown committed
788
    char *db= passwd;
789 790 791
    char *save_db;
    uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
                      *passwd++ : strlen(passwd));
792 793
    uint dummy_errors, save_db_length, db_length;
    int res;
794 795 796
    Security_context save_security_ctx= *thd->security_ctx;
    USER_CONN *save_user_connect;

unknown's avatar
unknown committed
797
    db+= passwd_len + 1;
798
#ifndef EMBEDDED_LIBRARY
799
    /* Small check for incoming packet */
unknown's avatar
unknown committed
800
    if ((uint) ((uchar*) db - net->read_pos) > packet_length)
801
    {
unknown's avatar
unknown committed
802
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
803 804
      break;
    }
805
#endif
806
    /* Convert database name to utf8 */
807 808 809 810 811 812 813
    /*
      Handle problem with old bug in client protocol where db had an extra
      \0
    */
    db_length= (packet_end - db);
    if (db_length > 0 && db[db_length-1] == 0)
      db_length--;
814
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
815
                             system_charset_info, db, db_length,
816
                             thd->charset(), &dummy_errors)]= 0;
817
    db= db_buff;
unknown's avatar
unknown committed
818

819
    /* Save user and privileges */
820 821 822
    save_db_length= thd->db_length;
    save_db= thd->db;
    save_user_connect= thd->user_connect;
823 824

    if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
825
    {
826
      thd->security_ctx->user= save_security_ctx.user;
unknown's avatar
unknown committed
827
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
828 829
      break;
    }
unknown's avatar
unknown committed
830

unknown's avatar
unknown committed
831 832
    /* Clear variables that are allocated */
    thd->user_connect= 0;
833
    res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
unknown's avatar
unknown committed
834

835 836
    if (res)
    {
837
      /* authentication failure, we shall restore old user */
838
      if (res > 0)
unknown's avatar
unknown committed
839
        my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
840 841
      else
        thd->clear_error();                     // Error already sent to client
842 843
      x_free(thd->security_ctx->user);
      *thd->security_ctx= save_security_ctx;
unknown's avatar
unknown committed
844
      thd->user_connect= save_user_connect;
845 846 847 848 849
      thd->db= save_db;
      thd->db_length= save_db_length;
    }
    else
    {
850
#ifndef NO_EMBEDDED_ACCESS_CHECKS
851
      /* we've authenticated new user */
unknown's avatar
unknown committed
852 853
      if (save_user_connect)
	decrease_user_connections(save_user_connect);
854
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
855
      x_free((gptr) save_db);
856
      x_free((gptr)  save_security_ctx.user);
857
    }
unknown's avatar
unknown committed
858 859
    break;
  }
860
  case COM_STMT_EXECUTE:
unknown's avatar
unknown committed
861
  {
862
    mysql_stmt_execute(thd, packet, packet_length);
unknown's avatar
unknown committed
863 864
    break;
  }
865
  case COM_STMT_FETCH:
866 867 868 869
  {
    mysql_stmt_fetch(thd, packet, packet_length);
    break;
  }
870
  case COM_STMT_SEND_LONG_DATA:
unknown's avatar
unknown committed
871
  {
872
    mysql_stmt_get_longdata(thd, packet, packet_length);
unknown's avatar
unknown committed
873 874
    break;
  }
875
  case COM_STMT_PREPARE:
unknown's avatar
unknown committed
876
  {
877
    mysql_stmt_prepare(thd, packet, packet_length);
unknown's avatar
unknown committed
878 879
    break;
  }
880
  case COM_STMT_CLOSE:
unknown's avatar
unknown committed
881
  {
882
    mysql_stmt_close(thd, packet);
unknown's avatar
unknown committed
883 884
    break;
  }
885
  case COM_STMT_RESET:
886 887 888 889
  {
    mysql_stmt_reset(thd, packet);
    break;
  }
unknown's avatar
unknown committed
890 891
  case COM_QUERY:
  {
892 893
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
894
    char *packet_end= thd->query + thd->query_length;
unknown's avatar
unknown committed
895 896
    /* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */
    const char *format= "%.*b";
unknown's avatar
unknown committed
897
    general_log_print(thd, command, format, thd->query_length, thd->query);
898
    DBUG_PRINT("query",("%-.4096s",thd->query));
899 900 901 902

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

903
    mysql_parse(thd,thd->query, thd->query_length);
904

905
    while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error)
906
    {
unknown's avatar
unknown committed
907
      char *next_packet= thd->lex->found_semicolon;
908
      net->no_send_error= 0;
909
      /*
910 911
        Multiple queries exits, execute them individually
      */
912 913
      if (thd->lock || thd->open_tables || thd->derived_tables ||
          thd->prelocked_mode)
914
        close_thread_tables(thd);
unknown's avatar
unknown committed
915
      ulong length= (ulong)(packet_end - next_packet);
916

917
      log_slow_statement(thd);
918

919
      /* Remove garbage at start of query */
unknown's avatar
unknown committed
920
      while (my_isspace(thd->charset(), *next_packet) && length > 0)
921
      {
unknown's avatar
unknown committed
922
        next_packet++;
923 924
        length--;
      }
unknown's avatar
unknown committed
925
      VOID(pthread_mutex_lock(&LOCK_thread_count));
926
      thd->query_length= length;
unknown's avatar
unknown committed
927
      thd->query= next_packet;
928
      thd->query_id= next_query_id();
929
      thd->set_time(); /* Reset the query start time. */
930
      /* TODO: set thd->lex->sql_command to SQLCOM_END here */
931
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
932
      mysql_parse(thd, next_packet, length);
933 934
    }

unknown's avatar
unknown committed
935 936 937 938 939
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
940
  case COM_FIELD_LIST:				// This isn't actually needed
unknown's avatar
unknown committed
941
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
942 943
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
unknown's avatar
unknown committed
944 945 946
    break;
#else
  {
947
    char *fields, *packet_end= packet + packet_length - 1, *arg_end;
948
    /* Locked closure of all tables */
unknown's avatar
unknown committed
949
    TABLE_LIST table_list;
unknown's avatar
unknown committed
950
    LEX_STRING conv_name;
951
    uint dummy;
unknown's avatar
unknown committed
952

unknown's avatar
unknown committed
953 954
    /* used as fields initializator */
    lex_start(thd, 0, 0);
955

956 957
    statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
			&LOCK_status);
unknown's avatar
unknown committed
958
    bzero((char*) &table_list,sizeof(table_list));
959
    if (thd->copy_db_to(&table_list.db, &dummy))
unknown's avatar
unknown committed
960
      break;
961 962 963 964
    /*
      We have name + wildcard in packet, separated by endzero
    */
    arg_end= strend(packet);
unknown's avatar
unknown committed
965
    thd->convert_string(&conv_name, system_charset_info,
966
			packet, (uint) (arg_end - packet), thd->charset());
967
    table_list.alias= table_list.table_name= conv_name.str;
968
    packet= arg_end + 1;
969 970

    if (!my_strcasecmp(system_charset_info, table_list.db,
971
                       INFORMATION_SCHEMA_NAME.str))
972 973 974 975 976 977
    {
      ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
      if (schema_table)
        table_list.schema_table= schema_table;
    }

978
    thd->query_length= (uint) (packet_end - packet); // Don't count end \0
unknown's avatar
unknown committed
979 980
    if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
      break;
unknown's avatar
unknown committed
981
    general_log_print(thd, command, "%s %s", table_list.table_name, fields);
982
    if (lower_case_table_names)
983
      my_casedn_str(files_charset_info, table_list.table_name);
unknown's avatar
unknown committed
984

unknown's avatar
unknown committed
985
    if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
986
		     0, 0, test(table_list.schema_table)))
unknown's avatar
unknown committed
987
      break;
unknown's avatar
unknown committed
988 989
    if (grant_option &&
	check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
990
      break;
991 992
    /* init structures for VIEW processing */
    table_list.select_lex= &(thd->lex->select_lex);
993
    mysql_init_query(thd, "", 0);
994 995 996
    thd->lex->
      select_lex.table_list.link_in_list((byte*) &table_list,
                                         (byte**) &table_list.next_local);
unknown's avatar
unknown committed
997
    thd->lex->add_to_query_tables(&table_list);
998

999 1000
    /* switch on VIEW optimisation: do not fill temporary tables */
    thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
unknown's avatar
unknown committed
1001
    mysqld_list_fields(thd,&table_list,fields);
1002
    thd->lex->unit.cleanup();
1003
    thd->cleanup_after_query();
unknown's avatar
unknown committed
1004 1005 1006 1007
    break;
  }
#endif
  case COM_QUIT:
1008
    /* We don't calculate statistics for this command */
unknown's avatar
unknown committed
1009
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1010 1011 1012 1013
    net->error=0;				// Don't give 'abort' message
    error=TRUE;					// End server
    break;

1014
#ifdef REMOVED
unknown's avatar
unknown committed
1015
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1016
    {
1017
      LEX_STRING db, alias;
1018
      HA_CREATE_INFO create_info;
unknown's avatar
unknown committed
1019

1020 1021
      statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB],
			  &LOCK_status);
1022 1023 1024
      if (thd->LEX_STRING_make(&db, packet, packet_length -1) ||
          thd->LEX_STRING_make(&alias, db.str, db.length) ||
          check_db_name(&db))
1025
      {
1026
	my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
1027 1028
	break;
      }
1029 1030
      if (check_access(thd, CREATE_ACL, db.str , 0, 1, 0,
                       is_schema_db(db.str)))
unknown's avatar
unknown committed
1031
	break;
unknown's avatar
unknown committed
1032
      general_log_print(thd, command, packet);
1033
      bzero(&create_info, sizeof(create_info));
1034
      mysql_create_db(thd, (lower_case_table_names == 2 ? alias.str : db.str),
1035
                      &create_info, 0);
unknown's avatar
unknown committed
1036 1037
      break;
    }
unknown's avatar
unknown committed
1038
  case COM_DROP_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1039
    {
1040 1041
      statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB],
			  &LOCK_status);
1042 1043 1044 1045
      LEX_STRING db;

      if (thd->LEX_STRING_make(&db, packet, packet_length - 1) ||
          check_db_name(&db))
1046
      {
1047
	my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
1048 1049
	break;
      }
1050
      if (check_access(thd, DROP_ACL, db.str, 0, 1, 0, is_schema_db(db.str)))
1051
	break;
unknown's avatar
unknown committed
1052 1053
      if (thd->locked_tables || thd->active_transaction())
      {
unknown's avatar
unknown committed
1054 1055
	my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                   ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
unknown's avatar
unknown committed
1056
	break;
unknown's avatar
unknown committed
1057
      }
1058 1059
      general_log_print(thd, command, db.str);
      mysql_rm_db(thd, db.str, 0, 0);
unknown's avatar
unknown committed
1060 1061
      break;
    }
1062
#endif
1063
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1064 1065
  case COM_BINLOG_DUMP:
    {
unknown's avatar
unknown committed
1066 1067 1068 1069
      ulong pos;
      ushort flags;
      uint32 slave_server_id;

1070
      statistic_increment(thd->status_var.com_other,&LOCK_status);
1071
      thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
unknown committed
1072
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1073
	break;
unknown's avatar
unknown committed
1074

1075
      /* TODO: The following has to be changed to an 8 byte integer */
1076 1077
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
1078
      thd->server_id=0; /* avoid suicide */
unknown's avatar
unknown committed
1079
      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
unknown's avatar
unknown committed
1080
	kill_zombie_dump_threads(slave_server_id);
1081
      thd->server_id = slave_server_id;
unknown's avatar
unknown committed
1082

unknown's avatar
unknown committed
1083
      general_log_print(thd, command, "Log: '%s'  Pos: %ld", packet+10,
unknown's avatar
unknown committed
1084
                      (long) pos);
1085
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1086
      unregister_slave(thd,1,1);
unknown's avatar
unknown committed
1087
      /*  fake COM_QUIT -- if we get here, the thread needs to terminate */
1088 1089
      error = TRUE;
      net->error = 0;
unknown's avatar
unknown committed
1090 1091
      break;
    }
1092
#endif
unknown's avatar
unknown committed
1093
  case COM_REFRESH:
unknown's avatar
unknown committed
1094 1095 1096 1097 1098 1099
  {
    bool not_used;
    statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH],
                        &LOCK_status);
    ulong options= (ulong) (uchar) packet[0];
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1100
      break;
unknown's avatar
unknown committed
1101
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1102 1103 1104 1105
    if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
      send_ok(thd);
    break;
  }
1106
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1107
  case COM_SHUTDOWN:
1108
  {
1109
    statistic_increment(thd->status_var.com_other, &LOCK_status);
unknown's avatar
unknown committed
1110
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1111
      break; /* purecov: inspected */
1112
    /*
1113 1114 1115 1116
      If the client is < 4.1.3, it is going to send us no argument; then
      packet_length is 1, packet[0] is the end 0 of the packet. Note that
      SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in
      packet[0].
1117
    */
1118 1119
    enum mysql_enum_shutdown_level level=
      (enum mysql_enum_shutdown_level) (uchar) packet[0];
1120 1121 1122 1123 1124 1125 1126
    if (level == SHUTDOWN_DEFAULT)
      level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable
    else if (level != SHUTDOWN_WAIT_ALL_BUFFERS)
    {
      my_error(ER_NOT_SUPPORTED_YET, MYF(0), "this shutdown level");
      break;
    }
1127
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
unknown's avatar
unknown committed
1128
    general_log_print(thd, command, NullS);
1129
    send_eof(thd);
unknown's avatar
unknown committed
1130 1131 1132
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
1133 1134 1135 1136 1137 1138
    /*
      The client is next going to send a COM_QUIT request (as part of
      mysql_close()). Make the life simpler for the client by sending
      the response for the coming COM_QUIT in advance
    */
    send_eof(thd);
1139
    close_connection(thd, 0, 1);
unknown's avatar
unknown committed
1140 1141 1142 1143
    close_thread_tables(thd);			// Free before kill
    kill_mysql();
    error=TRUE;
    break;
1144
  }
1145
#endif
unknown's avatar
unknown committed
1146 1147
  case COM_STATISTICS:
  {
1148 1149 1150
    STATUS_VAR current_global_status_var;
    ulong uptime;
    uint length;
1151
    ulonglong queries_per_second1000;
unknown's avatar
unknown committed
1152
#ifndef EMBEDDED_LIBRARY
1153 1154
    char buff[250];
    uint buff_len= sizeof(buff);
unknown's avatar
unknown committed
1155 1156
#else
    char *buff= thd->net.last_error;
1157
    uint buff_len= sizeof(thd->net.last_error);
unknown's avatar
unknown committed
1158
#endif
1159

1160 1161 1162
    general_log_print(thd, command, NullS);
    statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS],
			&LOCK_status);
1163
    calc_sum_of_all_status(&current_global_status_var);
1164 1165 1166 1167 1168
    if (!(uptime= (ulong) (thd->start_time - server_start_time)))
      queries_per_second1000= 0;
    else
      queries_per_second1000= thd->query_id * LL(1000) / uptime;

1169 1170 1171
    length= my_snprintf((char*) buff, buff_len - 1,
                        "Uptime: %lu  Threads: %d  Questions: %lu  "
                        "Slow queries: %lu  Opens: %lu  Flush tables: %lu  "
1172
                        "Open tables: %u  Queries per second avg: %u.%u",
1173 1174 1175 1176 1177 1178
                        uptime,
                        (int) thread_count, (ulong) thd->query_id,
                        current_global_status_var.long_query_count,
                        current_global_status_var.opened_tables,
                        refresh_version,
                        cached_open_tables(),
1179 1180
                        (uint) (queries_per_second1000 / 1000),
                        (uint) (queries_per_second1000 % 1000));
unknown's avatar
unknown committed
1181
#ifdef SAFEMALLOC
1182
    if (sf_malloc_cur_memory)				// Using SAFEMALLOC
1183 1184 1185 1186 1187 1188 1189
    {
      char *end= buff + length;
      length+= my_snprintf(end, buff_len - length - 1,
                           end,"  Memory in use: %ldK  Max memory used: %ldK",
                           (sf_malloc_cur_memory+1023L)/1024L,
                           (sf_malloc_max_memory+1023L)/1024L);
    }
unknown's avatar
unknown committed
1190 1191
#endif
#ifndef EMBEDDED_LIBRARY
1192 1193
    VOID(my_net_write(net, buff, length));
      VOID(net_flush(net));
unknown's avatar
unknown committed
1194
#endif
unknown's avatar
unknown committed
1195 1196 1197
    break;
  }
  case COM_PING:
1198
    statistic_increment(thd->status_var.com_other, &LOCK_status);
1199
    send_ok(thd);				// Tell client we are alive
unknown's avatar
unknown committed
1200 1201
    break;
  case COM_PROCESS_INFO:
1202 1203
    statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
			&LOCK_status);
1204 1205
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd, PROCESS_ACL))
unknown's avatar
unknown committed
1206
      break;
unknown's avatar
unknown committed
1207
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1208
    mysqld_list_processes(thd,
1209 1210
			  thd->security_ctx->master_access & PROCESS_ACL ? 
			  NullS : thd->security_ctx->priv_user, 0);
unknown's avatar
unknown committed
1211 1212 1213
    break;
  case COM_PROCESS_KILL:
  {
1214
    statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
1215
    ulong id=(ulong) uint4korr(packet);
1216
    sql_kill(thd,id,false);
unknown's avatar
unknown committed
1217 1218
    break;
  }
1219 1220
  case COM_SET_OPTION:
  {
1221 1222
    statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION],
			&LOCK_status);
unknown's avatar
unknown committed
1223 1224 1225 1226
    uint opt_command= uint2korr(packet);

    switch (opt_command) {
    case (int) MYSQL_OPTION_MULTI_STATEMENTS_ON:
1227
      thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
unknown's avatar
unknown committed
1228
      send_eof(thd);
1229
      break;
unknown's avatar
unknown committed
1230
    case (int) MYSQL_OPTION_MULTI_STATEMENTS_OFF:
1231
      thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
unknown's avatar
unknown committed
1232
      send_eof(thd);
1233 1234
      break;
    default:
unknown's avatar
unknown committed
1235
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1236 1237 1238 1239
      break;
    }
    break;
  }
unknown's avatar
unknown committed
1240
  case COM_DEBUG:
1241
    statistic_increment(thd->status_var.com_other, &LOCK_status);
unknown's avatar
unknown committed
1242
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1243
      break;					/* purecov: inspected */
1244
    mysql_print_status();
unknown's avatar
unknown committed
1245
    general_log_print(thd, command, NullS);
1246
    send_eof(thd);
unknown's avatar
unknown committed
1247 1248 1249 1250 1251
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
1252
  case COM_END:
unknown's avatar
unknown committed
1253
  default:
unknown's avatar
unknown committed
1254
    my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
1255 1256
    break;
  }
1257 1258
  if (thd->lock || thd->open_tables || thd->derived_tables ||
      thd->prelocked_mode)
unknown's avatar
unknown committed
1259 1260 1261 1262
  {
    thd->proc_info="closing tables";
    close_thread_tables(thd);			/* Free tables */
  }
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272
  /*
    assume handlers auto-commit (if some doesn't - transaction handling
    in MySQL should be redesigned to support it; it's a big change,
    and it's not worth it - better to commit explicitly only writing
    transactions, read-only ones should better take care of themselves.
    saves some work in 2pc too)
    see also sql_base.cc - close_thread_tables()
  */
  bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
  if (!thd->active_transaction())
1273
    thd->transaction.xid_state.xid.null();
unknown's avatar
unknown committed
1274

unknown's avatar
unknown committed
1275 1276 1277
  /* report error issued during command execution */
  if (thd->killed_errno() && !thd->net.report_error)
    thd->send_kill_message();
unknown's avatar
unknown committed
1278
  if (thd->net.report_error)
1279
    net_send_error(thd);
unknown's avatar
unknown committed
1280

1281
  log_slow_statement(thd);
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296

  thd->proc_info="cleaning up";
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
  thd->proc_info=0;
  thd->command=COM_SLEEP;
  thd->query=0;
  thd->query_length=0;
  thread_running--;
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
  thd->packet.shrink(thd->variables.net_buffer_length);	// Reclaim some memory
  free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
  DBUG_RETURN(error);
}


1297
void log_slow_statement(THD *thd)
1298
{
1299
  time_t start_of_query;
unknown's avatar
unknown committed
1300
  DBUG_ENTER("log_slow_statement");
1301 1302 1303 1304 1305 1306 1307

  /*
    The following should never be true with our current code base,
    but better to keep this here so we don't accidently try to log a
    statement in a trigger or stored function
  */
  if (unlikely(thd->in_sub_stmt))
unknown's avatar
unknown committed
1308
    DBUG_VOID_RETURN;                           // Don't set time for sub stmt
1309 1310

  start_of_query= thd->start_time;
1311
  thd->end_time();				// Set start time
1312

1313 1314 1315 1316 1317
  /*
    Do not log administrative statements unless the appropriate option is
    set; do not log into slow log if reading from backup.
  */
  if (thd->enable_slow_log && !thd->user_time)
unknown's avatar
unknown committed
1318
  {
1319 1320
    thd->proc_info="logging slow query";

1321 1322
    if ((ulong) (thd->start_time - thd->time_after_lock) >
	thd->variables.long_query_time ||
1323 1324
	((thd->server_status &
	  (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
1325
	 (specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES)))
1326
    {
1327
      thd->status_var.long_query_count++;
unknown's avatar
unknown committed
1328
      slow_log_print(thd, thd->query, thd->query_length, start_of_query);
1329
    }
unknown's avatar
unknown committed
1330
  }
unknown's avatar
unknown committed
1331
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
1332 1333
}

1334

unknown's avatar
unknown committed
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362
/*
  Create a TABLE_LIST object for an INFORMATION_SCHEMA table.

  SYNOPSIS
    prepare_schema_table()
      thd              thread handle
      lex              current lex
      table_ident      table alias if it's used
      schema_table_idx the type of the INFORMATION_SCHEMA table to be
                       created

  DESCRIPTION
    This function is used in the parser to convert a SHOW or DESCRIBE
    table_name command to a SELECT from INFORMATION_SCHEMA.
    It prepares a SELECT_LEX and a TABLE_LIST object to represent the
    given command as a SELECT parse tree.

  NOTES
    Due to the way this function works with memory and LEX it cannot
    be used outside the parser (parse tree transformations outside
    the parser break PS and SP).

  RETURN VALUE
    0                 success
    1                 out of memory or SHOW commands are not allowed
                      in this version of the server.
*/

1363 1364 1365
int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
                         enum enum_schema_tables schema_table_idx)
{
1366
  SELECT_LEX *schema_select_lex= NULL;
1367
  DBUG_ENTER("prepare_schema_table");
1368

1369
  switch (schema_table_idx) {
1370 1371
  case SCH_SCHEMATA:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
unknown's avatar
unknown committed
1372 1373
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0));   /* purecov: inspected */
1374 1375 1376 1377
    DBUG_RETURN(1);
#else
    break;
#endif
1378

1379 1380 1381
  case SCH_TABLE_NAMES:
  case SCH_TABLES:
  case SCH_VIEWS:
1382
  case SCH_TRIGGERS:
unknown's avatar
unknown committed
1383
  case SCH_EVENTS:
1384
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1385 1386
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1387 1388 1389
    DBUG_RETURN(1);
#else
    {
1390 1391
      LEX_STRING db;
      uint dummy;
unknown's avatar
unknown committed
1392
      if (lex->select_lex.db == NULL &&
1393
          thd->copy_db_to(&lex->select_lex.db, &dummy))
1394
      {
unknown's avatar
unknown committed
1395
        DBUG_RETURN(1);
1396
      }
1397 1398 1399
      schema_select_lex= new SELECT_LEX();
      db.str= schema_select_lex->db= lex->select_lex.db;
      schema_select_lex->table_list.first= NULL;
1400
      db.length= strlen(db.str);
unknown's avatar
unknown committed
1401

1402
      if (check_db_name(&db))
1403
      {
1404
        my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
1405 1406 1407 1408 1409 1410 1411
        DBUG_RETURN(1);
      }
      break;
    }
#endif
  case SCH_COLUMNS:
  case SCH_STATISTICS:
unknown's avatar
unknown committed
1412
  {
1413
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1414 1415
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1416 1417
    DBUG_RETURN(1);
#else
unknown's avatar
unknown committed
1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
    DBUG_ASSERT(table_ident);
    TABLE_LIST **query_tables_last= lex->query_tables_last;
    schema_select_lex= new SELECT_LEX();
    /* 'parent_lex' is used in init_query() so it must be before it. */
    schema_select_lex->parent_lex= lex;
    schema_select_lex->init_query();
    if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
      DBUG_RETURN(1);
    lex->query_tables_last= query_tables_last;
    break;
  }
1429
#endif
1430 1431 1432
  case SCH_OPEN_TABLES:
  case SCH_VARIABLES:
  case SCH_STATUS:
1433 1434
  case SCH_PROCEDURES:
  case SCH_CHARSETS:
unknown's avatar
unknown committed
1435
  case SCH_ENGINES:
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
  case SCH_COLLATIONS:
  case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
  case SCH_USER_PRIVILEGES:
  case SCH_SCHEMA_PRIVILEGES:
  case SCH_TABLE_PRIVILEGES:
  case SCH_COLUMN_PRIVILEGES:
  case SCH_TABLE_CONSTRAINTS:
  case SCH_KEY_COLUMN_USAGE:
  default:
    break;
  }
  
  SELECT_LEX *select_lex= lex->current_select;
  if (make_schema_select(thd, select_lex, schema_table_idx))
  {
    DBUG_RETURN(1);
  }
  TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
unknown's avatar
unknown committed
1454
  table_list->schema_select_lex= schema_select_lex;
1455
  table_list->schema_table_reformed= 1;
1456 1457 1458 1459
  DBUG_RETURN(0);
}


1460 1461
/*
  Read query from packet and store in thd->query
1462
  Used in COM_QUERY and COM_STMT_PREPARE
1463 1464 1465 1466 1467 1468 1469

  DESCRIPTION
    Sets the following THD variables:
      query
      query_length

  RETURN VALUES
unknown's avatar
unknown committed
1470 1471
    FALSE ok
    TRUE  error;  In this case thd->fatal_error is set
1472 1473
*/

1474
bool alloc_query(THD *thd, const char *packet, uint packet_length)
1475 1476
{
  packet_length--;				// Remove end null
1477
  /* Remove garbage at start and end of query */
unknown's avatar
unknown committed
1478
  while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
1479 1480 1481 1482
  {
    packet++;
    packet_length--;
  }
1483
  const char *pos= packet + packet_length;     // Point at end null
unknown's avatar
unknown committed
1484
  while (packet_length > 0 &&
unknown's avatar
unknown committed
1485
	 (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
1486 1487 1488 1489 1490
  {
    pos--;
    packet_length--;
  }
  /* We must allocate some extra memory for query cache */
unknown's avatar
unknown committed
1491
  thd->query_length= 0;                        // Extra safety: Avoid races
1492 1493
  if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
					      packet_length,
1494 1495
					      thd->db_length+ 1 +
					      QUERY_CACHE_FLAGS_SIZE)))
unknown's avatar
unknown committed
1496
    return TRUE;
1497 1498
  thd->query[packet_length]=0;
  thd->query_length= packet_length;
1499 1500 1501 1502

  /* Reclaim some memory */
  thd->packet.shrink(thd->variables.net_buffer_length);
  thd->convert_buffer.shrink(thd->variables.net_buffer_length);
1503

unknown's avatar
unknown committed
1504
  return FALSE;
1505 1506
}

1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519
static void reset_one_shot_variables(THD *thd) 
{
  thd->variables.character_set_client=
    global_system_variables.character_set_client;
  thd->variables.collation_connection=
    global_system_variables.collation_connection;
  thd->variables.collation_database=
    global_system_variables.collation_database;
  thd->variables.collation_server=
    global_system_variables.collation_server;
  thd->update_charset();
  thd->variables.time_zone=
    global_system_variables.time_zone;
1520
  thd->variables.lc_time_names= &my_locale_en_US;
1521 1522 1523
  thd->one_shot_set= 0;
}

1524

1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609
static
bool sp_process_definer(THD *thd)
{
  DBUG_ENTER("sp_process_definer");

  LEX *lex= thd->lex;

  /*
    If the definer is not specified, this means that CREATE-statement missed
    DEFINER-clause. DEFINER-clause can be missed in two cases:

      - The user submitted a statement w/o the clause. This is a normal
        case, we should assign CURRENT_USER as definer.

      - Our slave received an updated from the master, that does not
        replicate definer for stored rountines. We should also assign
        CURRENT_USER as definer here, but also we should mark this routine
        as NON-SUID. This is essential for the sake of backward
        compatibility.

        The problem is the slave thread is running under "special" user (@),
        that actually does not exist. In the older versions we do not fail
        execution of a stored routine if its definer does not exist and
        continue the execution under the authorization of the invoker
        (BUG#13198). And now if we try to switch to slave-current-user (@),
        we will fail.

        Actually, this leads to the inconsistent state of master and
        slave (different definers, different SUID behaviour), but it seems,
        this is the best we can do.
  */

  if (!lex->definer)
  {
    Query_arena original_arena;
    Query_arena *ps_arena= thd->activate_stmt_arena_if_needed(&original_arena);

    lex->definer= create_default_definer(thd);

    if (ps_arena)
      thd->restore_active_arena(ps_arena, &original_arena);

    /* Error has been already reported. */
    if (lex->definer == NULL)
      DBUG_RETURN(TRUE);

    if (thd->slave_thread)
      lex->sphead->m_chistics->suid= SP_IS_NOT_SUID;
  }
  else
  {
    /*
      If the specified definer differs from the current user, we
      should check that the current user has SUPER privilege (in order
      to create a stored routine under another user one must have
      SUPER privilege).
    */
    if ((strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
         my_strcasecmp(system_charset_info, lex->definer->host.str,
                       thd->security_ctx->priv_host)) &&
        check_global_access(thd, SUPER_ACL))
    {
      my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
      DBUG_RETURN(TRUE);
    }
  }

  /* Check that the specified definer exists. Emit a warning if not. */

#ifndef NO_EMBEDDED_ACCESS_CHECKS
  if (!is_acl_user(lex->definer->host.str, lex->definer->user.str))
  {
    push_warning_printf(thd,
                        MYSQL_ERROR::WARN_LEVEL_NOTE,
                        ER_NO_SUCH_USER,
                        ER(ER_NO_SUCH_USER),
                        lex->definer->user.str,
                        lex->definer->host.str);
  }
#endif /* NO_EMBEDDED_ACCESS_CHECKS */

  DBUG_RETURN(FALSE);
}


1610
/*
1611
  Execute command saved in thd and lex->sql_command
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632

  SYNOPSIS
    mysql_execute_command()
      thd                       Thread handle

  IMPLEMENTATION

    Before every operation that can request a write lock for a table
    wait if a global read lock exists. However do not wait if this
    thread has locked tables already. No new locks can be requested
    until the other locks are released. The thread that requests the
    global read lock waits for write locked tables to become unlocked.

    Note that wait_if_global_read_lock() sets a protection against a new
    global read lock when it succeeds. This needs to be released by
    start_waiting_global_read_lock() after the operation.

  RETURN
    FALSE       OK
    TRUE        Error
*/
unknown's avatar
unknown committed
1633

unknown's avatar
unknown committed
1634
bool
1635
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
1636
{
1637 1638
  bool res= FALSE;
  bool need_start_waiting= FALSE; // have protection against global read lock
unknown's avatar
unknown committed
1639
  int  up_result= 0;
1640
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
1641
  /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
unknown's avatar
unknown committed
1642
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
1643
  /* first table of first SELECT_LEX */
unknown's avatar
unknown committed
1644
  TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
unknown's avatar
VIEW  
unknown committed
1645 1646 1647
  /* list of all tables in query */
  TABLE_LIST *all_tables;
  /* most outer SELECT_LEX_UNIT of query */
1648
  SELECT_LEX_UNIT *unit= &lex->unit;
1649
  /* Saved variable value */
unknown's avatar
unknown committed
1650
  DBUG_ENTER("mysql_execute_command");
1651
  thd->net.no_send_error= 0;
unknown's avatar
unknown committed
1652 1653 1654
#ifdef WITH_PARTITION_STORAGE_ENGINE
  thd->work_part_info= 0;
#endif
unknown's avatar
unknown committed
1655

unknown's avatar
VIEW  
unknown committed
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671
  /*
    In many cases first table of main SELECT_LEX have special meaning =>
    check that it is first table in global list and relink it first in 
    queries_tables list if it is necessary (we need such relinking only
    for queries with subqueries in select list, in this case tables of
    subqueries will go to global list first)

    all_tables will differ from first_table only if most upper SELECT_LEX
    do not contain tables.

    Because of above in place where should be at least one table in most
    outer SELECT_LEX we have following check:
    DBUG_ASSERT(first_table == all_tables);
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
  */
  lex->first_lists_tables_same();
1672
  /* should be assigned after making first tables same */
unknown's avatar
VIEW  
unknown committed
1673
  all_tables= lex->query_tables;
1674 1675 1676 1677
  /* set context for commands which do not use setup_tables */
  select_lex->
    context.resolve_in_table_list_only((TABLE_LIST*)select_lex->
                                       table_list.first);
unknown's avatar
VIEW  
unknown committed
1678

1679 1680 1681 1682 1683
  /*
    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.
1684
    Don't reset warnings when executing a stored routine.
1685
  */
1686
  if ((all_tables || &lex->select_lex != lex->all_selects_list ||
1687
       lex->sroutines.records) && !thd->spcont)
unknown's avatar
unknown committed
1688
    mysql_reset_errors(thd, 0);
1689

unknown's avatar
SCRUM  
unknown committed
1690
#ifdef HAVE_REPLICATION
1691
  if (unlikely(thd->slave_thread))
1692
  {
1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716
    if (lex->sql_command == SQLCOM_DROP_TRIGGER)
    {
      /*
        When dropping a trigger, we need to load its table name
        before checking slave filter rules.
      */
      add_table_for_trigger(thd, thd->lex->spname, 1, &all_tables);
      
      if (!all_tables)
      {
        /*
          If table name cannot be loaded,
          it means the trigger does not exists possibly because
          CREATE TRIGGER was previously skipped for this trigger
          according to slave filtering rules.
          Returning success without producing any errors in this case.
        */
        DBUG_RETURN(0);
      }
      
      // force searching in slave.cc:tables_ok() 
      all_tables->updating= 1;
    }
    
unknown's avatar
unknown committed
1717
    /*
unknown's avatar
unknown committed
1718 1719
      Check if statment should be skipped because of slave filtering
      rules
1720 1721

      Exceptions are:
unknown's avatar
unknown committed
1722 1723
      - UPDATE MULTI: For this statement, we want to check the filtering
        rules later in the code
1724
      - SET: we always execute it (Not that many SET commands exists in
unknown's avatar
unknown committed
1725 1726
        the binary log anyway -- only 4.1 masters write SET statements,
	in 5.0 there are no SET statements in the binary log)
1727 1728
      - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we
        have stale files on slave caused by exclusion of one tmp table).
unknown's avatar
merge  
unknown committed
1729
    */
unknown's avatar
unknown committed
1730 1731
    if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
	!(lex->sql_command == SQLCOM_SET_OPTION) &&
1732
	!(lex->sql_command == SQLCOM_DROP_TABLE &&
1733
          lex->drop_temporary && lex->drop_if_exists) &&
unknown's avatar
Merge  
unknown committed
1734
        all_tables_not_ok(thd, all_tables))
unknown's avatar
unknown committed
1735 1736
    {
      /* we warn the slave SQL thread */
unknown's avatar
unknown committed
1737
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754
      if (thd->one_shot_set)
      {
        /*
          It's ok to check thd->one_shot_set here:

          The charsets in a MySQL 5.0 slave can change by both a binlogged
          SET ONE_SHOT statement and the event-internal charset setting, 
          and these two ways to change charsets do not seems to work
          together.

          At least there seems to be problems in the rli cache for
          charsets if we are using ONE_SHOT.  Note that this is normally no
          problem because either the >= 5.0 slave reads a 4.1 binlog (with
          ONE_SHOT) *or* or 5.0 binlog (without ONE_SHOT) but never both."
        */
        reset_one_shot_variables(thd);
      }
1755
      DBUG_RETURN(0);
unknown's avatar
unknown committed
1756
    }
1757
  }
1758
  else
1759
  {
1760
#endif /* HAVE_REPLICATION */
1761 1762 1763 1764 1765 1766
    /*
      When option readonly is set deny operations which change non-temporary
      tables. Except for the replication thread and the 'super' users.
    */
    if (opt_readonly &&
	!(thd->security_ctx->master_access & SUPER_ACL) &&
1767
	(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA) &&
1768 1769 1770 1771 1772
        !((lex->sql_command == SQLCOM_CREATE_TABLE) &&
          (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) &&
        !((lex->sql_command == SQLCOM_DROP_TABLE) && lex->drop_temporary) &&
        ((lex->sql_command != SQLCOM_UPDATE_MULTI) &&
          some_non_temp_table_to_be_updated(thd, all_tables)))
1773 1774 1775 1776 1777 1778 1779
    {
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
      DBUG_RETURN(-1);
    }
#ifdef HAVE_REPLICATION
  } /* endif unlikely slave */
#endif
1780 1781
  statistic_increment(thd->status_var.com_stat[lex->sql_command],
                      &LOCK_status);
1782

unknown's avatar
unknown committed
1783
  switch (lex->sql_command) {
1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822
  case SQLCOM_SHOW_EVENTS:
    if ((res= check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0,
                           is_schema_db(thd->lex->select_lex.db))))
      break;
    /* fall through */
  case SQLCOM_SHOW_STATUS_PROC:
  case SQLCOM_SHOW_STATUS_FUNC:
    res= execute_sqlcom_select(thd, all_tables);
    break;
  case SQLCOM_SHOW_STATUS:
  {
    system_status_var old_status_var= thd->status_var;
    thd->initial_status_var= &old_status_var;
    res= execute_sqlcom_select(thd, all_tables);
    /* Don't log SHOW STATUS commands to slow query log */
    thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED |
                           SERVER_QUERY_NO_GOOD_INDEX_USED);
    /*
      restore status variables, as we don't want 'show status' to cause
      changes
    */
    pthread_mutex_lock(&LOCK_status);
    add_diff_to_status(&global_status_var, &thd->status_var,
                       &old_status_var);
    thd->status_var= old_status_var;
    pthread_mutex_unlock(&LOCK_status);
    break;
  }
  case SQLCOM_SHOW_DATABASES:
  case SQLCOM_SHOW_TABLES:
  case SQLCOM_SHOW_TRIGGERS:
  case SQLCOM_SHOW_TABLE_STATUS:
  case SQLCOM_SHOW_OPEN_TABLES:
  case SQLCOM_SHOW_PLUGINS:
  case SQLCOM_SHOW_FIELDS:
  case SQLCOM_SHOW_KEYS:
  case SQLCOM_SHOW_VARIABLES:
  case SQLCOM_SHOW_CHARSETS:
  case SQLCOM_SHOW_COLLATIONS:
unknown's avatar
unknown committed
1823
  case SQLCOM_SELECT:
1824
    thd->status_var.last_query_cost= 0.0;
unknown's avatar
VIEW  
unknown committed
1825
    if (all_tables)
unknown's avatar
unknown committed
1826
    {
1827 1828 1829 1830
      res= check_table_access(thd,
                              lex->exchange ? SELECT_ACL | FILE_ACL :
                              SELECT_ACL,
                              all_tables, 0);
unknown's avatar
unknown committed
1831 1832
    }
    else
unknown's avatar
VIEW  
unknown committed
1833
      res= check_access(thd,
1834 1835 1836 1837
                        lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
                        any_db, 0, 0, 0, 0);
    if (!res)
      res= execute_sqlcom_select(thd, all_tables);
unknown's avatar
unknown committed
1838
    break;
unknown's avatar
unknown committed
1839
  case SQLCOM_PREPARE:
1840
  {
1841
    mysql_sql_stmt_prepare(thd);
unknown's avatar
unknown committed
1842 1843 1844 1845
    break;
  }
  case SQLCOM_EXECUTE:
  {
1846
    mysql_sql_stmt_execute(thd);
unknown's avatar
unknown committed
1847 1848 1849 1850
    break;
  }
  case SQLCOM_DEALLOCATE_PREPARE:
  {
1851
    mysql_sql_stmt_close(thd);
unknown's avatar
unknown committed
1852 1853
    break;
  }
unknown's avatar
unknown committed
1854
  case SQLCOM_DO:
1855 1856
    if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
        open_and_lock_tables(thd, all_tables))
unknown's avatar
unknown committed
1857
      goto error;
unknown's avatar
unknown committed
1858 1859

    res= mysql_do(thd, *lex->insert_list);
unknown's avatar
unknown committed
1860 1861
    break;

1862
  case SQLCOM_EMPTY_QUERY:
1863
    send_ok(thd);
1864 1865
    break;

unknown's avatar
unknown committed
1866 1867 1868 1869
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

1870
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1871
  case SQLCOM_PURGE:
1872
  {
unknown's avatar
unknown committed
1873
    if (check_global_access(thd, SUPER_ACL))
1874
      goto error;
unknown's avatar
unknown committed
1875
    /* PURGE MASTER LOGS TO 'file' */
1876 1877 1878
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
1879 1880
  case SQLCOM_PURGE_BEFORE:
  {
1881 1882
    Item *it;

1883 1884
    if (check_global_access(thd, SUPER_ACL))
      goto error;
unknown's avatar
unknown committed
1885
    /* PURGE MASTER LOGS BEFORE 'data' */
1886
    it= (Item *)lex->value_list.head();
1887
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) ||
unknown's avatar
unknown committed
1888
        it->check_cols(1))
1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899
    {
      my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE");
      goto error;
    }
    it= new Item_func_unix_timestamp(it);
    /*
      it is OK only emulate fix_fieds, because we need only
      value of constant
    */
    it->quick_fix_field();
    res = purge_master_logs_before_date(thd, (ulong)it->val_int());
1900 1901
    break;
  }
1902
#endif
unknown's avatar
unknown committed
1903 1904
  case SQLCOM_SHOW_WARNS:
  {
1905 1906
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
1907 1908 1909
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
unknown's avatar
unknown committed
1910 1911 1912 1913
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
1914 1915
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
1916 1917
    break;
  }
unknown's avatar
unknown committed
1918 1919
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
1920
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1921
      goto error;
1922
    /* This query don't work now. See comment in repl_failsafe.cc */
unknown's avatar
unknown committed
1923
#ifndef WORKING_NEW_MASTER
unknown's avatar
unknown committed
1924 1925
    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
    goto error;
unknown's avatar
unknown committed
1926
#else
unknown's avatar
unknown committed
1927 1928
    res = show_new_master(thd);
    break;
unknown's avatar
unknown committed
1929
#endif
unknown's avatar
unknown committed
1930
  }
1931

unknown's avatar
unknown committed
1932
#ifdef HAVE_REPLICATION
1933 1934
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
1935
    if (check_global_access(thd, REPL_SLAVE_ACL))
1936 1937 1938 1939
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
1940 1941
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
1942
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1943
      goto error;
1944
    res = mysql_show_binlog_events(thd);
unknown's avatar
unknown committed
1945 1946
    break;
  }
1947 1948
#endif

unknown's avatar
unknown committed
1949
  case SQLCOM_BACKUP_TABLE:
1950
  {
unknown's avatar
VIEW  
unknown committed
1951
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
1952
    if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
unknown's avatar
unknown committed
1953
	check_global_access(thd, FILE_ACL))
1954
      goto error; /* purecov: inspected */
1955
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
1956
    res = mysql_backup_table(thd, first_table);
1957
    select_lex->table_list.first= (byte*) first_table;
1958
    lex->query_tables=all_tables;
1959 1960
    break;
  }
unknown's avatar
unknown committed
1961
  case SQLCOM_RESTORE_TABLE:
1962
  {
unknown's avatar
VIEW  
unknown committed
1963
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
1964
    if (check_table_access(thd, INSERT_ACL, all_tables, 0) ||
unknown's avatar
unknown committed
1965
	check_global_access(thd, FILE_ACL))
1966
      goto error; /* purecov: inspected */
1967
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
1968
    res = mysql_restore_table(thd, first_table);
1969
    select_lex->table_list.first= (byte*) first_table;
1970
    lex->query_tables=all_tables;
1971 1972
    break;
  }
unknown's avatar
unknown committed
1973 1974
  case SQLCOM_ASSIGN_TO_KEYCACHE:
  {
unknown's avatar
VIEW  
unknown committed
1975
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
1976
    if (check_access(thd, INDEX_ACL, first_table->db,
1977 1978
                     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
unknown's avatar
unknown committed
1979
      goto error;
1980
    res= mysql_assign_to_keycache(thd, first_table, &lex->ident);
unknown's avatar
unknown committed
1981 1982
    break;
  }
unknown's avatar
unknown committed
1983 1984
  case SQLCOM_PRELOAD_KEYS:
  {
unknown's avatar
VIEW  
unknown committed
1985
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
1986
    if (check_access(thd, INDEX_ACL, first_table->db,
1987 1988
                     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
1989
      goto error;
unknown's avatar
VIEW  
unknown committed
1990
    res = mysql_preload_keys(thd, first_table);
unknown's avatar
unknown committed
1991 1992
    break;
  }
unknown's avatar
unknown committed
1993
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
1994
  case SQLCOM_CHANGE_MASTER:
1995
  {
unknown's avatar
unknown committed
1996
    if (check_global_access(thd, SUPER_ACL))
1997
      goto error;
1998
    pthread_mutex_lock(&LOCK_active_mi);
1999
    res = change_master(thd,active_mi);
2000
    pthread_mutex_unlock(&LOCK_active_mi);
2001 2002
    break;
  }
unknown's avatar
unknown committed
2003
  case SQLCOM_SHOW_SLAVE_STAT:
2004
  {
2005 2006
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2007
      goto error;
2008
    pthread_mutex_lock(&LOCK_active_mi);
2009
    res = show_master_info(thd,active_mi);
2010
    pthread_mutex_unlock(&LOCK_active_mi);
2011 2012
    break;
  }
unknown's avatar
unknown committed
2013
  case SQLCOM_SHOW_MASTER_STAT:
2014
  {
2015 2016
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2017 2018 2019 2020
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
2021

2022
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
2023
    if (check_global_access(thd, SUPER_ACL))
2024
      goto error;
2025
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2026
      goto error;
2027
    res = load_master_data(thd);
2028
    break;
unknown's avatar
unknown committed
2029
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
2030
  case SQLCOM_SHOW_ENGINE_STATUS:
unknown's avatar
unknown committed
2031
    {
2032
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2033 2034
        goto error;
      res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_STATUS);
unknown's avatar
unknown committed
2035 2036
      break;
    }
unknown's avatar
unknown committed
2037
  case SQLCOM_SHOW_ENGINE_MUTEX:
unknown's avatar
unknown committed
2038 2039
    {
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2040
        goto error;
unknown's avatar
unknown committed
2041
      res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
unknown's avatar
unknown committed
2042 2043
      break;
    }
unknown's avatar
unknown committed
2044
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2045
  case SQLCOM_LOAD_MASTER_TABLE:
2046
  {
unknown's avatar
VIEW  
unknown committed
2047
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2048 2049
    DBUG_ASSERT(first_table->db); /* Must be set in the parser */

unknown's avatar
VIEW  
unknown committed
2050
    if (check_access(thd, CREATE_ACL, first_table->db,
2051 2052
		     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
unknown's avatar
unknown committed
2053 2054 2055 2056
      goto error;				/* purecov: inspected */
    if (grant_option)
    {
      /* Check that the first table has CREATE privilege */
unknown's avatar
VIEW  
unknown committed
2057
      if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
2058
	goto error;
unknown's avatar
unknown committed
2059
    }
2060
    pthread_mutex_lock(&LOCK_active_mi);
2061 2062 2063 2064
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
2065
    if (!fetch_master_table(thd, first_table->db, first_table->table_name,
2066
			    active_mi, 0, 0))
2067
    {
2068
      send_ok(thd);
2069
    }
2070
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2071
    break;
2072
  }
unknown's avatar
unknown committed
2073
#endif /* HAVE_REPLICATION */
2074

unknown's avatar
unknown committed
2075
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
2076
  {
2077
    /* If CREATE TABLE of non-temporary table, do implicit commit */
2078 2079 2080 2081 2082 2083 2084 2085
    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
    {
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
unknown's avatar
VIEW  
unknown committed
2086 2087 2088 2089 2090
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    bool link_to_local;
    // Skip first table, which is the table we are creating
    TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
    TABLE_LIST *select_tables= lex->query_tables;
unknown's avatar
unknown committed
2091

unknown's avatar
VIEW  
unknown committed
2092
    if ((res= create_table_precheck(thd, select_tables, create_table)))
unknown's avatar
unknown committed
2093
      goto end_with_restore_list;
unknown's avatar
unknown committed
2094

2095
#ifndef HAVE_READLINK
unknown's avatar
unknown committed
2096
    if (lex->create_info.data_file_name)
2097 2098
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                   "DATA DIRECTORY option ignored");
unknown's avatar
unknown committed
2099
    if (lex->create_info.index_file_name)
2100 2101
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                   "INDEX DIRECTORY option ignored");
2102 2103
    lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
2104
    /* Fix names if symlinked tables */
unknown's avatar
unknown committed
2105
    if (append_file_to_dir(thd, &lex->create_info.data_file_name,
2106
			   create_table->table_name) ||
unknown's avatar
VIEW  
unknown committed
2107
	append_file_to_dir(thd, &lex->create_info.index_file_name,
2108
			   create_table->table_name))
unknown's avatar
unknown committed
2109
      goto end_with_restore_list;
2110
#endif
2111
    /*
2112
      If we are using SET CHARSET without DEFAULT, add an implicit
2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123
      DEFAULT to not confuse old users. (This may change).
    */
    if ((lex->create_info.used_fields & 
	 (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
	HA_CREATE_USED_CHARSET)
    {
      lex->create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
      lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
      lex->create_info.default_table_charset= lex->create_info.table_charset;
      lex->create_info.table_charset= 0;
    }
2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136
    /*
      The create-select command will open and read-lock the select table
      and then create, open and write-lock the new table. If a global
      read lock steps in, we get a deadlock. The write lock waits for
      the global read lock, while the global read lock waits for the
      select table to be closed. So we wait until the global readlock is
      gone before starting both steps. Note that
      wait_if_global_read_lock() sets a protection against a new global
      read lock when it succeeds. This needs to be released by
      start_waiting_global_read_lock(). We protect the normal CREATE
      TABLE in the same way. That way we avoid that a new table is
      created during a gobal read lock.
    */
2137 2138
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
2139
    {
unknown's avatar
unknown committed
2140 2141
      res= 1;
      goto end_with_restore_list;
2142
    }
2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153
#ifdef WITH_PARTITION_STORAGE_ENGINE
    {
      partition_info *part_info= thd->lex->part_info;
      if (part_info && !(part_info= thd->lex->part_info->get_clone()))
      {
        res= -1;
        goto end_with_restore_list;
      }
      thd->work_part_info= part_info;
    }
#endif
2154
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
2155 2156
    {
      select_result *result;
2157

2158
      select_lex->options|= SELECT_NO_UNLOCK;
2159
      unit->set_limit(select_lex);
2160

unknown's avatar
VIEW  
unknown committed
2161
      if (!(res= open_and_lock_tables(thd, select_tables)))
2162
      {
2163 2164 2165 2166
        /*
          Is table which we are changing used somewhere in other parts
          of query
        */
2167
        if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
2168
        {
2169
          TABLE_LIST *duplicate;
2170
          if ((duplicate= unique_table(thd, create_table, select_tables, 0)))
2171 2172 2173
          {
            update_non_unique_table_error(create_table, "CREATE", duplicate);
            res= 1;
2174
            goto end_with_restore_list;
2175
          }
2176
        }
unknown's avatar
unknown committed
2177 2178 2179 2180 2181 2182 2183 2184
        /* If we create merge table, we have to test tables in merge, too */
        if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
        {
          TABLE_LIST *tab;
          for (tab= (TABLE_LIST*) lex->create_info.merge_list.first;
               tab;
               tab= tab->next_local)
          {
2185
            TABLE_LIST *duplicate;
2186
            if ((duplicate= unique_table(thd, tab, select_tables, 0)))
unknown's avatar
unknown committed
2187
            {
2188
              update_non_unique_table_error(tab, "CREATE", duplicate);
unknown's avatar
unknown committed
2189
              res= 1;
2190
              goto end_with_restore_list;
unknown's avatar
unknown committed
2191 2192 2193
            }
          }
        }
2194

unknown's avatar
VIEW  
unknown committed
2195 2196 2197 2198 2199
        if ((result= new select_create(create_table,
				       &lex->create_info,
				       lex->create_list,
				       lex->key_list,
				       select_lex->item_list,
2200 2201
				       lex->duplicates,
				       lex->ignore)))
2202 2203 2204 2205 2206
        {
          /*
            CREATE from SELECT give its SELECT_LEX for SELECT,
            and item_list belong to SELECT
          */
2207
          res= handle_select(thd, lex, result, 0);
2208
          delete result;
2209
        }
unknown's avatar
unknown committed
2210
	/* reset for PS */
2211 2212
	lex->create_list.empty();
	lex->key_list.empty();
2213 2214
      }
    }
unknown's avatar
unknown committed
2215
    else
unknown's avatar
unknown committed
2216
    {
2217 2218 2219
      /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
      if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
        thd->options|= OPTION_KEEP_LOG;
unknown's avatar
unknown committed
2220
      /* regular create */
unknown's avatar
unknown committed
2221
      if (lex->like_name)
unknown's avatar
unknown committed
2222
        res= mysql_create_like_table(thd, create_table, &lex->create_info, 
unknown's avatar
unknown committed
2223
                                     lex->like_name); 
unknown's avatar
unknown committed
2224
      else
2225
      {
unknown's avatar
VIEW  
unknown committed
2226
        res= mysql_create_table(thd, create_table->db,
2227
				create_table->table_name, &lex->create_info,
unknown's avatar
VIEW  
unknown committed
2228
				lex->create_list,
2229
				lex->key_list, 0, 0, 1);
2230
      }
unknown's avatar
unknown committed
2231
      if (!res)
2232
	send_ok(thd);
unknown's avatar
unknown committed
2233
    }
2234

unknown's avatar
unknown committed
2235
    /* put tables back for PS rexecuting */
unknown's avatar
unknown committed
2236
end_with_restore_list:
unknown's avatar
VIEW  
unknown committed
2237
    lex->link_first_table_back(create_table, link_to_local);
unknown's avatar
unknown committed
2238
    break;
unknown's avatar
unknown committed
2239
  }
unknown's avatar
unknown committed
2240
  case SQLCOM_CREATE_INDEX:
unknown's avatar
VIEW  
unknown committed
2241 2242
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, INDEX_ACL, all_tables))
unknown's avatar
unknown committed
2243
      goto error; /* purecov: inspected */
2244
    thd->enable_slow_log= opt_log_slow_admin_statements;
2245
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2246
      goto error;
2247
    res= mysql_create_index(thd, first_table, lex->key_list);
unknown's avatar
unknown committed
2248 2249
    break;

unknown's avatar
unknown committed
2250
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2251
  case SQLCOM_SLAVE_START:
2252
  {
2253
    pthread_mutex_lock(&LOCK_active_mi);
2254
    start_slave(thd,active_mi,1 /* net report*/);
2255
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2256
    break;
2257
  }
unknown's avatar
unknown committed
2258
  case SQLCOM_SLAVE_STOP:
2259 2260 2261 2262 2263 2264
  /*
    If the client thread has locked tables, a deadlock is possible.
    Assume that
    - the client thread does LOCK TABLE t READ.
    - then the master updates t.
    - then the SQL slave thread wants to update t,
2265
      so it waits for the client thread because t is locked by it.
2266
    - then the client thread does SLAVE STOP.
2267 2268
      SLAVE STOP waits for the SQL slave thread to terminate its
      update t, which waits for the client thread because t is locked by it.
2269 2270 2271
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
2272
  if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock)
2273
  {
2274 2275
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
2276
    goto error;
2277
  }
2278
  {
2279
    pthread_mutex_lock(&LOCK_active_mi);
2280
    stop_slave(thd,active_mi,1/* net report*/);
2281
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2282
    break;
2283
  }
unknown's avatar
unknown committed
2284
#endif /* HAVE_REPLICATION */
2285

unknown's avatar
unknown committed
2286
  case SQLCOM_ALTER_TABLE:
unknown's avatar
VIEW  
unknown committed
2287
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2288
    {
unknown's avatar
unknown committed
2289
      ulong priv=0;
unknown's avatar
unknown committed
2290
      ulong priv_needed= ALTER_ACL;
2291 2292 2293 2294 2295
      /*
        We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
        as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
      */
      if (lex->alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME))
unknown's avatar
unknown committed
2296 2297
        priv_needed|= DROP_ACL;

unknown's avatar
unknown committed
2298 2299
      /* Must be set in the parser */
      DBUG_ASSERT(select_lex->db);
unknown's avatar
unknown committed
2300
      if (check_access(thd, priv_needed, first_table->db,
2301 2302 2303 2304
		       &first_table->grant.privilege, 0, 0,
                       test(first_table->schema_table)) ||
	  check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0,
                       is_schema_db(select_lex->db))||
unknown's avatar
VIEW  
unknown committed
2305
	  check_merge_table_access(thd, first_table->db,
2306 2307 2308
				   (TABLE_LIST *)
				   lex->create_info.merge_list.first))
	goto error;				/* purecov: inspected */
unknown's avatar
unknown committed
2309 2310
      if (grant_option)
      {
unknown's avatar
unknown committed
2311
	if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0))
unknown's avatar
unknown committed
2312
	  goto error;
2313
	if (lex->name.str && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
unknown's avatar
unknown committed
2314 2315 2316
	{					// Rename of table
	  TABLE_LIST tmp_table;
	  bzero((char*) &tmp_table,sizeof(tmp_table));
2317
	  tmp_table.table_name= lex->name.str;
2318
	  tmp_table.db=select_lex->db;
unknown's avatar
unknown committed
2319
	  tmp_table.grant.privilege=priv;
unknown's avatar
unknown committed
2320 2321
	  if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
			  UINT_MAX, 0))
unknown's avatar
unknown committed
2322 2323 2324
	    goto error;
	}
      }
2325
      /* Don't yet allow changing of symlinks with ALTER TABLE */
2326 2327 2328 2329 2330 2331
      if (lex->create_info.data_file_name)
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                     "DATA DIRECTORY option ignored");
      if (lex->create_info.index_file_name)
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                     "INDEX DIRECTORY option ignored");
2332
      lex->create_info.data_file_name=lex->create_info.index_file_name=0;
unknown's avatar
unknown committed
2333
      /* ALTER TABLE ends previous transaction */
2334
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2335
	goto error;
2336

2337 2338 2339 2340 2341
      if (!thd->locked_tables &&
          !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
      {
        res= 1;
        break;
unknown's avatar
unknown committed
2342
      }
2343

2344
      thd->enable_slow_log= opt_log_slow_admin_statements;
2345
      res= mysql_alter_table(thd, select_lex->db, lex->name.str,
2346 2347 2348 2349 2350
                             &lex->create_info,
                             first_table, lex->create_list,
                             lex->key_list,
                             select_lex->order_list.elements,
                             (ORDER *) select_lex->order_list.first,
2351
                             lex->ignore, &lex->alter_info, 1);
unknown's avatar
unknown committed
2352 2353
      break;
    }
unknown's avatar
unknown committed
2354
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
2355
  {
unknown's avatar
VIEW  
unknown committed
2356
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2357
    TABLE_LIST *table;
unknown's avatar
VIEW  
unknown committed
2358
    for (table= first_table; table; table= table->next_local->next_local)
unknown's avatar
unknown committed
2359
    {
unknown's avatar
unknown committed
2360
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
2361
		       &table->grant.privilege,0,0, test(table->schema_table)) ||
unknown's avatar
VIEW  
unknown committed
2362
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
2363 2364
		       &table->next_local->grant.privilege, 0, 0,
                       test(table->next_local->schema_table)))
unknown's avatar
unknown committed
2365 2366 2367
	goto error;
      if (grant_option)
      {
unknown's avatar
VIEW  
unknown committed
2368
	TABLE_LIST old_list, new_list;
unknown's avatar
unknown committed
2369 2370 2371 2372
	/*
	  we do not need initialize old_list and new_list because we will
	  come table[0] and table->next[0] there
	*/
unknown's avatar
VIEW  
unknown committed
2373 2374
	old_list= table[0];
	new_list= table->next_local[0];
2375
	if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, 0, 1, 0) ||
unknown's avatar
VIEW  
unknown committed
2376
	    (!test_all_bits(table->next_local->grant.privilege,
2377
			    INSERT_ACL | CREATE_ACL) &&
unknown's avatar
VIEW  
unknown committed
2378
	     check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
unknown's avatar
unknown committed
2379 2380 2381
	  goto error;
      }
    }
unknown's avatar
VIEW  
unknown committed
2382
    query_cache_invalidate3(thd, first_table, 0);
unknown's avatar
unknown committed
2383
    if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
unknown's avatar
unknown committed
2384
      goto error;
unknown's avatar
unknown committed
2385
    break;
unknown's avatar
unknown committed
2386
  }
2387
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2388 2389
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2390 2391
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2392
    goto error;
unknown's avatar
unknown committed
2393 2394
#else
    {
unknown's avatar
unknown committed
2395
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2396 2397 2398 2399
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
2400
#endif
2401
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2402
  case SQLCOM_SHOW_CREATE:
unknown's avatar
VIEW  
unknown committed
2403
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2404
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2405 2406
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2407
    goto error;
unknown's avatar
unknown committed
2408
#else
unknown's avatar
unknown committed
2409
    {
2410 2411 2412 2413
      /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
      if (lex->only_view)
        first_table->skip_temporary= 1;

unknown's avatar
unknown committed
2414
      if (check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db,
2415 2416
		       &first_table->grant.privilege, 0, 0, 
                       test(first_table->schema_table)))
unknown's avatar
unknown committed
2417
	goto error;
unknown's avatar
unknown committed
2418
      if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0))
2419
	goto error;
unknown's avatar
unknown committed
2420
      res= mysqld_show_create(thd, first_table);
unknown's avatar
unknown committed
2421 2422
      break;
    }
unknown's avatar
unknown committed
2423
#endif
2424 2425
  case SQLCOM_CHECKSUM:
  {
unknown's avatar
VIEW  
unknown committed
2426
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2427
    if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, 0))
2428
      goto error; /* purecov: inspected */
unknown's avatar
VIEW  
unknown committed
2429
    res = mysql_checksum_table(thd, first_table, &lex->check_opt);
2430 2431
    break;
  }
unknown's avatar
unknown committed
2432
  case SQLCOM_REPAIR:
2433
  {
unknown's avatar
VIEW  
unknown committed
2434
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2435
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
2436
      goto error; /* purecov: inspected */
2437
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2438
    res= mysql_repair_table(thd, first_table, &lex->check_opt);
2439 2440 2441
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
2442 2443 2444
      /*
        Presumably, REPAIR and binlog writing doesn't require synchronization
      */
2445 2446
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
2447
	thd->clear_error(); // No binlog error generated
unknown's avatar
unknown committed
2448 2449
        thd->binlog_query(THD::STMT_QUERY_TYPE,
                          thd->query, thd->query_length, 0, FALSE);
2450 2451
      }
    }
2452
    select_lex->table_list.first= (byte*) first_table;
2453
    lex->query_tables=all_tables;
2454 2455
    break;
  }
unknown's avatar
unknown committed
2456
  case SQLCOM_CHECK:
2457
  {
unknown's avatar
VIEW  
unknown committed
2458
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2459
    if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0))
2460
      goto error; /* purecov: inspected */
2461
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2462
    res = mysql_check_table(thd, first_table, &lex->check_opt);
2463
    select_lex->table_list.first= (byte*) first_table;
2464
    lex->query_tables=all_tables;
2465 2466
    break;
  }
unknown's avatar
unknown committed
2467 2468
  case SQLCOM_ANALYZE:
  {
unknown's avatar
VIEW  
unknown committed
2469
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2470
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
unknown's avatar
unknown committed
2471
      goto error; /* purecov: inspected */
2472
    thd->enable_slow_log= opt_log_slow_admin_statements;
2473
    res= mysql_analyze_table(thd, first_table, &lex->check_opt);
2474 2475 2476
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
2477 2478 2479
      /*
        Presumably, ANALYZE and binlog writing doesn't require synchronization
      */
2480 2481
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
2482
	thd->clear_error(); // No binlog error generated
unknown's avatar
unknown committed
2483 2484
        thd->binlog_query(THD::STMT_QUERY_TYPE,
                          thd->query, thd->query_length, 0, FALSE);
2485 2486
      }
    }
2487
    select_lex->table_list.first= (byte*) first_table;
2488
    lex->query_tables=all_tables;
unknown's avatar
unknown committed
2489
    break;
unknown's avatar
unknown committed
2490
  }
2491

unknown's avatar
unknown committed
2492 2493
  case SQLCOM_OPTIMIZE:
  {
unknown's avatar
VIEW  
unknown committed
2494
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2495
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
unknown's avatar
unknown committed
2496
      goto error; /* purecov: inspected */
2497
    thd->enable_slow_log= opt_log_slow_admin_statements;
2498
    res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
unknown's avatar
VIEW  
unknown committed
2499 2500
      mysql_recreate_table(thd, first_table, 1) :
      mysql_optimize_table(thd, first_table, &lex->check_opt);
2501 2502 2503
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
2504 2505 2506
      /*
        Presumably, OPTIMIZE and binlog writing doesn't require synchronization
      */
2507 2508
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
2509
	thd->clear_error(); // No binlog error generated
unknown's avatar
unknown committed
2510 2511
        thd->binlog_query(THD::STMT_QUERY_TYPE,
                          thd->query, thd->query_length, 0, FALSE);
2512 2513
      }
    }
2514
    select_lex->table_list.first= (byte*) first_table;
2515
    lex->query_tables=all_tables;
unknown's avatar
unknown committed
2516 2517 2518
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
VIEW  
unknown committed
2519 2520
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (update_precheck(thd, all_tables))
unknown's avatar
unknown committed
2521
      break;
2522 2523
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
unknown's avatar
unknown committed
2524 2525 2526 2527 2528 2529 2530 2531
    res= (up_result= mysql_update(thd, all_tables,
                                  select_lex->item_list,
                                  lex->value_list,
                                  select_lex->where,
                                  select_lex->order_list.elements,
                                  (ORDER *) select_lex->order_list.first,
                                  unit->select_limit_cnt,
                                  lex->duplicates, lex->ignore));
2532
    /* mysql_update return 2 if we need to switch to multi-update */
unknown's avatar
unknown committed
2533
    if (up_result != 2)
2534
      break;
unknown's avatar
unknown committed
2535
    /* Fall through */
2536
  case SQLCOM_UPDATE_MULTI:
unknown's avatar
unknown committed
2537 2538 2539
  {
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    /* if we switched from normal update, rights are checked */
unknown's avatar
unknown committed
2540
    if (up_result != 2)
2541
    {
unknown's avatar
unknown committed
2542 2543 2544 2545 2546
      if ((res= multi_update_precheck(thd, all_tables)))
        break;
    }
    else
      res= 0;
unknown's avatar
unknown committed
2547

2548
    res= mysql_multi_update_prepare(thd);
unknown's avatar
unknown committed
2549

2550
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2551
    /* Check slave filtering rules */
2552
    if (unlikely(thd->slave_thread))
unknown's avatar
unknown committed
2553
    {
2554 2555
      if (all_tables_not_ok(thd, all_tables))
      {
2556 2557 2558 2559 2560
        if (res!= 0)
        {
          res= 0;             /* don't care of prev failure  */
          thd->clear_error(); /* filters are of highest prior */
        }
2561 2562 2563 2564
        /* we warn the slave SQL thread */
        my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
        break;
      }
2565 2566
      if (res)
        break;
unknown's avatar
unknown committed
2567
    }
2568 2569
    else
    {
2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582
#endif /* HAVE_REPLICATION */
      if (res)
        break;
      if (opt_readonly &&
	  !(thd->security_ctx->master_access & SUPER_ACL) &&
	  some_non_temp_table_to_be_updated(thd, all_tables))
      {
	my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
	break;
      }
#ifdef HAVE_REPLICATION
    }  /* unlikely */
#endif
unknown's avatar
unknown committed
2583

unknown's avatar
unknown committed
2584 2585 2586 2587 2588 2589
    res= mysql_multi_update(thd, all_tables,
                            &select_lex->item_list,
                            &lex->value_list,
                            select_lex->where,
                            select_lex->options,
                            lex->duplicates, lex->ignore, unit, select_lex);
unknown's avatar
unknown committed
2590
    break;
unknown's avatar
unknown committed
2591
  }
unknown's avatar
unknown committed
2592
  case SQLCOM_REPLACE:
2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622
#ifndef DBUG_OFF
    if (mysql_bin_log.is_open())
    {
      /*
        Generate an incident log event before writing the real event
        to the binary log.  We put this event is before the statement
        since that makes it simpler to check that the statement was
        not executed on the slave (since incidents usually stop the
        slave).

        Observe that any row events that are generated will be
        generated before.

        This is only for testing purposes and will not be present in a
        release build.
      */

      Incident incident= INCIDENT_NONE;
      DBUG_PRINT("debug", ("Just before generate_incident()"));
      DBUG_EXECUTE_IF("incident_database_resync_on_replace",
                      incident= INCIDENT_LOST_EVENTS;);
      if (incident)
      {
        Incident_log_event ev(thd, incident);
        mysql_bin_log.write(&ev);
        mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
      }
      DBUG_PRINT("debug", ("Just after generate_incident()"));
    }
#endif
2623 2624
  case SQLCOM_INSERT:
  {
unknown's avatar
VIEW  
unknown committed
2625
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2626
    if ((res= insert_precheck(thd, all_tables)))
unknown's avatar
unknown committed
2627
      break;
2628 2629 2630 2631 2632 2633 2634 2635

    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
    {
      res= 1;
      break;
    }

unknown's avatar
VIEW  
unknown committed
2636
    res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
unknown's avatar
unknown committed
2637
		      lex->update_list, lex->value_list,
2638
                      lex->duplicates, lex->ignore);
2639 2640 2641 2642 2643 2644 2645

    /*
      If we have inserted into a VIEW, and the base table has
      AUTO_INCREMENT column, but this column is not accessible through
      a view, then we should restore LAST_INSERT_ID to the value it
      had before the statement.
    */
unknown's avatar
VIEW  
unknown committed
2646
    if (first_table->view && !first_table->contain_auto_increment)
2647 2648
      thd->first_successful_insert_id_in_cur_stmt=
        thd->first_successful_insert_id_in_prev_stmt;
2649

unknown's avatar
unknown committed
2650
    break;
2651
  }
unknown's avatar
unknown committed
2652 2653 2654
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
unknown's avatar
unknown committed
2655
    select_result *sel_result;
unknown's avatar
VIEW  
unknown committed
2656
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2657
    if ((res= insert_precheck(thd, all_tables)))
2658
      break;
unknown's avatar
unknown committed
2659

2660
    /* Fix lock for first table */
unknown's avatar
VIEW  
unknown committed
2661 2662
    if (first_table->lock_type == TL_WRITE_DELAYED)
      first_table->lock_type= TL_WRITE;
2663

2664 2665
    /* Don't unlock tables until command is written to binary log */
    select_lex->options|= SELECT_NO_UNLOCK;
unknown's avatar
unknown committed
2666

2667
    unit->set_limit(select_lex);
2668 2669 2670 2671 2672 2673 2674 2675

    if (! thd->locked_tables &&
        ! (need_start_waiting= ! wait_if_global_read_lock(thd, 0, 1)))
    {
      res= 1;
      break;
    }

unknown's avatar
VIEW  
unknown committed
2676
    if (!(res= open_and_lock_tables(thd, all_tables)))
2677
    {
2678
      /* Skip first table, which is the table we are inserting in */
unknown's avatar
unknown committed
2679 2680
      TABLE_LIST *second_table= first_table->next_local;
      select_lex->table_list.first= (byte*) second_table;
2681 2682
      select_lex->context.table_list= 
        select_lex->context.first_name_resolution_table= second_table;
2683
      res= mysql_insert_select_prepare(thd);
unknown's avatar
unknown committed
2684 2685 2686 2687 2688 2689 2690
      if (!res && (sel_result= new select_insert(first_table,
                                                 first_table->table,
                                                 &lex->field_list,
                                                 &lex->update_list,
                                                 &lex->value_list,
                                                 lex->duplicates,
                                                 lex->ignore)))
2691
      {
unknown's avatar
unknown committed
2692
	res= handle_select(thd, lex, sel_result, OPTION_SETUP_TABLES_DONE);
2693 2694 2695 2696 2697 2698 2699 2700 2701
        /*
          Invalidate the table in the query cache if something changed
          after unlocking when changes become visible.
          TODO: this is workaround. right way will be move invalidating in
          the unlock procedure.
        */
        if (first_table->lock_type ==  TL_WRITE_CONCURRENT_INSERT &&
            thd->lock)
        {
2702 2703 2704
          /* INSERT ... SELECT should invalidate only the very first table */
          TABLE_LIST *save_table= first_table->next_local;
          first_table->next_local= 0;
2705 2706
          mysql_unlock_tables(thd, thd->lock);
          query_cache_invalidate3(thd, first_table, 1);
2707
          first_table->next_local= save_table;
2708 2709
          thd->lock=0;
        }
unknown's avatar
unknown committed
2710
        delete sel_result;
2711
      }
2712
      /* revert changes for SP */
unknown's avatar
unknown committed
2713
      select_lex->table_list.first= (byte*) first_table;
2714
    }
unknown's avatar
VIEW  
unknown committed
2715

2716 2717 2718 2719 2720 2721
    /*
      If we have inserted into a VIEW, and the base table has
      AUTO_INCREMENT column, but this column is not accessible through
      a view, then we should restore LAST_INSERT_ID to the value it
      had before the statement.
    */
unknown's avatar
VIEW  
unknown committed
2722
    if (first_table->view && !first_table->contain_auto_increment)
2723 2724
      thd->first_successful_insert_id_in_cur_stmt=
        thd->first_successful_insert_id_in_prev_stmt;
2725

unknown's avatar
unknown committed
2726 2727
    break;
  }
2728
  case SQLCOM_TRUNCATE:
2729 2730 2731 2732 2733
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
VIEW  
unknown committed
2734
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2735
    if (check_one_table_access(thd, DROP_ACL, all_tables))
unknown's avatar
unknown committed
2736
      goto error;
2737 2738 2739 2740
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
2741
    if (thd->locked_tables || thd->active_transaction())
2742
    {
unknown's avatar
unknown committed
2743 2744
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
2745 2746
      goto error;
    }
unknown's avatar
VIEW  
unknown committed
2747

unknown's avatar
unknown committed
2748
    res= mysql_truncate(thd, first_table, 0);
2749
    break;
unknown's avatar
unknown committed
2750
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
2751
  {
unknown's avatar
VIEW  
unknown committed
2752 2753
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if ((res= delete_precheck(thd, all_tables)))
unknown's avatar
unknown committed
2754
      break;
2755 2756
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
2757 2758 2759 2760 2761 2762 2763 2764

    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
    {
      res= 1;
      break;
    }

unknown's avatar
VIEW  
unknown committed
2765
    res = mysql_delete(thd, all_tables, select_lex->where,
2766
                       &select_lex->order_list,
unknown's avatar
unknown committed
2767 2768
                       unit->select_limit_cnt, select_lex->options,
                       FALSE);
unknown's avatar
unknown committed
2769 2770
    break;
  }
2771
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
2772
  {
unknown's avatar
VIEW  
unknown committed
2773
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2774
    TABLE_LIST *aux_tables=
unknown's avatar
unknown committed
2775
      (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
unknown's avatar
unknown committed
2776
    multi_delete *del_result;
unknown's avatar
unknown committed
2777

2778 2779 2780 2781 2782 2783 2784
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
    {
      res= 1;
      break;
    }

2785
    if ((res= multi_delete_precheck(thd, all_tables)))
2786
      break;
unknown's avatar
unknown committed
2787

unknown's avatar
unknown committed
2788
    /* condition will be TRUE on SP re-excuting */
2789 2790
    if (select_lex->item_list.elements != 0)
      select_lex->item_list.empty();
unknown's avatar
unknown committed
2791
    if (add_item_to_list(thd, new Item_null()))
unknown's avatar
unknown committed
2792
      goto error;
2793

unknown's avatar
unknown committed
2794
    thd->proc_info="init";
unknown's avatar
VIEW  
unknown committed
2795 2796 2797 2798
    if ((res= open_and_lock_tables(thd, all_tables)))
      break;

    if ((res= mysql_multi_delete_prepare(thd)))
unknown's avatar
unknown committed
2799
      goto error;
2800

unknown's avatar
unknown committed
2801 2802
    if (!thd->is_fatal_error &&
        (del_result= new multi_delete(aux_tables, lex->table_count)))
unknown's avatar
unknown committed
2803
    {
2804 2805 2806
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
2807
			select_lex->item_list,
unknown's avatar
unknown committed
2808
			select_lex->where,
2809
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
unknown's avatar
unknown committed
2810 2811
			(ORDER *)NULL,
			select_lex->options | thd->options |
2812 2813
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
                        OPTION_SETUP_TABLES_DONE,
unknown's avatar
unknown committed
2814 2815
			del_result, unit, select_lex);
      delete del_result;
unknown's avatar
unknown committed
2816 2817
    }
    else
2818
      res= TRUE;                                // Error
unknown's avatar
unknown committed
2819 2820
    break;
  }
unknown's avatar
unknown committed
2821
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
2822
  {
unknown's avatar
VIEW  
unknown committed
2823
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2824 2825
    if (!lex->drop_temporary)
    {
unknown's avatar
VIEW  
unknown committed
2826
      if (check_table_access(thd, DROP_ACL, all_tables, 0))
2827 2828
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2829
        goto error;
2830
    }
unknown's avatar
unknown committed
2831
    else
unknown's avatar
unknown committed
2832 2833 2834 2835 2836 2837
    {
      /*
	If this is a slave thread, we may sometimes execute some 
	DROP / * 40005 TEMPORARY * / TABLE
	that come from parts of binlogs (likely if we use RESET SLAVE or CHANGE
	MASTER TO), while the temporary table has already been dropped.
unknown's avatar
unknown committed
2838 2839
	To not generate such irrelevant "table does not exist errors",
	we silently add IF EXISTS if TEMPORARY was used.
unknown's avatar
unknown committed
2840 2841
      */
      if (thd->slave_thread)
2842
        lex->drop_if_exists= 1;
2843

unknown's avatar
unknown committed
2844
      /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
2845
      thd->options|= OPTION_KEEP_LOG;
unknown's avatar
unknown committed
2846
    }
2847
    /* DDL and binlog write order protected by LOCK_open */
unknown's avatar
VIEW  
unknown committed
2848 2849
    res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
			lex->drop_temporary);
unknown's avatar
unknown committed
2850 2851
  }
  break;
unknown's avatar
unknown committed
2852
  case SQLCOM_DROP_INDEX:
unknown's avatar
VIEW  
unknown committed
2853 2854
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, INDEX_ACL, all_tables))
unknown's avatar
unknown committed
2855
      goto error;				/* purecov: inspected */
2856
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2857
      goto error;
2858
    res= mysql_drop_index(thd, first_table, &lex->alter_info);
unknown's avatar
unknown committed
2859 2860
    break;
  case SQLCOM_SHOW_PROCESSLIST:
2861 2862
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
2863
      break;
unknown's avatar
unknown committed
2864
    mysqld_list_processes(thd,
2865 2866 2867 2868
			  (thd->security_ctx->master_access & PROCESS_ACL ?
                           NullS :
                           thd->security_ctx->priv_user),
                          lex->verbose);
unknown's avatar
unknown committed
2869
    break;
unknown's avatar
unknown committed
2870 2871
  case SQLCOM_SHOW_STORAGE_ENGINES:
    res= mysqld_show_storage_engines(thd);
unknown's avatar
unknown committed
2872
    break;
unknown's avatar
unknown committed
2873 2874 2875
  case SQLCOM_SHOW_AUTHORS:
    res= mysqld_show_authors(thd);
    break;
2876 2877 2878
  case SQLCOM_SHOW_CONTRIBUTORS:
    res= mysqld_show_contributors(thd);
    break;
unknown's avatar
unknown committed
2879 2880 2881 2882 2883 2884
  case SQLCOM_SHOW_PRIVILEGES:
    res= mysqld_show_privileges(thd);
    break;
  case SQLCOM_SHOW_COLUMN_TYPES:
    res= mysqld_show_column_types(thd);
    break;
unknown's avatar
unknown committed
2885
  case SQLCOM_SHOW_ENGINE_LOGS:
unknown's avatar
unknown committed
2886
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2887 2888
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
2889
    goto error;
unknown's avatar
unknown committed
2890 2891
#else
    {
2892
      if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0,0))
unknown's avatar
unknown committed
2893
	goto error;
unknown's avatar
unknown committed
2894
      res= ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_LOGS);
unknown's avatar
unknown committed
2895 2896
      break;
    }
unknown's avatar
unknown committed
2897 2898
#endif
  case SQLCOM_CHANGE_DB:
2899 2900 2901 2902
  {
    LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) };

    if (!mysql_change_db(thd, &db_str, FALSE))
2903
      send_ok(thd);
2904

unknown's avatar
unknown committed
2905
    break;
2906
  }
2907

unknown's avatar
unknown committed
2908 2909
  case SQLCOM_LOAD:
  {
unknown's avatar
VIEW  
unknown committed
2910
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2911
    uint privilege= (lex->duplicates == DUP_REPLACE ?
unknown's avatar
unknown committed
2912 2913
		     INSERT_ACL | DELETE_ACL : INSERT_ACL) |
                    (lex->local_file ? 0 : FILE_ACL);
2914

unknown's avatar
unknown committed
2915
    if (lex->local_file)
unknown's avatar
unknown committed
2916
    {
2917
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
2918
          !opt_local_infile)
2919
      {
unknown's avatar
unknown committed
2920
	my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0));
2921 2922
	goto error;
      }
unknown's avatar
unknown committed
2923
    }
unknown's avatar
unknown committed
2924 2925 2926 2927

    if (check_one_table_access(thd, privilege, all_tables))
      goto error;

unknown's avatar
VIEW  
unknown committed
2928
    res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
unknown's avatar
unknown committed
2929
                    lex->update_list, lex->value_list, lex->duplicates,
2930
                    lex->ignore, (bool) lex->local_file);
unknown's avatar
unknown committed
2931 2932
    break;
  }
2933

unknown's avatar
unknown committed
2934
  case SQLCOM_SET_OPTION:
2935 2936
  {
    List<set_var_base> *lex_var_list= &lex->var_list;
2937
    if ((check_table_access(thd, SELECT_ACL, all_tables, 0) ||
unknown's avatar
unknown committed
2938 2939
	 open_and_lock_tables(thd, all_tables)))
      goto error;
2940 2941
    if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
    {
unknown's avatar
unknown committed
2942 2943
      my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
      goto error;
2944 2945 2946 2947 2948 2949 2950 2951
    }
    if (!(res= sql_set_variables(thd, lex_var_list)))
    {
      /*
        If the previous command was a SET ONE_SHOT, we don't want to forget
        about the ONE_SHOT property of that SET. So we use a |= instead of = .
      */
      thd->one_shot_set|= lex->one_shot_set;
2952
      send_ok(thd);
2953
    }
unknown's avatar
unknown committed
2954
    break;
2955
  }
unknown's avatar
unknown committed
2956

unknown's avatar
unknown committed
2957
  case SQLCOM_UNLOCK_TABLES:
2958 2959 2960 2961 2962 2963
    /*
      It is critical for mysqldump --single-transaction --master-data that
      UNLOCK TABLES does not implicitely commit a connection which has only
      done FLUSH TABLES WITH READ LOCK + BEGIN. If this assumption becomes
      false, mysqldump will not work.
    */
unknown's avatar
unknown committed
2964
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
2965 2966
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
2967
      end_active_trans(thd);
unknown's avatar
unknown committed
2968
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
2969 2970
    }
    if (thd->global_read_lock)
2971
      unlock_global_read_lock(thd);
2972
    send_ok(thd);
unknown's avatar
unknown committed
2973 2974
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
2975
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
2976
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2977
      goto error;
unknown's avatar
VIEW  
unknown committed
2978
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
2979
      goto error;
unknown's avatar
unknown committed
2980
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
2981
    thd->options|= OPTION_TABLE_LOCK;
unknown's avatar
VIEW  
unknown committed
2982

2983
    if (!(res= simple_open_n_lock_tables(thd, all_tables)))
unknown's avatar
unknown committed
2984
    {
2985 2986
#ifdef HAVE_QUERY_CACHE
      if (thd->variables.query_cache_wlock_invalidate)
unknown's avatar
VIEW  
unknown committed
2987
	query_cache.invalidate_locked_for_write(first_table);
2988
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
2989 2990
      thd->locked_tables=thd->lock;
      thd->lock=0;
2991
      send_ok(thd);
unknown's avatar
unknown committed
2992
    }
unknown's avatar
unknown committed
2993 2994
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
2995 2996 2997
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
2998
  {
2999 3000 3001 3002 3003
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
unknown committed
3004
    char *alias;
3005 3006
    if (!(alias=thd->strmake(lex->name.str, lex->name.length)) ||
        check_db_name(&lex->name))
unknown's avatar
unknown committed
3007
    {
3008
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3009 3010
      break;
    }
3011 3012 3013
    /*
      If in a slave thread :
      CREATE DATABASE DB was certainly not preceded by USE DB.
3014
      For that reason, db_ok() in sql/slave.cc did not check the
3015 3016 3017
      do_db/ignore_db. And as this query involves no tables, tables_ok()
      above was not called. So we have to check rules again here.
    */
3018
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
3019
    if (thd->slave_thread && 
3020 3021
	(!rpl_filter->db_ok(lex->name.str) ||
	 !rpl_filter->db_ok_with_wild_table(lex->name.str)))
unknown's avatar
unknown committed
3022
    {
unknown's avatar
unknown committed
3023
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3024
      break;
unknown's avatar
unknown committed
3025
    }
3026
#endif
3027 3028
    if (check_access(thd,CREATE_ACL,lex->name.str, 0, 1, 0,
                     is_schema_db(lex->name.str)))
3029
      break;
3030 3031
    res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
                              lex->name.str), &lex->create_info, 0);
3032 3033
    break;
  }
unknown's avatar
unknown committed
3034
  case SQLCOM_DROP_DB:
3035
  {
3036 3037 3038 3039 3040
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
3041
    if (check_db_name(&lex->name))
unknown's avatar
unknown committed
3042
    {
3043
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3044 3045
      break;
    }
3046 3047 3048 3049 3050 3051 3052
    /*
      If in a slave thread :
      DROP DATABASE DB may not be preceded by USE DB.
      For that reason, maybe db_ok() in sql/slave.cc did not check the 
      do_db/ignore_db. And as this query involves no tables, tables_ok()
      above was not called. So we have to check rules again here.
    */
3053
#ifdef HAVE_REPLICATION
3054
    if (thd->slave_thread && 
3055 3056
	(!rpl_filter->db_ok(lex->name.str) ||
	 !rpl_filter->db_ok_with_wild_table(lex->name.str)))
unknown's avatar
unknown committed
3057
    {
unknown's avatar
unknown committed
3058
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3059
      break;
unknown's avatar
unknown committed
3060
    }
3061
#endif
3062 3063
    if (check_access(thd,DROP_ACL,lex->name.str,0,1,0,
                     is_schema_db(lex->name.str)))
3064
      break;
3065 3066
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3067 3068
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3069 3070
      goto error;
    }
3071
    res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0);
3072 3073
    break;
  }
unknown's avatar
unknown committed
3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096
  case SQLCOM_RENAME_DB:
  {
    LEX_STRING *olddb, *newdb;
    List_iterator <LEX_STRING> db_list(lex->db_list);
    olddb= db_list++;
    newdb= db_list++;
    if (end_active_trans(thd))
    {
      res= 1;
      break;
    }
#ifdef HAVE_REPLICATION
    if (thd->slave_thread && 
       (!rpl_filter->db_ok(olddb->str) ||
        !rpl_filter->db_ok(newdb->str) ||
        !rpl_filter->db_ok_with_wild_table(olddb->str) ||
        !rpl_filter->db_ok_with_wild_table(newdb->str)))
    {
      res= 1;
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
      break;
    }
#endif
3097 3098 3099 3100 3101
    if (check_db_name(newdb))
    {
      my_error(ER_WRONG_DB_NAME, MYF(0), newdb->str);
      break;
    }
unknown's avatar
unknown committed
3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120
    if (check_access(thd,ALTER_ACL,olddb->str,0,1,0,is_schema_db(olddb->str)) ||
        check_access(thd,DROP_ACL,olddb->str,0,1,0,is_schema_db(olddb->str)) ||
        check_access(thd,CREATE_ACL,newdb->str,0,1,0,is_schema_db(newdb->str)))
    {
      res= 1;
      break;
    }
    if (thd->locked_tables || thd->active_transaction())
    {
      res= 1;
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
      goto error;
    }
    res= mysql_rename_db(thd, olddb, newdb);
    if (!res)
      send_ok(thd);
    break;
  }
3121 3122
  case SQLCOM_ALTER_DB:
  {
3123 3124
    LEX_STRING *db= &lex->name;
    if (check_db_name(db))
3125
    {
3126
      my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
3127 3128
      break;
    }
unknown's avatar
unknown committed
3129 3130 3131
    /*
      If in a slave thread :
      ALTER DATABASE DB may not be preceded by USE DB.
3132
      For that reason, maybe db_ok() in sql/slave.cc did not check the
unknown's avatar
unknown committed
3133 3134 3135 3136
      do_db/ignore_db. And as this query involves no tables, tables_ok()
      above was not called. So we have to check rules again here.
    */
#ifdef HAVE_REPLICATION
3137
    if (thd->slave_thread &&
3138 3139
	(!rpl_filter->db_ok(db->str) ||
	 !rpl_filter->db_ok_with_wild_table(db->str)))
unknown's avatar
unknown committed
3140
    {
unknown's avatar
unknown committed
3141
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
unknown's avatar
unknown committed
3142 3143 3144
      break;
    }
#endif
3145
    if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0, is_schema_db(db->str)))
3146 3147 3148
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3149 3150
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3151 3152
      goto error;
    }
3153
    res= mysql_alter_db(thd, db->str, &lex->create_info);
3154 3155
    break;
  }
unknown's avatar
unknown committed
3156 3157
  case SQLCOM_SHOW_CREATE_DB:
  {
3158
    if (check_db_name(&lex->name))
unknown's avatar
unknown committed
3159
    {
3160
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3161 3162
      break;
    }
3163
    res= mysqld_show_create_db(thd, lex->name.str, &lex->create_info);
unknown's avatar
unknown committed
3164 3165
    break;
  }
unknown's avatar
unknown committed
3166 3167
  case SQLCOM_CREATE_EVENT:
  case SQLCOM_ALTER_EVENT:
3168
  do
unknown's avatar
unknown committed
3169
  {
unknown's avatar
unknown committed
3170
    DBUG_ASSERT(lex->event_parse_data);
unknown's avatar
unknown committed
3171 3172 3173 3174 3175 3176
    if (lex->table_or_sp_used())
    {
      my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored "
               "function calls as part of this statement");
      break;
    }
3177 3178 3179 3180 3181

    res= sp_process_definer(thd);
    if (res)
      break;

unknown's avatar
unknown committed
3182 3183
    switch (lex->sql_command) {
    case SQLCOM_CREATE_EVENT:
3184 3185 3186 3187
    {
      bool if_not_exists= (lex->create_info.options &
                           HA_LEX_CREATE_IF_NOT_EXISTS);
      res= Events::create_event(thd, lex->event_parse_data, if_not_exists);
unknown's avatar
unknown committed
3188
      break;
3189
    }
unknown's avatar
unknown committed
3190
    case SQLCOM_ALTER_EVENT:
3191 3192 3193
      res= Events::update_event(thd, lex->event_parse_data,
                                lex->spname ? &lex->spname->m_db : NULL,
                                lex->spname ? &lex->spname->m_name : NULL);
unknown's avatar
unknown committed
3194
      break;
3195 3196
    default:
      DBUG_ASSERT(0);
unknown's avatar
unknown committed
3197
    }
3198
    DBUG_PRINT("info",("DDL error code=%d", res));
unknown's avatar
unknown committed
3199
    if (!res)
3200
      send_ok(thd);
unknown's avatar
unknown committed
3201

3202 3203 3204 3205 3206 3207
  } while (0);
  /* Don't do it, if we are inside a SP */
  if (!thd->spcont)
  {
    delete lex->sphead;
    lex->sphead= NULL;
unknown's avatar
unknown committed
3208
  }
3209 3210
  /* lex->unit.cleanup() is called outside, no need to call it here */
  break;
unknown's avatar
unknown committed
3211
  case SQLCOM_SHOW_CREATE_EVENT:
3212 3213 3214 3215 3216 3217 3218 3219
    res= Events::show_create_event(thd, lex->spname->m_db,
                                   lex->spname->m_name);
    break;
  case SQLCOM_DROP_EVENT:
    if (!(res= Events::drop_event(thd,
                                  lex->spname->m_db, lex->spname->m_name,
                                  lex->drop_if_exists)))
      send_ok(thd);
3220
    break;
unknown's avatar
unknown committed
3221
  case SQLCOM_CREATE_FUNCTION:                  // UDF function
unknown's avatar
unknown committed
3222
  {
3223
    if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
unknown's avatar
unknown committed
3224
      break;
unknown's avatar
unknown committed
3225
#ifdef HAVE_DLOPEN
3226 3227
    if (sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                        &thd->sp_func_cache, FALSE))
unknown's avatar
unknown committed
3228
    {
3229
      my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str);
unknown's avatar
unknown committed
3230 3231
      goto error;
    }
3232
    if (!(res = mysql_create_function(thd, &lex->udf)))
unknown's avatar
unknown committed
3233
      send_ok(thd);
unknown's avatar
unknown committed
3234
#else
unknown's avatar
unknown committed
3235
    my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled");
unknown's avatar
unknown committed
3236
    res= TRUE;
unknown's avatar
unknown committed
3237 3238
#endif
    break;
unknown's avatar
unknown committed
3239
  }
unknown's avatar
unknown committed
3240
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3241 3242
  case SQLCOM_CREATE_USER:
  {
3243
    if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) &&
3244
        check_global_access(thd,CREATE_USER_ACL))
3245
      break;
3246 3247
    if (end_active_trans(thd))
      goto error;
3248
    /* Conditionally writes to binlog */
3249 3250 3251 3252
    if (!(res= mysql_create_user(thd, lex->users_list)))
      send_ok(thd);
    break;
  }
3253 3254
  case SQLCOM_DROP_USER:
  {
3255
    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) &&
3256
        check_global_access(thd,CREATE_USER_ACL))
3257
      break;
3258 3259
    if (end_active_trans(thd))
      goto error;
3260
    /* Conditionally writes to binlog */
3261
    if (!(res= mysql_drop_user(thd, lex->users_list)))
3262 3263 3264 3265 3266
      send_ok(thd);
    break;
  }
  case SQLCOM_RENAME_USER:
  {
3267
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
3268
        check_global_access(thd,CREATE_USER_ACL))
3269
      break;
3270 3271
    if (end_active_trans(thd))
      goto error;
3272
    /* Conditionally writes to binlog */
3273
    if (!(res= mysql_rename_user(thd, lex->users_list)))
3274 3275 3276 3277 3278
      send_ok(thd);
    break;
  }
  case SQLCOM_REVOKE_ALL:
  {
3279
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
3280
        check_global_access(thd,CREATE_USER_ACL))
3281
      break;
3282
    /* Conditionally writes to binlog */
3283 3284 3285 3286
    if (!(res = mysql_revoke_all(thd, lex->users_list)))
      send_ok(thd);
    break;
  }
3287 3288 3289 3290
  case SQLCOM_REVOKE:
  case SQLCOM_GRANT:
  {
    if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
unknown's avatar
unknown committed
3291
		     first_table ?  first_table->db : select_lex->db,
unknown's avatar
VIEW  
unknown committed
3292
		     first_table ? &first_table->grant.privilege : 0,
3293 3294 3295
		     first_table ? 0 : 1, 0,
                     first_table ? (bool) first_table->schema_table :
                     select_lex->db ? is_schema_db(select_lex->db) : 0))
3296 3297
      goto error;

3298
    if (thd->security_ctx->user)              // If not replication
unknown's avatar
unknown committed
3299
    {
3300
      LEX_USER *user, *tmp_user;
3301

unknown's avatar
unknown committed
3302
      List_iterator <LEX_USER> user_list(lex->users_list);
3303
      while ((tmp_user= user_list++))
unknown's avatar
unknown committed
3304
      {
3305 3306
        if (!(user= get_current_user(thd, tmp_user)))
          goto error;
3307 3308 3309 3310 3311 3312 3313 3314
        if (specialflag & SPECIAL_NO_RESOLVE &&
            hostname_requires_resolving(user->host.str))
          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                              ER_WARN_HOSTNAME_WONT_WORK,
                              ER(ER_WARN_HOSTNAME_WONT_WORK),
                              user->host.str);
        // Are we trying to change a password of another user
        DBUG_ASSERT(user->host.str != 0);
3315
        if (strcmp(thd->security_ctx->user, user->user.str) ||
3316
            my_strcasecmp(system_charset_info,
3317
                          user->host.str, thd->security_ctx->host_or_ip))
3318 3319
        {
          // TODO: use check_change_password()
3320 3321
          if (is_acl_user(user->host.str, user->user.str) &&
              user->password.str &&
3322
              check_access(thd, UPDATE_ACL,"mysql",0,1,1,0))
3323 3324 3325 3326 3327 3328
          {
            my_message(ER_PASSWORD_NOT_ALLOWED,
                       ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
            goto error;
          }
        }
unknown's avatar
SCRUM  
unknown committed
3329 3330
      }
    }
unknown's avatar
VIEW  
unknown committed
3331
    if (first_table)
3332
    {
3333 3334
      if (lex->type == TYPE_ENUM_PROCEDURE ||
          lex->type == TYPE_ENUM_FUNCTION)
3335 3336 3337 3338 3339
      {
        uint grants= lex->all_privileges 
		   ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
		   : lex->grant;
        if (grant_option && 
3340 3341
	    check_grant_routine(thd, grants | GRANT_ACL, all_tables,
                                lex->type == TYPE_ENUM_PROCEDURE, 0))
3342
	  goto error;
3343
        /* Conditionally writes to binlog */
3344 3345 3346 3347
        res= mysql_routine_grant(thd, all_tables,
                                 lex->type == TYPE_ENUM_PROCEDURE, 
                                 lex->users_list, grants,
                                 lex->sql_command == SQLCOM_REVOKE, 0);
3348 3349 3350 3351 3352 3353 3354 3355
      }
      else
      {
	if (grant_option && check_grant(thd,
					(lex->grant | lex->grant_tot_col |
					 GRANT_ACL),
					all_tables, 0, UINT_MAX, 0))
	  goto error;
3356
        /* Conditionally writes to binlog */
3357 3358 3359 3360
        res= mysql_table_grant(thd, all_tables, lex->users_list,
			       lex->columns, lex->grant,
			       lex->sql_command == SQLCOM_REVOKE);
      }
3361 3362 3363
    }
    else
    {
3364
      if (lex->columns.elements || lex->type)
3365
      {
unknown's avatar
unknown committed
3366 3367
	my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
                   MYF(0));
unknown's avatar
unknown committed
3368
        goto error;
3369 3370
      }
      else
3371
	/* Conditionally writes to binlog */
3372 3373 3374 3375
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
3376
	if (lex->sql_command == SQLCOM_GRANT)
3377
	{
unknown's avatar
unknown committed
3378
	  List_iterator <LEX_USER> str_list(lex->users_list);
3379 3380 3381 3382 3383
	  LEX_USER *user, *tmp_user;
	  while ((tmp_user=str_list++))
          {
            if (!(user= get_current_user(thd, tmp_user)))
              goto error;
3384
	    reset_mqh(user, 0);
3385
          }
3386
	}
3387 3388 3389 3390
      }
    }
    break;
  }
unknown's avatar
SCRUM  
unknown committed
3391
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
unknown's avatar
unknown committed
3392
  case SQLCOM_RESET:
3393 3394 3395
    /*
      RESET commands are never written to the binary log, so we have to
      initialize this variable because RESET shares the same code as FLUSH
3396 3397 3398 3399
    */
    lex->no_write_to_binlog= 1;
  case SQLCOM_FLUSH:
  {
unknown's avatar
unknown committed
3400
    bool write_to_binlog;
unknown's avatar
unknown committed
3401
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
3402
      goto error;
3403

3404 3405 3406 3407
    /*
      reload_acl_and_cache() will tell us if we are allowed to write to the
      binlog or not.
    */
unknown's avatar
unknown committed
3408
    if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
3409 3410 3411 3412 3413
    {
      /*
        We WANT to write and we CAN write.
        ! we write after unlocking the table.
      */
3414 3415 3416
      /*
        Presumably, RESET and binlog writing doesn't require synchronization
      */
3417 3418 3419 3420
      if (!lex->no_write_to_binlog && write_to_binlog)
      {
        if (mysql_bin_log.is_open())
        {
unknown's avatar
unknown committed
3421 3422
          thd->binlog_query(THD::STMT_QUERY_TYPE,
                            thd->query, thd->query_length, 0, FALSE);
3423 3424 3425
        }
      }
      send_ok(thd);
3426 3427
    } 
    
unknown's avatar
unknown committed
3428
    break;
3429
  }
unknown's avatar
unknown committed
3430
  case SQLCOM_KILL:
3431 3432 3433
  {
    Item *it= (Item *)lex->value_list.head();

unknown's avatar
unknown committed
3434 3435 3436 3437 3438 3439 3440
    if (lex->table_or_sp_used())
    {
      my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored "
               "function calls as part of this statement");
      break;
    }

3441
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1))
3442 3443 3444 3445 3446
    {
      my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
		 MYF(0));
      goto error;
    }
3447
    sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
unknown's avatar
unknown committed
3448
    break;
3449
  }
unknown's avatar
unknown committed
3450
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
3451
  case SQLCOM_SHOW_GRANTS:
3452 3453 3454 3455
  {
    LEX_USER *grant_user= get_current_user(thd, lex->grant_user);
    if (!grant_user)
      goto error;
3456
    if ((thd->security_ctx->priv_user &&
3457
	 !strcmp(thd->security_ctx->priv_user, grant_user->user.str)) ||
3458
	!check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
unknown's avatar
unknown committed
3459
    {
3460
      res = mysql_show_grants(thd, grant_user);
unknown's avatar
unknown committed
3461 3462
    }
    break;
3463
  }
unknown's avatar
unknown committed
3464
#endif
3465
  case SQLCOM_HA_OPEN:
unknown's avatar
VIEW  
unknown committed
3466
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3467
    if (check_table_access(thd, SELECT_ACL, all_tables, 0))
3468
      goto error;
unknown's avatar
unknown committed
3469
    res= mysql_ha_open(thd, first_table, 0);
3470 3471
    break;
  case SQLCOM_HA_CLOSE:
unknown's avatar
VIEW  
unknown committed
3472 3473
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    res= mysql_ha_close(thd, first_table);
3474 3475
    break;
  case SQLCOM_HA_READ:
unknown's avatar
VIEW  
unknown committed
3476
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3477 3478 3479 3480 3481
    /*
      There is no need to check for table permissions here, because
      if a user has no permissions to read a table, he won't be
      able to open it (with SQLCOM_HA_OPEN) in the first place.
    */
3482
    unit->set_limit(select_lex);
3483
    res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
unknown's avatar
VIEW  
unknown committed
3484
                       lex->insert_list, lex->ha_rkey_mode, select_lex->where,
3485
                       unit->select_limit_cnt, unit->offset_limit_cnt);
3486 3487
    break;

unknown's avatar
unknown committed
3488
  case SQLCOM_BEGIN:
3489 3490 3491 3492 3493 3494
    if (thd->transaction.xid_state.xa_state != XA_NOTR)
    {
      my_error(ER_XAER_RMFAIL, MYF(0),
               xa_state_names[thd->transaction.xid_state.xa_state]);
      break;
    }
unknown's avatar
unknown committed
3495
    if (begin_trans(thd))
unknown's avatar
unknown committed
3496
      goto error;
unknown's avatar
unknown committed
3497
    send_ok(thd);
unknown's avatar
unknown committed
3498 3499
    break;
  case SQLCOM_COMMIT:
3500
    if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
unknown's avatar
unknown committed
3501
                              lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
unknown's avatar
unknown committed
3502
      goto error;
3503
    send_ok(thd);
unknown's avatar
unknown committed
3504 3505
    break;
  case SQLCOM_ROLLBACK:
3506
    if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
unknown's avatar
unknown committed
3507
                              lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
unknown's avatar
unknown committed
3508
      goto error;
3509
    send_ok(thd);
unknown's avatar
unknown committed
3510
    break;
unknown's avatar
unknown committed
3511
  case SQLCOM_RELEASE_SAVEPOINT:
unknown's avatar
unknown committed
3512
  {
3513 3514
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
unknown's avatar
unknown committed
3515 3516 3517
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
3518
                       (uchar *)sv->name, sv->length) == 0)
unknown's avatar
unknown committed
3519 3520
        break;
    }
3521
    if (sv)
unknown's avatar
unknown committed
3522
    {
3523
      if (ha_release_savepoint(thd, sv))
unknown's avatar
unknown committed
3524
        res= TRUE; // cannot happen
unknown's avatar
unknown committed
3525 3526
      else
        send_ok(thd);
3527
      thd->transaction.savepoints=sv->prev;
unknown's avatar
unknown committed
3528
    }
3529
    else
unknown's avatar
unknown committed
3530
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
3531
    break;
unknown's avatar
unknown committed
3532
  }
unknown's avatar
unknown committed
3533
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
unknown's avatar
unknown committed
3534
  {
3535 3536
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
3537 3538 3539
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
3540
                       (uchar *)sv->name, sv->length) == 0)
3541 3542
        break;
    }
3543
    if (sv)
3544
    {
3545
      if (ha_rollback_to_savepoint(thd, sv))
3546 3547
        res= TRUE; // cannot happen
      else
unknown's avatar
unknown committed
3548
      {
3549
        if (((thd->options & OPTION_KEEP_LOG) || thd->no_trans_update.all) &&
unknown's avatar
unknown committed
3550 3551 3552 3553 3554 3555
            !thd->slave_thread)
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_WARNING_NOT_COMPLETE_ROLLBACK,
                       ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
        send_ok(thd);
      }
3556
      thd->transaction.savepoints=sv;
unknown's avatar
unknown committed
3557 3558
    }
    else
3559
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
3560
    break;
3561
  }
3562
  case SQLCOM_SAVEPOINT:
3563 3564
    if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
          thd->in_sub_stmt) || !opt_using_transactions)
unknown's avatar
unknown committed
3565
      send_ok(thd);
unknown's avatar
unknown committed
3566
    else
3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604
    {
      SAVEPOINT **sv, *newsv;
      for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
      {
        if (my_strnncoll(system_charset_info,
                         (uchar *)lex->ident.str, lex->ident.length,
                         (uchar *)(*sv)->name, (*sv)->length) == 0)
          break;
      }
      if (*sv) /* old savepoint of the same name exists */
      {
        newsv=*sv;
        ha_release_savepoint(thd, *sv); // it cannot fail
        *sv=(*sv)->prev;
      }
      else if ((newsv=(SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
                                               savepoint_alloc_size)) == 0)
      {
        my_error(ER_OUT_OF_RESOURCES, MYF(0));
        break;
      }
      newsv->name=strmake_root(&thd->transaction.mem_root,
                               lex->ident.str, lex->ident.length);
      newsv->length=lex->ident.length;
      /*
        if we'll get an error here, don't add new savepoint to the list.
        we'll lose a little bit of memory in transaction mem_root, but it'll
        be free'd when transaction ends anyway
      */
      if (ha_savepoint(thd, newsv))
        res= TRUE;
      else
      {
        newsv->prev=thd->transaction.savepoints;
        thd->transaction.savepoints=newsv;
        send_ok(thd);
      }
    }
unknown's avatar
unknown committed
3605
    break;
3606 3607
  case SQLCOM_CREATE_PROCEDURE:
  case SQLCOM_CREATE_SPFUNCTION:
unknown's avatar
unknown committed
3608
  {
3609
    uint namelen;
unknown's avatar
unknown committed
3610
    char *name;
unknown's avatar
unknown committed
3611
    int sp_result= SP_INTERNAL_ERROR;
3612

3613
    DBUG_ASSERT(lex->sphead != 0);
unknown's avatar
unknown committed
3614
    DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
3615 3616 3617 3618
    /*
      Verify that the database name is allowed, optionally
      lowercase it.
    */
3619
    if (check_db_name(&lex->sphead->m_db))
3620
    {
3621
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str);
3622
      goto create_sp_error;
3623 3624
    }

3625
    /*
3626 3627 3628
      Check that a database directory with this name
      exists. Design note: This won't work on virtual databases
      like information_schema.
3629 3630
    */
    if (check_db_dir_existence(lex->sphead->m_db.str))
3631
    {
3632
      my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
3633
      goto create_sp_error;
3634
    }
3635

3636 3637
    if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
                     is_schema_db(lex->sphead->m_db.str)))
3638
      goto create_sp_error;
3639

3640 3641
    if (end_active_trans(thd))
      goto create_sp_error;
3642 3643

    name= lex->sphead->name(&namelen);
3644
#ifdef HAVE_DLOPEN
unknown's avatar
unknown committed
3645 3646 3647
    if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
    {
      udf_func *udf = find_udf(name, namelen);
3648

unknown's avatar
unknown committed
3649
      if (udf)
3650
      {
3651 3652
        my_error(ER_UDF_EXISTS, MYF(0), name);
        goto create_sp_error;
3653
      }
unknown's avatar
unknown committed
3654 3655 3656
    }
#endif

3657 3658
    if (sp_process_definer(thd))
      goto create_sp_error;
3659

unknown's avatar
unknown committed
3660 3661
    res= (sp_result= lex->sphead->create(thd));
    switch (sp_result) {
3662
    case SP_OK:
unknown's avatar
unknown committed
3663
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3664
      /* only add privileges if really neccessary */
3665
      if (sp_automatic_privileges && !opt_noacl &&
3666
          check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
3667
                               lex->sphead->m_db.str, name,
3668
                               lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
3669
      {
unknown's avatar
unknown committed
3670
        if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
3671
                                lex->sql_command == SQLCOM_CREATE_PROCEDURE))
3672 3673 3674
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_PROC_AUTO_GRANT_FAIL,
                       ER(ER_PROC_AUTO_GRANT_FAIL));
unknown's avatar
unknown committed
3675
        close_thread_tables(thd);
3676
      }
unknown's avatar
unknown committed
3677
#endif
unknown's avatar
unknown committed
3678
    break;
3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697
    case SP_WRITE_ROW_FAILED:
      my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name);
    break;
    case SP_BAD_IDENTIFIER:
      my_error(ER_TOO_LONG_IDENT, MYF(0), name);
    break;
    case SP_BODY_TOO_LONG:
      my_error(ER_TOO_LONG_BODY, MYF(0), name);
    break;
    default:
      my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name);
    break;
    } /* end switch */

    /*
      Capture all errors within this CASE and
      clean up the environment.
    */
create_sp_error:
unknown's avatar
unknown committed
3698
    if (sp_result != SP_OK )
3699 3700 3701 3702
      goto error;
    send_ok(thd);
    break; /* break super switch */
  } /* end case group bracket */
3703 3704 3705 3706
  case SQLCOM_CALL:
    {
      sp_head *sp;

3707 3708 3709 3710 3711 3712 3713 3714 3715
      /*
        This will cache all SP and SF and open and lock all tables
        required for execution.
      */
      if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
	  open_and_lock_tables(thd, all_tables))
       goto error;

      /*
3716 3717
        By this moment all needed SPs should be in cache so no need to look 
        into DB. 
3718
      */
3719 3720
      if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                                &thd->sp_proc_cache, TRUE)))
3721
      {
3722
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
unknown's avatar
unknown committed
3723
                 lex->spname->m_qname.str);
3724
	goto error;
3725 3726 3727
      }
      else
      {
unknown's avatar
unknown committed
3728
	ha_rows select_limit;
unknown's avatar
unknown committed
3729 3730
        /* bits that should be cleared in thd->server_status */
	uint bits_to_be_cleared= 0;
3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742
        /*
          Check that the stored procedure doesn't contain Dynamic SQL
          and doesn't return result sets: such stored procedures can't
          be called from a function or trigger.
        */
        if (thd->in_sub_stmt)
        {
          const char *where= (thd->in_sub_stmt & SUB_STMT_TRIGGER ?
                              "trigger" : "function");
          if (sp->is_not_allowed_in_function(where))
            goto error;
        }
3743

3744 3745
	my_bool nsok= thd->net.no_send_ok;
	thd->net.no_send_ok= TRUE;
3746
	if (sp->m_flags & sp_head::MULTI_RESULTS)
3747
	{
3748
	  if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
3749
	  {
3750 3751 3752 3753
            /*
              The client does not support multiple result sets being sent
              back
            */
3754
	    my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
3755 3756 3757
	    thd->net.no_send_ok= nsok;
	    goto error;
	  }
unknown's avatar
unknown committed
3758 3759 3760 3761 3762 3763 3764
          /*
            If SERVER_MORE_RESULTS_EXISTS is not set,
            then remember that it should be cleared
          */
	  bits_to_be_cleared= (~thd->server_status &
                               SERVER_MORE_RESULTS_EXISTS);
	  thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
3765 3766
	}

3767
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3768
	if (check_routine_access(thd, EXECUTE_ACL,
3769
				 sp->m_db.str, sp->m_name.str, TRUE, FALSE))
3770 3771 3772 3773
	{
	  thd->net.no_send_ok= nsok;
	  goto error;
	}
3774
#endif
unknown's avatar
unknown committed
3775 3776
	select_limit= thd->variables.select_limit;
	thd->variables.select_limit= HA_POS_ERROR;
3777

3778
        /* 
3779
          We never write CALL statements into binlog:
3780 3781 3782 3783 3784
           - If the mode is non-prelocked, each statement will be logged
             separately.
           - If the mode is prelocked, the invoking statement will care
             about writing into binlog.
          So just execute the statement.
3785
        */
3786
	res= sp->execute_procedure(thd, &lex->value_list);
3787 3788 3789
	/*
          If warnings have been cleared, we have to clear total_warn_count
          too, otherwise the clients get confused.
3790 3791 3792 3793
	 */
	if (thd->warn_list.is_empty())
	  thd->total_warn_count= 0;

unknown's avatar
unknown committed
3794
	thd->variables.select_limit= select_limit;
3795

3796
	thd->net.no_send_ok= nsok;
unknown's avatar
unknown committed
3797
        thd->server_status&= ~bits_to_be_cleared;
3798

unknown's avatar
unknown committed
3799
	if (!res)
unknown's avatar
unknown committed
3800 3801
	  send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
                                thd->row_count_func));
3802
	else
3803 3804
        {
          DBUG_ASSERT(thd->net.report_error == 1 || thd->killed);
3805
	  goto error;		// Substatement should already have sent error
3806
        }
3807
      }
3808
      break;
3809 3810
    }
  case SQLCOM_ALTER_PROCEDURE:
3811
  case SQLCOM_ALTER_FUNCTION:
3812
    {
unknown's avatar
unknown committed
3813
      int sp_result;
3814 3815 3816 3817
      sp_head *sp;
      st_sp_chistics chistics;

      memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
unknown's avatar
unknown committed
3818
      if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
3819 3820
        sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                            &thd->sp_proc_cache, FALSE);
3821
      else
3822 3823
        sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                            &thd->sp_func_cache, FALSE);
unknown's avatar
unknown committed
3824
      mysql_reset_errors(thd, 0);
3825
      if (! sp)
3826 3827
      {
	if (lex->spname->m_db.str)
unknown's avatar
unknown committed
3828
	  sp_result= SP_KEY_NOT_FOUND;
3829 3830 3831 3832 3833 3834
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
      }
3835 3836
      else
      {
3837 3838 3839
        if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str, 
				 sp->m_name.str,
                                 lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
3840
	  goto error;
3841 3842 3843

        if (end_active_trans(thd)) 
          goto error;
3844
	memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
3845 3846
        if ((sp->m_type == TYPE_ENUM_FUNCTION) &&
            !trust_function_creators &&  mysql_bin_log.is_open() &&
3847 3848 3849 3850 3851 3852
            !sp->m_chistics->detistic &&
            (chistics.daccess == SP_CONTAINS_SQL ||
             chistics.daccess == SP_MODIFIES_SQL_DATA))
        {
          my_message(ER_BINLOG_UNSAFE_ROUTINE,
		     ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0));
unknown's avatar
unknown committed
3853
          sp_result= SP_INTERNAL_ERROR;
3854 3855 3856
        }
        else
        {
3857 3858 3859 3860 3861 3862
          /*
            Note that if you implement the capability of ALTER FUNCTION to
            alter the body of the function, this command should be made to
            follow the restrictions that log-bin-trust-function-creators=0
            already puts on CREATE FUNCTION.
          */
unknown's avatar
unknown committed
3863
          /* Conditionally writes to binlog */
3864
          if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
unknown's avatar
unknown committed
3865 3866
            sp_result= sp_update_procedure(thd, lex->spname,
                                           &lex->sp_chistics);
3867
          else
unknown's avatar
unknown committed
3868
            sp_result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
3869
        }
3870
      }
unknown's avatar
unknown committed
3871
      switch (sp_result)
3872
      {
unknown's avatar
unknown committed
3873
      case SP_OK:
3874
	send_ok(thd);
unknown's avatar
unknown committed
3875 3876
	break;
      case SP_KEY_NOT_FOUND:
3877 3878
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
3879 3880
	goto error;
      default:
3881 3882
	my_error(ER_SP_CANT_ALTER, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
3883
	goto error;
3884
      }
3885
      break;
3886 3887
    }
  case SQLCOM_DROP_PROCEDURE:
3888
  case SQLCOM_DROP_FUNCTION:
3889
    {
unknown's avatar
unknown committed
3890
      int sp_result;
3891 3892
      int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
                 TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
3893

unknown's avatar
unknown committed
3894
      sp_result= sp_routine_exists_in_table(thd, type, lex->spname);
unknown's avatar
unknown committed
3895
      mysql_reset_errors(thd, 0);
unknown's avatar
unknown committed
3896
      if (sp_result == SP_OK)
3897
      {
3898 3899 3900
        char *db= lex->spname->m_db.str;
	char *name= lex->spname->m_name.str;

3901 3902
	if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
unknown's avatar
merge  
unknown committed
3903
          goto error;
3904 3905 3906

        if (end_active_trans(thd)) 
          goto error;
unknown's avatar
unknown committed
3907
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3908
	if (sp_automatic_privileges && !opt_noacl &&
3909 3910
	    sp_revoke_privileges(thd, db, name, 
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE))
3911 3912 3913 3914 3915
	{
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
		       ER_PROC_AUTO_REVOKE_FAIL,
		       ER(ER_PROC_AUTO_REVOKE_FAIL));
	}
unknown's avatar
unknown committed
3916
#endif
unknown's avatar
unknown committed
3917
        /* Conditionally writes to binlog */
3918
	if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
unknown's avatar
unknown committed
3919
	  sp_result= sp_drop_procedure(thd, lex->spname);
3920
	else
unknown's avatar
unknown committed
3921
	  sp_result= sp_drop_function(thd, lex->spname);
3922 3923 3924
      }
      else
      {
3925
#ifdef HAVE_DLOPEN
3926 3927 3928 3929 3930 3931
	if (lex->sql_command == SQLCOM_DROP_FUNCTION)
	{
          udf_func *udf = find_udf(lex->spname->m_name.str,
                                   lex->spname->m_name.length);
          if (udf)
          {
3932
	    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
3933
	      goto error;
3934

3935
	    if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
3936
	    {
3937 3938
	      send_ok(thd);
	      break;
3939 3940
	    }
	  }
3941
	}
3942
#endif
3943
	if (lex->spname->m_db.str)
unknown's avatar
unknown committed
3944
	  sp_result= SP_KEY_NOT_FOUND;
3945 3946 3947 3948 3949
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
3950
      }
unknown's avatar
unknown committed
3951 3952
      res= sp_result;
      switch (sp_result) {
3953
      case SP_OK:
3954
	send_ok(thd);
3955 3956
	break;
      case SP_KEY_NOT_FOUND:
3957 3958
	if (lex->drop_if_exists)
	{
3959
	  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
3960
			      ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
3961
			      SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
3962
	  res= FALSE;
3963 3964 3965
	  send_ok(thd);
	  break;
	}
3966 3967
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
3968 3969
	goto error;
      default:
3970 3971
	my_error(ER_SP_DROP_FAILED, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
3972
	goto error;
3973
      }
3974
      break;
3975
    }
unknown's avatar
unknown committed
3976 3977
  case SQLCOM_SHOW_CREATE_PROC:
    {
unknown's avatar
unknown committed
3978
      if (sp_show_create_procedure(thd, lex->spname) != SP_OK)
3979
      {			/* We don't distinguish between errors for now */
3980 3981
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
3982 3983 3984 3985 3986 3987
	goto error;
      }
      break;
    }
  case SQLCOM_SHOW_CREATE_FUNC:
    {
unknown's avatar
unknown committed
3988
      if (sp_show_create_function(thd, lex->spname) != SP_OK)
3989
      {			/* We don't distinguish between errors for now */
3990 3991
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
3992 3993 3994 3995
	goto error;
      }
      break;
    }
3996
#ifdef NOT_USED
unknown's avatar
unknown committed
3997 3998
  case SQLCOM_SHOW_STATUS_PROC:
    {
3999
      res= sp_show_status_procedure(thd, (lex->wild ?
unknown's avatar
unknown committed
4000 4001 4002 4003 4004
					  lex->wild->ptr() : NullS));
      break;
    }
  case SQLCOM_SHOW_STATUS_FUNC:
    {
4005
      res= sp_show_status_function(thd, (lex->wild ? 
unknown's avatar
unknown committed
4006 4007 4008
					 lex->wild->ptr() : NullS));
      break;
    }
4009
#endif
unknown's avatar
unknown committed
4010 4011 4012 4013 4014 4015 4016
#ifndef DBUG_OFF
  case SQLCOM_SHOW_PROC_CODE:
  case SQLCOM_SHOW_FUNC_CODE:
    {
      sp_head *sp;

      if (lex->sql_command == SQLCOM_SHOW_PROC_CODE)
unknown's avatar
unknown committed
4017 4018
        sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                            &thd->sp_proc_cache, FALSE);
unknown's avatar
unknown committed
4019
      else
unknown's avatar
unknown committed
4020 4021
        sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                            &thd->sp_func_cache, FALSE);
4022
      if (!sp || sp->show_routine_code(thd))
4023 4024
      {
        /* We don't distinguish between errors for now */
unknown's avatar
unknown committed
4025 4026 4027 4028 4029 4030 4031
        my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
        goto error;
      }
      break;
    }
#endif // ifndef DBUG_OFF
unknown's avatar
VIEW  
unknown committed
4032 4033
  case SQLCOM_CREATE_VIEW:
    {
4034 4035 4036
      if (end_active_trans(thd))
        goto error;

4037
      res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
unknown's avatar
VIEW  
unknown committed
4038 4039 4040 4041
      break;
    }
  case SQLCOM_DROP_VIEW:
    {
unknown's avatar
unknown committed
4042 4043 4044
      if (check_table_access(thd, DROP_ACL, all_tables, 0) ||
          end_active_trans(thd))
        goto error;
4045 4046
      /* Conditionally writes to binlog. */
      res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
unknown's avatar
VIEW  
unknown committed
4047 4048
      break;
    }
4049 4050
  case SQLCOM_CREATE_TRIGGER:
  {
4051 4052 4053
    if (end_active_trans(thd))
      goto error;

4054
    /* Conditionally writes to binlog. */
4055 4056
    res= mysql_create_or_drop_trigger(thd, all_tables, 1);

4057 4058 4059 4060
    break;
  }
  case SQLCOM_DROP_TRIGGER:
  {
4061 4062 4063
    if (end_active_trans(thd))
      goto error;

4064
    /* Conditionally writes to binlog. */
4065 4066 4067
    res= mysql_create_or_drop_trigger(thd, all_tables, 0);
    break;
  }
4068
  case SQLCOM_XA_START:
4069 4070
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
        thd->lex->xa_opt == XA_RESUME)
4071
    {
4072
      if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
4073 4074 4075 4076
      {
        my_error(ER_XAER_NOTA, MYF(0));
        break;
      }
4077
      thd->transaction.xid_state.xa_state=XA_ACTIVE;
4078 4079 4080
      send_ok(thd);
      break;
    }
unknown's avatar
unknown committed
4081
    if (thd->lex->xa_opt != XA_NONE)
4082 4083 4084 4085
    { // JOIN is not supported yet. TODO
      my_error(ER_XAER_INVAL, MYF(0));
      break;
    }
4086
    if (thd->transaction.xid_state.xa_state != XA_NOTR)
4087
    {
unknown's avatar
unknown committed
4088
      my_error(ER_XAER_RMFAIL, MYF(0),
4089
               xa_state_names[thd->transaction.xid_state.xa_state]);
4090 4091 4092 4093 4094 4095 4096
      break;
    }
    if (thd->active_transaction() || thd->locked_tables)
    {
      my_error(ER_XAER_OUTSIDE, MYF(0));
      break;
    }
4097 4098 4099 4100 4101 4102 4103 4104 4105
    if (xid_cache_search(thd->lex->xid))
    {
      my_error(ER_XAER_DUPID, MYF(0));
      break;
    }
    DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
    thd->transaction.xid_state.xa_state=XA_ACTIVE;
    thd->transaction.xid_state.xid.set(thd->lex->xid);
    xid_cache_insert(&thd->transaction.xid_state);
4106
    thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN);
4107
    thd->no_trans_update.all= FALSE;
4108 4109 4110 4111 4112 4113 4114 4115 4116 4117
    thd->server_status|= SERVER_STATUS_IN_TRANS;
    send_ok(thd);
    break;
  case SQLCOM_XA_END:
    /* fake it */
    if (thd->lex->xa_opt != XA_NONE)
    { // SUSPEND and FOR MIGRATE are not supported yet. TODO
      my_error(ER_XAER_INVAL, MYF(0));
      break;
    }
4118
    if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
4119
    {
unknown's avatar
unknown committed
4120
      my_error(ER_XAER_RMFAIL, MYF(0),
4121
               xa_state_names[thd->transaction.xid_state.xa_state]);
4122 4123
      break;
    }
4124
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4125 4126 4127 4128
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
4129
    thd->transaction.xid_state.xa_state=XA_IDLE;
4130 4131 4132
    send_ok(thd);
    break;
  case SQLCOM_XA_PREPARE:
4133
    if (thd->transaction.xid_state.xa_state != XA_IDLE)
4134
    {
unknown's avatar
unknown committed
4135
      my_error(ER_XAER_RMFAIL, MYF(0),
4136
               xa_state_names[thd->transaction.xid_state.xa_state]);
4137 4138
      break;
    }
4139
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4140 4141 4142 4143 4144 4145 4146
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
    if (ha_prepare(thd))
    {
      my_error(ER_XA_RBROLLBACK, MYF(0));
4147 4148
      xid_cache_delete(&thd->transaction.xid_state);
      thd->transaction.xid_state.xa_state=XA_NOTR;
4149 4150
      break;
    }
4151
    thd->transaction.xid_state.xa_state=XA_PREPARED;
4152 4153 4154
    send_ok(thd);
    break;
  case SQLCOM_XA_COMMIT:
4155
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4156
    {
4157 4158
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
4159
        my_error(ER_XAER_NOTA, MYF(0));
unknown's avatar
unknown committed
4160
      else
4161 4162 4163
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
        xid_cache_delete(xs);
unknown's avatar
unknown committed
4164
        send_ok(thd);
4165
      }
4166 4167
      break;
    }
4168
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
unknown's avatar
unknown committed
4169
        thd->lex->xa_opt == XA_ONE_PHASE)
4170
    {
unknown's avatar
unknown committed
4171 4172 4173
      int r;
      if ((r= ha_commit(thd)))
        my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
4174 4175 4176
      else
        send_ok(thd);
    }
4177
    else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
unknown's avatar
unknown committed
4178
             thd->lex->xa_opt == XA_NONE)
4179
    {
4180 4181 4182
      if (wait_if_global_read_lock(thd, 0, 0))
      {
        ha_rollback(thd);
4183
        my_error(ER_XAER_RMERR, MYF(0));
4184
      }
4185
      else
4186 4187 4188 4189 4190 4191 4192
      {
        if (ha_commit_one_phase(thd, 1))
          my_error(ER_XAER_RMERR, MYF(0));
        else
          send_ok(thd);
        start_waiting_global_read_lock(thd);
      }
4193 4194 4195
    }
    else
    {
unknown's avatar
unknown committed
4196
      my_error(ER_XAER_RMFAIL, MYF(0),
4197
               xa_state_names[thd->transaction.xid_state.xa_state]);
4198 4199
      break;
    }
unknown's avatar
unknown committed
4200 4201
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
    thd->no_trans_update.all= FALSE;
4202
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
4203 4204
    xid_cache_delete(&thd->transaction.xid_state);
    thd->transaction.xid_state.xa_state=XA_NOTR;
4205 4206
    break;
  case SQLCOM_XA_ROLLBACK:
4207
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4208
    {
4209 4210
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
4211
        my_error(ER_XAER_NOTA, MYF(0));
unknown's avatar
unknown committed
4212
      else
4213 4214 4215
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
        xid_cache_delete(xs);
unknown's avatar
unknown committed
4216
        send_ok(thd);
4217
      }
4218 4219
      break;
    }
4220 4221
    if (thd->transaction.xid_state.xa_state != XA_IDLE &&
        thd->transaction.xid_state.xa_state != XA_PREPARED)
4222
    {
unknown's avatar
unknown committed
4223
      my_error(ER_XAER_RMFAIL, MYF(0),
4224
               xa_state_names[thd->transaction.xid_state.xa_state]);
4225 4226 4227 4228 4229 4230
      break;
    }
    if (ha_rollback(thd))
      my_error(ER_XAER_RMERR, MYF(0));
    else
      send_ok(thd);
4231
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
4232
    thd->no_trans_update.all= FALSE;
4233
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
4234 4235
    xid_cache_delete(&thd->transaction.xid_state);
    thd->transaction.xid_state.xa_state=XA_NOTR;
4236 4237
    break;
  case SQLCOM_XA_RECOVER:
4238
    res= mysql_xa_recover(thd);
4239
    break;
unknown's avatar
unknown committed
4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263
  case SQLCOM_ALTER_TABLESPACE:
    if (check_access(thd, ALTER_ACL, thd->db, 0, 1, 0, thd->db ? is_schema_db(thd->db) : 0))
      break;
    if (!(res= mysql_alter_tablespace(thd, lex->alter_tablespace_info)))
      send_ok(thd);
    break;
  case SQLCOM_INSTALL_PLUGIN:
    if (! (res= mysql_install_plugin(thd, &thd->lex->comment,
                                     &thd->lex->ident)))
      send_ok(thd);
    break;
  case SQLCOM_UNINSTALL_PLUGIN:
    if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment)))
      send_ok(thd);
    break;
  case SQLCOM_BINLOG_BASE64_EVENT:
  {
#ifndef EMBEDDED_LIBRARY
    mysql_client_binlog_statement(thd);
#else /* EMBEDDED_LIBRARY */
    my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "embedded");
#endif /* EMBEDDED_LIBRARY */
    break;
  }
unknown's avatar
unknown committed
4264 4265 4266 4267 4268
  case SQLCOM_CREATE_SERVER:
  {
    int error;
    LEX *lex= thd->lex;
    DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER"));
unknown's avatar
unknown committed
4269 4270 4271 4272

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4273 4274
    if ((error= create_server(thd, &lex->server_options)))
    {
4275
      DBUG_PRINT("info", ("problem creating server <%s>",
unknown's avatar
unknown committed
4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287
                          lex->server_options.server_name));
      my_error(error, MYF(0), lex->server_options.server_name);
      break;
    }
    send_ok(thd, 1);
    break;
  }
  case SQLCOM_ALTER_SERVER:
  {
    int error;
    LEX *lex= thd->lex;
    DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER"));
unknown's avatar
unknown committed
4288 4289 4290 4291

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4292 4293
    if ((error= alter_server(thd, &lex->server_options)))
    {
4294
      DBUG_PRINT("info", ("problem altering server <%s>",
unknown's avatar
unknown committed
4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306
                          lex->server_options.server_name));
      my_error(error, MYF(0), lex->server_options.server_name);
      break;
    }
    send_ok(thd, 1);
    break;
  }
  case SQLCOM_DROP_SERVER:
  {
    int err_code;
    LEX *lex= thd->lex;
    DBUG_PRINT("info", ("case SQLCOM_DROP_SERVER"));
unknown's avatar
unknown committed
4307 4308 4309 4310

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4311 4312
    if ((err_code= drop_server(thd, &lex->server_options)))
    {
unknown's avatar
unknown committed
4313
      if (! lex->drop_if_exists && err_code == ER_FOREIGN_SERVER_DOESNT_EXIST)
unknown's avatar
unknown committed
4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327
      {
        DBUG_PRINT("info", ("problem dropping server %s",
                            lex->server_options.server_name));
        my_error(err_code, MYF(0), lex->server_options.server_name);
      }
      else
      {
        send_ok(thd, 0);
      }
      break;
    }
    send_ok(thd, 1);
    break;
  }
4328
  default:
4329
#ifndef EMBEDDED_LIBRARY
4330
    DBUG_ASSERT(0);                             /* Impossible */
4331
#endif
4332
    send_ok(thd);
unknown's avatar
unknown committed
4333 4334
    break;
  }
unknown's avatar
unknown committed
4335

unknown's avatar
unknown committed
4336
  thd->proc_info="query end";
4337 4338

  /*
unknown's avatar
unknown committed
4339
    Binlog-related cleanup:
4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350
    Reset system variables temporarily modified by SET ONE SHOT.

    Exception: If this is a SET, do nothing. This is to allow
    mysqlbinlog to print many SET commands (in this case we want the
    charset temp setting to live until the real query). This is also
    needed so that SET CHARACTER_SET_CLIENT... does not cancel itself
    immediately.
  */
  if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION)
    reset_one_shot_variables(thd);

4351
  /*
4352 4353
    The return value for ROW_COUNT() is "implementation dependent" if the
    statement is not DELETE, INSERT or UPDATE, but -1 is what JDBC and ODBC
4354 4355 4356 4357
    wants. We also keep the last value in case of SQLCOM_CALL or
    SQLCOM_EXECUTE.
  */
  if (!(sql_command_flags[lex->sql_command] & CF_HAS_ROW_COUNT))
4358
    thd->row_count_func= -1;
4359

4360
  goto finish;
unknown's avatar
unknown committed
4361 4362

error:
4363 4364
  res= TRUE;

4365
finish:
4366 4367 4368 4369 4370 4371 4372 4373 4374
  if (need_start_waiting)
  {
    /*
      Release the protection against the global read lock and wake
      everyone, who might want to set a global read lock.
    */
    start_waiting_global_read_lock(thd);
  }
  DBUG_RETURN(res || thd->net.report_error);
unknown's avatar
unknown committed
4375 4376 4377
}


4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400
static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
{
  LEX	*lex= thd->lex;
  select_result *result=lex->result;
  bool res;
  /* assign global limit variable if limit is not given */
  {
    SELECT_LEX *param= lex->unit.global_parameters;
    if (!param->explicit_limit)
      param->select_limit=
        new Item_int((ulonglong) thd->variables.select_limit);
  }
  if (!(res= open_and_lock_tables(thd, all_tables)))
  {
    if (lex->describe)
    {
      /*
        We always use select_send for EXPLAIN, even if it's an EXPLAIN
        for SELECT ... INTO OUTFILE: a user application should be able
        to prepend EXPLAIN to any query and receive output for it,
        even if the query itself redirects the output.
      */
      if (!(result= new select_send()))
4401
        return 1;                               /* purecov: inspected */
4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419
      thd->send_explain_fields(result);
      res= mysql_explain_union(thd, &thd->lex->unit, result);
      if (lex->describe & DESCRIBE_EXTENDED)
      {
        char buff[1024];
        String str(buff,(uint32) sizeof(buff), system_charset_info);
        str.length(0);
        thd->lex->unit.print(&str);
        str.append('\0');
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
                     ER_YES, str.ptr());
      }
      result->send_eof();
      delete result;
    }
    else
    {
      if (!result && !(result= new select_send()))
4420
        return 1;                               /* purecov: inspected */
4421 4422 4423 4424 4425 4426 4427 4428 4429 4430
      query_cache_store_query(thd, all_tables);
      res= handle_select(thd, lex, result, 0);
      if (result != lex->result)
        delete result;
    }
  }
  return res;
}


unknown's avatar
unknown committed
4431
/*
4432
  Check grants for commands which work only with one table.
unknown's avatar
unknown committed
4433

4434
  SYNOPSIS
4435
    check_single_table_access()
unknown's avatar
unknown committed
4436
    thd			Thread handler
4437
    privilege		requested privilege
unknown's avatar
VIEW  
unknown committed
4438
    all_tables		global table list of query
4439 4440
    no_errors           FALSE/TRUE - report/don't report error to
                            the client (using my_error() call).
unknown's avatar
unknown committed
4441 4442 4443

  RETURN
    0 - OK
unknown's avatar
unknown committed
4444
    1 - access denied, error is sent to client
unknown's avatar
unknown committed
4445 4446
*/

4447
bool check_single_table_access(THD *thd, ulong privilege, 
4448
                               TABLE_LIST *all_tables, bool no_errors)
unknown's avatar
unknown committed
4449
{
4450 4451 4452 4453 4454 4455
  Security_context * backup_ctx= thd->security_ctx;

  /* we need to switch to the saved context (if any) */
  if (all_tables->security_ctx)
    thd->security_ctx= all_tables->security_ctx;

4456 4457 4458 4459 4460 4461 4462 4463
  const char *db_name;
  if ((all_tables->view || all_tables->field_translation) &&
      !all_tables->schema_table)
    db_name= all_tables->view_db.str;
  else
    db_name= all_tables->db;

  if (check_access(thd, privilege, db_name,
4464
		   &all_tables->grant.privilege, 0, no_errors,
4465
                   test(all_tables->schema_table)))
4466
    goto deny;
unknown's avatar
unknown committed
4467

unknown's avatar
unknown committed
4468
  /* Show only 1 table for check_grant */
4469 4470 4471
  if (grant_option &&
      !(all_tables->belong_to_view &&
        (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
4472
      check_grant(thd, privilege, all_tables, 0, 1, no_errors))
4473 4474 4475
    goto deny;

  thd->security_ctx= backup_ctx;
4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499
  return 0;

deny:
  thd->security_ctx= backup_ctx;
  return 1;
}

/*
  Check grants for commands which work only with one table and all other
  tables belonging to subselects or implicitly opened tables.

  SYNOPSIS
    check_one_table_access()
    thd			Thread handler
    privilege		requested privilege
    all_tables		global table list of query

  RETURN
    0 - OK
    1 - access denied, error is sent to client
*/

bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
{
4500
  if (check_single_table_access (thd,privilege,all_tables, FALSE))
4501
    return 1;
unknown's avatar
unknown committed
4502

4503
  /* Check rights on tables of subselects and implictly opened tables */
unknown's avatar
unknown committed
4504
  TABLE_LIST *subselects_tables, *view= all_tables->view ? all_tables : 0;
unknown's avatar
VIEW  
unknown committed
4505
  if ((subselects_tables= all_tables->next_global))
unknown's avatar
unknown committed
4506
  {
unknown's avatar
unknown committed
4507 4508 4509 4510 4511 4512
    /*
      Access rights asked for the first table of a view should be the same
      as for the view
    */
    if (view && subselects_tables->belong_to_view == view)
    {
4513
      if (check_single_table_access (thd, privilege, subselects_tables, FALSE))
unknown's avatar
unknown committed
4514 4515 4516 4517 4518
        return 1;
      subselects_tables= subselects_tables->next_global;
    }
    if (subselects_tables &&
        (check_table_access(thd, SELECT_ACL, subselects_tables, 0)))
4519
      return 1;
unknown's avatar
unknown committed
4520 4521
  }
  return 0;
unknown's avatar
unknown committed
4522 4523 4524
}


unknown's avatar
unknown committed
4525
/****************************************************************************
unknown's avatar
unknown committed
4526
  Get the user (global) and database privileges for all used tables
unknown's avatar
unknown committed
4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539

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

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

    save_priv	In this we store global and db level grants for the table
		Note that we don't store db level grants if the global grants
unknown's avatar
unknown committed
4540 4541
                is enough to satisfy the request and the global grants contains
                a SELECT grant.
unknown's avatar
unknown committed
4542 4543 4544
****************************************************************************/

bool
unknown's avatar
unknown committed
4545
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
4546
	     bool dont_check_global_grants, bool no_errors, bool schema_db)
unknown's avatar
unknown committed
4547
{
4548
  Security_context *sctx= thd->security_ctx;
unknown's avatar
unknown committed
4549 4550
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  ulong db_access;
unknown's avatar
unknown committed
4551
  bool  db_is_pattern= test(want_access & GRANT_ACL);
unknown's avatar
unknown committed
4552 4553
#endif
  ulong dummy;
4554 4555
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("db: %s  want_access: %lu  master_access: %lu",
4556
                      db ? db : "", want_access, sctx->master_access));
unknown's avatar
unknown committed
4557 4558 4559 4560 4561
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

4562
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
4563
  {
4564
    DBUG_PRINT("error",("No database"));
4565
    if (!no_errors)
unknown's avatar
unknown committed
4566 4567
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
                 MYF(0));                       /* purecov: tested */
unknown's avatar
unknown committed
4568
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4569 4570
  }

4571 4572 4573 4574 4575
  if (schema_db)
  {
    if (want_access & ~(SELECT_ACL | EXTRA_ACL))
    {
      if (!no_errors)
4576 4577
      {
        const char *db_name= db ? db : thd->db;
4578
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
4579 4580
                 sctx->priv_user, sctx->priv_host, db_name);
      }
4581 4582 4583 4584 4585 4586 4587 4588 4589
      DBUG_RETURN(TRUE);
    }
    else
    {
      *save_priv= SELECT_ACL;
      DBUG_RETURN(FALSE);
    }
  }

unknown's avatar
unknown committed
4590 4591 4592
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  DBUG_RETURN(0);
#else
4593
  if ((sctx->master_access & want_access) == want_access)
unknown's avatar
unknown committed
4594
  {
4595 4596 4597 4598 4599
    /*
      If we don't have a global SELECT privilege, we have to get the database
      specific access rights to be able to handle queries of type
      UPDATE t1 SET a=1 WHERE b > 0
    */
4600 4601
    db_access= sctx->db_access;
    if (!(sctx->master_access & SELECT_ACL) &&
unknown's avatar
unknown committed
4602
	(db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
4603 4604 4605
      db_access=acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
                        db_is_pattern);
    *save_priv=sctx->master_access | db_access;
unknown's avatar
unknown committed
4606
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
4607
  }
4608
  if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
4609
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
4610
  {						// We can never grant this
4611
    DBUG_PRINT("error",("No possible access"));
4612
    if (!no_errors)
4613
      my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
4614 4615
               sctx->priv_user,
               sctx->priv_host,
4616 4617 4618
               (thd->password ?
                ER(ER_YES) :
                ER(ER_NO)));                    /* purecov: tested */
unknown's avatar
unknown committed
4619
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4620 4621 4622
  }

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

unknown's avatar
unknown committed
4625
  if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
4626 4627
    db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
                       db_is_pattern);
unknown's avatar
unknown committed
4628
  else
4629
    db_access= sctx->db_access;
4630
  DBUG_PRINT("info",("db_access: %lu", db_access));
unknown's avatar
unknown committed
4631
  /* Remove SHOW attribute and access rights we already have */
4632
  want_access &= ~(sctx->master_access | EXTRA_ACL);
4633 4634
  DBUG_PRINT("info",("db_access: %lu  want_access: %lu",
                     db_access, want_access));
4635
  db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
4636 4637

  /* grant_option is set if there exists a single table or column grant */
unknown's avatar
unknown committed
4638
  if (db_access == want_access ||
4639
      (grant_option && !dont_check_global_grants &&
4640
       !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
unknown's avatar
unknown committed
4641
    DBUG_RETURN(FALSE);				/* Ok */
4642 4643

  DBUG_PRINT("error",("Access denied"));
4644
  if (!no_errors)
4645
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
4646
             sctx->priv_user, sctx->priv_host,
4647 4648 4649
             (db ? db : (thd->db ?
                         thd->db :
                         "unknown")));          /* purecov: tested */
unknown's avatar
unknown committed
4650
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4651
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
4652 4653 4654
}


4655 4656 4657 4658 4659 4660 4661 4662 4663
/*
  check for global access and give descriptive error message if it fails

  SYNOPSIS
    check_global_access()
    thd			Thread handler
    want_access		Use should have any of these global rights

  WARNING
4664
    One gets access right if one has ANY of the rights in want_access
4665 4666 4667 4668 4669 4670 4671 4672
    This is useful as one in most cases only need one global right,
    but in some case we want to check if the user has SUPER or
    REPL_CLIENT_ACL rights.

  RETURN
    0	ok
    1	Access denied.  In this case an error is sent to the client
*/
unknown's avatar
unknown committed
4673 4674

bool check_global_access(THD *thd, ulong want_access)
unknown's avatar
unknown committed
4675
{
unknown's avatar
unknown committed
4676 4677 4678
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  return 0;
#else
unknown's avatar
unknown committed
4679
  char command[128];
4680
  if ((thd->security_ctx->master_access & want_access))
unknown's avatar
unknown committed
4681 4682
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
4683
  my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
unknown's avatar
unknown committed
4684
  return 1;
unknown's avatar
unknown committed
4685
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
4686 4687 4688
}


4689 4690
static bool check_show_access(THD *thd, TABLE_LIST *table)
{
unknown's avatar
unknown committed
4691
  switch (get_schema_table_idx(table->schema_table)) {
4692 4693
  case SCH_SCHEMATA:
    return (specialflag & SPECIAL_SKIP_SHOW_DB) &&
unknown's avatar
unknown committed
4694
      check_global_access(thd, SHOW_DB_ACL);
4695 4696 4697 4698 4699

  case SCH_TABLE_NAMES:
  case SCH_TABLES:
  case SCH_VIEWS:
  case SCH_TRIGGERS:
unknown's avatar
unknown committed
4700 4701 4702
  case SCH_EVENTS:
  {
    const char *dst_db_name= table->schema_select_lex->db;
4703

unknown's avatar
unknown committed
4704
    DBUG_ASSERT(dst_db_name);
4705

unknown's avatar
unknown committed
4706 4707 4708 4709
    if (check_access(thd, SELECT_ACL, dst_db_name,
                     &thd->col_access, FALSE, FALSE,
                     is_schema_db(dst_db_name)))
      return TRUE;
4710

unknown's avatar
unknown committed
4711 4712 4713 4714 4715 4716 4717
    if (!thd->col_access && check_grant_db(thd, dst_db_name))
    {
      my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
               thd->security_ctx->priv_user,
               thd->security_ctx->priv_host,
               dst_db_name);
      return TRUE;
4718 4719
    }

unknown's avatar
unknown committed
4720 4721 4722
    return FALSE;
  }

4723 4724
  case SCH_COLUMNS:
  case SCH_STATISTICS:
unknown's avatar
unknown committed
4725 4726 4727
  {
    TABLE_LIST *dst_table;
    dst_table= (TABLE_LIST *) table->schema_select_lex->table_list.first;
4728

unknown's avatar
unknown committed
4729
    DBUG_ASSERT(dst_table);
4730

unknown's avatar
unknown committed
4731 4732 4733 4734 4735 4736
    if (check_access(thd, SELECT_ACL | EXTRA_ACL,
                     dst_table->db,
                     &dst_table->grant.privilege,
                     FALSE, FALSE,
                     test(dst_table->schema_table)))
      return FALSE;
4737

unknown's avatar
unknown committed
4738 4739 4740 4741
    return (grant_option &&
            check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE));
  }
  default:
4742 4743 4744 4745 4746 4747 4748
    break;
  }

  return FALSE;
}


unknown's avatar
unknown committed
4749
/*
4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769
  Check the privilege for all used tables.

  SYNOPSYS
    check_table_access()
      thd          Thread context
      want_access  Privileges requested
      tables       List of tables to be checked
      no_errors    FALSE/TRUE - report/don't report error to
                   the client (using my_error() call).

  NOTES
    Table privileges are cached in the table list for GRANT checking.
    This functions assumes that table list used and
    thd->lex->query_tables_own_last value correspond to each other
    (the latter should be either 0 or point to next_global member
    of one of elements of this table list).

  RETURN VALUE
    FALSE - OK
    TRUE  - Access denied
unknown's avatar
unknown committed
4770 4771
*/

4772
bool
unknown's avatar
unknown committed
4773
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
4774
		   bool no_errors)
unknown's avatar
unknown committed
4775
{
unknown's avatar
unknown committed
4776 4777
  uint found=0;
  ulong found_access=0;
4778
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4779
  TABLE_LIST *org_tables= tables;
unknown's avatar
unknown committed
4780
#endif
4781
  TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
4782
  Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx;
4783
  /*
unknown's avatar
unknown committed
4784 4785 4786
    The check that first_not_own_table is not reached is for the case when
    the given table list refers to the list for prelocking (contains tables
    of other queries). For simple queries first_not_own_table is 0.
4787
  */
unknown's avatar
unknown committed
4788
  for (; tables != first_not_own_table; tables= tables->next_global)
unknown's avatar
unknown committed
4789
  {
4790 4791 4792 4793 4794
    if (tables->security_ctx)
      sctx= tables->security_ctx;
    else
      sctx= backup_ctx;

4795
    if (tables->schema_table && 
4796
        (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
4797 4798 4799
    {
      if (!no_errors)
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
4800
                 sctx->priv_user, sctx->priv_host,
4801
                 INFORMATION_SCHEMA_NAME.str);
4802 4803
      return TRUE;
    }
4804 4805 4806 4807 4808
    /*
       Register access for view underlying table.
       Remove SHOW_VIEW_ACL, because it will be checked during making view
     */
    tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
unknown's avatar
unknown committed
4809 4810 4811 4812 4813 4814 4815 4816 4817 4818

    if (tables->schema_table_reformed)
    {
      if (check_show_access(thd, tables))
        goto deny;

      continue;
    }

    if (tables->derived ||
4819
        (tables->table && (int)tables->table->s->tmp_table))
unknown's avatar
unknown committed
4820
      continue;
4821 4822
    thd->security_ctx= sctx;
    if ((sctx->master_access & want_access) ==
4823
        (want_access & ~EXTRA_ACL) &&
unknown's avatar
unknown committed
4824
	thd->db)
unknown's avatar
unknown committed
4825
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
4826
    else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
unknown's avatar
unknown committed
4827 4828 4829 4830 4831
    {
      if (found && !grant_option)		// db already checked
	tables->grant.privilege=found_access;
      else
      {
4832
	if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
4833
			 0, no_errors, test(tables->schema_table)))
4834
	  goto deny;                            // Access denied
unknown's avatar
unknown committed
4835
	found_access=tables->grant.privilege;
unknown's avatar
unknown committed
4836
	found=1;
unknown's avatar
unknown committed
4837 4838
      }
    }
4839
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
4840
			  0, no_errors, test(tables->schema_table)))
4841
      goto deny;
unknown's avatar
unknown committed
4842
  }
4843
  thd->security_ctx= backup_ctx;
unknown's avatar
unknown committed
4844
  if (grant_option)
4845
    return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
unknown's avatar
unknown committed
4846
		       test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
unknown's avatar
unknown committed
4847
  return FALSE;
4848 4849 4850
deny:
  thd->security_ctx= backup_ctx;
  return TRUE;
unknown's avatar
unknown committed
4851 4852
}

4853

4854
bool
4855 4856
check_routine_access(THD *thd, ulong want_access,char *db, char *name,
		     bool is_proc, bool no_errors)
4857 4858 4859 4860 4861
{
  TABLE_LIST tables[1];
  
  bzero((char *)tables, sizeof(TABLE_LIST));
  tables->db= db;
4862
  tables->table_name= tables->alias= name;
4863
  
unknown's avatar
unknown committed
4864 4865 4866 4867 4868 4869 4870
  /*
    The following test is just a shortcut for check_access() (to avoid
    calculating db_access) under the assumption that it's common to
    give persons global right to execute all stored SP (but not
    necessary to create them).
  */
  if ((thd->security_ctx->master_access & want_access) == want_access)
4871 4872
    tables->grant.privilege= want_access;
  else if (check_access(thd,want_access,db,&tables->grant.privilege,
unknown's avatar
unknown committed
4873
			0, no_errors, 0))
4874 4875
    return TRUE;
  
unknown's avatar
unknown committed
4876
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4877
  if (grant_option)
4878
    return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
unknown's avatar
unknown committed
4879
#endif
4880 4881 4882 4883

  return FALSE;
}

4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898

/*
  Check if the routine has any of the routine privileges

  SYNOPSIS
    check_some_routine_access()
    thd		 Thread handler
    db           Database name
    name         Routine name

  RETURN
    0            ok
    1            error
*/

4899 4900
bool check_some_routine_access(THD *thd, const char *db, const char *name,
                               bool is_proc)
4901 4902
{
  ulong save_priv;
4903
  if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
4904
    return FALSE;
4905 4906 4907 4908 4909
  /*
    There are no routines in information_schema db. So we can safely
    pass zero to last paramter of check_access function
  */
  if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1, 0) ||
4910 4911
      (save_priv & SHOW_PROC_ACLS))
    return FALSE;
4912
  return check_routine_level_acl(thd, db, name, is_proc);
4913 4914 4915
}


4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940
/*
  Check if the given table has any of the asked privileges

  SYNOPSIS
    check_some_access()
    thd		 Thread handler
    want_access	 Bitmap of possible privileges to check for

  RETURN
    0  ok
    1  error
*/


bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
{
  ulong access;
  DBUG_ENTER("check_some_access");

  /* This loop will work as long as we have less than 32 privileges */
  for (access= 1; access < want_access ; access<<= 1)
  {
    if (access & want_access)
    {
      if (!check_access(thd, access, table->db,
4941 4942
                        &table->grant.privilege, 0, 1,
                        test(table->schema_table)) &&
4943 4944 4945 4946 4947 4948 4949 4950 4951
          !grant_option || !check_grant(thd, access, table, 0, 1, 1))
        DBUG_RETURN(0);
    }
  }
  DBUG_PRINT("exit",("no matching access rights"));
  DBUG_RETURN(1);
}


4952 4953
bool check_merge_table_access(THD *thd, char *db,
			      TABLE_LIST *table_list)
4954 4955 4956 4957
{
  int error=0;
  if (table_list)
  {
4958
    /* Check that all tables use the current database */
4959
    TABLE_LIST *tmp;
unknown's avatar
VIEW  
unknown committed
4960
    for (tmp= table_list; tmp; tmp= tmp->next_local)
4961 4962 4963 4964
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
    }
4965
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
unknown's avatar
unknown committed
4966
			     table_list,0);
4967 4968 4969 4970
  }
  return error;
}

unknown's avatar
unknown committed
4971

unknown's avatar
unknown committed
4972 4973 4974 4975 4976 4977 4978 4979 4980 4981
/****************************************************************************
	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

unknown's avatar
unknown committed
4982 4983 4984 4985
#ifndef DBUG_OFF
long max_stack_used;
#endif

4986
#ifndef EMBEDDED_LIBRARY
4987 4988 4989 4990 4991 4992 4993 4994
/*
  Note: The 'buf' parameter is necessary, even if it is unused here.
  - fix_fields functions has a "dummy" buffer large enough for the
    corresponding exec. (Thus we only have to check in fix_fields.)
  - Passing to check_stack_overrun() prevents the compiler from removing it.
 */
bool check_stack_overrun(THD *thd, long margin,
			 char *buf __attribute__((unused)))
unknown's avatar
unknown committed
4995 4996
{
  long stack_used;
4997
  DBUG_ASSERT(thd == current_thd);
unknown's avatar
unknown committed
4998
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
unknown's avatar
unknown committed
4999
      (long) (thread_stack - margin))
unknown's avatar
unknown committed
5000
  {
5001 5002 5003
    sprintf(errbuff[0],ER(ER_STACK_OVERRUN_NEED_MORE),
            stack_used,thread_stack,margin);
    my_message(ER_STACK_OVERRUN_NEED_MORE,errbuff[0],MYF(0));
5004
    thd->fatal_error();
unknown's avatar
unknown committed
5005 5006
    return 1;
  }
unknown's avatar
unknown committed
5007 5008 5009
#ifndef DBUG_OFF
  max_stack_used= max(max_stack_used, stack_used);
#endif
unknown's avatar
unknown committed
5010 5011
  return 0;
}
5012
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
5013 5014 5015 5016

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

5017
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
unknown's avatar
unknown committed
5018
{
5019
  LEX	*lex= current_thd->lex;
5020
  ulong old_info=0;
unknown's avatar
unknown committed
5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046
  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;
}


/****************************************************************************
5047
  Initialize global thd variables needed for query
unknown's avatar
unknown committed
5048 5049
****************************************************************************/

5050
void
5051
mysql_init_query(THD *thd, const char *buf, uint length)
unknown's avatar
unknown committed
5052 5053
{
  DBUG_ENTER("mysql_init_query");
unknown's avatar
unknown committed
5054
  lex_start(thd, buf, length);
5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065
  mysql_reset_thd_for_next_command(thd);
  DBUG_VOID_RETURN;
}


/*
 Reset THD part responsible for command processing state.

 DESCRIPTION
   This needs to be called before execution of every statement
   (prepared or conventional).
5066
   It is not called by substatements of routines.
5067 5068 5069 5070 5071 5072 5073 5074 5075 5076

 TODO
   Make it a method of THD and align its name with the rest of
   reset/end/start/init methods.
   Call it after we use THD for queries, not before.
*/

void mysql_reset_thd_for_next_command(THD *thd)
{
  DBUG_ENTER("mysql_reset_thd_for_next_command");
5077
  DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
5078
  thd->free_list= 0;
5079
  thd->select_number= 1;
5080 5081 5082 5083
  /*
    Those two lines below are theoretically unneeded as
    THD::cleanup_after_query() should take care of this already.
  */
5084
  thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty();
5085 5086 5087
  thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;

  thd->query_start_used= 0;
5088
  thd->is_fatal_error= thd->time_zone_used= 0;
unknown's avatar
unknown committed
5089
  thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | 
unknown's avatar
unknown committed
5090 5091
                          SERVER_QUERY_NO_INDEX_USED |
                          SERVER_QUERY_NO_GOOD_INDEX_USED);
5092 5093 5094 5095 5096 5097
  /*
    If in autocommit mode and not in a transaction, reset
    OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG to not get warnings
    in ha_rollback_trans() about some tables couldn't be rolled back.
  */
  if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
unknown's avatar
unknown committed
5098 5099 5100 5101
  {
    thd->options&= ~OPTION_KEEP_LOG;
    thd->no_trans_update.all= FALSE;
  }
5102
  DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
unknown's avatar
unknown committed
5103
  thd->tmp_table_used= 0;
5104 5105
  if (!thd->in_sub_stmt)
  {
5106
    if (opt_bin_log)
5107
    {
5108
      reset_dynamic(&thd->user_var_events);
5109 5110
      thd->user_var_events_alloc= thd->mem_root;
    }
5111
    thd->clear_error();
5112 5113 5114 5115
    thd->total_warn_count=0;			// Warnings for this query
    thd->rand_used= 0;
    thd->sent_row_count= thd->examined_row_count= 0;
  }
5116 5117 5118 5119
  /*
    Because we come here only for start of top-statements, binlog format is
    constant inside a complex statement (using stored functions) etc.
  */
unknown's avatar
unknown committed
5120 5121
  thd->reset_current_stmt_binlog_row_based();

unknown's avatar
unknown committed
5122 5123 5124
  DBUG_VOID_RETURN;
}

5125

5126 5127 5128
void
mysql_init_select(LEX *lex)
{
unknown's avatar
unknown committed
5129
  SELECT_LEX *select_lex= lex->current_select;
unknown's avatar
unknown committed
5130
  select_lex->init_select();
5131
  lex->wild= 0;
5132 5133
  if (select_lex == &lex->select_lex)
  {
5134
    DBUG_ASSERT(lex->result == 0);
5135 5136
    lex->exchange= 0;
  }
5137 5138
}

5139

unknown's avatar
unknown committed
5140
bool
unknown's avatar
unknown committed
5141
mysql_new_select(LEX *lex, bool move_down)
5142
{
unknown's avatar
unknown committed
5143
  SELECT_LEX *select_lex;
5144
  THD *thd= lex->thd;
unknown's avatar
unknown committed
5145 5146
  DBUG_ENTER("mysql_new_select");

5147
  if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
5148
    DBUG_RETURN(1);
5149
  select_lex->select_number= ++thd->select_number;
unknown's avatar
unknown committed
5150
  select_lex->parent_lex= lex; /* Used in init_query. */
unknown's avatar
unknown committed
5151 5152
  select_lex->init_query();
  select_lex->init_select();
unknown's avatar
unknown committed
5153 5154
  lex->nest_level++;
  select_lex->nest_level= lex->nest_level;
5155 5156 5157 5158 5159
  /*
    Don't evaluate this subquery during statement prepare even if
    it's a constant one. The flag is switched off in the end of
    mysql_stmt_prepare.
  */
unknown's avatar
unknown committed
5160
  if (thd->stmt_arena->is_stmt_prepare())
5161
    select_lex->uncacheable|= UNCACHEABLE_PREPARE;
unknown's avatar
unknown committed
5162 5163
  if (move_down)
  {
unknown's avatar
unknown committed
5164
    SELECT_LEX_UNIT *unit;
5165
    lex->subqueries= TRUE;
unknown's avatar
unknown committed
5166
    /* first select_lex of subselect or derived table */
5167
    if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
unknown's avatar
unknown committed
5168
      DBUG_RETURN(1);
unknown's avatar
unknown committed
5169

unknown's avatar
unknown committed
5170 5171
    unit->init_query();
    unit->init_select();
5172
    unit->thd= thd;
unknown's avatar
unknown committed
5173
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
5174 5175
    unit->link_next= 0;
    unit->link_prev= 0;
5176
    unit->return_to= lex->current_select;
unknown's avatar
unknown committed
5177
    select_lex->include_down(unit);
5178 5179 5180 5181 5182
    /*
      By default we assume that it is usual subselect and we have outer name
      resolution context, if no we will assign it to 0 later
    */
    select_lex->context.outer_context= &select_lex->outer_select()->context;
unknown's avatar
unknown committed
5183 5184
  }
  else
unknown's avatar
unknown committed
5185
  {
unknown's avatar
VIEW  
unknown committed
5186 5187
    if (lex->current_select->order_list.first && !lex->current_select->braces)
    {
unknown's avatar
unknown committed
5188
      my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
unknown's avatar
unknown committed
5189
      DBUG_RETURN(1);
unknown's avatar
VIEW  
unknown committed
5190
    }
5191
    select_lex->include_neighbour(lex->current_select);
5192 5193 5194 5195 5196
    SELECT_LEX_UNIT *unit= select_lex->master_unit();                              
    if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->thd))
      DBUG_RETURN(1);
    select_lex->context.outer_context= 
                unit->first_select()->context.outer_context;
unknown's avatar
unknown committed
5197
  }
unknown's avatar
unknown committed
5198

5199
  select_lex->master_unit()->global_parameters= select_lex;
5200
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
5201
  lex->current_select= select_lex;
5202 5203 5204 5205 5206
  /*
    in subquery is SELECT query and we allow resolution of names in SELECT
    list
  */
  select_lex->context.resolve_in_select_list= TRUE;
unknown's avatar
unknown committed
5207
  DBUG_RETURN(0);
5208
}
unknown's avatar
unknown committed
5209

5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224
/*
  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)
{
5225
  THD *thd;
5226
  LEX *lex;
5227
  LEX_STRING tmp, null_lex_string;
5228 5229
  Item *var;
  char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end;
5230
  DBUG_ENTER("create_select_for_variable");
5231 5232

  thd= current_thd;
unknown's avatar
unknown committed
5233
  lex= thd->lex;
5234 5235 5236 5237
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
5238
  bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
5239 5240 5241 5242
  /*
    We set the name of Item to @@session.var_name because that then is used
    as the column name in the output.
  */
unknown's avatar
unknown committed
5243 5244 5245 5246 5247 5248
  if ((var= get_system_var(thd, OPT_SESSION, tmp, null_lex_string)))
  {
    end= strxmov(buff, "@@session.", var_name, NullS);
    var->set_name(buff, end-buff, system_charset_info);
    add_item_to_list(thd, var);
  }
5249 5250 5251
  DBUG_VOID_RETURN;
}

5252

unknown's avatar
unknown committed
5253 5254
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
5255
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
5256
  mysql_init_select(lex);
5257 5258
  lex->select_lex.select_limit= 0;
  lex->unit.select_limit_cnt= HA_POS_ERROR;
unknown's avatar
unknown committed
5259
  lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list);
5260
  lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
unknown's avatar
VIEW  
unknown committed
5261 5262
  lex->query_tables= 0;
  lex->query_tables_last= &lex->query_tables;
unknown's avatar
unknown committed
5263
}
unknown's avatar
unknown committed
5264

5265

5266 5267 5268 5269
/*
  When you modify mysql_parse(), you may need to mofify
  mysql_test_parse_for_slave() in this same file.
*/
unknown's avatar
unknown committed
5270

5271
void mysql_parse(THD *thd, char *inBuf, uint length)
unknown's avatar
unknown committed
5272 5273
{
  DBUG_ENTER("mysql_parse");
5274 5275 5276

  DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););

5277
  mysql_init_query(thd, inBuf, length);
5278

unknown's avatar
unknown committed
5279
  if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
unknown's avatar
unknown committed
5280
  {
unknown's avatar
unknown committed
5281
    LEX *lex= thd->lex;
5282
    
5283 5284
    sp_cache_flush_obsolete(&thd->sp_proc_cache);
    sp_cache_flush_obsolete(&thd->sp_func_cache);
5285
    
5286
    if (!MYSQLparse((void *)thd) && ! thd->is_fatal_error)
unknown's avatar
unknown committed
5287
    {
unknown's avatar
unknown committed
5288
#ifndef NO_EMBEDDED_ACCESS_CHECKS
5289
      if (mqh_used && thd->user_connect &&
5290
	  check_mqh(thd, lex->sql_command))
5291 5292 5293 5294
      {
	thd->net.error = 0;
      }
      else
unknown's avatar
unknown committed
5295
#endif
5296
      {
5297
	if (! thd->net.report_error)
unknown's avatar
unknown committed
5298
	{
5299 5300 5301 5302 5303 5304 5305 5306 5307 5308
          /*
            Binlog logs a string starting from thd->query and having length
            thd->query_length; so we set thd->query_length correctly (to not
            log several statements in one event, when we executed only first).
            We set it to not see the ';' (otherwise it would get into binlog
            and Query_log_event::print() would give ';;' output).
            This also helps display only the current query in SHOW
            PROCESSLIST.
            Note that we don't need LOCK_thread_count to modify query_length.
          */
unknown's avatar
unknown committed
5309 5310
          if (lex->found_semicolon &&
              (thd->query_length= (ulong)(lex->found_semicolon - thd->query)))
5311 5312
            thd->query_length--;
          /* Actually execute the query */
unknown's avatar
unknown committed
5313
	  mysql_execute_command(thd);
unknown's avatar
SCRUM  
unknown committed
5314
	  query_cache_end_of_result(thd);
unknown's avatar
unknown committed
5315
	}
5316
      }
unknown's avatar
unknown committed
5317 5318
    }
    else
5319
    {
5320
      DBUG_ASSERT(thd->net.report_error);
5321
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
5322
			 thd->is_fatal_error));
5323 5324

      query_cache_abort(&thd->net);
5325
    }
5326 5327 5328 5329 5330 5331
    if (thd->lex->sphead)
    {
      delete thd->lex->sphead;
      thd->lex->sphead= 0;
    }
    lex->unit.cleanup();
unknown's avatar
unknown committed
5332
    thd->proc_info="freeing items";
5333
    thd->end_statement();
5334
    thd->cleanup_after_query();
5335
    DBUG_ASSERT(thd->change_list.is_empty());
unknown's avatar
unknown committed
5336
  }
unknown's avatar
unknown committed
5337 5338 5339 5340
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
5341
#ifdef HAVE_REPLICATION
5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352
/*
  Usable by the replication SQL thread only: just parse a query to know if it
  can be ignored because of replicate-*-table rules.

  RETURN VALUES
    0	cannot be ignored
    1	can be ignored
*/

bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
{
unknown's avatar
unknown committed
5353
  LEX *lex= thd->lex;
5354
  bool error= 0;
unknown's avatar
unknown committed
5355
  DBUG_ENTER("mysql_test_parse_for_slave");
5356

5357
  mysql_init_query(thd, inBuf, length);
5358
  if (!MYSQLparse((void*) thd) && ! thd->is_fatal_error &&
5359
      all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
unknown's avatar
unknown committed
5360
    error= 1;                  /* Ignore question */
5361
  thd->end_statement();
5362
  thd->cleanup_after_query();
unknown's avatar
unknown committed
5363
  DBUG_RETURN(error);
5364
}
unknown's avatar
unknown committed
5365
#endif
unknown's avatar
unknown committed
5366

5367

unknown's avatar
unknown committed
5368

unknown's avatar
unknown committed
5369 5370 5371 5372 5373
/*****************************************************************************
** Store field definition for create
** Return 0 if ok
******************************************************************************/

5374
bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
unknown's avatar
unknown committed
5375
		       char *length, char *decimals,
5376
		       uint type_modifier,
5377 5378
		       Item *default_value, Item *on_update_value,
                       LEX_STRING *comment,
5379 5380
		       char *change,
                       List<String> *interval_list, CHARSET_INFO *cs,
unknown's avatar
unknown committed
5381
		       uint uint_geom_type)
unknown's avatar
unknown committed
5382 5383
{
  register create_field *new_field;
unknown's avatar
unknown committed
5384
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
5385 5386
  DBUG_ENTER("add_field_to_list");

5387 5388
  if (check_string_char_length(field_name, "", NAME_CHAR_LEN,
                               system_charset_info, 1))
unknown's avatar
unknown committed
5389
  {
5390
    my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */
unknown's avatar
unknown committed
5391 5392 5393 5394
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
5395
    lex->col_list.push_back(new key_part_spec(field_name->str, 0));
5396 5397
    lex->key_list.push_back(new Key(Key::PRIMARY, NullS,
                                    &default_key_create_info,
5398
				    0, lex->col_list));
unknown's avatar
unknown committed
5399 5400 5401 5402
    lex->col_list.empty();
  }
  if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
  {
5403
    lex->col_list.push_back(new key_part_spec(field_name->str, 0));
5404 5405
    lex->key_list.push_back(new Key(Key::UNIQUE, NullS,
                                    &default_key_create_info, 0,
unknown's avatar
unknown committed
5406 5407 5408 5409
				    lex->col_list));
    lex->col_list.empty();
  }

5410
  if (default_value)
unknown's avatar
unknown committed
5411
  {
5412
    /* 
unknown's avatar
unknown committed
5413 5414
      Default value should be literal => basic constants =>
      no need fix_fields()
5415 5416 5417
      
      We allow only one function as part of default value - 
      NOW() as default for TIMESTAMP type.
5418
    */
5419 5420
    if (default_value->type() == Item::FUNC_ITEM && 
        !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
5421
         type == MYSQL_TYPE_TIMESTAMP))
5422
    {
5423
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5424 5425 5426
      DBUG_RETURN(1);
    }
    else if (default_value->type() == Item::NULL_ITEM)
unknown's avatar
unknown committed
5427
    {
5428
      default_value= 0;
5429 5430 5431
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
5432
	my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5433 5434 5435 5436 5437
	DBUG_RETURN(1);
      }
    }
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
5438
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
unknown's avatar
unknown committed
5439 5440 5441
      DBUG_RETURN(1);
    }
  }
5442

5443
  if (on_update_value && type != MYSQL_TYPE_TIMESTAMP)
5444
  {
5445
    my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
5446 5447
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
5448

5449
  if (type == MYSQL_TYPE_TIMESTAMP && length)
5450 5451 5452 5453 5454
  {
    /* Display widths are no longer supported for TIMSTAMP as of MySQL 4.1.
       In other words, for declarations such as TIMESTAMP(2), TIMESTAMP(4),
       and so on, the display width is ignored.
    */
unknown's avatar
unknown committed
5455
    char buf[32];
5456
    my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length);
unknown's avatar
unknown committed
5457
    WARN_DEPRECATED(thd, "5.2", buf, "'TIMESTAMP'");
5458 5459
  }

5460
  if (!(new_field= new create_field()) ||
5461
      new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
5462 5463
                      default_value, on_update_value, comment, change,
                      interval_list, cs, uint_geom_type))
unknown's avatar
unknown committed
5464
    DBUG_RETURN(1);
unknown's avatar
unknown committed
5465 5466 5467 5468 5469 5470

  lex->create_list.push_back(new_field);
  lex->last_field=new_field;
  DBUG_RETURN(0);
}

5471

unknown's avatar
unknown committed
5472 5473 5474 5475
/* Store position for column in ALTER TABLE .. ADD column */

void store_position_for_column(const char *name)
{
5476
  current_thd->lex->last_field->after=my_const_cast(char*) (name);
unknown's avatar
unknown committed
5477 5478 5479
}

bool
unknown's avatar
unknown committed
5480
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
5481 5482 5483 5484
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
5485
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
5486 5487 5488 5489 5490
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
unknown's avatar
unknown committed
5491
  thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
5492 5493 5494 5495 5496 5497 5498 5499 5500
  return 0;
}


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


unknown's avatar
unknown committed
5501
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
5502 5503 5504
{
  ORDER *order;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
5505
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER))))
unknown's avatar
unknown committed
5506
    DBUG_RETURN(1);
unknown's avatar
unknown committed
5507 5508
  order->item_ptr= item;
  order->item= &order->item_ptr;
unknown's avatar
unknown committed
5509 5510 5511
  order->asc = asc;
  order->free_me=0;
  order->used=0;
5512
  order->counter_used= 0;
unknown's avatar
unknown committed
5513
  list.link_in_list((byte*) order,(byte**) &order->next);
unknown's avatar
unknown committed
5514 5515 5516 5517
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
5518 5519 5520 5521 5522 5523 5524 5525 5526 5527
/*
  Add a table to list of used tables

  SYNOPSIS
    add_table_to_list()
    table		Table to add
    alias		alias for table (or null if no alias)
    table_options	A set of the following bits:
			TL_OPTION_UPDATING	Table will be updated
			TL_OPTION_FORCE_INDEX	Force usage of index
5528
			TL_OPTION_ALIAS	        an alias in multi table DELETE
unknown's avatar
unknown committed
5529 5530 5531 5532 5533 5534 5535 5536 5537
    lock_type		How table should be locked
    use_index		List of indexed used in USE INDEX
    ignore_index	List of indexed used in IGNORE INDEX

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

unknown's avatar
unknown committed
5538 5539
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
5540
					     LEX_STRING *alias,
unknown's avatar
unknown committed
5541 5542
					     ulong table_options,
					     thr_lock_type lock_type,
5543
					     List<index_hint> *index_hints_arg,
unknown's avatar
unknown committed
5544
                                             LEX_STRING *option)
unknown's avatar
unknown committed
5545 5546
{
  register TABLE_LIST *ptr;
unknown's avatar
unknown committed
5547
  TABLE_LIST *previous_table_ref; /* The table preceding the current one. */
unknown's avatar
unknown committed
5548
  char *alias_str;
5549
  LEX *lex= thd->lex;
unknown's avatar
unknown committed
5550
  DBUG_ENTER("add_table_to_list");
5551
  LINT_INIT(previous_table_ref);
unknown's avatar
unknown committed
5552 5553 5554 5555

  if (!table)
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? alias->str : table->table.str;
5556 5557
  if (!test(table_options & TL_OPTION_ALIAS) && 
      check_table_name(table->table.str, table->table.length))
unknown's avatar
unknown committed
5558
  {
5559
    my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
unknown's avatar
unknown committed
5560 5561
    DBUG_RETURN(0);
  }
unknown's avatar
unknown committed
5562 5563

  if (table->is_derived_table() == FALSE && table->db.str &&
5564
      check_db_name(&table->db))
unknown's avatar
unknown committed
5565 5566 5567 5568
  {
    my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str);
    DBUG_RETURN(0);
  }
unknown's avatar
unknown committed
5569 5570

  if (!alias)					/* Alias is case sensitive */
5571 5572 5573
  {
    if (table->sel)
    {
unknown's avatar
unknown committed
5574 5575
      my_message(ER_DERIVED_MUST_HAVE_ALIAS,
                 ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
5576 5577
      DBUG_RETURN(0);
    }
5578
    if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
5579
      DBUG_RETURN(0);
5580
  }
unknown's avatar
unknown committed
5581
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
5582
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
5583
  if (table->db.str)
5584 5585 5586 5587
  {
    ptr->db= table->db.str;
    ptr->db_length= table->db.length;
  }
unknown's avatar
unknown committed
5588 5589
  else if (thd->copy_db_to(&ptr->db, &ptr->db_length))
    DBUG_RETURN(0);
unknown's avatar
unknown committed
5590

5591
  ptr->alias= alias_str;
5592
  if (lower_case_table_names && table->table.length)
5593
    table->table.length= my_casedn_str(files_charset_info, table->table.str);
5594 5595
  ptr->table_name=table->table.str;
  ptr->table_name_length=table->table.length;
5596
  ptr->lock_type=   lock_type;
unknown's avatar
unknown committed
5597 5598
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
5599
  ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
5600
  ptr->derived=	    table->sel;
5601
  if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db,
5602
                                      INFORMATION_SCHEMA_NAME.str))
5603
  {
5604
    ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
5605 5606
    if (!schema_table ||
        (schema_table->hidden && 
5607
         (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0))
5608
    {
unknown's avatar
unknown committed
5609
      my_error(ER_UNKNOWN_TABLE, MYF(0),
5610
               ptr->table_name, INFORMATION_SCHEMA_NAME.str);
5611 5612
      DBUG_RETURN(0);
    }
5613
    ptr->schema_table_name= ptr->table_name;
5614 5615
    ptr->schema_table= schema_table;
  }
5616
  ptr->select_lex=  lex->current_select;
unknown's avatar
unknown committed
5617
  ptr->cacheable_table= 1;
5618
  ptr->index_hints= index_hints_arg;
unknown's avatar
unknown committed
5619
  ptr->option= option ? option->str : 0;
unknown's avatar
unknown committed
5620
  /* check that used name is unique */
5621
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
5622
  {
unknown's avatar
unknown committed
5623 5624 5625 5626
    TABLE_LIST *first_table= (TABLE_LIST*) table_list.first;
    if (lex->sql_command == SQLCOM_CREATE_VIEW)
      first_table= first_table ? first_table->next_local : NULL;
    for (TABLE_LIST *tables= first_table ;
unknown's avatar
unknown committed
5627
	 tables ;
unknown's avatar
VIEW  
unknown committed
5628
	 tables=tables->next_local)
unknown's avatar
unknown committed
5629
    {
5630 5631
      if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
	  !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
5632
      {
5633
	my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
unknown's avatar
unknown committed
5634 5635
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
5636 5637
    }
  }
unknown's avatar
unknown committed
5638 5639 5640
  /* Store the table reference preceding the current one. */
  if (table_list.elements > 0)
  {
5641 5642 5643
    /*
      table_list.next points to the last inserted TABLE_LIST->next_local'
      element
5644
      We don't use the offsetof() macro here to avoid warnings from gcc
5645
    */
5646 5647 5648
    previous_table_ref= (TABLE_LIST*) ((char*) table_list.next -
                                       ((char*) &(ptr->next_local) -
                                        (char*) ptr));
5649 5650 5651 5652 5653 5654 5655 5656
    /*
      Set next_name_resolution_table of the previous table reference to point
      to the current table reference. In effect the list
      TABLE_LIST::next_name_resolution_table coincides with
      TABLE_LIST::next_local. Later this may be changed in
      store_top_level_join_columns() for NATURAL/USING joins.
    */
    previous_table_ref->next_name_resolution_table= ptr;
unknown's avatar
unknown committed
5657
  }
5658

unknown's avatar
unknown committed
5659 5660 5661 5662 5663 5664
  /*
    Link the current table reference in a local list (list for current select).
    Notice that as a side effect here we set the next_local field of the
    previous table reference to 'ptr'. Here we also add one element to the
    list 'table_list'.
  */
unknown's avatar
VIEW  
unknown committed
5665
  table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
unknown's avatar
unknown committed
5666
  ptr->next_name_resolution_table= NULL;
5667
  /* Link table in global list (all used tables) */
5668
  lex->add_to_query_tables(ptr);
unknown's avatar
unknown committed
5669 5670 5671
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
5672

5673 5674 5675 5676
/*
  Initialize a new table list for a nested join

  SYNOPSIS
unknown's avatar
unknown committed
5677
    init_nested_join()
5678
    thd         current thread
5679

5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698
  DESCRIPTION
    The function initializes a structure of the TABLE_LIST type
    for a nested join. It sets up its nested join list as empty.
    The created structure is added to the front of the current
    join list in the st_select_lex object. Then the function
    changes the current nest level for joins to refer to the newly
    created empty list after having saved the info on the old level
    in the initialized structure.

  RETURN VALUE
    0,  if success
    1,  otherwise
*/

bool st_select_lex::init_nested_join(THD *thd)
{
  TABLE_LIST *ptr;
  NESTED_JOIN *nested_join;
  DBUG_ENTER("init_nested_join");
5699

5700 5701
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
5702
    DBUG_RETURN(1);
5703 5704 5705
  nested_join= ptr->nested_join=
    ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));

5706 5707 5708
  join_list->push_front(ptr);
  ptr->embedding= embedding;
  ptr->join_list= join_list;
5709
  ptr->alias= (char*) "(nested_join)";
5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726
  embedding= ptr;
  join_list= &nested_join->join_list;
  join_list->empty();
  DBUG_RETURN(0);
}


/*
  End a nested join table list

  SYNOPSIS
    end_nested_join()
    thd         current thread

  DESCRIPTION
    The function returns to the previous join nest level.
    If the current level contains only one member, the function
5727
    moves it one level up, eliminating the nest.
5728 5729 5730 5731 5732 5733 5734 5735 5736

  RETURN VALUE
    Pointer to TABLE_LIST element added to the total table list, if success
    0, otherwise
*/

TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
{
  TABLE_LIST *ptr;
5737
  NESTED_JOIN *nested_join;
5738
  DBUG_ENTER("end_nested_join");
5739

unknown's avatar
unknown committed
5740
  DBUG_ASSERT(embedding);
5741 5742 5743
  ptr= embedding;
  join_list= ptr->join_list;
  embedding= ptr->embedding;
5744
  nested_join= ptr->nested_join;
5745 5746 5747 5748 5749 5750 5751 5752 5753
  if (nested_join->join_list.elements == 1)
  {
    TABLE_LIST *embedded= nested_join->join_list.head();
    join_list->pop();
    embedded->join_list= join_list;
    embedded->embedding= embedding;
    join_list->push_front(embedded);
    ptr= embedded;
  }
5754
  else if (nested_join->join_list.elements == 0)
unknown's avatar
unknown committed
5755 5756
  {
    join_list->pop();
5757
    ptr= 0;                                     // return value
unknown's avatar
unknown committed
5758
  }
5759 5760 5761 5762 5763 5764 5765 5766
  DBUG_RETURN(ptr);
}


/*
  Nest last join operation

  SYNOPSIS
5767
    nest_last_join()
5768 5769 5770 5771 5772 5773
    thd         current thread

  DESCRIPTION
    The function nest last join operation as if it was enclosed in braces.

  RETURN VALUE
5774 5775 5776
    0  Error
    #  Pointer to TABLE_LIST element created for the new nested join

5777 5778 5779 5780 5781 5782
*/

TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
{
  TABLE_LIST *ptr;
  NESTED_JOIN *nested_join;
5783
  List<TABLE_LIST> *embedded_list;
5784
  DBUG_ENTER("nest_last_join");
5785

5786 5787
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
5788
    DBUG_RETURN(0);
5789 5790 5791
  nested_join= ptr->nested_join=
    ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));

5792 5793
  ptr->embedding= embedding;
  ptr->join_list= join_list;
5794
  ptr->alias= (char*) "(nest_last_join)";
5795
  embedded_list= &nested_join->join_list;
5796
  embedded_list->empty();
5797 5798

  for (uint i=0; i < 2; i++)
5799 5800 5801 5802 5803
  {
    TABLE_LIST *table= join_list->pop();
    table->join_list= embedded_list;
    table->embedding= ptr;
    embedded_list->push_back(table);
unknown's avatar
unknown committed
5804 5805 5806 5807 5808 5809 5810
    if (table->natural_join)
    {
      ptr->is_natural_join= TRUE;
      /*
        If this is a JOIN ... USING, move the list of joined fields to the
        table reference that describes the join.
      */
unknown's avatar
unknown committed
5811 5812
      if (prev_join_using)
        ptr->join_using_fields= prev_join_using;
unknown's avatar
unknown committed
5813
    }
5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853
  }
  join_list->push_front(ptr);
  nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
  DBUG_RETURN(ptr);
}


/*
  Add a table to the current join list

  SYNOPSIS
    add_joined_table()
    table       the table to add

  DESCRIPTION
    The function puts a table in front of the current join list
    of st_select_lex object.
    Thus, joined tables are put into this list in the reverse order
    (the most outer join operation follows first).

  RETURN VALUE
    None
*/

void st_select_lex::add_joined_table(TABLE_LIST *table)
{
  DBUG_ENTER("add_joined_table");
  join_list->push_front(table);
  table->join_list= join_list;
  table->embedding= embedding;
  DBUG_VOID_RETURN;
}


/*
  Convert a right join into equivalent left join

  SYNOPSIS
    convert_right_join()
    thd         current thread
5854 5855 5856

  DESCRIPTION
    The function takes the current join list t[0],t[1] ... and
5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879
    effectively converts it into the list t[1],t[0] ...
    Although the outer_join flag for the new nested table contains
    JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
    operation.

  EXAMPLES
    SELECT * FROM t1 RIGHT JOIN t2 ON on_expr =>
      SELECT * FROM t2 LEFT JOIN t1 ON on_expr

    SELECT * FROM t1,t2 RIGHT JOIN t3 ON on_expr =>
      SELECT * FROM t1,t3 LEFT JOIN t2 ON on_expr

    SELECT * FROM t1,t2 RIGHT JOIN (t3,t4) ON on_expr =>
      SELECT * FROM t1,(t3,t4) LEFT JOIN t2 ON on_expr

    SELECT * FROM t1 LEFT JOIN t2 ON on_expr1 RIGHT JOIN t3  ON on_expr2 =>
      SELECT * FROM t3 LEFT JOIN (t1 LEFT JOIN t2 ON on_expr2) ON on_expr1

  RETURN
    Pointer to the table representing the inner table, if success
    0, otherwise
*/

5880
TABLE_LIST *st_select_lex::convert_right_join()
5881 5882
{
  TABLE_LIST *tab2= join_list->pop();
5883
  TABLE_LIST *tab1= join_list->pop();
5884 5885 5886 5887 5888 5889 5890 5891 5892
  DBUG_ENTER("convert_right_join");

  join_list->push_front(tab2);
  join_list->push_front(tab1);
  tab1->outer_join|= JOIN_TYPE_RIGHT;

  DBUG_RETURN(tab1);
}

unknown's avatar
unknown committed
5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905
/*
  Set lock for all tables in current select level

  SYNOPSIS:
    set_lock_for_tables()
    lock_type			Lock to set for tables

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

unknown's avatar
unknown committed
5906
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
5907 5908 5909 5910 5911 5912
{
  bool for_update= lock_type >= TL_READ_NO_INSERT;
  DBUG_ENTER("set_lock_for_tables");
  DBUG_PRINT("enter", ("lock_type: %d  for_update: %d", lock_type,
		       for_update));

unknown's avatar
VIEW  
unknown committed
5913 5914 5915
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first;
       tables;
       tables= tables->next_local)
unknown's avatar
unknown committed
5916 5917 5918 5919 5920 5921 5922
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
5923

unknown's avatar
unknown committed
5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947
/*
  Create a fake SELECT_LEX for a unit

  SYNOPSIS:
    add_fake_select_lex()
    thd			   thread handle

  DESCRIPTION
    The method create a fake SELECT_LEX object for a unit.
    This object is created for any union construct containing a union
    operation and also for any single select union construct of the form
    (SELECT ... ORDER BY order_list [LIMIT n]) ORDER BY ... 
    or of the form
    (SELECT ... ORDER BY LIMIT n) ORDER BY ...
  
  NOTES
    The object is used to retrieve rows from the temporary table
    where the result on the union is obtained.

  RETURN VALUES
    1     on failure to create the object
    0     on success
*/

unknown's avatar
unknown committed
5948
bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
unknown's avatar
unknown committed
5949 5950 5951 5952
{
  SELECT_LEX *first_sl= first_select();
  DBUG_ENTER("add_fake_select_lex");
  DBUG_ASSERT(!fake_select_lex);
unknown's avatar
unknown committed
5953

unknown's avatar
unknown committed
5954
  if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
5955 5956 5957 5958
      DBUG_RETURN(1);
  fake_select_lex->include_standalone(this, 
                                      (SELECT_LEX_NODE**)&fake_select_lex);
  fake_select_lex->select_number= INT_MAX;
unknown's avatar
unknown committed
5959
  fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */
unknown's avatar
unknown committed
5960 5961
  fake_select_lex->make_empty_select();
  fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
5962 5963
  fake_select_lex->select_limit= 0;

unknown's avatar
unknown committed
5964
  fake_select_lex->context.outer_context=first_sl->context.outer_context;
5965 5966 5967
  /* allow item list resolving in fake select for ORDER BY */
  fake_select_lex->context.resolve_in_select_list= TRUE;
  fake_select_lex->context.select_lex= fake_select_lex;
unknown's avatar
unknown committed
5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978

  if (!first_sl->next_select())
  {
    /* 
      This works only for 
      (SELECT ... ORDER BY list [LIMIT n]) ORDER BY order_list [LIMIT m],
      (SELECT ... LIMIT n) ORDER BY order_list [LIMIT m]
      just before the parser starts processing order_list
    */ 
    global_parameters= fake_select_lex;
    fake_select_lex->no_table_names_allowed= 1;
unknown's avatar
unknown committed
5979
    thd_arg->lex->current_select= fake_select_lex;
unknown's avatar
unknown committed
5980
  }
unknown's avatar
unknown committed
5981
  thd_arg->lex->pop_context();
unknown's avatar
unknown committed
5982 5983 5984
  DBUG_RETURN(0);
}

5985

unknown's avatar
unknown committed
5986
/*
5987 5988
  Push a new name resolution context for a JOIN ... ON clause to the
  context stack of a query block.
unknown's avatar
unknown committed
5989 5990

  SYNOPSIS
5991
    push_new_name_resolution_context()
unknown's avatar
unknown committed
5992
    thd       pointer to current thread
unknown's avatar
unknown committed
5993
    left_op   left  operand of the JOIN
unknown's avatar
unknown committed
5994 5995 5996 5997
    right_op  rigth operand of the JOIN

  DESCRIPTION
    Create a new name resolution context for a JOIN ... ON clause,
5998 5999 6000
    set the first and last leaves of the list of table references
    to be used for name resolution, and push the newly created
    context to the stack of contexts of the query.
unknown's avatar
unknown committed
6001 6002

  RETURN
6003 6004
    FALSE  if all is OK
    TRUE   if a memory allocation error occured
unknown's avatar
unknown committed
6005 6006
*/

6007 6008 6009
bool
push_new_name_resolution_context(THD *thd,
                                 TABLE_LIST *left_op, TABLE_LIST *right_op)
unknown's avatar
unknown committed
6010 6011
{
  Name_resolution_context *on_context;
6012
  if (!(on_context= new (thd->mem_root) Name_resolution_context))
6013
    return TRUE;
unknown's avatar
unknown committed
6014 6015 6016 6017 6018
  on_context->init();
  on_context->first_name_resolution_table=
    left_op->first_leaf_for_name_resolution();
  on_context->last_name_resolution_table=
    right_op->last_leaf_for_name_resolution();
6019
  return thd->lex->push_context(on_context);
unknown's avatar
unknown committed
6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039
}


/*
  Add an ON condition to the second operand of a JOIN ... ON.

  SYNOPSIS
    add_join_on
    b     the second operand of a JOIN ... ON
    expr  the condition to be added to the ON clause

  DESCRIPTION
    Add an ON condition to the right operand of a JOIN ... ON clause.

  RETURN
    FALSE  if there was some error
    TRUE   if all is OK
*/

void add_join_on(TABLE_LIST *b, Item *expr)
unknown's avatar
unknown committed
6040
{
6041
  if (expr)
6042
  {
6043
    if (!b->on_expr)
unknown's avatar
unknown committed
6044
      b->on_expr= expr;
6045 6046
    else
    {
unknown's avatar
unknown committed
6047 6048 6049 6050 6051 6052
      /*
        If called from the parser, this happens if you have both a
        right and left join. If called later, it happens if we add more
        than one condition to the ON clause.
      */
      b->on_expr= new Item_cond_and(b->on_expr,expr);
6053 6054
    }
    b->on_expr->top_level_item();
6055
  }
unknown's avatar
unknown committed
6056 6057 6058
}


6059
/*
unknown's avatar
unknown committed
6060 6061
  Mark that there is a NATURAL JOIN or JOIN ... USING between two
  tables.
6062 6063 6064

  SYNOPSIS
    add_join_natural()
unknown's avatar
unknown committed
6065 6066 6067
    a			Left join argument
    b			Right join argument
    using_fields        Field names from USING clause
unknown's avatar
unknown committed
6068
    lex                 The current st_select_lex
unknown's avatar
unknown committed
6069
  
6070
  IMPLEMENTATION
unknown's avatar
unknown committed
6071 6072 6073 6074 6075 6076 6077 6078 6079 6080
    This function marks that table b should be joined with a either via
    a NATURAL JOIN or via JOIN ... USING. Both join types are special
    cases of each other, so we treat them together. The function
    setup_conds() creates a list of equal condition between all fields
    of the same name for NATURAL JOIN or the fields in 'using_fields'
    for JOIN ... USING. The list of equality conditions is stored
    either in b->on_expr, or in JOIN::conds, depending on whether there
    was an outer join.

  EXAMPLE
6081 6082 6083
    SELECT * FROM t1 NATURAL LEFT JOIN t2
     <=>
    SELECT * FROM t1 LEFT JOIN t2 ON (t1.i=t2.i and t1.j=t2.j ... )
unknown's avatar
unknown committed
6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094

    SELECT * FROM t1 NATURAL JOIN t2 WHERE <some_cond>
     <=>
    SELECT * FROM t1, t2 WHERE (t1.i=t2.i and t1.j=t2.j and <some_cond>)

    SELECT * FROM t1 JOIN t2 USING(j) WHERE <some_cond>
     <=>
    SELECT * FROM t1, t2 WHERE (t1.j=t2.j and <some_cond>)

  RETURN
    None
6095 6096
*/

unknown's avatar
unknown committed
6097 6098
void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
                      SELECT_LEX *lex)
unknown's avatar
unknown committed
6099
{
unknown's avatar
unknown committed
6100
  b->natural_join= a;
unknown's avatar
unknown committed
6101
  lex->prev_join_using= using_fields;
unknown's avatar
unknown committed
6102 6103
}

unknown's avatar
unknown committed
6104

6105
/*
6106 6107 6108 6109
  Reload/resets privileges and the different caches.

  SYNOPSIS
    reload_acl_and_cache()
6110
    thd			Thread handler (can be NULL!)
6111 6112 6113 6114 6115
    options             What should be reset/reloaded (tables, privileges,
    slave...)
    tables              Tables to flush (if any)
    write_to_binlog     Depending on 'options', it may be very bad to write the
                        query to the binlog (e.g. FLUSH SLAVE); this is a
unknown's avatar
unknown committed
6116 6117 6118
                        pointer where reload_acl_and_cache() will put 0 if
                        it thinks we really should not write to the binlog.
                        Otherwise it will put 1.
6119 6120 6121

  RETURN
    0	 ok
unknown's avatar
unknown committed
6122
    !=0  error.  thd->killed or thd->net.report_error is set
6123 6124
*/

6125 6126
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
                          bool *write_to_binlog)
unknown's avatar
unknown committed
6127 6128 6129
{
  bool result=0;
  select_errors=0;				/* Write if more errors */
6130
  bool tmp_write_to_binlog= 1;
6131

6132
  DBUG_ASSERT(!thd || !thd->in_sub_stmt);
6133

unknown's avatar
SCRUM  
unknown committed
6134
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
6135 6136
  if (options & REFRESH_GRANT)
  {
6137 6138 6139 6140 6141 6142
    THD *tmp_thd= 0;
    /*
      If reload_acl_and_cache() is called from SIGHUP handler we have to
      allocate temporary THD for execution of acl_reload()/grant_reload().
    */
    if (!thd && (thd= (tmp_thd= new THD)))
6143 6144
    {
      thd->thread_stack= (char*) &tmp_thd;
6145
      thd->store_globals();
6146
    }
6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158
    if (thd)
    {
      (void)acl_reload(thd);
      (void)grant_reload(thd);
    }
    if (tmp_thd)
    {
      delete tmp_thd;
      /* Remember that we don't have a THD */
      my_pthread_setspecific_ptr(THR_THD,  0);
      thd= 0;
    }
6159
    reset_mqh((LEX_USER *)NULL, TRUE);
unknown's avatar
unknown committed
6160
  }
unknown's avatar
SCRUM  
unknown committed
6161
#endif
unknown's avatar
unknown committed
6162 6163
  if (options & REFRESH_LOG)
  {
6164
    /*
unknown's avatar
unknown committed
6165
      Flush the normal query log, the update log, the binary log,
unknown's avatar
unknown committed
6166 6167
      the slow query log, the relay log (if it exists) and the log
      tables.
6168
    */
unknown's avatar
unknown committed
6169

6170
    /*
unknown's avatar
unknown committed
6171 6172 6173 6174
      Writing this command to the binlog may result in infinite loops
      when doing mysqlbinlog|mysql, and anyway it does not really make
      sense to log it automatically (would cause more trouble to users
      than it would help them)
6175 6176
    */
    tmp_write_to_binlog= 0;
6177 6178 6179 6180
    if( mysql_bin_log.is_open() )
    {
      mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
    }
unknown's avatar
unknown committed
6181
#ifdef HAVE_REPLICATION
6182
    pthread_mutex_lock(&LOCK_active_mi);
6183
    rotate_relay_log(active_mi);
6184
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
6185
#endif
unknown's avatar
unknown committed
6186 6187 6188 6189 6190

    /* flush slow and general logs */
    logger.flush_logs(thd);

    if (ha_flush_logs(NULL))
unknown's avatar
unknown committed
6191
      result=1;
unknown's avatar
unknown committed
6192 6193
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
6194
  }
unknown's avatar
unknown committed
6195
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
6196 6197
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
6198
    query_cache.pack();				// FLUSH QUERY CACHE
6199
    options &= ~REFRESH_QUERY_CACHE;    // Don't flush cache, just free memory
unknown's avatar
unknown committed
6200 6201 6202
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
6203
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
6204
  }
unknown's avatar
unknown committed
6205
#endif /*HAVE_QUERY_CACHE*/
6206 6207 6208 6209 6210
  /*
    Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
    (see sql_yacc.yy)
  */
  if (options & (REFRESH_TABLES | REFRESH_READ_LOCK)) 
unknown's avatar
unknown committed
6211
  {
6212
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
6213
    {
6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224
      /*
        We must not try to aspire a global read lock if we have a write
        locked table. This would lead to a deadlock when trying to
        reopen (and re-lock) the table after the flush.
      */
      if (thd->locked_tables)
      {
        THR_LOCK_DATA **lock_p= thd->locked_tables->locks;
        THR_LOCK_DATA **end_p= lock_p + thd->locked_tables->lock_count;

        for (; lock_p < end_p; lock_p++)
unknown's avatar
unknown committed
6225
        {
6226 6227 6228 6229 6230
          if ((*lock_p)->type == TL_WRITE)
          {
            my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
            return 1;
          }
unknown's avatar
unknown committed
6231
        }
6232
      }
unknown's avatar
unknown committed
6233 6234 6235 6236
      /*
	Writing to the binlog could cause deadlocks, as we don't log
	UNLOCK TABLES
      */
6237
      tmp_write_to_binlog= 0;
6238
      if (lock_global_read_lock(thd))
unknown's avatar
unknown committed
6239
	return 1;                               // Killed
6240 6241
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
                                 tables);
unknown's avatar
unknown committed
6242
      if (make_global_read_lock_block_commit(thd)) // Killed
6243 6244 6245 6246 6247
      {
        /* Don't leave things in a half-locked state */
        unlock_global_read_lock(thd);
        return 1;
      }
unknown's avatar
unknown committed
6248
    }
6249 6250
    else
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
unknown's avatar
unknown committed
6251
    my_dbopt_cleanup();
unknown's avatar
unknown committed
6252 6253 6254
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
unknown's avatar
unknown committed
6255
  if (thd && (options & REFRESH_STATUS))
unknown's avatar
unknown committed
6256
    refresh_status(thd);
unknown's avatar
unknown committed
6257 6258
  if (options & REFRESH_THREADS)
    flush_thread_cache();
unknown's avatar
unknown committed
6259
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
6260
  if (options & REFRESH_MASTER)
6261
  {
6262
    DBUG_ASSERT(thd);
6263
    tmp_write_to_binlog= 0;
6264
    if (reset_master(thd))
unknown's avatar
unknown committed
6265
    {
6266
      result=1;
unknown's avatar
unknown committed
6267 6268
      thd->fatal_error();                       // Ensure client get error
    }
6269
  }
6270
#endif
unknown's avatar
unknown committed
6271
#ifdef OPENSSL
6272 6273 6274 6275 6276 6277
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
unknown's avatar
unknown committed
6278
#ifdef HAVE_REPLICATION
6279 6280
 if (options & REFRESH_SLAVE)
 {
6281
   tmp_write_to_binlog= 0;
6282
   pthread_mutex_lock(&LOCK_active_mi);
6283
   if (reset_slave(thd, active_mi))
6284
     result=1;
6285
   pthread_mutex_unlock(&LOCK_active_mi);
6286
 }
6287
#endif
6288
 if (options & REFRESH_USER_RESOURCES)
6289
   reset_mqh((LEX_USER *) NULL, 0);             /* purecov: inspected */
unknown's avatar
unknown committed
6290
 *write_to_binlog= tmp_write_to_binlog;
6291
 return result;
unknown's avatar
unknown committed
6292 6293
}

6294

6295
/*
6296
  kills a thread
6297 6298 6299 6300 6301

  SYNOPSIS
    kill_one_thread()
    thd			Thread class
    id			Thread id
6302
    only_kill_query     Should it kill the query or the connection
6303 6304 6305 6306 6307

  NOTES
    This is written such that we have a short lock on LOCK_thread_count
*/

6308
uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
unknown's avatar
unknown committed
6309 6310 6311
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
6312 6313
  DBUG_ENTER("kill_one_thread");
  DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query));
6314 6315
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
6316 6317
  while ((tmp=it++))
  {
unknown's avatar
unknown committed
6318 6319
    if (tmp->command == COM_DAEMON)
      continue;
unknown's avatar
unknown committed
6320 6321
    if (tmp->thread_id == id)
    {
6322 6323
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
6324 6325 6326
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
6327 6328
  if (tmp)
  {
6329 6330
    if ((thd->security_ctx->master_access & SUPER_ACL) ||
	!strcmp(thd->security_ctx->user, tmp->security_ctx->user))
6331
    {
unknown's avatar
SCRUM  
unknown committed
6332
      tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
6333 6334 6335 6336 6337 6338
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }
6339 6340 6341 6342
  DBUG_PRINT("exit", ("%d", error));
  DBUG_RETURN(error);
}

6343

6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357
/*
  kills a thread and sends response

  SYNOPSIS
    sql_kill()
    thd			Thread class
    id			Thread id
    only_kill_query     Should it kill the query or the connection
*/

void sql_kill(THD *thd, ulong id, bool only_kill_query)
{
  uint error;
  if (!(error= kill_one_thread(thd, id, only_kill_query)))
6358
    send_ok(thd);
unknown's avatar
unknown committed
6359
  else
unknown's avatar
unknown committed
6360
    my_error(error, MYF(0), id);
unknown's avatar
unknown committed
6361 6362
}

unknown's avatar
unknown committed
6363

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

unknown's avatar
unknown committed
6366 6367
bool append_file_to_dir(THD *thd, const char **filename_ptr,
                        const char *table_name)
6368
{
6369
  char buff[FN_REFLEN],*ptr, *end;
6370 6371 6372 6373 6374 6375 6376
  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))
  {
6377
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
6378 6379 6380 6381
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
6382
  end=convert_dirname(buff, *filename_ptr, NullS);
unknown's avatar
unknown committed
6383
  if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
6384 6385
    return 1;					// End of memory
  *filename_ptr=ptr;
6386
  strxmov(ptr,buff,table_name,NullS);
6387 6388
  return 0;
}
6389

6390

6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404
/*
  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;
6405 6406
  LEX *lex= thd->lex;
  if (lex->current_select != &lex->select_lex)
6407 6408
  {
    char command[80];
6409 6410
    strmake(command, lex->yylval->symbol.str,
	    min(lex->yylval->symbol.length, sizeof(command)-1));
6411
    my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
6412 6413 6414 6415
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
6416

unknown's avatar
unknown committed
6417

unknown's avatar
unknown committed
6418
Comp_creator *comp_eq_creator(bool invert)
unknown's avatar
unknown committed
6419
{
unknown's avatar
unknown committed
6420
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
unknown's avatar
unknown committed
6421 6422
}

unknown's avatar
unknown committed
6423

unknown's avatar
unknown committed
6424
Comp_creator *comp_ge_creator(bool invert)
unknown's avatar
unknown committed
6425
{
unknown's avatar
unknown committed
6426
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
unknown's avatar
unknown committed
6427 6428
}

unknown's avatar
unknown committed
6429

unknown's avatar
unknown committed
6430
Comp_creator *comp_gt_creator(bool invert)
unknown's avatar
unknown committed
6431
{
unknown's avatar
unknown committed
6432
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
unknown's avatar
unknown committed
6433 6434
}

unknown's avatar
unknown committed
6435

unknown's avatar
unknown committed
6436
Comp_creator *comp_le_creator(bool invert)
unknown's avatar
unknown committed
6437
{
unknown's avatar
unknown committed
6438
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
unknown's avatar
unknown committed
6439 6440
}

unknown's avatar
unknown committed
6441

unknown's avatar
unknown committed
6442
Comp_creator *comp_lt_creator(bool invert)
unknown's avatar
unknown committed
6443
{
unknown's avatar
unknown committed
6444
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
unknown's avatar
unknown committed
6445 6446
}

unknown's avatar
unknown committed
6447

unknown's avatar
unknown committed
6448
Comp_creator *comp_ne_creator(bool invert)
unknown's avatar
unknown committed
6449
{
unknown's avatar
unknown committed
6450
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
unknown's avatar
unknown committed
6451
}
unknown's avatar
unknown committed
6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471


/*
  Construct ALL/ANY/SOME subquery Item

  SYNOPSIS
    all_any_subquery_creator()
    left_expr - pointer to left expression
    cmp - compare function creator
    all - true if we create ALL subquery
    select_lex - pointer on parsed subquery structure

  RETURN VALUE
    constructed Item (or 0 if out of memory)
*/
Item * all_any_subquery_creator(Item *left_expr,
				chooser_compare_func_creator cmp,
				bool all,
				SELECT_LEX *select_lex)
{
unknown's avatar
unknown committed
6472
  if ((cmp == &comp_eq_creator) && !all)       //  = ANY <=> IN
unknown's avatar
unknown committed
6473
    return new Item_in_subselect(left_expr, select_lex);
unknown's avatar
unknown committed
6474 6475

  if ((cmp == &comp_ne_creator) && all)        // <> ALL <=> NOT IN
unknown's avatar
unknown committed
6476 6477 6478
    return new Item_func_not(new Item_in_subselect(left_expr, select_lex));

  Item_allany_subselect *it=
6479
    new Item_allany_subselect(left_expr, cmp, select_lex, all);
unknown's avatar
unknown committed
6480
  if (all)
6481
    return it->upper_item= new Item_func_not_all(it);	/* ALL */
unknown's avatar
unknown committed
6482

6483
  return it->upper_item= new Item_func_nop_all(it);      /* ANY/SOME */
unknown's avatar
unknown committed
6484
}
6485 6486


6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498
/*
  CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
  the proper arguments.  This isn't very fast but it should work for most
  cases.

  In the future ALTER TABLE will notice that only added indexes
  and create these one by one for the existing table without having to do
  a full rebuild.

  One should normally create all indexes with CREATE TABLE or ALTER TABLE.
*/

unknown's avatar
unknown committed
6499
bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
6500 6501
{
  List<create_field> fields;
6502 6503
  ALTER_INFO alter_info;
  alter_info.flags= ALTER_ADD_INDEX;
6504 6505 6506
  HA_CREATE_INFO create_info;
  DBUG_ENTER("mysql_create_index");
  bzero((char*) &create_info,sizeof(create_info));
unknown's avatar
unknown committed
6507
  create_info.db_type= 0;
6508
  create_info.default_table_charset= thd->variables.collation_database;
6509
  create_info.row_type= ROW_TYPE_NOT_USED;
6510
  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
6511
				&create_info, table_list,
6512
				fields, keys, 0, (ORDER*)0,
6513
                                0, &alter_info, 1));
6514 6515 6516
}


unknown's avatar
unknown committed
6517
bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
6518 6519 6520 6521 6522 6523
{
  List<create_field> fields;
  List<Key> keys;
  HA_CREATE_INFO create_info;
  DBUG_ENTER("mysql_drop_index");
  bzero((char*) &create_info,sizeof(create_info));
unknown's avatar
unknown committed
6524
  create_info.db_type= 0;
6525
  create_info.default_table_charset= thd->variables.collation_database;
6526
  create_info.row_type= ROW_TYPE_NOT_USED;
6527 6528
  alter_info->clear();
  alter_info->flags= ALTER_DROP_INDEX;
6529
  DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
6530
				&create_info, table_list,
6531
				fields, keys, 0, (ORDER*)0,
6532
                                0, alter_info, 1));
6533
}
unknown's avatar
merge  
unknown committed
6534 6535


6536 6537 6538 6539 6540
/*
  Multi update query pre-check

  SYNOPSIS
    multi_update_precheck()
unknown's avatar
unknown committed
6541
    thd		Thread handler
unknown's avatar
VIEW  
unknown committed
6542
    tables	Global/local table list (have to be the same)
6543

unknown's avatar
unknown committed
6544
  RETURN VALUE
unknown's avatar
unknown committed
6545 6546
    FALSE OK
    TRUE  Error
6547
*/
unknown's avatar
unknown committed
6548

unknown's avatar
unknown committed
6549
bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
6550 6551 6552 6553 6554
{
  const char *msg= 0;
  TABLE_LIST *table;
  LEX *lex= thd->lex;
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
6555
  DBUG_ENTER("multi_update_precheck");
6556 6557 6558

  if (select_lex->item_list.elements != lex->value_list.elements)
  {
6559
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6560
    DBUG_RETURN(TRUE);
6561 6562 6563 6564 6565
  }
  /*
    Ensure that we have UPDATE or SELECT privilege for each table
    The exact privilege is checked in mysql_multi_update()
  */
unknown's avatar
VIEW  
unknown committed
6566
  for (table= tables; table; table= table->next_local)
6567
  {
6568 6569 6570
    if (table->derived)
      table->grant.privilege= SELECT_ACL;
    else if ((check_access(thd, UPDATE_ACL, table->db,
6571 6572
                           &table->grant.privilege, 0, 1,
                           test(table->schema_table)) ||
6573 6574
              grant_option &&
              check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
unknown's avatar
unknown committed
6575
             (check_access(thd, SELECT_ACL, table->db,
6576 6577
                           &table->grant.privilege, 0, 0,
                           test(table->schema_table)) ||
unknown's avatar
unknown committed
6578
              grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
unknown's avatar
unknown committed
6579
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6580

unknown's avatar
VIEW  
unknown committed
6581
    table->table_in_first_from_clause= 1;
6582
  }
unknown's avatar
unknown committed
6583 6584 6585
  /*
    Is there tables of subqueries?
  */
6586
  if (&lex->select_lex != lex->all_selects_list)
6587
  {
6588
    DBUG_PRINT("info",("Checking sub query list"));
unknown's avatar
VIEW  
unknown committed
6589
    for (table= tables; table; table= table->next_global)
6590
    {
6591
      if (!table->table_in_first_from_clause)
6592 6593
      {
	if (check_access(thd, SELECT_ACL, table->db,
6594 6595
			 &table->grant.privilege, 0, 0,
                         test(table->schema_table)) ||
unknown's avatar
unknown committed
6596
	    grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
unknown's avatar
unknown committed
6597
	  DBUG_RETURN(TRUE);
6598 6599 6600 6601 6602 6603
      }
    }
  }

  if (select_lex->order_list.elements)
    msg= "ORDER BY";
6604
  else if (select_lex->select_limit)
6605 6606 6607 6608
    msg= "LIMIT";
  if (msg)
  {
    my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
unknown's avatar
unknown committed
6609
    DBUG_RETURN(TRUE);
6610
  }
unknown's avatar
unknown committed
6611
  DBUG_RETURN(FALSE);
6612 6613 6614 6615 6616 6617 6618
}

/*
  Multi delete query pre-check

  SYNOPSIS
    multi_delete_precheck()
unknown's avatar
unknown committed
6619
    thd			Thread handler
unknown's avatar
VIEW  
unknown committed
6620
    tables		Global/local table list
6621

unknown's avatar
unknown committed
6622
  RETURN VALUE
unknown's avatar
unknown committed
6623 6624
    FALSE OK
    TRUE  error
6625
*/
unknown's avatar
unknown committed
6626

6627
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
6628 6629 6630
{
  SELECT_LEX *select_lex= &thd->lex->select_lex;
  TABLE_LIST *aux_tables=
unknown's avatar
unknown committed
6631
    (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
6632
  TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
unknown's avatar
VIEW  
unknown committed
6633
  DBUG_ENTER("multi_delete_precheck");
unknown's avatar
unknown committed
6634

6635 6636
  /* sql_yacc guarantees that tables and aux_tables are not zero */
  DBUG_ASSERT(aux_tables != 0);
unknown's avatar
unknown committed
6637
  if (check_table_access(thd, SELECT_ACL, tables, 0))
6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648
    DBUG_RETURN(TRUE);

  /*
    Since aux_tables list is not part of LEX::query_tables list we
    have to juggle with LEX::query_tables_own_last value to be able
    call check_table_access() safely.
  */
  thd->lex->query_tables_own_last= 0;
  if (check_table_access(thd, DELETE_ACL, aux_tables, 0))
  {
    thd->lex->query_tables_own_last= save_query_tables_own_last;
unknown's avatar
unknown committed
6649
    DBUG_RETURN(TRUE);
6650 6651 6652
  }
  thd->lex->query_tables_own_last= save_query_tables_own_last;

6653 6654
  if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
  {
unknown's avatar
unknown committed
6655 6656
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
6657
    DBUG_RETURN(TRUE);
6658
  }
6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683
  DBUG_RETURN(FALSE);
}


/*
  Link tables in auxilary table list of multi-delete with corresponding
  elements in main table list, and set proper locks for them.

  SYNOPSIS
    multi_delete_set_locks_and_link_aux_tables()
      lex - pointer to LEX representing multi-delete

  RETURN VALUE
    FALSE - success
    TRUE  - error
*/

bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
{
  TABLE_LIST *tables= (TABLE_LIST*)lex->select_lex.table_list.first;
  TABLE_LIST *target_tbl;
  DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables");

  lex->table_count= 0;

unknown's avatar
unknown committed
6684
  for (target_tbl= (TABLE_LIST *)lex->auxiliary_table_list.first;
6685
       target_tbl; target_tbl= target_tbl->next_local)
6686
  {
6687
    lex->table_count++;
6688 6689
    /* All tables in aux_tables must be found in FROM PART */
    TABLE_LIST *walk;
unknown's avatar
VIEW  
unknown committed
6690
    for (walk= tables; walk; walk= walk->next_local)
6691
    {
unknown's avatar
unknown committed
6692 6693 6694
      if (!my_strcasecmp(table_alias_charset,
			 target_tbl->alias, walk->alias) &&
	  !strcmp(walk->db, target_tbl->db))
6695 6696 6697 6698
	break;
    }
    if (!walk)
    {
6699
      my_error(ER_UNKNOWN_TABLE, MYF(0),
6700
               target_tbl->table_name, "MULTI DELETE");
unknown's avatar
unknown committed
6701
      DBUG_RETURN(TRUE);
6702
    }
unknown's avatar
unknown committed
6703 6704 6705 6706 6707
    if (!walk->derived)
    {
      target_tbl->table_name= walk->table_name;
      target_tbl->table_name_length= walk->table_name_length;
    }
unknown's avatar
unknown committed
6708
    walk->updating= target_tbl->updating;
unknown's avatar
unknown committed
6709
    walk->lock_type= target_tbl->lock_type;
unknown's avatar
VIEW  
unknown committed
6710
    target_tbl->correspondent_table= walk;	// Remember corresponding table
6711
  }
unknown's avatar
unknown committed
6712
  DBUG_RETURN(FALSE);
6713 6714 6715
}


unknown's avatar
unknown committed
6716 6717 6718 6719 6720
/*
  simple UPDATE query pre-check

  SYNOPSIS
    update_precheck()
unknown's avatar
unknown committed
6721 6722
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
6723 6724

  RETURN VALUE
unknown's avatar
unknown committed
6725 6726
    FALSE OK
    TRUE  Error
unknown's avatar
unknown committed
6727
*/
unknown's avatar
unknown committed
6728

unknown's avatar
unknown committed
6729
bool update_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
6730 6731 6732 6733
{
  DBUG_ENTER("update_precheck");
  if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
  {
unknown's avatar
unknown committed
6734
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6735
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6736
  }
unknown's avatar
unknown committed
6737
  DBUG_RETURN(check_one_table_access(thd, UPDATE_ACL, tables));
unknown's avatar
unknown committed
6738 6739 6740 6741 6742 6743 6744 6745
}


/*
  simple DELETE query pre-check

  SYNOPSIS
    delete_precheck()
unknown's avatar
unknown committed
6746 6747
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
6748 6749

  RETURN VALUE
unknown's avatar
unknown committed
6750 6751
    FALSE  OK
    TRUE   error
unknown's avatar
unknown committed
6752
*/
unknown's avatar
unknown committed
6753

unknown's avatar
unknown committed
6754
bool delete_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
6755 6756 6757
{
  DBUG_ENTER("delete_precheck");
  if (check_one_table_access(thd, DELETE_ACL, tables))
unknown's avatar
unknown committed
6758
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6759
  /* Set privilege for the WHERE clause */
unknown's avatar
unknown committed
6760
  tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
6761
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
6762 6763 6764 6765 6766 6767 6768 6769
}


/*
  simple INSERT query pre-check

  SYNOPSIS
    insert_precheck()
unknown's avatar
unknown committed
6770 6771
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
6772 6773

  RETURN VALUE
unknown's avatar
unknown committed
6774 6775
    FALSE  OK
    TRUE   error
unknown's avatar
unknown committed
6776
*/
unknown's avatar
unknown committed
6777

unknown's avatar
merge  
unknown committed
6778
bool insert_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
6779 6780 6781 6782
{
  LEX *lex= thd->lex;
  DBUG_ENTER("insert_precheck");

unknown's avatar
unknown committed
6783 6784 6785 6786
  /*
    Check that we have modify privileges for the first table and
    select privileges for the rest
  */
unknown's avatar
unknown committed
6787 6788 6789
  ulong privilege= (INSERT_ACL |
                    (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
                    (lex->value_list.elements ? UPDATE_ACL : 0));
unknown's avatar
unknown committed
6790 6791

  if (check_one_table_access(thd, privilege, tables))
unknown's avatar
unknown committed
6792
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6793

unknown's avatar
unknown committed
6794
  if (lex->update_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
6795
  {
unknown's avatar
unknown committed
6796
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6797
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6798
  }
unknown's avatar
unknown committed
6799
  DBUG_RETURN(FALSE);
6800
}
unknown's avatar
unknown committed
6801 6802 6803 6804 6805 6806 6807


/*
  CREATE TABLE query pre-check

  SYNOPSIS
    create_table_precheck()
unknown's avatar
unknown committed
6808 6809 6810
    thd			Thread handler
    tables		Global table list
    create_table	Table which will be created
unknown's avatar
unknown committed
6811 6812

  RETURN VALUE
unknown's avatar
unknown committed
6813 6814
    FALSE   OK
    TRUE   Error
unknown's avatar
unknown committed
6815
*/
unknown's avatar
unknown committed
6816

unknown's avatar
unknown committed
6817 6818
bool create_table_precheck(THD *thd, TABLE_LIST *tables,
                           TABLE_LIST *create_table)
unknown's avatar
unknown committed
6819 6820
{
  LEX *lex= thd->lex;
6821 6822
  SELECT_LEX *select_lex= &lex->select_lex;
  ulong want_priv;
unknown's avatar
merge  
unknown committed
6823
  bool error= TRUE;                                 // Error message is given
unknown's avatar
unknown committed
6824
  DBUG_ENTER("create_table_precheck");
6825 6826 6827

  want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
              CREATE_TMP_ACL : CREATE_ACL);
unknown's avatar
unknown committed
6828 6829
  lex->create_info.alias= create_table->alias;
  if (check_access(thd, want_priv, create_table->db,
6830 6831
		   &create_table->grant.privilege, 0, 0,
                   test(create_table->schema_table)) ||
unknown's avatar
unknown committed
6832 6833 6834
      check_merge_table_access(thd, create_table->db,
			       (TABLE_LIST *)
			       lex->create_info.merge_list.first))
6835 6836
    goto err;
  if (grant_option && want_priv != CREATE_TMP_ACL &&
6837
      check_grant(thd, want_priv, create_table, 0, 1, 0))
6838 6839 6840 6841 6842 6843
    goto err;

  if (select_lex->item_list.elements)
  {
    /* Check permissions for used tables in CREATE TABLE ... SELECT */

6844 6845
#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
    /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
6846
    /*
6847
      Only do the check for PS, because we on execute we have to check that
unknown's avatar
unknown committed
6848 6849
      against the opened tables to ensure we don't use a table that is part
      of the view (which can only be done after the table has been opened).
6850
    */
unknown's avatar
unknown committed
6851
    if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
6852
    {
unknown's avatar
unknown committed
6853 6854 6855 6856
      /*
        For temporary tables we don't have to check if the created table exists
      */
      if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
unknown's avatar
unknown committed
6857
          find_table_in_global_list(tables, create_table->db,
6858
                                    create_table->table_name))
unknown's avatar
unknown committed
6859
      {
6860
	error= FALSE;
unknown's avatar
unknown committed
6861 6862 6863
        goto err;
      }
    }
6864
#endif
6865 6866 6867
    if (tables && check_table_access(thd, SELECT_ACL, tables,0))
      goto err;
  }
unknown's avatar
merge  
unknown committed
6868
  error= FALSE;
6869 6870 6871

err:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
6872
}
unknown's avatar
unknown committed
6873 6874 6875 6876 6877 6878 6879


/*
  negate given expression

  SYNOPSIS
    negate_expression()
6880
    thd  thread handler
unknown's avatar
unknown committed
6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908
    expr expression for negation

  RETURN
    negated expression
*/

Item *negate_expression(THD *thd, Item *expr)
{
  Item *negated;
  if (expr->type() == Item::FUNC_ITEM &&
      ((Item_func *) expr)->functype() == Item_func::NOT_FUNC)
  {
    /* it is NOT(NOT( ... )) */
    Item *arg= ((Item_func *) expr)->arguments()[0];
    enum_parsing_place place= thd->lex->current_select->parsing_place;
    if (arg->is_bool_func() || place == IN_WHERE || place == IN_HAVING)
      return arg;
    /*
      if it is not boolean function then we have to emulate value of
      not(not(a)), it will be a != 0
    */
    return new Item_func_ne(arg, new Item_int((char*) "0", 0, 1));
  }

  if ((negated= expr->neg_transformer(thd)) != 0)
    return negated;
  return new Item_func_not(expr);
}
6909

6910 6911
/*
  Set the specified definer to the default value, which is the current user in
6912
  the thread.
6913 6914 6915 6916 6917 6918 6919
 
  SYNOPSIS
    get_default_definer()
    thd       [in] thread handler
    definer   [out] definer
*/
 
6920
void get_default_definer(THD *thd, LEX_USER *definer)
6921 6922 6923 6924 6925 6926 6927 6928 6929 6930
{
  const Security_context *sctx= thd->security_ctx;

  definer->user.str= (char *) sctx->priv_user;
  definer->user.length= strlen(definer->user.str);

  definer->host.str= (char *) sctx->priv_host;
  definer->host.length= strlen(definer->host.str);
}

6931

6932
/*
6933
  Create default definer for the specified THD.
6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951

  SYNOPSIS
    create_default_definer()
    thd         [in] thread handler

  RETURN
    On success, return a valid pointer to the created and initialized
    LEX_USER, which contains definer information.
    On error, return 0.
*/

LEX_USER *create_default_definer(THD *thd)
{
  LEX_USER *definer;

  if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
    return 0;

6952
  get_default_definer(thd, definer);
6953 6954 6955 6956 6957

  return definer;
}


6958
/*
6959
  Create definer with the given user and host names.
6960 6961

  SYNOPSIS
6962 6963 6964 6965
    create_definer()
    thd         [in] thread handler
    user_name   [in] user name
    host_name   [in] host name
6966 6967

  RETURN
6968
    On success, return a valid pointer to the created and initialized
6969
    LEX_USER, which contains definer information.
6970
    On error, return 0.
6971 6972
*/

6973
LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
6974
{
6975 6976 6977 6978
  LEX_USER *definer;

  /* Create and initialize. */

unknown's avatar
unknown committed
6979
  if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
6980 6981 6982 6983 6984 6985
    return 0;

  definer->user= *user_name;
  definer->host= *host_name;

  return definer;
6986
}
6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005


/*
  Retuns information about user or current user.

  SYNOPSIS
    get_current_user()
    thd         [in] thread handler
    user        [in] user

  RETURN
    On success, return a valid pointer to initialized
    LEX_USER, which contains user information.
    On error, return 0.
*/

LEX_USER *get_current_user(THD *thd, LEX_USER *user)
{
  if (!user->user.str)  // current_user
7006 7007
    return create_default_definer(thd);

7008 7009
  return user;
}
7010 7011 7012


/*
7013
  Check that byte length of a string does not exceed some limit.
7014 7015

  SYNOPSIS
7016 7017 7018 7019
  check_string_byte_length()
      str              string to be checked
      err_msg          error message to be displayed if the string is too long
      max_byte_length  max length in bytes
7020 7021 7022 7023

  RETURN
    FALSE   the passed string is not longer than max_length
    TRUE    the passed string is longer than max_length
7024 7025 7026

  NOTE
    The function is not used in existing code but can be useful later?
7027 7028
*/

7029 7030
bool check_string_byte_length(LEX_STRING *str, const char *err_msg,
                              uint max_byte_length)
7031
{
7032
  if (str->length <= max_byte_length)
unknown's avatar
unknown committed
7033
    return FALSE;
7034

7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066
  my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_byte_length);

  return TRUE;
}


/*
  Check that char length of a string does not exceed some limit.

  SYNOPSIS
  check_string_char_length()
      str              string to be checked
      err_msg          error message to be displayed if the string is too long
      max_char_length  max length in symbols
      cs               string charset

  RETURN
    FALSE   the passed string is not longer than max_char_length
    TRUE    the passed string is longer than max_char_length
*/


bool check_string_char_length(LEX_STRING *str, const char *err_msg,
                              uint max_char_length, CHARSET_INFO *cs,
                              bool no_error)
{
  int well_formed_error;
  uint res= cs->cset->well_formed_len(cs, str->str, str->str + str->length,
                                      max_char_length, &well_formed_error);

  if (!well_formed_error &&  str->length == res)
    return FALSE;
unknown's avatar
unknown committed
7067

7068 7069
  if (!no_error)
    my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_char_length);
7070 7071
  return TRUE;
}