sql_parse.cc 220 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
/**
  @defgroup Runtime_Environment Runtime Environment
  @{
*/

36 37 38 39 40 41
/* 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 || \
42
   (LP)->sql_command == SQLCOM_SHOW_CREATE_FUNC || \
43 44 45
   (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
   "FUNCTION" : "PROCEDURE")

46
static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
unknown's avatar
unknown committed
47
static bool check_show_create_table_access(THD *thd, TABLE_LIST *table);
unknown's avatar
unknown committed
48

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

unknown's avatar
unknown committed
51
const LEX_STRING command_name[]={
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 78 79 80 81 82
  { 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
83 84
};

unknown's avatar
unknown committed
85 86 87 88
const char *xa_state_names[]={
  "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
};

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

99

100
bool end_active_trans(THD *thd)
101
{
unknown's avatar
unknown committed
102
  int error=0;
103
  DBUG_ENTER("end_active_trans");
104
  if (unlikely(thd->in_sub_stmt))
105 106 107 108
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    DBUG_RETURN(1);
  }
109 110 111 112 113 114
  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
115
  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
unknown's avatar
unknown committed
116
		      OPTION_TABLE_LOCK))
117
  {
118
    DBUG_PRINT("info",("options: 0x%llx", thd->options));
119 120 121
    /* Safety if one did "drop table" on locked tables */
    if (!thd->locked_tables)
      thd->options&= ~OPTION_TABLE_LOCK;
122
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
123
    if (ha_commit(thd))
unknown's avatar
unknown committed
124
      error=1;
125
  }
126
  thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
unknown's avatar
unknown committed
127
  thd->transaction.all.modified_non_trans_table= FALSE;
128
  DBUG_RETURN(error);
129 130
}

131

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

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


171 172 173 174 175 176 177 178 179 180 181 182
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;
}

183

unknown's avatar
unknown committed
184 185 186 187
/**
  Mark all commands that somehow changes a table.

  This is used to check number of updates / hour.
unknown's avatar
unknown committed
188 189 190

  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
191

192
  See COMMAND_FLAG_xxx for different type of commands
unknown's avatar
unknown committed
193 194
     2  - query that returns meaningful ROW_COUNT() -
          a number of modified rows
195 196
*/

197
uint sql_command_flags[SQLCOM_END+1];
198 199 200

void init_update_queries(void)
{
201
  bzero((uchar*) &sql_command_flags, sizeof(sql_command_flags));
202 203 204

  sql_command_flags[SQLCOM_CREATE_TABLE]=   CF_CHANGES_DATA;
  sql_command_flags[SQLCOM_CREATE_INDEX]=   CF_CHANGES_DATA;
205 206
  sql_command_flags[SQLCOM_ALTER_TABLE]=    CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
  sql_command_flags[SQLCOM_TRUNCATE]=       CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
207 208 209 210 211 212 213 214 215 216 217 218
  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;
219
  sql_command_flags[SQLCOM_DROP_EVENT]=     CF_CHANGES_DATA;
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241

  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]=      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;
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
  sql_command_flags[SQLCOM_SHOW_NEW_MASTER]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_BINLOGS]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_SLAVE_HOSTS]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_BINLOG_EVENTS]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_COLUMN_TYPES]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_STORAGE_ENGINES]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_AUTHORS]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_CONTRIBUTORS]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_PRIVILEGES]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_WARNS]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_ERRORS]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_ENGINE_STATUS]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_ENGINE_MUTEX]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_ENGINE_LOGS]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_PROCESSLIST]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_GRANTS]=  CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_CREATE_DB]=  CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_CREATE]=  CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_MASTER_STAT]=  CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]=  CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_CREATE_PROC]=  CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]=  CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]=  CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]=  CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_PROC_CODE]=  CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_FUNC_CODE]=  CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]=  CF_STATUS_COMMAND;
269 270
  sql_command_flags[SQLCOM_SHOW_PROFILES]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND;
271 272 273

   sql_command_flags[SQLCOM_SHOW_TABLES]=       (CF_STATUS_COMMAND |
                                               CF_SHOW_TABLE_COMMAND);
274 275 276 277 278 279 280 281 282 283 284
  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;
285 286 287 288 289 290 291 292

  /*
    The following admin table operations are allowed
    on log tables.
  */
  sql_command_flags[SQLCOM_REPAIR]=           CF_WRITE_LOGS_COMMAND;
  sql_command_flags[SQLCOM_OPTIMIZE]=         CF_WRITE_LOGS_COMMAND;
  sql_command_flags[SQLCOM_ANALYZE]=          CF_WRITE_LOGS_COMMAND;
293 294
}

295

unknown's avatar
unknown committed
296 297
bool is_update_query(enum enum_sql_command command)
{
unknown's avatar
unknown committed
298
  DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
299
  return (sql_command_flags[command] & CF_CHANGES_DATA) != 0;
unknown's avatar
unknown committed
300
}
301

302 303 304 305 306 307 308 309 310 311
/**
  Check if a sql command is allowed to write to log tables.
  @param command The SQL command
  @return true if writing is allowed
*/
bool is_log_table_write_query(enum enum_sql_command command)
{
  DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
  return (sql_command_flags[command] & CF_WRITE_LOGS_COMMAND) != 0;
}
312

313 314
void execute_init_command(THD *thd, sys_var_str *init_command_var,
			  rw_lock_t *var_mutex)
unknown's avatar
unknown committed
315 316 317 318
{
  Vio* save_vio;
  ulong save_client_capabilities;

319
  thd_proc_info(thd, "Execution of init_command");
320 321 322 323 324 325
  /*
    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);
unknown's avatar
unknown committed
326 327
  save_client_capabilities= thd->client_capabilities;
  thd->client_capabilities|= CLIENT_MULTI_QUERIES;
328 329 330 331
  /*
    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
332 333
  save_vio= thd->net.vio;
  thd->net.vio= 0;
334 335 336
  dispatch_command(COM_QUERY, thd,
                   init_command_var->value,
                   init_command_var->value_length);
337
  rw_unlock(var_mutex);
unknown's avatar
unknown committed
338 339 340 341 342
  thd->client_capabilities= save_client_capabilities;
  thd->net.vio= save_vio;
}


unknown's avatar
unknown committed
343
/**
344
  Execute commands from bootstrap_file.
unknown's avatar
unknown committed
345 346

  Used when creating the initial grant tables.
347
*/
unknown's avatar
unknown committed
348

349
pthread_handler_t handle_bootstrap(void *arg)
unknown's avatar
unknown committed
350
{
351 352 353
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
354
  const char* found_semicolon= NULL;
unknown's avatar
unknown committed
355

356
  /* The following must be called before DBUG_ENTER */
357
  thd->thread_stack= (char*) &thd;
358
  if (my_thread_init() || thd->store_globals())
unknown's avatar
unknown committed
359
  {
unknown's avatar
unknown committed
360
#ifndef EMBEDDED_LIBRARY
361
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
unknown's avatar
unknown committed
362
#endif
363
    thd->fatal_error();
364
    goto end;
unknown's avatar
unknown committed
365
  }
366 367
  DBUG_ENTER("handle_bootstrap");

unknown's avatar
unknown committed
368
#ifndef EMBEDDED_LIBRARY
369 370
  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
371
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
372

373
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
374 375
    thd->options |= OPTION_BIG_SELECTS;

376
  thd_proc_info(thd, 0);
unknown's avatar
unknown committed
377
  thd->version=refresh_version;
378 379
  thd->security_ctx->priv_user=
    thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
unknown's avatar
unknown committed
380
  thd->security_ctx->priv_host[0]=0;
381 382 383 384 385 386
  /*
    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
387

388
  buff= (char*) thd->net.buff;
389
  thd->init_for_queries();
unknown's avatar
unknown committed
390 391
  while (fgets(buff, thd->net.max_packet, file))
  {
392 393 394 395 396 397 398 399 400 401 402
    /* 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))
      {
403 404
        net_end_statement(thd);
        bootstrap_error= 1;
405 406 407 408 409 410 411
        break;
      }
      buff= (char*) thd->net.buff;
      fgets(buff + length, thd->net.max_packet - length, file);
      length+= (ulong) strlen(buff + length);
      /* purecov: end */
    }
412
    if (bootstrap_error)
413
      break;                                    /* purecov: inspected */
unknown's avatar
unknown committed
414

unknown's avatar
unknown committed
415
    while (length && (my_isspace(thd->charset(), buff[length-1]) ||
416
                      buff[length-1] == ';'))
unknown's avatar
unknown committed
417 418
      length--;
    buff[length]=0;
unknown's avatar
unknown committed
419 420 421 422 423

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

424
    thd->query_length=length;
425 426 427
    thd->query= (char*) thd->memdup_w_gap(buff, length+1, 
                                          thd->db_length+1+
                                          QUERY_CACHE_FLAGS_SIZE);
unknown's avatar
unknown committed
428
    thd->query[length] = '\0';
429
    DBUG_PRINT("query",("%-.4096s",thd->query));
430 431 432 433
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
    thd->profiling.set_query_source(thd->query, length);
#endif

434 435 436 437
    /*
      We don't need to obtain LOCK_thread_count here because in bootstrap
      mode we have only one thread.
    */
438
    thd->query_id=next_query_id();
439
    thd->set_time();
440
    mysql_parse(thd, thd->query, length, & found_semicolon);
unknown's avatar
unknown committed
441
    close_thread_tables(thd);			// Free tables
442

443 444
    bootstrap_error= thd->is_error();
    net_end_statement(thd);
445

446
    if (bootstrap_error)
447 448
      break;

unknown's avatar
unknown committed
449
    free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
450
#ifdef USING_TRANSACTIONS
451
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
452
#endif
unknown's avatar
unknown committed
453
  }
454 455

end:
456 457 458 459
  net_end(&thd->net);
  thd->cleanup();
  delete thd;

unknown's avatar
unknown committed
460
#ifndef EMBEDDED_LIBRARY
461 462 463
  (void) pthread_mutex_lock(&LOCK_thread_count);
  thread_count--;
  (void) pthread_mutex_unlock(&LOCK_thread_count);
464
  (void) pthread_cond_broadcast(&COND_thread_count);
465 466
  my_thread_end();
  pthread_exit(0);
unknown's avatar
unknown committed
467
#endif
468
  DBUG_RETURN(0);
unknown's avatar
unknown committed
469 470 471
}


472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
/**
  @brief Check access privs for a MERGE table and fix children lock types.

  @param[in]        thd         thread handle
  @param[in]        db          database name
  @param[in,out]    table_list  list of child tables (merge_list)
                                lock_type and optionally db set per table

  @return           status
    @retval         0           OK
    @retval         != 0        Error

  @detail
    This function is used for write access to MERGE tables only
    (CREATE TABLE, ALTER TABLE ... UNION=(...)). Set TL_WRITE for
    every child. Set 'db' for every child if not present.
*/
unknown's avatar
unknown committed
489
#ifndef NO_EMBEDDED_ACCESS_CHECKS
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
static bool check_merge_table_access(THD *thd, char *db,
                                     TABLE_LIST *table_list)
{
  int error= 0;

  if (table_list)
  {
    /* Check that all tables use the current database */
    TABLE_LIST *tlist;

    for (tlist= table_list; tlist; tlist= tlist->next_local)
    {
      if (!tlist->db || !tlist->db[0])
        tlist->db= db; /* purecov: inspected */
    }
    error= check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
506
                              table_list, UINT_MAX, FALSE);
507 508 509
  }
  return error;
}
unknown's avatar
unknown committed
510
#endif
511

unknown's avatar
unknown committed
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
/* 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() */
527 528 529

void cleanup_items(Item *item)
{
unknown's avatar
unknown committed
530
  DBUG_ENTER("cleanup_items");  
531 532
  for (; item ; item=item->next)
    item->cleanup();
unknown's avatar
unknown committed
533
  DBUG_VOID_RETURN;
534 535
}

unknown's avatar
unknown committed
536 537
/**
  Handle COM_TABLE_DUMP command.
unknown's avatar
unknown committed
538

unknown's avatar
unknown committed
539 540 541 542
  @param thd           thread handle
  @param db            database name or an empty string. If empty,
                       the current database of the connection is used
  @param tbl_name      name of the table to dump
unknown's avatar
unknown committed
543

unknown's avatar
unknown committed
544
  @note
unknown's avatar
unknown committed
545 546
    This function is written to handle one specific command only.

unknown's avatar
unknown committed
547
  @retval
unknown's avatar
unknown committed
548
    0               success
unknown's avatar
unknown committed
549
  @retval
unknown's avatar
unknown committed
550 551 552 553
    1               error, the error message is set in THD
*/

static
554
int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name)
unknown's avatar
unknown committed
555 556 557 558 559
{
  TABLE* table;
  TABLE_LIST* table_list;
  int error = 0;
  DBUG_ENTER("mysql_table_dump");
560 561 562 563 564
  if (db->length == 0)
  {
    db->str= thd->db;            /* purecov: inspected */
    db->length= thd->db_length;  /* purecov: inspected */
  }
565
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
566
    DBUG_RETURN(1); // out of memory
567
  table_list->db= db->str;
568
  table_list->table_name= table_list->alias= tbl_name;
unknown's avatar
VIEW  
unknown committed
569 570
  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
571

572
  if (check_db_name(db))
573
  {
574 575
    /* purecov: begin inspected */
    my_error(ER_WRONG_DB_NAME ,MYF(0), db->str ? db->str : "NULL");
576
    goto err;
577
    /* purecov: end */
578
  }
579
  if (lower_case_table_names)
580
    my_casedn_str(files_charset_info, tbl_name);
581

582
  if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT, 0)))
583 584
    DBUG_RETURN(1);

unknown's avatar
unknown committed
585
  if (check_one_table_access(thd, SELECT_ACL, table_list))
unknown's avatar
unknown committed
586 587
    goto err;
  thd->free_list = 0;
unknown's avatar
unknown committed
588
  thd->query_length=(uint) strlen(tbl_name);
unknown's avatar
unknown committed
589
  thd->query = tbl_name;
unknown's avatar
unknown committed
590
  if ((error = mysqld_dump_create_info(thd, table_list, -1)))
591
  {
592
    my_error(ER_GET_ERRNO, MYF(0), my_errno);
593 594
    goto err;
  }
unknown's avatar
unknown committed
595
  net_flush(&thd->net);
unknown's avatar
unknown committed
596
  if ((error= table->file->dump(thd,-1)))
597
    my_error(ER_GET_ERRNO, MYF(0), error);
unknown's avatar
unknown committed
598

unknown's avatar
unknown committed
599
err:
unknown's avatar
unknown committed
600
  DBUG_RETURN(error);
unknown's avatar
unknown committed
601 602
}

unknown's avatar
unknown committed
603 604
/**
  Ends the current transaction and (maybe) begin the next.
unknown's avatar
unknown committed
605

unknown's avatar
unknown committed
606 607
  @param thd            Current thread
  @param completion     Completion type
unknown's avatar
unknown committed
608

unknown's avatar
unknown committed
609 610
  @retval
    0   OK
unknown's avatar
unknown committed
611 612
*/

613
int end_trans(THD *thd, enum enum_mysql_completiontype completion)
unknown's avatar
unknown committed
614 615 616
{
  bool do_release= 0;
  int res= 0;
617
  DBUG_ENTER("end_trans");
unknown's avatar
unknown committed
618

619
  if (unlikely(thd->in_sub_stmt))
620 621 622 623
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    DBUG_RETURN(1);
  }
624 625 626 627 628 629
  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
630 631 632 633 634 635 636 637
  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;
638
    res= ha_commit(thd);
639
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
unknown's avatar
unknown committed
640
    thd->transaction.all.modified_non_trans_table= FALSE;
unknown's avatar
unknown committed
641 642
    break;
  case COMMIT_RELEASE:
unknown's avatar
unknown committed
643
    do_release= 1; /* fall through */
unknown's avatar
unknown committed
644 645 646 647 648 649
  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
650
    do_release= 1; /* fall through */
unknown's avatar
unknown committed
651 652 653 654
  case ROLLBACK:
  case ROLLBACK_AND_CHAIN:
  {
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
unknown's avatar
unknown committed
655
    if (ha_rollback(thd))
unknown's avatar
unknown committed
656
      res= -1;
657
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
unknown's avatar
unknown committed
658
    thd->transaction.all.modified_non_trans_table= FALSE;
unknown's avatar
unknown committed
659 660 661 662 663 664 665 666 667
    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
668

unknown's avatar
unknown committed
669 670 671
  if (res < 0)
    my_error(thd->killed_errno(), MYF(0));
  else if ((res == 0) && do_release)
unknown's avatar
unknown committed
672 673
    thd->killed= THD::KILL_CONNECTION;

unknown's avatar
unknown committed
674 675
  DBUG_RETURN(res);
}
unknown's avatar
unknown committed
676

677
#ifndef EMBEDDED_LIBRARY
678

unknown's avatar
unknown committed
679
/**
unknown's avatar
unknown committed
680
  Read one command from connection and execute it (query or simple command).
681
  This function is called in loop from thread function.
682 683 684

  For profiling to work, it must never be called recursively.

unknown's avatar
unknown committed
685
  @retval
686
    0  success
unknown's avatar
unknown committed
687
  @retval
688 689 690
    1  request of thread shutdown (see dispatch_command() description)
*/

unknown's avatar
unknown committed
691 692
bool do_command(THD *thd)
{
693
  bool return_value;
unknown's avatar
unknown committed
694
  char *packet= 0;
unknown's avatar
unknown committed
695
  ulong packet_length;
unknown's avatar
unknown committed
696
  NET *net= &thd->net;
unknown's avatar
unknown committed
697 698 699
  enum enum_server_command command;
  DBUG_ENTER("do_command");

unknown's avatar
unknown committed
700 701 702 703
  /*
    indicator of uninitialized lex => normal flow of errors handling
    (see my_message_sql)
  */
704
  thd->lex->current_select= 0;
unknown's avatar
unknown committed
705

unknown's avatar
unknown committed
706 707 708 709 710 711
  /*
    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
  */
712
  my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
unknown's avatar
unknown committed
713

714 715 716 717
  /*
    XXX: this code is here only to clear possible errors of init_connect. 
    Consider moving to init_connect() instead.
  */
unknown's avatar
unknown committed
718
  thd->clear_error();				// Clear error message
719
  thd->main_da.reset_diagnostics_area();
unknown's avatar
unknown committed
720 721

  net_new_transaction(net);
722 723 724 725 726 727

  packet_length= my_net_read(net);
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
  thd->profiling.start_new_query();
#endif
  if (packet_length == packet_error)
unknown's avatar
unknown committed
728
  {
729 730 731
    DBUG_PRINT("info",("Got error %d reading command from socket %s",
		       net->error,
		       vio_description(net->vio)));
732

733
    /* Check if we can continue without closing the connection */
734

735 736 737 738
    /* The error must be set. */
    DBUG_ASSERT(thd->is_error());
    net_end_statement(thd);

739
    if (net->error != 3)
740
    {
741
      return_value= TRUE;                       // We have to close it.
742 743
      goto out;
    }
744

745
    net->error= 0;
746 747
    return_value= FALSE;
    goto out;
unknown's avatar
unknown committed
748
  }
749 750 751 752 753 754 755 756 757 758 759

  packet= (char*) net->read_pos;
  /*
    'packet_length' contains length of data, as it was stored in packet
    header. In case of malformed header, my_net_read returns zero.
    If packet_length is not zero, my_net_read ensures that the returned
    number of bytes was actually read from network.
    There is also an extra safety measure in my_net_read:
    it sets packet[packet_length]= 0, but only for non-zero packets.
  */
  if (packet_length == 0)                       /* safety */
unknown's avatar
unknown committed
760
  {
761 762 763
    /* Initialize with COM_SLEEP packet */
    packet[0]= (uchar) COM_SLEEP;
    packet_length= 1;
unknown's avatar
unknown committed
764
  }
765 766 767 768 769 770 771 772 773 774 775
  /* Do not rely on my_net_read, extra safety against programming errors. */
  packet[packet_length]= '\0';                  /* safety */

  command= (enum enum_server_command) (uchar) packet[0];

  if (command >= COM_END)
    command= COM_END;				// Wrong command

  DBUG_PRINT("info",("Command on %s = %d (%s)",
                     vio_description(net->vio), command,
                     command_name[command].str));
unknown's avatar
unknown committed
776 777

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

780
  DBUG_ASSERT(packet_length);
781 782 783 784 785 786 787
  return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1));

out:
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
  thd->profiling.finish_current_query();
#endif
  DBUG_RETURN(return_value);
788
}
789
#endif  /* EMBEDDED_LIBRARY */
790

791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
/**
  @brief Determine if an attempt to update a non-temporary table while the
    read-only option was enabled has been made.

  This is a helper function to mysql_execute_command.

  @note SQLCOM_MULTI_UPDATE is an exception and delt with elsewhere.

  @see mysql_execute_command
  @returns Status code
    @retval TRUE The statement should be denied.
    @retval FALSE The statement isn't updating any relevant tables.
*/

static my_bool deny_updates_if_read_only_option(THD *thd,
                                                TABLE_LIST *all_tables)
{
  DBUG_ENTER("deny_updates_if_read_only_option");

  if (!opt_readonly)
    DBUG_RETURN(FALSE);

  LEX *lex= thd->lex;

  const my_bool user_is_super=
    ((ulong)(thd->security_ctx->master_access & SUPER_ACL) ==
     (ulong)SUPER_ACL);

  if (user_is_super)
    DBUG_RETURN(FALSE);

822
  if (!(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA))
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
    DBUG_RETURN(FALSE);

  /* Multi update is an exception and is dealt with later. */
  if (lex->sql_command == SQLCOM_UPDATE_MULTI)
    DBUG_RETURN(FALSE);

  const my_bool create_temp_tables= 
    (lex->sql_command == SQLCOM_CREATE_TABLE) &&
    (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE);

  const my_bool drop_temp_tables= 
    (lex->sql_command == SQLCOM_DROP_TABLE) &&
    lex->drop_temporary;

  const my_bool update_real_tables=
    some_non_temp_table_to_be_updated(thd, all_tables) &&
    !(create_temp_tables || drop_temp_tables);


  const my_bool create_or_drop_databases=
    (lex->sql_command == SQLCOM_CREATE_DB) ||
    (lex->sql_command == SQLCOM_DROP_DB);

  if (update_real_tables || create_or_drop_databases)
  {
      /*
        An attempt was made to modify one or more non-temporary tables.
      */
      DBUG_RETURN(TRUE);
  }


  /* Assuming that only temporary tables are modified. */
  DBUG_RETURN(FALSE);
}
858

unknown's avatar
unknown committed
859 860
/**
  Perform one connection-level (COM_XXXX) command.
861

unknown's avatar
unknown committed
862 863 864 865 866 867 868 869
  @param command         type of command to perform
  @param thd             connection handle
  @param packet          data for the command, packet is always null-terminated
  @param packet_length   length of packet + 1 (to show that data is
                         null-terminated) except for COM_SLEEP, where it
                         can be zero.

  @todo
870 871 872
    set thd->lex->sql_command to SQLCOM_END here.
  @todo
    The following has to be changed to an 8 byte integer
unknown's avatar
unknown committed
873 874

  @retval
875
    0   ok
unknown's avatar
unknown committed
876
  @retval
877 878 879
    1   request of thread shutdown, i. e. if command is
        COM_QUIT/COM_SHUTDOWN
*/
880 881 882 883
bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
884
  bool error= 0;
885
  DBUG_ENTER("dispatch_command");
886
  DBUG_PRINT("info",("packet: '%*.s'; command: %d", packet_length, packet, command));
887

888
  thd->command=command;
unknown's avatar
unknown committed
889
  /*
890 891
    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
892
  */
893
  thd->enable_slow_log= TRUE;
894
  thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
unknown's avatar
unknown committed
895
  thd->set_time();
unknown's avatar
unknown committed
896
  VOID(pthread_mutex_lock(&LOCK_thread_count));
unknown's avatar
unknown committed
897
  thd->query_id= global_query_id;
unknown's avatar
unknown committed
898
  if (command != COM_STATISTICS && command != COM_PING)
899
    next_query_id();
unknown's avatar
unknown committed
900
  thread_running++;
901
  /* TODO: set thd->lex->sql_command to SQLCOM_END here */
unknown's avatar
unknown committed
902
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
903

904 905
  thd->server_status&=
           ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
906
  switch (command) {
unknown's avatar
unknown committed
907
  case COM_INIT_DB:
unknown's avatar
unknown committed
908 909
  {
    LEX_STRING tmp;
910
    status_var_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB]);
unknown's avatar
unknown committed
911
    thd->convert_string(&tmp, system_charset_info,
912
			packet, packet_length, thd->charset());
unknown's avatar
unknown committed
913
    if (!mysql_change_db(thd, &tmp, FALSE))
914
    {
915
      general_log_write(thd, command, thd->db, thd->db_length);
916 917
      send_ok(thd);
    }
unknown's avatar
unknown committed
918 919
    break;
  }
unknown's avatar
unknown committed
920
#ifdef HAVE_REPLICATION
921 922
  case COM_REGISTER_SLAVE:
  {
923
    if (!register_slave(thd, (uchar*)packet, packet_length))
924
      send_ok(thd);
925 926
    break;
  }
927
#endif
unknown's avatar
unknown committed
928
  case COM_TABLE_DUMP:
929
  {
930 931
    char *tbl_name;
    LEX_STRING db;
932
    /* Safe because there is always a trailing \0 at the end of the packet */
933
    uint db_len= *(uchar*) packet;
934
    if (db_len + 1 > packet_length || db_len > NAME_LEN)
unknown's avatar
unknown committed
935
    {
unknown's avatar
unknown committed
936
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
937 938
      break;
    }
939
    /* Safe because there is always a trailing \0 at the end of the packet */
940
    uint tbl_len= *(uchar*) (packet + db_len + 1);
941
    if (db_len + tbl_len + 2 > packet_length || tbl_len > NAME_LEN)
unknown's avatar
unknown committed
942
    {
unknown's avatar
unknown committed
943
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
944 945
      break;
    }
946

947
    status_var_increment(thd->status_var.com_other);
948
    thd->enable_slow_log= opt_log_slow_admin_statements;
949
    db.str= (char*) thd->alloc(db_len + tbl_len + 2);
950
    if (!db.str)
951 952 953 954
    {
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
      break;
    }
955
    db.length= db_len;
956
    tbl_name= strmake(db.str, packet + 1, db_len)+1;
957
    strmake(tbl_name, packet + db_len + 2, tbl_len);
958 959
    if (mysql_table_dump(thd, &db, tbl_name) == 0)
      thd->main_da.disable_status();
960 961
    break;
  }
unknown's avatar
unknown committed
962 963
  case COM_CHANGE_USER:
  {
964
    status_var_increment(thd->status_var.com_other);
965 966
    char *user= (char*) packet, *packet_end= packet + packet_length;
    /* Safe because there is always a trailing \0 at the end of the packet */
967 968
    char *passwd= strend(user)+1;

unknown's avatar
unknown committed
969
    thd->change_user();
970
    thd->clear_error();                         // if errors from rollback
unknown's avatar
unknown committed
971

972
    /*
unknown's avatar
unknown committed
973 974 975
      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).
976 977 978

      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
979
    */
980
    char db_buff[NAME_LEN+1];                 // buffer to store db in utf8
unknown's avatar
unknown committed
981
    char *db= passwd;
982
    char *save_db;
983 984 985 986 987 988 989 990 991
    /*
      If there is no password supplied, the packet must contain '\0',
      in any type of handshake (4.1 or pre-4.1).
     */
    if (passwd >= packet_end)
    {
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
      break;
    }
992
    uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
993
                      (uchar)(*passwd++) : strlen(passwd));
994 995
    uint dummy_errors, save_db_length, db_length;
    int res;
996 997 998
    Security_context save_security_ctx= *thd->security_ctx;
    USER_CONN *save_user_connect;

unknown's avatar
unknown committed
999
    db+= passwd_len + 1;
1000 1001 1002 1003 1004
    /*
      Database name is always NUL-terminated, so in case of empty database
      the packet must contain at least the trailing '\0'.
    */
    if (db >= packet_end)
