sql_parse.cc 210 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
static bool check_show_create_table_access(THD *thd, TABLE_LIST *table);
unknown's avatar
unknown committed
43

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

unknown's avatar
unknown committed
46
const LEX_STRING command_name[]={
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 77
  { C_STRING_WITH_LEN("Sleep") },
  { C_STRING_WITH_LEN("Quit") },
  { C_STRING_WITH_LEN("Init DB") },
  { C_STRING_WITH_LEN("Query") },
  { C_STRING_WITH_LEN("Field List") },
  { C_STRING_WITH_LEN("Create DB") },
  { C_STRING_WITH_LEN("Drop DB") },
  { C_STRING_WITH_LEN("Refresh") },
  { C_STRING_WITH_LEN("Shutdown") },
  { C_STRING_WITH_LEN("Statistics") },
  { C_STRING_WITH_LEN("Processlist") },
  { C_STRING_WITH_LEN("Connect") },
  { C_STRING_WITH_LEN("Kill") },
  { C_STRING_WITH_LEN("Debug") },
  { C_STRING_WITH_LEN("Ping") },
  { C_STRING_WITH_LEN("Time") },
  { C_STRING_WITH_LEN("Delayed insert") },
  { C_STRING_WITH_LEN("Change user") },
  { C_STRING_WITH_LEN("Binlog Dump") },
  { C_STRING_WITH_LEN("Table Dump") },
  { C_STRING_WITH_LEN("Connect Out") },
  { C_STRING_WITH_LEN("Register Slave") },
  { C_STRING_WITH_LEN("Prepare") },
  { C_STRING_WITH_LEN("Execute") },
  { C_STRING_WITH_LEN("Long Data") },
  { C_STRING_WITH_LEN("Close stmt") },
  { C_STRING_WITH_LEN("Reset stmt") },
  { C_STRING_WITH_LEN("Set option") },
  { C_STRING_WITH_LEN("Fetch") },
  { C_STRING_WITH_LEN("Daemon") },
  { C_STRING_WITH_LEN("Error") }  // Last command number
unknown's avatar
unknown committed
78 79
};

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

unknown's avatar
unknown committed
84

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

95

96
bool end_active_trans(THD *thd)
97
{
unknown's avatar
unknown committed
98
  int error=0;
99
  DBUG_ENTER("end_active_trans");
100
  if (unlikely(thd->in_sub_stmt))
101 102 103 104
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    DBUG_RETURN(1);
  }
105 106 107 108 109 110
  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
111
  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
unknown's avatar
unknown committed
112
		      OPTION_TABLE_LOCK))
113
  {
114 115 116 117
    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;
118
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
119
    if (ha_commit(thd))
unknown's avatar
unknown committed
120
      error=1;
121
  }
122 123
  thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
  thd->no_trans_update.all= FALSE;
124
  DBUG_RETURN(error);
125 126
}

127

unknown's avatar
unknown committed
128
bool begin_trans(THD *thd)
unknown's avatar
unknown committed
129 130
{
  int error=0;
131
  if (unlikely(thd->in_sub_stmt))
132 133 134 135
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    return 1;
  }
unknown's avatar
unknown committed
136 137 138 139 140 141 142 143 144 145
  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
  {
146
    LEX *lex= thd->lex;
147
    thd->options|= OPTION_BEGIN;
unknown's avatar
unknown committed
148 149
    thd->server_status|= SERVER_STATUS_IN_TRANS;
    if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
unknown's avatar
unknown committed
150
      error= ha_start_consistent_snapshot(thd);
unknown's avatar
unknown committed
151 152 153
  }
  return error;
}
154

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


167 168 169 170 171 172 173 174 175 176 177 178
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;
}

179

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

  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
186

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

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

void init_update_queries(void)
{
196
  bzero((uchar*) &sql_command_flags, sizeof(sql_command_flags));
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 252

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

255

unknown's avatar
unknown committed
256 257
bool is_update_query(enum enum_sql_command command)
{
unknown's avatar
unknown committed
258
  DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
259
  return (sql_command_flags[command] & CF_CHANGES_DATA) != 0;
unknown's avatar
unknown committed
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;
303
  const char* found_semicolon= NULL;
unknown's avatar
unknown committed
304

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

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

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

  thd->proc_info=0;
  thd->version=refresh_version;
327 328
  thd->security_ctx->priv_user=
    thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
unknown's avatar
unknown committed
329
  thd->security_ctx->priv_host[0]=0;
330 331 332 333 334 335
  /*
    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
336

337
  buff= (char*) thd->net.buff;
338
  thd->init_for_queries();
unknown's avatar
unknown committed
339 340
  while (fgets(buff, thd->net.max_packet, file))
  {
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
    /* 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
363

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

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

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

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

    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
399
    free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
400
#ifdef USING_TRANSACTIONS
401
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
402
#endif
unknown's avatar
unknown committed
403
  }
404 405

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

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

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


unknown's avatar
unknown committed
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
/* 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() */
440 441 442

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

unknown's avatar
unknown committed
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
/*
  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
468
int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name)
unknown's avatar
unknown committed
469 470 471 472 473
{
  TABLE* table;
  TABLE_LIST* table_list;
  int error = 0;
  DBUG_ENTER("mysql_table_dump");
474 475 476 477 478
  if (db->length == 0)
  {
    db->str= thd->db;            /* purecov: inspected */
    db->length= thd->db_length;  /* purecov: inspected */
  }
479
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
480
    DBUG_RETURN(1); // out of memory
481
  table_list->db= db->str;
482
  table_list->table_name= table_list->alias= tbl_name;
unknown's avatar
VIEW  
unknown committed
483 484
  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
485

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

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

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

unknown's avatar
unknown committed
513
err:
unknown's avatar
unknown committed
514
  DBUG_RETURN(error);
unknown's avatar
unknown committed
515 516
}

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

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

  RETURN
    0 - OK
*/

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

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

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

unknown's avatar
unknown committed
590 591
  DBUG_RETURN(res);
}
unknown's avatar
unknown committed
592

593
#ifndef EMBEDDED_LIBRARY
594 595

/*
unknown's avatar
unknown committed
596
  Read one command from connection and execute it (query or simple command).
597 598 599 600 601 602 603 604
  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
605 606
bool do_command(THD *thd)
{
unknown's avatar
unknown committed
607
  char *packet= 0;
unknown's avatar
unknown committed
608
  ulong packet_length;
unknown's avatar
unknown committed
609
  NET *net= &thd->net;
unknown's avatar
unknown committed
610 611 612
  enum enum_server_command command;
  DBUG_ENTER("do_command");

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

unknown's avatar
unknown committed
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
  */
625
  my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
unknown's avatar
unknown committed
626

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

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

  /* Restore read timeout value */
657
  my_net_set_read_timeout(net, thd->variables.net_read_timeout);
unknown's avatar
unknown committed
658

659 660 661 662 663 664 665 666 667
  /*
    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
668
  DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
669
}
670
#endif  /* EMBEDDED_LIBRARY */
671

672

673 674
/*
   Perform one connection-level (COM_XXXX) command.
675

676 677 678 679 680 681 682 683 684 685 686 687 688
  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
*/
689

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

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

703
  thd->command=command;
unknown's avatar
unknown committed
704
  /*
705 706
    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
707
  */
708
  thd->enable_slow_log= TRUE;
709
  thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
unknown's avatar
unknown committed
710
  thd->set_time();
unknown's avatar
unknown committed
711
  VOID(pthread_mutex_lock(&LOCK_thread_count));
unknown's avatar
unknown committed
712
  thd->query_id= global_query_id;
unknown's avatar
unknown committed
713
  if (command != COM_STATISTICS && command != COM_PING)
714
    next_query_id();
unknown's avatar
unknown committed
715
  thread_running++;
716
  /* TODO: set thd->lex->sql_command to SQLCOM_END here */
unknown's avatar
unknown committed
717
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
718

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

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

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

783
    /*
unknown's avatar
unknown committed
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 788 789

      Cast *passwd to an unsigned char, so that it doesn't extend the sign
      for *passwd > 127 and become 2**32-127 after casting to uint.
unknown's avatar
unknown committed
790
    */
791
    char db_buff[NAME_LEN+1];                 // buffer to store db in utf8
unknown's avatar
unknown committed
792
    char *db= passwd;
793 794
    char *save_db;
    uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
795
                      (uchar)(*passwd++) : strlen(passwd));
796 797
    uint dummy_errors, save_db_length, db_length;
    int res;
798 799 800
    Security_context save_security_ctx= *thd->security_ctx;
    USER_CONN *save_user_connect;

unknown's avatar
unknown committed
801
    db+= passwd_len + 1;
802
#ifndef EMBEDDED_LIBRARY
803
    /* Small check for incoming packet */
unknown's avatar
unknown committed
804
    if ((uint) ((uchar*) db - net->read_pos) > packet_length)
805
    {
unknown's avatar
unknown committed
806
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
807 808
      break;
    }
809
#endif
810
    /* Convert database name to utf8 */
811 812 813 814 815 816 817
    /*
      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--;
818
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
819
                             system_charset_info, db, db_length,
820
                             thd->charset(), &dummy_errors)]= 0;
821
    db= db_buff;
unknown's avatar
unknown committed
822

823
    /* Save user and privileges */
824 825 826
    save_db_length= thd->db_length;
    save_db= thd->db;
    save_user_connect= thd->user_connect;
827 828

    if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
829
    {
830
      thd->security_ctx->user= save_security_ctx.user;
unknown's avatar
unknown committed
831
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
832 833
      break;
    }
unknown's avatar
unknown committed
834

unknown's avatar
unknown committed
835 836
    /* Clear variables that are allocated */
    thd->user_connect= 0;
837
    res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
unknown's avatar
unknown committed
838

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

unknown's avatar
unknown committed
903
    general_log_print(thd, command, format, thd->query_length, thd->query);
904
    DBUG_PRINT("query",("%-.4096s",thd->query));
905 906 907 908

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

909
    mysql_parse(thd, thd->query, thd->query_length, & found_semicolon);
910

911
    while (!thd->killed && found_semicolon && !thd->net.report_error)
912
    {
913
      char *next_packet= (char*) found_semicolon;
914
      net->no_send_error= 0;
915
      /*
916 917
        Multiple queries exits, execute them individually
      */
918 919
      if (thd->lock || thd->open_tables || thd->derived_tables ||
          thd->prelocked_mode)
920
        close_thread_tables(thd);
unknown's avatar
unknown committed
921
      ulong length= (ulong)(packet_end - next_packet);
922

923
      log_slow_statement(thd);
924

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

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

unknown's avatar
unknown committed
959
    /* used as fields initializator */
960
    lex_start(thd);
961

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

    if (!my_strcasecmp(system_charset_info, table_list.db,
976
                       INFORMATION_SCHEMA_NAME.str))
977 978 979 980 981 982
    {
      ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
      if (schema_table)
        table_list.schema_table= schema_table;
    }

983
    thd->query_length= (uint) (packet_end - packet); // Don't count end \0
984
    if (!(thd->query=fields= (char*) thd->memdup(packet,thd->query_length+1)))
unknown's avatar
unknown committed
985
      break;
unknown's avatar
unknown committed
986
    general_log_print(thd, command, "%s %s", table_list.table_name, fields);
987
    if (lower_case_table_names)
988
      my_casedn_str(files_charset_info, table_list.table_name);
unknown's avatar
unknown committed
989

unknown's avatar
unknown committed
990
    if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
991
		     0, 0, test(table_list.schema_table)))
unknown's avatar
unknown committed
992
      break;
993
    if (check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
994
      break;
995 996
    /* init structures for VIEW processing */
    table_list.select_lex= &(thd->lex->select_lex);
997 998 999 1000

    lex_start(thd);
    mysql_reset_thd_for_next_command(thd);

1001
    thd->lex->
1002 1003
      select_lex.table_list.link_in_list((uchar*) &table_list,
                                         (uchar**) &table_list.next_local);
unknown's avatar
unknown committed
1004
    thd->lex->add_to_query_tables(&table_list);
1005

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

1021
#ifdef REMOVED
unknown's avatar
unknown committed
1022
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1023
    {
1024
      LEX_STRING db, alias;
1025
      HA_CREATE_INFO create_info;
unknown's avatar
unknown committed
1026

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

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

1075
      status_var_increment(thd->status_var.com_other);
1076
      thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
unknown committed
1077
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1078
	break;
unknown's avatar
unknown committed
1079

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

unknown's avatar
unknown committed
1088
      general_log_print(thd, command, "Log: '%s'  Pos: %ld", packet+10,
unknown's avatar
unknown committed
1089
                      (long) pos);
1090
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1091
      unregister_slave(thd,1,1);
unknown's avatar
unknown committed
1092
      /*  fake COM_QUIT -- if we get here, the thread needs to terminate */
1093 1094
      error = TRUE;
      net->error = 0;
unknown's avatar
unknown committed
1095 1096
      break;
    }
1097
#endif
unknown's avatar
unknown committed
1098
  case COM_REFRESH:
unknown's avatar
unknown committed
1099 1100
  {
    bool not_used;
1101
    status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
unknown's avatar
unknown committed
1102 1103
    ulong options= (ulong) (uchar) packet[0];
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1104
      break;
unknown's avatar
unknown committed
1105
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1106 1107 1108 1109
    if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
      send_ok(thd);
    break;
  }
1110
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1111
  case COM_SHUTDOWN:
1112
  {
1113
    status_var_increment(thd->status_var.com_other);
unknown's avatar
unknown committed
1114
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1115
      break; /* purecov: inspected */
1116
    /*
1117 1118 1119 1120
      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].
1121
    */
1122 1123
    enum mysql_enum_shutdown_level level=
      (enum mysql_enum_shutdown_level) (uchar) packet[0];
1124 1125 1126 1127 1128 1129 1130
    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;
    }
1131
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
unknown's avatar
unknown committed
1132
    general_log_print(thd, command, NullS);
1133
    send_eof(thd);
unknown's avatar
unknown committed
1134 1135 1136
#ifdef __WIN__
    sleep(1);					// must wait after eof()
#endif
1137 1138 1139 1140 1141 1142
    /*
      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);
1143
    close_connection(thd, 0, 1);
unknown's avatar
unknown committed
1144 1145 1146 1147
    close_thread_tables(thd);			// Free before kill
    kill_mysql();
    error=TRUE;
    break;
1148
  }
1149
#endif
unknown's avatar
unknown committed
1150 1151
  case COM_STATISTICS:
  {
1152 1153 1154
    STATUS_VAR current_global_status_var;
    ulong uptime;
    uint length;
1155
    ulonglong queries_per_second1000;
unknown's avatar
unknown committed
1156
#ifndef EMBEDDED_LIBRARY
1157 1158
    char buff[250];
    uint buff_len= sizeof(buff);
unknown's avatar
unknown committed
1159 1160
#else
    char *buff= thd->net.last_error;
1161
    uint buff_len= sizeof(thd->net.last_error);
unknown's avatar
unknown committed
1162
#endif
1163

1164
    general_log_print(thd, command, NullS);
1165
    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]);
1166
    calc_sum_of_all_status(&current_global_status_var);
1167 1168 1169 1170 1171
    if (!(uptime= (ulong) (thd->start_time - server_start_time)))
      queries_per_second1000= 0;
    else
      queries_per_second1000= thd->query_id * LL(1000) / uptime;

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

    switch (opt_command) {
    case (int) MYSQL_OPTION_MULTI_STATEMENTS_ON:
1228
      thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
unknown's avatar
unknown committed
1229
      send_eof(thd);
1230
      break;
unknown's avatar
unknown committed
1231
    case (int) MYSQL_OPTION_MULTI_STATEMENTS_OFF:
1232
      thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
unknown's avatar
unknown committed
1233
      send_eof(thd);
1234 1235
      break;
    default:
unknown's avatar
unknown committed
1236
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1237 1238 1239 1240
      break;
    }
    break;
  }
unknown's avatar
unknown committed
1241
  case COM_DEBUG:
1242
    status_var_increment(thd->status_var.com_other);
unknown's avatar
unknown committed
1243
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1244
      break;					/* purecov: inspected */
1245
    mysql_print_status();
unknown's avatar
unknown committed
1246
    general_log_print(thd, command, NullS);
1247
    send_eof(thd);
unknown's avatar
unknown committed
1248 1249 1250 1251 1252
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
1253
  case COM_END:
unknown's avatar
unknown committed
1254
  default:
unknown's avatar
unknown committed
1255
    my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
1256 1257
    break;
  }
1258 1259
  if (thd->lock || thd->open_tables || thd->derived_tables ||
      thd->prelocked_mode)
unknown's avatar
unknown committed
1260 1261 1262 1263
  {
    thd->proc_info="closing tables";
    close_thread_tables(thd);			/* Free tables */
  }
1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
  /*
    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())
1274
    thd->transaction.xid_state.xid.null();
unknown's avatar
unknown committed
1275

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

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

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


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

  /*
    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
1309
    DBUG_VOID_RETURN;                           // Don't set time for sub stmt
1310 1311

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

1314 1315 1316 1317 1318
  /*
    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
1319
  {
1320 1321
    thd->proc_info="logging slow query";

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

1335

unknown's avatar
unknown committed
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 1363
/*
  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.
*/

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

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

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

1403
      if (check_db_name(&db))
1404
      {
1405
        my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
1406 1407 1408 1409 1410 1411 1412
        DBUG_RETURN(1);
      }
      break;
    }
#endif
  case SCH_COLUMNS:
  case SCH_STATISTICS:
unknown's avatar
unknown committed
1413
  {
1414
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1415 1416
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1417 1418
    DBUG_RETURN(1);
#else
unknown's avatar
unknown committed
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429
    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;
  }
1430
#endif
1431 1432 1433
  case SCH_OPEN_TABLES:
  case SCH_VARIABLES:
  case SCH_STATUS:
1434 1435
  case SCH_PROCEDURES:
  case SCH_CHARSETS:
unknown's avatar
unknown committed
1436
  case SCH_ENGINES:
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
  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
1455
  table_list->schema_select_lex= schema_select_lex;
1456
  table_list->schema_table_reformed= 1;
1457 1458 1459 1460
  DBUG_RETURN(0);
}


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

  DESCRIPTION
    Sets the following THD variables:
      query
      query_length

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

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

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

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

1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520
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;
1521
  thd->variables.lc_time_names= &my_locale_en_US;
1522 1523 1524
  thd->one_shot_set= 0;
}

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

1572
    if (thd->slave_thread && lex->sphead)
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 1610
      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);
}


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

  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
1634

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

unknown's avatar
VIEW  
unknown committed
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672
  /*
    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();
1673
  /* should be assigned after making first tables same */
unknown's avatar
VIEW  
unknown committed
1674
  all_tables= lex->query_tables;
1675 1676 1677 1678
  /* 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
1679

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

unknown's avatar
SCRUM  
unknown committed
1691
#ifdef HAVE_REPLICATION
1692
  if (unlikely(thd->slave_thread))
1693
  {
1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717
    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
1718
    /*
unknown's avatar
unknown committed
1719 1720
      Check if statment should be skipped because of slave filtering
      rules
1721 1722

      Exceptions are:
unknown's avatar
unknown committed
1723 1724
      - UPDATE MULTI: For this statement, we want to check the filtering
        rules later in the code
1725
      - SET: we always execute it (Not that many SET commands exists in
unknown's avatar
unknown committed
1726 1727
        the binary log anyway -- only 4.1 masters write SET statements,
	in 5.0 there are no SET statements in the binary log)
1728 1729
      - 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
1730
    */
unknown's avatar
unknown committed
1731 1732
    if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
	!(lex->sql_command == SQLCOM_SET_OPTION) &&
1733
	!(lex->sql_command == SQLCOM_DROP_TABLE &&
1734
          lex->drop_temporary && lex->drop_if_exists) &&
unknown's avatar
Merge  
unknown committed
1735
        all_tables_not_ok(thd, all_tables))
unknown's avatar
unknown committed
1736 1737
    {
      /* we warn the slave SQL thread */
unknown's avatar
unknown committed
1738
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755
      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);
      }
1756
      DBUG_RETURN(0);
unknown's avatar
unknown committed
1757
    }
1758
  }
1759
  else