1005
    {
unknown's avatar
unknown committed
1006
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1007 1008
      break;
    }
1009 1010
    db_length= strlen(db);

1011
    char *ptr= db + db_length + 1;
1012 1013
    uint cs_number= 0;

1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
    if (ptr < packet_end)
    {
      if (ptr + 2 > packet_end)
      {
        my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
        break;
      }

      cs_number= uint2korr(ptr);
    }
1024

1025
    /* Convert database name to utf8 */
1026
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
1027
                             system_charset_info, db, db_length,
1028
                             thd->charset(), &dummy_errors)]= 0;
1029
    db= db_buff;
unknown's avatar
unknown committed
1030

1031
    /* Save user and privileges */
1032 1033 1034
    save_db_length= thd->db_length;
    save_db= thd->db;
    save_user_connect= thd->user_connect;
1035 1036

    if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
1037
    {
1038
      thd->security_ctx->user= save_security_ctx.user;
unknown's avatar
unknown committed
1039
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
1040 1041
      break;
    }
unknown's avatar
unknown committed
1042

unknown's avatar
unknown committed
1043 1044
    /* Clear variables that are allocated */
    thd->user_connect= 0;
1045
    thd->security_ctx->priv_user= thd->security_ctx->user;
1046
    res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
unknown's avatar
unknown committed
1047

1048 1049
    if (res)
    {
1050 1051
      x_free(thd->security_ctx->user);
      *thd->security_ctx= save_security_ctx;
unknown's avatar
unknown committed
1052
      thd->user_connect= save_user_connect;
1053 1054 1055 1056 1057
      thd->db= save_db;
      thd->db_length= save_db_length;
    }
    else
    {
1058
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1059
      /* we've authenticated new user */
unknown's avatar
unknown committed
1060 1061
      if (save_user_connect)
	decrease_user_connections(save_user_connect);
1062
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
1063 1064
      x_free(save_db);
      x_free(save_security_ctx.user);
1065 1066 1067 1068 1069 1070

      if (cs_number)
      {
        thd_init_client_charset(thd, cs_number);
        thd->update_charset();
      }
1071
    }
unknown's avatar
unknown committed
1072 1073
    break;
  }
1074
  case COM_STMT_EXECUTE:
unknown's avatar
unknown committed
1075
  {
1076
    mysql_stmt_execute(thd, packet, packet_length);
unknown's avatar
unknown committed
1077 1078
    break;
  }
1079
  case COM_STMT_FETCH:
1080 1081 1082 1083
  {
    mysql_stmt_fetch(thd, packet, packet_length);
    break;
  }
1084
  case COM_STMT_SEND_LONG_DATA:
unknown's avatar
unknown committed
1085
  {
1086
    mysql_stmt_get_longdata(thd, packet, packet_length);
unknown's avatar
unknown committed
1087 1088
    break;
  }
1089
  case COM_STMT_PREPARE:
unknown's avatar
unknown committed
1090
  {
1091
    mysql_stmt_prepare(thd, packet, packet_length);
unknown's avatar
unknown committed
1092 1093
    break;
  }
1094
  case COM_STMT_CLOSE:
unknown's avatar
unknown committed
1095
  {
1096
    mysql_stmt_close(thd, packet);
unknown's avatar
unknown committed
1097 1098
    break;
  }
1099
  case COM_STMT_RESET:
1100 1101 1102 1103
  {
    mysql_stmt_reset(thd, packet);
    break;
  }
unknown's avatar
unknown committed
1104 1105
  case COM_QUERY:
  {
1106 1107
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
1108
    char *packet_end= thd->query + thd->query_length;
unknown's avatar
unknown committed
1109
    /* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */
1110
    const char* end_of_stmt= NULL;
1111

1112
    general_log_write(thd, command, thd->query, thd->query_length);
1113
    DBUG_PRINT("query",("%-.4096s",thd->query));
1114 1115 1116
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
    thd->profiling.set_query_source(thd->query, thd->query_length);
#endif
1117 1118 1119 1120

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

1121
    mysql_parse(thd, thd->query, thd->query_length, &end_of_stmt);
1122

1123
    while (!thd->killed && (end_of_stmt != NULL) && ! thd->is_error())
1124
    {
1125
      char *beginning_of_next_stmt= (char*) end_of_stmt;
1126 1127 1128

      net_end_statement(thd);
      query_cache_end_of_result(thd);
1129
      /*
1130 1131
        Multiple queries exits, execute them individually
      */
1132
      close_thread_tables(thd);
1133
      ulong length= (ulong)(packet_end - beginning_of_next_stmt);
1134

1135
      log_slow_statement(thd);
1136

1137
      /* Remove garbage at start of query */
1138
      while (length > 0 && my_isspace(thd->charset(), *beginning_of_next_stmt))
1139
      {
1140
        beginning_of_next_stmt++;
1141 1142
        length--;
      }
1143 1144 1145 1146 1147 1148 1149

#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
      thd->profiling.finish_current_query();
      thd->profiling.start_new_query("continuing");
      thd->profiling.set_query_source(beginning_of_next_stmt, length);
#endif

unknown's avatar
unknown committed
1150
      VOID(pthread_mutex_lock(&LOCK_thread_count));
1151
      thd->query_length= length;
1152
      thd->query= beginning_of_next_stmt;
1153
      thd->query_id= next_query_id();
1154
      thd->set_time(); /* Reset the query start time. */
1155
      /* TODO: set thd->lex->sql_command to SQLCOM_END here */
1156
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
1157
      mysql_parse(thd, beginning_of_next_stmt, length, &end_of_stmt);
1158 1159
    }

unknown's avatar
unknown committed
1160 1161 1162 1163 1164
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1165
  case COM_FIELD_LIST:				// This isn't actually needed
unknown's avatar
unknown committed
1166
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1167 1168
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
unknown's avatar
unknown committed
1169 1170 1171
    break;
#else
  {
1172
    char *fields, *packet_end= packet + packet_length, *arg_end;
1173
    /* Locked closure of all tables */
unknown's avatar
unknown committed
1174
    TABLE_LIST table_list;
unknown's avatar
unknown committed
1175
    LEX_STRING conv_name;
unknown's avatar
unknown committed
1176

unknown's avatar
unknown committed
1177
    /* used as fields initializator */
1178
    lex_start(thd);
1179

1180
    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]);
unknown's avatar
unknown committed
1181
    bzero((char*) &table_list,sizeof(table_list));
1182
    if (thd->copy_db_to(&table_list.db, &table_list.db_length))
unknown's avatar
unknown committed
1183
      break;
1184 1185 1186 1187
    /*
      We have name + wildcard in packet, separated by endzero
    */
    arg_end= strend(packet);
unknown's avatar
unknown committed
1188
    thd->convert_string(&conv_name, system_charset_info,
1189
			packet, (uint) (arg_end - packet), thd->charset());
1190
    table_list.alias= table_list.table_name= conv_name.str;
1191
    packet= arg_end + 1;
1192 1193

    if (!my_strcasecmp(system_charset_info, table_list.db,
1194
                       INFORMATION_SCHEMA_NAME.str))
1195 1196 1197 1198 1199 1200
    {
      ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
      if (schema_table)
        table_list.schema_table= schema_table;
    }

1201
    thd->query_length= (uint) (packet_end - packet); // Don't count end \0
1202
    if (!(thd->query=fields= (char*) thd->memdup(packet,thd->query_length+1)))
unknown's avatar
unknown committed
1203
      break;
unknown's avatar
unknown committed
1204
    general_log_print(thd, command, "%s %s", table_list.table_name, fields);
1205
    if (lower_case_table_names)
1206
      my_casedn_str(files_charset_info, table_list.table_name);
unknown's avatar
unknown committed
1207

unknown's avatar
unknown committed
1208
    if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
1209
		     0, 0, test(table_list.schema_table)))
unknown's avatar
unknown committed
1210
      break;
1211
    if (check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
1212
      break;
1213 1214
    /* init structures for VIEW processing */
    table_list.select_lex= &(thd->lex->select_lex);
1215 1216 1217 1218

    lex_start(thd);
    mysql_reset_thd_for_next_command(thd);

1219
    thd->lex->
1220 1221
      select_lex.table_list.link_in_list((uchar*) &table_list,
                                         (uchar**) &table_list.next_local);
unknown's avatar
unknown committed
1222
    thd->lex->add_to_query_tables(&table_list);
1223

1224 1225
    /* switch on VIEW optimisation: do not fill temporary tables */
    thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
unknown's avatar
unknown committed
1226
    mysqld_list_fields(thd,&table_list,fields);
1227
    thd->lex->unit.cleanup();
1228
    thd->cleanup_after_query();
unknown's avatar
unknown committed
1229 1230 1231 1232
    break;
  }
#endif
  case COM_QUIT:
1233
    /* We don't calculate statistics for this command */
unknown's avatar
unknown committed
1234
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1235
    net->error=0;				// Don't give 'abort' message
1236
    thd->main_da.disable_status();              // Don't send anything back
unknown's avatar
unknown committed
1237 1238 1239
    error=TRUE;					// End server
    break;

1240
#ifdef REMOVED
unknown's avatar
unknown committed
1241
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1242
    {
1243
      LEX_STRING db, alias;
1244
      HA_CREATE_INFO create_info;
unknown's avatar
unknown committed
1245

1246
      status_var_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB]);
1247
      if (thd->make_lex_string(&db, packet, packet_length, FALSE) ||
1248
          thd->make_lex_string(&alias, db.str, db.length, FALSE) ||
1249
          check_db_name(&db))
1250
      {
1251
	my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
1252 1253
	break;
      }
1254 1255
      if (check_access(thd, CREATE_ACL, db.str , 0, 1, 0,
                       is_schema_db(db.str)))
unknown's avatar
unknown committed
1256
	break;
unknown's avatar
unknown committed
1257
      general_log_print(thd, command, packet);
1258
      bzero(&create_info, sizeof(create_info));
1259
      mysql_create_db(thd, (lower_case_table_names == 2 ? alias.str : db.str),
1260
                      &create_info, 0);
unknown's avatar
unknown committed
1261 1262
      break;
    }
unknown's avatar
unknown committed
1263
  case COM_DROP_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1264
    {
1265
      status_var_increment(thd->status_var.com_stat[SQLCOM_DROP_DB]);
1266 1267
      LEX_STRING db;

1268
      if (thd->make_lex_string(&db, packet, packet_length, FALSE) ||
1269
          check_db_name(&db))
1270
      {
1271
	my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
1272 1273
	break;
      }
1274
      if (check_access(thd, DROP_ACL, db.str, 0, 1, 0, is_schema_db(db.str)))
1275
	break;
unknown's avatar
unknown committed
1276 1277
      if (thd->locked_tables || thd->active_transaction())
      {
unknown's avatar
unknown committed
1278 1279
	my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                   ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
unknown's avatar
unknown committed
1280
	break;
unknown's avatar
unknown committed
1281
      }
1282
      general_log_write(thd, command, db.str, db.length);
1283
      mysql_rm_db(thd, db.str, 0, 0);
unknown's avatar
unknown committed
1284 1285
      break;
    }
1286
#endif
1287
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1288 1289
  case COM_BINLOG_DUMP:
    {
unknown's avatar
unknown committed
1290 1291 1292 1293
      ulong pos;
      ushort flags;
      uint32 slave_server_id;

1294
      status_var_increment(thd->status_var.com_other);
1295
      thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
unknown committed
1296
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1297
	break;
unknown's avatar
unknown committed
1298

1299
      /* TODO: The following has to be changed to an 8 byte integer */
1300 1301
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
1302
      thd->server_id=0; /* avoid suicide */
unknown's avatar
unknown committed
1303
      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
unknown's avatar
unknown committed
1304
	kill_zombie_dump_threads(slave_server_id);
1305
      thd->server_id = slave_server_id;
unknown's avatar
unknown committed
1306

unknown's avatar
unknown committed
1307
      general_log_print(thd, command, "Log: '%s'  Pos: %ld", packet+10,
unknown's avatar
unknown committed
1308
                      (long) pos);
1309
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1310
      unregister_slave(thd,1,1);
unknown's avatar
unknown committed
1311
      /*  fake COM_QUIT -- if we get here, the thread needs to terminate */
1312
      error = TRUE;
unknown's avatar
unknown committed
1313 1314
      break;
    }
1315
#endif
unknown's avatar
unknown committed
1316
  case COM_REFRESH:
unknown's avatar
unknown committed
1317 1318
  {
    bool not_used;
1319
    status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
unknown's avatar
unknown committed
1320 1321
    ulong options= (ulong) (uchar) packet[0];
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1322
      break;
unknown's avatar
unknown committed
1323
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1324 1325 1326 1327
    if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
      send_ok(thd);
    break;
  }
1328
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1329
  case COM_SHUTDOWN:
1330
  {
1331
    status_var_increment(thd->status_var.com_other);
unknown's avatar
unknown committed
1332
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1333
      break; /* purecov: inspected */
1334
    /*
1335
      If the client is < 4.1.3, it is going to send us no argument; then
1336
      packet_length is 0, packet[0] is the end 0 of the packet. Note that
1337 1338
      SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in
      packet[0].
1339
    */
1340 1341
    enum mysql_enum_shutdown_level level=
      (enum mysql_enum_shutdown_level) (uchar) packet[0];
1342 1343 1344 1345 1346 1347 1348
    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;
    }
1349
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
unknown's avatar
unknown committed
1350
    general_log_print(thd, command, NullS);
1351
    send_eof(thd);
unknown's avatar
unknown committed
1352 1353 1354 1355
    close_thread_tables(thd);			// Free before kill
    kill_mysql();
    error=TRUE;
    break;
1356
  }
1357
#endif
unknown's avatar
unknown committed
1358 1359
  case COM_STATISTICS:
  {
1360 1361 1362
    STATUS_VAR current_global_status_var;
    ulong uptime;
    uint length;
1363
    ulonglong queries_per_second1000;
1364 1365
    char buff[250];
    uint buff_len= sizeof(buff);
1366

1367
    general_log_print(thd, command, NullS);
1368
    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]);
1369
    calc_sum_of_all_status(&current_global_status_var);
1370 1371 1372 1373 1374
    if (!(uptime= (ulong) (thd->start_time - server_start_time)))
      queries_per_second1000= 0;
    else
      queries_per_second1000= thd->query_id * LL(1000) / uptime;

1375 1376 1377
    length= my_snprintf((char*) buff, buff_len - 1,
                        "Uptime: %lu  Threads: %d  Questions: %lu  "
                        "Slow queries: %lu  Opens: %lu  Flush tables: %lu  "
1378
                        "Open tables: %u  Queries per second avg: %u.%u",
1379 1380 1381 1382 1383 1384
                        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(),
1385 1386
                        (uint) (queries_per_second1000 / 1000),
                        (uint) (queries_per_second1000 % 1000));
1387 1388 1389 1390
#ifdef EMBEDDED_LIBRARY
    /* Store the buffer in permanent memory */
    send_ok(thd, 0, 0, buff);
#endif
unknown's avatar
unknown committed
1391
#ifdef SAFEMALLOC
1392
    if (sf_malloc_cur_memory)				// Using SAFEMALLOC
1393 1394 1395 1396 1397 1398 1399
    {
      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
1400 1401
#endif
#ifndef EMBEDDED_LIBRARY
1402
    VOID(my_net_write(net, (uchar*) buff, length));
1403 1404
    VOID(net_flush(net));
    thd->main_da.disable_status();
unknown's avatar
unknown committed
1405
#endif
unknown's avatar
unknown committed
1406 1407 1408
    break;
  }
  case COM_PING:
1409
    status_var_increment(thd->status_var.com_other);
1410
    send_ok(thd);				// Tell client we are alive
unknown's avatar
unknown committed
1411 1412
    break;
  case COM_PROCESS_INFO:
1413
    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]);
1414 1415
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd, PROCESS_ACL))
unknown's avatar
unknown committed
1416
      break;
unknown's avatar
unknown committed
1417
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1418
    mysqld_list_processes(thd,
1419 1420
			  thd->security_ctx->master_access & PROCESS_ACL ? 
			  NullS : thd->security_ctx->priv_user, 0);
unknown's avatar
unknown committed
1421 1422 1423
    break;
  case COM_PROCESS_KILL:
  {
1424
    status_var_increment(thd->status_var.com_stat[SQLCOM_KILL]);
1425
    ulong id=(ulong) uint4korr(packet);
1426
    sql_kill(thd,id,false);
unknown's avatar
unknown committed
1427 1428
    break;
  }
1429 1430
  case COM_SET_OPTION:
  {
1431
    status_var_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION]);
unknown's avatar
unknown committed
1432 1433 1434 1435
    uint opt_command= uint2korr(packet);

    switch (opt_command) {
    case (int) MYSQL_OPTION_MULTI_STATEMENTS_ON:
1436
      thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
unknown's avatar
unknown committed
1437
      send_eof(thd);
1438
      break;
unknown's avatar
unknown committed
1439
    case (int) MYSQL_OPTION_MULTI_STATEMENTS_OFF:
1440
      thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
unknown's avatar
unknown committed
1441
      send_eof(thd);
1442 1443
      break;
    default:
unknown's avatar
unknown committed
1444
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1445 1446 1447 1448
      break;
    }
    break;
  }
unknown's avatar
unknown committed
1449
  case COM_DEBUG:
1450
    status_var_increment(thd->status_var.com_other);
unknown's avatar
unknown committed
1451
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1452
      break;					/* purecov: inspected */
1453
    mysql_print_status();
unknown's avatar
unknown committed
1454
    general_log_print(thd, command, NullS);
1455
    send_eof(thd);
unknown's avatar
unknown committed
1456 1457 1458 1459 1460
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
1461
  case COM_END:
unknown's avatar
unknown committed
1462
  default:
unknown's avatar
unknown committed
1463
    my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
1464 1465
    break;
  }
1466

1467
  thd_proc_info(thd, "closing tables");
1468 1469 1470
  /* Free tables */
  close_thread_tables(thd);

1471 1472 1473 1474 1475 1476 1477 1478 1479 1480
  /*
    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())
1481
    thd->transaction.xid_state.xid.null();
unknown's avatar
unknown committed
1482

unknown's avatar
unknown committed
1483
  /* report error issued during command execution */
1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496
  if (thd->killed_errno())
  {
    if (! thd->main_da.is_set())
      thd->send_kill_message();
  }
  if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
  {
    thd->killed= THD::NOT_KILLED;
    thd->mysys_var->abort= 0;
  }

  net_end_statement(thd);
  query_cache_end_of_result(thd);
unknown's avatar
unknown committed
1497

1498
  log_slow_statement(thd);
1499

1500
  thd_proc_info(thd, "cleaning up");
1501
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
1502
  thd_proc_info(thd, 0);
1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513
  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);
}


1514
void log_slow_statement(THD *thd)
1515
{
unknown's avatar
unknown committed
1516
  DBUG_ENTER("log_slow_statement");
1517 1518 1519 1520 1521 1522 1523

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

1526 1527 1528 1529 1530
  /*
    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
1531
  {
1532
    ulonglong end_utime_of_query= thd->current_utime();
1533
    thd_proc_info(thd, "logging slow query");
1534

1535 1536 1537 1538
    if (((end_utime_of_query - thd->utime_after_lock) >
         thd->variables.long_query_time ||
         ((thd->server_status &
           (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
1539 1540
          opt_log_queries_not_using_indexes &&
           !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) &&
1541
        thd->examined_row_count >= thd->variables.min_examined_row_limit)
1542
    {
1543
      thd_proc_info(thd, "logging slow query");
1544
      thd->status_var.long_query_count++;
1545
      slow_log_print(thd, thd->query, thd->query_length, end_utime_of_query);
1546
    }
unknown's avatar
unknown committed
1547
  }
unknown's avatar
unknown committed
1548
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
1549 1550
}

1551

unknown's avatar
unknown committed
1552
/**
unknown's avatar
unknown committed
1553 1554 1555 1556 1557 1558 1559
  Create a TABLE_LIST object for an INFORMATION_SCHEMA table.

    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.

unknown's avatar
unknown committed
1560 1561 1562 1563 1564 1565 1566
  @param thd              thread handle
  @param lex              current lex
  @param table_ident      table alias if it's used
  @param schema_table_idx the type of the INFORMATION_SCHEMA table to be
                          created

  @note
unknown's avatar
unknown committed
1567 1568 1569 1570
    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).

unknown's avatar
unknown committed
1571
  @retval
unknown's avatar
unknown committed
1572
    0                 success
unknown's avatar
unknown committed
1573
  @retval
unknown's avatar
unknown committed
1574 1575 1576 1577
    1                 out of memory or SHOW commands are not allowed
                      in this version of the server.
*/

1578 1579 1580
int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
                         enum enum_schema_tables schema_table_idx)
{
1581
  SELECT_LEX *schema_select_lex= NULL;
1582
  DBUG_ENTER("prepare_schema_table");
1583

1584
  switch (schema_table_idx) {
1585 1586
  case SCH_SCHEMATA:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
unknown's avatar
unknown committed
1587 1588
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0));   /* purecov: inspected */
1589 1590 1591 1592
    DBUG_RETURN(1);
#else
    break;
#endif
1593

1594 1595 1596
  case SCH_TABLE_NAMES:
  case SCH_TABLES:
  case SCH_VIEWS:
1597
  case SCH_TRIGGERS:
unknown's avatar
unknown committed
1598
  case SCH_EVENTS:
1599
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1600 1601
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1602 1603 1604
    DBUG_RETURN(1);
#else
    {
1605
      LEX_STRING db;
1606
      size_t dummy;
unknown's avatar
unknown committed
1607
      if (lex->select_lex.db == NULL &&
1608
          lex->copy_db_to(&lex->select_lex.db, &dummy))
1609
      {
unknown's avatar
unknown committed
1610
        DBUG_RETURN(1);
1611
      }
1612 1613 1614
      schema_select_lex= new SELECT_LEX();
      db.str= schema_select_lex->db= lex->select_lex.db;
      schema_select_lex->table_list.first= NULL;
1615
      db.length= strlen(db.str);
unknown's avatar
unknown committed
1616

1617
      if (check_db_name(&db))
1618
      {
1619
        my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
1620 1621 1622 1623 1624 1625 1626
        DBUG_RETURN(1);
      }
      break;
    }
#endif
  case SCH_COLUMNS:
  case SCH_STATISTICS:
unknown's avatar
unknown committed
1627
  {
1628
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1629 1630
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1631 1632
    DBUG_RETURN(1);
#else
unknown's avatar
unknown committed
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
    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;
  }
1644
#endif
1645 1646 1647 1648 1649
  case SCH_PROFILES:
    /* 
      Mark this current profiling record to be discarded.  We don't
      wish to have SHOW commands show up in profiling.
    */
1650 1651
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
    thd->profiling.discard_current_query();
1652 1653
#endif
    break;
1654 1655 1656
  case SCH_OPEN_TABLES:
  case SCH_VARIABLES:
  case SCH_STATUS:
1657 1658
  case SCH_PROCEDURES:
  case SCH_CHARSETS:
unknown's avatar
unknown committed
1659
  case SCH_ENGINES:
1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677
  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
1678
  table_list->schema_select_lex= schema_select_lex;
1679
  table_list->schema_table_reformed= 1;
1680 1681 1682 1683
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
1684 1685 1686
/**
  Read query from packet and store in thd->query.
  Used in COM_QUERY and COM_STMT_PREPARE.
1687 1688

    Sets the following THD variables:
unknown's avatar
unknown committed
1689 1690
  - query
  - query_length
1691

unknown's avatar
unknown committed
1692
  @retval
unknown's avatar
unknown committed
1693
    FALSE ok
unknown's avatar
unknown committed
1694
  @retval
unknown's avatar
unknown committed
1695
    TRUE  error;  In this case thd->fatal_error is set
1696 1697
*/

1698
bool alloc_query(THD *thd, const char *packet, uint packet_length)
1699
{
1700
  /* Remove garbage at start and end of query */
1701
  while (packet_length > 0 && my_isspace(thd->charset(), packet[0]))
1702 1703 1704 1705
  {
    packet++;
    packet_length--;
  }
1706
  const char *pos= packet + packet_length;     // Point at end null
unknown's avatar
unknown committed
1707
  while (packet_length > 0 &&
unknown's avatar
unknown committed
1708
	 (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
1709 1710 1711 1712 1713
  {
    pos--;
    packet_length--;
  }
  /* We must allocate some extra memory for query cache */
unknown's avatar
unknown committed
1714
  thd->query_length= 0;                        // Extra safety: Avoid races
1715
  if (!(thd->query= (char*) thd->memdup_w_gap((uchar*) (packet),
1716
					      packet_length,
1717 1718
					      thd->db_length+ 1 +
					      QUERY_CACHE_FLAGS_SIZE)))
unknown's avatar
unknown committed
1719
    return TRUE;
1720 1721
  thd->query[packet_length]=0;
  thd->query_length= packet_length;
1722 1723 1724 1725

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

unknown's avatar
unknown committed
1727
  return FALSE;
1728 1729
}

1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742
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;
1743
  thd->variables.lc_time_names= &my_locale_en_US;
1744 1745 1746
  thd->one_shot_set= 0;
}

1747

1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793
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);

1794
    if (thd->slave_thread && lex->sphead)
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 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832
      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);
}


unknown's avatar
unknown committed
1833 1834
/**
  Execute command saved in thd and lex->sql_command.
1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845

    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.

unknown's avatar
unknown committed
1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857
  @param thd                       Thread handle

  @todo
    - 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.
    - TODO: use check_change_password()
    - JOIN is not supported yet. TODO
    - SUSPEND and FOR MIGRATE are not supported yet. TODO

  @retval
1858
    FALSE       OK
unknown's avatar
unknown committed
1859
  @retval
1860 1861
    TRUE        Error
*/
unknown's avatar
unknown committed
1862

unknown's avatar
unknown committed
1863
bool
1864
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
1865
{
1866 1867
  bool res= FALSE;
  bool need_start_waiting= FALSE; // have protection against global read lock
unknown's avatar
unknown committed
1868
  int  up_result= 0;
1869
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
1870
  /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
unknown's avatar
unknown committed
1871
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
1872
  /* first table of first SELECT_LEX */
unknown's avatar
unknown committed
1873
  TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
unknown's avatar
VIEW  
unknown committed
1874 1875 1876
  /* list of all tables in query */
  TABLE_LIST *all_tables;
  /* most outer SELECT_LEX_UNIT of query */
1877
  SELECT_LEX_UNIT *unit= &lex->unit;
1878
  /* Saved variable value */
unknown's avatar
unknown committed
1879
  DBUG_ENTER("mysql_execute_command");
unknown's avatar
unknown committed
1880 1881 1882
#ifdef WITH_PARTITION_STORAGE_ENGINE
  thd->work_part_info= 0;
#endif
unknown's avatar
unknown committed
1883

unknown's avatar
VIEW  
unknown committed
1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899
  /*
    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();
1900
  /* should be assigned after making first tables same */
unknown's avatar
VIEW  
unknown committed
1901
  all_tables= lex->query_tables;
1902 1903 1904 1905
  /* 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
1906

1907 1908 1909 1910 1911
  /*
    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.
1912
    Don't reset warnings when executing a stored routine.
1913
  */
1914
  if ((all_tables || !lex->is_single_level_stmt()) && !thd->spcont)
unknown's avatar
unknown committed
1915
    mysql_reset_errors(thd, 0);
1916

unknown's avatar
SCRUM  
unknown committed
1917
#ifdef HAVE_REPLICATION
1918
  if (unlikely(thd->slave_thread))
1919
  {
1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943
    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
1944
    /*
unknown's avatar
unknown committed
1945 1946
      Check if statment should be skipped because of slave filtering
      rules
1947 1948

      Exceptions are:
unknown's avatar
unknown committed
1949 1950
      - UPDATE MULTI: For this statement, we want to check the filtering
        rules later in the code
1951
      - SET: we always execute it (Not that many SET commands exists in
unknown's avatar
unknown committed
1952 1953
        the binary log anyway -- only 4.1 masters write SET statements,
	in 5.0 there are no SET statements in the binary log)
1954 1955
      - 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
1956
    */
unknown's avatar
unknown committed
1957 1958
    if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
	!(lex->sql_command == SQLCOM_SET_OPTION) &&
1959
	!(lex->sql_command == SQLCOM_DROP_TABLE &&
1960
          lex->drop_temporary && lex->drop_if_exists) &&
unknown's avatar
Merge  
unknown committed
1961
        all_tables_not_ok(thd, all_tables))
unknown's avatar
unknown committed
1962 1963
    {
      /* we warn the slave SQL thread */
unknown's avatar
unknown committed
1964
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981
      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);
      }
1982
      DBUG_RETURN(0);
unknown's avatar
unknown committed
1983
    }
1984
  }
1985
  else
1986
  {
1987
#endif /* HAVE_REPLICATION */
1988 1989 1990 1991
    /*
      When option readonly is set deny operations which change non-temporary
      tables. Except for the replication thread and the 'super' users.
    */
1992
    if (deny_updates_if_read_only_option(thd, all_tables))
1993 1994 1995 1996 1997 1998 1999
    {
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
      DBUG_RETURN(-1);
    }
#ifdef HAVE_REPLICATION
  } /* endif unlikely slave */
#endif
2000
  status_var_increment(thd->status_var.com_stat[lex->sql_command]);
2001

unknown's avatar
unknown committed
2002 2003
  DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE);
  
unknown's avatar
unknown committed
2004
  switch (lex->sql_command) {
2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039
  case SQLCOM_SHOW_EVENTS:
  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:
2040
  case SQLCOM_SHOW_STORAGE_ENGINES:
2041
  case SQLCOM_SHOW_PROFILE:
unknown's avatar
unknown committed
2042
  case SQLCOM_SELECT:
2043
    thd->status_var.last_query_cost= 0.0;
unknown's avatar
VIEW  
unknown committed
2044
    if (all_tables)
unknown's avatar
unknown committed
2045
    {
2046 2047 2048
      res= check_table_access(thd,
                              lex->exchange ? SELECT_ACL | FILE_ACL :
                              SELECT_ACL,
2049
                              all_tables, UINT_MAX, FALSE);
unknown's avatar
unknown committed
2050 2051
    }
    else
unknown's avatar
VIEW  
unknown committed
2052
      res= check_access(thd,
2053 2054 2055 2056
                        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
2057
    break;
unknown's avatar
unknown committed
2058
  case SQLCOM_PREPARE:
2059
  {
2060
    mysql_sql_stmt_prepare(thd);
unknown's avatar
unknown committed
2061 2062 2063 2064
    break;
  }
  case SQLCOM_EXECUTE:
  {
2065
    mysql_sql_stmt_execute(thd);
unknown's avatar
unknown committed
2066 2067 2068 2069
    break;
  }
  case SQLCOM_DEALLOCATE_PREPARE:
  {
2070
    mysql_sql_stmt_close(thd);
unknown's avatar
unknown committed
2071 2072
    break;
  }
unknown's avatar
unknown committed
2073
  case SQLCOM_DO:
2074
    if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
2075
        open_and_lock_tables(thd, all_tables))
unknown's avatar
unknown committed
2076
      goto error;
unknown's avatar
unknown committed
2077 2078

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

2081
  case SQLCOM_EMPTY_QUERY:
2082
    send_ok(thd);
2083 2084
    break;

unknown's avatar
unknown committed
2085 2086 2087 2088
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

2089
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2090
  case SQLCOM_PURGE:
2091
  {
unknown's avatar
unknown committed
2092
    if (check_global_access(thd, SUPER_ACL))
2093
      goto error;
unknown's avatar
unknown committed
2094
    /* PURGE MASTER LOGS TO 'file' */
2095 2096 2097
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
2098 2099
  case SQLCOM_PURGE_BEFORE:
  {
2100 2101
    Item *it;

2102 2103
    if (check_global_access(thd, SUPER_ACL))
      goto error;
unknown's avatar
unknown committed
2104
    /* PURGE MASTER LOGS BEFORE 'data' */
2105
    it= (Item *)lex->value_list.head();
2106
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) ||
unknown's avatar
unknown committed
2107
        it->check_cols(1))
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118
    {
      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());
2119 2120
    break;
  }
2121
#endif
unknown's avatar
unknown committed
2122 2123
  case SQLCOM_SHOW_WARNS:
  {
2124 2125
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
2126 2127 2128
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
unknown's avatar
unknown committed
2129 2130 2131 2132
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
2133 2134
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
2135 2136
    break;
  }
unknown's avatar
unknown committed
2137 2138
  case SQLCOM_SHOW_PROFILES:
  {
2139
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
2140
    thd->profiling.discard_current_query();
unknown's avatar
unknown committed
2141
    res= thd->profiling.show_profiles();
2142 2143 2144
    if (res)
      goto error;
#else
2145
    my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILES", "enable-profiling");
2146 2147
    goto error;
#endif
unknown's avatar
unknown committed
2148 2149
    break;
  }
unknown's avatar
unknown committed
2150 2151
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
2152
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2153
      goto error;
2154
    /* This query don't work now. See comment in repl_failsafe.cc */
unknown's avatar
unknown committed
2155
#ifndef WORKING_NEW_MASTER
unknown's avatar
unknown committed
2156 2157
    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
    goto error;
unknown's avatar
unknown committed
2158
#else
unknown's avatar
unknown committed
2159 2160
    res = show_new_master(thd);
    break;
unknown's avatar
unknown committed
2161
#endif
unknown's avatar
unknown committed
2162
  }
2163

unknown's avatar
unknown committed
2164
#ifdef HAVE_REPLICATION
2165 2166
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
2167
    if (check_global_access(thd, REPL_SLAVE_ACL))
2168 2169 2170 2171
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
2172 2173
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
2174
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2175
      goto error;
2176
    res = mysql_show_binlog_events(thd);
unknown's avatar
unknown committed
2177 2178
    break;
  }
2179 2180
#endif

unknown's avatar
unknown committed
2181
  case SQLCOM_BACKUP_TABLE:
2182
  {
unknown's avatar
VIEW  
unknown committed
2183
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2184
    if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
unknown's avatar
unknown committed
2185
	check_global_access(thd, FILE_ACL))
2186
      goto error; /* purecov: inspected */
2187
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2188
    res = mysql_backup_table(thd, first_table);
2189
    select_lex->table_list.first= (uchar*) first_table;
2190
    lex->query_tables=all_tables;
2191 2192
    break;
  }
unknown's avatar
unknown committed
2193
  case SQLCOM_RESTORE_TABLE:
2194
  {
unknown's avatar
VIEW  
unknown committed
2195
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2196
    if (check_table_access(thd, INSERT_ACL, all_tables, UINT_MAX, FALSE) ||
unknown's avatar
unknown committed
2197
	check_global_access(thd, FILE_ACL))
2198
      goto error; /* purecov: inspected */
2199
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2200
    res = mysql_restore_table(thd, first_table);
2201
    select_lex->table_list.first= (uchar*) first_table;
2202
    lex->query_tables=all_tables;
2203 2204
    break;
  }
unknown's avatar
unknown committed
2205 2206
  case SQLCOM_ASSIGN_TO_KEYCACHE:
  {
unknown's avatar
VIEW  
unknown committed
2207
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2208
    if (check_access(thd, INDEX_ACL, first_table->db,
2209 2210
                     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
unknown's avatar
unknown committed
2211
      goto error;
2212
    res= mysql_assign_to_keycache(thd, first_table, &lex->ident);
unknown's avatar
unknown committed
2213 2214
    break;
  }
unknown's avatar
unknown committed
2215 2216
  case SQLCOM_PRELOAD_KEYS:
  {
unknown's avatar
VIEW  
unknown committed
2217
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2218
    if (check_access(thd, INDEX_ACL, first_table->db,
2219 2220
                     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
2221
      goto error;
unknown's avatar
VIEW  
unknown committed
2222
    res = mysql_preload_keys(thd, first_table);
unknown's avatar
unknown committed
2223 2224
    break;
  }
unknown's avatar
unknown committed
2225
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2226
  case SQLCOM_CHANGE_MASTER:
2227
  {
unknown's avatar
unknown committed
2228
    if (check_global_access(thd, SUPER_ACL))
2229
      goto error;
2230
    pthread_mutex_lock(&LOCK_active_mi);
2231
    res = change_master(thd,active_mi);
2232
    pthread_mutex_unlock(&LOCK_active_mi);
2233 2234
    break;
  }
unknown's avatar
unknown committed
2235
  case SQLCOM_SHOW_SLAVE_STAT:
2236
  {
2237 2238
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2239
      goto error;
2240
    pthread_mutex_lock(&LOCK_active_mi);
2241 2242 2243 2244 2245 2246 2247 2248 2249 2250
    if (active_mi != NULL)
    {
      res = show_master_info(thd, active_mi);
    }
    else
    {
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                   "the master info structure does not exist");
      send_ok(thd);
    }
2251
    pthread_mutex_unlock(&LOCK_active_mi);
2252 2253
    break;
  }
unknown's avatar
unknown committed
2254
  case SQLCOM_SHOW_MASTER_STAT:
2255
  {
2256 2257
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2258 2259 2260 2261
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
2262

2263
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
2264
    if (check_global_access(thd, SUPER_ACL))
2265
      goto error;
2266
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2267
      goto error;
2268
    res = load_master_data(thd);
2269
    break;
unknown's avatar
unknown committed
2270
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
2271
  case SQLCOM_SHOW_ENGINE_STATUS:
unknown's avatar
unknown committed
2272
    {
2273
      if (check_global_access(thd, PROCESS_ACL))
unknown's avatar
unknown committed
2274 2275
        goto error;
      res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_STATUS);
unknown's avatar
unknown committed
2276 2277
      break;
    }
unknown's avatar
unknown committed
2278
  case SQLCOM_SHOW_ENGINE_MUTEX:
unknown's avatar
unknown committed
2279
    {
2280
      if (check_global_access(thd, PROCESS_ACL))
unknown's avatar
unknown committed
2281
        goto error;
unknown's avatar
unknown committed
2282
      res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
unknown's avatar
unknown committed
2283 2284
      break;
    }
unknown's avatar
unknown committed
2285
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2286
  case SQLCOM_LOAD_MASTER_TABLE:
2287
  {
unknown's avatar
VIEW  
unknown committed
2288
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2289 2290
    DBUG_ASSERT(first_table->db); /* Must be set in the parser */

unknown's avatar
VIEW  
unknown committed
2291
    if (check_access(thd, CREATE_ACL, first_table->db,
2292 2293
		     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
unknown's avatar
unknown committed
2294
      goto error;				/* purecov: inspected */
2295 2296 2297 2298
    /* Check that the first table has CREATE privilege */
    if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
      goto error;

2299
    pthread_mutex_lock(&LOCK_active_mi);
2300 2301 2302 2303
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
2304
    if (!fetch_master_table(thd, first_table->db, first_table->table_name,
2305
			    active_mi, 0, 0))
2306
    {
2307
      send_ok(thd);
2308
    }
2309
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2310
    break;
2311
  }
unknown's avatar
unknown committed
2312
#endif /* HAVE_REPLICATION */
2313

unknown's avatar
unknown committed
2314
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
2315
  {
2316
    /* If CREATE TABLE of non-temporary table, do implicit commit */
2317 2318 2319 2320 2321 2322 2323 2324
    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
    {
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
unknown's avatar
VIEW  
unknown committed
2325 2326 2327 2328 2329
    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;
2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350
    /*
      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
2351

unknown's avatar
VIEW  
unknown committed
2352
    if ((res= create_table_precheck(thd, select_tables, create_table)))
unknown's avatar
unknown committed
2353
      goto end_with_restore_list;
unknown's avatar
unknown committed
2354

2355 2356 2357
    /* Might have been updated in create_table_precheck */
    create_info.alias= create_table->alias;

2358
#ifndef HAVE_READLINK
2359
    if (create_info.data_file_name)
2360 2361
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                   "DATA DIRECTORY option ignored");
2362
    if (create_info.index_file_name)
2363 2364
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                   "INDEX DIRECTORY option ignored");
2365
    create_info.data_file_name= create_info.index_file_name= NULL;
2366
#else
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388

    if (test_if_data_home_dir(lex->create_info.data_file_name))
    {
      my_error(ER_WRONG_ARGUMENTS,MYF(0),"DATA DIRECORY");
      res= -1;
      break;
    }
    if (test_if_data_home_dir(lex->create_info.index_file_name))
    {
      my_error(ER_WRONG_ARGUMENTS,MYF(0),"INDEX DIRECORY");
      res= -1;
      break;
    }

#ifdef WITH_PARTITION_STORAGE_ENGINE
    if (check_partition_dirs(thd->lex->part_info))
    {
      res= -1;
      break;
    }
#endif

2389
    /* Fix names if symlinked tables */
2390
    if (append_file_to_dir(thd, &create_info.data_file_name,
2391
			   create_table->table_name) ||
2392
	append_file_to_dir(thd, &create_info.index_file_name,
2393
			   create_table->table_name))
unknown's avatar
unknown committed
2394
      goto end_with_restore_list;
2395
#endif
2396
    /*
2397
      If we are using SET CHARSET without DEFAULT, add an implicit
2398 2399
      DEFAULT to not confuse old users. (This may change).
    */
2400
    if ((create_info.used_fields &
2401 2402 2403
	 (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
	HA_CREATE_USED_CHARSET)
    {
2404 2405 2406 2407
      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;
2408
    }
2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421
    /*
      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.
    */
2422 2423
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
2424
    {
unknown's avatar
unknown committed
2425 2426
      res= 1;
      goto end_with_restore_list;
2427
    }
2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438
#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
2439
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
2440 2441
    {
      select_result *result;
2442

2443
      select_lex->options|= SELECT_NO_UNLOCK;
2444
      unit->set_limit(select_lex);
2445

2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458
      /*
        Disable non-empty MERGE tables with CREATE...SELECT. Too
        complicated. See Bug #26379. Empty MERGE tables are read-only
        and don't allow CREATE...SELECT anyway.
      */
      if (create_info.used_fields & HA_CREATE_USED_UNION)
      {
        my_error(ER_WRONG_OBJECT, MYF(0), create_table->db,
                 create_table->table_name, "BASE TABLE");
        res= 1;
        goto end_with_restore_list;
      }

2459
      if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
unknown's avatar
unknown committed
2460 2461 2462 2463 2464 2465
      {
        lex->link_first_table_back(create_table, link_to_local);
        create_table->create= TRUE;
      }

      if (!(res= open_and_lock_tables(thd, lex->query_tables)))
2466
      {
2467 2468 2469 2470
        /*
          Is table which we are changing used somewhere in other parts
          of query
        */
2471
        if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
2472
        {
2473
          TABLE_LIST *duplicate;
unknown's avatar
unknown committed
2474
          create_table= lex->unlink_first_table(&link_to_local);
2475
          if ((duplicate= unique_table(thd, create_table, select_tables, 0)))
2476 2477 2478
          {
            update_non_unique_table_error(create_table, "CREATE", duplicate);
            res= 1;
2479
            goto end_with_restore_list;
2480
          }
2481
        }
unknown's avatar
unknown committed
2482
        /* If we create merge table, we have to test tables in merge, too */
2483
        if (create_info.used_fields & HA_CREATE_USED_UNION)
unknown's avatar
unknown committed
2484 2485
        {
          TABLE_LIST *tab;
2486
          for (tab= (TABLE_LIST*) create_info.merge_list.first;
unknown's avatar
unknown committed
2487 2488 2489
               tab;
               tab= tab->next_local)
          {
2490
            TABLE_LIST *duplicate;
2491
            if ((duplicate= unique_table(thd, tab, select_tables, 0)))
unknown's avatar
unknown committed
2492
            {
2493
              update_non_unique_table_error(tab, "CREATE", duplicate);
unknown's avatar
unknown committed
2494
              res= 1;
2495
              goto end_with_restore_list;
unknown's avatar
unknown committed
2496 2497 2498
            }
          }
        }
2499

unknown's avatar
unknown committed
2500
        /*
2501 2502
          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
2503
        */
unknown's avatar
VIEW  
unknown committed
2504
        if ((result= new select_create(create_table,
2505 2506 2507 2508
                                       &create_info,
                                       &alter_info,
                                       select_lex->item_list,
                                       lex->duplicates,
2509
                                       lex->ignore,
2510
                                       select_tables)))
2511 2512 2513 2514 2515
        {
          /*
            CREATE from SELECT give its SELECT_LEX for SELECT,
            and item_list belong to SELECT
          */
2516
          res= handle_select(thd, lex, result, 0);
2517
          delete result;
2518
        }
2519
      }
2520
      else if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
unknown's avatar
unknown committed
2521 2522
        create_table= lex->unlink_first_table(&link_to_local);

2523
    }
unknown's avatar
unknown committed
2524
    else
unknown's avatar
unknown committed
2525
    {
2526
      /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
2527
      if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
2528
        thd->options|= OPTION_KEEP_LOG;
unknown's avatar
unknown committed
2529
      /* regular create */
2530
      if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
unknown's avatar
unknown committed
2531
        res= mysql_create_like_table(thd, create_table, select_tables,
2532
                                     &create_info);
unknown's avatar
unknown committed
2533
      else
2534
      {
unknown's avatar
VIEW  
unknown committed
2535
        res= mysql_create_table(thd, create_table->db,
2536 2537
                                create_table->table_name, &create_info,
                                &alter_info, 0, 0);
2538
      }
unknown's avatar
unknown committed
2539
      if (!res)
2540
	send_ok(thd);
unknown's avatar
unknown committed
2541
    }
2542

unknown's avatar
unknown committed
2543
    /* put tables back for PS rexecuting */
unknown's avatar
unknown committed
2544
end_with_restore_list:
unknown's avatar
VIEW  
unknown committed
2545
    lex->link_first_table_back(create_table, link_to_local);
unknown's avatar
unknown committed
2546
    break;
unknown's avatar
unknown committed
2547
  }
unknown's avatar
unknown committed
2548
  case SQLCOM_CREATE_INDEX:
2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566
    /* 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
2567 2568
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, INDEX_ACL, all_tables))
unknown's avatar
unknown committed
2569
      goto error; /* purecov: inspected */
2570
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2571
      goto error;
2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582
    /*
      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
2583

2584 2585 2586 2587 2588
    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
2589
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2590
  case SQLCOM_SLAVE_START:
2591
  {
2592
    pthread_mutex_lock(&LOCK_active_mi);
2593
    start_slave(thd,active_mi,1 /* net report*/);
2594
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2595
    break;
2596
  }
unknown's avatar
unknown committed
2597
  case SQLCOM_SLAVE_STOP:
2598 2599 2600 2601 2602 2603
  /*
    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,
2604
      so it waits for the client thread because t is locked by it.
2605
    - then the client thread does SLAVE STOP.
2606 2607
      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.
2608 2609 2610
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
2611
  if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock)
2612
  {
2613 2614
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
2615
    goto error;
2616
  }
2617
  {
2618
    pthread_mutex_lock(&LOCK_active_mi);
2619
    stop_slave(thd,active_mi,1/* net report*/);
2620
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2621
    break;
2622
  }
unknown's avatar
unknown committed
2623
#endif /* HAVE_REPLICATION */
2624

unknown's avatar
unknown committed
2625
  case SQLCOM_ALTER_TABLE:
unknown's avatar
VIEW  
unknown committed
2626
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2627
    {
unknown's avatar
unknown committed
2628
      ulong priv=0;
unknown's avatar
unknown committed
2629
      ulong priv_needed= ALTER_ACL;
2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640
      /*
        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;
2641 2642 2643 2644
      /*
        We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
        as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
      */
2645
      if (alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME))
unknown's avatar
unknown committed
2646 2647
        priv_needed|= DROP_ACL;

unknown's avatar
unknown committed
2648 2649
      /* Must be set in the parser */
      DBUG_ASSERT(select_lex->db);
unknown's avatar
unknown committed
2650
      if (check_access(thd, priv_needed, first_table->db,
2651 2652 2653 2654
		       &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
2655
	  check_merge_table_access(thd, first_table->db,
2656
				   (TABLE_LIST *)
2657
				   create_info.merge_list.first))
2658
	goto error;				/* purecov: inspected */
2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670
      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
2671
      }
2672

2673
      /* Don't yet allow changing of symlinks with ALTER TABLE */
2674
      if (create_info.data_file_name)
2675 2676
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                     "DATA DIRECTORY option ignored");
2677
      if (create_info.index_file_name)
2678 2679
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                     "INDEX DIRECTORY option ignored");
2680
      create_info.data_file_name= create_info.index_file_name= NULL;
unknown's avatar
unknown committed
2681
      /* ALTER TABLE ends previous transaction */
2682
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2683
	goto error;
2684

2685 2686 2687 2688 2689
      if (!thd->locked_tables &&
          !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
      {
        res= 1;
        break;
unknown's avatar
unknown committed
2690
      }
2691

2692
      thd->enable_slow_log= opt_log_slow_admin_statements;
2693
      res= mysql_alter_table(thd, select_lex->db, lex->name.str,
2694 2695 2696
                             &create_info,
                             first_table,
                             &alter_info,
2697 2698
                             select_lex->order_list.elements,
                             (ORDER *) select_lex->order_list.first,
2699
                             lex->ignore);
unknown's avatar
unknown committed
2700 2701
      break;
    }
unknown's avatar
unknown committed
2702
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
2703
  {
unknown's avatar
VIEW  
unknown committed
2704
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2705
    TABLE_LIST *table;
unknown's avatar
VIEW  
unknown committed
2706
    for (table= first_table; table; table= table->next_local->next_local)
unknown's avatar
unknown committed
2707
    {
unknown's avatar
unknown committed
2708
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
2709
		       &table->grant.privilege,0,0, test(table->schema_table)) ||
unknown's avatar
VIEW  
unknown committed
2710
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
2711 2712
		       &table->next_local->grant.privilege, 0, 0,
                       test(table->next_local->schema_table)))
unknown's avatar
unknown committed
2713
	goto error;
2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725
      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
2726
    }
2727

unknown's avatar
unknown committed
2728
    if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
unknown's avatar
unknown committed
2729
      goto error;
unknown's avatar
unknown committed
2730
    break;
unknown's avatar
unknown committed
2731
  }
2732
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2733 2734
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2735 2736
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2737
    goto error;
unknown's avatar
unknown committed
2738 2739
#else
    {
unknown's avatar
unknown committed
2740
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2741 2742 2743 2744
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
2745
#endif
2746
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2747
  case SQLCOM_SHOW_CREATE:
unknown's avatar
VIEW  
unknown committed
2748
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2749
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2750 2751
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2752
    goto error;
unknown's avatar
unknown committed
2753
#else
unknown's avatar
unknown committed
2754
    {
2755 2756 2757
      /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
      if (lex->only_view)
        first_table->skip_temporary= 1;
unknown's avatar
unknown committed
2758
      if (check_show_create_table_access(thd, first_table))
2759
	goto error;
unknown's avatar
unknown committed
2760
      res= mysqld_show_create(thd, first_table);
unknown's avatar
unknown committed
2761 2762
      break;
    }
unknown's avatar
unknown committed
2763
#endif
2764 2765
  case SQLCOM_CHECKSUM:
  {
unknown's avatar
VIEW  
unknown committed
2766
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2767 2768
    if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables,
                           UINT_MAX, FALSE))
2769
      goto error; /* purecov: inspected */
unknown's avatar
VIEW  
unknown committed
2770
    res = mysql_checksum_table(thd, first_table, &lex->check_opt);
2771 2772
    break;
  }
unknown's avatar
unknown committed
2773
  case SQLCOM_REPAIR:
2774
  {
unknown's avatar
VIEW  
unknown committed
2775
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2776 2777
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
                           UINT_MAX, FALSE))
2778
      goto error; /* purecov: inspected */
2779
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2780
    res= mysql_repair_table(thd, first_table, &lex->check_opt);
2781 2782 2783
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
2784 2785 2786
      /*
        Presumably, REPAIR and binlog writing doesn't require synchronization
      */
2787
      write_bin_log(thd, TRUE, thd->query, thd->query_length);
2788
    }
2789
    select_lex->table_list.first= (uchar*) first_table;
2790
    lex->query_tables=all_tables;
2791 2792
    break;
  }
unknown's avatar
unknown committed
2793
  case SQLCOM_CHECK:
2794
  {
unknown's avatar
VIEW  
unknown committed
2795
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2796 2797
    if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables,
                           UINT_MAX, FALSE))
2798
      goto error; /* purecov: inspected */
2799
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2800
    res = mysql_check_table(thd, first_table, &lex->check_opt);
2801
    select_lex->table_list.first= (uchar*) first_table;
2802
    lex->query_tables=all_tables;
2803 2804
    break;
  }
unknown's avatar
unknown committed
2805 2806
  case SQLCOM_ANALYZE:
  {
unknown's avatar
VIEW  
unknown committed
2807
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2808 2809
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
                           UINT_MAX, FALSE))
unknown's avatar
unknown committed
2810
      goto error; /* purecov: inspected */
2811
    thd->enable_slow_log= opt_log_slow_admin_statements;
2812
    res= mysql_analyze_table(thd, first_table, &lex->check_opt);
2813 2814 2815
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
2816 2817 2818
      /*
        Presumably, ANALYZE and binlog writing doesn't require synchronization
      */
2819
      write_bin_log(thd, TRUE, thd->query, thd->query_length);
2820
    }
2821
    select_lex->table_list.first= (uchar*) first_table;
2822
    lex->query_tables=all_tables;
unknown's avatar
unknown committed
2823
    break;
unknown's avatar
unknown committed
2824
  }
2825

unknown's avatar
unknown committed
2826 2827
  case SQLCOM_OPTIMIZE:
  {
unknown's avatar
VIEW  
unknown committed
2828
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2829 2830
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
                           UINT_MAX, FALSE))
unknown's avatar
unknown committed
2831
      goto error; /* purecov: inspected */
2832
    thd->enable_slow_log= opt_log_slow_admin_statements;
2833
    res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
2834
      mysql_recreate_table(thd, first_table) :
unknown's avatar
VIEW  
unknown committed
2835
      mysql_optimize_table(thd, first_table, &lex->check_opt);
2836 2837 2838
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
2839 2840 2841
      /*
        Presumably, OPTIMIZE and binlog writing doesn't require synchronization
      */
2842
      write_bin_log(thd, TRUE, thd->query, thd->query_length);
2843
    }
2844
    select_lex->table_list.first= (uchar*) first_table;
2845
    lex->query_tables=all_tables;
unknown's avatar
unknown committed
2846 2847 2848
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
VIEW  
unknown committed
2849 2850
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (update_precheck(thd, all_tables))
unknown's avatar
unknown committed
2851
      break;
2852 2853
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
unknown's avatar
unknown committed
2854 2855 2856 2857 2858 2859 2860 2861
    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));
2862
    /* mysql_update return 2 if we need to switch to multi-update */
unknown's avatar
unknown committed
2863
    if (up_result != 2)
2864
      break;
unknown's avatar
unknown committed
2865
    /* Fall through */
2866
  case SQLCOM_UPDATE_MULTI:
unknown's avatar
unknown committed
2867 2868 2869
  {
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    /* if we switched from normal update, rights are checked */
unknown's avatar
unknown committed
2870
    if (up_result != 2)
2871
    {
unknown's avatar
unknown committed
2872 2873 2874 2875 2876
      if ((res= multi_update_precheck(thd, all_tables)))
        break;
    }
    else
      res= 0;
unknown's avatar
unknown committed
2877

2878
    res= mysql_multi_update_prepare(thd);
unknown's avatar
unknown committed
2879

2880
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2881
    /* Check slave filtering rules */
2882
    if (unlikely(thd->slave_thread))
unknown's avatar
unknown committed
2883
    {
2884 2885
      if (all_tables_not_ok(thd, all_tables))
      {
2886 2887 2888 2889 2890
        if (res!= 0)
        {
          res= 0;             /* don't care of prev failure  */
          thd->clear_error(); /* filters are of highest prior */
        }
2891 2892 2893 2894
        /* we warn the slave SQL thread */
        my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
        break;
      }
2895 2896
      if (res)
        break;
unknown's avatar
unknown committed
2897
    }
2898 2899
    else
    {
2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912
#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
2913

unknown's avatar
unknown committed
2914 2915 2916 2917 2918 2919
    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
2920
    break;
unknown's avatar
unknown committed
2921
  }
unknown's avatar
unknown committed
2922
  case SQLCOM_REPLACE:
2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952
#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
2953 2954
  case SQLCOM_INSERT:
  {
unknown's avatar
VIEW  
unknown committed
2955
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2956
    if ((res= insert_precheck(thd, all_tables)))
unknown's avatar
unknown committed
2957
      break;
2958 2959 2960 2961 2962 2963 2964 2965

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

unknown's avatar
VIEW  
unknown committed
2966
    res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
unknown's avatar
unknown committed
2967
		      lex->update_list, lex->value_list,
2968
                      lex->duplicates, lex->ignore);
2969 2970 2971 2972 2973 2974 2975

    /*
      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
2976
    if (first_table->view && !first_table->contain_auto_increment)
2977 2978
      thd->first_successful_insert_id_in_cur_stmt=
        thd->first_successful_insert_id_in_prev_stmt;
2979

unknown's avatar
unknown committed
2980
    break;
2981
  }
unknown's avatar
unknown committed
2982 2983 2984
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
unknown's avatar
unknown committed
2985
    select_result *sel_result;
unknown's avatar
VIEW  
unknown committed
2986
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2987
    if ((res= insert_precheck(thd, all_tables)))
2988
      break;
unknown's avatar
unknown committed
2989

2990
    /* Fix lock for first table */
unknown's avatar
VIEW  
unknown committed
2991 2992
    if (first_table->lock_type == TL_WRITE_DELAYED)
      first_table->lock_type= TL_WRITE;
2993

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

2997
    unit->set_limit(select_lex);
2998 2999 3000 3001 3002 3003 3004 3005

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

unknown's avatar
VIEW  
unknown committed
3006
    if (!(res= open_and_lock_tables(thd, all_tables)))
3007
    {
3008
      /* Skip first table, which is the table we are inserting in */
unknown's avatar
unknown committed
3009
      TABLE_LIST *second_table= first_table->next_local;
3010
      select_lex->table_list.first= (uchar*) second_table;
3011 3012
      select_lex->context.table_list= 
        select_lex->context.first_name_resolution_table= second_table;
3013
      res= mysql_insert_select_prepare(thd);
unknown's avatar
unknown committed
3014 3015 3016 3017 3018 3019 3020
      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)))
3021
      {
unknown's avatar
unknown committed
3022
	res= handle_select(thd, lex, sel_result, OPTION_SETUP_TABLES_DONE);
3023 3024 3025 3026 3027 3028 3029 3030 3031
        /*
          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)
        {
3032 3033 3034
          /* INSERT ... SELECT should invalidate only the very first table */
          TABLE_LIST *save_table= first_table->next_local;
          first_table->next_local= 0;
3035 3036
          mysql_unlock_tables(thd, thd->lock);
          query_cache_invalidate3(thd, first_table, 1);
3037
          first_table->next_local= save_table;
3038 3039
          thd->lock=0;
        }
unknown's avatar
unknown committed
3040
        delete sel_result;
3041
      }
3042
      /* revert changes for SP */
3043
      select_lex->table_list.first= (uchar*) first_table;
3044
    }
unknown's avatar
VIEW  
unknown committed
3045

3046 3047 3048 3049 3050 3051
    /*
      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
3052
    if (first_table->view && !first_table->contain_auto_increment)
3053 3054
      thd->first_successful_insert_id_in_cur_stmt=
        thd->first_successful_insert_id_in_prev_stmt;
3055

unknown's avatar
unknown committed
3056 3057
    break;
  }
3058
  case SQLCOM_TRUNCATE:
3059 3060 3061 3062 3063
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
VIEW  
unknown committed
3064
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3065
    if (check_one_table_access(thd, DROP_ACL, all_tables))
unknown's avatar
unknown committed
3066
      goto error;
3067 3068 3069 3070
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
3071
    if (thd->locked_tables || thd->active_transaction())
3072
    {
unknown's avatar
unknown committed
3073 3074
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3075 3076
      goto error;
    }
unknown's avatar
VIEW  
unknown committed
3077

unknown's avatar
unknown committed
3078
    res= mysql_truncate(thd, first_table, 0);
3079
    break;
unknown's avatar
unknown committed
3080
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
3081
  {
unknown's avatar
VIEW  
unknown committed
3082 3083
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if ((res= delete_precheck(thd, all_tables)))
unknown's avatar
unknown committed
3084
      break;
3085 3086
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
3087 3088 3089 3090 3091 3092 3093 3094

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

unknown's avatar
VIEW  
unknown committed
3095
    res = mysql_delete(thd, all_tables, select_lex->where,
3096
                       &select_lex->order_list,
unknown's avatar
unknown committed
3097 3098
                       unit->select_limit_cnt, select_lex->options,
                       FALSE);
unknown's avatar
unknown committed
3099 3100
    break;
  }
3101
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
3102
  {
unknown's avatar
VIEW  
unknown committed
3103
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3104
    TABLE_LIST *aux_tables=
unknown's avatar
unknown committed
3105
      (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
unknown's avatar
unknown committed
3106
    multi_delete *del_result;
unknown's avatar
unknown committed
3107

3108 3109 3110 3111 3112 3113 3114
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
    {
      res= 1;
      break;
    }

3115
    if ((res= multi_delete_precheck(thd, all_tables)))
3116
      break;
unknown's avatar
unknown committed
3117

unknown's avatar
unknown committed
3118
    /* condition will be TRUE on SP re-excuting */
3119 3120
    if (select_lex->item_list.elements != 0)
      select_lex->item_list.empty();
unknown's avatar
unknown committed
3121
    if (add_item_to_list(thd, new Item_null()))
unknown's avatar
unknown committed
3122
      goto error;
3123

3124
    thd_proc_info(thd, "init");
unknown's avatar
VIEW  
unknown committed
3125 3126 3127 3128
    if ((res= open_and_lock_tables(thd, all_tables)))
      break;

    if ((res= mysql_multi_delete_prepare(thd)))
unknown's avatar
unknown committed
3129
      goto error;
3130

unknown's avatar
unknown committed
3131 3132
    if (!thd->is_fatal_error &&
        (del_result= new multi_delete(aux_tables, lex->table_count)))
unknown's avatar
unknown committed
3133
    {
3134 3135 3136
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
3137
			select_lex->item_list,
unknown's avatar
unknown committed
3138
			select_lex->where,
3139
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
unknown's avatar
unknown committed
3140 3141
			(ORDER *)NULL,
			select_lex->options | thd->options |
3142 3143
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
                        OPTION_SETUP_TABLES_DONE,
unknown's avatar
unknown committed
3144
			del_result, unit, select_lex);
3145 3146
      res|= thd->is_error();
      if (res)
3147
        del_result->abort();
unknown's avatar
unknown committed
3148
      delete del_result;
unknown's avatar
unknown committed
3149 3150
    }
    else
3151
      res= TRUE;                                // Error
unknown's avatar
unknown committed
3152 3153
    break;
  }
unknown's avatar
unknown committed
3154
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
3155
  {
unknown's avatar
VIEW  
unknown committed
3156
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3157 3158
    if (!lex->drop_temporary)
    {
3159
      if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE))
3160 3161
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
unknown's avatar
unknown committed
3162
        goto error;
3163
    }
unknown's avatar
unknown committed
3164
    else
unknown's avatar
unknown committed
3165 3166 3167 3168 3169 3170
    {
      /*
	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
3171 3172
	To not generate such irrelevant "table does not exist errors",
	we silently add IF EXISTS if TEMPORARY was used.
unknown's avatar
unknown committed
3173 3174
      */
      if (thd->slave_thread)
3175
        lex->drop_if_exists= 1;
3176

unknown's avatar
unknown committed
3177
      /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
3178
      thd->options|= OPTION_KEEP_LOG;
unknown's avatar
unknown committed
3179
    }
3180
    /* DDL and binlog write order protected by LOCK_open */
unknown's avatar
VIEW  
unknown committed
3181 3182
    res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
			lex->drop_temporary);
unknown's avatar
unknown committed
3183 3184
  }
  break;
unknown's avatar
unknown committed
3185
  case SQLCOM_SHOW_PROCESSLIST:
3186 3187
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
3188
      break;
unknown's avatar
unknown committed
3189
    mysqld_list_processes(thd,
3190 3191 3192 3193
			  (thd->security_ctx->master_access & PROCESS_ACL ?
                           NullS :
                           thd->security_ctx->priv_user),
                          lex->verbose);
unknown's avatar
unknown committed
3194
    break;
unknown's avatar
unknown committed
3195 3196 3197
  case SQLCOM_SHOW_AUTHORS:
    res= mysqld_show_authors(thd);
    break;
3198 3199 3200
  case SQLCOM_SHOW_CONTRIBUTORS:
    res= mysqld_show_contributors(thd);
    break;
unknown's avatar
unknown committed
3201 3202 3203 3204 3205 3206
  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
3207
  case SQLCOM_SHOW_ENGINE_LOGS:
unknown's avatar
unknown committed
3208
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
3209 3210
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
3211
    goto error;
unknown's avatar
unknown committed
3212 3213
#else
    {
3214
      if (check_access(thd, FILE_ACL, any_db,0,0,0,0))
unknown's avatar
unknown committed
3215
	goto error;
unknown's avatar
unknown committed
3216
      res= ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_LOGS);
unknown's avatar
unknown committed
3217 3218
      break;
    }
unknown's avatar
unknown committed
3219 3220
#endif
  case SQLCOM_CHANGE_DB:
3221 3222 3223 3224
  {
    LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) };

    if (!mysql_change_db(thd, &db_str, FALSE))
3225
      send_ok(thd);
3226

unknown's avatar
unknown committed
3227
    break;
3228
  }
3229

unknown's avatar
unknown committed
3230 3231
  case SQLCOM_LOAD:
  {
unknown's avatar
VIEW  
unknown committed
3232
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3233
    uint privilege= (lex->duplicates == DUP_REPLACE ?
unknown's avatar
unknown committed
3234 3235
		     INSERT_ACL | DELETE_ACL : INSERT_ACL) |
                    (lex->local_file ? 0 : FILE_ACL);
3236

unknown's avatar
unknown committed
3237
    if (lex->local_file)
unknown's avatar
unknown committed
3238
    {
3239
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
3240
          !opt_local_infile)
3241
      {
unknown's avatar
unknown committed
3242
	my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0));
3243 3244
	goto error;
      }
unknown's avatar
unknown committed
3245
    }
unknown's avatar
unknown committed
3246 3247 3248 3249

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

unknown's avatar
VIEW  
unknown committed
3250
    res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
unknown's avatar
unknown committed
3251
                    lex->update_list, lex->value_list, lex->duplicates,
3252
                    lex->ignore, (bool) lex->local_file);
unknown's avatar
unknown committed
3253 3254
    break;
  }
3255

unknown's avatar
unknown committed
3256
  case SQLCOM_SET_OPTION:
3257 3258
  {
    List<set_var_base> *lex_var_list= &lex->var_list;
3259 3260 3261 3262

    if (lex->autocommit && end_active_trans(thd))
      goto error;

3263
    if ((check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
unknown's avatar
unknown committed
3264 3265
	 open_and_lock_tables(thd, all_tables)))
      goto error;
3266 3267
    if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
    {
unknown's avatar
unknown committed
3268 3269
      my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
      goto error;
3270 3271 3272 3273 3274 3275 3276 3277
    }
    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;
3278
      send_ok(thd);
3279
    }
3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291
    else
    {
      /*
        We encountered some sort of error, but no message was sent.
        Send something semi-generic here since we don't know which
        assignment in the list caused the error.
      */
      if (!thd->is_error())
        my_error(ER_WRONG_ARGUMENTS,MYF(0),"SET");
      goto error;
    }

unknown's avatar
unknown committed
3292
    break;
3293
  }
unknown's avatar
unknown committed
3294

unknown's avatar
unknown committed
3295
  case SQLCOM_UNLOCK_TABLES:
3296 3297 3298 3299 3300 3301
    /*
      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
3302
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
3303 3304
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
3305
      end_active_trans(thd);
3306
      thd->options&= ~(OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3307 3308
    }
    if (thd->global_read_lock)
3309
      unlock_global_read_lock(thd);
3310
    send_ok(thd);
unknown's avatar
unknown committed
3311 3312
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
3313
    unlock_locked_tables(thd);
3314
    /* we must end the trasaction first, regardless of anything */
unknown's avatar
unknown committed
3315
    if (end_active_trans(thd))
unknown's avatar
unknown committed
3316
      goto error;
3317 3318
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
                           UINT_MAX, FALSE))
3319
      goto error;
unknown's avatar
unknown committed
3320
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
3321
    thd->options|= OPTION_TABLE_LOCK;
unknown's avatar
VIEW  
unknown committed
3322

3323
    if (!(res= simple_open_n_lock_tables(thd, all_tables)))
unknown's avatar
unknown committed
3324
    {
3325 3326
#ifdef HAVE_QUERY_CACHE
      if (thd->variables.query_cache_wlock_invalidate)
unknown's avatar
VIEW  
unknown committed
3327
	query_cache.invalidate_locked_for_write(first_table);
3328
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
3329 3330
      thd->locked_tables=thd->lock;
      thd->lock=0;
3331
      send_ok(thd);
unknown's avatar
unknown committed
3332
    }
unknown's avatar
unknown committed
3333
    else
3334 3335 3336 3337 3338 3339 3340
    {
      /* 
        Need to end the current transaction, so the storage engine (InnoDB)
        can free its locks if LOCK TABLES locked some tables before finding
        that it can't lock a table in its list
      */
      end_active_trans(thd);
3341
      thd->options&= ~(OPTION_TABLE_LOCK);
3342
    }
unknown's avatar
unknown committed
3343 3344 3345
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
3346
  {
3347 3348 3349 3350 3351 3352
    /*
      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);
3353 3354 3355 3356 3357
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
unknown committed
3358
    char *alias;
3359 3360
    if (!(alias=thd->strmake(lex->name.str, lex->name.length)) ||
        check_db_name(&lex->name))
unknown's avatar
unknown committed
3361
    {
3362
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3363 3364
      break;
    }
3365 3366 3367
    /*
      If in a slave thread :
      CREATE DATABASE DB was certainly not preceded by USE DB.
3368
      For that reason, db_ok() in sql/slave.cc did not check the
3369 3370 3371
      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.
    */
3372
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
3373
    if (thd->slave_thread && 
3374 3375
	(!rpl_filter->db_ok(lex->name.str) ||
	 !rpl_filter->db_ok_with_wild_table(lex->name.str)))
unknown's avatar
unknown committed
3376
    {
unknown's avatar
unknown committed
3377
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3378
      break;
unknown's avatar
unknown committed
3379
    }
3380
#endif
3381 3382
    if (check_access(thd,CREATE_ACL,lex->name.str, 0, 1, 0,
                     is_schema_db(lex->name.str)))
3383
      break;
3384
    res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
3385
                              lex->name.str), &create_info, 0);
3386 3387
    break;
  }
unknown's avatar
unknown committed
3388
  case SQLCOM_DROP_DB:
3389
  {
3390 3391 3392 3393 3394
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
3395
    if (check_db_name(&lex->name))
unknown's avatar
unknown committed
3396
    {
3397
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3398 3399
      break;
    }
3400 3401 3402 3403 3404 3405 3406
    /*
      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.
    */
3407
#ifdef HAVE_REPLICATION
3408
    if (thd->slave_thread && 
3409 3410
	(!rpl_filter->db_ok(lex->name.str) ||
	 !rpl_filter->db_ok_with_wild_table(lex->name.str)))
unknown's avatar
unknown committed
3411
    {
unknown's avatar
unknown committed
3412
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3413
      break;
unknown's avatar
unknown committed
3414
    }
3415
#endif
3416 3417
    if (check_access(thd,DROP_ACL,lex->name.str,0,1,0,
                     is_schema_db(lex->name.str)))
3418
      break;
3419 3420
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3421 3422
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3423 3424
      goto error;
    }
3425
    res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0);
3426 3427
    break;
  }
3428
  case SQLCOM_ALTER_DB_UPGRADE:
unknown's avatar
unknown committed
3429
  {
3430
    LEX_STRING *db= & lex->name;
unknown's avatar
unknown committed
3431 3432 3433 3434 3435 3436 3437
    if (end_active_trans(thd))
    {
      res= 1;
      break;
    }
#ifdef HAVE_REPLICATION
    if (thd->slave_thread && 
3438 3439
       (!rpl_filter->db_ok(db->str) ||
        !rpl_filter->db_ok_with_wild_table(db->str)))
unknown's avatar
unknown committed
3440 3441 3442 3443 3444 3445
    {
      res= 1;
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
      break;
    }
#endif
3446
    if (check_db_name(db))
3447
    {
3448
      my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
3449 3450
      break;
    }
3451 3452 3453
    if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0, is_schema_db(db->str)) ||
        check_access(thd, DROP_ACL, db->str, 0, 1, 0, is_schema_db(db->str)) ||
        check_access(thd, CREATE_ACL, db->str, 0, 1, 0, is_schema_db(db->str)))
unknown's avatar
unknown committed
3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464
    {
      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;
    }
3465 3466

    res= mysql_upgrade_db(thd, db);
unknown's avatar
unknown committed
3467 3468 3469 3470
    if (!res)
      send_ok(thd);
    break;
  }
3471 3472
  case SQLCOM_ALTER_DB:
  {
3473
    LEX_STRING *db= &lex->name;
3474
    HA_CREATE_INFO create_info(lex->create_info);
3475
    if (check_db_name(db))
3476
    {
3477
      my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
3478 3479
      break;
    }
unknown's avatar
unknown committed
3480 3481 3482
    /*
      If in a slave thread :
      ALTER DATABASE DB may not be preceded by USE DB.
3483
      For that reason, maybe db_ok() in sql/slave.cc did not check the
unknown's avatar
unknown committed
3484 3485 3486 3487
      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
3488
    if (thd->slave_thread &&
3489 3490
	(!rpl_filter->db_ok(db->str) ||
	 !rpl_filter->db_ok_with_wild_table(db->str)))
unknown's avatar
unknown committed
3491
    {
unknown's avatar
unknown committed
3492
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
unknown's avatar
unknown committed
3493 3494 3495
      break;
    }
#endif
3496
    if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0, is_schema_db(db->str)))
3497 3498 3499
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3500 3501
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3502 3503
      goto error;
    }
3504
    res= mysql_alter_db(thd, db->str, &create_info);
3505 3506
    break;
  }
unknown's avatar
unknown committed
3507 3508
  case SQLCOM_SHOW_CREATE_DB:
  {
unknown's avatar
unknown committed
3509 3510
    DBUG_EXECUTE_IF("4x_server_emul",
                    my_error(ER_UNKNOWN_ERROR, MYF(0)); goto error;);
3511
    if (check_db_name(&lex->name))
unknown's avatar
unknown committed
3512
    {
3513
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3514 3515
      break;
    }
3516
    res= mysqld_show_create_db(thd, lex->name.str, &lex->create_info);
unknown's avatar
unknown committed
3517 3518
    break;
  }
unknown's avatar
unknown committed
3519 3520
  case SQLCOM_CREATE_EVENT:
  case SQLCOM_ALTER_EVENT:
3521
  do
unknown's avatar
unknown committed
3522
  {
unknown's avatar
unknown committed
3523
    DBUG_ASSERT(lex->event_parse_data);
unknown's avatar
unknown committed
3524 3525 3526 3527 3528 3529
    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;
    }
3530 3531 3532 3533 3534

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

unknown's avatar
unknown committed
3535 3536
    switch (lex->sql_command) {
    case SQLCOM_CREATE_EVENT:
3537 3538 3539 3540
    {
      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
3541
      break;
3542
    }
unknown's avatar
unknown committed
3543
    case SQLCOM_ALTER_EVENT:
3544 3545 3546
      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
3547
      break;
3548 3549
    default:
      DBUG_ASSERT(0);
unknown's avatar
unknown committed
3550
    }
3551
    DBUG_PRINT("info",("DDL error code=%d", res));
unknown's avatar
unknown committed
3552
    if (!res)
3553
      send_ok(thd);
unknown's avatar
unknown committed
3554

3555 3556 3557 3558 3559 3560
  } 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
3561
  }
3562 3563
  /* lex->unit.cleanup() is called outside, no need to call it here */
  break;
unknown's avatar
unknown committed
3564
  case SQLCOM_SHOW_CREATE_EVENT:
3565 3566 3567 3568 3569 3570 3571 3572
    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);
3573
    break;
unknown's avatar
unknown committed
3574
  case SQLCOM_CREATE_FUNCTION:                  // UDF function
unknown's avatar
unknown committed
3575
  {
3576
    if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
unknown's avatar
unknown committed
3577
      break;
unknown's avatar
unknown committed
3578
#ifdef HAVE_DLOPEN
3579
    if (!(res = mysql_create_function(thd, &lex->udf)))
unknown's avatar
unknown committed
3580
      send_ok(thd);
unknown's avatar
unknown committed
3581
#else
unknown's avatar
unknown committed
3582
    my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled");
unknown's avatar
unknown committed
3583
    res= TRUE;
unknown's avatar
unknown committed
3584 3585
#endif
    break;
unknown's avatar
unknown committed
3586
  }
unknown's avatar
unknown committed
3587
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3588 3589
  case SQLCOM_CREATE_USER:
  {
3590
    if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) &&
3591
        check_global_access(thd,CREATE_USER_ACL))
3592
      break;
3593 3594
    if (end_active_trans(thd))
      goto error;
3595
    /* Conditionally writes to binlog */
3596 3597 3598 3599
    if (!(res= mysql_create_user(thd, lex->users_list)))
      send_ok(thd);
    break;
  }
3600 3601
  case SQLCOM_DROP_USER:
  {
3602
    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) &&
3603
        check_global_access(thd,CREATE_USER_ACL))
3604
      break;
3605 3606
    if (end_active_trans(thd))
      goto error;
3607
    /* Conditionally writes to binlog */
3608
    if (!(res= mysql_drop_user(thd, lex->users_list)))
3609 3610 3611 3612 3613
      send_ok(thd);
    break;
  }
  case SQLCOM_RENAME_USER:
  {
3614
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
3615
        check_global_access(thd,CREATE_USER_ACL))
3616
      break;
3617 3618
    if (end_active_trans(thd))
      goto error;
3619
    /* Conditionally writes to binlog */
3620
    if (!(res= mysql_rename_user(thd, lex->users_list)))
3621 3622 3623 3624 3625
      send_ok(thd);
    break;
  }
  case SQLCOM_REVOKE_ALL:
  {
3626 3627
    if (end_active_trans(thd))
      goto error;
3628
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
3629
        check_global_access(thd,CREATE_USER_ACL))
3630
      break;
3631
    /* Conditionally writes to binlog */
3632 3633 3634 3635
    if (!(res = mysql_revoke_all(thd, lex->users_list)))
      send_ok(thd);
    break;
  }
3636 3637 3638
  case SQLCOM_REVOKE:
  case SQLCOM_GRANT:
  {
3639 3640 3641
    if (end_active_trans(thd))
      goto error;

3642
    if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
unknown's avatar
unknown committed
3643
		     first_table ?  first_table->db : select_lex->db,
unknown's avatar
VIEW  
unknown committed
3644
		     first_table ? &first_table->grant.privilege : 0,
3645 3646 3647
		     first_table ? 0 : 1, 0,
                     first_table ? (bool) first_table->schema_table :
                     select_lex->db ? is_schema_db(select_lex->db) : 0))
3648 3649
      goto error;

3650
    if (thd->security_ctx->user)              // If not replication
unknown's avatar
unknown committed
3651
    {
3652
      LEX_USER *user, *tmp_user;
3653

unknown's avatar
unknown committed
3654
      List_iterator <LEX_USER> user_list(lex->users_list);
3655
      while ((tmp_user= user_list++))
unknown's avatar
unknown committed
3656
      {
3657 3658
        if (!(user= get_current_user(thd, tmp_user)))
          goto error;
3659 3660 3661 3662 3663 3664 3665 3666
        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);
3667
        if (strcmp(thd->security_ctx->user, user->user.str) ||
3668
            my_strcasecmp(system_charset_info,
3669
                          user->host.str, thd->security_ctx->host_or_ip))
3670 3671
        {
          // TODO: use check_change_password()
3672 3673
          if (is_acl_user(user->host.str, user->user.str) &&
              user->password.str &&
3674
              check_access(thd, UPDATE_ACL,"mysql",0,1,1,0))
3675 3676 3677 3678 3679 3680
          {
            my_message(ER_PASSWORD_NOT_ALLOWED,
                       ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
            goto error;
          }
        }
unknown's avatar
SCRUM  
unknown committed
3681 3682
      }
    }
unknown's avatar
VIEW  
unknown committed
3683
    if (first_table)
3684
    {
3685 3686
      if (lex->type == TYPE_ENUM_PROCEDURE ||
          lex->type == TYPE_ENUM_FUNCTION)
3687 3688 3689 3690
      {
        uint grants= lex->all_privileges 
		   ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
		   : lex->grant;
3691
        if (check_grant_routine(thd, grants | GRANT_ACL, all_tables,
3692
                                lex->type == TYPE_ENUM_PROCEDURE, 0))
3693
	  goto error;
3694
        /* Conditionally writes to binlog */
3695 3696 3697 3698
        res= mysql_routine_grant(thd, all_tables,
                                 lex->type == TYPE_ENUM_PROCEDURE, 
                                 lex->users_list, grants,
                                 lex->sql_command == SQLCOM_REVOKE, 0);
3699 3700 3701
      }
      else
      {
3702 3703
	if (check_grant(thd,(lex->grant | lex->grant_tot_col | GRANT_ACL),
                        all_tables, 0, UINT_MAX, 0))
3704
	  goto error;
3705
        /* Conditionally writes to binlog */
3706 3707 3708 3709
        res= mysql_table_grant(thd, all_tables, lex->users_list,
			       lex->columns, lex->grant,
			       lex->sql_command == SQLCOM_REVOKE);
      }
3710 3711 3712
    }
    else
    {
3713
      if (lex->columns.elements || lex->type)
3714
      {
unknown's avatar
unknown committed
3715 3716
	my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
                   MYF(0));
unknown's avatar
unknown committed
3717
        goto error;
3718 3719
      }
      else
3720
	/* Conditionally writes to binlog */
3721 3722 3723 3724
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
3725
	if (lex->sql_command == SQLCOM_GRANT)
3726
	{
unknown's avatar
unknown committed
3727
	  List_iterator <LEX_USER> str_list(lex->users_list);
3728 3729 3730 3731 3732
	  LEX_USER *user, *tmp_user;
	  while ((tmp_user=str_list++))
          {
            if (!(user= get_current_user(thd, tmp_user)))
              goto error;
3733
	    reset_mqh(user, 0);
3734
          }
3735
	}
3736 3737 3738 3739
      }
    }
    break;
  }
unknown's avatar
SCRUM  
unknown committed
3740
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
unknown's avatar
unknown committed
3741
  case SQLCOM_RESET:
3742 3743 3744
    /*
      RESET commands are never written to the binary log, so we have to
      initialize this variable because RESET shares the same code as FLUSH
3745 3746 3747 3748
    */
    lex->no_write_to_binlog= 1;
  case SQLCOM_FLUSH:
  {
unknown's avatar
unknown committed
3749
    bool write_to_binlog;
unknown's avatar
unknown committed
3750
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
3751
      goto error;
3752

3753 3754 3755 3756
    /*
      reload_acl_and_cache() will tell us if we are allowed to write to the
      binlog or not.
    */
unknown's avatar
unknown committed
3757
    if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
3758 3759 3760 3761 3762
    {
      /*
        We WANT to write and we CAN write.
        ! we write after unlocking the table.
      */
3763 3764 3765
      /*
        Presumably, RESET and binlog writing doesn't require synchronization
      */
3766 3767
      if (!lex->no_write_to_binlog && write_to_binlog)
      {
3768
        write_bin_log(thd, FALSE, thd->query, thd->query_length);
3769 3770
      }
      send_ok(thd);
3771 3772
    } 
    
unknown's avatar
unknown committed
3773
    break;
3774
  }