1760
  {
1761
#endif /* HAVE_REPLICATION */
1762 1763 1764 1765 1766 1767
    /*
      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) &&
1768
	(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA) &&
1769 1770 1771 1772 1773
        !((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)))
1774 1775 1776 1777 1778 1779 1780
    {
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
      DBUG_RETURN(-1);
    }
#ifdef HAVE_REPLICATION
  } /* endif unlikely slave */
#endif
1781
  status_var_increment(thd->status_var.com_stat[lex->sql_command]);
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:
1823
  case SQLCOM_SHOW_STORAGE_ENGINES:
unknown's avatar
unknown committed
1824
  case SQLCOM_SELECT:
1825
    thd->status_var.last_query_cost= 0.0;
unknown's avatar
VIEW  
unknown committed
1826
    if (all_tables)
unknown's avatar
unknown committed
1827
    {
1828 1829 1830 1831
      res= check_table_access(thd,
                              lex->exchange ? SELECT_ACL | FILE_ACL :
                              SELECT_ACL,
                              all_tables, 0);
unknown's avatar
unknown committed
1832 1833
    }
    else
unknown's avatar
VIEW  
unknown committed
1834
      res= check_access(thd,
1835 1836 1837 1838
                        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
1839
    break;
unknown's avatar
unknown committed
1840
  case SQLCOM_PREPARE:
1841
  {
1842
    mysql_sql_stmt_prepare(thd);
unknown's avatar
unknown committed
1843 1844 1845 1846
    break;
  }
  case SQLCOM_EXECUTE:
  {
1847
    mysql_sql_stmt_execute(thd);
unknown's avatar
unknown committed
1848 1849 1850 1851
    break;
  }
  case SQLCOM_DEALLOCATE_PREPARE:
  {
1852
    mysql_sql_stmt_close(thd);
unknown's avatar
unknown committed
1853 1854
    break;
  }
unknown's avatar
unknown committed
1855
  case SQLCOM_DO:
1856 1857
    if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
        open_and_lock_tables(thd, all_tables))
unknown's avatar
unknown committed
1858
      goto error;
unknown's avatar
unknown committed
1859 1860

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

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

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

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

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

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

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

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

unknown's avatar
VIEW  
unknown committed
2051
    if (check_access(thd, CREATE_ACL, first_table->db,
2052 2053
		     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
unknown's avatar
unknown committed
2054
      goto error;				/* purecov: inspected */
2055 2056 2057 2058
    /* Check that the first table has CREATE privilege */
    if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
      goto error;

2059
    pthread_mutex_lock(&LOCK_active_mi);
2060 2061 2062 2063
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
2064
    if (!fetch_master_table(thd, first_table->db, first_table->table_name,
2065
			    active_mi, 0, 0))
2066
    {
2067
      send_ok(thd);
2068
    }
2069
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2070
    break;
2071
  }
unknown's avatar
unknown committed
2072
#endif /* HAVE_REPLICATION */
2073

unknown's avatar
unknown committed
2074
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
2075
  {
2076
    /* If CREATE TABLE of non-temporary table, do implicit commit */
2077 2078 2079 2080 2081 2082 2083 2084
    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
    {
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
unknown's avatar
VIEW  
unknown committed
2085 2086 2087 2088 2089
    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;
2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110
    /*
      Code below (especially in mysql_create_table() and select_create
      methods) may modify HA_CREATE_INFO structure in LEX, so we have to
      use a copy of this structure to make execution prepared statement-
      safe. A shallow copy is enough as this code won't modify any memory
      referenced from this structure.
    */
    HA_CREATE_INFO create_info(lex->create_info);
    /*
      We need to copy alter_info for the same reasons of re-execution
      safety, only in case of Alter_info we have to do (almost) a deep
      copy.
    */
    Alter_info alter_info(lex->alter_info, thd->mem_root);

    if (thd->is_fatal_error)
    {
      /* If out of memory when creating a copy of alter_info. */
      res= 1;
      goto end_with_restore_list;
    }
unknown's avatar
unknown committed
2111

unknown's avatar
VIEW  
unknown committed
2112
    if ((res= create_table_precheck(thd, select_tables, create_table)))
unknown's avatar
unknown committed
2113
      goto end_with_restore_list;
unknown's avatar
unknown committed
2114

2115 2116 2117
    /* Might have been updated in create_table_precheck */
    create_info.alias= create_table->alias;

2118
#ifndef HAVE_READLINK
2119
    if (create_info.data_file_name)
2120 2121
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                   "DATA DIRECTORY option ignored");
2122
    if (create_info.index_file_name)
2123 2124
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                   "INDEX DIRECTORY option ignored");
2125
    create_info.data_file_name= create_info.index_file_name= NULL;
2126
#else
2127
    /* Fix names if symlinked tables */
2128
    if (append_file_to_dir(thd, &create_info.data_file_name,
2129
			   create_table->table_name) ||
2130
	append_file_to_dir(thd, &create_info.index_file_name,
2131
			   create_table->table_name))
unknown's avatar
unknown committed
2132
      goto end_with_restore_list;
2133
#endif
2134
    /*
2135
      If we are using SET CHARSET without DEFAULT, add an implicit
2136 2137
      DEFAULT to not confuse old users. (This may change).
    */
2138
    if ((create_info.used_fields &
2139 2140 2141
	 (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
	HA_CREATE_USED_CHARSET)
    {
2142 2143 2144 2145
      create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
      create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
      create_info.default_table_charset= create_info.table_charset;
      create_info.table_charset= 0;
2146
    }
2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159
    /*
      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.
    */
2160 2161
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
2162
    {
unknown's avatar
unknown committed
2163 2164
      res= 1;
      goto end_with_restore_list;
2165
    }
2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176
#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
2177
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
2178 2179
    {
      select_result *result;
2180

2181
      select_lex->options|= SELECT_NO_UNLOCK;
2182
      unit->set_limit(select_lex);
2183

2184
      if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
unknown's avatar
unknown committed
2185 2186 2187 2188 2189 2190
      {
        lex->link_first_table_back(create_table, link_to_local);
        create_table->create= TRUE;
      }

      if (!(res= open_and_lock_tables(thd, lex->query_tables)))
2191
      {
2192 2193 2194 2195
        /*
          Is table which we are changing used somewhere in other parts
          of query
        */
2196
        if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
2197
        {
2198
          TABLE_LIST *duplicate;
unknown's avatar
unknown committed
2199
          create_table= lex->unlink_first_table(&link_to_local);
2200
          if ((duplicate= unique_table(thd, create_table, select_tables, 0)))
2201 2202 2203
          {
            update_non_unique_table_error(create_table, "CREATE", duplicate);
            res= 1;
2204
            goto end_with_restore_list;
2205
          }
2206
        }
unknown's avatar
unknown committed
2207
        /* If we create merge table, we have to test tables in merge, too */
2208
        if (create_info.used_fields & HA_CREATE_USED_UNION)
unknown's avatar
unknown committed
2209 2210
        {
          TABLE_LIST *tab;
2211
          for (tab= (TABLE_LIST*) create_info.merge_list.first;
unknown's avatar
unknown committed
2212 2213 2214
               tab;
               tab= tab->next_local)
          {
2215
            TABLE_LIST *duplicate;
2216
            if ((duplicate= unique_table(thd, tab, select_tables, 0)))
unknown's avatar
unknown committed
2217
            {
2218
              update_non_unique_table_error(tab, "CREATE", duplicate);
unknown's avatar
unknown committed
2219
              res= 1;
2220
              goto end_with_restore_list;
unknown's avatar
unknown committed
2221 2222 2223
            }
          }
        }
2224

unknown's avatar
unknown committed
2225
        /*
2226 2227
          select_create is currently not re-execution friendly and
          needs to be created for every execution of a PS/SP.
unknown's avatar
unknown committed
2228
        */
unknown's avatar
VIEW  
unknown committed
2229
        if ((result= new select_create(create_table,
2230 2231 2232 2233 2234
                                       &create_info,
                                       &alter_info,
                                       select_lex->item_list,
                                       lex->duplicates,
                                       lex->ignore)))
2235 2236 2237 2238 2239
        {
          /*
            CREATE from SELECT give its SELECT_LEX for SELECT,
            and item_list belong to SELECT
          */
2240
          res= handle_select(thd, lex, result, 0);
2241
          delete result;
2242
        }
2243
      }
2244
      else if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
unknown's avatar
unknown committed
2245 2246
        create_table= lex->unlink_first_table(&link_to_local);

2247
    }
unknown's avatar
unknown committed
2248
    else
unknown's avatar
unknown committed
2249
    {
2250
      /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
2251
      if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
2252
        thd->options|= OPTION_KEEP_LOG;
unknown's avatar
unknown committed
2253
      /* regular create */
2254
      if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
unknown's avatar
unknown committed
2255
        res= mysql_create_like_table(thd, create_table, select_tables,
2256
                                     &create_info);
unknown's avatar
unknown committed
2257
      else
2258
      {
unknown's avatar
VIEW  
unknown committed
2259
        res= mysql_create_table(thd, create_table->db,
2260 2261
                                create_table->table_name, &create_info,
                                &alter_info, 0, 0);
2262
      }
unknown's avatar
unknown committed
2263
      if (!res)
2264
	send_ok(thd);
unknown's avatar
unknown committed
2265
    }
2266

unknown's avatar
unknown committed
2267
    /* put tables back for PS rexecuting */
unknown's avatar
unknown committed
2268
end_with_restore_list:
unknown's avatar
VIEW  
unknown committed
2269
    lex->link_first_table_back(create_table, link_to_local);
unknown's avatar
unknown committed
2270
    break;
unknown's avatar
unknown committed
2271
  }
unknown's avatar
unknown committed
2272
  case SQLCOM_CREATE_INDEX:
2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290
    /* Fall through */
  case SQLCOM_DROP_INDEX:
  /*
    CREATE INDEX and DROP INDEX are implemented by calling ALTER
    TABLE with proper arguments.

    In the future ALTER TABLE will notice that the request is to
    only add indexes and create these one by one for the existing
    table without having to do a full rebuild.
  */
  {
    /* Prepare stack copies to be re-execution safe */
    HA_CREATE_INFO create_info;
    Alter_info alter_info(lex->alter_info, thd->mem_root);

    if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
      goto error;

unknown's avatar
VIEW  
unknown committed
2291 2292
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, INDEX_ACL, all_tables))
unknown's avatar
unknown committed
2293
      goto error; /* purecov: inspected */
2294
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2295
      goto error;
2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306
    /*
      Currently CREATE INDEX or DROP INDEX cause a full table rebuild
      and thus classify as slow administrative statements just like
      ALTER TABLE.
    */
    thd->enable_slow_log= opt_log_slow_admin_statements;

    bzero((char*) &create_info, sizeof(create_info));
    create_info.db_type= 0;
    create_info.row_type= ROW_TYPE_NOT_USED;
    create_info.default_table_charset= thd->variables.collation_database;
unknown's avatar
unknown committed
2307

2308 2309 2310 2311 2312
    res= mysql_alter_table(thd, first_table->db, first_table->table_name,
                           &create_info, first_table, &alter_info,
                           0, (ORDER*) 0, 0);
    break;
  }
unknown's avatar
unknown committed
2313
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2314
  case SQLCOM_SLAVE_START:
2315
  {
2316
    pthread_mutex_lock(&LOCK_active_mi);
2317
    start_slave(thd,active_mi,1 /* net report*/);
2318
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2319
    break;
2320
  }
unknown's avatar
unknown committed
2321
  case SQLCOM_SLAVE_STOP:
2322 2323 2324 2325 2326 2327
  /*
    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,
2328
      so it waits for the client thread because t is locked by it.
2329
    - then the client thread does SLAVE STOP.
2330 2331
      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.
2332 2333 2334
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
2335
  if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock)
2336
  {
2337 2338
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
2339
    goto error;
2340
  }
2341
  {
2342
    pthread_mutex_lock(&LOCK_active_mi);
2343
    stop_slave(thd,active_mi,1/* net report*/);
2344
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2345
    break;
2346
  }
unknown's avatar
unknown committed
2347
#endif /* HAVE_REPLICATION */
2348

unknown's avatar
unknown committed
2349
  case SQLCOM_ALTER_TABLE:
unknown's avatar
VIEW  
unknown committed
2350
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2351
    {
unknown's avatar
unknown committed
2352
      ulong priv=0;
unknown's avatar
unknown committed
2353
      ulong priv_needed= ALTER_ACL;
2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364
      /*
        Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
        so we have to use a copy of this structure to make execution
        prepared statement- safe. A shallow copy is enough as no memory
        referenced from this structure will be modified.
      */
      HA_CREATE_INFO create_info(lex->create_info);
      Alter_info alter_info(lex->alter_info, thd->mem_root);

      if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
        goto error;
2365 2366 2367 2368
      /*
        We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
        as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
      */
2369
      if (alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME))
unknown's avatar
unknown committed
2370 2371
        priv_needed|= DROP_ACL;

unknown's avatar
unknown committed
2372 2373
      /* Must be set in the parser */
      DBUG_ASSERT(select_lex->db);
unknown's avatar
unknown committed
2374
      if (check_access(thd, priv_needed, first_table->db,
2375 2376 2377 2378
		       &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
2379
	  check_merge_table_access(thd, first_table->db,
2380
				   (TABLE_LIST *)
2381
				   create_info.merge_list.first))
2382
	goto error;				/* purecov: inspected */
2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394
      if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0))
        goto error;
      if (lex->name.str && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
      { // Rename of table
          TABLE_LIST tmp_table;
          bzero((char*) &tmp_table,sizeof(tmp_table));
          tmp_table.table_name= lex->name.str;
          tmp_table.db=select_lex->db;
          tmp_table.grant.privilege=priv;
          if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
              UINT_MAX, 0))
            goto error;
unknown's avatar
unknown committed
2395
      }
2396

2397
      /* Don't yet allow changing of symlinks with ALTER TABLE */
2398
      if (create_info.data_file_name)
2399 2400
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                     "DATA DIRECTORY option ignored");
2401
      if (create_info.index_file_name)
2402 2403
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                     "INDEX DIRECTORY option ignored");
2404
      create_info.data_file_name= create_info.index_file_name= NULL;
unknown's avatar
unknown committed
2405
      /* ALTER TABLE ends previous transaction */
2406
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2407
	goto error;
2408

2409 2410 2411 2412 2413
      if (!thd->locked_tables &&
          !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
      {
        res= 1;
        break;
unknown's avatar
unknown committed
2414
      }
2415

2416
      thd->enable_slow_log= opt_log_slow_admin_statements;
2417
      res= mysql_alter_table(thd, select_lex->db, lex->name.str,
2418 2419 2420
                             &create_info,
                             first_table,
                             &alter_info,
2421 2422
                             select_lex->order_list.elements,
                             (ORDER *) select_lex->order_list.first,
2423
                             lex->ignore);
unknown's avatar
unknown committed
2424 2425
      break;
    }
unknown's avatar
unknown committed
2426
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
2427
  {
unknown's avatar
VIEW  
unknown committed
2428
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2429
    TABLE_LIST *table;
unknown's avatar
VIEW  
unknown committed
2430
    for (table= first_table; table; table= table->next_local->next_local)
unknown's avatar
unknown committed
2431
    {
unknown's avatar
unknown committed
2432
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
2433
		       &table->grant.privilege,0,0, test(table->schema_table)) ||
unknown's avatar
VIEW  
unknown committed
2434
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
2435 2436
		       &table->next_local->grant.privilege, 0, 0,
                       test(table->next_local->schema_table)))
unknown's avatar
unknown committed
2437
	goto error;
2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449
      TABLE_LIST old_list, new_list;
      /*
        we do not need initialize old_list and new_list because we will
        come table[0] and table->next[0] there
      */
      old_list= table[0];
      new_list= table->next_local[0];
      if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, 0, 1, 0) ||
         (!test_all_bits(table->next_local->grant.privilege,
                         INSERT_ACL | CREATE_ACL) &&
          check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
        goto error;
unknown's avatar
unknown committed
2450
    }
unknown's avatar
VIEW  
unknown committed
2451
    query_cache_invalidate3(thd, first_table, 0);
unknown's avatar
unknown committed
2452
    if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
unknown's avatar
unknown committed
2453
      goto error;
unknown's avatar
unknown committed
2454
    break;
unknown's avatar
unknown committed
2455
  }
2456
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2457 2458
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2459 2460
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2461
    goto error;
unknown's avatar
unknown committed
2462 2463
#else
    {
unknown's avatar
unknown committed
2464
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2465 2466 2467 2468
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
2469
#endif
2470
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2471
  case SQLCOM_SHOW_CREATE:
unknown's avatar
VIEW  
unknown committed
2472
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2473
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2474 2475
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2476
    goto error;
unknown's avatar
unknown committed
2477
#else
unknown's avatar
unknown committed
2478
    {
2479 2480 2481
      /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
      if (lex->only_view)
        first_table->skip_temporary= 1;
unknown's avatar
unknown committed
2482
      if (check_show_create_table_access(thd, first_table))
2483
	goto error;
unknown's avatar
unknown committed
2484
      res= mysqld_show_create(thd, first_table);
unknown's avatar
unknown committed
2485 2486
      break;
    }
unknown's avatar
unknown committed
2487
#endif
2488 2489
  case SQLCOM_CHECKSUM:
  {
unknown's avatar
VIEW  
unknown committed
2490
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2491
    if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, 0))
2492
      goto error; /* purecov: inspected */
unknown's avatar
VIEW  
unknown committed
2493
    res = mysql_checksum_table(thd, first_table, &lex->check_opt);
2494 2495
    break;
  }
unknown's avatar
unknown committed
2496
  case SQLCOM_REPAIR:
2497
  {
unknown's avatar
VIEW  
unknown committed
2498
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2499
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
2500
      goto error; /* purecov: inspected */
2501
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2502
    res= mysql_repair_table(thd, first_table, &lex->check_opt);
2503 2504 2505
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
2506 2507 2508
      /*
        Presumably, REPAIR and binlog writing doesn't require synchronization
      */
2509 2510
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
2511
	thd->clear_error(); // No binlog error generated
unknown's avatar
unknown committed
2512 2513
        thd->binlog_query(THD::STMT_QUERY_TYPE,
                          thd->query, thd->query_length, 0, FALSE);
2514 2515
      }
    }
2516
    select_lex->table_list.first= (uchar*) first_table;
2517
    lex->query_tables=all_tables;
2518 2519
    break;
  }
unknown's avatar
unknown committed
2520
  case SQLCOM_CHECK:
2521
  {
unknown's avatar
VIEW  
unknown committed
2522
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2523
    if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0))
2524
      goto error; /* purecov: inspected */
2525
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2526
    res = mysql_check_table(thd, first_table, &lex->check_opt);
2527
    select_lex->table_list.first= (uchar*) first_table;
2528
    lex->query_tables=all_tables;
2529 2530
    break;
  }
unknown's avatar
unknown committed
2531 2532
  case SQLCOM_ANALYZE:
  {
unknown's avatar
VIEW  
unknown committed
2533
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2534
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
unknown's avatar
unknown committed
2535
      goto error; /* purecov: inspected */
2536
    thd->enable_slow_log= opt_log_slow_admin_statements;
2537
    res= mysql_analyze_table(thd, first_table, &lex->check_opt);
2538 2539 2540
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
2541 2542 2543
      /*
        Presumably, ANALYZE and binlog writing doesn't require synchronization
      */
2544 2545
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
2546
	thd->clear_error(); // No binlog error generated
unknown's avatar
unknown committed
2547 2548
        thd->binlog_query(THD::STMT_QUERY_TYPE,
                          thd->query, thd->query_length, 0, FALSE);
2549 2550
      }
    }
2551
    select_lex->table_list.first= (uchar*) first_table;
2552
    lex->query_tables=all_tables;
unknown's avatar
unknown committed
2553
    break;
unknown's avatar
unknown committed
2554
  }
2555

unknown's avatar
unknown committed
2556 2557
  case SQLCOM_OPTIMIZE:
  {
unknown's avatar
VIEW  
unknown committed
2558
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2559
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
unknown's avatar
unknown committed
2560
      goto error; /* purecov: inspected */
2561
    thd->enable_slow_log= opt_log_slow_admin_statements;
2562
    res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
2563
      mysql_recreate_table(thd, first_table) :
unknown's avatar
VIEW  
unknown committed
2564
      mysql_optimize_table(thd, first_table, &lex->check_opt);
2565 2566 2567
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
2568 2569 2570
      /*
        Presumably, OPTIMIZE and binlog writing doesn't require synchronization
      */
2571 2572
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
2573
	thd->clear_error(); // No binlog error generated
unknown's avatar
unknown committed
2574 2575
        thd->binlog_query(THD::STMT_QUERY_TYPE,
                          thd->query, thd->query_length, 0, FALSE);
2576 2577
      }
    }
2578
    select_lex->table_list.first= (uchar*) first_table;
2579
    lex->query_tables=all_tables;
unknown's avatar
unknown committed
2580 2581 2582
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
VIEW  
unknown committed
2583 2584
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (update_precheck(thd, all_tables))
unknown's avatar
unknown committed
2585
      break;
2586 2587
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
unknown's avatar
unknown committed
2588 2589 2590 2591 2592 2593 2594 2595
    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));
2596
    /* mysql_update return 2 if we need to switch to multi-update */
unknown's avatar
unknown committed
2597
    if (up_result != 2)
2598
      break;
unknown's avatar
unknown committed
2599
    /* Fall through */
2600
  case SQLCOM_UPDATE_MULTI:
unknown's avatar
unknown committed
2601 2602 2603
  {
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    /* if we switched from normal update, rights are checked */
unknown's avatar
unknown committed
2604
    if (up_result != 2)
2605
    {
unknown's avatar
unknown committed
2606 2607 2608 2609 2610
      if ((res= multi_update_precheck(thd, all_tables)))
        break;
    }
    else
      res= 0;
unknown's avatar
unknown committed
2611

2612
    res= mysql_multi_update_prepare(thd);
unknown's avatar
unknown committed
2613

2614
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2615
    /* Check slave filtering rules */
2616
    if (unlikely(thd->slave_thread))
unknown's avatar
unknown committed
2617
    {
2618 2619
      if (all_tables_not_ok(thd, all_tables))
      {
2620 2621 2622 2623 2624
        if (res!= 0)
        {
          res= 0;             /* don't care of prev failure  */
          thd->clear_error(); /* filters are of highest prior */
        }
2625 2626 2627 2628
        /* we warn the slave SQL thread */
        my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
        break;
      }
2629 2630
      if (res)
        break;
unknown's avatar
unknown committed
2631
    }
2632 2633
    else
    {
2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646
#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
2647

unknown's avatar
unknown committed
2648 2649 2650 2651 2652 2653
    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
2654
    break;
unknown's avatar
unknown committed
2655
  }
unknown's avatar
unknown committed
2656
  case SQLCOM_REPLACE:
2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686
#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
2687 2688
  case SQLCOM_INSERT:
  {
unknown's avatar
VIEW  
unknown committed
2689
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2690
    if ((res= insert_precheck(thd, all_tables)))
unknown's avatar
unknown committed
2691
      break;
2692 2693 2694 2695 2696 2697 2698 2699

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

unknown's avatar
VIEW  
unknown committed
2700
    res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
unknown's avatar
unknown committed
2701
		      lex->update_list, lex->value_list,
2702
                      lex->duplicates, lex->ignore);
2703 2704 2705 2706 2707 2708 2709

    /*
      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
2710
    if (first_table->view && !first_table->contain_auto_increment)
2711 2712
      thd->first_successful_insert_id_in_cur_stmt=
        thd->first_successful_insert_id_in_prev_stmt;
2713

unknown's avatar
unknown committed
2714
    break;
2715
  }
unknown's avatar
unknown committed
2716 2717 2718
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
unknown's avatar
unknown committed
2719
    select_result *sel_result;
unknown's avatar
VIEW  
unknown committed
2720
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2721
    if ((res= insert_precheck(thd, all_tables)))
2722
      break;
unknown's avatar
unknown committed
2723

2724
    /* Fix lock for first table */
unknown's avatar
VIEW  
unknown committed
2725 2726
    if (first_table->lock_type == TL_WRITE_DELAYED)
      first_table->lock_type= TL_WRITE;
2727

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

2731
    unit->set_limit(select_lex);
2732 2733 2734 2735 2736 2737 2738 2739

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

unknown's avatar
VIEW  
unknown committed
2740
    if (!(res= open_and_lock_tables(thd, all_tables)))
2741
    {
2742
      /* Skip first table, which is the table we are inserting in */
unknown's avatar
unknown committed
2743
      TABLE_LIST *second_table= first_table->next_local;
2744
      select_lex->table_list.first= (uchar*) second_table;
2745 2746
      select_lex->context.table_list= 
        select_lex->context.first_name_resolution_table= second_table;
2747
      res= mysql_insert_select_prepare(thd);
unknown's avatar
unknown committed
2748 2749 2750 2751 2752 2753 2754
      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)))
2755
      {
unknown's avatar
unknown committed
2756
	res= handle_select(thd, lex, sel_result, OPTION_SETUP_TABLES_DONE);
2757 2758 2759 2760 2761 2762 2763 2764 2765
        /*
          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)
        {
2766 2767 2768
          /* INSERT ... SELECT should invalidate only the very first table */
          TABLE_LIST *save_table= first_table->next_local;
          first_table->next_local= 0;
2769 2770
          mysql_unlock_tables(thd, thd->lock);
          query_cache_invalidate3(thd, first_table, 1);
2771
          first_table->next_local= save_table;
2772 2773
          thd->lock=0;
        }
unknown's avatar
unknown committed
2774
        delete sel_result;
2775
      }
2776
      /* revert changes for SP */
2777
      select_lex->table_list.first= (uchar*) first_table;
2778
    }
unknown's avatar
VIEW  
unknown committed
2779

2780 2781 2782 2783 2784 2785
    /*
      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
2786
    if (first_table->view && !first_table->contain_auto_increment)
2787 2788
      thd->first_successful_insert_id_in_cur_stmt=
        thd->first_successful_insert_id_in_prev_stmt;
2789

unknown's avatar
unknown committed
2790 2791
    break;
  }
2792
  case SQLCOM_TRUNCATE:
2793 2794 2795 2796 2797
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
VIEW  
unknown committed
2798
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2799
    if (check_one_table_access(thd, DROP_ACL, all_tables))
unknown's avatar
unknown committed
2800
      goto error;
2801 2802 2803 2804
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
2805
    if (thd->locked_tables || thd->active_transaction())
2806
    {
unknown's avatar
unknown committed
2807 2808
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
2809 2810
      goto error;
    }
unknown's avatar
VIEW  
unknown committed
2811

unknown's avatar
unknown committed
2812
    res= mysql_truncate(thd, first_table, 0);
2813
    break;
unknown's avatar
unknown committed
2814
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
2815
  {
unknown's avatar
VIEW  
unknown committed
2816 2817
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if ((res= delete_precheck(thd, all_tables)))
unknown's avatar
unknown committed
2818
      break;
2819 2820
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
2821 2822 2823 2824 2825 2826 2827 2828

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

unknown's avatar
VIEW  
unknown committed
2829
    res = mysql_delete(thd, all_tables, select_lex->where,
2830
                       &select_lex->order_list,
unknown's avatar
unknown committed
2831 2832
                       unit->select_limit_cnt, select_lex->options,
                       FALSE);
unknown's avatar
unknown committed
2833 2834
    break;
  }
2835
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
2836
  {
unknown's avatar
VIEW  
unknown committed
2837
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2838
    TABLE_LIST *aux_tables=
unknown's avatar
unknown committed
2839
      (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
unknown's avatar
unknown committed
2840
    multi_delete *del_result;
unknown's avatar
unknown committed
2841

2842 2843 2844 2845 2846 2847 2848
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
    {
      res= 1;
      break;
    }

2849
    if ((res= multi_delete_precheck(thd, all_tables)))
2850
      break;
unknown's avatar
unknown committed
2851

unknown's avatar
unknown committed
2852
    /* condition will be TRUE on SP re-excuting */
2853 2854
    if (select_lex->item_list.elements != 0)
      select_lex->item_list.empty();
unknown's avatar
unknown committed
2855
    if (add_item_to_list(thd, new Item_null()))
unknown's avatar
unknown committed
2856
      goto error;
2857

unknown's avatar
unknown committed
2858
    thd->proc_info="init";
unknown's avatar
VIEW  
unknown committed
2859 2860 2861 2862
    if ((res= open_and_lock_tables(thd, all_tables)))
      break;

    if ((res= mysql_multi_delete_prepare(thd)))
unknown's avatar
unknown committed
2863
      goto error;
2864

unknown's avatar
unknown committed
2865 2866
    if (!thd->is_fatal_error &&
        (del_result= new multi_delete(aux_tables, lex->table_count)))
unknown's avatar
unknown committed
2867
    {
2868 2869 2870
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
2871
			select_lex->item_list,
unknown's avatar
unknown committed
2872
			select_lex->where,
2873
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
unknown's avatar
unknown committed
2874 2875
			(ORDER *)NULL,
			select_lex->options | thd->options |
2876 2877
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
                        OPTION_SETUP_TABLES_DONE,
unknown's avatar
unknown committed
2878 2879
			del_result, unit, select_lex);
      delete del_result;
unknown's avatar
unknown committed
2880 2881
    }
    else
2882
      res= TRUE;                                // Error
unknown's avatar
unknown committed
2883 2884
    break;
  }
unknown's avatar
unknown committed
2885
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
2886
  {
unknown's avatar
VIEW  
unknown committed
2887
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2888 2889
    if (!lex->drop_temporary)
    {
unknown's avatar
VIEW  
unknown committed
2890
      if (check_table_access(thd, DROP_ACL, all_tables, 0))
2891 2892
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2893
        goto error;
2894
    }
unknown's avatar
unknown committed
2895
    else
unknown's avatar
unknown committed
2896 2897 2898 2899 2900 2901
    {
      /*
	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
2902 2903
	To not generate such irrelevant "table does not exist errors",
	we silently add IF EXISTS if TEMPORARY was used.
unknown's avatar
unknown committed
2904 2905
      */
      if (thd->slave_thread)
2906
        lex->drop_if_exists= 1;
2907

unknown's avatar
unknown committed
2908
      /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
2909
      thd->options|= OPTION_KEEP_LOG;
unknown's avatar
unknown committed
2910
    }
2911
    /* DDL and binlog write order protected by LOCK_open */
unknown's avatar
VIEW  
unknown committed
2912 2913
    res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
			lex->drop_temporary);
unknown's avatar
unknown committed
2914 2915
  }
  break;
unknown's avatar
unknown committed
2916
  case SQLCOM_SHOW_PROCESSLIST:
2917 2918
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
2919
      break;
unknown's avatar
unknown committed
2920
    mysqld_list_processes(thd,
2921 2922 2923 2924
			  (thd->security_ctx->master_access & PROCESS_ACL ?
                           NullS :
                           thd->security_ctx->priv_user),
                          lex->verbose);
unknown's avatar
unknown committed
2925
    break;
unknown's avatar
unknown committed
2926 2927 2928
  case SQLCOM_SHOW_AUTHORS:
    res= mysqld_show_authors(thd);
    break;
2929 2930 2931
  case SQLCOM_SHOW_CONTRIBUTORS:
    res= mysqld_show_contributors(thd);
    break;
unknown's avatar
unknown committed
2932 2933 2934 2935 2936 2937
  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
2938
  case SQLCOM_SHOW_ENGINE_LOGS:
unknown's avatar
unknown committed
2939
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2940 2941
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
2942
    goto error;
unknown's avatar
unknown committed
2943 2944
#else
    {
2945
      if (check_access(thd, FILE_ACL, any_db,0,0,0,0))
unknown's avatar
unknown committed
2946
	goto error;
unknown's avatar
unknown committed
2947
      res= ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_LOGS);
unknown's avatar
unknown committed
2948 2949
      break;
    }
unknown's avatar
unknown committed
2950 2951
#endif
  case SQLCOM_CHANGE_DB:
2952 2953 2954 2955
  {
    LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) };

    if (!mysql_change_db(thd, &db_str, FALSE))
2956
      send_ok(thd);
2957

unknown's avatar
unknown committed
2958
    break;
2959
  }
2960

unknown's avatar
unknown committed
2961 2962
  case SQLCOM_LOAD:
  {
unknown's avatar
VIEW  
unknown committed
2963
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2964
    uint privilege= (lex->duplicates == DUP_REPLACE ?
unknown's avatar
unknown committed
2965 2966
		     INSERT_ACL | DELETE_ACL : INSERT_ACL) |
                    (lex->local_file ? 0 : FILE_ACL);
2967

unknown's avatar
unknown committed
2968
    if (lex->local_file)
unknown's avatar
unknown committed
2969
    {
2970
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
2971
          !opt_local_infile)
2972
      {
unknown's avatar
unknown committed
2973
	my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0));
2974 2975
	goto error;
      }
unknown's avatar
unknown committed
2976
    }
unknown's avatar
unknown committed
2977 2978 2979 2980

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

unknown's avatar
VIEW  
unknown committed
2981
    res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
unknown's avatar
unknown committed
2982
                    lex->update_list, lex->value_list, lex->duplicates,
2983
                    lex->ignore, (bool) lex->local_file);
unknown's avatar
unknown committed
2984 2985
    break;
  }
2986

unknown's avatar
unknown committed
2987
  case SQLCOM_SET_OPTION:
2988 2989
  {
    List<set_var_base> *lex_var_list= &lex->var_list;
2990
    if ((check_table_access(thd, SELECT_ACL, all_tables, 0) ||
unknown's avatar
unknown committed
2991 2992
	 open_and_lock_tables(thd, all_tables)))
      goto error;
2993 2994
    if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
    {
unknown's avatar
unknown committed
2995 2996
      my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
      goto error;
2997 2998 2999 3000 3001 3002 3003 3004
    }
    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;
3005
      send_ok(thd);
3006
    }
unknown's avatar
unknown committed
3007
    break;
3008
  }
unknown's avatar
unknown committed
3009

unknown's avatar
unknown committed
3010
  case SQLCOM_UNLOCK_TABLES:
3011 3012 3013 3014 3015 3016
    /*
      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
3017
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
3018 3019
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
3020
      end_active_trans(thd);
unknown's avatar
unknown committed
3021
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3022 3023
    }
    if (thd->global_read_lock)
3024
      unlock_global_read_lock(thd);
3025
    send_ok(thd);
unknown's avatar
unknown committed
3026 3027
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
3028
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
3029
    if (end_active_trans(thd))
unknown's avatar
unknown committed
3030
      goto error;
unknown's avatar
VIEW  
unknown committed
3031
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
3032
      goto error;
unknown's avatar
unknown committed
3033
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
3034
    thd->options|= OPTION_TABLE_LOCK;
unknown's avatar
VIEW  
unknown committed
3035

3036
    if (!(res= simple_open_n_lock_tables(thd, all_tables)))
unknown's avatar
unknown committed
3037
    {
3038 3039
#ifdef HAVE_QUERY_CACHE
      if (thd->variables.query_cache_wlock_invalidate)
unknown's avatar
VIEW  
unknown committed
3040
	query_cache.invalidate_locked_for_write(first_table);
3041
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
3042 3043
      thd->locked_tables=thd->lock;
      thd->lock=0;
3044
      send_ok(thd);
unknown's avatar
unknown committed
3045
    }
unknown's avatar
unknown committed
3046 3047
    else
      thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3048 3049 3050
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
3051
  {
3052 3053 3054 3055 3056 3057
    /*
      As mysql_create_db() may modify HA_CREATE_INFO structure passed to
      it, we need to use a copy of LEX::create_info to make execution
      prepared statement- safe.
    */
    HA_CREATE_INFO create_info(lex->create_info);
3058 3059 3060 3061 3062
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
unknown committed
3063
    char *alias;
3064 3065
    if (!(alias=thd->strmake(lex->name.str, lex->name.length)) ||
        check_db_name(&lex->name))
unknown's avatar
unknown committed
3066
    {
3067
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3068 3069
      break;
    }
3070 3071 3072
    /*
      If in a slave thread :
      CREATE DATABASE DB was certainly not preceded by USE DB.
3073
      For that reason, db_ok() in sql/slave.cc did not check the
3074 3075 3076
      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.
    */
3077
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
3078
    if (thd->slave_thread && 
3079 3080
	(!rpl_filter->db_ok(lex->name.str) ||
	 !rpl_filter->db_ok_with_wild_table(lex->name.str)))
unknown's avatar
unknown committed
3081
    {
unknown's avatar
unknown committed
3082
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3083
      break;
unknown's avatar
unknown committed
3084
    }
3085
#endif
3086 3087
    if (check_access(thd,CREATE_ACL,lex->name.str, 0, 1, 0,
                     is_schema_db(lex->name.str)))
3088
      break;
3089
    res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
3090
                              lex->name.str), &create_info, 0);
3091 3092
    break;
  }
unknown's avatar
unknown committed
3093
  case SQLCOM_DROP_DB:
3094
  {
3095 3096 3097 3098 3099
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
3100
    if (check_db_name(&lex->name))
unknown's avatar
unknown committed
3101
    {
3102
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3103 3104
      break;
    }
3105 3106 3107 3108 3109 3110 3111
    /*
      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.
    */
3112
#ifdef HAVE_REPLICATION
3113
    if (thd->slave_thread && 
3114 3115
	(!rpl_filter->db_ok(lex->name.str) ||
	 !rpl_filter->db_ok_with_wild_table(lex->name.str)))
unknown's avatar
unknown committed
3116
    {
unknown's avatar
unknown committed
3117
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3118
      break;
unknown's avatar
unknown committed
3119
    }
3120
#endif
3121 3122
    if (check_access(thd,DROP_ACL,lex->name.str,0,1,0,
                     is_schema_db(lex->name.str)))
3123
      break;
3124 3125
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3126 3127
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3128 3129
      goto error;
    }
3130
    res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0);
3131 3132
    break;
  }
unknown's avatar
unknown committed
3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155
  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
3156 3157 3158 3159 3160
    if (check_db_name(newdb))
    {
      my_error(ER_WRONG_DB_NAME, MYF(0), newdb->str);
      break;
    }
unknown's avatar
unknown committed
3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179
    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;
  }
3180 3181
  case SQLCOM_ALTER_DB:
  {
3182
    LEX_STRING *db= &lex->name;
3183
    HA_CREATE_INFO create_info(lex->create_info);
3184
    if (check_db_name(db))
3185
    {
3186
      my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
3187 3188
      break;
    }
unknown's avatar
unknown committed
3189 3190 3191
    /*
      If in a slave thread :
      ALTER DATABASE DB may not be preceded by USE DB.
3192
      For that reason, maybe db_ok() in sql/slave.cc did not check the
unknown's avatar
unknown committed
3193 3194 3195 3196
      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
3197
    if (thd->slave_thread &&
3198 3199
	(!rpl_filter->db_ok(db->str) ||
	 !rpl_filter->db_ok_with_wild_table(db->str)))
unknown's avatar
unknown committed
3200
    {
unknown's avatar
unknown committed
3201
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
unknown's avatar
unknown committed
3202 3203 3204
      break;
    }
#endif
3205
    if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0, is_schema_db(db->str)))
3206 3207 3208
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3209 3210
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3211 3212
      goto error;
    }
3213
    res= mysql_alter_db(thd, db->str, &create_info);
3214 3215
    break;
  }
unknown's avatar
unknown committed
3216 3217
  case SQLCOM_SHOW_CREATE_DB:
  {
3218
    if (check_db_name(&lex->name))
unknown's avatar
unknown committed
3219
    {
3220
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3221 3222
      break;
    }
3223
    res= mysqld_show_create_db(thd, lex->name.str, &lex->create_info);
unknown's avatar
unknown committed
3224 3225
    break;
  }
unknown's avatar
unknown committed
3226 3227
  case SQLCOM_CREATE_EVENT:
  case SQLCOM_ALTER_EVENT:
3228
  do
unknown's avatar
unknown committed
3229
  {
unknown's avatar
unknown committed
3230
    DBUG_ASSERT(lex->event_parse_data);
unknown's avatar
unknown committed
3231 3232 3233 3234 3235 3236
    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;
    }
3237 3238 3239 3240 3241

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

unknown's avatar
unknown committed
3242 3243
    switch (lex->sql_command) {
    case SQLCOM_CREATE_EVENT:
3244 3245 3246 3247
    {
      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
3248
      break;
3249
    }
unknown's avatar
unknown committed
3250
    case SQLCOM_ALTER_EVENT:
3251 3252 3253
      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
3254
      break;
3255 3256
    default:
      DBUG_ASSERT(0);
unknown's avatar
unknown committed
3257
    }
3258
    DBUG_PRINT("info",("DDL error code=%d", res));
unknown's avatar
unknown committed
3259
    if (!res)
3260
      send_ok(thd);
unknown's avatar
unknown committed
3261

3262 3263 3264 3265 3266 3267
  } 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
3268
  }
3269 3270
  /* lex->unit.cleanup() is called outside, no need to call it here */
  break;
unknown's avatar
unknown committed
3271
  case SQLCOM_SHOW_CREATE_EVENT:
3272 3273 3274 3275 3276 3277 3278 3279
    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);
3280
    break;
unknown's avatar
unknown committed
3281
  case SQLCOM_CREATE_FUNCTION:                  // UDF function
unknown's avatar
unknown committed
3282
  {
3283
    if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
unknown's avatar
unknown committed
3284
      break;
unknown's avatar
unknown committed
3285
#ifdef HAVE_DLOPEN
3286 3287
    if (sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                        &thd->sp_func_cache, FALSE))
unknown's avatar
unknown committed
3288
    {
3289
      my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str);
unknown's avatar
unknown committed
3290 3291
      goto error;
    }
3292
    if (!(res = mysql_create_function(thd, &lex->udf)))
unknown's avatar
unknown committed
3293
      send_ok(thd);
unknown's avatar
unknown committed
3294
#else
unknown's avatar
unknown committed
3295
    my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled");
unknown's avatar
unknown committed
3296
    res= TRUE;
unknown's avatar
unknown committed
3297 3298
#endif
    break;
unknown's avatar
unknown committed
3299
  }
unknown's avatar
unknown committed
3300
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3301 3302
  case SQLCOM_CREATE_USER:
  {
3303
    if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) &&
3304
        check_global_access(thd,CREATE_USER_ACL))
3305
      break;
3306 3307
    if (end_active_trans(thd))
      goto error;
3308
    /* Conditionally writes to binlog */
3309 3310 3311 3312
    if (!(res= mysql_create_user(thd, lex->users_list)))
      send_ok(thd);
    break;
  }