unknown's avatar
unknown committed
3775
  case SQLCOM_KILL:
3776 3777 3778
  {
    Item *it= (Item *)lex->value_list.head();

unknown's avatar
unknown committed
3779 3780 3781 3782 3783 3784 3785
    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;
    }

3786
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1))
3787 3788 3789 3790 3791
    {
      my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
		 MYF(0));
      goto error;
    }
3792
    sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
unknown's avatar
unknown committed
3793
    break;
3794
  }
unknown's avatar
unknown committed
3795
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
3796
  case SQLCOM_SHOW_GRANTS:
3797 3798 3799 3800
  {
    LEX_USER *grant_user= get_current_user(thd, lex->grant_user);
    if (!grant_user)
      goto error;
3801
    if ((thd->security_ctx->priv_user &&
3802
	 !strcmp(thd->security_ctx->priv_user, grant_user->user.str)) ||
3803
	!check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
unknown's avatar
unknown committed
3804
    {
3805
      res = mysql_show_grants(thd, grant_user);
unknown's avatar
unknown committed
3806 3807
    }
    break;
3808
  }
unknown's avatar
unknown committed
3809
#endif
3810
  case SQLCOM_HA_OPEN:
unknown's avatar
VIEW  
unknown committed
3811
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3812
    if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE))
3813
      goto error;
unknown's avatar
unknown committed
3814
    res= mysql_ha_open(thd, first_table, 0);
3815 3816
    break;
  case SQLCOM_HA_CLOSE:
unknown's avatar
VIEW  
unknown committed
3817 3818
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    res= mysql_ha_close(thd, first_table);
3819 3820
    break;
  case SQLCOM_HA_READ:
unknown's avatar
VIEW  
unknown committed
3821
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3822 3823 3824 3825 3826
    /*
      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.
    */
3827
    unit->set_limit(select_lex);
3828
    res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
unknown's avatar
VIEW  
unknown committed
3829
                       lex->insert_list, lex->ha_rkey_mode, select_lex->where,
3830
                       unit->select_limit_cnt, unit->offset_limit_cnt);
3831 3832
    break;

unknown's avatar
unknown committed
3833
  case SQLCOM_BEGIN:
3834 3835 3836 3837 3838 3839
    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
3840
    if (begin_trans(thd))
unknown's avatar
unknown committed
3841
      goto error;
unknown's avatar
unknown committed
3842
    send_ok(thd);
unknown's avatar
unknown committed
3843 3844
    break;
  case SQLCOM_COMMIT:
3845
    if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
unknown's avatar
unknown committed
3846
                              lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
unknown's avatar
unknown committed
3847
      goto error;
3848
    send_ok(thd);
unknown's avatar
unknown committed
3849 3850
    break;
  case SQLCOM_ROLLBACK:
3851
    if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
unknown's avatar
unknown committed
3852
                              lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
unknown's avatar
unknown committed
3853
      goto error;
3854
    send_ok(thd);
unknown's avatar
unknown committed
3855
    break;
unknown's avatar
unknown committed
3856
  case SQLCOM_RELEASE_SAVEPOINT:
unknown's avatar
unknown committed
3857
  {
3858 3859
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
unknown's avatar
unknown committed
3860 3861 3862
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
3863
                       (uchar *)sv->name, sv->length) == 0)
unknown's avatar
unknown committed
3864 3865
        break;
    }
3866
    if (sv)
unknown's avatar
unknown committed
3867
    {
3868
      if (ha_release_savepoint(thd, sv))
unknown's avatar
unknown committed
3869
        res= TRUE; // cannot happen
unknown's avatar
unknown committed
3870 3871
      else
        send_ok(thd);
3872
      thd->transaction.savepoints=sv->prev;
unknown's avatar
unknown committed
3873
    }
3874
    else
unknown's avatar
unknown committed
3875
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
3876
    break;
unknown's avatar
unknown committed
3877
  }
unknown's avatar
unknown committed
3878
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
unknown's avatar
unknown committed
3879
  {
3880 3881
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
3882 3883 3884
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
3885
                       (uchar *)sv->name, sv->length) == 0)
3886 3887
        break;
    }
3888
    if (sv)
3889
    {
3890
      if (ha_rollback_to_savepoint(thd, sv))
3891 3892
        res= TRUE; // cannot happen
      else
unknown's avatar
unknown committed
3893
      {
unknown's avatar
unknown committed
3894 3895
        if (((thd->options & OPTION_KEEP_LOG) || 
             thd->transaction.all.modified_non_trans_table) &&
unknown's avatar
unknown committed
3896 3897 3898 3899 3900 3901
            !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);
      }
3902
      thd->transaction.savepoints=sv;
unknown's avatar
unknown committed
3903 3904
    }
    else
3905
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
3906
    break;
3907
  }
3908
  case SQLCOM_SAVEPOINT:
3909 3910
    if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
          thd->in_sub_stmt) || !opt_using_transactions)
unknown's avatar
unknown committed
3911
      send_ok(thd);
unknown's avatar
unknown committed
3912
    else
3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950
    {
      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
3951
    break;
3952 3953
  case SQLCOM_CREATE_PROCEDURE:
  case SQLCOM_CREATE_SPFUNCTION:
unknown's avatar
unknown committed
3954
  {
3955
    uint namelen;
unknown's avatar
unknown committed
3956
    char *name;
unknown's avatar
unknown committed
3957
    int sp_result= SP_INTERNAL_ERROR;
3958

3959
    DBUG_ASSERT(lex->sphead != 0);
unknown's avatar
unknown committed
3960
    DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
3961 3962 3963 3964
    /*
      Verify that the database name is allowed, optionally
      lowercase it.
    */
3965
    if (check_db_name(&lex->sphead->m_db))
3966
    {
3967
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str);
3968
      goto create_sp_error;
3969 3970
    }

3971
    /*
3972 3973 3974
      Check that a database directory with this name
      exists. Design note: This won't work on virtual databases
      like information_schema.
3975 3976
    */
    if (check_db_dir_existence(lex->sphead->m_db.str))
3977
    {
3978
      my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
3979
      goto create_sp_error;
3980
    }
3981

3982 3983
    if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
                     is_schema_db(lex->sphead->m_db.str)))
3984
      goto create_sp_error;
3985

3986 3987
    if (end_active_trans(thd))
      goto create_sp_error;
3988 3989

    name= lex->sphead->name(&namelen);
3990
#ifdef HAVE_DLOPEN
unknown's avatar
unknown committed
3991 3992 3993
    if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
    {
      udf_func *udf = find_udf(name, namelen);
3994

unknown's avatar
unknown committed
3995
      if (udf)
3996
      {
3997 3998
        my_error(ER_UDF_EXISTS, MYF(0), name);
        goto create_sp_error;
3999
      }
unknown's avatar
unknown committed
4000 4001 4002
    }
#endif

4003 4004
    if (sp_process_definer(thd))
      goto create_sp_error;
4005

unknown's avatar
unknown committed
4006 4007
    res= (sp_result= lex->sphead->create(thd));
    switch (sp_result) {
4008
    case SP_OK:
unknown's avatar
unknown committed
4009
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4010
      /* only add privileges if really neccessary */
4011
      if (sp_automatic_privileges && !opt_noacl &&
4012
          check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
4013
                               lex->sphead->m_db.str, name,
4014
                               lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
4015
      {
unknown's avatar
unknown committed
4016
        if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
4017
                                lex->sql_command == SQLCOM_CREATE_PROCEDURE))
4018 4019 4020
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_PROC_AUTO_GRANT_FAIL,
                       ER(ER_PROC_AUTO_GRANT_FAIL));
unknown's avatar
unknown committed
4021
        close_thread_tables(thd);
4022
      }
unknown's avatar
unknown committed
4023
#endif
unknown's avatar
unknown committed
4024
    break;
4025 4026 4027 4028 4029 4030 4031 4032 4033
    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;
4034 4035 4036
    case SP_FLD_STORE_FAILED:
      my_error(ER_CANT_CREATE_SROUTINE, MYF(0), name);
      break;
4037 4038 4039 4040 4041 4042 4043 4044 4045 4046
    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
4047
    if (sp_result != SP_OK )
4048 4049 4050 4051
      goto error;
    send_ok(thd);
    break; /* break super switch */
  } /* end case group bracket */
4052 4053 4054 4055
  case SQLCOM_CALL:
    {
      sp_head *sp;

4056 4057 4058 4059
      /*
        This will cache all SP and SF and open and lock all tables
        required for execution.
      */
4060
      if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
4061 4062 4063 4064
	  open_and_lock_tables(thd, all_tables))
       goto error;

      /*
4065 4066
        By this moment all needed SPs should be in cache so no need to look 
        into DB. 
4067
      */
4068 4069
      if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                                &thd->sp_proc_cache, TRUE)))
4070
      {
4071
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
unknown's avatar
unknown committed
4072
                 lex->spname->m_qname.str);
4073
	goto error;
4074 4075 4076
      }
      else
      {
unknown's avatar
unknown committed
4077
	ha_rows select_limit;
unknown's avatar
unknown committed
4078 4079
        /* bits that should be cleared in thd->server_status */
	uint bits_to_be_cleared= 0;
4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091
        /*
          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;
        }
4092

4093
	if (sp->m_flags & sp_head::MULTI_RESULTS)
4094
	{
4095
	  if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
4096
	  {
4097 4098 4099 4100
            /*
              The client does not support multiple result sets being sent
              back
            */
4101
	    my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
4102 4103
	    goto error;
	  }
unknown's avatar
unknown committed
4104 4105 4106 4107 4108 4109 4110
          /*
            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;
4111 4112
	}

4113
	if (check_routine_access(thd, EXECUTE_ACL,
4114
				 sp->m_db.str, sp->m_name.str, TRUE, FALSE))
4115 4116 4117
	{
	  goto error;
	}
unknown's avatar
unknown committed
4118 4119
	select_limit= thd->variables.select_limit;
	thd->variables.select_limit= HA_POS_ERROR;
4120

4121
        /* 
4122
          We never write CALL statements into binlog:
4123 4124 4125 4126 4127
           - 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.
4128
        */
4129
	res= sp->execute_procedure(thd, &lex->value_list);
4130 4131 4132
	/*
          If warnings have been cleared, we have to clear total_warn_count
          too, otherwise the clients get confused.
4133 4134 4135 4136
	 */
	if (thd->warn_list.is_empty())
	  thd->total_warn_count= 0;

unknown's avatar
unknown committed
4137
	thd->variables.select_limit= select_limit;
4138

unknown's avatar
unknown committed
4139
        thd->server_status&= ~bits_to_be_cleared;
4140

unknown's avatar
unknown committed
4141
	if (!res)
unknown's avatar
unknown committed
4142 4143
	  send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
                                thd->row_count_func));
4144
	else
4145
        {
4146
          DBUG_ASSERT(thd->is_error() || thd->killed);
4147
	  goto error;		// Substatement should already have sent error
4148
        }
4149
      }
4150
      break;
4151 4152
    }
  case SQLCOM_ALTER_PROCEDURE:
4153
  case SQLCOM_ALTER_FUNCTION:
4154
    {
unknown's avatar
unknown committed
4155
      int sp_result;
4156 4157 4158 4159
      sp_head *sp;
      st_sp_chistics chistics;

      memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
unknown's avatar
unknown committed
4160
      if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
4161 4162
        sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                            &thd->sp_proc_cache, FALSE);
4163
      else
4164 4165
        sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                            &thd->sp_func_cache, FALSE);
unknown's avatar
unknown committed
4166
      mysql_reset_errors(thd, 0);
4167
      if (! sp)
4168 4169
      {
	if (lex->spname->m_db.str)
unknown's avatar
unknown committed
4170
	  sp_result= SP_KEY_NOT_FOUND;
4171 4172 4173 4174 4175 4176
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
      }
4177 4178
      else
      {
4179 4180 4181
        if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str, 
				 sp->m_name.str,
                                 lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
4182
	  goto error;
4183 4184 4185

        if (end_active_trans(thd)) 
          goto error;
4186
	memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
4187 4188
        if ((sp->m_type == TYPE_ENUM_FUNCTION) &&
            !trust_function_creators &&  mysql_bin_log.is_open() &&
4189 4190 4191 4192 4193 4194
            !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
4195
          sp_result= SP_INTERNAL_ERROR;
4196 4197 4198
        }
        else
        {
4199 4200 4201 4202 4203 4204
          /*
            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
4205
          /* Conditionally writes to binlog */
unknown's avatar
unknown committed
4206 4207 4208 4209 4210 4211 4212 4213 4214

          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);
4215
        }
4216
      }
unknown's avatar
unknown committed
4217
      switch (sp_result)
4218
      {
unknown's avatar
unknown committed
4219
      case SP_OK:
4220
	send_ok(thd);
unknown's avatar
unknown committed
4221 4222
	break;
      case SP_KEY_NOT_FOUND:
4223 4224
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
4225 4226
	goto error;
      default:
4227 4228
	my_error(ER_SP_CANT_ALTER, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
4229
	goto error;
4230
      }
4231
      break;
4232 4233
    }
  case SQLCOM_DROP_PROCEDURE:
4234
  case SQLCOM_DROP_FUNCTION:
4235
    {
unknown's avatar
unknown committed
4236
      int sp_result;
4237 4238
      int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
                 TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
4239

unknown's avatar
unknown committed
4240
      sp_result= sp_routine_exists_in_table(thd, type, lex->spname);
unknown's avatar
unknown committed
4241
      mysql_reset_errors(thd, 0);
unknown's avatar
unknown committed
4242
      if (sp_result == SP_OK)
4243
      {
4244 4245 4246
        char *db= lex->spname->m_db.str;
	char *name= lex->spname->m_name.str;

4247 4248
	if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
unknown's avatar
merge  
unknown committed
4249
          goto error;
4250 4251 4252

        if (end_active_trans(thd)) 
          goto error;
unknown's avatar
unknown committed
4253
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4254
	if (sp_automatic_privileges && !opt_noacl &&
4255 4256
	    sp_revoke_privileges(thd, db, name, 
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE))
4257 4258 4259 4260 4261
	{
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
		       ER_PROC_AUTO_REVOKE_FAIL,
		       ER(ER_PROC_AUTO_REVOKE_FAIL));
	}
unknown's avatar
unknown committed
4262
#endif
unknown's avatar
unknown committed
4263
        /* Conditionally writes to binlog */
unknown's avatar
unknown committed
4264 4265 4266 4267 4268 4269

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

        sp_result= sp_drop_routine(thd, type, lex->spname);
4270 4271 4272
      }
      else
      {
4273
#ifdef HAVE_DLOPEN
4274 4275 4276 4277 4278 4279
	if (lex->sql_command == SQLCOM_DROP_FUNCTION)
	{
          udf_func *udf = find_udf(lex->spname->m_name.str,
                                   lex->spname->m_name.length);
          if (udf)
          {
4280
	    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
4281
	      goto error;
4282

4283
	    if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
4284
	    {
4285 4286
	      send_ok(thd);
	      break;
4287 4288
	    }
	  }
4289
	}
4290
#endif
4291
	if (lex->spname->m_db.str)
unknown's avatar
unknown committed
4292
	  sp_result= SP_KEY_NOT_FOUND;
4293 4294 4295 4296 4297
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
4298
      }
unknown's avatar
unknown committed
4299 4300
      res= sp_result;
      switch (sp_result) {
4301
      case SP_OK:
4302
	send_ok(thd);
4303 4304
	break;
      case SP_KEY_NOT_FOUND:
4305 4306
	if (lex->drop_if_exists)
	{
4307
	  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
4308
			      ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
4309
			      SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4310
	  res= FALSE;
4311 4312 4313
	  send_ok(thd);
	  break;
	}
4314 4315
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4316 4317
	goto error;
      default:
4318 4319
	my_error(ER_SP_DROP_FAILED, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4320
	goto error;
4321
      }
4322
      break;
4323
    }
unknown's avatar
unknown committed
4324 4325
  case SQLCOM_SHOW_CREATE_PROC:
    {
unknown's avatar
unknown committed
4326 4327
      if (sp_show_create_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname))
      {
4328 4329
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4330 4331 4332 4333 4334 4335
	goto error;
      }
      break;
    }
  case SQLCOM_SHOW_CREATE_FUNC:
    {
unknown's avatar
unknown committed
4336 4337
      if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname))
      {
4338 4339
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4340 4341 4342 4343
	goto error;
      }
      break;
    }
4344
#ifdef NOT_USED
unknown's avatar
unknown committed
4345 4346
  case SQLCOM_SHOW_STATUS_PROC:
    {
unknown's avatar
unknown committed
4347 4348
      res= sp_show_status_routine(thd, TYPE_ENUM_PROCEDURE,
                                  (lex->wild ? lex->wild->ptr() : NullS));
unknown's avatar
unknown committed
4349 4350 4351 4352
      break;
    }
  case SQLCOM_SHOW_STATUS_FUNC:
    {
unknown's avatar
unknown committed
4353 4354
      res= sp_show_status_routine(thd, TYPE_ENUM_FUNCTION,
                                  (lex->wild ? lex->wild->ptr() : NullS));
unknown's avatar
unknown committed
4355 4356
      break;
    }
4357
#endif
unknown's avatar
unknown committed
4358 4359 4360 4361 4362 4363 4364
#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
4365 4366
        sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                            &thd->sp_proc_cache, FALSE);
unknown's avatar
unknown committed
4367
      else
unknown's avatar
unknown committed
4368 4369
        sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                            &thd->sp_func_cache, FALSE);
4370
      if (!sp || sp->show_routine_code(thd))
4371 4372
      {
        /* We don't distinguish between errors for now */
unknown's avatar
unknown committed
4373 4374 4375 4376 4377 4378 4379
        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
unknown committed
4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392
  case SQLCOM_SHOW_CREATE_TRIGGER:
    {
      if (lex->spname->m_name.length > NAME_LEN)
      {
        my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
        goto error;
      }

      if (show_create_trigger(thd, lex->spname))
        goto error; /* Error has been already logged. */

      break;
    }
unknown's avatar
VIEW  
unknown committed
4393 4394
  case SQLCOM_CREATE_VIEW:
    {
4395 4396 4397 4398
      /*
        Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands
        as specified through the thd->lex->create_view_mode flag.
      */
4399 4400 4401
      if (end_active_trans(thd))
        goto error;

4402
      res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
unknown's avatar
VIEW  
unknown committed
4403 4404 4405 4406
      break;
    }
  case SQLCOM_DROP_VIEW:
    {
4407
      if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE) ||
unknown's avatar
unknown committed
4408 4409
          end_active_trans(thd))
        goto error;
4410 4411
      /* Conditionally writes to binlog. */
      res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
unknown's avatar
VIEW  
unknown committed
4412 4413
      break;
    }
4414 4415
  case SQLCOM_CREATE_TRIGGER:
  {
4416 4417 4418
    if (end_active_trans(thd))
      goto error;

4419
    /* Conditionally writes to binlog. */
4420 4421
    res= mysql_create_or_drop_trigger(thd, all_tables, 1);

4422 4423 4424 4425
    break;
  }
  case SQLCOM_DROP_TRIGGER:
  {
4426 4427 4428
    if (end_active_trans(thd))
      goto error;

4429
    /* Conditionally writes to binlog. */
4430 4431 4432
    res= mysql_create_or_drop_trigger(thd, all_tables, 0);
    break;
  }
4433
  case SQLCOM_XA_START:
4434 4435
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
        thd->lex->xa_opt == XA_RESUME)
4436
    {
4437
      if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
4438 4439 4440 4441
      {
        my_error(ER_XAER_NOTA, MYF(0));
        break;
      }
4442
      thd->transaction.xid_state.xa_state=XA_ACTIVE;
4443 4444 4445
      send_ok(thd);
      break;
    }
unknown's avatar
unknown committed
4446
    if (thd->lex->xa_opt != XA_NONE)
4447 4448 4449 4450
    { // JOIN is not supported yet. TODO
      my_error(ER_XAER_INVAL, MYF(0));
      break;
    }
4451
    if (thd->transaction.xid_state.xa_state != XA_NOTR)
4452
    {
unknown's avatar
unknown committed
4453
      my_error(ER_XAER_RMFAIL, MYF(0),
4454
               xa_state_names[thd->transaction.xid_state.xa_state]);
4455 4456 4457 4458 4459 4460 4461
      break;
    }
    if (thd->active_transaction() || thd->locked_tables)
    {
      my_error(ER_XAER_OUTSIDE, MYF(0));
      break;
    }
4462 4463 4464 4465 4466 4467 4468 4469 4470
    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);
unknown's avatar
unknown committed
4471
    thd->transaction.all.modified_non_trans_table= FALSE;
4472
    thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN);
4473 4474 4475 4476 4477 4478 4479 4480 4481 4482
    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;
    }
4483
    if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
4484
    {
unknown's avatar
unknown committed
4485
      my_error(ER_XAER_RMFAIL, MYF(0),
4486
               xa_state_names[thd->transaction.xid_state.xa_state]);
4487 4488
      break;
    }
4489
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4490 4491 4492 4493
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
4494
    thd->transaction.xid_state.xa_state=XA_IDLE;
4495 4496 4497
    send_ok(thd);
    break;
  case SQLCOM_XA_PREPARE:
4498
    if (thd->transaction.xid_state.xa_state != XA_IDLE)
4499
    {
unknown's avatar
unknown committed
4500
      my_error(ER_XAER_RMFAIL, MYF(0),
4501
               xa_state_names[thd->transaction.xid_state.xa_state]);
4502 4503
      break;
    }
4504
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4505 4506 4507 4508 4509 4510 4511
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
    if (ha_prepare(thd))
    {
      my_error(ER_XA_RBROLLBACK, MYF(0));
4512 4513
      xid_cache_delete(&thd->transaction.xid_state);
      thd->transaction.xid_state.xa_state=XA_NOTR;
4514 4515
      break;
    }
4516
    thd->transaction.xid_state.xa_state=XA_PREPARED;
4517 4518 4519
    send_ok(thd);
    break;
  case SQLCOM_XA_COMMIT:
4520
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4521
    {
4522 4523
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
4524
        my_error(ER_XAER_NOTA, MYF(0));
unknown's avatar
unknown committed
4525
      else
4526 4527 4528
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
        xid_cache_delete(xs);
unknown's avatar
unknown committed
4529
        send_ok(thd);
4530
      }
4531 4532
      break;
    }
4533
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
unknown's avatar
unknown committed
4534
        thd->lex->xa_opt == XA_ONE_PHASE)
4535
    {
unknown's avatar
unknown committed
4536 4537 4538
      int r;
      if ((r= ha_commit(thd)))
        my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
4539 4540 4541
      else
        send_ok(thd);
    }
4542
    else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
unknown's avatar
unknown committed
4543
             thd->lex->xa_opt == XA_NONE)
4544
    {
4545 4546 4547
      if (wait_if_global_read_lock(thd, 0, 0))
      {
        ha_rollback(thd);
4548
        my_error(ER_XAER_RMERR, MYF(0));
4549
      }
4550
      else
4551 4552 4553 4554 4555 4556 4557
      {
        if (ha_commit_one_phase(thd, 1))
          my_error(ER_XAER_RMERR, MYF(0));
        else
          send_ok(thd);
        start_waiting_global_read_lock(thd);
      }
4558 4559 4560
    }
    else
    {
unknown's avatar
unknown committed
4561
      my_error(ER_XAER_RMFAIL, MYF(0),
4562
               xa_state_names[thd->transaction.xid_state.xa_state]);
4563 4564
      break;
    }
unknown's avatar
unknown committed
4565
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
unknown's avatar
unknown committed
4566
    thd->transaction.all.modified_non_trans_table= FALSE;
4567
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
4568 4569
    xid_cache_delete(&thd->transaction.xid_state);
    thd->transaction.xid_state.xa_state=XA_NOTR;
4570 4571
    break;
  case SQLCOM_XA_ROLLBACK:
4572
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4573
    {
4574 4575
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
4576
        my_error(ER_XAER_NOTA, MYF(0));
unknown's avatar
unknown committed
4577
      else
4578 4579 4580
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
        xid_cache_delete(xs);
unknown's avatar
unknown committed
4581
        send_ok(thd);
4582
      }
4583 4584
      break;
    }
4585 4586
    if (thd->transaction.xid_state.xa_state != XA_IDLE &&
        thd->transaction.xid_state.xa_state != XA_PREPARED)
4587
    {
unknown's avatar
unknown committed
4588
      my_error(ER_XAER_RMFAIL, MYF(0),
4589
               xa_state_names[thd->transaction.xid_state.xa_state]);
4590 4591 4592 4593 4594 4595
      break;
    }
    if (ha_rollback(thd))
      my_error(ER_XAER_RMERR, MYF(0));
    else
      send_ok(thd);
4596
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
unknown's avatar
unknown committed
4597
    thd->transaction.all.modified_non_trans_table= FALSE;
4598
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
4599 4600
    xid_cache_delete(&thd->transaction.xid_state);
    thd->transaction.xid_state.xa_state=XA_NOTR;
4601 4602
    break;
  case SQLCOM_XA_RECOVER:
4603
    res= mysql_xa_recover(thd);
4604
    break;
unknown's avatar
unknown committed
4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628
  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