3313 3314
  case SQLCOM_DROP_USER:
  {
3315
    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) &&
3316
        check_global_access(thd,CREATE_USER_ACL))
3317
      break;
3318 3319
    if (end_active_trans(thd))
      goto error;
3320
    /* Conditionally writes to binlog */
3321
    if (!(res= mysql_drop_user(thd, lex->users_list)))
3322 3323 3324 3325 3326
      send_ok(thd);
    break;
  }
  case SQLCOM_RENAME_USER:
  {
3327
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
3328
        check_global_access(thd,CREATE_USER_ACL))
3329
      break;
3330 3331
    if (end_active_trans(thd))
      goto error;
3332
    /* Conditionally writes to binlog */
3333
    if (!(res= mysql_rename_user(thd, lex->users_list)))
3334 3335 3336 3337 3338
      send_ok(thd);
    break;
  }
  case SQLCOM_REVOKE_ALL:
  {
3339
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
3340
        check_global_access(thd,CREATE_USER_ACL))
3341
      break;
3342
    /* Conditionally writes to binlog */
3343 3344 3345 3346
    if (!(res = mysql_revoke_all(thd, lex->users_list)))
      send_ok(thd);
    break;
  }
3347 3348 3349 3350
  case SQLCOM_REVOKE:
  case SQLCOM_GRANT:
  {
    if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
unknown's avatar
unknown committed
3351
		     first_table ?  first_table->db : select_lex->db,
unknown's avatar
VIEW  
unknown committed
3352
		     first_table ? &first_table->grant.privilege : 0,
3353 3354 3355
		     first_table ? 0 : 1, 0,
                     first_table ? (bool) first_table->schema_table :
                     select_lex->db ? is_schema_db(select_lex->db) : 0))
3356 3357
      goto error;

3358
    if (thd->security_ctx->user)              // If not replication
unknown's avatar
unknown committed
3359
    {
3360
      LEX_USER *user, *tmp_user;
3361

unknown's avatar
unknown committed
3362
      List_iterator <LEX_USER> user_list(lex->users_list);
3363
      while ((tmp_user= user_list++))
unknown's avatar
unknown committed
3364
      {
3365 3366
        if (!(user= get_current_user(thd, tmp_user)))
          goto error;
3367 3368 3369 3370 3371 3372 3373 3374
        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);
3375
        if (strcmp(thd->security_ctx->user, user->user.str) ||
3376
            my_strcasecmp(system_charset_info,
3377
                          user->host.str, thd->security_ctx->host_or_ip))
3378 3379
        {
          // TODO: use check_change_password()
3380 3381
          if (is_acl_user(user->host.str, user->user.str) &&
              user->password.str &&
3382
              check_access(thd, UPDATE_ACL,"mysql",0,1,1,0))
3383 3384 3385 3386 3387 3388
          {
            my_message(ER_PASSWORD_NOT_ALLOWED,
                       ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
            goto error;
          }
        }
unknown's avatar
SCRUM  
unknown committed
3389 3390
      }
    }
unknown's avatar
VIEW  
unknown committed
3391
    if (first_table)
3392
    {
3393 3394
      if (lex->type == TYPE_ENUM_PROCEDURE ||
          lex->type == TYPE_ENUM_FUNCTION)
3395 3396 3397 3398
      {
        uint grants= lex->all_privileges 
		   ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
		   : lex->grant;
3399
        if (check_grant_routine(thd, grants | GRANT_ACL, all_tables,
3400
                                lex->type == TYPE_ENUM_PROCEDURE, 0))
3401
	  goto error;
3402
        /* Conditionally writes to binlog */
3403 3404 3405 3406
        res= mysql_routine_grant(thd, all_tables,
                                 lex->type == TYPE_ENUM_PROCEDURE, 
                                 lex->users_list, grants,
                                 lex->sql_command == SQLCOM_REVOKE, 0);
3407 3408 3409
      }
      else
      {
3410 3411
	if (check_grant(thd,(lex->grant | lex->grant_tot_col | GRANT_ACL),
                        all_tables, 0, UINT_MAX, 0))
3412
	  goto error;
3413
        /* Conditionally writes to binlog */
3414 3415 3416 3417
        res= mysql_table_grant(thd, all_tables, lex->users_list,
			       lex->columns, lex->grant,
			       lex->sql_command == SQLCOM_REVOKE);
      }
3418 3419 3420
    }
    else
    {
3421
      if (lex->columns.elements || lex->type)
3422
      {
unknown's avatar
unknown committed
3423 3424
	my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
                   MYF(0));
unknown's avatar
unknown committed
3425
        goto error;
3426 3427
      }
      else
3428
	/* Conditionally writes to binlog */
3429 3430 3431 3432
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
3433
	if (lex->sql_command == SQLCOM_GRANT)
3434
	{
unknown's avatar
unknown committed
3435
	  List_iterator <LEX_USER> str_list(lex->users_list);
3436 3437 3438 3439 3440
	  LEX_USER *user, *tmp_user;
	  while ((tmp_user=str_list++))
          {
            if (!(user= get_current_user(thd, tmp_user)))
              goto error;
3441
	    reset_mqh(user, 0);
3442
          }
3443
	}
3444 3445 3446 3447
      }
    }
    break;
  }
unknown's avatar
SCRUM  
unknown committed
3448
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
unknown's avatar
unknown committed
3449
  case SQLCOM_RESET:
3450 3451 3452
    /*
      RESET commands are never written to the binary log, so we have to
      initialize this variable because RESET shares the same code as FLUSH
3453 3454 3455 3456
    */
    lex->no_write_to_binlog= 1;
  case SQLCOM_FLUSH:
  {
unknown's avatar
unknown committed
3457
    bool write_to_binlog;
unknown's avatar
unknown committed
3458
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
3459
      goto error;
3460

3461 3462 3463 3464
    /*
      reload_acl_and_cache() will tell us if we are allowed to write to the
      binlog or not.
    */
unknown's avatar
unknown committed
3465
    if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
3466 3467 3468 3469 3470
    {
      /*
        We WANT to write and we CAN write.
        ! we write after unlocking the table.
      */
3471 3472 3473
      /*
        Presumably, RESET and binlog writing doesn't require synchronization
      */
3474 3475 3476 3477
      if (!lex->no_write_to_binlog && write_to_binlog)
      {
        if (mysql_bin_log.is_open())
        {
unknown's avatar
unknown committed
3478 3479
          thd->binlog_query(THD::STMT_QUERY_TYPE,
                            thd->query, thd->query_length, 0, FALSE);
3480 3481 3482
        }
      }
      send_ok(thd);
3483 3484
    } 
    
unknown's avatar
unknown committed
3485
    break;
3486
  }
unknown's avatar
unknown committed
3487
  case SQLCOM_KILL:
3488 3489 3490
  {
    Item *it= (Item *)lex->value_list.head();

unknown's avatar
unknown committed
3491 3492 3493 3494 3495 3496 3497
    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;
    }

3498
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1))
3499 3500 3501 3502 3503
    {
      my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
		 MYF(0));
      goto error;
    }
3504
    sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
unknown's avatar
unknown committed
3505
    break;
3506
  }
unknown's avatar
unknown committed
3507
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
3508
  case SQLCOM_SHOW_GRANTS:
3509 3510 3511 3512
  {
    LEX_USER *grant_user= get_current_user(thd, lex->grant_user);
    if (!grant_user)
      goto error;
3513
    if ((thd->security_ctx->priv_user &&
3514
	 !strcmp(thd->security_ctx->priv_user, grant_user->user.str)) ||
3515
	!check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
unknown's avatar
unknown committed
3516
    {
3517
      res = mysql_show_grants(thd, grant_user);
unknown's avatar
unknown committed
3518 3519
    }
    break;
3520
  }
unknown's avatar
unknown committed
3521
#endif
3522
  case SQLCOM_HA_OPEN:
unknown's avatar
VIEW  
unknown committed
3523
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3524
    if (check_table_access(thd, SELECT_ACL, all_tables, 0))
3525
      goto error;
unknown's avatar
unknown committed
3526
    res= mysql_ha_open(thd, first_table, 0);
3527 3528
    break;
  case SQLCOM_HA_CLOSE:
unknown's avatar
VIEW  
unknown committed
3529 3530
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    res= mysql_ha_close(thd, first_table);
3531 3532
    break;
  case SQLCOM_HA_READ:
unknown's avatar
VIEW  
unknown committed
3533
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3534 3535 3536 3537 3538
    /*
      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.
    */
3539
    unit->set_limit(select_lex);
3540
    res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
unknown's avatar
VIEW  
unknown committed
3541
                       lex->insert_list, lex->ha_rkey_mode, select_lex->where,
3542
                       unit->select_limit_cnt, unit->offset_limit_cnt);
3543 3544
    break;

unknown's avatar
unknown committed
3545
  case SQLCOM_BEGIN:
3546 3547 3548 3549 3550 3551
    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
3552
    if (begin_trans(thd))
unknown's avatar
unknown committed
3553
      goto error;
unknown's avatar
unknown committed
3554
    send_ok(thd);
unknown's avatar
unknown committed
3555 3556
    break;
  case SQLCOM_COMMIT:
3557
    if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
unknown's avatar
unknown committed
3558
                              lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
unknown's avatar
unknown committed
3559
      goto error;
3560
    send_ok(thd);
unknown's avatar
unknown committed
3561 3562
    break;
  case SQLCOM_ROLLBACK:
3563
    if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
unknown's avatar
unknown committed
3564
                              lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
unknown's avatar
unknown committed
3565
      goto error;
3566
    send_ok(thd);
unknown's avatar
unknown committed
3567
    break;
unknown's avatar
unknown committed
3568
  case SQLCOM_RELEASE_SAVEPOINT:
unknown's avatar
unknown committed
3569
  {
3570 3571
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
unknown's avatar
unknown committed
3572 3573 3574
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
3575
                       (uchar *)sv->name, sv->length) == 0)
unknown's avatar
unknown committed
3576 3577
        break;
    }
3578
    if (sv)
unknown's avatar
unknown committed
3579
    {
3580
      if (ha_release_savepoint(thd, sv))
unknown's avatar
unknown committed
3581
        res= TRUE; // cannot happen
unknown's avatar
unknown committed
3582 3583
      else
        send_ok(thd);
3584
      thd->transaction.savepoints=sv->prev;
unknown's avatar
unknown committed
3585
    }
3586
    else
unknown's avatar
unknown committed
3587
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
3588
    break;
unknown's avatar
unknown committed
3589
  }
unknown's avatar
unknown committed
3590
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
unknown's avatar
unknown committed
3591
  {
3592 3593
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
3594 3595 3596
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
3597
                       (uchar *)sv->name, sv->length) == 0)
3598 3599
        break;
    }
3600
    if (sv)
3601
    {
3602
      if (ha_rollback_to_savepoint(thd, sv))
3603 3604
        res= TRUE; // cannot happen
      else
unknown's avatar
unknown committed
3605
      {
3606
        if (((thd->options & OPTION_KEEP_LOG) || thd->no_trans_update.all) &&
unknown's avatar
unknown committed
3607 3608 3609 3610 3611 3612
            !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);
      }
3613
      thd->transaction.savepoints=sv;
unknown's avatar
unknown committed
3614 3615
    }
    else
3616
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
3617
    break;
3618
  }
3619
  case SQLCOM_SAVEPOINT:
3620 3621
    if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
          thd->in_sub_stmt) || !opt_using_transactions)
unknown's avatar
unknown committed
3622
      send_ok(thd);
unknown's avatar
unknown committed
3623
    else
3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661
    {
      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
3662
    break;
3663 3664
  case SQLCOM_CREATE_PROCEDURE:
  case SQLCOM_CREATE_SPFUNCTION:
unknown's avatar
unknown committed
3665
  {
3666
    uint namelen;
unknown's avatar
unknown committed
3667
    char *name;
unknown's avatar
unknown committed
3668
    int sp_result= SP_INTERNAL_ERROR;
3669

3670
    DBUG_ASSERT(lex->sphead != 0);
unknown's avatar
unknown committed
3671
    DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
3672 3673 3674 3675
    /*
      Verify that the database name is allowed, optionally
      lowercase it.
    */
3676
    if (check_db_name(&lex->sphead->m_db))
3677
    {
3678
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str);
3679
      goto create_sp_error;
3680 3681
    }

3682
    /*
3683 3684 3685
      Check that a database directory with this name
      exists. Design note: This won't work on virtual databases
      like information_schema.
3686 3687
    */
    if (check_db_dir_existence(lex->sphead->m_db.str))
3688
    {
3689
      my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
3690
      goto create_sp_error;
3691
    }
3692

3693 3694
    if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
                     is_schema_db(lex->sphead->m_db.str)))
3695
      goto create_sp_error;
3696

3697 3698
    if (end_active_trans(thd))
      goto create_sp_error;
3699 3700

    name= lex->sphead->name(&namelen);
3701
#ifdef HAVE_DLOPEN
unknown's avatar
unknown committed
3702 3703 3704
    if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
    {
      udf_func *udf = find_udf(name, namelen);
3705

unknown's avatar
unknown committed
3706
      if (udf)
3707
      {
3708 3709
        my_error(ER_UDF_EXISTS, MYF(0), name);
        goto create_sp_error;
3710
      }
unknown's avatar
unknown committed
3711 3712 3713
    }
#endif

3714 3715
    if (sp_process_definer(thd))
      goto create_sp_error;
3716

unknown's avatar
unknown committed
3717 3718
    res= (sp_result= lex->sphead->create(thd));
    switch (sp_result) {
3719
    case SP_OK:
unknown's avatar
unknown committed
3720
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3721
      /* only add privileges if really neccessary */
3722
      if (sp_automatic_privileges && !opt_noacl &&
3723
          check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
3724
                               lex->sphead->m_db.str, name,
3725
                               lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
3726
      {
unknown's avatar
unknown committed
3727
        if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
3728
                                lex->sql_command == SQLCOM_CREATE_PROCEDURE))
3729 3730 3731
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_PROC_AUTO_GRANT_FAIL,
                       ER(ER_PROC_AUTO_GRANT_FAIL));
unknown's avatar
unknown committed
3732
        close_thread_tables(thd);
3733
      }
unknown's avatar
unknown committed
3734
#endif
unknown's avatar
unknown committed
3735
    break;
3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754
    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
3755
    if (sp_result != SP_OK )
3756 3757 3758 3759
      goto error;
    send_ok(thd);
    break; /* break super switch */
  } /* end case group bracket */
3760 3761 3762 3763
  case SQLCOM_CALL:
    {
      sp_head *sp;

3764 3765 3766 3767 3768 3769 3770 3771 3772
      /*
        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;

      /*
3773 3774
        By this moment all needed SPs should be in cache so no need to look 
        into DB. 
3775
      */
3776 3777
      if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                                &thd->sp_proc_cache, TRUE)))
3778
      {
3779
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
unknown's avatar
unknown committed
3780
                 lex->spname->m_qname.str);
3781
	goto error;
3782 3783 3784
      }
      else
      {
unknown's avatar
unknown committed
3785
	ha_rows select_limit;
unknown's avatar
unknown committed
3786 3787
        /* bits that should be cleared in thd->server_status */
	uint bits_to_be_cleared= 0;
3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799
        /*
          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;
        }
3800

3801
	my_bool save_no_send_ok= thd->net.no_send_ok;
3802
	thd->net.no_send_ok= TRUE;
3803
	if (sp->m_flags & sp_head::MULTI_RESULTS)
3804
	{
3805
	  if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
3806
	  {
3807 3808 3809 3810
            /*
              The client does not support multiple result sets being sent
              back
            */
3811
	    my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
3812
	    thd->net.no_send_ok= save_no_send_ok;
3813 3814
	    goto error;
	  }
unknown's avatar
unknown committed
3815 3816 3817 3818 3819 3820 3821
          /*
            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;
3822 3823
	}

3824
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3825
	if (check_routine_access(thd, EXECUTE_ACL,
3826
				 sp->m_db.str, sp->m_name.str, TRUE, FALSE))
3827
	{
3828
	  thd->net.no_send_ok= save_no_send_ok;
3829 3830
	  goto error;
	}
3831
#endif
unknown's avatar
unknown committed
3832 3833
	select_limit= thd->variables.select_limit;
	thd->variables.select_limit= HA_POS_ERROR;
3834

3835
        /* 
3836
          We never write CALL statements into binlog:
3837 3838 3839 3840 3841
           - 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.
3842
        */
3843
	res= sp->execute_procedure(thd, &lex->value_list);
3844 3845 3846
	/*
          If warnings have been cleared, we have to clear total_warn_count
          too, otherwise the clients get confused.
3847 3848 3849 3850
	 */
	if (thd->warn_list.is_empty())
	  thd->total_warn_count= 0;

unknown's avatar
unknown committed
3851
	thd->variables.select_limit= select_limit;
3852

3853
	thd->net.no_send_ok= save_no_send_ok;
unknown's avatar
unknown committed
3854
        thd->server_status&= ~bits_to_be_cleared;
3855

unknown's avatar
unknown committed
3856
	if (!res)
unknown's avatar
unknown committed
3857 3858
	  send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
                                thd->row_count_func));
3859
	else
3860 3861
        {
          DBUG_ASSERT(thd->net.report_error == 1 || thd->killed);
3862
	  goto error;		// Substatement should already have sent error
3863
        }
3864
      }
3865
      break;
3866 3867
    }
  case SQLCOM_ALTER_PROCEDURE:
3868
  case SQLCOM_ALTER_FUNCTION:
3869
    {
unknown's avatar
unknown committed
3870
      int sp_result;
3871 3872 3873 3874
      sp_head *sp;
      st_sp_chistics chistics;

      memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
unknown's avatar
unknown committed
3875
      if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
3876 3877
        sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                            &thd->sp_proc_cache, FALSE);
3878
      else
3879 3880
        sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                            &thd->sp_func_cache, FALSE);
unknown's avatar
unknown committed
3881
      mysql_reset_errors(thd, 0);
3882
      if (! sp)
3883 3884
      {
	if (lex->spname->m_db.str)
unknown's avatar
unknown committed
3885
	  sp_result= SP_KEY_NOT_FOUND;
3886 3887 3888 3889 3890 3891
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
      }
3892 3893
      else
      {
3894 3895 3896
        if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str, 
				 sp->m_name.str,
                                 lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
3897
	  goto error;
3898 3899 3900

        if (end_active_trans(thd)) 
          goto error;
3901
	memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
3902 3903
        if ((sp->m_type == TYPE_ENUM_FUNCTION) &&
            !trust_function_creators &&  mysql_bin_log.is_open() &&
3904 3905 3906 3907 3908 3909
            !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
3910
          sp_result= SP_INTERNAL_ERROR;
3911 3912 3913
        }
        else
        {
3914 3915 3916 3917 3918 3919
          /*
            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
3920
          /* Conditionally writes to binlog */
unknown's avatar
unknown committed
3921 3922 3923 3924 3925 3926 3927 3928 3929

          int type= lex->sql_command == SQLCOM_ALTER_PROCEDURE ?
                    TYPE_ENUM_PROCEDURE :
                    TYPE_ENUM_FUNCTION;

          sp_result= sp_update_routine(thd,
                                       type,
                                       lex->spname,
                                       &lex->sp_chistics);
3930
        }
3931
      }
unknown's avatar
unknown committed
3932
      switch (sp_result)
3933
      {
unknown's avatar
unknown committed
3934
      case SP_OK:
3935
	send_ok(thd);
unknown's avatar
unknown committed
3936 3937
	break;
      case SP_KEY_NOT_FOUND:
3938 3939
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
3940 3941
	goto error;
      default:
3942 3943
	my_error(ER_SP_CANT_ALTER, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
3944
	goto error;
3945
      }
3946
      break;
3947 3948
    }
  case SQLCOM_DROP_PROCEDURE:
3949
  case SQLCOM_DROP_FUNCTION:
3950
    {
unknown's avatar
unknown committed
3951
      int sp_result;
3952 3953
      int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
                 TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
3954

unknown's avatar
unknown committed
3955
      sp_result= sp_routine_exists_in_table(thd, type, lex->spname);
unknown's avatar
unknown committed
3956
      mysql_reset_errors(thd, 0);
unknown's avatar
unknown committed
3957
      if (sp_result == SP_OK)
3958
      {
3959 3960 3961
        char *db= lex->spname->m_db.str;
	char *name= lex->spname->m_name.str;

3962 3963
	if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
unknown's avatar
merge  
unknown committed
3964
          goto error;
3965 3966 3967

        if (end_active_trans(thd)) 
          goto error;
unknown's avatar
unknown committed
3968
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3969
	if (sp_automatic_privileges && !opt_noacl &&
3970 3971
	    sp_revoke_privileges(thd, db, name, 
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE))
3972 3973 3974 3975 3976
	{
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
		       ER_PROC_AUTO_REVOKE_FAIL,
		       ER(ER_PROC_AUTO_REVOKE_FAIL));
	}
unknown's avatar
unknown committed
3977
#endif
unknown's avatar
unknown committed
3978
        /* Conditionally writes to binlog */
unknown's avatar
unknown committed
3979 3980 3981 3982 3983 3984

        int type= lex->sql_command == SQLCOM_DROP_PROCEDURE ?
                  TYPE_ENUM_PROCEDURE :
                  TYPE_ENUM_FUNCTION;

        sp_result= sp_drop_routine(thd, type, lex->spname);
3985 3986 3987
      }
      else
      {
3988
#ifdef HAVE_DLOPEN
3989 3990 3991 3992 3993 3994
	if (lex->sql_command == SQLCOM_DROP_FUNCTION)
	{
          udf_func *udf = find_udf(lex->spname->m_name.str,
                                   lex->spname->m_name.length);
          if (udf)
          {
3995
	    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
3996
	      goto error;
3997

3998
	    if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
3999
	    {
4000 4001
	      send_ok(thd);
	      break;
4002 4003
	    }
	  }
4004
	}
4005
#endif
4006
	if (lex->spname->m_db.str)
unknown's avatar
unknown committed
4007
	  sp_result= SP_KEY_NOT_FOUND;
4008 4009 4010 4011 4012
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
4013
      }
unknown's avatar
unknown committed
4014 4015
      res= sp_result;
      switch (sp_result) {
4016
      case SP_OK:
4017
	send_ok(thd);
4018 4019
	break;
      case SP_KEY_NOT_FOUND:
4020 4021
	if (lex->drop_if_exists)
	{
4022
	  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
4023
			      ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
4024
			      SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4025
	  res= FALSE;
4026 4027 4028
	  send_ok(thd);
	  break;
	}
4029 4030
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4031 4032
	goto error;
      default:
4033 4034
	my_error(ER_SP_DROP_FAILED, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4035
	goto error;
4036
      }
4037
      break;
4038
    }
unknown's avatar
unknown committed
4039 4040
  case SQLCOM_SHOW_CREATE_PROC:
    {
unknown's avatar
unknown committed
4041 4042
      if (sp_show_create_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname))
      {
4043 4044
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4045 4046 4047 4048 4049 4050
	goto error;
      }
      break;
    }
  case SQLCOM_SHOW_CREATE_FUNC:
    {
unknown's avatar
unknown committed
4051 4052
      if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname))
      {
4053 4054
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4055 4056 4057 4058
	goto error;
      }
      break;
    }
4059
#ifdef NOT_USED
unknown's avatar
unknown committed
4060 4061
  case SQLCOM_SHOW_STATUS_PROC:
    {
unknown's avatar
unknown committed
4062 4063
      res= sp_show_status_routine(thd, TYPE_ENUM_PROCEDURE,
                                  (lex->wild ? lex->wild->ptr() : NullS));
unknown's avatar
unknown committed
4064 4065 4066 4067
      break;
    }
  case SQLCOM_SHOW_STATUS_FUNC:
    {
unknown's avatar
unknown committed
4068 4069
      res= sp_show_status_routine(thd, TYPE_ENUM_FUNCTION,
                                  (lex->wild ? lex->wild->ptr() : NullS));
unknown's avatar
unknown committed
4070 4071
      break;
    }
4072
#endif
unknown's avatar
unknown committed
4073 4074 4075 4076 4077 4078 4079
#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
4080 4081
        sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                            &thd->sp_proc_cache, FALSE);
unknown's avatar
unknown committed
4082
      else
unknown's avatar
unknown committed
4083 4084
        sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                            &thd->sp_func_cache, FALSE);
4085
      if (!sp || sp->show_routine_code(thd))
4086 4087
      {
        /* We don't distinguish between errors for now */
unknown's avatar
unknown committed
4088 4089 4090 4091 4092 4093 4094
        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
4095 4096
  case SQLCOM_CREATE_VIEW:
    {
4097 4098 4099
      if (end_active_trans(thd))
        goto error;

4100
      res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
unknown's avatar
VIEW  
unknown committed
4101 4102 4103 4104
      break;
    }
  case SQLCOM_DROP_VIEW:
    {
unknown's avatar
unknown committed
4105 4106 4107
      if (check_table_access(thd, DROP_ACL, all_tables, 0) ||
          end_active_trans(thd))
        goto error;
4108 4109
      /* Conditionally writes to binlog. */
      res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
unknown's avatar
VIEW  
unknown committed
4110 4111
      break;
    }
4112 4113
  case SQLCOM_CREATE_TRIGGER:
  {
4114 4115 4116
    if (end_active_trans(thd))
      goto error;

4117
    /* Conditionally writes to binlog. */
4118 4119
    res= mysql_create_or_drop_trigger(thd, all_tables, 1);

4120 4121 4122 4123
    break;
  }
  case SQLCOM_DROP_TRIGGER:
  {
4124 4125 4126
    if (end_active_trans(thd))
      goto error;

4127
    /* Conditionally writes to binlog. */
4128 4129 4130
    res= mysql_create_or_drop_trigger(thd, all_tables, 0);
    break;
  }
4131
  case SQLCOM_XA_START:
4132 4133
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
        thd->lex->xa_opt == XA_RESUME)
4134
    {
4135
      if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
4136 4137 4138 4139
      {
        my_error(ER_XAER_NOTA, MYF(0));
        break;
      }
4140
      thd->transaction.xid_state.xa_state=XA_ACTIVE;
4141 4142 4143
      send_ok(thd);
      break;
    }
unknown's avatar
unknown committed
4144
    if (thd->lex->xa_opt != XA_NONE)
4145 4146 4147 4148
    { // JOIN is not supported yet. TODO
      my_error(ER_XAER_INVAL, MYF(0));
      break;
    }
4149
    if (thd->transaction.xid_state.xa_state != XA_NOTR)
4150
    {
unknown's avatar
unknown committed
4151
      my_error(ER_XAER_RMFAIL, MYF(0),
4152
               xa_state_names[thd->transaction.xid_state.xa_state]);
4153 4154 4155 4156 4157 4158 4159
      break;
    }
    if (thd->active_transaction() || thd->locked_tables)
    {
      my_error(ER_XAER_OUTSIDE, MYF(0));
      break;
    }
4160 4161 4162 4163 4164 4165 4166 4167 4168
    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);
4169
    thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN);
4170
    thd->no_trans_update.all= FALSE;
4171 4172 4173 4174 4175 4176 4177 4178 4179 4180
    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;
    }
4181
    if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
4182
    {
unknown's avatar
unknown committed
4183
      my_error(ER_XAER_RMFAIL, MYF(0),
4184
               xa_state_names[thd->transaction.xid_state.xa_state]);
4185 4186
      break;
    }
4187
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4188 4189 4190 4191
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
4192
    thd->transaction.xid_state.xa_state=XA_IDLE;
4193 4194 4195
    send_ok(thd);
    break;
  case SQLCOM_XA_PREPARE:
4196
    if (thd->transaction.xid_state.xa_state != XA_IDLE)
4197
    {
unknown's avatar
unknown committed
4198
      my_error(ER_XAER_RMFAIL, MYF(0),
4199
               xa_state_names[thd->transaction.xid_state.xa_state]);
4200 4201
      break;
    }
4202
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4203 4204 4205 4206 4207 4208 4209
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
    if (ha_prepare(thd))
    {
      my_error(ER_XA_RBROLLBACK, MYF(0));
4210 4211
      xid_cache_delete(&thd->transaction.xid_state);
      thd->transaction.xid_state.xa_state=XA_NOTR;
4212 4213
      break;
    }
4214
    thd->transaction.xid_state.xa_state=XA_PREPARED;
4215 4216 4217
    send_ok(thd);
    break;
  case SQLCOM_XA_COMMIT:
4218
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4219
    {
4220 4221
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
4222
        my_error(ER_XAER_NOTA, MYF(0));
unknown's avatar
unknown committed
4223
      else
4224 4225 4226
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
        xid_cache_delete(xs);
unknown's avatar
unknown committed
4227
        send_ok(thd);
4228
      }
4229 4230
      break;
    }
4231
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
unknown's avatar
unknown committed
4232
        thd->lex->xa_opt == XA_ONE_PHASE)
4233
    {
unknown's avatar
unknown committed
4234 4235 4236
      int r;
      if ((r= ha_commit(thd)))
        my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
4237 4238 4239
      else
        send_ok(thd);
    }
4240
    else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
unknown's avatar
unknown committed
4241
             thd->lex->xa_opt == XA_NONE)
4242
    {
4243 4244 4245
      if (wait_if_global_read_lock(thd, 0, 0))
      {
        ha_rollback(thd);
4246
        my_error(ER_XAER_RMERR, MYF(0));
4247
      }
4248
      else
4249 4250 4251 4252 4253 4254 4255
      {
        if (ha_commit_one_phase(thd, 1))
          my_error(ER_XAER_RMERR, MYF(0));
        else
          send_ok(thd);
        start_waiting_global_read_lock(thd);
      }
4256 4257 4258
    }
    else
    {
unknown's avatar
unknown committed
4259
      my_error(ER_XAER_RMFAIL, MYF(0),
4260
               xa_state_names[thd->transaction.xid_state.xa_state]);
4261 4262
      break;
    }
unknown's avatar
unknown committed
4263 4264
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
    thd->no_trans_update.all= FALSE;
4265
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
4266 4267
    xid_cache_delete(&thd->transaction.xid_state);
    thd->transaction.xid_state.xa_state=XA_NOTR;
4268 4269
    break;
  case SQLCOM_XA_ROLLBACK:
4270
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4271
    {
4272 4273
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
4274
        my_error(ER_XAER_NOTA, MYF(0));
unknown's avatar
unknown committed
4275
      else
4276 4277 4278
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
        xid_cache_delete(xs);
unknown's avatar
unknown committed
4279
        send_ok(thd);
4280
      }
4281 4282
      break;
    }
4283 4284
    if (thd->transaction.xid_state.xa_state != XA_IDLE &&
        thd->transaction.xid_state.xa_state != XA_PREPARED)
4285
    {
unknown's avatar
unknown committed
4286
      my_error(ER_XAER_RMFAIL, MYF(0),
4287
               xa_state_names[thd->transaction.xid_state.xa_state]);
4288 4289 4290 4291 4292 4293
      break;
    }
    if (ha_rollback(thd))
      my_error(ER_XAER_RMERR, MYF(0));
    else
      send_ok(thd);
4294
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
4295
    thd->no_trans_update.all= FALSE;
4296
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
4297 4298
    xid_cache_delete(&thd->transaction.xid_state);
    thd->transaction.xid_state.xa_state=XA_NOTR;
4299 4300
    break;
  case SQLCOM_XA_RECOVER:
4301
    res= mysql_xa_recover(thd);
4302
    break;
unknown's avatar
unknown committed
4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326
  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