4629 4630 4631 4632 4633
  case SQLCOM_CREATE_SERVER:
  {
    int error;
    LEX *lex= thd->lex;
    DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER"));
unknown's avatar
unknown committed
4634 4635 4636 4637

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4638 4639
    if ((error= create_server(thd, &lex->server_options)))
    {
4640
      DBUG_PRINT("info", ("problem creating server <%s>",
unknown's avatar
unknown committed
4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652
                          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
4653 4654 4655 4656

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4657 4658
    if ((error= alter_server(thd, &lex->server_options)))
    {
4659
      DBUG_PRINT("info", ("problem altering server <%s>",
unknown's avatar
unknown committed
4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671
                          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
4672 4673 4674 4675

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4676 4677
    if ((err_code= drop_server(thd, &lex->server_options)))
    {
unknown's avatar
unknown committed
4678
      if (! lex->drop_if_exists && err_code == ER_FOREIGN_SERVER_DOESNT_EXIST)
unknown's avatar
unknown committed
4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692
      {
        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;
  }
4693
  default:
4694
#ifndef EMBEDDED_LIBRARY
4695
    DBUG_ASSERT(0);                             /* Impossible */
4696
#endif
4697
    send_ok(thd);
unknown's avatar
unknown committed
4698 4699
    break;
  }
4700
  thd_proc_info(thd, "query end");
4701 4702

  /*
unknown's avatar
unknown committed
4703
    Binlog-related cleanup:
4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714
    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);

4715
  /*
4716 4717
    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
4718 4719 4720 4721
    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))
4722
    thd->row_count_func= -1;
4723

4724
  goto finish;
unknown's avatar
unknown committed
4725 4726

error:
4727 4728
  res= TRUE;

4729
finish:
4730 4731 4732 4733 4734 4735 4736 4737
  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);
  }
4738
  DBUG_RETURN(res || thd->is_error());
unknown's avatar
unknown committed
4739 4740 4741
}


4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764
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()))
4765
        return 1;                               /* purecov: inspected */
4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777
      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());
      }
4778 4779 4780 4781
      if (res)
        result->abort();
      else
        result->send_eof();
4782 4783 4784 4785 4786
      delete result;
    }
    else
    {
      if (!result && !(result= new select_send()))
4787
        return 1;                               /* purecov: inspected */
4788 4789 4790 4791 4792 4793 4794 4795 4796 4797
      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
4798
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
4799
/**
4800
  Check grants for commands which work only with one table.
unknown's avatar
unknown committed
4801

4802 4803 4804
  @param thd                    Thread handler
  @param privilege              requested privilege
  @param all_tables             global table list of query
unknown's avatar
unknown committed
4805
  @param no_errors              FALSE/TRUE - report/don't report error to
4806
                            the client (using my_error() call).
unknown's avatar
unknown committed
4807 4808 4809 4810 4811

  @retval
    0   OK
  @retval
    1   access denied, error is sent to client
unknown's avatar
unknown committed
4812 4813
*/

4814
bool check_single_table_access(THD *thd, ulong privilege, 
4815
                               TABLE_LIST *all_tables, bool no_errors)
unknown's avatar
unknown committed
4816
{
4817 4818 4819 4820 4821 4822
  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;

4823 4824 4825 4826 4827 4828 4829 4830
  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,
4831
		   &all_tables->grant.privilege, 0, no_errors,
4832
                   test(all_tables->schema_table)))
4833
    goto deny;
unknown's avatar
unknown committed
4834

unknown's avatar
unknown committed
4835
  /* Show only 1 table for check_grant */
4836
  if (!(all_tables->belong_to_view &&
4837
        (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
4838
      check_grant(thd, privilege, all_tables, 0, 1, no_errors))
4839 4840 4841
    goto deny;

  thd->security_ctx= backup_ctx;
4842 4843 4844 4845 4846 4847 4848
  return 0;

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

unknown's avatar
unknown committed
4849
/**
4850 4851 4852
  Check grants for commands which work only with one table and all other
  tables belonging to subselects or implicitly opened tables.

unknown's avatar
unknown committed
4853 4854 4855 4856 4857 4858 4859 4860
  @param thd			Thread handler
  @param privilege		requested privilege
  @param all_tables		global table list of query

  @retval
    0   OK
  @retval
    1   access denied, error is sent to client
4861 4862 4863 4864
*/

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

4868
  /* Check rights on tables of subselects and implictly opened tables */
unknown's avatar
unknown committed
4869
  TABLE_LIST *subselects_tables, *view= all_tables->view ? all_tables : 0;
unknown's avatar
VIEW  
unknown committed
4870
  if ((subselects_tables= all_tables->next_global))
unknown's avatar
unknown committed
4871
  {
unknown's avatar
unknown committed
4872 4873 4874 4875 4876 4877
    /*
      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)
    {
4878
      if (check_single_table_access (thd, privilege, subselects_tables, FALSE))
unknown's avatar
unknown committed
4879 4880 4881 4882
        return 1;
      subselects_tables= subselects_tables->next_global;
    }
    if (subselects_tables &&
4883
        (check_table_access(thd, SELECT_ACL, subselects_tables, UINT_MAX, FALSE)))
4884
      return 1;
unknown's avatar
unknown committed
4885 4886
  }
  return 0;
unknown's avatar
unknown committed
4887 4888 4889
}


unknown's avatar
unknown committed
4890 4891
/**
  Get the user (global) and database privileges for all used tables.
unknown's avatar
unknown committed
4892

unknown's avatar
unknown committed
4893 4894 4895 4896
  @param 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 is enough to satisfy the request and the
                      global grants contains a SELECT grant.
unknown's avatar
unknown committed
4897

unknown's avatar
unknown committed
4898
  @note
unknown's avatar
unknown committed
4899 4900 4901 4902 4903
    The idea of EXTRA_ACL is that one will be granted access to the table if
    one has the asked privilege on any column combination of the table; For
    example to be able to check a table one needs to have SELECT privilege on
    any column of the table.

unknown's avatar
unknown committed
4904
  @retval
unknown's avatar
unknown committed
4905
    0  ok
unknown's avatar
unknown committed
4906 4907 4908 4909
  @retval
    1  If we can't get the privileges and we don't use table/column
    grants.
*/
unknown's avatar
unknown committed
4910
bool
unknown's avatar
unknown committed
4911
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
4912
	     bool dont_check_global_grants, bool no_errors, bool schema_db)
unknown's avatar
unknown committed
4913
{
4914
  Security_context *sctx= thd->security_ctx;
unknown's avatar
unknown committed
4915
  ulong db_access;
4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926
  /*
    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
4927
  ulong dummy;
4928 4929
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("db: %s  want_access: %lu  master_access: %lu",
4930
                      db ? db : "", want_access, sctx->master_access));
unknown's avatar
unknown committed
4931 4932 4933 4934 4935
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

4936
  thd_proc_info(thd, "checking permissions");
4937
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
4938
  {
4939
    DBUG_PRINT("error",("No database"));
4940
    if (!no_errors)
unknown's avatar
unknown committed
4941 4942
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
                 MYF(0));                       /* purecov: tested */
unknown's avatar
unknown committed
4943
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4944 4945
  }

4946 4947
  if (schema_db)
  {
4948 4949
    if (!(sctx->master_access & FILE_ACL) && (want_access & FILE_ACL) ||
        (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
4950 4951
    {
      if (!no_errors)
4952 4953
      {
        const char *db_name= db ? db : thd->db;
4954
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
4955 4956
                 sctx->priv_user, sctx->priv_host, db_name);
      }
4957 4958 4959 4960 4961 4962 4963 4964 4965
      DBUG_RETURN(TRUE);
    }
    else
    {
      *save_priv= SELECT_ACL;
      DBUG_RETURN(FALSE);
    }
  }

4966
  if ((sctx->master_access & want_access) == want_access)
unknown's avatar
unknown committed
4967
  {
4968 4969 4970 4971 4972
    /*
      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
    */
4973 4974
    db_access= sctx->db_access;
    if (!(sctx->master_access & SELECT_ACL) &&
unknown's avatar
unknown committed
4975
	(db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
4976 4977 4978
      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
4979
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
4980
  }
4981
  if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
4982
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
4983
  {						// We can never grant this
4984
    DBUG_PRINT("error",("No possible access"));
4985
    if (!no_errors)
4986
      my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
4987 4988
               sctx->priv_user,
               sctx->priv_host,
4989 4990 4991
               (thd->password ?
                ER(ER_YES) :
                ER(ER_NO)));                    /* purecov: tested */
unknown's avatar
unknown committed
4992
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
4993 4994 4995
  }

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

unknown's avatar
unknown committed
4998
  if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
4999 5000
    db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
                       db_is_pattern);
unknown's avatar
unknown committed
5001
  else
5002
    db_access= sctx->db_access;
5003
  DBUG_PRINT("info",("db_access: %lu", db_access));
unknown's avatar
unknown committed
5004
  /* Remove SHOW attribute and access rights we already have */
5005
  want_access &= ~(sctx->master_access | EXTRA_ACL);
5006 5007
  DBUG_PRINT("info",("db_access: %lu  want_access: %lu",
                     db_access, want_access));
5008
  db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
5009

unknown's avatar
unknown committed
5010
  if (db_access == want_access ||
5011
      (!dont_check_global_grants &&
5012
       !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
unknown's avatar
unknown committed
5013
    DBUG_RETURN(FALSE);				/* Ok */
5014 5015

  DBUG_PRINT("error",("Access denied"));
5016
  if (!no_errors)
5017
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
5018
             sctx->priv_user, sctx->priv_host,
5019 5020 5021
             (db ? db : (thd->db ?
                         thd->db :
                         "unknown")));          /* purecov: tested */
unknown's avatar
unknown committed
5022
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
5023 5024 5025
}


unknown's avatar
unknown committed
5026 5027
/**
  check for global access and give descriptive error message if it fails.
5028

unknown's avatar
unknown committed
5029 5030
  @param thd			Thread handler
  @param want_access		Use should have any of these global rights
5031

unknown's avatar
unknown committed
5032 5033
  @warning
    One gets access right if one has ANY of the rights in want_access.
5034 5035 5036 5037
    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.

unknown's avatar
unknown committed
5038
  @retval
5039
    0	ok
unknown's avatar
unknown committed
5040
  @retval
5041 5042
    1	Access denied.  In this case an error is sent to the client
*/
unknown's avatar
unknown committed
5043 5044

bool check_global_access(THD *thd, ulong want_access)
unknown's avatar
unknown committed
5045
{
unknown's avatar
unknown committed
5046
  char command[128];
5047
  if ((thd->security_ctx->master_access & want_access))
unknown's avatar
unknown committed
5048 5049
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
5050
  my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
unknown's avatar
unknown committed
5051
  return 1;
unknown's avatar
unknown committed
5052 5053 5054
}


5055 5056
static bool check_show_access(THD *thd, TABLE_LIST *table)
{
unknown's avatar
unknown committed
5057
  switch (get_schema_table_idx(table->schema_table)) {
5058 5059
  case SCH_SCHEMATA:
    return (specialflag & SPECIAL_SKIP_SHOW_DB) &&
unknown's avatar
unknown committed
5060
      check_global_access(thd, SHOW_DB_ACL);
5061 5062 5063 5064 5065

  case SCH_TABLE_NAMES:
  case SCH_TABLES:
  case SCH_VIEWS:
  case SCH_TRIGGERS:
unknown's avatar
unknown committed
5066 5067 5068
  case SCH_EVENTS:
  {
    const char *dst_db_name= table->schema_select_lex->db;
5069

unknown's avatar
unknown committed
5070
    DBUG_ASSERT(dst_db_name);
5071

unknown's avatar
unknown committed
5072 5073 5074 5075
    if (check_access(thd, SELECT_ACL, dst_db_name,
                     &thd->col_access, FALSE, FALSE,
                     is_schema_db(dst_db_name)))
      return TRUE;
5076

unknown's avatar
unknown committed
5077 5078 5079 5080 5081 5082 5083
    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;
5084 5085
    }

unknown's avatar
unknown committed
5086 5087 5088
    return FALSE;
  }

5089 5090
  case SCH_COLUMNS:
  case SCH_STATISTICS:
unknown's avatar
unknown committed
5091 5092 5093
  {
    TABLE_LIST *dst_table;
    dst_table= (TABLE_LIST *) table->schema_select_lex->table_list.first;
5094

unknown's avatar
unknown committed
5095
    DBUG_ASSERT(dst_table);
5096

unknown's avatar
unknown committed
5097 5098 5099 5100 5101 5102
    if (check_access(thd, SELECT_ACL | EXTRA_ACL,
                     dst_table->db,
                     &dst_table->grant.privilege,
                     FALSE, FALSE,
                     test(dst_table->schema_table)))
      return FALSE;
5103

5104
    return (check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE));
unknown's avatar
unknown committed
5105 5106
  }
  default:
5107 5108 5109 5110 5111 5112 5113
    break;
  }

  return FALSE;
}


unknown's avatar
unknown committed
5114
/**
5115 5116
  Check the privilege for all used tables.

5117 5118 5119 5120 5121 5122
  @param    thd          Thread context
  @param    want_access  Privileges requested
  @param    tables       List of tables to be checked
  @param    number       Check at most this number of tables.
  @param    no_errors    FALSE/TRUE - report/don't report error to
                         the client (using my_error() call).
5123

unknown's avatar
unknown committed
5124
  @note
5125 5126 5127 5128 5129 5130
    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).

5131 5132
  @retval  FALSE   OK
  @retval  TRUE    Access denied
unknown's avatar
unknown committed
5133 5134
*/

5135
bool
unknown's avatar
unknown committed
5136
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
5137
		   uint number, bool no_errors)
unknown's avatar
unknown committed
5138
{
5139 5140
  TABLE_LIST *org_tables= tables;
  TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
5141
  uint i= 0;
5142
  Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx;
5143
  /*
unknown's avatar
unknown committed
5144 5145 5146
    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.
5147
  */
5148 5149
  for (; i < number && tables != first_not_own_table;
       tables= tables->next_global, i++)
unknown's avatar
unknown committed
5150
  {
5151 5152 5153 5154 5155
    if (tables->security_ctx)
      sctx= tables->security_ctx;
    else
      sctx= backup_ctx;

5156
    if (tables->schema_table && 
5157
        (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
5158 5159 5160
    {
      if (!no_errors)
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
5161
                 sctx->priv_user, sctx->priv_host,
5162
                 INFORMATION_SCHEMA_NAME.str);
5163 5164
      return TRUE;
    }
5165 5166 5167 5168 5169
    /*
       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
5170 5171 5172 5173 5174 5175 5176 5177 5178 5179

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

      continue;
    }

    if (tables->derived ||
5180
        (tables->table && (int)tables->table->s->tmp_table))
unknown's avatar
unknown committed
5181
      continue;
5182 5183
    thd->security_ctx= sctx;
    if ((sctx->master_access & want_access) ==
5184
        (want_access & ~EXTRA_ACL) &&
unknown's avatar
unknown committed
5185
	thd->db)
unknown's avatar
unknown committed
5186
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
5187
    else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
unknown's avatar
unknown committed
5188
    {
5189
      if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
5190
			 0, no_errors, test(tables->schema_table)))
5191
        goto deny;                            // Access denied
unknown's avatar
unknown committed
5192
    }
5193
    else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
5194
			  0, no_errors, test(tables->schema_table)))
5195
      goto deny;
unknown's avatar
unknown committed
5196
  }
5197
  thd->security_ctx= backup_ctx;
5198
  return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
5199
		       test(want_access & EXTRA_ACL), number, no_errors);
5200 5201 5202
deny:
  thd->security_ctx= backup_ctx;
  return TRUE;
unknown's avatar
unknown committed
5203 5204
}

5205

5206
bool
5207 5208
check_routine_access(THD *thd, ulong want_access,char *db, char *name,
		     bool is_proc, bool no_errors)
5209 5210 5211 5212 5213
{
  TABLE_LIST tables[1];
  
  bzero((char *)tables, sizeof(TABLE_LIST));
  tables->db= db;
5214
  tables->table_name= tables->alias= name;
5215
  
unknown's avatar
unknown committed
5216 5217 5218 5219 5220 5221 5222
  /*
    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)
5223 5224
    tables->grant.privilege= want_access;
  else if (check_access(thd,want_access,db,&tables->grant.privilege,
unknown's avatar
unknown committed
5225
			0, no_errors, 0))
5226 5227
    return TRUE;
  
5228
    return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
5229 5230
}

5231

unknown's avatar
unknown committed
5232 5233
/**
  Check if the routine has any of the routine privileges.
5234

unknown's avatar
unknown committed
5235 5236 5237
  @param thd	       Thread handler
  @param db           Database name
  @param name         Routine name
5238

unknown's avatar
unknown committed
5239
  @retval
5240
    0            ok
unknown's avatar
unknown committed
5241
  @retval
5242 5243 5244
    1            error
*/

5245 5246
bool check_some_routine_access(THD *thd, const char *db, const char *name,
                               bool is_proc)
5247 5248
{
  ulong save_priv;
5249
  if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
5250
    return FALSE;
5251 5252 5253 5254 5255
  /*
    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) ||
5256 5257
      (save_priv & SHOW_PROC_ACLS))
    return FALSE;
5258
  return check_routine_level_acl(thd, db, name, is_proc);
5259 5260 5261
}


5262 5263 5264
/*
  Check if the given table has any of the asked privileges

unknown's avatar
unknown committed
5265 5266
  @param thd		 Thread handler
  @param want_access	 Bitmap of possible privileges to check for
5267

unknown's avatar
unknown committed
5268
  @retval
5269
    0  ok
unknown's avatar
unknown committed
5270
  @retval
5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284
    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,
5285 5286
                        &table->grant.privilege, 0, 1,
                        test(table->schema_table)) &&
5287
          !check_grant(thd, access, table, 0, 1, 1))
5288 5289 5290 5291 5292 5293 5294
        DBUG_RETURN(0);
    }
  }
  DBUG_PRINT("exit",("no matching access rights"));
  DBUG_RETURN(1);
}

unknown's avatar
unknown committed
5295
#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
5296

unknown's avatar
unknown committed
5297 5298 5299 5300
/****************************************************************************
	Check stack size; Send error if there isn't enough stack to continue
****************************************************************************/

5301 5302
#ifndef EMBEDDED_LIBRARY

unknown's avatar
unknown committed
5303 5304 5305 5306 5307 5308
#if STACK_DIRECTION < 0
#define used_stack(A,B) (long) (A - B)
#else
#define used_stack(A,B) (long) (B - A)
#endif

unknown's avatar
unknown committed
5309 5310 5311 5312
#ifndef DBUG_OFF
long max_stack_used;
#endif

unknown's avatar
unknown committed
5313 5314
/**
  @note
5315 5316 5317 5318
  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.
unknown's avatar
unknown committed
5319
*/
5320
bool check_stack_overrun(THD *thd, long margin,
5321
			 uchar *buf __attribute__((unused)))
unknown's avatar
unknown committed
5322 5323
{
  long stack_used;
5324
  DBUG_ASSERT(thd == current_thd);
unknown's avatar
unknown committed
5325
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
unknown's avatar
unknown committed
5326
      (long) (thread_stack - margin))
unknown's avatar
unknown committed
5327
  {
5328 5329 5330
    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));
5331
    thd->fatal_error();
unknown's avatar
unknown committed
5332 5333
    return 1;
  }
unknown's avatar
unknown committed
5334 5335 5336
#ifndef DBUG_OFF
  max_stack_used= max(max_stack_used, stack_used);
#endif
unknown's avatar
unknown committed
5337 5338
  return 0;
}
5339
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
5340 5341 5342 5343

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

5344
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
unknown's avatar
unknown committed
5345
{
5346
  LEX	*lex= current_thd->lex;
5347
  ulong old_info=0;
unknown's avatar
unknown committed
5348 5349 5350 5351 5352
  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);
5353 5354
  if (!(lex->yacc_yyvs= (uchar*)
	my_realloc(lex->yacc_yyvs,
unknown's avatar
unknown committed
5355 5356
		   *yystacksize*sizeof(**yyvs),
		   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
5357 5358
      !(lex->yacc_yyss= (uchar*)
	my_realloc(lex->yacc_yyss,
unknown's avatar
unknown committed
5359 5360 5361 5362 5363
		   *yystacksize*sizeof(**yyss),
		   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
    return 1;
  if (old_info)
  {						// Copy old info from stack
5364 5365
    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
5366 5367 5368 5369 5370 5371 5372
  }
  *yyss=(short*) lex->yacc_yyss;
  *yyvs=(YYSTYPE*) lex->yacc_yyvs;
  return 0;
}


unknown's avatar
unknown committed
5373
/**
5374 5375 5376 5377
 Reset THD part responsible for command processing state.

   This needs to be called before execution of every statement
   (prepared or conventional).
5378
   It is not called by substatements of routines.
5379

unknown's avatar
unknown committed
5380
  @todo
5381 5382
   Make it a method of THD and align its name with the rest of
   reset/end/start/init methods.
unknown's avatar
unknown committed
5383
  @todo
5384 5385 5386 5387 5388 5389
   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");
5390
  DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
5391
  DBUG_ASSERT(! thd->in_sub_stmt);
5392
  thd->free_list= 0;
5393
  thd->select_number= 1;
5394 5395 5396 5397
  /*
    Those two lines below are theoretically unneeded as
    THD::cleanup_after_query() should take care of this already.
  */
5398
  thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty();
5399 5400 5401
  thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;

  thd->query_start_used= 0;
5402
  thd->is_fatal_error= thd->time_zone_used= 0;
unknown's avatar
unknown committed
5403
  thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | 
unknown's avatar
unknown committed
5404 5405
                          SERVER_QUERY_NO_INDEX_USED |
                          SERVER_QUERY_NO_GOOD_INDEX_USED);
5406 5407 5408 5409 5410 5411
  /*
    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
5412 5413
  {
    thd->options&= ~OPTION_KEEP_LOG;
5414
    thd->transaction.all.modified_non_trans_table= FALSE;
unknown's avatar
unknown committed
5415
  }
5416
  DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
unknown's avatar
unknown committed
5417
  thd->thread_specific_used= FALSE;
5418 5419

  if (opt_bin_log)
5420
  {
5421 5422
    reset_dynamic(&thd->user_var_events);
    thd->user_var_events_alloc= thd->mem_root;
5423
  }
5424 5425 5426 5427 5428 5429
  thd->clear_error();
  thd->main_da.reset_diagnostics_area();
  thd->total_warn_count=0;			// Warnings for this query
  thd->rand_used= 0;
  thd->sent_row_count= thd->examined_row_count= 0;

5430 5431 5432 5433
  /*
    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
5434 5435
  thd->reset_current_stmt_binlog_row_based();

unknown's avatar
unknown committed
5436 5437 5438
  DBUG_VOID_RETURN;
}

5439

5440 5441 5442
void
mysql_init_select(LEX *lex)
{
unknown's avatar
unknown committed
5443
  SELECT_LEX *select_lex= lex->current_select;
unknown's avatar
unknown committed
5444
  select_lex->init_select();
5445
  lex->wild= 0;
5446 5447
  if (select_lex == &lex->select_lex)
  {
5448
    DBUG_ASSERT(lex->result == 0);
5449 5450
    lex->exchange= 0;
  }
5451 5452
}

5453

unknown's avatar
unknown committed
5454
bool
unknown's avatar
unknown committed
5455
mysql_new_select(LEX *lex, bool move_down)
5456
{
unknown's avatar
unknown committed
5457
  SELECT_LEX *select_lex;
5458
  THD *thd= lex->thd;
unknown's avatar
unknown committed
5459 5460
  DBUG_ENTER("mysql_new_select");

5461
  if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
5462
    DBUG_RETURN(1);
5463
  select_lex->select_number= ++thd->select_number;
unknown's avatar
unknown committed
5464
  select_lex->parent_lex= lex; /* Used in init_query. */
unknown's avatar
unknown committed
5465 5466
  select_lex->init_query();
  select_lex->init_select();
unknown's avatar
unknown committed
5467
  lex->nest_level++;
unknown's avatar
unknown committed
5468 5469 5470 5471 5472
  if (lex->nest_level > (int) MAX_SELECT_NESTING)
  {
    my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT,MYF(0),MAX_SELECT_NESTING);
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
5473
  select_lex->nest_level= lex->nest_level;
5474 5475 5476 5477 5478
  /*
    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
5479
  if (thd->stmt_arena->is_stmt_prepare())
5480
    select_lex->uncacheable|= UNCACHEABLE_PREPARE;
unknown's avatar
unknown committed
5481 5482
  if (move_down)
  {
unknown's avatar
unknown committed
5483
    SELECT_LEX_UNIT *unit;
5484
    lex->subqueries= TRUE;
unknown's avatar
unknown committed
5485
    /* first select_lex of subselect or derived table */
5486
    if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
unknown's avatar
unknown committed
5487
      DBUG_RETURN(1);
unknown's avatar
unknown committed
5488

unknown's avatar
unknown committed
5489 5490
    unit->init_query();
    unit->init_select();
5491
    unit->thd= thd;
unknown's avatar
unknown committed
5492
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
5493 5494
    unit->link_next= 0;
    unit->link_prev= 0;
5495
    unit->return_to= lex->current_select;
unknown's avatar
unknown committed
5496
    select_lex->include_down(unit);
5497 5498 5499 5500 5501
    /*
      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
5502 5503
  }
  else
unknown's avatar
unknown committed
5504
  {
unknown's avatar
VIEW  
unknown committed
5505 5506
    if (lex->current_select->order_list.first && !lex->current_select->braces)
    {
unknown's avatar
unknown committed
5507
      my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
unknown's avatar
unknown committed
5508
      DBUG_RETURN(1);
unknown's avatar
VIEW  
unknown committed
5509
    }
5510
    select_lex->include_neighbour(lex->current_select);
5511 5512 5513 5514 5515
    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
5516
  }
unknown's avatar
unknown committed
5517

5518
  select_lex->master_unit()->global_parameters= select_lex;
5519
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
5520
  lex->current_select= select_lex;
5521 5522 5523 5524 5525
  /*
    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
5526
  DBUG_RETURN(0);
5527
}
unknown's avatar
unknown committed
5528

unknown's avatar
unknown committed
5529
/**
5530 5531
  Create a select to return the same output as 'SELECT @@var_name'.

unknown's avatar
unknown committed
5532
  Used for SHOW COUNT(*) [ WARNINGS | ERROR].
5533

unknown's avatar
unknown committed
5534
  This will crash with a core dump if the variable doesn't exists.
5535

unknown's avatar
unknown committed
5536
  @param var_name		Variable name
5537 5538 5539 5540
*/

void create_select_for_variable(const char *var_name)
{
5541
  THD *thd;
5542
  LEX *lex;
5543
  LEX_STRING tmp, null_lex_string;
5544 5545
  Item *var;
  char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end;
5546
  DBUG_ENTER("create_select_for_variable");
5547 5548

  thd= current_thd;
unknown's avatar
unknown committed
5549
  lex= thd->lex;
5550 5551 5552 5553
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
5554
  bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
5555 5556 5557 5558
  /*
    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
5559 5560 5561 5562 5563 5564
  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);
  }
5565 5566 5567
  DBUG_VOID_RETURN;
}

5568

unknown's avatar
unknown committed
5569 5570
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
5571
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
5572
  mysql_init_select(lex);
5573 5574
  lex->select_lex.select_limit= 0;
  lex->unit.select_limit_cnt= HA_POS_ERROR;
unknown's avatar
unknown committed
5575
  lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list);
5576
  lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
unknown's avatar
VIEW  
unknown committed
5577 5578
  lex->query_tables= 0;
  lex->query_tables_last= &lex->query_tables;
unknown's avatar
unknown committed
5579
}
unknown's avatar
unknown committed
5580

5581

5582 5583 5584 5585
/*
  When you modify mysql_parse(), you may need to mofify
  mysql_test_parse_for_slave() in this same file.
*/
unknown's avatar
unknown committed
5586

5587 5588
/**
  Parse a query.
unknown's avatar
unknown committed
5589 5590 5591 5592 5593 5594

  @param       thd     Current thread
  @param       inBuf   Begining of the query text
  @param       length  Length of the query text
  @param[out]  found_semicolon For multi queries, position of the character of
                               the next query in the query text.
5595 5596 5597 5598
*/

void mysql_parse(THD *thd, const char *inBuf, uint length,
                 const char ** found_semicolon)
unknown's avatar
unknown committed
5599 5600
{
  DBUG_ENTER("mysql_parse");
5601 5602 5603

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

5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621
  /*
    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);
5622

5623
  if (query_cache_send_result_to_client(thd, (char*) inBuf, length) <= 0)
unknown's avatar
unknown committed
5624
  {
unknown's avatar
unknown committed
5625
    LEX *lex= thd->lex;
5626

5627 5628
    sp_cache_flush_obsolete(&thd->sp_proc_cache);
    sp_cache_flush_obsolete(&thd->sp_func_cache);
5629 5630 5631

    Lex_input_stream lip(thd, inBuf, length);

unknown's avatar
unknown committed
5632
    bool err= parse_sql(thd, &lip, NULL);
5633 5634
    *found_semicolon= lip.found_semicolon;

5635
    if (!err)
unknown's avatar
unknown committed
5636
    {
unknown's avatar
unknown committed
5637
#ifndef NO_EMBEDDED_ACCESS_CHECKS
5638
      if (mqh_used && thd->user_connect &&
5639
	  check_mqh(thd, lex->sql_command))
5640 5641 5642 5643
      {
	thd->net.error = 0;
      }
      else
unknown's avatar
unknown committed
5644
#endif
5645
      {
5646
	if (! thd->is_error())
unknown's avatar
unknown committed
5647
	{
5648 5649 5650 5651 5652 5653 5654 5655 5656 5657
          /*
            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.
          */
5658 5659
          if (*found_semicolon &&
              (thd->query_length= (ulong)(*found_semicolon - thd->query)))
5660 5661
            thd->query_length--;
          /* Actually execute the query */
5662 5663
          lex->set_trg_event_type_for_tables();
          mysql_execute_command(thd);
unknown's avatar
unknown committed
5664
	}
5665
      }
unknown's avatar
unknown committed
5666 5667
    }
    else
5668
    {
5669
      DBUG_ASSERT(thd->is_error());
5670
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
5671
			 thd->is_fatal_error));
5672 5673

      query_cache_abort(&thd->net);
5674
    }
5675 5676 5677 5678 5679 5680
    if (thd->lex->sphead)
    {
      delete thd->lex->sphead;
      thd->lex->sphead= 0;
    }
    lex->unit.cleanup();
5681
    thd_proc_info(thd, "freeing items");
5682
    thd->end_statement();
5683
    thd->cleanup_after_query();
5684
    DBUG_ASSERT(thd->change_list.is_empty());
unknown's avatar
unknown committed
5685
  }
5686 5687 5688 5689 5690 5691
  else
  {
    /* There are no multi queries in the cache. */
    *found_semicolon= NULL;
  }

unknown's avatar
unknown committed
5692 5693 5694 5695
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
5696
#ifdef HAVE_REPLICATION
5697 5698 5699 5700
/*
  Usable by the replication SQL thread only: just parse a query to know if it
  can be ignored because of replicate-*-table rules.

unknown's avatar
unknown committed
5701
  @retval
5702
    0	cannot be ignored
unknown's avatar
unknown committed
5703
  @retval
5704 5705 5706 5707 5708
    1	can be ignored
*/

bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
{
unknown's avatar
unknown committed
5709
  LEX *lex= thd->lex;
5710
  bool error= 0;
unknown's avatar
unknown committed
5711
  DBUG_ENTER("mysql_test_parse_for_slave");
5712

5713 5714 5715 5716
  Lex_input_stream lip(thd, inBuf, length);
  lex_start(thd);
  mysql_reset_thd_for_next_command(thd);

unknown's avatar
unknown committed
5717
  if (!parse_sql(thd, &lip, NULL) &&
5718
      all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
unknown's avatar
unknown committed
5719
    error= 1;                  /* Ignore question */
5720
  thd->end_statement();
5721
  thd->cleanup_after_query();
unknown's avatar
unknown committed
5722
  DBUG_RETURN(error);
5723
}
unknown's avatar
unknown committed
5724
#endif
unknown's avatar
unknown committed
5725

5726

unknown's avatar
unknown committed
5727

unknown's avatar
unknown committed
5728 5729 5730 5731 5732 5733
/**
  Store field definition for create.

  @return
    Return 0 if ok
*/
unknown's avatar
unknown committed
5734

5735
bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
unknown's avatar
unknown committed
5736
		       char *length, char *decimals,
5737
		       uint type_modifier,
5738 5739
		       Item *default_value, Item *on_update_value,
                       LEX_STRING *comment,
5740 5741
		       char *change,
                       List<String> *interval_list, CHARSET_INFO *cs,
unknown's avatar
unknown committed
5742
		       uint uint_geom_type)
unknown's avatar
unknown committed
5743
{
unknown's avatar
unknown committed
5744
  register Create_field *new_field;
unknown's avatar
unknown committed
5745
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
5746 5747
  DBUG_ENTER("add_field_to_list");

5748 5749
  if (check_string_char_length(field_name, "", NAME_CHAR_LEN,
                               system_charset_info, 1))
unknown's avatar
unknown committed
5750
  {
5751
    my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */
unknown's avatar
unknown committed
5752 5753 5754 5755
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
5756
    Key *key;
unknown's avatar
unknown committed
5757
    lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
5758 5759 5760 5761
    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
5762 5763 5764 5765
    lex->col_list.empty();
  }
  if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
  {
5766
    Key *key;
unknown's avatar
unknown committed
5767
    lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
5768 5769 5770 5771
    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
5772 5773 5774
    lex->col_list.empty();
  }

5775
  if (default_value)
unknown's avatar
unknown committed
5776
  {
5777
    /* 
unknown's avatar
unknown committed
5778 5779
      Default value should be literal => basic constants =>
      no need fix_fields()
5780 5781 5782
      
      We allow only one function as part of default value - 
      NOW() as default for TIMESTAMP type.
5783
    */
5784 5785
    if (default_value->type() == Item::FUNC_ITEM && 
        !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
5786
         type == MYSQL_TYPE_TIMESTAMP))
5787
    {
5788
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5789 5790 5791
      DBUG_RETURN(1);
    }
    else if (default_value->type() == Item::NULL_ITEM)
unknown's avatar
unknown committed
5792
    {
5793
      default_value= 0;
5794 5795 5796
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
5797
	my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5798 5799 5800 5801 5802
	DBUG_RETURN(1);
      }
    }
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
5803
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
unknown's avatar
unknown committed
5804 5805 5806
      DBUG_RETURN(1);
    }
  }
5807

5808
  if (on_update_value && type != MYSQL_TYPE_TIMESTAMP)
5809
  {
5810
    my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
5811 5812
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
5813

5814
  if (type == MYSQL_TYPE_TIMESTAMP && length)
5815 5816 5817 5818 5819
  {
    /* 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
5820
    char buf[32];
5821
    my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length);
unknown's avatar
unknown committed
5822
    WARN_DEPRECATED(thd, "5.2", buf, "'TIMESTAMP'");
5823 5824
  }

unknown's avatar
unknown committed
5825
  if (!(new_field= new Create_field()) ||
5826
      new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
5827 5828
                      default_value, on_update_value, comment, change,
                      interval_list, cs, uint_geom_type))
unknown's avatar
unknown committed
5829
    DBUG_RETURN(1);
unknown's avatar
unknown committed
5830

5831
  lex->alter_info.create_list.push_back(new_field);
unknown's avatar
unknown committed
5832 5833 5834 5835
  lex->last_field=new_field;
  DBUG_RETURN(0);
}

5836

unknown's avatar
unknown committed
5837
/** Store position for column in ALTER TABLE .. ADD column. */
unknown's avatar
unknown committed
5838 5839 5840

void store_position_for_column(const char *name)
{
5841
  current_thd->lex->last_field->after=my_const_cast(char*) (name);
unknown's avatar
unknown committed
5842 5843 5844
}

bool
unknown's avatar
unknown committed
5845
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
5846 5847 5848 5849
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
5850
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
5851 5852 5853 5854 5855
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
5856
  thd->lex->proc_list.link_in_list((uchar*) order,(uchar**) &order->next);
unknown's avatar
unknown committed
5857 5858 5859 5860
  return 0;
}


unknown's avatar
unknown committed
5861 5862 5863
/**
  save order by and tables in own lists.
*/
unknown's avatar
unknown committed
5864

unknown's avatar
unknown committed
5865
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
5866 5867 5868
{
  ORDER *order;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
5869
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER))))
unknown's avatar
unknown committed
5870
    DBUG_RETURN(1);