4327 4328 4329 4330 4331
  case SQLCOM_CREATE_SERVER:
  {
    int error;
    LEX *lex= thd->lex;
    DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER"));
unknown's avatar
unknown committed
4332 4333 4334 4335

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4336 4337
    if ((error= create_server(thd, &lex->server_options)))
    {
4338
      DBUG_PRINT("info", ("problem creating server <%s>",
unknown's avatar
unknown committed
4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350
                          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
4351 4352 4353 4354

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4355 4356
    if ((error= alter_server(thd, &lex->server_options)))
    {
4357
      DBUG_PRINT("info", ("problem altering server <%s>",
unknown's avatar
unknown committed
4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369
                          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
4370 4371 4372 4373

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4374 4375
    if ((err_code= drop_server(thd, &lex->server_options)))
    {
unknown's avatar
unknown committed
4376
      if (! lex->drop_if_exists && err_code == ER_FOREIGN_SERVER_DOESNT_EXIST)
unknown's avatar
unknown committed
4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390
      {
        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;
  }
4391
  default:
4392
#ifndef EMBEDDED_LIBRARY
4393
    DBUG_ASSERT(0);                             /* Impossible */
4394
#endif
4395
    send_ok(thd);
unknown's avatar
unknown committed
4396 4397
    break;
  }
unknown's avatar
unknown committed
4398

unknown's avatar
unknown committed
4399
  thd->proc_info="query end";
4400 4401

  /*
unknown's avatar
unknown committed
4402
    Binlog-related cleanup:
4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413
    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);

4414
  /*
4415 4416
    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
4417 4418 4419 4420
    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))
4421
    thd->row_count_func= -1;
4422

4423
  goto finish;
unknown's avatar
unknown committed
4424 4425

error:
4426 4427
  res= TRUE;

4428
finish:
4429 4430 4431 4432 4433 4434 4435 4436 4437
  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
4438 4439 4440
}


4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463
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()))
4464
        return 1;                               /* purecov: inspected */
4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482
      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()))
4483
        return 1;                               /* purecov: inspected */
4484 4485 4486 4487 4488 4489 4490 4491 4492 4493
      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
4494
/*
4495
  Check grants for commands which work only with one table.
unknown's avatar
unknown committed
4496

4497
  SYNOPSIS
4498
    check_single_table_access()
unknown's avatar
unknown committed
4499
    thd			Thread handler
4500
    privilege		requested privilege
unknown's avatar
VIEW  
unknown committed
4501
    all_tables		global table list of query
4502 4503
    no_errors           FALSE/TRUE - report/don't report error to
                            the client (using my_error() call).
unknown's avatar
unknown committed
4504 4505 4506

  RETURN
    0 - OK
unknown's avatar
unknown committed
4507
    1 - access denied, error is sent to client
unknown's avatar
unknown committed
4508 4509
*/

4510
bool check_single_table_access(THD *thd, ulong privilege, 
4511
                               TABLE_LIST *all_tables, bool no_errors)
unknown's avatar
unknown committed
4512
{
4513 4514 4515 4516 4517 4518
  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;

4519 4520 4521 4522 4523 4524 4525 4526
  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,
4527
		   &all_tables->grant.privilege, 0, no_errors,
4528
                   test(all_tables->schema_table)))
4529
    goto deny;
unknown's avatar
unknown committed
4530

unknown's avatar
unknown committed
4531
  /* Show only 1 table for check_grant */
4532
  if (!(all_tables->belong_to_view &&
4533
        (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
4534
      check_grant(thd, privilege, all_tables, 0, 1, no_errors))
4535 4536 4537
    goto deny;

  thd->security_ctx= backup_ctx;
4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561
  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)
{
4562
  if (check_single_table_access (thd,privilege,all_tables, FALSE))
4563
    return 1;
unknown's avatar
unknown committed
4564

4565
  /* Check rights on tables of subselects and implictly opened tables */
unknown's avatar
unknown committed
4566
  TABLE_LIST *subselects_tables, *view= all_tables->view ? all_tables : 0;
unknown's avatar
VIEW  
unknown committed
4567
  if ((subselects_tables= all_tables->next_global))
unknown's avatar
unknown committed
4568
  {
unknown's avatar
unknown committed
4569 4570 4571 4572 4573 4574
    /*
      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)
    {
4575
      if (check_single_table_access (thd, privilege, subselects_tables, FALSE))
unknown's avatar
unknown committed
4576 4577 4578 4579 4580
        return 1;
      subselects_tables= subselects_tables->next_global;
    }
    if (subselects_tables &&
        (check_table_access(thd, SELECT_ACL, subselects_tables, 0)))
4581
      return 1;
unknown's avatar
unknown committed
4582 4583
  }
  return 0;
unknown's avatar
unknown committed
4584 4585 4586
}


unknown's avatar
unknown committed
4587
/****************************************************************************
unknown's avatar
unknown committed
4588
  Get the user (global) and database privileges for all used tables
unknown's avatar
unknown committed
4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601

  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
4602 4603
                is enough to satisfy the request and the global grants contains
                a SELECT grant.
unknown's avatar
unknown committed
4604 4605 4606
****************************************************************************/

bool
unknown's avatar
unknown committed
4607
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
4608
	     bool dont_check_global_grants, bool no_errors, bool schema_db)
unknown's avatar
unknown committed
4609
{
4610
  Security_context *sctx= thd->security_ctx;
unknown's avatar
unknown committed
4611 4612
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  ulong db_access;
4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623
  /*
    GRANT command:
    In case of database level grant the database name may be a pattern,
    in case of table|column level grant the database name can not be a pattern.
    We use 'dont_check_global_grants' as a flag to determine
    if it's database level grant command 
    (see SQLCOM_GRANT case, mysql_execute_command() function) and
    set db_is_pattern according to 'dont_check_global_grants' value.
  */
  bool  db_is_pattern= (test(want_access & GRANT_ACL) &&
                        dont_check_global_grants);
unknown's avatar
unknown committed
4624 4625
#endif
  ulong dummy;
4626 4627
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("db: %s  want_access: %lu  master_access: %lu",
4628
                      db ? db : "", want_access, sctx->master_access));
unknown's avatar
unknown committed
4629 4630 4631 4632 4633
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

4634
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
4635
  {
4636
    DBUG_PRINT("error",("No database"));
4637
    if (!no_errors)
unknown's avatar
unknown committed
4638 4639
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
                 MYF(0));                       /* purecov: tested */
unknown's avatar
unknown committed
4640
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4641 4642
  }

4643 4644
  if (schema_db)
  {
4645 4646
    if (!(sctx->master_access & FILE_ACL) && (want_access & FILE_ACL) ||
        (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
4647 4648
    {
      if (!no_errors)
4649 4650
      {
        const char *db_name= db ? db : thd->db;
4651
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
4652 4653
                 sctx->priv_user, sctx->priv_host, db_name);
      }
4654 4655 4656 4657 4658 4659 4660 4661 4662
      DBUG_RETURN(TRUE);
    }
    else
    {
      *save_priv= SELECT_ACL;
      DBUG_RETURN(FALSE);
    }
  }

unknown's avatar
unknown committed
4663 4664 4665
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  DBUG_RETURN(0);
#else
4666
  if ((sctx->master_access & want_access) == want_access)
unknown's avatar
unknown committed
4667
  {
4668 4669 4670 4671 4672
    /*
      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
    */
4673 4674
    db_access= sctx->db_access;
    if (!(sctx->master_access & SELECT_ACL) &&
unknown's avatar
unknown committed
4675
	(db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
4676 4677 4678
      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
4679
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
4680
  }
4681
  if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
4682
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
4683
  {						// We can never grant this
4684
    DBUG_PRINT("error",("No possible access"));
4685
    if (!no_errors)
4686
      my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
4687 4688
               sctx->priv_user,
               sctx->priv_host,
4689 4690 4691
               (thd->password ?
                ER(ER_YES) :
                ER(ER_NO)));                    /* purecov: tested */
unknown's avatar
unknown committed
4692
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4693 4694 4695
  }

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

unknown's avatar
unknown committed
4698
  if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
4699 4700
    db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
                       db_is_pattern);
unknown's avatar
unknown committed
4701
  else
4702
    db_access= sctx->db_access;
4703
  DBUG_PRINT("info",("db_access: %lu", db_access));
unknown's avatar
unknown committed
4704
  /* Remove SHOW attribute and access rights we already have */
4705
  want_access &= ~(sctx->master_access | EXTRA_ACL);
4706 4707
  DBUG_PRINT("info",("db_access: %lu  want_access: %lu",
                     db_access, want_access));
4708
  db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
4709

unknown's avatar
unknown committed
4710
  if (db_access == want_access ||
4711
      (!dont_check_global_grants &&
4712
       !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
unknown's avatar
unknown committed
4713
    DBUG_RETURN(FALSE);				/* Ok */
4714 4715

  DBUG_PRINT("error",("Access denied"));
4716
  if (!no_errors)
4717
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
4718
             sctx->priv_user, sctx->priv_host,
4719 4720 4721
             (db ? db : (thd->db ?
                         thd->db :
                         "unknown")));          /* purecov: tested */
unknown's avatar
unknown committed
4722
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4723
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
4724 4725 4726
}


4727 4728 4729 4730 4731 4732 4733 4734 4735
/*
  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
4736
    One gets access right if one has ANY of the rights in want_access
4737 4738 4739 4740 4741 4742 4743 4744
    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
4745 4746

bool check_global_access(THD *thd, ulong want_access)
unknown's avatar
unknown committed
4747
{
unknown's avatar
unknown committed
4748 4749 4750
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  return 0;
#else
unknown's avatar
unknown committed
4751
  char command[128];
4752
  if ((thd->security_ctx->master_access & want_access))
unknown's avatar
unknown committed
4753 4754
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
4755
  my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
unknown's avatar
unknown committed
4756
  return 1;
unknown's avatar
unknown committed
4757
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
unknown's avatar
unknown committed
4758 4759 4760
}


4761 4762
static bool check_show_access(THD *thd, TABLE_LIST *table)
{
unknown's avatar
unknown committed
4763
  switch (get_schema_table_idx(table->schema_table)) {
4764 4765
  case SCH_SCHEMATA:
    return (specialflag & SPECIAL_SKIP_SHOW_DB) &&
unknown's avatar
unknown committed
4766
      check_global_access(thd, SHOW_DB_ACL);
4767 4768 4769 4770 4771

  case SCH_TABLE_NAMES:
  case SCH_TABLES:
  case SCH_VIEWS:
  case SCH_TRIGGERS:
unknown's avatar
unknown committed
4772 4773 4774
  case SCH_EVENTS:
  {
    const char *dst_db_name= table->schema_select_lex->db;
4775

unknown's avatar
unknown committed
4776
    DBUG_ASSERT(dst_db_name);
4777

unknown's avatar
unknown committed
4778 4779 4780 4781
    if (check_access(thd, SELECT_ACL, dst_db_name,
                     &thd->col_access, FALSE, FALSE,
                     is_schema_db(dst_db_name)))
      return TRUE;
4782

unknown's avatar
unknown committed
4783 4784 4785 4786 4787 4788 4789
    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;
4790 4791
    }

unknown's avatar
unknown committed
4792 4793 4794
    return FALSE;
  }

4795 4796
  case SCH_COLUMNS:
  case SCH_STATISTICS:
unknown's avatar
unknown committed
4797 4798 4799
  {
    TABLE_LIST *dst_table;
    dst_table= (TABLE_LIST *) table->schema_select_lex->table_list.first;
4800

unknown's avatar
unknown committed
4801
    DBUG_ASSERT(dst_table);
4802

unknown's avatar
unknown committed
4803 4804 4805 4806 4807 4808
    if (check_access(thd, SELECT_ACL | EXTRA_ACL,
                     dst_table->db,
                     &dst_table->grant.privilege,
                     FALSE, FALSE,
                     test(dst_table->schema_table)))
      return FALSE;
4809

4810
    return (check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE));
unknown's avatar
unknown committed
4811 4812
  }
  default:
4813 4814 4815 4816 4817 4818 4819
    break;
  }

  return FALSE;
}


unknown's avatar
unknown committed
4820
/*
4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840
  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
4841 4842
*/

4843
bool
unknown's avatar
unknown committed
4844
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
4845
		   bool no_errors)
unknown's avatar
unknown committed
4846
{
4847
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4848
  TABLE_LIST *org_tables= tables;
unknown's avatar
unknown committed
4849
#endif
4850
  TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
4851
  Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx;
4852
  /*
unknown's avatar
unknown committed
4853 4854 4855
    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.
4856
  */
unknown's avatar
unknown committed
4857
  for (; tables != first_not_own_table; tables= tables->next_global)
unknown's avatar
unknown committed
4858
  {
4859 4860 4861 4862 4863
    if (tables->security_ctx)
      sctx= tables->security_ctx;
    else
      sctx= backup_ctx;

4864
    if (tables->schema_table && 
4865
        (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
4866 4867 4868
    {
      if (!no_errors)
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
4869
                 sctx->priv_user, sctx->priv_host,
4870
                 INFORMATION_SCHEMA_NAME.str);
4871 4872
      return TRUE;
    }
4873 4874 4875 4876 4877
    /*
       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
4878 4879 4880 4881 4882 4883 4884 4885 4886 4887

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

      continue;
    }

    if (tables->derived ||
4888
        (tables->table && (int)tables->table->s->tmp_table))
unknown's avatar
unknown committed
4889
      continue;
4890 4891
    thd->security_ctx= sctx;
    if ((sctx->master_access & want_access) ==
4892
        (want_access & ~EXTRA_ACL) &&
unknown's avatar
unknown committed
4893
	thd->db)
unknown's avatar
unknown committed
4894
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
4895
    else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
unknown's avatar
unknown committed
4896
    {
4897
      if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
4898
			 0, no_errors, test(tables->schema_table)))
4899
        goto deny;                            // Access denied
unknown's avatar
unknown committed
4900
    }
4901
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
4902
			  0, no_errors, test(tables->schema_table)))
4903
      goto deny;
unknown's avatar
unknown committed
4904
  }
4905
  thd->security_ctx= backup_ctx;
4906
  return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
unknown's avatar
unknown committed
4907
		       test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
4908 4909 4910
deny:
  thd->security_ctx= backup_ctx;
  return TRUE;
unknown's avatar
unknown committed
4911 4912
}

4913

4914
bool
4915 4916
check_routine_access(THD *thd, ulong want_access,char *db, char *name,
		     bool is_proc, bool no_errors)
4917 4918 4919 4920 4921
{
  TABLE_LIST tables[1];
  
  bzero((char *)tables, sizeof(TABLE_LIST));
  tables->db= db;
4922
  tables->table_name= tables->alias= name;
4923
  
unknown's avatar
unknown committed
4924 4925 4926 4927 4928 4929 4930
  /*
    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)
4931 4932
    tables->grant.privilege= want_access;
  else if (check_access(thd,want_access,db,&tables->grant.privilege,
unknown's avatar
unknown committed
4933
			0, no_errors, 0))
4934 4935
    return TRUE;
  
unknown's avatar
unknown committed
4936
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4937
    return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
4938
#else
4939
  return FALSE;
4940
#endif
4941 4942
}

4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957

/*
  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
*/

4958 4959
bool check_some_routine_access(THD *thd, const char *db, const char *name,
                               bool is_proc)
4960 4961
{
  ulong save_priv;
4962
  if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
4963
    return FALSE;
4964 4965 4966 4967 4968
  /*
    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) ||
4969 4970
      (save_priv & SHOW_PROC_ACLS))
    return FALSE;
4971
  return check_routine_level_acl(thd, db, name, is_proc);
4972 4973 4974
}


4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999
/*
  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,
5000 5001
                        &table->grant.privilege, 0, 1,
                        test(table->schema_table)) &&
5002
          !check_grant(thd, access, table, 0, 1, 1))
5003 5004 5005 5006 5007 5008 5009 5010
        DBUG_RETURN(0);
    }
  }
  DBUG_PRINT("exit",("no matching access rights"));
  DBUG_RETURN(1);
}


5011 5012
bool check_merge_table_access(THD *thd, char *db,
			      TABLE_LIST *table_list)
5013 5014 5015 5016
{
  int error=0;
  if (table_list)
  {
5017
    /* Check that all tables use the current database */
5018
    TABLE_LIST *tmp;
unknown's avatar
VIEW  
unknown committed
5019
    for (tmp= table_list; tmp; tmp= tmp->next_local)
5020 5021 5022 5023
    {
      if (!tmp->db || !tmp->db[0])
	tmp->db=db;
    }
5024
    error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
unknown's avatar
unknown committed
5025
			     table_list,0);
5026 5027 5028 5029
  }
  return error;
}

unknown's avatar
unknown committed
5030

unknown's avatar
unknown committed
5031 5032 5033 5034
/****************************************************************************
	Check stack size; Send error if there isn't enough stack to continue
****************************************************************************/

5035 5036 5037
#ifndef EMBEDDED_LIBRARY

#define used_stack(A,B) (long)(A > B ? A - B : B - A)
unknown's avatar
unknown committed
5038

unknown's avatar
unknown committed
5039 5040 5041 5042
#ifndef DBUG_OFF
long max_stack_used;
#endif

5043 5044 5045 5046 5047 5048 5049
/*
  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,
5050
			 uchar *buf __attribute__((unused)))
unknown's avatar
unknown committed
5051 5052
{
  long stack_used;
5053
  DBUG_ASSERT(thd == current_thd);
unknown's avatar
unknown committed
5054
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
unknown's avatar
unknown committed
5055
      (long) (thread_stack - margin))
unknown's avatar
unknown committed
5056
  {
5057 5058 5059
    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));
5060
    thd->fatal_error();
unknown's avatar
unknown committed
5061 5062
    return 1;
  }
unknown's avatar
unknown committed
5063 5064 5065
#ifndef DBUG_OFF
  max_stack_used= max(max_stack_used, stack_used);
#endif
unknown's avatar
unknown committed
5066 5067
  return 0;
}
5068
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
5069 5070 5071 5072

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

5073
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
unknown's avatar
unknown committed
5074
{
5075
  LEX	*lex= current_thd->lex;
5076
  ulong old_info=0;
unknown's avatar
unknown committed
5077 5078 5079 5080 5081
  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);
5082 5083
  if (!(lex->yacc_yyvs= (uchar*)
	my_realloc(lex->yacc_yyvs,
unknown's avatar
unknown committed
5084 5085
		   *yystacksize*sizeof(**yyvs),
		   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
5086 5087
      !(lex->yacc_yyss= (uchar*)
	my_realloc(lex->yacc_yyss,
unknown's avatar
unknown committed
5088 5089 5090 5091 5092
		   *yystacksize*sizeof(**yyss),
		   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
    return 1;
  if (old_info)
  {						// Copy old info from stack
5093 5094
    memcpy(lex->yacc_yyss, (uchar*) *yyss, old_info*sizeof(**yyss));
    memcpy(lex->yacc_yyvs, (uchar*) *yyvs, old_info*sizeof(**yyvs));
unknown's avatar
unknown committed
5095 5096 5097 5098 5099 5100 5101
  }
  *yyss=(short*) lex->yacc_yyss;
  *yyvs=(YYSTYPE*) lex->yacc_yyvs;
  return 0;
}


5102 5103 5104 5105 5106 5107
/*
 Reset THD part responsible for command processing state.

 DESCRIPTION
   This needs to be called before execution of every statement
   (prepared or conventional).
5108
   It is not called by substatements of routines.
5109 5110 5111 5112 5113 5114 5115 5116 5117 5118

 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");
5119
  DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
5120
  thd->free_list= 0;
5121
  thd->select_number= 1;
5122 5123 5124 5125
  /*
    Those two lines below are theoretically unneeded as
    THD::cleanup_after_query() should take care of this already.
  */
5126
  thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty();
5127 5128 5129
  thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;

  thd->query_start_used= 0;
5130
  thd->is_fatal_error= thd->time_zone_used= 0;
unknown's avatar
unknown committed
5131
  thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | 
unknown's avatar
unknown committed
5132 5133
                          SERVER_QUERY_NO_INDEX_USED |
                          SERVER_QUERY_NO_GOOD_INDEX_USED);
5134 5135 5136 5137 5138 5139
  /*
    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
5140 5141 5142 5143
  {
    thd->options&= ~OPTION_KEEP_LOG;
    thd->no_trans_update.all= FALSE;
  }
5144
  DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
unknown's avatar
unknown committed
5145
  thd->tmp_table_used= 0;
5146 5147
  if (!thd->in_sub_stmt)
  {
5148
    if (opt_bin_log)
5149
    {
5150
      reset_dynamic(&thd->user_var_events);
5151 5152
      thd->user_var_events_alloc= thd->mem_root;
    }
5153
    thd->clear_error();
5154 5155 5156 5157
    thd->total_warn_count=0;			// Warnings for this query
    thd->rand_used= 0;
    thd->sent_row_count= thd->examined_row_count= 0;
  }
5158 5159 5160 5161
  /*
    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
5162 5163
  thd->reset_current_stmt_binlog_row_based();

unknown's avatar
unknown committed
5164 5165 5166
  DBUG_VOID_RETURN;
}

5167

5168 5169 5170
void
mysql_init_select(LEX *lex)
{
unknown's avatar
unknown committed
5171
  SELECT_LEX *select_lex= lex->current_select;
unknown's avatar
unknown committed
5172
  select_lex->init_select();
5173
  lex->wild= 0;
5174 5175
  if (select_lex == &lex->select_lex)
  {
5176
    DBUG_ASSERT(lex->result == 0);
5177 5178
    lex->exchange= 0;
  }
5179 5180
}

5181

unknown's avatar
unknown committed
5182
bool
unknown's avatar
unknown committed
5183
mysql_new_select(LEX *lex, bool move_down)
5184
{
unknown's avatar
unknown committed
5185
  SELECT_LEX *select_lex;
5186
  THD *thd= lex->thd;
unknown's avatar
unknown committed
5187 5188
  DBUG_ENTER("mysql_new_select");

5189
  if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
5190
    DBUG_RETURN(1);
5191
  select_lex->select_number= ++thd->select_number;
unknown's avatar
unknown committed
5192
  select_lex->parent_lex= lex; /* Used in init_query. */
unknown's avatar
unknown committed
5193 5194
  select_lex->init_query();
  select_lex->init_select();
unknown's avatar
unknown committed
5195 5196
  lex->nest_level++;
  select_lex->nest_level= lex->nest_level;
5197 5198 5199 5200 5201
  /*
    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
5202
  if (thd->stmt_arena->is_stmt_prepare())
5203
    select_lex->uncacheable|= UNCACHEABLE_PREPARE;
unknown's avatar
unknown committed
5204 5205
  if (move_down)
  {
unknown's avatar
unknown committed
5206
    SELECT_LEX_UNIT *unit;
5207
    lex->subqueries= TRUE;
unknown's avatar
unknown committed
5208
    /* first select_lex of subselect or derived table */
5209
    if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
unknown's avatar
unknown committed
5210
      DBUG_RETURN(1);
unknown's avatar
unknown committed
5211

unknown's avatar
unknown committed
5212 5213
    unit->init_query();
    unit->init_select();
5214
    unit->thd= thd;
unknown's avatar
unknown committed
5215
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
5216 5217
    unit->link_next= 0;
    unit->link_prev= 0;
5218
    unit->return_to= lex->current_select;
unknown's avatar
unknown committed
5219
    select_lex->include_down(unit);
5220 5221 5222 5223 5224
    /*
      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
5225 5226
  }
  else
unknown's avatar
unknown committed
5227
  {
unknown's avatar
VIEW  
unknown committed
5228 5229
    if (lex->current_select->order_list.first && !lex->current_select->braces)
    {
unknown's avatar
unknown committed
5230
      my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
unknown's avatar
unknown committed
5231
      DBUG_RETURN(1);
unknown's avatar
VIEW  
unknown committed
5232
    }
5233
    select_lex->include_neighbour(lex->current_select);
5234 5235 5236 5237 5238
    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
5239
  }
unknown's avatar
unknown committed
5240

5241
  select_lex->master_unit()->global_parameters= select_lex;
5242
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
5243
  lex->current_select= select_lex;
5244 5245 5246 5247 5248
  /*
    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
5249
  DBUG_RETURN(0);
5250
}
unknown's avatar
unknown committed
5251

5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266
/*
  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)
{
5267
  THD *thd;
5268
  LEX *lex;
5269
  LEX_STRING tmp, null_lex_string;
5270 5271
  Item *var;
  char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end;
5272
  DBUG_ENTER("create_select_for_variable");
5273 5274

  thd= current_thd;
unknown's avatar
unknown committed
5275
  lex= thd->lex;
5276 5277 5278 5279
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
5280
  bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
5281 5282 5283 5284
  /*
    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
5285 5286 5287 5288 5289 5290
  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);
  }
5291 5292 5293
  DBUG_VOID_RETURN;
}

5294

unknown's avatar
unknown committed
5295 5296
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
5297
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
5298
  mysql_init_select(lex);
5299 5300
  lex->select_lex.select_limit= 0;
  lex->unit.select_limit_cnt= HA_POS_ERROR;
unknown's avatar
unknown committed
5301
  lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list);
5302
  lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
unknown's avatar
VIEW  
unknown committed
5303 5304
  lex->query_tables= 0;
  lex->query_tables_last= &lex->query_tables;
unknown's avatar
unknown committed
5305
}
unknown's avatar
unknown committed
5306

5307

5308 5309 5310 5311
/*
  When you modify mysql_parse(), you may need to mofify
  mysql_test_parse_for_slave() in this same file.
*/
unknown's avatar
unknown committed
5312

5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323
/**
  Parse a query.
  @param thd Current thread
  @param inBuf Begining of the query text
  @param length Length of the query text
  @param [out] semicolon For multi queries, position of the character of
  the next query in the query text.
*/

void mysql_parse(THD *thd, const char *inBuf, uint length,
                 const char ** found_semicolon)
unknown's avatar
unknown committed
5324 5325
{
  DBUG_ENTER("mysql_parse");
5326 5327 5328

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

5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346
  /*
    Warning.
    The purpose of query_cache_send_result_to_client() is to lookup the
    query in the query cache first, to avoid parsing and executing it.
    So, the natural implementation would be to:
    - first, call query_cache_send_result_to_client,
    - second, if caching failed, initialise the lexical and syntactic parser.
    The problem is that the query cache depends on a clean initialization
    of (among others) lex->safe_to_cache_query and thd->server_status,
    which are reset respectively in
    - lex_start()
    - mysql_reset_thd_for_next_command()
    So, initializing the lexical analyser *before* using the query cache
    is required for the cache to work properly.
    FIXME: cleanup the dependencies in the code to simplify this.
  */
  lex_start(thd);
  mysql_reset_thd_for_next_command(thd);
5347

5348
  if (query_cache_send_result_to_client(thd, (char*) inBuf, length) <= 0)
unknown's avatar
unknown committed
5349
  {
unknown's avatar
unknown committed
5350
    LEX *lex= thd->lex;
5351

5352 5353
    sp_cache_flush_obsolete(&thd->sp_proc_cache);
    sp_cache_flush_obsolete(&thd->sp_func_cache);
5354 5355 5356 5357 5358 5359 5360 5361

    Lex_input_stream lip(thd, inBuf, length);
    thd->m_lip= &lip;

    int err= MYSQLparse(thd);
    *found_semicolon= lip.found_semicolon;

    if (!err && ! thd->is_fatal_error)
unknown's avatar
unknown committed
5362
    {
unknown's avatar
unknown committed
5363
#ifndef NO_EMBEDDED_ACCESS_CHECKS
5364
      if (mqh_used && thd->user_connect &&
5365
	  check_mqh(thd, lex->sql_command))
5366 5367 5368 5369
      {
	thd->net.error = 0;
      }
      else
unknown's avatar
unknown committed
5370
#endif
5371
      {
5372
	if (! thd->net.report_error)
unknown's avatar
unknown committed
5373
	{
5374 5375 5376 5377 5378 5379 5380 5381 5382 5383
          /*
            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.
          */
5384 5385
          if (lip.found_semicolon &&
              (thd->query_length= (ulong)(lip.found_semicolon - thd->query)))
5386 5387
            thd->query_length--;
          /* Actually execute the query */
unknown's avatar
unknown committed
5388
	  mysql_execute_command(thd);
unknown's avatar
SCRUM  
unknown committed
5389
	  query_cache_end_of_result(thd);
unknown's avatar
unknown committed
5390
	}
5391
      }
unknown's avatar
unknown committed
5392 5393
    }
    else
5394
    {
5395
      DBUG_ASSERT(thd->net.report_error);
5396
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
5397
			 thd->is_fatal_error));
5398 5399

      query_cache_abort(&thd->net);
5400
    }
5401 5402 5403 5404 5405 5406
    if (thd->lex->sphead)
    {
      delete thd->lex->sphead;
      thd->lex->sphead= 0;
    }
    lex->unit.cleanup();
unknown's avatar
unknown committed
5407
    thd->proc_info="freeing items";
5408
    thd->end_statement();
5409
    thd->cleanup_after_query();
5410
    DBUG_ASSERT(thd->change_list.is_empty());
unknown's avatar
unknown committed
5411
  }
5412 5413 5414 5415 5416 5417
  else
  {
    /* There are no multi queries in the cache. */
    *found_semicolon= NULL;
  }

unknown's avatar
unknown committed
5418 5419 5420 5421
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
5422
#ifdef HAVE_REPLICATION
5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433
/*
  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
5434
  LEX *lex= thd->lex;
5435
  bool error= 0;
unknown's avatar
unknown committed
5436
  DBUG_ENTER("mysql_test_parse_for_slave");
5437

5438 5439 5440 5441 5442 5443 5444
  Lex_input_stream lip(thd, inBuf, length);
  thd->m_lip= &lip;
  lex_start(thd);
  mysql_reset_thd_for_next_command(thd);
  int err= MYSQLparse((void*) thd);

  if (!err && ! thd->is_fatal_error &&
5445
      all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
unknown's avatar
unknown committed
5446
    error= 1;                  /* Ignore question */
5447
  thd->end_statement();
5448
  thd->cleanup_after_query();
unknown's avatar
unknown committed
5449
  DBUG_RETURN(error);
5450
}
unknown's avatar
unknown committed
5451
#endif
unknown's avatar
unknown committed
5452

5453

unknown's avatar
unknown committed
5454

unknown's avatar
unknown committed
5455 5456 5457 5458 5459
/*****************************************************************************
** Store field definition for create
** Return 0 if ok
******************************************************************************/

5460
bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
unknown's avatar
unknown committed
5461
		       char *length, char *decimals,
5462
		       uint type_modifier,
5463 5464
		       Item *default_value, Item *on_update_value,
                       LEX_STRING *comment,
5465 5466
		       char *change,
                       List<String> *interval_list, CHARSET_INFO *cs,
unknown's avatar
unknown committed
5467
		       uint uint_geom_type)
unknown's avatar
unknown committed
5468 5469
{
  register create_field *new_field;
unknown's avatar
unknown committed
5470
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
5471 5472
  DBUG_ENTER("add_field_to_list");

5473 5474
  if (check_string_char_length(field_name, "", NAME_CHAR_LEN,
                               system_charset_info, 1))
unknown's avatar
unknown committed
5475
  {
5476
    my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */
unknown's avatar
unknown committed
5477 5478 5479 5480
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
5481
    Key *key;
5482
    lex->col_list.push_back(new key_part_spec(field_name->str, 0));
5483 5484 5485 5486
    key= new Key(Key::PRIMARY, NullS,
                      &default_key_create_info,
                      0, lex->col_list);
    lex->alter_info.key_list.push_back(key);
unknown's avatar
unknown committed
5487 5488 5489 5490
    lex->col_list.empty();
  }
  if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
  {
5491
    Key *key;
5492
    lex->col_list.push_back(new key_part_spec(field_name->str, 0));
5493 5494 5495 5496
    key= new Key(Key::UNIQUE, NullS,
                 &default_key_create_info, 0,
                 lex->col_list);
    lex->alter_info.key_list.push_back(key);
unknown's avatar
unknown committed
5497 5498 5499
    lex->col_list.empty();
  }

5500
  if (default_value)
unknown's avatar
unknown committed
5501
  {
5502
    /* 
unknown's avatar
unknown committed
5503 5504
      Default value should be literal => basic constants =>
      no need fix_fields()
5505 5506 5507
      
      We allow only one function as part of default value - 
      NOW() as default for TIMESTAMP type.
5508
    */
5509 5510
    if (default_value->type() == Item::FUNC_ITEM && 
        !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
5511
         type == MYSQL_TYPE_TIMESTAMP))
5512
    {
5513
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5514 5515 5516
      DBUG_RETURN(1);
    }
    else if (default_value->type() == Item::NULL_ITEM)
unknown's avatar
unknown committed
5517
    {
5518
      default_value= 0;
5519 5520 5521
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
5522
	my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5523 5524 5525 5526 5527
	DBUG_RETURN(1);
      }
    }
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
5528
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
unknown's avatar
unknown committed
5529 5530 5531
      DBUG_RETURN(1);
    }
  }