unknown's avatar
unknown committed
5871 5872
  order->item_ptr= item;
  order->item= &order->item_ptr;
unknown's avatar
unknown committed
5873 5874 5875
  order->asc = asc;
  order->free_me=0;
  order->used=0;
5876
  order->counter_used= 0;
5877
  list.link_in_list((uchar*) order,(uchar**) &order->next);
unknown's avatar
unknown committed
5878 5879 5880 5881
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895
/**
  Add a table to list of used tables.

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

  @retval
unknown's avatar
unknown committed
5896
      0		Error
unknown's avatar
unknown committed
5897 5898
  @retval
    \#	Pointer to TABLE_LIST element added to the total table list
unknown's avatar
unknown committed
5899 5900
*/

unknown's avatar
unknown committed
5901 5902
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
5903
					     LEX_STRING *alias,
unknown's avatar
unknown committed
5904 5905
					     ulong table_options,
					     thr_lock_type lock_type,
unknown's avatar
unknown committed
5906
					     List<Index_hint> *index_hints_arg,
unknown's avatar
unknown committed
5907
                                             LEX_STRING *option)
unknown's avatar
unknown committed
5908 5909
{
  register TABLE_LIST *ptr;
unknown's avatar
unknown committed
5910
  TABLE_LIST *previous_table_ref; /* The table preceding the current one. */
unknown's avatar
unknown committed
5911
  char *alias_str;
5912
  LEX *lex= thd->lex;
unknown's avatar
unknown committed
5913
  DBUG_ENTER("add_table_to_list");
5914
  LINT_INIT(previous_table_ref);
unknown's avatar
unknown committed
5915 5916 5917 5918

  if (!table)
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? alias->str : table->table.str;
5919 5920
  if (!test(table_options & TL_OPTION_ALIAS) && 
      check_table_name(table->table.str, table->table.length))
unknown's avatar
unknown committed
5921
  {
5922
    my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
unknown's avatar
unknown committed
5923 5924
    DBUG_RETURN(0);
  }
unknown's avatar
unknown committed
5925 5926

  if (table->is_derived_table() == FALSE && table->db.str &&
5927
      check_db_name(&table->db))
unknown's avatar
unknown committed
5928 5929 5930 5931
  {
    my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str);
    DBUG_RETURN(0);
  }
unknown's avatar
unknown committed
5932 5933

  if (!alias)					/* Alias is case sensitive */
5934 5935 5936
  {
    if (table->sel)
    {
unknown's avatar
unknown committed
5937 5938
      my_message(ER_DERIVED_MUST_HAVE_ALIAS,
                 ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
5939 5940
      DBUG_RETURN(0);
    }
5941
    if (!(alias_str= (char*) thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
5942
      DBUG_RETURN(0);
5943
  }
unknown's avatar
unknown committed
5944
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
5945
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
5946
  if (table->db.str)
5947 5948 5949 5950
  {
    ptr->db= table->db.str;
    ptr->db_length= table->db.length;
  }
5951
  else if (lex->copy_db_to(&ptr->db, &ptr->db_length))
unknown's avatar
unknown committed
5952
    DBUG_RETURN(0);
unknown's avatar
unknown committed
5953

5954
  ptr->alias= alias_str;
5955
  if (lower_case_table_names && table->table.length)
5956
    table->table.length= my_casedn_str(files_charset_info, table->table.str);
5957 5958
  ptr->table_name=table->table.str;
  ptr->table_name_length=table->table.length;
5959
  ptr->lock_type=   lock_type;
unknown's avatar
unknown committed
5960 5961
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
5962
  ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
5963
  ptr->derived=	    table->sel;
5964
  if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db,
5965
                                      INFORMATION_SCHEMA_NAME.str))
5966
  {
5967
    ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
5968 5969
    if (!schema_table ||
        (schema_table->hidden && 
unknown's avatar
unknown committed
5970
         ((sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0 || 
5971 5972 5973
          /*
            this check is used for show columns|keys from I_S hidden table
          */
unknown's avatar
unknown committed
5974 5975
          lex->sql_command == SQLCOM_SHOW_FIELDS ||
          lex->sql_command == SQLCOM_SHOW_KEYS)))
5976
    {
unknown's avatar
unknown committed
5977
      my_error(ER_UNKNOWN_TABLE, MYF(0),
5978
               ptr->table_name, INFORMATION_SCHEMA_NAME.str);
5979 5980
      DBUG_RETURN(0);
    }
5981
    ptr->schema_table_name= ptr->table_name;
5982 5983
    ptr->schema_table= schema_table;
  }
5984
  ptr->select_lex=  lex->current_select;
unknown's avatar
unknown committed
5985
  ptr->cacheable_table= 1;
5986
  ptr->index_hints= index_hints_arg;
unknown's avatar
unknown committed
5987
  ptr->option= option ? option->str : 0;
unknown's avatar
unknown committed
5988
  /* check that used name is unique */
5989
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
5990
  {
unknown's avatar
unknown committed
5991 5992 5993 5994
    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
5995
	 tables ;
unknown's avatar
VIEW  
unknown committed
5996
	 tables=tables->next_local)
unknown's avatar
unknown committed
5997
    {
5998 5999
      if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
	  !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
6000
      {
6001
	my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
unknown's avatar
unknown committed
6002 6003
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
6004 6005
    }
  }
unknown's avatar
unknown committed
6006 6007 6008
  /* Store the table reference preceding the current one. */
  if (table_list.elements > 0)
  {
6009 6010 6011
    /*
      table_list.next points to the last inserted TABLE_LIST->next_local'
      element
6012
      We don't use the offsetof() macro here to avoid warnings from gcc
6013
    */
6014 6015 6016
    previous_table_ref= (TABLE_LIST*) ((char*) table_list.next -
                                       ((char*) &(ptr->next_local) -
                                        (char*) ptr));
6017 6018 6019 6020 6021 6022 6023 6024
    /*
      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
6025
  }
6026

unknown's avatar
unknown committed
6027 6028 6029 6030 6031 6032
  /*
    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'.
  */
6033
  table_list.link_in_list((uchar*) ptr, (uchar**) &ptr->next_local);
unknown's avatar
unknown committed
6034
  ptr->next_name_resolution_table= NULL;
6035
  /* Link table in global list (all used tables) */
6036
  lex->add_to_query_tables(ptr);
unknown's avatar
unknown committed
6037 6038 6039
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
6040

unknown's avatar
unknown committed
6041 6042
/**
  Initialize a new table list for a nested join.
6043

6044 6045 6046 6047 6048 6049 6050 6051
    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.

unknown's avatar
unknown committed
6052 6053 6054 6055 6056 6057
  @param thd         current thread

  @retval
    0   if success
  @retval
    1   otherwise
6058 6059 6060 6061 6062 6063 6064
*/

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

6066 6067
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
6068
    DBUG_RETURN(1);
6069
  nested_join= ptr->nested_join=
6070
    ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
6071

6072 6073 6074
  join_list->push_front(ptr);
  ptr->embedding= embedding;
  ptr->join_list= join_list;
6075
  ptr->alias= (char*) "(nested_join)";
6076 6077 6078 6079 6080 6081 6082
  embedding= ptr;
  join_list= &nested_join->join_list;
  join_list->empty();
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
6083 6084
/**
  End a nested join table list.
6085 6086 6087

    The function returns to the previous join nest level.
    If the current level contains only one member, the function
6088
    moves it one level up, eliminating the nest.
6089

unknown's avatar
unknown committed
6090 6091 6092 6093 6094
  @param thd         current thread

  @return
    - Pointer to TABLE_LIST element added to the total table list, if success
    - 0, otherwise
6095 6096 6097 6098 6099
*/

TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
{
  TABLE_LIST *ptr;
6100
  NESTED_JOIN *nested_join;
6101
  DBUG_ENTER("end_nested_join");
6102

unknown's avatar
unknown committed
6103
  DBUG_ASSERT(embedding);
6104 6105 6106
  ptr= embedding;
  join_list= ptr->join_list;
  embedding= ptr->embedding;
6107
  nested_join= ptr->nested_join;
6108 6109 6110 6111 6112 6113 6114 6115 6116
  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;
  }
6117
  else if (nested_join->join_list.elements == 0)
unknown's avatar
unknown committed
6118 6119
  {
    join_list->pop();
6120
    ptr= 0;                                     // return value
unknown's avatar
unknown committed
6121
  }
6122 6123 6124 6125
  DBUG_RETURN(ptr);
}


unknown's avatar
unknown committed
6126 6127
/**
  Nest last join operation.
6128 6129 6130

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

unknown's avatar
unknown committed
6131
  @param thd         current thread
6132

unknown's avatar
unknown committed
6133
  @retval
6134
    0  Error
unknown's avatar
unknown committed
6135 6136
  @retval
    \#  Pointer to TABLE_LIST element created for the new nested join
6137 6138 6139 6140 6141 6142
*/

TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
{
  TABLE_LIST *ptr;
  NESTED_JOIN *nested_join;
6143
  List<TABLE_LIST> *embedded_list;
6144
  DBUG_ENTER("nest_last_join");
6145

6146 6147
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
6148
    DBUG_RETURN(0);
6149
  nested_join= ptr->nested_join=
6150
    ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
6151

6152 6153
  ptr->embedding= embedding;
  ptr->join_list= join_list;
6154
  ptr->alias= (char*) "(nest_last_join)";
6155
  embedded_list= &nested_join->join_list;
6156
  embedded_list->empty();
6157 6158

  for (uint i=0; i < 2; i++)
6159 6160 6161 6162 6163
  {
    TABLE_LIST *table= join_list->pop();
    table->join_list= embedded_list;
    table->embedding= ptr;
    embedded_list->push_back(table);
unknown's avatar
unknown committed
6164 6165 6166 6167 6168 6169 6170
    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
6171 6172
      if (prev_join_using)
        ptr->join_using_fields= prev_join_using;
unknown's avatar
unknown committed
6173
    }
6174 6175 6176 6177 6178 6179 6180
  }
  join_list->push_front(ptr);
  nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
  DBUG_RETURN(ptr);
}


unknown's avatar
unknown committed
6181 6182
/**
  Add a table to the current join list.
6183 6184 6185 6186 6187 6188

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

unknown's avatar
unknown committed
6189 6190 6191
  @param table       the table to add

  @return
6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204
    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;
}


unknown's avatar
unknown committed
6205 6206
/**
  Convert a right join into equivalent left join.
6207 6208

    The function takes the current join list t[0],t[1] ... and
6209 6210 6211 6212 6213 6214
    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
unknown's avatar
unknown committed
6215
  @verbatim
6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226
    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
unknown's avatar
unknown committed
6227
   @endverbatim
6228

unknown's avatar
unknown committed
6229
  @param thd         current thread
6230

unknown's avatar
unknown committed
6231 6232 6233
  @return
    - Pointer to the table representing the inner table, if success
    - 0, otherwise
6234 6235
*/

6236
TABLE_LIST *st_select_lex::convert_right_join()
6237 6238
{
  TABLE_LIST *tab2= join_list->pop();
6239
  TABLE_LIST *tab1= join_list->pop();
6240 6241 6242 6243 6244 6245 6246 6247 6248
  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
6249 6250
/**
  Set lock for all tables in current select level.
unknown's avatar
unknown committed
6251

unknown's avatar
unknown committed
6252
  @param lock_type			Lock to set for tables
unknown's avatar
unknown committed
6253

unknown's avatar
unknown committed
6254
  @note
unknown's avatar
unknown committed
6255 6256 6257 6258 6259
    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
6260
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
6261 6262 6263 6264 6265 6266
{
  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
6267 6268 6269
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first;
       tables;
       tables= tables->next_local)
unknown's avatar
unknown committed
6270 6271 6272 6273 6274 6275 6276
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
6277

unknown's avatar
unknown committed
6278 6279
/**
  Create a fake SELECT_LEX for a unit.
unknown's avatar
unknown committed
6280 6281 6282 6283

    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
unknown's avatar
unknown committed
6284
    @verbatim
unknown's avatar
unknown committed
6285
    (SELECT ... ORDER BY order_list [LIMIT n]) ORDER BY ... 
unknown's avatar
unknown committed
6286
    @endvarbatim
unknown's avatar
unknown committed
6287
    or of the form
unknown's avatar
unknown committed
6288
    @varbatim
unknown's avatar
unknown committed
6289
    (SELECT ... ORDER BY LIMIT n) ORDER BY ...
unknown's avatar
unknown committed
6290
    @endvarbatim
unknown's avatar
unknown committed
6291
  
unknown's avatar
unknown committed
6292 6293 6294
  @param thd_arg		   thread handle

  @note
unknown's avatar
unknown committed
6295 6296 6297
    The object is used to retrieve rows from the temporary table
    where the result on the union is obtained.

unknown's avatar
unknown committed
6298
  @retval
unknown's avatar
unknown committed
6299
    1     on failure to create the object
unknown's avatar
unknown committed
6300
  @retval
unknown's avatar
unknown committed
6301 6302 6303
    0     on success
*/

unknown's avatar
unknown committed
6304
bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
unknown's avatar
unknown committed
6305 6306 6307 6308
{
  SELECT_LEX *first_sl= first_select();
  DBUG_ENTER("add_fake_select_lex");
  DBUG_ASSERT(!fake_select_lex);
unknown's avatar
unknown committed
6309

unknown's avatar
unknown committed
6310
  if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
6311 6312 6313 6314
      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
6315
  fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */
unknown's avatar
unknown committed
6316 6317
  fake_select_lex->make_empty_select();
  fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
6318 6319
  fake_select_lex->select_limit= 0;

unknown's avatar
unknown committed
6320
  fake_select_lex->context.outer_context=first_sl->context.outer_context;
6321 6322 6323
  /* 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
6324

6325
  if (!is_union())
unknown's avatar
unknown committed
6326 6327 6328 6329 6330 6331 6332 6333 6334
  {
    /* 
      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
6335
    thd_arg->lex->current_select= fake_select_lex;
unknown's avatar
unknown committed
6336
  }
unknown's avatar
unknown committed
6337
  thd_arg->lex->pop_context();
unknown's avatar
unknown committed
6338 6339 6340
  DBUG_RETURN(0);
}

6341

unknown's avatar
unknown committed
6342
/**
6343 6344
  Push a new name resolution context for a JOIN ... ON clause to the
  context stack of a query block.
unknown's avatar
unknown committed
6345 6346

    Create a new name resolution context for a JOIN ... ON clause,
6347 6348 6349
    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
6350

unknown's avatar
unknown committed
6351 6352 6353 6354 6355
  @param thd       pointer to current thread
  @param left_op   left  operand of the JOIN
  @param right_op  rigth operand of the JOIN

  @retval
6356
    FALSE  if all is OK
unknown's avatar
unknown committed
6357
  @retval
6358
    TRUE   if a memory allocation error occured
unknown's avatar
unknown committed
6359 6360
*/

6361 6362 6363
bool
push_new_name_resolution_context(THD *thd,
                                 TABLE_LIST *left_op, TABLE_LIST *right_op)
unknown's avatar
unknown committed
6364 6365
{
  Name_resolution_context *on_context;
6366
  if (!(on_context= new (thd->mem_root) Name_resolution_context))
6367
    return TRUE;
unknown's avatar
unknown committed
6368 6369 6370 6371 6372
  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();
6373
  return thd->lex->push_context(on_context);
unknown's avatar
unknown committed
6374 6375 6376
}


unknown's avatar
unknown committed
6377
/**
unknown's avatar
unknown committed
6378 6379 6380 6381
  Add an ON condition to the second operand of a JOIN ... ON.

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

unknown's avatar
unknown committed
6382 6383
  @param b     the second operand of a JOIN ... ON
  @param expr  the condition to be added to the ON clause
unknown's avatar
unknown committed
6384

unknown's avatar
unknown committed
6385
  @retval
unknown's avatar
unknown committed
6386
    FALSE  if there was some error
unknown's avatar
unknown committed
6387
  @retval
unknown's avatar
unknown committed
6388 6389 6390 6391
    TRUE   if all is OK
*/

void add_join_on(TABLE_LIST *b, Item *expr)
unknown's avatar
unknown committed
6392
{
6393
  if (expr)
6394
  {
6395
    if (!b->on_expr)
unknown's avatar
unknown committed
6396
      b->on_expr= expr;
6397 6398
    else
    {
unknown's avatar
unknown committed
6399 6400 6401 6402 6403 6404
      /*
        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);
6405 6406
    }
    b->on_expr->top_level_item();
6407
  }
unknown's avatar
unknown committed
6408 6409 6410
}


unknown's avatar
unknown committed
6411
/**
unknown's avatar
unknown committed
6412 6413
  Mark that there is a NATURAL JOIN or JOIN ... USING between two
  tables.
6414

unknown's avatar
unknown committed
6415 6416 6417 6418 6419 6420 6421 6422 6423 6424
    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
unknown's avatar
unknown committed
6425
  @verbatim
6426 6427 6428
    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
6429

unknown's avatar
unknown committed
6430 6431 6432
    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>)
unknown's avatar
unknown committed
6433

unknown's avatar
unknown committed
6434 6435 6436
    SELECT * FROM t1 JOIN t2 USING(j) WHERE <some_cond>
     <=>
    SELECT * FROM t1, t2 WHERE (t1.j=t2.j and <some_cond>)
unknown's avatar
unknown committed
6437 6438 6439 6440 6441
   @endverbatim

  @param a		  Left join argument
  @param b		  Right join argument
  @param using_fields    Field names from USING clause
6442 6443
*/

unknown's avatar
unknown committed
6444 6445
void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
                      SELECT_LEX *lex)
unknown's avatar
unknown committed
6446
{
unknown's avatar
unknown committed
6447
  b->natural_join= a;
unknown's avatar
unknown committed
6448
  lex->prev_join_using= using_fields;
unknown's avatar
unknown committed
6449 6450
}

unknown's avatar
unknown committed
6451

6452
/**
6453 6454
  Reload/resets privileges and the different caches.

6455 6456 6457 6458
  @param thd Thread handler (can be NULL!)
  @param options What should be reset/reloaded (tables, privileges, slave...)
  @param tables Tables to flush (if any)
  @param write_to_binlog True if we can write to the binlog.
6459
               
6460 6461 6462 6463 6464 6465 6466 6467
  @note Depending on 'options', it may be very bad to write the
    query to the binlog (e.g. FLUSH SLAVE); this is a
    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.

  @return Error status code
    @retval 0 Ok
6468
    @retval !=0  Error; thd->killed is set or thd->is_error() is true
6469 6470
*/

6471 6472
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
                          bool *write_to_binlog)
unknown's avatar
unknown committed
6473 6474 6475
{
  bool result=0;
  select_errors=0;				/* Write if more errors */
6476
  bool tmp_write_to_binlog= 1;
6477

6478
  DBUG_ASSERT(!thd || !thd->in_sub_stmt);
6479

unknown's avatar
SCRUM  
unknown committed
6480
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
6481 6482
  if (options & REFRESH_GRANT)
  {
6483 6484 6485 6486 6487 6488
    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)))
6489 6490
    {
      thd->thread_stack= (char*) &tmp_thd;
6491
      thd->store_globals();
6492
    }
6493 6494
    if (thd)
    {
6495 6496 6497 6498
      if (acl_reload(thd))
        result= 1;
      if (grant_reload(thd))
        result= 1;
6499 6500 6501 6502 6503 6504 6505 6506
    }
    if (tmp_thd)
    {
      delete tmp_thd;
      /* Remember that we don't have a THD */
      my_pthread_setspecific_ptr(THR_THD,  0);
      thd= 0;
    }
6507
    reset_mqh((LEX_USER *)NULL, TRUE);
unknown's avatar
unknown committed
6508
  }
unknown's avatar
SCRUM  
unknown committed
6509
#endif
unknown's avatar
unknown committed
6510 6511
  if (options & REFRESH_LOG)
  {
6512
    /*
unknown's avatar
unknown committed
6513
      Flush the normal query log, the update log, the binary log,
unknown's avatar
unknown committed
6514 6515
      the slow query log, the relay log (if it exists) and the log
      tables.
6516
    */
unknown's avatar
unknown committed
6517

6518
    /*
unknown's avatar
unknown committed
6519 6520 6521 6522
      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)
6523 6524
    */
    tmp_write_to_binlog= 0;
6525 6526 6527 6528
    if( mysql_bin_log.is_open() )
    {
      mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
    }
unknown's avatar
unknown committed
6529
#ifdef HAVE_REPLICATION
6530
    pthread_mutex_lock(&LOCK_active_mi);
6531
    rotate_relay_log(active_mi);
6532
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
6533
#endif
unknown's avatar
unknown committed
6534 6535 6536 6537 6538

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

    if (ha_flush_logs(NULL))
unknown's avatar
unknown committed
6539
      result=1;
unknown's avatar
unknown committed
6540 6541
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
6542
  }
unknown's avatar
unknown committed
6543
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
6544 6545
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
6546
    query_cache.pack();				// FLUSH QUERY CACHE
6547
    options &= ~REFRESH_QUERY_CACHE;    // Don't flush cache, just free memory
unknown's avatar
unknown committed
6548 6549 6550
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
6551
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
6552
  }
unknown's avatar
unknown committed
6553
#endif /*HAVE_QUERY_CACHE*/
6554 6555 6556 6557 6558
  /*
    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
6559
  {
6560
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
6561
    {
6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572
      /*
        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
6573
        {
6574
          if ((*lock_p)->type >= TL_WRITE_ALLOW_WRITE)
6575 6576 6577 6578
          {
            my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
            return 1;
          }
unknown's avatar
unknown committed
6579
        }
6580
      }
unknown's avatar
unknown committed
6581 6582 6583 6584
      /*
	Writing to the binlog could cause deadlocks, as we don't log
	UNLOCK TABLES
      */
6585
      tmp_write_to_binlog= 0;
6586
      if (lock_global_read_lock(thd))
unknown's avatar
unknown committed
6587
	return 1;                               // Killed
6588 6589
      result= close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
                                  FALSE : TRUE, TRUE);
unknown's avatar
unknown committed
6590
      if (make_global_read_lock_block_commit(thd)) // Killed
6591 6592 6593 6594 6595
      {
        /* Don't leave things in a half-locked state */
        unlock_global_read_lock(thd);
        return 1;
      }
unknown's avatar
unknown committed
6596
    }
6597
    else
6598 6599
      result= close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
                                  FALSE : TRUE, FALSE);
unknown's avatar
unknown committed
6600
    my_dbopt_cleanup();
unknown's avatar
unknown committed
6601 6602 6603
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
unknown's avatar
unknown committed
6604
  if (thd && (options & REFRESH_STATUS))
unknown's avatar
unknown committed
6605
    refresh_status(thd);
unknown's avatar
unknown committed
6606 6607
  if (options & REFRESH_THREADS)
    flush_thread_cache();
unknown's avatar
unknown committed
6608
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
6609
  if (options & REFRESH_MASTER)
6610
  {
6611
    DBUG_ASSERT(thd);
6612
    tmp_write_to_binlog= 0;
6613
    if (reset_master(thd))
unknown's avatar
unknown committed
6614
    {
6615
      result=1;
unknown's avatar
unknown committed
6616
    }
6617
  }
6618
#endif
unknown's avatar
unknown committed
6619
#ifdef OPENSSL
6620 6621 6622 6623 6624 6625
   if (options & REFRESH_DES_KEY_FILE)
   {
     if (des_key_file)
       result=load_des_key_file(des_key_file);
   }
#endif
unknown's avatar
unknown committed
6626
#ifdef HAVE_REPLICATION
6627 6628
 if (options & REFRESH_SLAVE)
 {
6629
   tmp_write_to_binlog= 0;
6630
   pthread_mutex_lock(&LOCK_active_mi);
6631
   if (reset_slave(thd, active_mi))
6632
     result=1;
6633
   pthread_mutex_unlock(&LOCK_active_mi);
6634
 }
6635
#endif
6636
 if (options & REFRESH_USER_RESOURCES)
6637
   reset_mqh((LEX_USER *) NULL, 0);             /* purecov: inspected */
unknown's avatar
unknown committed
6638
 *write_to_binlog= tmp_write_to_binlog;
6639
 return result;
unknown's avatar
unknown committed
6640 6641
}

6642

unknown's avatar
unknown committed
6643 6644
/**
  kill on thread.
6645

unknown's avatar
unknown committed
6646 6647 6648
  @param thd			Thread class
  @param id			Thread id
  @param only_kill_query        Should it kill the query or the connection
6649

unknown's avatar
unknown committed
6650
  @note
6651 6652 6653
    This is written such that we have a short lock on LOCK_thread_count
*/

6654
uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
unknown's avatar
unknown committed
6655 6656 6657
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
6658 6659
  DBUG_ENTER("kill_one_thread");
  DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query));
6660 6661
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
6662 6663
  while ((tmp=it++))
  {
unknown's avatar
unknown committed
6664 6665
    if (tmp->command == COM_DAEMON)
      continue;
unknown's avatar
unknown committed
6666 6667
    if (tmp->thread_id == id)
    {
6668 6669
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
6670 6671 6672
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
6673 6674
  if (tmp)
  {
6675 6676
    if ((thd->security_ctx->master_access & SUPER_ACL) ||
	!strcmp(thd->security_ctx->user, tmp->security_ctx->user))
6677
    {
unknown's avatar
SCRUM  
unknown committed
6678
      tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
6679 6680 6681 6682 6683 6684
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }
6685 6686 6687 6688
  DBUG_PRINT("exit", ("%d", error));
  DBUG_RETURN(error);
}

6689

6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703
/*
  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)))
6704
    send_ok(thd);
unknown's avatar
unknown committed
6705
  else
unknown's avatar
unknown committed
6706
    my_error(error, MYF(0), id);
unknown's avatar
unknown committed
6707 6708
}

unknown's avatar
unknown committed
6709

unknown's avatar
unknown committed
6710
/** If pointer is not a null pointer, append filename to it. */
6711

unknown's avatar
unknown committed
6712 6713
bool append_file_to_dir(THD *thd, const char **filename_ptr,
                        const char *table_name)
6714
{
6715
  char buff[FN_REFLEN],*ptr, *end;
6716 6717 6718 6719 6720 6721 6722
  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))
  {
6723
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
6724 6725 6726 6727
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
6728
  end=convert_dirname(buff, *filename_ptr, NullS);
6729
  if (!(ptr= (char*) thd->alloc((size_t) (end-buff) + strlen(table_name)+1)))
6730 6731
    return 1;					// End of memory
  *filename_ptr=ptr;
6732
  strxmov(ptr,buff,table_name,NullS);
6733 6734
  return 0;
}
6735

6736

unknown's avatar
unknown committed
6737 6738
/**
  Check if the select is a simple select (not an union).
6739

unknown's avatar
unknown committed
6740
  @retval
6741
    0	ok
unknown's avatar
unknown committed
6742
  @retval
6743 6744 6745 6746 6747 6748
    1	error	; In this case the error messege is sent to the client
*/

bool check_simple_select()
{
  THD *thd= current_thd;
6749 6750
  LEX *lex= thd->lex;
  if (lex->current_select != &lex->select_lex)
6751 6752
  {
    char command[80];
6753 6754 6755
    Lex_input_stream *lip= thd->m_lip;
    strmake(command, lip->yylval->symbol.str,
	    min(lip->yylval->symbol.length, sizeof(command)-1));
6756
    my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
6757 6758 6759 6760
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
6761

unknown's avatar
unknown committed
6762

unknown's avatar
unknown committed
6763
Comp_creator *comp_eq_creator(bool invert)
unknown's avatar
unknown committed
6764
{
unknown's avatar
unknown committed
6765
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
unknown's avatar
unknown committed
6766 6767
}

unknown's avatar
unknown committed
6768

unknown's avatar
unknown committed
6769
Comp_creator *comp_ge_creator(bool invert)
unknown's avatar
unknown committed
6770
{
unknown's avatar
unknown committed
6771
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
unknown's avatar
unknown committed
6772 6773
}

unknown's avatar
unknown committed
6774

unknown's avatar
unknown committed
6775
Comp_creator *comp_gt_creator(bool invert)
unknown's avatar
unknown committed
6776
{
unknown's avatar
unknown committed
6777
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
unknown's avatar
unknown committed
6778 6779
}

unknown's avatar
unknown committed
6780

unknown's avatar
unknown committed
6781
Comp_creator *comp_le_creator(bool invert)
unknown's avatar
unknown committed
6782
{
unknown's avatar
unknown committed
6783
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
unknown's avatar
unknown committed
6784 6785
}

unknown's avatar
unknown committed
6786

unknown's avatar
unknown committed
6787
Comp_creator *comp_lt_creator(bool invert)
unknown's avatar
unknown committed
6788
{
unknown's avatar
unknown committed
6789
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
unknown's avatar
unknown committed
6790 6791
}

unknown's avatar
unknown committed
6792

unknown's avatar
unknown committed
6793
Comp_creator *comp_ne_creator(bool invert)
unknown's avatar
unknown committed
6794
{
unknown's avatar
unknown committed
6795
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
unknown's avatar
unknown committed
6796
}
unknown's avatar
unknown committed
6797 6798


unknown's avatar
unknown committed
6799 6800
/**
  Construct ALL/ANY/SOME subquery Item.
unknown's avatar
unknown committed
6801

unknown's avatar
unknown committed
6802 6803 6804 6805
  @param left_expr   pointer to left expression
  @param cmp         compare function creator
  @param all         true if we create ALL subquery
  @param select_lex  pointer on parsed subquery structure
unknown's avatar
unknown committed
6806

unknown's avatar
unknown committed
6807
  @return
unknown's avatar
unknown committed
6808 6809 6810 6811 6812 6813 6814
    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
6815
  if ((cmp == &comp_eq_creator) && !all)       //  = ANY <=> IN
unknown's avatar
unknown committed
6816
    return new Item_in_subselect(left_expr, select_lex);
unknown's avatar
unknown committed
6817 6818

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

  Item_allany_subselect *it=
6822
    new Item_allany_subselect(left_expr, cmp, select_lex, all);
unknown's avatar
unknown committed
6823
  if (all)
6824
    return it->upper_item= new Item_func_not_all(it);	/* ALL */
unknown's avatar
unknown committed
6825

6826
  return it->upper_item= new Item_func_nop_all(it);      /* ANY/SOME */
unknown's avatar
unknown committed
6827
}
6828 6829


unknown's avatar
unknown committed
6830 6831
/**
  Multi update query pre-check.
6832

unknown's avatar
unknown committed
6833 6834
  @param thd		Thread handler
  @param tables	Global/local table list (have to be the same)
6835

unknown's avatar
unknown committed
6836
  @retval
unknown's avatar
unknown committed
6837
    FALSE OK
unknown's avatar
unknown committed
6838
  @retval
unknown's avatar
unknown committed
6839
    TRUE  Error
6840
*/
unknown's avatar
unknown committed
6841

unknown's avatar
unknown committed
6842
bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
6843 6844 6845 6846 6847
{
  const char *msg= 0;
  TABLE_LIST *table;
  LEX *lex= thd->lex;
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
6848
  DBUG_ENTER("multi_update_precheck");
6849 6850 6851

  if (select_lex->item_list.elements != lex->value_list.elements)
  {
6852
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
6853
    DBUG_RETURN(TRUE);
6854 6855 6856 6857 6858
  }
  /*
    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
6859
  for (table= tables; table; table= table->next_local)
6860
  {
6861 6862 6863
    if (table->derived)
      table->grant.privilege= SELECT_ACL;
    else if ((check_access(thd, UPDATE_ACL, table->db,
6864 6865
                           &table->grant.privilege, 0, 1,
                           test(table->schema_table)) ||
6866
              check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
unknown's avatar
unknown committed
6867
             (check_access(thd, SELECT_ACL, table->db,
6868 6869
                           &table->grant.privilege, 0, 0,
                           test(table->schema_table)) ||
6870
              check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
unknown's avatar
unknown committed
6871
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
6872

unknown's avatar
VIEW  
unknown committed
6873
    table->table_in_first_from_clause= 1;
6874
  }
unknown's avatar
unknown committed
6875 6876 6877
  /*
    Is there tables of subqueries?
  */
6878
  if (&lex->select_lex != lex->all_selects_list)
6879
  {
6880
    DBUG_PRINT("info",("Checking sub query list"));
unknown's avatar
VIEW  
unknown committed
6881
    for (table= tables; table; table= table->next_global)
6882
    {
6883
      if (!table->table_in_first_from_clause)
6884 6885
      {
	if (check_access(thd, SELECT_ACL, table->db,
6886 6887
			 &table->grant.privilege, 0, 0,
                         test(table->schema_table)) ||
6888
	    check_grant(thd, SELECT_ACL, table, 0, 1, 0))
unknown's avatar
unknown committed
6889
	  DBUG_RETURN(TRUE);
6890 6891 6892 6893 6894 6895
      }
    }
  }

  if (select_lex->order_list.elements)
    msg= "ORDER BY";
6896
  else if (select_lex->select_limit)
6897 6898 6899 6900
    msg= "LIMIT";
  if (msg)
  {
    my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
unknown's avatar
unknown committed
6901
    DBUG_RETURN(TRUE);
6902
  }
unknown's avatar
unknown committed
6903
  DBUG_RETURN(FALSE);
6904 6905
}

unknown's avatar
unknown committed
6906 6907
/**
  Multi delete query pre-check.
6908

unknown's avatar
unknown committed
6909 6910
  @param thd			Thread handler
  @param tables		Global/local table list
6911

unknown's avatar
unknown committed
6912
  @retval
unknown's avatar
unknown committed
6913
    FALSE OK
unknown's avatar
unknown committed
6914
  @retval
unknown's avatar
unknown committed
6915
    TRUE  error
6916
*/
unknown's avatar
unknown committed
6917

6918
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
6919 6920 6921
{
  SELECT_LEX *select_lex= &thd->lex->select_lex;
  TABLE_LIST *aux_tables=
unknown's avatar
unknown committed
6922
    (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
6923
  TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
unknown's avatar
VIEW  
unknown committed
6924
  DBUG_ENTER("multi_delete_precheck");
unknown's avatar
unknown committed
6925

6926 6927
  /* sql_yacc guarantees that tables and aux_tables are not zero */
  DBUG_ASSERT(aux_tables != 0);
6928
  if (check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
6929 6930 6931 6932 6933 6934 6935 6936
    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;
6937
  if (check_table_access(thd, DELETE_ACL, aux_tables, UINT_MAX, FALSE))
6938 6939
  {
    thd->lex->query_tables_own_last= save_query_tables_own_last;
unknown's avatar
unknown committed
6940
    DBUG_RETURN(TRUE);
6941 6942 6943
  }
  thd->lex->query_tables_own_last= save_query_tables_own_last;

6944 6945
  if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
  {
unknown's avatar
unknown committed
6946 6947
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
6948
    DBUG_RETURN(TRUE);
6949
  }
6950 6951 6952 6953
  DBUG_RETURN(FALSE);
}


unknown's avatar
unknown committed
6954
/**
6955 6956 6957
  Link tables in auxilary table list of multi-delete with corresponding
  elements in main table list, and set proper locks for them.

unknown's avatar
unknown committed
6958
  @param lex   pointer to LEX representing multi-delete
6959

unknown's avatar
unknown committed
6960 6961 6962 6963
  @retval
    FALSE   success
  @retval
    TRUE    error
6964 6965 6966 6967 6968 6969 6970 6971 6972 6973
*/

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
6974
  for (target_tbl= (TABLE_LIST *)lex->auxiliary_table_list.first;
6975
       target_tbl; target_tbl= target_tbl->next_local)
6976
  {
6977
    lex->table_count++;
6978 6979
    /* All tables in aux_tables must be found in FROM PART */
    TABLE_LIST *walk;
unknown's avatar
VIEW  
unknown committed
6980
    for (walk= tables; walk; walk= walk->next_local)
6981
    {
unknown's avatar
unknown committed
6982 6983 6984
      if (!my_strcasecmp(table_alias_charset,
			 target_tbl->alias, walk->alias) &&
	  !strcmp(walk->db, target_tbl->db))
6985 6986 6987 6988
	break;
    }
    if (!walk)
    {
6989
      my_error(ER_UNKNOWN_TABLE, MYF(0),
6990
               target_tbl->table_name, "MULTI DELETE");
unknown's avatar
unknown committed
6991
      DBUG_RETURN(TRUE);
6992
    }
unknown's avatar
unknown committed
6993 6994 6995 6996 6997
    if (!walk->derived)
    {
      target_tbl->table_name= walk->table_name;
      target_tbl->table_name_length= walk->table_name_length;
    }
unknown's avatar
unknown committed
6998
    walk->updating= target_tbl->updating;
unknown's avatar
unknown committed
6999
    walk->lock_type= target_tbl->lock_type;
unknown's avatar
VIEW  
unknown committed
7000
    target_tbl->correspondent_table= walk;	// Remember corresponding table
7001
  }
unknown's avatar
unknown committed
7002
  DBUG_RETURN(FALSE);
7003 7004 7005
}


unknown's avatar
unknown committed
7006 7007
/**
  simple UPDATE query pre-check.
unknown's avatar
unknown committed
7008

unknown's avatar
unknown committed
7009 7010
  @param thd		Thread handler
  @param tables	Global table list
unknown's avatar
unknown committed
7011

unknown's avatar
unknown committed
7012
  @retval
unknown's avatar
unknown committed
7013
    FALSE OK
unknown's avatar
unknown committed
7014
  @retval
unknown's avatar
unknown committed
7015
    TRUE  Error
unknown's avatar
unknown committed
7016
*/
unknown's avatar
unknown committed
7017

unknown's avatar
unknown committed
7018
bool update_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7019 7020 7021 7022
{
  DBUG_ENTER("update_precheck");
  if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
  {
unknown's avatar
unknown committed
7023
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7024
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7025
  }
unknown's avatar
unknown committed
7026
  DBUG_RETURN(check_one_table_access(thd, UPDATE_ACL, tables));
unknown's avatar
unknown committed
7027 7028 7029
}


unknown's avatar
unknown committed
7030 7031
/**
  simple DELETE query pre-check.
unknown's avatar
unknown committed
7032

unknown's avatar
unknown committed
7033 7034
  @param thd		Thread handler
  @param tables	Global table list
unknown's avatar
unknown committed
7035

unknown's avatar
unknown committed
7036
  @retval
unknown's avatar
unknown committed
7037
    FALSE  OK
unknown's avatar
unknown committed
7038
  @retval
unknown's avatar
unknown committed
7039
    TRUE   error
unknown's avatar
unknown committed
7040
*/
unknown's avatar
unknown committed
7041

unknown's avatar
unknown committed
7042
bool delete_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7043 7044 7045
{
  DBUG_ENTER("delete_precheck");
  if (check_one_table_access(thd, DELETE_ACL, tables))
unknown's avatar
unknown committed
7046
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7047
  /* Set privilege for the WHERE clause */
unknown's avatar
unknown committed
7048
  tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
7049
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
7050 7051 7052
}


unknown's avatar
unknown committed
7053 7054
/**
  simple INSERT query pre-check.
unknown's avatar
unknown committed
7055

unknown's avatar
unknown committed
7056 7057
  @param thd		Thread handler
  @param tables	Global table list
unknown's avatar
unknown committed
7058

unknown's avatar
unknown committed
7059
  @retval
unknown's avatar
unknown committed
7060
    FALSE  OK
unknown's avatar
unknown committed
7061
  @retval
unknown's avatar
unknown committed
7062
    TRUE   error
unknown's avatar
unknown committed
7063
*/
unknown's avatar
unknown committed
7064

unknown's avatar
merge  
unknown committed
7065
bool insert_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7066 7067 7068 7069
{
  LEX *lex= thd->lex;
  DBUG_ENTER("insert_precheck");

unknown's avatar
unknown committed
7070 7071 7072 7073
  /*
    Check that we have modify privileges for the first table and
    select privileges for the rest
  */
unknown's avatar
unknown committed
7074 7075 7076
  ulong privilege= (INSERT_ACL |
                    (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
                    (lex->value_list.elements ? UPDATE_ACL : 0));
unknown's avatar
unknown committed
7077 7078

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

unknown's avatar
unknown committed
7081
  if (lex->update_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
7082
  {
unknown's avatar
unknown committed
7083
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7084
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7085
  }
unknown's avatar
unknown committed
7086
  DBUG_RETURN(FALSE);
7087
}
unknown's avatar
unknown committed
7088 7089


unknown's avatar
unknown committed
7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104
/**
    @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)) ||
7105
         check_grant(thd, SELECT_ACL, table, 2, UINT_MAX, 0);
unknown's avatar
unknown committed
7106 7107 7108
}


unknown's avatar
unknown committed
7109 7110
/**
  CREATE TABLE query pre-check.
unknown's avatar
unknown committed
7111

unknown's avatar
unknown committed
7112 7113 7114
  @param thd			Thread handler
  @param tables		Global table list
  @param create_table	        Table which will be created
unknown's avatar
unknown committed
7115

unknown's avatar
unknown committed
7116
  @retval
unknown's avatar
unknown committed
7117
    FALSE   OK
unknown's avatar
unknown committed
7118
  @retval
unknown's avatar
unknown committed
7119
    TRUE   Error
unknown's avatar
unknown committed
7120
*/
unknown's avatar
unknown committed
7121

unknown's avatar
unknown committed
7122 7123
bool create_table_precheck(THD *thd, TABLE_LIST *tables,
                           TABLE_LIST *create_table)
unknown's avatar
unknown committed
7124 7125
{
  LEX *lex= thd->lex;
7126 7127
  SELECT_LEX *select_lex= &lex->select_lex;
  ulong want_priv;
unknown's avatar
merge  
unknown committed
7128
  bool error= TRUE;                                 // Error message is given
unknown's avatar
unknown committed
7129
  DBUG_ENTER("create_table_precheck");
7130

7131 7132 7133 7134 7135
  /*
    Require CREATE [TEMPORARY] privilege on new table; for
    CREATE TABLE ... SELECT, also require INSERT.
  */

7136
  want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
7137 7138 7139
              CREATE_TMP_ACL : CREATE_ACL) |
             (select_lex->item_list.elements ? INSERT_ACL : 0);

unknown's avatar
unknown committed
7140
  if (check_access(thd, want_priv, create_table->db,
7141 7142
		   &create_table->grant.privilege, 0, 0,
                   test(create_table->schema_table)) ||
unknown's avatar
unknown committed
7143 7144 7145
      check_merge_table_access(thd, create_table->db,
			       (TABLE_LIST *)
			       lex->create_info.merge_list.first))
7146
    goto err;
7147
  if (want_priv != CREATE_TMP_ACL &&
7148
      check_grant(thd, want_priv, create_table, 0, 1, 0))
7149 7150 7151 7152 7153 7154
    goto err;

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

7155 7156
#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
    /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
7157
    /*
7158
      Only do the check for PS, because we on execute we have to check that
unknown's avatar
unknown committed
7159 7160
      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).
7161
    */
unknown's avatar
unknown committed
7162
    if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
7163
    {
unknown's avatar
unknown committed
7164 7165 7166 7167
      /*
        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
7168
          find_table_in_global_list(tables, create_table->db,
7169
                                    create_table->table_name))
unknown's avatar
unknown committed
7170
      {
7171
	error= FALSE;
unknown's avatar
unknown committed
7172 7173 7174
        goto err;
      }
    }
7175
#endif
7176
    if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
7177 7178
      goto err;
  }
unknown's avatar
unknown committed
7179 7180 7181 7182 7183
  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
7184
  error= FALSE;
7185 7186 7187

err:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
7188
}
unknown's avatar
unknown committed
7189 7190


unknown's avatar
unknown committed
7191 7192
/**
  negate given expression.
unknown's avatar
unknown committed
7193

unknown's avatar
unknown committed
7194 7195
  @param thd  thread handler
  @param expr expression for negation
unknown's avatar
unknown committed
7196

unknown's avatar
unknown committed
7197
  @return
unknown's avatar
unknown committed
7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222
    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);
}
7223

unknown's avatar
unknown committed
7224 7225 7226
/**
  Set the specified definer to the default value, which is the
  current user in the thread.
7227
 
unknown's avatar
unknown committed
7228 7229
  @param[in]  thd       thread handler
  @param[out] definer   definer
7230 7231
*/
 
7232
void get_default_definer(THD *thd, LEX_USER *definer)
7233 7234 7235 7236 7237 7238 7239 7240 7241 7242
{
  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);
}

7243

unknown's avatar
unknown committed
7244
/**
7245
  Create default definer for the specified THD.
7246

unknown's avatar
unknown committed
7247
  @param[in] thd         thread handler
7248

unknown's avatar
unknown committed
7249 7250
  @return
    - On success, return a valid pointer to the created and initialized
7251
    LEX_USER, which contains definer information.
unknown's avatar
unknown committed
7252
    - On error, return 0.
7253 7254 7255 7256 7257 7258 7259 7260 7261
*/

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

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

7262
  get_default_definer(thd, definer);
7263 7264 7265 7266 7267

  return definer;
}


unknown's avatar
unknown committed
7268
/**
7269
  Create definer with the given user and host names.
7270

unknown's avatar
unknown committed
7271 7272 7273
  @param[in] thd          thread handler
  @param[in] user_name    user name
  @param[in] host_name    host name
7274

unknown's avatar
unknown committed
7275 7276
  @return
    - On success, return a valid pointer to the created and initialized
7277
    LEX_USER, which contains definer information.
unknown's avatar
unknown committed
7278
    - On error, return 0.
7279 7280
*/

7281
LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
7282
{
7283 7284 7285 7286
  LEX_USER *definer;

  /* Create and initialize. */

unknown's avatar
unknown committed
7287
  if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
7288 7289 7290 7291 7292 7293
    return 0;

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

  return definer;
7294
}
7295 7296


unknown's avatar
unknown committed
7297
/**
7298 7299
  Retuns information about user or current user.

unknown's avatar
unknown committed
7300 7301
  @param[in] thd          thread handler
  @param[in] user         user
7302

unknown's avatar
unknown committed
7303 7304
  @return
    - On success, return a valid pointer to initialized
7305
    LEX_USER, which contains user information.
unknown's avatar
unknown committed
7306
    - On error, return 0.
7307 7308 7309 7310 7311
*/

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

7314 7315
  return user;
}
7316 7317


unknown's avatar
unknown committed
7318
/**
7319
  Check that byte length of a string does not exceed some limit.
7320

unknown's avatar
unknown committed
7321 7322 7323
  @param str         string to be checked
  @param err_msg     error message to be displayed if the string is too long
  @param max_length  max length
7324

unknown's avatar
unknown committed
7325
  @retval
7326
    FALSE   the passed string is not longer than max_length
unknown's avatar
unknown committed
7327
  @retval
7328
    TRUE    the passed string is longer than max_length
7329 7330 7331

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

7334 7335
bool check_string_byte_length(LEX_STRING *str, const char *err_msg,
                              uint max_byte_length)
7336
{
7337
  if (str->length <= max_byte_length)
unknown's avatar
unknown committed
7338
    return FALSE;
7339

7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371
  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
7372

7373 7374
  if (!no_error)
    my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_char_length);
7375 7376
  return TRUE;
}
7377 7378


7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421
/*
  Check if path does not contain mysql data home directory
  SYNOPSIS
    test_if_data_home_dir()
    dir                     directory
    conv_home_dir           converted data home directory
    home_dir_len            converted data home directory length

  RETURN VALUES
    0	ok
    1	error  
*/

bool test_if_data_home_dir(const char *dir)
{
  char path[FN_REFLEN], conv_path[FN_REFLEN];
  uint dir_len, home_dir_len= strlen(mysql_unpacked_real_data_home);
  DBUG_ENTER("test_if_data_home_dir");

  if (!dir)
    DBUG_RETURN(0);

  (void) fn_format(path, dir, "", "",
                   (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS));
  dir_len= unpack_dirname(conv_path, dir);

  if (home_dir_len < dir_len)
  {
    if (lower_case_file_system)
    {
      if (!my_strnncoll(character_set_filesystem,
                        (const uchar*) conv_path, home_dir_len,
                        (const uchar*) mysql_unpacked_real_data_home,
                        home_dir_len))
        DBUG_RETURN(1);
    }
    else if (!memcmp(conv_path, mysql_unpacked_real_data_home, home_dir_len))
      DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}


7422 7423 7424 7425 7426 7427 7428 7429 7430
extern int MYSQLparse(void *thd); // from sql_yacc.cc


/**
  This is a wrapper of MYSQLparse(). All the code should call parse_sql()
  instead of MYSQLparse().

  @param thd Thread context.
  @param lip Lexer context.
unknown's avatar
unknown committed
7431
  @param creation_ctx Object creation context.
7432 7433 7434 7435 7436 7437

  @return Error status.
    @retval FALSE on success.
    @retval TRUE on parsing error.
*/

unknown's avatar
unknown committed
7438 7439 7440
bool parse_sql(THD *thd,
               Lex_input_stream *lip,
               Object_creation_ctx *creation_ctx)
7441 7442 7443
{
  DBUG_ASSERT(thd->m_lip == NULL);

unknown's avatar
unknown committed
7444 7445 7446 7447 7448 7449 7450 7451 7452
  /* Backup creation context. */

  Object_creation_ctx *backup_ctx= NULL;

  if (creation_ctx)
    backup_ctx= creation_ctx->set_n_backup(thd);

  /* Set Lex_input_stream. */

7453 7454
  thd->m_lip= lip;

unknown's avatar
unknown committed
7455 7456
  /* Parse the query. */

7457 7458
  bool mysql_parse_status= MYSQLparse(thd) != 0;

7459
  /* Check that if MYSQLparse() failed, thd->is_error() is set. */
7460 7461

  DBUG_ASSERT(!mysql_parse_status ||
7462
              mysql_parse_status && thd->is_error());
unknown's avatar
unknown committed
7463 7464

  /* Reset Lex_input_stream. */
7465 7466 7467

  thd->m_lip= NULL;

unknown's avatar
unknown committed
7468 7469 7470 7471 7472 7473 7474
  /* Restore creation context. */

  if (creation_ctx)
    creation_ctx->restore_env(thd, backup_ctx);

  /* That's it. */

7475
  return mysql_parse_status || thd->is_fatal_error;
7476
}
7477 7478 7479 7480

/**
  @} (end of group Runtime_Environment)
*/