5532

5533
  if (on_update_value && type != MYSQL_TYPE_TIMESTAMP)
5534
  {
5535
    my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
5536 5537
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
5538

5539
  if (type == MYSQL_TYPE_TIMESTAMP && length)
5540 5541 5542 5543 5544
  {
    /* 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
5545
    char buf[32];
5546
    my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length);
unknown's avatar
unknown committed
5547
    WARN_DEPRECATED(thd, "5.2", buf, "'TIMESTAMP'");
5548 5549
  }

5550
  if (!(new_field= new create_field()) ||
5551
      new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
5552 5553
                      default_value, on_update_value, comment, change,
                      interval_list, cs, uint_geom_type))
unknown's avatar
unknown committed
5554
    DBUG_RETURN(1);
unknown's avatar
unknown committed
5555

5556
  lex->alter_info.create_list.push_back(new_field);
unknown's avatar
unknown committed
5557 5558 5559 5560
  lex->last_field=new_field;
  DBUG_RETURN(0);
}

5561

unknown's avatar
unknown committed
5562 5563 5564 5565
/* Store position for column in ALTER TABLE .. ADD column */

void store_position_for_column(const char *name)
{
5566
  current_thd->lex->last_field->after=my_const_cast(char*) (name);
unknown's avatar
unknown committed
5567 5568 5569
}

bool
unknown's avatar
unknown committed
5570
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
5571 5572 5573 5574
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
5575
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
5576 5577 5578 5579 5580
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
5581
  thd->lex->proc_list.link_in_list((uchar*) order,(uchar**) &order->next);
unknown's avatar
unknown committed
5582 5583 5584 5585 5586 5587 5588 5589 5590
  return 0;
}


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


unknown's avatar
unknown committed
5591
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
5592 5593 5594
{
  ORDER *order;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
5595
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER))))
unknown's avatar
unknown committed
5596
    DBUG_RETURN(1);
unknown's avatar
unknown committed
5597 5598
  order->item_ptr= item;
  order->item= &order->item_ptr;
unknown's avatar
unknown committed
5599 5600 5601
  order->asc = asc;
  order->free_me=0;
  order->used=0;
5602
  order->counter_used= 0;
5603
  list.link_in_list((uchar*) order,(uchar**) &order->next);
unknown's avatar
unknown committed
5604 5605 5606 5607
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
5608 5609 5610 5611 5612 5613 5614 5615 5616 5617
/*
  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
5618
			TL_OPTION_ALIAS	        an alias in multi table DELETE
unknown's avatar
unknown committed
5619 5620 5621 5622 5623 5624 5625 5626 5627
    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
5628 5629
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
5630
					     LEX_STRING *alias,
unknown's avatar
unknown committed
5631 5632
					     ulong table_options,
					     thr_lock_type lock_type,
5633
					     List<index_hint> *index_hints_arg,
unknown's avatar
unknown committed
5634
                                             LEX_STRING *option)
unknown's avatar
unknown committed
5635 5636
{
  register TABLE_LIST *ptr;
unknown's avatar
unknown committed
5637
  TABLE_LIST *previous_table_ref; /* The table preceding the current one. */
unknown's avatar
unknown committed
5638
  char *alias_str;
5639
  LEX *lex= thd->lex;
unknown's avatar
unknown committed
5640
  DBUG_ENTER("add_table_to_list");
5641
  LINT_INIT(previous_table_ref);
unknown's avatar
unknown committed
5642 5643 5644 5645

  if (!table)
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? alias->str : table->table.str;
5646 5647
  if (!test(table_options & TL_OPTION_ALIAS) && 
      check_table_name(table->table.str, table->table.length))
unknown's avatar
unknown committed
5648
  {
5649
    my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
unknown's avatar
unknown committed
5650 5651
    DBUG_RETURN(0);
  }
unknown's avatar
unknown committed
5652 5653

  if (table->is_derived_table() == FALSE && table->db.str &&
5654
      check_db_name(&table->db))
unknown's avatar
unknown committed
5655 5656 5657 5658
  {
    my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str);
    DBUG_RETURN(0);
  }
unknown's avatar
unknown committed
5659 5660

  if (!alias)					/* Alias is case sensitive */
5661 5662 5663
  {
    if (table->sel)
    {
unknown's avatar
unknown committed
5664 5665
      my_message(ER_DERIVED_MUST_HAVE_ALIAS,
                 ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
5666 5667
      DBUG_RETURN(0);
    }
5668
    if (!(alias_str= (char*) thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
5669
      DBUG_RETURN(0);
5670
  }
unknown's avatar
unknown committed
5671
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
5672
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
5673
  if (table->db.str)
5674 5675 5676 5677
  {
    ptr->db= table->db.str;
    ptr->db_length= table->db.length;
  }
unknown's avatar
unknown committed
5678 5679
  else if (thd->copy_db_to(&ptr->db, &ptr->db_length))
    DBUG_RETURN(0);
unknown's avatar
unknown committed
5680

5681
  ptr->alias= alias_str;
5682
  if (lower_case_table_names && table->table.length)
5683
    table->table.length= my_casedn_str(files_charset_info, table->table.str);
5684 5685
  ptr->table_name=table->table.str;
  ptr->table_name_length=table->table.length;
5686
  ptr->lock_type=   lock_type;
unknown's avatar
unknown committed
5687 5688
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
5689
  ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
5690
  ptr->derived=	    table->sel;
5691
  if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db,
5692
                                      INFORMATION_SCHEMA_NAME.str))
5693
  {
5694
    ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
5695 5696
    if (!schema_table ||
        (schema_table->hidden && 
5697
         (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0))
5698
    {
unknown's avatar
unknown committed
5699
      my_error(ER_UNKNOWN_TABLE, MYF(0),
5700
               ptr->table_name, INFORMATION_SCHEMA_NAME.str);
5701 5702
      DBUG_RETURN(0);
    }
5703
    ptr->schema_table_name= ptr->table_name;
5704 5705
    ptr->schema_table= schema_table;
  }
5706
  ptr->select_lex=  lex->current_select;
unknown's avatar
unknown committed
5707
  ptr->cacheable_table= 1;
5708
  ptr->index_hints= index_hints_arg;
unknown's avatar
unknown committed
5709
  ptr->option= option ? option->str : 0;
unknown's avatar
unknown committed
5710
  /* check that used name is unique */
5711
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
5712
  {
unknown's avatar
unknown committed
5713 5714 5715 5716
    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
5717
	 tables ;
unknown's avatar
VIEW  
unknown committed
5718
	 tables=tables->next_local)
unknown's avatar
unknown committed
5719
    {
5720 5721
      if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
	  !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
5722
      {
5723
	my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
unknown's avatar
unknown committed
5724 5725
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
5726 5727
    }
  }
unknown's avatar
unknown committed
5728 5729 5730
  /* Store the table reference preceding the current one. */
  if (table_list.elements > 0)
  {
5731 5732 5733
    /*
      table_list.next points to the last inserted TABLE_LIST->next_local'
      element
5734
      We don't use the offsetof() macro here to avoid warnings from gcc
5735
    */
5736 5737 5738
    previous_table_ref= (TABLE_LIST*) ((char*) table_list.next -
                                       ((char*) &(ptr->next_local) -
                                        (char*) ptr));
5739 5740 5741 5742 5743 5744 5745 5746
    /*
      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
5747
  }
5748

unknown's avatar
unknown committed
5749 5750 5751 5752 5753 5754
  /*
    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'.
  */
5755
  table_list.link_in_list((uchar*) ptr, (uchar**) &ptr->next_local);
unknown's avatar
unknown committed
5756
  ptr->next_name_resolution_table= NULL;
5757
  /* Link table in global list (all used tables) */
5758
  lex->add_to_query_tables(ptr);
unknown's avatar
unknown committed
5759 5760 5761
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
5762

5763 5764 5765 5766
/*
  Initialize a new table list for a nested join

  SYNOPSIS
unknown's avatar
unknown committed
5767
    init_nested_join()
5768
    thd         current thread
5769

5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788
  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");
5789

5790 5791
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
5792
    DBUG_RETURN(1);
5793
  nested_join= ptr->nested_join=
5794
    ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
5795

5796 5797 5798
  join_list->push_front(ptr);
  ptr->embedding= embedding;
  ptr->join_list= join_list;
5799
  ptr->alias= (char*) "(nested_join)";
5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816
  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
5817
    moves it one level up, eliminating the nest.
5818 5819 5820 5821 5822 5823 5824 5825 5826

  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;
5827
  NESTED_JOIN *nested_join;
5828
  DBUG_ENTER("end_nested_join");
5829

unknown's avatar
unknown committed
5830
  DBUG_ASSERT(embedding);
5831 5832 5833
  ptr= embedding;
  join_list= ptr->join_list;
  embedding= ptr->embedding;
5834
  nested_join= ptr->nested_join;
5835 5836 5837 5838 5839 5840 5841 5842 5843
  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;
  }
5844
  else if (nested_join->join_list.elements == 0)
unknown's avatar
unknown committed
5845 5846
  {
    join_list->pop();
5847
    ptr= 0;                                     // return value
unknown's avatar
unknown committed
5848
  }
5849 5850 5851 5852 5853 5854 5855 5856
  DBUG_RETURN(ptr);
}


/*
  Nest last join operation

  SYNOPSIS
5857
    nest_last_join()
5858 5859 5860 5861 5862 5863
    thd         current thread

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

  RETURN VALUE
5864 5865 5866
    0  Error
    #  Pointer to TABLE_LIST element created for the new nested join

5867 5868 5869 5870 5871 5872
*/

TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
{
  TABLE_LIST *ptr;
  NESTED_JOIN *nested_join;
5873
  List<TABLE_LIST> *embedded_list;
5874
  DBUG_ENTER("nest_last_join");
5875

5876 5877
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
5878
    DBUG_RETURN(0);
5879
  nested_join= ptr->nested_join=
5880
    ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
5881

5882 5883
  ptr->embedding= embedding;
  ptr->join_list= join_list;
5884
  ptr->alias= (char*) "(nest_last_join)";
5885
  embedded_list= &nested_join->join_list;
5886
  embedded_list->empty();
5887 5888

  for (uint i=0; i < 2; i++)
5889 5890 5891 5892 5893
  {
    TABLE_LIST *table= join_list->pop();
    table->join_list= embedded_list;
    table->embedding= ptr;
    embedded_list->push_back(table);
unknown's avatar
unknown committed
5894 5895 5896 5897 5898 5899 5900
    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
5901 5902
      if (prev_join_using)
        ptr->join_using_fields= prev_join_using;
unknown's avatar
unknown committed
5903
    }
5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943
  }
  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
5944 5945 5946

  DESCRIPTION
    The function takes the current join list t[0],t[1] ... and
5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969
    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
*/

5970
TABLE_LIST *st_select_lex::convert_right_join()
5971 5972
{
  TABLE_LIST *tab2= join_list->pop();
5973
  TABLE_LIST *tab1= join_list->pop();
5974 5975 5976 5977 5978 5979 5980 5981 5982
  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
5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995
/*
  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
5996
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
5997 5998 5999 6000 6001 6002
{
  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
6003 6004 6005
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first;
       tables;
       tables= tables->next_local)
unknown's avatar
unknown committed
6006 6007 6008 6009 6010 6011 6012
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
6013

unknown's avatar
unknown committed
6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037
/*
  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
6038
bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
unknown's avatar
unknown committed
6039 6040 6041 6042
{
  SELECT_LEX *first_sl= first_select();
  DBUG_ENTER("add_fake_select_lex");
  DBUG_ASSERT(!fake_select_lex);
unknown's avatar
unknown committed
6043

unknown's avatar
unknown committed
6044
  if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
6045 6046 6047 6048
      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
6049
  fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */
unknown's avatar
unknown committed
6050 6051
  fake_select_lex->make_empty_select();
  fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
6052 6053
  fake_select_lex->select_limit= 0;

unknown's avatar
unknown committed
6054
  fake_select_lex->context.outer_context=first_sl->context.outer_context;
6055 6056 6057
  /* 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
6058

6059
  if (!is_union())
unknown's avatar
unknown committed
6060 6061 6062 6063 6064 6065 6066 6067 6068
  {
    /* 
      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
6069
    thd_arg->lex->current_select= fake_select_lex;
unknown's avatar
unknown committed
6070
  }
unknown's avatar
unknown committed
6071
  thd_arg->lex->pop_context();
unknown's avatar
unknown committed
6072 6073 6074
  DBUG_RETURN(0);
}

6075

unknown's avatar
unknown committed
6076
/*
6077 6078
  Push a new name resolution context for a JOIN ... ON clause to the
  context stack of a query block.
unknown's avatar
unknown committed
6079 6080

  SYNOPSIS
6081
    push_new_name_resolution_context()
unknown's avatar
unknown committed
6082
    thd       pointer to current thread
unknown's avatar
unknown committed
6083
    left_op   left  operand of the JOIN
unknown's avatar
unknown committed
6084 6085 6086 6087
    right_op  rigth operand of the JOIN

  DESCRIPTION
    Create a new name resolution context for a JOIN ... ON clause,
6088 6089 6090
    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
6091 6092

  RETURN
6093 6094
    FALSE  if all is OK
    TRUE   if a memory allocation error occured
unknown's avatar
unknown committed
6095 6096
*/

6097 6098 6099
bool
push_new_name_resolution_context(THD *thd,
                                 TABLE_LIST *left_op, TABLE_LIST *right_op)
unknown's avatar
unknown committed
6100 6101
{
  Name_resolution_context *on_context;
6102
  if (!(on_context= new (thd->mem_root) Name_resolution_context))
6103
    return TRUE;
unknown's avatar
unknown committed
6104 6105 6106 6107 6108
  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();
6109
  return thd->lex->push_context(on_context);
unknown's avatar
unknown committed
6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129
}


/*
  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
6130
{
6131
  if (expr)
6132
  {
6133
    if (!b->on_expr)
unknown's avatar
unknown committed
6134
      b->on_expr= expr;
6135 6136
    else
    {
unknown's avatar
unknown committed
6137 6138 6139 6140 6141 6142
      /*
        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);
6143 6144
    }
    b->on_expr->top_level_item();
6145
  }
unknown's avatar
unknown committed
6146 6147 6148
}


6149
/*
unknown's avatar
unknown committed
6150 6151
  Mark that there is a NATURAL JOIN or JOIN ... USING between two
  tables.
6152 6153 6154

  SYNOPSIS
    add_join_natural()
unknown's avatar
unknown committed
6155 6156 6157
    a			Left join argument
    b			Right join argument
    using_fields        Field names from USING clause
unknown's avatar
unknown committed
6158
    lex                 The current st_select_lex
unknown's avatar
unknown committed
6159
  
6160
  IMPLEMENTATION
unknown's avatar
unknown committed
6161 6162 6163 6164 6165 6166 6167 6168 6169 6170
    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
6171 6172 6173
    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
6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184

    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
6185 6186
*/

unknown's avatar
unknown committed
6187 6188
void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
                      SELECT_LEX *lex)
unknown's avatar
unknown committed
6189
{
unknown's avatar
unknown committed
6190
  b->natural_join= a;
unknown's avatar
unknown committed
6191
  lex->prev_join_using= using_fields;
unknown's avatar
unknown committed
6192 6193
}

unknown's avatar
unknown committed
6194

6195
/*
6196 6197 6198 6199
  Reload/resets privileges and the different caches.

  SYNOPSIS
    reload_acl_and_cache()
6200
    thd			Thread handler (can be NULL!)
6201 6202 6203 6204 6205
    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
6206 6207 6208
                        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.
6209 6210 6211

  RETURN
    0	 ok
unknown's avatar
unknown committed
6212
    !=0  error.  thd->killed or thd->net.report_error is set
6213 6214
*/

6215 6216
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
                          bool *write_to_binlog)
unknown's avatar
unknown committed
6217 6218 6219
{
  bool result=0;
  select_errors=0;				/* Write if more errors */
6220
  bool tmp_write_to_binlog= 1;
6221

6222
  DBUG_ASSERT(!thd || !thd->in_sub_stmt);
6223

unknown's avatar
SCRUM  
unknown committed
6224
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
6225 6226
  if (options & REFRESH_GRANT)
  {
6227 6228 6229 6230 6231 6232
    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)))
6233 6234
    {
      thd->thread_stack= (char*) &tmp_thd;
6235
      thd->store_globals();
6236
    }
6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248
    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;
    }
6249
    reset_mqh((LEX_USER *)NULL, TRUE);
unknown's avatar
unknown committed
6250
  }
unknown's avatar
SCRUM  
unknown committed
6251
#endif
unknown's avatar
unknown committed
6252 6253
  if (options & REFRESH_LOG)
  {
6254
    /*
unknown's avatar
unknown committed
6255
      Flush the normal query log, the update log, the binary log,
unknown's avatar
unknown committed
6256 6257
      the slow query log, the relay log (if it exists) and the log
      tables.
6258
    */
unknown's avatar
unknown committed
6259

6260
    /*
unknown's avatar
unknown committed
6261 6262 6263 6264
      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)
6265 6266
    */
    tmp_write_to_binlog= 0;
6267 6268 6269 6270
    if( mysql_bin_log.is_open() )
    {
      mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
    }
unknown's avatar
unknown committed
6271
#ifdef HAVE_REPLICATION
6272
    pthread_mutex_lock(&LOCK_active_mi);
6273
    rotate_relay_log(active_mi);
6274
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
6275
#endif
unknown's avatar
unknown committed
6276 6277 6278 6279 6280

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

    if (ha_flush_logs(NULL))
unknown's avatar
unknown committed
6281
      result=1;
unknown's avatar
unknown committed
6282 6283
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
6284
  }
unknown's avatar
unknown committed
6285
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
6286 6287
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
6288
    query_cache.pack();				// FLUSH QUERY CACHE
6289
    options &= ~REFRESH_QUERY_CACHE;    // Don't flush cache, just free memory
unknown's avatar
unknown committed
6290 6291 6292
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
6293
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
6294
  }
unknown's avatar
unknown committed
6295
#endif /*HAVE_QUERY_CACHE*/
6296 6297 6298 6299 6300
  /*
    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
6301
  {
6302
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
6303
    {
6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314
      /*
        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
6315
        {
6316 6317 6318 6319 6320
          if ((*lock_p)->type == TL_WRITE)
          {
            my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
            return 1;
          }
unknown's avatar
unknown committed
6321
        }
6322
      }
unknown's avatar
unknown committed
6323 6324 6325 6326
      /*
	Writing to the binlog could cause deadlocks, as we don't log
	UNLOCK TABLES
      */
6327
      tmp_write_to_binlog= 0;
6328
      if (lock_global_read_lock(thd))
unknown's avatar
unknown committed
6329
	return 1;                               // Killed
6330 6331
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
                                 tables);
unknown's avatar
unknown committed
6332
      if (make_global_read_lock_block_commit(thd)) // Killed
6333 6334 6335 6336 6337
      {
        /* Don't leave things in a half-locked state */
        unlock_global_read_lock(thd);
        return 1;
      }
unknown's avatar
unknown committed
6338
    }
6339 6340
    else
      result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
unknown's avatar
unknown committed
6341
    my_dbopt_cleanup();
unknown's avatar
unknown committed
6342 6343 6344
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
unknown's avatar
unknown committed
6345
  if (thd && (options & REFRESH_STATUS))
unknown's avatar
unknown committed
6346
    refresh_status(thd);
unknown's avatar
unknown committed
6347 6348
  if (options & REFRESH_THREADS)
    flush_thread_cache();
unknown's avatar
unknown committed
6349
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
6350
  if (options & REFRESH_MASTER)
6351
  {
6352
    DBUG_ASSERT(thd);
6353
    tmp_write_to_binlog= 0;
6354
    if (reset_master(thd))
unknown's avatar
unknown committed
6355
    {
6356
      result=1;
unknown's avatar
unknown committed
6357 6358
      thd->fatal_error();                       // Ensure client get error
    }
6359
  }
6360
#endif
unknown's avatar
unknown committed
6361
#ifdef OPENSSL
6362 6363 6364 6365 6366 6367
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
unknown's avatar
unknown committed
6368
#ifdef HAVE_REPLICATION
6369 6370
 if (options & REFRESH_SLAVE)
 {
6371
   tmp_write_to_binlog= 0;
6372
   pthread_mutex_lock(&LOCK_active_mi);
6373
   if (reset_slave(thd, active_mi))
6374
     result=1;
6375
   pthread_mutex_unlock(&LOCK_active_mi);
6376
 }
6377
#endif
6378
 if (options & REFRESH_USER_RESOURCES)
6379
   reset_mqh((LEX_USER *) NULL, 0);             /* purecov: inspected */
unknown's avatar
unknown committed
6380
 *write_to_binlog= tmp_write_to_binlog;
6381
 return result;
unknown's avatar
unknown committed
6382 6383
}

6384

6385
/*
6386
  kills a thread
6387 6388 6389 6390 6391

  SYNOPSIS
    kill_one_thread()
    thd			Thread class
    id			Thread id
6392
    only_kill_query     Should it kill the query or the connection
6393 6394 6395 6396 6397

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

6398
uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
unknown's avatar
unknown committed
6399 6400 6401
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
6402 6403
  DBUG_ENTER("kill_one_thread");
  DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query));
6404 6405
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
6406 6407
  while ((tmp=it++))
  {
unknown's avatar
unknown committed
6408 6409
    if (tmp->command == COM_DAEMON)
      continue;
unknown's avatar
unknown committed
6410 6411
    if (tmp->thread_id == id)
    {
6412 6413
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
6414 6415 6416
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
6417 6418
  if (tmp)
  {
6419 6420
    if ((thd->security_ctx->master_access & SUPER_ACL) ||
	!strcmp(thd->security_ctx->user, tmp->security_ctx->user))
6421
    {
unknown's avatar
SCRUM  
unknown committed
6422
      tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
6423 6424 6425 6426 6427 6428
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }
6429 6430 6431 6432
  DBUG_PRINT("exit", ("%d", error));
  DBUG_RETURN(error);
}

6433

6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447
/*
  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)))
6448
    send_ok(thd);
unknown's avatar
unknown committed
6449
  else
unknown's avatar
unknown committed
6450
    my_error(error, MYF(0), id);
unknown's avatar
unknown committed
6451 6452
}

unknown's avatar
unknown committed
6453

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

unknown's avatar
unknown committed
6456 6457
bool append_file_to_dir(THD *thd, const char **filename_ptr,
                        const char *table_name)
6458
{
6459
  char buff[FN_REFLEN],*ptr, *end;
6460 6461 6462 6463 6464 6465 6466
  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))
  {
6467
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
6468 6469 6470 6471
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
6472
  end=convert_dirname(buff, *filename_ptr, NullS);
6473
  if (!(ptr= (char*) thd->alloc((size_t) (end-buff) + strlen(table_name)+1)))
6474 6475
    return 1;					// End of memory
  *filename_ptr=ptr;
6476
  strxmov(ptr,buff,table_name,NullS);
6477 6478
  return 0;
}
6479

6480

6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494
/*
  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;
6495 6496
  LEX *lex= thd->lex;
  if (lex->current_select != &lex->select_lex)
6497 6498
  {
    char command[80];
6499 6500 6501
    Lex_input_stream *lip= thd->m_lip;
    strmake(command, lip->yylval->symbol.str,
	    min(lip->yylval->symbol.length, sizeof(command)-1));
6502
    my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
6503 6504 6505 6506
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
6507

unknown's avatar
unknown committed
6508

unknown's avatar
unknown committed
6509
Comp_creator *comp_eq_creator(bool invert)
unknown's avatar
unknown committed
6510
{
unknown's avatar
unknown committed
6511
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
unknown's avatar
unknown committed
6512 6513
}

unknown's avatar
unknown committed
6514

unknown's avatar
unknown committed
6515
Comp_creator *comp_ge_creator(bool invert)
unknown's avatar
unknown committed
6516
{
unknown's avatar
unknown committed
6517
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
unknown's avatar
unknown committed
6518 6519
}

unknown's avatar
unknown committed
6520

unknown's avatar
unknown committed
6521
Comp_creator *comp_gt_creator(bool invert)
unknown's avatar
unknown committed
6522
{
unknown's avatar
unknown committed
6523
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
unknown's avatar
unknown committed
6524 6525
}

unknown's avatar
unknown committed
6526

unknown's avatar
unknown committed
6527
Comp_creator *comp_le_creator(bool invert)
unknown's avatar
unknown committed
6528
{
unknown's avatar
unknown committed
6529
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
unknown's avatar
unknown committed
6530 6531
}

unknown's avatar
unknown committed
6532

unknown's avatar
unknown committed
6533
Comp_creator *comp_lt_creator(bool invert)
unknown's avatar
unknown committed
6534
{
unknown's avatar
unknown committed
6535
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
unknown's avatar
unknown committed
6536 6537
}

unknown's avatar
unknown committed
6538

unknown's avatar
unknown committed
6539
Comp_creator *comp_ne_creator(bool invert)
unknown's avatar
unknown committed
6540
{
unknown's avatar
unknown committed
6541
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
unknown's avatar
unknown committed
6542
}
unknown's avatar
unknown committed
6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562


/*
  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
6563
  if ((cmp == &comp_eq_creator) && !all)       //  = ANY <=> IN
unknown's avatar
unknown committed
6564
    return new Item_in_subselect(left_expr, select_lex);
unknown's avatar
unknown committed
6565 6566

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

  Item_allany_subselect *it=
6570
    new Item_allany_subselect(left_expr, cmp, select_lex, all);
unknown's avatar
unknown committed
6571
  if (all)
6572
    return it->upper_item= new Item_func_not_all(it);	/* ALL */
unknown's avatar
unknown committed
6573

6574
  return it->upper_item= new Item_func_nop_all(it);      /* ANY/SOME */
unknown's avatar
unknown committed
6575
}
6576 6577 6578 6579 6580 6581 6582


/*
  Multi update query pre-check

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

unknown's avatar
unknown committed
6586
  RETURN VALUE
unknown's avatar
unknown committed
6587 6588
    FALSE OK
    TRUE  Error
6589
*/
unknown's avatar
unknown committed
6590

unknown's avatar
unknown committed
6591
bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
6592 6593 6594 6595 6596
{
  const char *msg= 0;
  TABLE_LIST *table;
  LEX *lex= thd->lex;
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
6597
  DBUG_ENTER("multi_update_precheck");
6598 6599 6600

  if (select_lex->item_list.elements != lex->value_list.elements)
  {
6601
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6602
    DBUG_RETURN(TRUE);
6603 6604 6605 6606 6607
  }
  /*
    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
6608
  for (table= tables; table; table= table->next_local)
6609
  {
6610 6611 6612
    if (table->derived)
      table->grant.privilege= SELECT_ACL;
    else if ((check_access(thd, UPDATE_ACL, table->db,
6613 6614
                           &table->grant.privilege, 0, 1,
                           test(table->schema_table)) ||
6615
              check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
unknown's avatar
unknown committed
6616
             (check_access(thd, SELECT_ACL, table->db,
6617 6618
                           &table->grant.privilege, 0, 0,
                           test(table->schema_table)) ||
6619
              check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
unknown's avatar
unknown committed
6620
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6621

unknown's avatar
VIEW  
unknown committed
6622
    table->table_in_first_from_clause= 1;
6623
  }
unknown's avatar
unknown committed
6624 6625 6626
  /*
    Is there tables of subqueries?
  */
6627
  if (&lex->select_lex != lex->all_selects_list)
6628
  {
6629
    DBUG_PRINT("info",("Checking sub query list"));
unknown's avatar
VIEW  
unknown committed
6630
    for (table= tables; table; table= table->next_global)
6631
    {
6632
      if (!table->table_in_first_from_clause)
6633 6634
      {
	if (check_access(thd, SELECT_ACL, table->db,
6635 6636
			 &table->grant.privilege, 0, 0,
                         test(table->schema_table)) ||
6637
	    check_grant(thd, SELECT_ACL, table, 0, 1, 0))
unknown's avatar
unknown committed
6638
	  DBUG_RETURN(TRUE);
6639 6640 6641 6642 6643 6644
      }
    }
  }

  if (select_lex->order_list.elements)
    msg= "ORDER BY";
6645
  else if (select_lex->select_limit)
6646 6647 6648 6649
    msg= "LIMIT";
  if (msg)
  {
    my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
unknown's avatar
unknown committed
6650
    DBUG_RETURN(TRUE);
6651
  }
unknown's avatar
unknown committed
6652
  DBUG_RETURN(FALSE);
6653 6654 6655 6656 6657 6658 6659
}

/*
  Multi delete query pre-check

  SYNOPSIS
    multi_delete_precheck()
unknown's avatar
unknown committed
6660
    thd			Thread handler
unknown's avatar
VIEW  
unknown committed
6661
    tables		Global/local table list
6662

unknown's avatar
unknown committed
6663
  RETURN VALUE
unknown's avatar
unknown committed
6664 6665
    FALSE OK
    TRUE  error
6666
*/
unknown's avatar
unknown committed
6667

6668
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
6669 6670 6671
{
  SELECT_LEX *select_lex= &thd->lex->select_lex;
  TABLE_LIST *aux_tables=
unknown's avatar
unknown committed
6672
    (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
6673
  TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
unknown's avatar
VIEW  
unknown committed
6674
  DBUG_ENTER("multi_delete_precheck");
unknown's avatar
unknown committed
6675

6676 6677
  /* sql_yacc guarantees that tables and aux_tables are not zero */
  DBUG_ASSERT(aux_tables != 0);
unknown's avatar
unknown committed
6678
  if (check_table_access(thd, SELECT_ACL, tables, 0))
6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689
    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
6690
    DBUG_RETURN(TRUE);
6691 6692 6693
  }
  thd->lex->query_tables_own_last= save_query_tables_own_last;

6694 6695
  if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
  {
unknown's avatar
unknown committed
6696 6697
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
6698
    DBUG_RETURN(TRUE);
6699
  }
6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724
  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
6725
  for (target_tbl= (TABLE_LIST *)lex->auxiliary_table_list.first;
6726
       target_tbl; target_tbl= target_tbl->next_local)
6727
  {
6728
    lex->table_count++;
6729 6730
    /* All tables in aux_tables must be found in FROM PART */
    TABLE_LIST *walk;
unknown's avatar
VIEW  
unknown committed
6731
    for (walk= tables; walk; walk= walk->next_local)
6732
    {
unknown's avatar
unknown committed
6733 6734 6735
      if (!my_strcasecmp(table_alias_charset,
			 target_tbl->alias, walk->alias) &&
	  !strcmp(walk->db, target_tbl->db))
6736 6737 6738 6739
	break;
    }
    if (!walk)
    {
6740
      my_error(ER_UNKNOWN_TABLE, MYF(0),
6741
               target_tbl->table_name, "MULTI DELETE");
unknown's avatar
unknown committed
6742
      DBUG_RETURN(TRUE);
6743
    }
unknown's avatar
unknown committed
6744 6745 6746 6747 6748
    if (!walk->derived)
    {
      target_tbl->table_name= walk->table_name;
      target_tbl->table_name_length= walk->table_name_length;
    }
unknown's avatar
unknown committed
6749
    walk->updating= target_tbl->updating;
unknown's avatar
unknown committed
6750
    walk->lock_type= target_tbl->lock_type;
unknown's avatar
VIEW  
unknown committed
6751
    target_tbl->correspondent_table= walk;	// Remember corresponding table
6752
  }
unknown's avatar
unknown committed
6753
  DBUG_RETURN(FALSE);
6754 6755 6756
}


unknown's avatar
unknown committed
6757 6758 6759 6760 6761
/*
  simple UPDATE query pre-check

  SYNOPSIS
    update_precheck()
unknown's avatar
unknown committed
6762 6763
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
6764 6765

  RETURN VALUE
unknown's avatar
unknown committed
6766 6767
    FALSE OK
    TRUE  Error
unknown's avatar
unknown committed
6768
*/
unknown's avatar
unknown committed
6769

unknown's avatar
unknown committed
6770
bool update_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
6771 6772 6773 6774
{
  DBUG_ENTER("update_precheck");
  if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
  {
unknown's avatar
unknown committed
6775
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6776
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6777
  }
unknown's avatar
unknown committed
6778
  DBUG_RETURN(check_one_table_access(thd, UPDATE_ACL, tables));
unknown's avatar
unknown committed
6779 6780 6781 6782 6783 6784 6785 6786
}


/*
  simple DELETE query pre-check

  SYNOPSIS
    delete_precheck()
unknown's avatar
unknown committed
6787 6788
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
6789 6790

  RETURN VALUE
unknown's avatar
unknown committed
6791 6792
    FALSE  OK
    TRUE   error
unknown's avatar
unknown committed
6793
*/
unknown's avatar
unknown committed
6794

unknown's avatar
unknown committed
6795
bool delete_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
6796 6797 6798
{
  DBUG_ENTER("delete_precheck");
  if (check_one_table_access(thd, DELETE_ACL, tables))
unknown's avatar
unknown committed
6799
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6800
  /* Set privilege for the WHERE clause */
unknown's avatar
unknown committed
6801
  tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
6802
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
6803 6804 6805 6806 6807 6808 6809 6810
}


/*
  simple INSERT query pre-check

  SYNOPSIS
    insert_precheck()
unknown's avatar
unknown committed
6811 6812
    thd		Thread handler
    tables	Global table list
unknown's avatar
unknown committed
6813 6814

  RETURN VALUE
unknown's avatar
unknown committed
6815 6816
    FALSE  OK
    TRUE   error
unknown's avatar
unknown committed
6817
*/
unknown's avatar
unknown committed
6818

unknown's avatar
merge  
unknown committed
6819
bool insert_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
6820 6821 6822 6823
{
  LEX *lex= thd->lex;
  DBUG_ENTER("insert_precheck");

unknown's avatar
unknown committed
6824 6825 6826 6827
  /*
    Check that we have modify privileges for the first table and
    select privileges for the rest
  */
unknown's avatar
unknown committed
6828 6829 6830
  ulong privilege= (INSERT_ACL |
                    (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
                    (lex->value_list.elements ? UPDATE_ACL : 0));
unknown's avatar
unknown committed
6831 6832

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

unknown's avatar
unknown committed
6835
  if (lex->update_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
6836
  {
unknown's avatar
unknown committed
6837
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6838
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6839
  }
unknown's avatar
unknown committed
6840
  DBUG_RETURN(FALSE);
6841
}
unknown's avatar
unknown committed
6842 6843


unknown's avatar
unknown committed
6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858
/**
    @brief  Check privileges for SHOW CREATE TABLE statement.

    @param  thd    Thread context
    @param  table  Target table

    @retval TRUE  Failure
    @retval FALSE Success
*/

static bool check_show_create_table_access(THD *thd, TABLE_LIST *table)
{
  return check_access(thd, SELECT_ACL | EXTRA_ACL, table->db,
                      &table->grant.privilege, 0, 0,
                      test(table->schema_table)) ||
6859
         check_grant(thd, SELECT_ACL, table, 2, UINT_MAX, 0);
unknown's avatar
unknown committed
6860 6861 6862
}


unknown's avatar
unknown committed
6863 6864 6865 6866 6867
/*
  CREATE TABLE query pre-check

  SYNOPSIS
    create_table_precheck()
unknown's avatar
unknown committed
6868 6869 6870
    thd			Thread handler
    tables		Global table list
    create_table	Table which will be created
unknown's avatar
unknown committed
6871 6872

  RETURN VALUE
unknown's avatar
unknown committed
6873 6874
    FALSE   OK
    TRUE   Error
unknown's avatar
unknown committed
6875
*/
unknown's avatar
unknown committed
6876

unknown's avatar
unknown committed
6877 6878
bool create_table_precheck(THD *thd, TABLE_LIST *tables,
                           TABLE_LIST *create_table)
unknown's avatar
unknown committed
6879 6880
{
  LEX *lex= thd->lex;
6881 6882
  SELECT_LEX *select_lex= &lex->select_lex;
  ulong want_priv;
unknown's avatar
merge  
unknown committed
6883
  bool error= TRUE;                                 // Error message is given
unknown's avatar
unknown committed
6884
  DBUG_ENTER("create_table_precheck");
6885 6886 6887

  want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
              CREATE_TMP_ACL : CREATE_ACL);
unknown's avatar
unknown committed
6888
  if (check_access(thd, want_priv, create_table->db,
6889 6890
		   &create_table->grant.privilege, 0, 0,
                   test(create_table->schema_table)) ||
unknown's avatar
unknown committed
6891 6892 6893
      check_merge_table_access(thd, create_table->db,
			       (TABLE_LIST *)
			       lex->create_info.merge_list.first))
6894
    goto err;
6895
  if (want_priv != CREATE_TMP_ACL &&
6896
      check_grant(thd, want_priv, create_table, 0, 1, 0))
6897 6898 6899 6900 6901 6902
    goto err;

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

6903 6904
#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
    /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
6905
    /*
6906
      Only do the check for PS, because we on execute we have to check that
unknown's avatar
unknown committed
6907 6908
      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).
6909
    */
unknown's avatar
unknown committed
6910
    if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
6911
    {
unknown's avatar
unknown committed
6912 6913 6914 6915
      /*
        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
6916
          find_table_in_global_list(tables, create_table->db,
6917
                                    create_table->table_name))
unknown's avatar
unknown committed
6918
      {
6919
	error= FALSE;
unknown's avatar
unknown committed
6920 6921 6922
        goto err;
      }
    }
6923
#endif
6924 6925 6926
    if (tables && check_table_access(thd, SELECT_ACL, tables,0))
      goto err;
  }
unknown's avatar
unknown committed
6927 6928 6929 6930 6931
  else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
  {
    if (check_show_create_table_access(thd, tables))
      goto err;
  }
unknown's avatar
merge  
unknown committed
6932
  error= FALSE;
6933 6934 6935

err:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
6936
}
unknown's avatar
unknown committed
6937 6938 6939 6940 6941 6942 6943


/*
  negate given expression

  SYNOPSIS
    negate_expression()
6944
    thd  thread handler
unknown's avatar
unknown committed
6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972
    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);
}
6973

6974 6975
/*
  Set the specified definer to the default value, which is the current user in
6976
  the thread.
6977 6978 6979 6980 6981 6982 6983
 
  SYNOPSIS
    get_default_definer()
    thd       [in] thread handler
    definer   [out] definer
*/
 
6984
void get_default_definer(THD *thd, LEX_USER *definer)
6985 6986 6987 6988 6989 6990 6991 6992 6993 6994
{
  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);
}

6995

6996
/*
6997
  Create default definer for the specified THD.
6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015

  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;

7016
  get_default_definer(thd, definer);
7017 7018 7019 7020 7021

  return definer;
}


7022
/*
7023
  Create definer with the given user and host names.
7024 7025

  SYNOPSIS
7026 7027 7028 7029
    create_definer()
    thd         [in] thread handler
    user_name   [in] user name
    host_name   [in] host name
7030 7031

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

7037
LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
7038
{
7039 7040 7041 7042
  LEX_USER *definer;

  /* Create and initialize. */

unknown's avatar
unknown committed
7043
  if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
7044 7045 7046 7047 7048 7049
    return 0;

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

  return definer;
7050
}
7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069


/*
  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
7070 7071
    return create_default_definer(thd);

7072 7073
  return user;
}
7074 7075 7076


/*
7077
  Check that byte length of a string does not exceed some limit.
7078 7079

  SYNOPSIS
7080 7081 7082 7083
  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
7084 7085 7086 7087

  RETURN
    FALSE   the passed string is not longer than max_length
    TRUE    the passed string is longer than max_length
7088 7089 7090

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

7093 7094
bool check_string_byte_length(LEX_STRING *str, const char *err_msg,
                              uint max_byte_length)
7095
{
7096
  if (str->length <= max_byte_length)
unknown's avatar
unknown committed
7097
    return FALSE;
7098

7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130
  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
7131

7132 7133
  if (!no_error)
    my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_char_length);
7134 7135
  return TRUE;
}