sql_parse.cc 227 KB
Newer Older
1
/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
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
const char *xa_state_names[]={
86
  "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED", "ROLLBACK ONLY"
unknown's avatar
unknown committed
87 88
};

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
/**
  Mark a XA transaction as rollback-only if the RM unilaterally
  rolled back the transaction branch.

  @note If a rollback was requested by the RM, this function sets
        the appropriate rollback error code and transits the state
        to XA_ROLLBACK_ONLY.

  @return TRUE if transaction was rolled back or if the transaction
          state is XA_ROLLBACK_ONLY. FALSE otherwise.
*/
static bool xa_trans_rolled_back(XID_STATE *xid_state)
{
  if (xid_state->rm_error)
  {
    switch (xid_state->rm_error) {
    case ER_LOCK_WAIT_TIMEOUT:
      my_error(ER_XA_RBTIMEOUT, MYF(0));
      break;
    case ER_LOCK_DEADLOCK:
      my_error(ER_XA_RBDEADLOCK, MYF(0));
      break;
    default:
      my_error(ER_XA_RBROLLBACK, MYF(0));
    }
    xid_state->xa_state= XA_ROLLBACK_ONLY;
  }

  return (xid_state->xa_state == XA_ROLLBACK_ONLY);
}

/**
  Rollback work done on behalf of at ransaction branch.
*/
static bool xa_trans_rollback(THD *thd)
{
  bool status= test(ha_rollback(thd));

  thd->options&= ~(ulong) OPTION_BEGIN;
  thd->transaction.all.modified_non_trans_table= FALSE;
  thd->server_status&= ~SERVER_STATUS_IN_TRANS;
  xid_cache_delete(&thd->transaction.xid_state);
  thd->transaction.xid_state.xa_state= XA_NOTR;
  thd->transaction.xid_state.rm_error= 0;

  return status;
}

unknown's avatar
unknown committed
137 138 139 140 141
static void unlock_locked_tables(THD *thd)
{
  if (thd->locked_tables)
  {
    thd->lock=thd->locked_tables;
142
    thd->locked_tables=0;			// Will be automatically closed
unknown's avatar
unknown committed
143 144 145 146
    close_thread_tables(thd);			// Free tables
  }
}

147

148
bool end_active_trans(THD *thd)
149
{
unknown's avatar
unknown committed
150
  int error=0;
151
  DBUG_ENTER("end_active_trans");
152
  if (unlikely(thd->in_sub_stmt))
153 154 155 156
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    DBUG_RETURN(1);
  }
157 158 159 160 161 162
  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
163
  if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
unknown's avatar
unknown committed
164
		      OPTION_TABLE_LOCK))
165
  {
166
    DBUG_PRINT("info",("options: 0x%llx", thd->options));
167 168 169
    /* Safety if one did "drop table" on locked tables */
    if (!thd->locked_tables)
      thd->options&= ~OPTION_TABLE_LOCK;
170
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
171
    if (ha_commit(thd))
unknown's avatar
unknown committed
172
      error=1;
173
  }
174
  thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
unknown's avatar
unknown committed
175
  thd->transaction.all.modified_non_trans_table= FALSE;
176
  DBUG_RETURN(error);
177 178
}

179

unknown's avatar
unknown committed
180
bool begin_trans(THD *thd)
unknown's avatar
unknown committed
181 182
{
  int error=0;
183
  if (unlikely(thd->in_sub_stmt))
184 185 186 187
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    return 1;
  }
unknown's avatar
unknown committed
188 189 190 191 192 193 194 195 196 197
  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
  {
198
    LEX *lex= thd->lex;
199
    thd->options|= OPTION_BEGIN;
unknown's avatar
unknown committed
200 201
    thd->server_status|= SERVER_STATUS_IN_TRANS;
    if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
unknown's avatar
unknown committed
202
      error= ha_start_consistent_snapshot(thd);
unknown's avatar
unknown committed
203 204 205
  }
  return error;
}
206

unknown's avatar
unknown committed
207
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
208 209
/**
  Returns true if all tables should be ignored.
210
*/
211 212
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
{
unknown's avatar
unknown committed
213 214
  return rpl_filter->is_on() && tables && !thd->spcont &&
         !rpl_filter->tables_ok(thd->db, tables);
215
}
unknown's avatar
unknown committed
216
#endif
217 218


219 220 221 222 223 224 225 226 227 228 229 230
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;
}

231

unknown's avatar
unknown committed
232 233 234 235
/**
  Mark all commands that somehow changes a table.

  This is used to check number of updates / hour.
unknown's avatar
unknown committed
236 237 238

  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
239

240
  See COMMAND_FLAG_xxx for different type of commands
unknown's avatar
unknown committed
241 242
     2  - query that returns meaningful ROW_COUNT() -
          a number of modified rows
243 244
*/

245
uint sql_command_flags[SQLCOM_END+1];
246 247 248

void init_update_queries(void)
{
249
  bzero((uchar*) &sql_command_flags, sizeof(sql_command_flags));
250

251
  sql_command_flags[SQLCOM_CREATE_TABLE]=   CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
252
  sql_command_flags[SQLCOM_CREATE_INDEX]=   CF_CHANGES_DATA;
253 254
  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;
255
  sql_command_flags[SQLCOM_DROP_TABLE]=     CF_CHANGES_DATA;
256
  sql_command_flags[SQLCOM_LOAD]=           CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
257 258 259 260 261 262
  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;
263
  sql_command_flags[SQLCOM_CREATE_VIEW]=    CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
264 265 266
  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;
267
  sql_command_flags[SQLCOM_DROP_EVENT]=     CF_CHANGES_DATA;
268

unknown's avatar
unknown committed
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
  sql_command_flags[SQLCOM_UPDATE]=	    CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
                                            CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_UPDATE_MULTI]=   CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
                                            CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_INSERT]=	    CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
                                            CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_INSERT_SELECT]=  CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
                                            CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_DELETE]=         CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
                                            CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_DELETE_MULTI]=   CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
                                            CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_REPLACE]=        CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
                                            CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
                                            CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_SELECT]=         CF_REEXECUTION_FRAGILE;
286 287 288 289 290 291 292 293 294
  sql_command_flags[SQLCOM_SET_OPTION]=     CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_DO]=             CF_REEXECUTION_FRAGILE;

  sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_SHOW_STATUS]=      CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_SHOW_DATABASES]=   CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_SHOW_TRIGGERS]=    CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_SHOW_EVENTS]=      CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_SHOW_OPEN_TABLES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
295
  sql_command_flags[SQLCOM_SHOW_PLUGINS]=     CF_STATUS_COMMAND;
296 297 298 299 300
  sql_command_flags[SQLCOM_SHOW_FIELDS]=      CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_SHOW_KEYS]=        CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_SHOW_VARIABLES]=   CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_SHOW_CHARSETS]=    CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
  sql_command_flags[SQLCOM_SHOW_COLLATIONS]=  CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
  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;
324
  sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]=  CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
325 326 327
  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;
328 329
  sql_command_flags[SQLCOM_SHOW_PROFILES]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND;
330 331

   sql_command_flags[SQLCOM_SHOW_TABLES]=       (CF_STATUS_COMMAND |
332 333
                                                 CF_SHOW_TABLE_COMMAND |
                                                 CF_REEXECUTION_FRAGILE);
334
  sql_command_flags[SQLCOM_SHOW_TABLE_STATUS]= (CF_STATUS_COMMAND |
335 336
                                                CF_SHOW_TABLE_COMMAND |
                                                CF_REEXECUTION_FRAGILE);
337 338 339 340 341 342 343

  /*
    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.
  */
344
  sql_command_flags[SQLCOM_CALL]= 		CF_HAS_ROW_COUNT | CF_REEXECUTION_FRAGILE;
345
  sql_command_flags[SQLCOM_EXECUTE]= 		CF_HAS_ROW_COUNT;
346 347 348 349 350 351 352 353

  /*
    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;
354 355
}

356

unknown's avatar
unknown committed
357 358
bool is_update_query(enum enum_sql_command command)
{
unknown's avatar
unknown committed
359
  DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
360
  return (sql_command_flags[command] & CF_CHANGES_DATA) != 0;
unknown's avatar
unknown committed
361
}
362

363 364 365 366 367 368 369 370 371 372
/**
  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;
}
373

374 375
void execute_init_command(THD *thd, sys_var_str *init_command_var,
			  rw_lock_t *var_mutex)
unknown's avatar
unknown committed
376 377 378 379
{
  Vio* save_vio;
  ulong save_client_capabilities;

380 381 382 383 384 385
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
  thd->profiling.start_new_query();
  thd->profiling.set_query_source(init_command_var->value,
                                  init_command_var->value_length);
#endif

386
  thd_proc_info(thd, "Execution of init_command");
387 388 389 390 391 392
  /*
    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
393 394
  save_client_capabilities= thd->client_capabilities;
  thd->client_capabilities|= CLIENT_MULTI_QUERIES;
395 396 397 398
  /*
    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
399 400
  save_vio= thd->net.vio;
  thd->net.vio= 0;
401 402 403
  dispatch_command(COM_QUERY, thd,
                   init_command_var->value,
                   init_command_var->value_length);
404
  rw_unlock(var_mutex);
unknown's avatar
unknown committed
405 406
  thd->client_capabilities= save_client_capabilities;
  thd->net.vio= save_vio;
407 408 409 410

#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
  thd->profiling.finish_current_query();
#endif
unknown's avatar
unknown committed
411 412 413
}


unknown's avatar
unknown committed
414
/**
415
  Execute commands from bootstrap_file.
unknown's avatar
unknown committed
416 417

  Used when creating the initial grant tables.
418
*/
unknown's avatar
unknown committed
419

420
pthread_handler_t handle_bootstrap(void *arg)
unknown's avatar
unknown committed
421
{
422 423 424
  THD *thd=(THD*) arg;
  FILE *file=bootstrap_file;
  char *buff;
425
  const char* found_semicolon= NULL;
unknown's avatar
unknown committed
426

427
  /* The following must be called before DBUG_ENTER */
428
  thd->thread_stack= (char*) &thd;
429
  if (my_thread_init() || thd->store_globals())
unknown's avatar
unknown committed
430
  {
unknown's avatar
unknown committed
431
#ifndef EMBEDDED_LIBRARY
432
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
unknown's avatar
unknown committed
433
#endif
434
    thd->fatal_error();
435
    goto end;
unknown's avatar
unknown committed
436
  }
437 438
  DBUG_ENTER("handle_bootstrap");

unknown's avatar
unknown committed
439
#ifndef EMBEDDED_LIBRARY
440 441
  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
442
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
443

444
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
445 446
    thd->options |= OPTION_BIG_SELECTS;

447
  thd_proc_info(thd, 0);
unknown's avatar
unknown committed
448
  thd->version=refresh_version;
449 450
  thd->security_ctx->priv_user=
    thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
unknown's avatar
unknown committed
451
  thd->security_ctx->priv_host[0]=0;
452 453 454 455 456 457
  /*
    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
458

459
  buff= (char*) thd->net.buff;
460
  thd->init_for_queries();
unknown's avatar
unknown committed
461 462
  while (fgets(buff, thd->net.max_packet, file))
  {
463 464 465 466 467 468 469 470 471 472 473
    /* 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))
      {
474 475
        net_end_statement(thd);
        bootstrap_error= 1;
476 477 478 479 480 481 482
        break;
      }
      buff= (char*) thd->net.buff;
      fgets(buff + length, thd->net.max_packet - length, file);
      length+= (ulong) strlen(buff + length);
      /* purecov: end */
    }
483
    if (bootstrap_error)
484
      break;                                    /* purecov: inspected */
unknown's avatar
unknown committed
485

unknown's avatar
unknown committed
486
    while (length && (my_isspace(thd->charset(), buff[length-1]) ||
487
                      buff[length-1] == ';'))
unknown's avatar
unknown committed
488 489
      length--;
    buff[length]=0;
unknown's avatar
unknown committed
490 491 492 493 494

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

495
    thd->query_length=length;
496 497 498
    thd->query= (char*) thd->memdup_w_gap(buff, length+1, 
                                          thd->db_length+1+
                                          QUERY_CACHE_FLAGS_SIZE);
unknown's avatar
unknown committed
499
    thd->query[length] = '\0';
500
    DBUG_PRINT("query",("%-.4096s",thd->query));
501
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
502
    thd->profiling.start_new_query();
503 504 505
    thd->profiling.set_query_source(thd->query, length);
#endif

506 507 508 509
    /*
      We don't need to obtain LOCK_thread_count here because in bootstrap
      mode we have only one thread.
    */
510
    thd->query_id=next_query_id();
511
    thd->set_time();
512
    mysql_parse(thd, thd->query, length, & found_semicolon);
unknown's avatar
unknown committed
513
    close_thread_tables(thd);			// Free tables
514

515 516
    bootstrap_error= thd->is_error();
    net_end_statement(thd);
517

518 519 520 521
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
    thd->profiling.finish_current_query();
#endif

522
    if (bootstrap_error)
523 524
      break;

unknown's avatar
unknown committed
525
    free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
526
#ifdef USING_TRANSACTIONS
527
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
528
#endif
unknown's avatar
unknown committed
529
  }
530 531

end:
532 533 534 535
  net_end(&thd->net);
  thd->cleanup();
  delete thd;

unknown's avatar
unknown committed
536
#ifndef EMBEDDED_LIBRARY
537 538 539
  (void) pthread_mutex_lock(&LOCK_thread_count);
  thread_count--;
  (void) pthread_mutex_unlock(&LOCK_thread_count);
540
  (void) pthread_cond_broadcast(&COND_thread_count);
541 542
  my_thread_end();
  pthread_exit(0);
unknown's avatar
unknown committed
543
#endif
544
  DBUG_RETURN(0);
unknown's avatar
unknown committed
545 546 547
}


548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
/**
  @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
565
#ifndef NO_EMBEDDED_ACCESS_CHECKS
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
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,
582
                              table_list, UINT_MAX, FALSE);
583 584 585
  }
  return error;
}
unknown's avatar
unknown committed
586
#endif
587

unknown's avatar
unknown committed
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
/* 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() */
603 604 605

void cleanup_items(Item *item)
{
unknown's avatar
unknown committed
606
  DBUG_ENTER("cleanup_items");  
607 608
  for (; item ; item=item->next)
    item->cleanup();
unknown's avatar
unknown committed
609
  DBUG_VOID_RETURN;
610 611
}

unknown's avatar
unknown committed
612 613
/**
  Handle COM_TABLE_DUMP command.
unknown's avatar
unknown committed
614

unknown's avatar
unknown committed
615 616 617 618
  @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
619

unknown's avatar
unknown committed
620
  @note
unknown's avatar
unknown committed
621 622
    This function is written to handle one specific command only.

unknown's avatar
unknown committed
623
  @retval
unknown's avatar
unknown committed
624
    0               success
unknown's avatar
unknown committed
625
  @retval
unknown's avatar
unknown committed
626 627 628 629
    1               error, the error message is set in THD
*/

static
630
int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name)
unknown's avatar
unknown committed
631 632 633 634 635
{
  TABLE* table;
  TABLE_LIST* table_list;
  int error = 0;
  DBUG_ENTER("mysql_table_dump");
636 637 638 639 640
  if (db->length == 0)
  {
    db->str= thd->db;            /* purecov: inspected */
    db->length= thd->db_length;  /* purecov: inspected */
  }
641
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
642
    DBUG_RETURN(1); // out of memory
643
  table_list->db= db->str;
644
  table_list->table_name= table_list->alias= tbl_name;
unknown's avatar
VIEW  
unknown committed
645 646
  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
647

648
  if (check_db_name(db))
649
  {
650 651
    /* purecov: begin inspected */
    my_error(ER_WRONG_DB_NAME ,MYF(0), db->str ? db->str : "NULL");
652
    goto err;
653
    /* purecov: end */
654
  }
655
  if (lower_case_table_names)
656
    my_casedn_str(files_charset_info, tbl_name);
657

658
  if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT, 0)))
659 660
    DBUG_RETURN(1);

unknown's avatar
unknown committed
661
  if (check_one_table_access(thd, SELECT_ACL, table_list))
unknown's avatar
unknown committed
662 663
    goto err;
  thd->free_list = 0;
unknown's avatar
unknown committed
664
  thd->query_length=(uint) strlen(tbl_name);
unknown's avatar
unknown committed
665
  thd->query = tbl_name;
unknown's avatar
unknown committed
666
  if ((error = mysqld_dump_create_info(thd, table_list, -1)))
667
  {
668
    my_error(ER_GET_ERRNO, MYF(0), my_errno);
669 670
    goto err;
  }
unknown's avatar
unknown committed
671
  net_flush(&thd->net);
unknown's avatar
unknown committed
672
  if ((error= table->file->dump(thd,-1)))
673
    my_error(ER_GET_ERRNO, MYF(0), error);
unknown's avatar
unknown committed
674

unknown's avatar
unknown committed
675
err:
unknown's avatar
unknown committed
676
  DBUG_RETURN(error);
unknown's avatar
unknown committed
677 678
}

unknown's avatar
unknown committed
679 680
/**
  Ends the current transaction and (maybe) begin the next.
unknown's avatar
unknown committed
681

unknown's avatar
unknown committed
682 683
  @param thd            Current thread
  @param completion     Completion type
unknown's avatar
unknown committed
684

unknown's avatar
unknown committed
685 686
  @retval
    0   OK
unknown's avatar
unknown committed
687 688
*/

689
int end_trans(THD *thd, enum enum_mysql_completiontype completion)
unknown's avatar
unknown committed
690 691 692
{
  bool do_release= 0;
  int res= 0;
693
  DBUG_ENTER("end_trans");
unknown's avatar
unknown committed
694

695
  if (unlikely(thd->in_sub_stmt))
696 697 698 699
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    DBUG_RETURN(1);
  }
700 701 702 703 704 705
  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
706 707 708 709 710 711 712 713
  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;
714
    res= ha_commit(thd);
715
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
unknown's avatar
unknown committed
716
    thd->transaction.all.modified_non_trans_table= FALSE;
unknown's avatar
unknown committed
717 718
    break;
  case COMMIT_RELEASE:
unknown's avatar
unknown committed
719
    do_release= 1; /* fall through */
unknown's avatar
unknown committed
720 721 722 723 724 725
  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
726
    do_release= 1; /* fall through */
unknown's avatar
unknown committed
727 728 729 730
  case ROLLBACK:
  case ROLLBACK_AND_CHAIN:
  {
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
unknown's avatar
unknown committed
731
    if (ha_rollback(thd))
unknown's avatar
unknown committed
732
      res= -1;
733
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
unknown's avatar
unknown committed
734
    thd->transaction.all.modified_non_trans_table= FALSE;
unknown's avatar
unknown committed
735 736 737 738 739 740 741 742 743
    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
744

unknown's avatar
unknown committed
745 746 747
  if (res < 0)
    my_error(thd->killed_errno(), MYF(0));
  else if ((res == 0) && do_release)
unknown's avatar
unknown committed
748 749
    thd->killed= THD::KILL_CONNECTION;

unknown's avatar
unknown committed
750 751
  DBUG_RETURN(res);
}
unknown's avatar
unknown committed
752

753
#ifndef EMBEDDED_LIBRARY
754

unknown's avatar
unknown committed
755
/**
unknown's avatar
unknown committed
756
  Read one command from connection and execute it (query or simple command).
757
  This function is called in loop from thread function.
758 759 760

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

unknown's avatar
unknown committed
761
  @retval
762
    0  success
unknown's avatar
unknown committed
763
  @retval
764 765 766
    1  request of thread shutdown (see dispatch_command() description)
*/

unknown's avatar
unknown committed
767 768
bool do_command(THD *thd)
{
769
  bool return_value;
unknown's avatar
unknown committed
770
  char *packet= 0;
unknown's avatar
unknown committed
771
  ulong packet_length;
unknown's avatar
unknown committed
772
  NET *net= &thd->net;
unknown's avatar
unknown committed
773 774 775
  enum enum_server_command command;
  DBUG_ENTER("do_command");

unknown's avatar
unknown committed
776 777 778 779
  /*
    indicator of uninitialized lex => normal flow of errors handling
    (see my_message_sql)
  */
780
  thd->lex->current_select= 0;
unknown's avatar
unknown committed
781

unknown's avatar
unknown committed
782 783 784 785 786 787
  /*
    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
  */
788
  my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
unknown's avatar
unknown committed
789

790 791 792 793
  /*
    XXX: this code is here only to clear possible errors of init_connect. 
    Consider moving to init_connect() instead.
  */
unknown's avatar
unknown committed
794
  thd->clear_error();				// Clear error message
795
  thd->main_da.reset_diagnostics_area();
unknown's avatar
unknown committed
796 797

  net_new_transaction(net);
798 799 800 801 802 803

  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
804
  {
805 806 807
    DBUG_PRINT("info",("Got error %d reading command from socket %s",
		       net->error,
		       vio_description(net->vio)));
808

809
    /* Check if we can continue without closing the connection */
810

811 812 813 814
    /* The error must be set. */
    DBUG_ASSERT(thd->is_error());
    net_end_statement(thd);

815
    if (net->error != 3)
816
    {
817
      return_value= TRUE;                       // We have to close it.
818 819
      goto out;
    }
820

821
    net->error= 0;
822 823
    return_value= FALSE;
    goto out;
unknown's avatar
unknown committed
824
  }
825 826 827 828 829 830 831 832 833 834 835

  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
836
  {
837 838 839
    /* Initialize with COM_SLEEP packet */
    packet[0]= (uchar) COM_SLEEP;
    packet_length= 1;
unknown's avatar
unknown committed
840
  }
841 842 843 844 845 846 847 848 849 850 851
  /* 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
852 853

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

856
  DBUG_ASSERT(packet_length);
857 858 859 860 861 862 863
  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);
864
}
865
#endif  /* EMBEDDED_LIBRARY */
866

867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897
/**
  @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);

898
  if (!(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA))
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
    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);
}
934

unknown's avatar
unknown committed
935 936
/**
  Perform one connection-level (COM_XXXX) command.
937

unknown's avatar
unknown committed
938 939 940 941 942 943 944 945
  @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
946 947 948
    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
949 950

  @retval
951
    0   ok
unknown's avatar
unknown committed
952
  @retval
953 954 955
    1   request of thread shutdown, i. e. if command is
        COM_QUIT/COM_SHUTDOWN
*/
956 957 958 959
bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
960
  bool error= 0;
961
  DBUG_ENTER("dispatch_command");
962
  DBUG_PRINT("info",("packet: '%*.s'; command: %d", packet_length, packet, command));
963

964
  thd->command=command;
unknown's avatar
unknown committed
965
  /*
966 967
    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
968
  */
969
  thd->enable_slow_log= TRUE;
970
  thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
unknown's avatar
unknown committed
971
  thd->set_time();
unknown's avatar
unknown committed
972
  VOID(pthread_mutex_lock(&LOCK_thread_count));
unknown's avatar
unknown committed
973
  thd->query_id= global_query_id;
974 975 976 977 978 979 980 981 982 983

  switch( command ) {
  /* Ignore these statements. */
  case COM_STATISTICS:
  case COM_PING:
    break;
  /* Only increase id on these statements but don't count them. */
  case COM_STMT_PREPARE: 
  case COM_STMT_CLOSE:
  case COM_STMT_RESET:
984
    next_query_id();
985 986 987 988 989 990 991
    break;
  /* Increase id and count all other statements. */
  default:
    statistic_increment(thd->status_var.questions, &LOCK_status);
    next_query_id();
  }

unknown's avatar
unknown committed
992
  thread_running++;
993
  /* TODO: set thd->lex->sql_command to SQLCOM_END here */
unknown's avatar
unknown committed
994
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
995

996 997 998 999 1000
  /**
    Clear the set of flags that are expected to be cleared at the
    beginning of each command.
  */
  thd->server_status&= ~SERVER_STATUS_CLEAR_SET;
1001
  switch (command) {
unknown's avatar
unknown committed
1002
  case COM_INIT_DB:
unknown's avatar
unknown committed
1003 1004
  {
    LEX_STRING tmp;
1005
    status_var_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB]);
unknown's avatar
unknown committed
1006
    thd->convert_string(&tmp, system_charset_info,
1007
			packet, packet_length, thd->charset());
unknown's avatar
unknown committed
1008
    if (!mysql_change_db(thd, &tmp, FALSE))
1009
    {
1010
      general_log_write(thd, command, thd->db, thd->db_length);
1011
      my_ok(thd);
1012
    }
unknown's avatar
unknown committed
1013 1014
    break;
  }
unknown's avatar
unknown committed
1015
#ifdef HAVE_REPLICATION
1016 1017
  case COM_REGISTER_SLAVE:
  {
1018
    if (!register_slave(thd, (uchar*)packet, packet_length))
1019
      my_ok(thd);
1020 1021
    break;
  }
1022
#endif
unknown's avatar
unknown committed
1023
  case COM_TABLE_DUMP:
1024
  {
1025 1026
    char *tbl_name;
    LEX_STRING db;
1027
    /* Safe because there is always a trailing \0 at the end of the packet */
1028
    uint db_len= *(uchar*) packet;
1029
    if (db_len + 1 > packet_length || db_len > NAME_LEN)
unknown's avatar
unknown committed
1030
    {
unknown's avatar
unknown committed
1031
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
1032 1033
      break;
    }
1034
    /* Safe because there is always a trailing \0 at the end of the packet */
1035
    uint tbl_len= *(uchar*) (packet + db_len + 1);
1036
    if (db_len + tbl_len + 2 > packet_length || tbl_len > NAME_LEN)
unknown's avatar
unknown committed
1037
    {
unknown's avatar
unknown committed
1038
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
1039 1040
      break;
    }
1041

1042
    status_var_increment(thd->status_var.com_other);
1043
    thd->enable_slow_log= opt_log_slow_admin_statements;
1044
    db.str= (char*) thd->alloc(db_len + tbl_len + 2);
1045
    if (!db.str)
1046 1047 1048 1049
    {
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
      break;
    }
1050
    db.length= db_len;
1051
    tbl_name= strmake(db.str, packet + 1, db_len)+1;
1052
    strmake(tbl_name, packet + db_len + 2, tbl_len);
1053 1054
    if (mysql_table_dump(thd, &db, tbl_name) == 0)
      thd->main_da.disable_status();
1055 1056
    break;
  }
unknown's avatar
unknown committed
1057 1058
  case COM_CHANGE_USER:
  {
1059
    status_var_increment(thd->status_var.com_other);
1060 1061
    char *user= (char*) packet, *packet_end= packet + packet_length;
    /* Safe because there is always a trailing \0 at the end of the packet */
1062 1063
    char *passwd= strend(user)+1;

unknown's avatar
unknown committed
1064
    thd->change_user();
1065
    thd->clear_error();                         // if errors from rollback
unknown's avatar
unknown committed
1066

1067
    /*
unknown's avatar
unknown committed
1068 1069 1070
      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).
1071 1072 1073

      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
1074
    */
1075
    char db_buff[NAME_LEN+1];                 // buffer to store db in utf8
unknown's avatar
unknown committed
1076
    char *db= passwd;
1077
    char *save_db;
1078 1079 1080 1081 1082 1083 1084 1085 1086
    /*
      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;
    }
1087
    uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
1088
                      (uchar)(*passwd++) : strlen(passwd));
1089 1090
    uint dummy_errors, save_db_length, db_length;
    int res;
1091 1092 1093
    Security_context save_security_ctx= *thd->security_ctx;
    USER_CONN *save_user_connect;

unknown's avatar
unknown committed
1094
    db+= passwd_len + 1;
1095 1096 1097 1098 1099
    /*
      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)
1100
    {
unknown's avatar
unknown committed
1101
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1102 1103
      break;
    }
1104 1105
    db_length= strlen(db);

1106
    char *ptr= db + db_length + 1;
1107 1108
    uint cs_number= 0;

1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
    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);
    }
1119

1120
    /* Convert database name to utf8 */
1121
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
1122
                             system_charset_info, db, db_length,
1123
                             thd->charset(), &dummy_errors)]= 0;
1124
    db= db_buff;
unknown's avatar
unknown committed
1125

1126
    /* Save user and privileges */
1127 1128 1129
    save_db_length= thd->db_length;
    save_db= thd->db;
    save_user_connect= thd->user_connect;
1130 1131

    if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
1132
    {
1133
      thd->security_ctx->user= save_security_ctx.user;
unknown's avatar
unknown committed
1134
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
1135 1136
      break;
    }
unknown's avatar
unknown committed
1137

unknown's avatar
unknown committed
1138 1139
    /* Clear variables that are allocated */
    thd->user_connect= 0;
1140
    thd->security_ctx->priv_user= thd->security_ctx->user;
1141
    res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
unknown's avatar
unknown committed
1142

1143 1144
    if (res)
    {
1145 1146
      x_free(thd->security_ctx->user);
      *thd->security_ctx= save_security_ctx;
unknown's avatar
unknown committed
1147
      thd->user_connect= save_user_connect;
1148 1149 1150 1151 1152
      thd->db= save_db;
      thd->db_length= save_db_length;
    }
    else
    {
1153
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1154
      /* we've authenticated new user */
unknown's avatar
unknown committed
1155 1156
      if (save_user_connect)
	decrease_user_connections(save_user_connect);
1157
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
1158 1159
      x_free(save_db);
      x_free(save_security_ctx.user);
1160 1161 1162 1163 1164 1165

      if (cs_number)
      {
        thd_init_client_charset(thd, cs_number);
        thd->update_charset();
      }
1166
    }
unknown's avatar
unknown committed
1167 1168
    break;
  }
1169
  case COM_STMT_EXECUTE:
unknown's avatar
unknown committed
1170
  {
1171
    mysql_stmt_execute(thd, packet, packet_length);
unknown's avatar
unknown committed
1172 1173
    break;
  }
1174
  case COM_STMT_FETCH:
1175 1176 1177 1178
  {
    mysql_stmt_fetch(thd, packet, packet_length);
    break;
  }
1179
  case COM_STMT_SEND_LONG_DATA:
unknown's avatar
unknown committed
1180
  {
1181
    mysql_stmt_get_longdata(thd, packet, packet_length);
unknown's avatar
unknown committed
1182 1183
    break;
  }
1184
  case COM_STMT_PREPARE:
unknown's avatar
unknown committed
1185
  {
1186
    mysql_stmt_prepare(thd, packet, packet_length);
unknown's avatar
unknown committed
1187 1188
    break;
  }
1189
  case COM_STMT_CLOSE:
unknown's avatar
unknown committed
1190
  {
1191
    mysql_stmt_close(thd, packet);
unknown's avatar
unknown committed
1192 1193
    break;
  }
1194
  case COM_STMT_RESET:
1195 1196 1197 1198
  {
    mysql_stmt_reset(thd, packet);
    break;
  }
unknown's avatar
unknown committed
1199 1200
  case COM_QUERY:
  {
1201 1202
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
1203
    char *packet_end= thd->query + thd->query_length;
unknown's avatar
unknown committed
1204
    /* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */
1205
    const char* end_of_stmt= NULL;
1206

1207
    general_log_write(thd, command, thd->query, thd->query_length);
1208
    DBUG_PRINT("query",("%-.4096s",thd->query));
1209 1210 1211
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
    thd->profiling.set_query_source(thd->query, thd->query_length);
#endif
1212 1213 1214 1215

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

1216
    mysql_parse(thd, thd->query, thd->query_length, &end_of_stmt);
1217

1218
    while (!thd->killed && (end_of_stmt != NULL) && ! thd->is_error())
1219
    {
1220
      char *beginning_of_next_stmt= (char*) end_of_stmt;
1221 1222 1223

      net_end_statement(thd);
      query_cache_end_of_result(thd);
1224
      /*
1225 1226
        Multiple queries exits, execute them individually
      */
1227
      close_thread_tables(thd);
1228
      ulong length= (ulong)(packet_end - beginning_of_next_stmt);
1229

1230
      log_slow_statement(thd);
1231

1232
      /* Remove garbage at start of query */
1233
      while (length > 0 && my_isspace(thd->charset(), *beginning_of_next_stmt))
1234
      {
1235
        beginning_of_next_stmt++;
1236 1237
        length--;
      }
1238 1239 1240 1241 1242 1243 1244

#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
1245
      VOID(pthread_mutex_lock(&LOCK_thread_count));
1246
      thd->query_length= length;
1247
      thd->query= beginning_of_next_stmt;
1248 1249 1250 1251
      /*
        Count each statement from the client.
      */
      statistic_increment(thd->status_var.questions, &LOCK_status);
1252
      thd->query_id= next_query_id();
1253
      thd->set_time(); /* Reset the query start time. */
1254
      /* TODO: set thd->lex->sql_command to SQLCOM_END here */
1255
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
1256
      mysql_parse(thd, beginning_of_next_stmt, length, &end_of_stmt);
1257 1258
    }

unknown's avatar
unknown committed
1259 1260 1261 1262 1263
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1264
  case COM_FIELD_LIST:				// This isn't actually needed
unknown's avatar
unknown committed
1265
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1266 1267
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
unknown's avatar
unknown committed
1268 1269 1270
    break;
#else
  {
1271
    char *fields, *packet_end= packet + packet_length, *arg_end;
1272
    /* Locked closure of all tables */
unknown's avatar
unknown committed
1273
    TABLE_LIST table_list;
unknown's avatar
unknown committed
1274
    LEX_STRING conv_name;
unknown's avatar
unknown committed
1275

unknown's avatar
unknown committed
1276
    /* used as fields initializator */
1277
    lex_start(thd);
1278

1279
    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]);
unknown's avatar
unknown committed
1280
    bzero((char*) &table_list,sizeof(table_list));
1281
    if (thd->copy_db_to(&table_list.db, &table_list.db_length))
unknown's avatar
unknown committed
1282
      break;
1283 1284 1285 1286
    /*
      We have name + wildcard in packet, separated by endzero
    */
    arg_end= strend(packet);
unknown's avatar
unknown committed
1287
    thd->convert_string(&conv_name, system_charset_info,
1288
			packet, (uint) (arg_end - packet), thd->charset());
1289
    table_list.alias= table_list.table_name= conv_name.str;
1290
    packet= arg_end + 1;
1291 1292

    if (!my_strcasecmp(system_charset_info, table_list.db,
1293
                       INFORMATION_SCHEMA_NAME.str))
1294 1295 1296 1297 1298 1299
    {
      ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
      if (schema_table)
        table_list.schema_table= schema_table;
    }

1300
    thd->query_length= (uint) (packet_end - packet); // Don't count end \0
1301
    if (!(thd->query=fields= (char*) thd->memdup(packet,thd->query_length+1)))
unknown's avatar
unknown committed
1302
      break;
unknown's avatar
unknown committed
1303
    general_log_print(thd, command, "%s %s", table_list.table_name, fields);
1304
    if (lower_case_table_names)
1305
      my_casedn_str(files_charset_info, table_list.table_name);
unknown's avatar
unknown committed
1306

unknown's avatar
unknown committed
1307
    if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
1308
		     0, 0, test(table_list.schema_table)))
unknown's avatar
unknown committed
1309
      break;
1310
    if (check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
1311
      break;
1312 1313
    /* init structures for VIEW processing */
    table_list.select_lex= &(thd->lex->select_lex);
1314 1315 1316 1317

    lex_start(thd);
    mysql_reset_thd_for_next_command(thd);

1318
    thd->lex->
1319 1320
      select_lex.table_list.link_in_list((uchar*) &table_list,
                                         (uchar**) &table_list.next_local);
unknown's avatar
unknown committed
1321
    thd->lex->add_to_query_tables(&table_list);
1322

1323 1324
    /* switch on VIEW optimisation: do not fill temporary tables */
    thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
unknown's avatar
unknown committed
1325
    mysqld_list_fields(thd,&table_list,fields);
1326
    thd->lex->unit.cleanup();
1327
    thd->cleanup_after_query();
unknown's avatar
unknown committed
1328 1329 1330 1331
    break;
  }
#endif
  case COM_QUIT:
1332
    /* We don't calculate statistics for this command */
unknown's avatar
unknown committed
1333
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1334
    net->error=0;				// Don't give 'abort' message
1335
    thd->main_da.disable_status();              // Don't send anything back
unknown's avatar
unknown committed
1336 1337 1338
    error=TRUE;					// End server
    break;

1339
#ifdef REMOVED
unknown's avatar
unknown committed
1340
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1341
    {
1342
      LEX_STRING db, alias;
1343
      HA_CREATE_INFO create_info;
unknown's avatar
unknown committed
1344

1345
      status_var_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB]);
1346
      if (thd->make_lex_string(&db, packet, packet_length, FALSE) ||
1347
          thd->make_lex_string(&alias, db.str, db.length, FALSE) ||
1348
          check_db_name(&db))
1349
      {
1350
	my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
1351 1352
	break;
      }
1353 1354
      if (check_access(thd, CREATE_ACL, db.str , 0, 1, 0,
                       is_schema_db(db.str)))
unknown's avatar
unknown committed
1355
	break;
unknown's avatar
unknown committed
1356
      general_log_print(thd, command, packet);
1357
      bzero(&create_info, sizeof(create_info));
1358
      mysql_create_db(thd, (lower_case_table_names == 2 ? alias.str : db.str),
1359
                      &create_info, 0);
unknown's avatar
unknown committed
1360 1361
      break;
    }
unknown's avatar
unknown committed
1362
  case COM_DROP_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1363
    {
1364
      status_var_increment(thd->status_var.com_stat[SQLCOM_DROP_DB]);
1365 1366
      LEX_STRING db;

1367
      if (thd->make_lex_string(&db, packet, packet_length, FALSE) ||
1368
          check_db_name(&db))
1369
      {
1370
	my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
1371 1372
	break;
      }
1373
      if (check_access(thd, DROP_ACL, db.str, 0, 1, 0, is_schema_db(db.str)))
1374
	break;
unknown's avatar
unknown committed
1375 1376
      if (thd->locked_tables || thd->active_transaction())
      {
unknown's avatar
unknown committed
1377 1378
	my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                   ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
unknown's avatar
unknown committed
1379
	break;
unknown's avatar
unknown committed
1380
      }
1381
      general_log_write(thd, command, db.str, db.length);
1382
      mysql_rm_db(thd, db.str, 0, 0);
unknown's avatar
unknown committed
1383 1384
      break;
    }
1385
#endif
1386
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1387 1388
  case COM_BINLOG_DUMP:
    {
unknown's avatar
unknown committed
1389 1390 1391 1392
      ulong pos;
      ushort flags;
      uint32 slave_server_id;

1393
      status_var_increment(thd->status_var.com_other);
1394
      thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
unknown committed
1395
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1396
	break;
unknown's avatar
unknown committed
1397

1398
      /* TODO: The following has to be changed to an 8 byte integer */
1399 1400
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
1401
      thd->server_id=0; /* avoid suicide */
unknown's avatar
unknown committed
1402
      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
unknown's avatar
unknown committed
1403
	kill_zombie_dump_threads(slave_server_id);
1404
      thd->server_id = slave_server_id;
unknown's avatar
unknown committed
1405

unknown's avatar
unknown committed
1406
      general_log_print(thd, command, "Log: '%s'  Pos: %ld", packet+10,
unknown's avatar
unknown committed
1407
                      (long) pos);
1408
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1409
      unregister_slave(thd,1,1);
unknown's avatar
unknown committed
1410
      /*  fake COM_QUIT -- if we get here, the thread needs to terminate */
1411
      error = TRUE;
unknown's avatar
unknown committed
1412 1413
      break;
    }
1414
#endif
unknown's avatar
unknown committed
1415
  case COM_REFRESH:
unknown's avatar
unknown committed
1416 1417
  {
    bool not_used;
1418
    status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
unknown's avatar
unknown committed
1419 1420
    ulong options= (ulong) (uchar) packet[0];
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1421
      break;
unknown's avatar
unknown committed
1422
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1423
    if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
1424
      my_ok(thd);
unknown's avatar
unknown committed
1425 1426
    break;
  }
1427
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1428
  case COM_SHUTDOWN:
1429
  {
1430
    status_var_increment(thd->status_var.com_other);
unknown's avatar
unknown committed
1431
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1432
      break; /* purecov: inspected */
1433
    /*
1434
      If the client is < 4.1.3, it is going to send us no argument; then
1435
      packet_length is 0, packet[0] is the end 0 of the packet. Note that
1436 1437
      SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in
      packet[0].
1438
    */
1439 1440
    enum mysql_enum_shutdown_level level=
      (enum mysql_enum_shutdown_level) (uchar) packet[0];
1441 1442 1443 1444 1445 1446 1447
    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;
    }
1448
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
unknown's avatar
unknown committed
1449
    general_log_print(thd, command, NullS);
1450
    my_eof(thd);
unknown's avatar
unknown committed
1451 1452 1453 1454
    close_thread_tables(thd);			// Free before kill
    kill_mysql();
    error=TRUE;
    break;
1455
  }
1456
#endif
unknown's avatar
unknown committed
1457 1458
  case COM_STATISTICS:
  {
1459 1460 1461
    STATUS_VAR current_global_status_var;
    ulong uptime;
    uint length;
1462
    ulonglong queries_per_second1000;
1463 1464
    char buff[250];
    uint buff_len= sizeof(buff);
1465

1466
    general_log_print(thd, command, NullS);
1467
    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]);
1468
    calc_sum_of_all_status(&current_global_status_var);
1469 1470 1471 1472 1473
    if (!(uptime= (ulong) (thd->start_time - server_start_time)))
      queries_per_second1000= 0;
    else
      queries_per_second1000= thd->query_id * LL(1000) / uptime;

1474 1475 1476
    length= my_snprintf((char*) buff, buff_len - 1,
                        "Uptime: %lu  Threads: %d  Questions: %lu  "
                        "Slow queries: %lu  Opens: %lu  Flush tables: %lu  "
1477
                        "Open tables: %u  Queries per second avg: %u.%u",
1478 1479 1480 1481 1482 1483
                        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(),
1484 1485
                        (uint) (queries_per_second1000 / 1000),
                        (uint) (queries_per_second1000 % 1000));
1486 1487
#ifdef EMBEDDED_LIBRARY
    /* Store the buffer in permanent memory */
1488
    my_ok(thd, 0, 0, buff);
1489
#endif
unknown's avatar
unknown committed
1490
#ifdef SAFEMALLOC
1491
    if (sf_malloc_cur_memory)				// Using SAFEMALLOC
1492 1493 1494 1495 1496 1497 1498
    {
      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
1499 1500
#endif
#ifndef EMBEDDED_LIBRARY
1501
    VOID(my_net_write(net, (uchar*) buff, length));
1502 1503
    VOID(net_flush(net));
    thd->main_da.disable_status();
unknown's avatar
unknown committed
1504
#endif
unknown's avatar
unknown committed
1505 1506 1507
    break;
  }
  case COM_PING:
1508
    status_var_increment(thd->status_var.com_other);
1509
    my_ok(thd);				// Tell client we are alive
unknown's avatar
unknown committed
1510 1511
    break;
  case COM_PROCESS_INFO:
1512
    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]);
1513 1514
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd, PROCESS_ACL))
unknown's avatar
unknown committed
1515
      break;
unknown's avatar
unknown committed
1516
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1517
    mysqld_list_processes(thd,
1518 1519
			  thd->security_ctx->master_access & PROCESS_ACL ? 
			  NullS : thd->security_ctx->priv_user, 0);
unknown's avatar
unknown committed
1520 1521 1522
    break;
  case COM_PROCESS_KILL:
  {
1523
    status_var_increment(thd->status_var.com_stat[SQLCOM_KILL]);
1524
    ulong id=(ulong) uint4korr(packet);
1525
    sql_kill(thd,id,false);
unknown's avatar
unknown committed
1526 1527
    break;
  }
1528 1529
  case COM_SET_OPTION:
  {
1530
    status_var_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION]);
unknown's avatar
unknown committed
1531 1532 1533 1534
    uint opt_command= uint2korr(packet);

    switch (opt_command) {
    case (int) MYSQL_OPTION_MULTI_STATEMENTS_ON:
1535
      thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
1536
      my_eof(thd);
1537
      break;
unknown's avatar
unknown committed
1538
    case (int) MYSQL_OPTION_MULTI_STATEMENTS_OFF:
1539
      thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
1540
      my_eof(thd);
1541 1542
      break;
    default:
unknown's avatar
unknown committed
1543
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1544 1545 1546 1547
      break;
    }
    break;
  }
unknown's avatar
unknown committed
1548
  case COM_DEBUG:
1549
    status_var_increment(thd->status_var.com_other);
unknown's avatar
unknown committed
1550
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1551
      break;					/* purecov: inspected */
1552
    mysql_print_status();
unknown's avatar
unknown committed
1553
    general_log_print(thd, command, NullS);
1554
    my_eof(thd);
unknown's avatar
unknown committed
1555 1556 1557 1558 1559
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
1560
  case COM_END:
unknown's avatar
unknown committed
1561
  default:
unknown's avatar
unknown committed
1562
    my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
1563 1564
    break;
  }
1565

1566 1567 1568 1569 1570 1571
  /* If commit fails, we should be able to reset the OK status. */
  thd->main_da.can_overwrite_status= TRUE;
  ha_autocommit_or_rollback(thd, thd->is_error());
  thd->main_da.can_overwrite_status= FALSE;

  thd->transaction.stmt.reset();
1572

unknown's avatar
unknown committed
1573

unknown's avatar
unknown committed
1574
  /* report error issued during command execution */
1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587
  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
1588

1589 1590 1591 1592
  thd->proc_info= "closing tables";
  /* Free tables */
  close_thread_tables(thd);

1593
  log_slow_statement(thd);
1594

1595
  thd_proc_info(thd, "cleaning up");
1596
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
1597
  thd_proc_info(thd, 0);
1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608
  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);
}


1609
void log_slow_statement(THD *thd)
1610
{
unknown's avatar
unknown committed
1611
  DBUG_ENTER("log_slow_statement");
1612 1613 1614 1615 1616 1617 1618

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

1621 1622 1623 1624 1625
  /*
    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
1626
  {
1627
    ulonglong end_utime_of_query= thd->current_utime();
1628
    thd_proc_info(thd, "logging slow query");
1629

1630 1631 1632 1633
    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)) &&
1634 1635
          opt_log_queries_not_using_indexes &&
           !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) &&
1636
        thd->examined_row_count >= thd->variables.min_examined_row_limit)
1637
    {
1638
      thd_proc_info(thd, "logging slow query");
1639
      thd->status_var.long_query_count++;
1640
      slow_log_print(thd, thd->query, thd->query_length, end_utime_of_query);
1641
    }
unknown's avatar
unknown committed
1642
  }
unknown's avatar
unknown committed
1643
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
1644 1645
}

1646

unknown's avatar
unknown committed
1647
/**
unknown's avatar
unknown committed
1648 1649 1650 1651 1652 1653 1654
  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
1655 1656 1657 1658 1659 1660 1661
  @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
1662 1663 1664 1665
    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
1666
  @retval
unknown's avatar
unknown committed
1667
    0                 success
unknown's avatar
unknown committed
1668
  @retval
unknown's avatar
unknown committed
1669 1670 1671 1672
    1                 out of memory or SHOW commands are not allowed
                      in this version of the server.
*/

1673 1674 1675
int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
                         enum enum_schema_tables schema_table_idx)
{
1676
  SELECT_LEX *schema_select_lex= NULL;
1677
  DBUG_ENTER("prepare_schema_table");
1678

1679
  switch (schema_table_idx) {
1680 1681
  case SCH_SCHEMATA:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
unknown's avatar
unknown committed
1682 1683
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0));   /* purecov: inspected */
1684 1685 1686 1687
    DBUG_RETURN(1);
#else
    break;
#endif
1688

1689 1690 1691
  case SCH_TABLE_NAMES:
  case SCH_TABLES:
  case SCH_VIEWS:
1692
  case SCH_TRIGGERS:
unknown's avatar
unknown committed
1693
  case SCH_EVENTS:
1694
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1695 1696
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1697 1698 1699
    DBUG_RETURN(1);
#else
    {
1700
      LEX_STRING db;
1701
      size_t dummy;
unknown's avatar
unknown committed
1702
      if (lex->select_lex.db == NULL &&
1703
          lex->copy_db_to(&lex->select_lex.db, &dummy))
1704
      {
unknown's avatar
unknown committed
1705
        DBUG_RETURN(1);
1706
      }
1707 1708 1709
      schema_select_lex= new SELECT_LEX();
      db.str= schema_select_lex->db= lex->select_lex.db;
      schema_select_lex->table_list.first= NULL;
1710
      db.length= strlen(db.str);
unknown's avatar
unknown committed
1711

1712
      if (check_db_name(&db))
1713
      {
1714
        my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
1715 1716 1717 1718 1719 1720 1721
        DBUG_RETURN(1);
      }
      break;
    }
#endif
  case SCH_COLUMNS:
  case SCH_STATISTICS:
unknown's avatar
unknown committed
1722
  {
1723
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1724 1725
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1726 1727
    DBUG_RETURN(1);
#else
unknown's avatar
unknown committed
1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738
    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;
  }
1739
#endif
1740 1741 1742 1743 1744
  case SCH_PROFILES:
    /* 
      Mark this current profiling record to be discarded.  We don't
      wish to have SHOW commands show up in profiling.
    */
1745 1746
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
    thd->profiling.discard_current_query();
1747 1748
#endif
    break;
1749 1750 1751
  case SCH_OPEN_TABLES:
  case SCH_VARIABLES:
  case SCH_STATUS:
1752 1753
  case SCH_PROCEDURES:
  case SCH_CHARSETS:
unknown's avatar
unknown committed
1754
  case SCH_ENGINES:
1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772
  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
1773
  table_list->schema_select_lex= schema_select_lex;
1774
  table_list->schema_table_reformed= 1;
1775 1776 1777 1778
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
1779 1780 1781
/**
  Read query from packet and store in thd->query.
  Used in COM_QUERY and COM_STMT_PREPARE.
1782 1783

    Sets the following THD variables:
unknown's avatar
unknown committed
1784 1785
  - query
  - query_length
1786

unknown's avatar
unknown committed
1787
  @retval
unknown's avatar
unknown committed
1788
    FALSE ok
unknown's avatar
unknown committed
1789
  @retval
unknown's avatar
unknown committed
1790
    TRUE  error;  In this case thd->fatal_error is set
1791 1792
*/

1793
bool alloc_query(THD *thd, const char *packet, uint packet_length)
1794
{
1795
  /* Remove garbage at start and end of query */
1796
  while (packet_length > 0 && my_isspace(thd->charset(), packet[0]))
1797 1798 1799 1800
  {
    packet++;
    packet_length--;
  }
1801
  const char *pos= packet + packet_length;     // Point at end null
unknown's avatar
unknown committed
1802
  while (packet_length > 0 &&
unknown's avatar
unknown committed
1803
	 (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
1804 1805 1806 1807 1808
  {
    pos--;
    packet_length--;
  }
  /* We must allocate some extra memory for query cache */
unknown's avatar
unknown committed
1809
  thd->query_length= 0;                        // Extra safety: Avoid races
1810
  if (!(thd->query= (char*) thd->memdup_w_gap((uchar*) (packet),
1811
					      packet_length,
1812 1813
					      thd->db_length+ 1 +
					      QUERY_CACHE_FLAGS_SIZE)))
unknown's avatar
unknown committed
1814
    return TRUE;
1815 1816
  thd->query[packet_length]=0;
  thd->query_length= packet_length;
1817 1818 1819 1820

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

unknown's avatar
unknown committed
1822
  return FALSE;
1823 1824
}

1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837
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;
1838
  thd->variables.lc_time_names= &my_locale_en_US;
1839 1840 1841
  thd->one_shot_set= 0;
}

1842

1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888
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);

1889
    if (thd->slave_thread && lex->sphead)
1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927
      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
1928 1929
/**
  Execute command saved in thd and lex->sql_command.
1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940

    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
1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952
  @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
1953
    FALSE       OK
unknown's avatar
unknown committed
1954
  @retval
1955 1956
    TRUE        Error
*/
unknown's avatar
unknown committed
1957

1958
int
1959
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
1960
{
1961
  int res= FALSE;
1962
  bool need_start_waiting= FALSE; // have protection against global read lock
unknown's avatar
unknown committed
1963
  int  up_result= 0;
1964
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
1965
  /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
unknown's avatar
unknown committed
1966
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
1967
  /* first table of first SELECT_LEX */
unknown's avatar
unknown committed
1968
  TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
unknown's avatar
VIEW  
unknown committed
1969 1970 1971
  /* list of all tables in query */
  TABLE_LIST *all_tables;
  /* most outer SELECT_LEX_UNIT of query */
1972
  SELECT_LEX_UNIT *unit= &lex->unit;
1973 1974 1975 1976
#ifdef HAVE_REPLICATION
  /* have table map for update for multi-update statement (BUG#37051) */
  bool have_table_map_for_update= FALSE;
#endif
1977
  /* Saved variable value */
unknown's avatar
unknown committed
1978
  DBUG_ENTER("mysql_execute_command");
unknown's avatar
unknown committed
1979 1980 1981
#ifdef WITH_PARTITION_STORAGE_ENGINE
  thd->work_part_info= 0;
#endif
unknown's avatar
unknown committed
1982

unknown's avatar
VIEW  
unknown committed
1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998
  /*
    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();
1999
  /* should be assigned after making first tables same */
unknown's avatar
VIEW  
unknown committed
2000
  all_tables= lex->query_tables;
2001 2002 2003 2004
  /* 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
2005

2006 2007 2008 2009 2010
  /*
    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.
2011
    Don't reset warnings when executing a stored routine.
2012
  */
2013
  if ((all_tables || !lex->is_single_level_stmt()) && !thd->spcont)
unknown's avatar
unknown committed
2014
    mysql_reset_errors(thd, 0);
2015

unknown's avatar
SCRUM  
unknown committed
2016
#ifdef HAVE_REPLICATION
2017
  if (unlikely(thd->slave_thread))
2018
  {
2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
    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;
    }
2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083

    /*
      For fix of BUG#37051, the master stores the table map for update
      in the Query_log_event, and the value is assigned to
      thd->variables.table_map_for_update before executing the update
      query.

      If thd->variables.table_map_for_update is set, then we are
      replicating from a new master, we can use this value to apply
      filter rules without opening all the tables. However If
      thd->variables.table_map_for_update is not set, then we are
      replicating from an old master, so we just skip this and
      continue with the old method. And of course, the bug would still
      exist for old masters.
    */
    if (lex->sql_command == SQLCOM_UPDATE_MULTI &&
        thd->table_map_for_update)
    {
      have_table_map_for_update= TRUE;
      table_map table_map_for_update= thd->table_map_for_update;
      uint nr= 0;
      TABLE_LIST *table;
      for (table=all_tables; table; table=table->next_global, nr++)
      {
        if (table_map_for_update & ((table_map)1 << nr))
          table->updating= TRUE;
        else
          table->updating= FALSE;
      }

      if (all_tables_not_ok(thd, all_tables))
      {
        /* we warn the slave SQL thread */
        my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
        if (thd->one_shot_set)
          reset_one_shot_variables(thd);
        DBUG_RETURN(0);
      }
      
      for (table=all_tables; table; table=table->next_global)
        table->updating= TRUE;
    }
2084
    
unknown's avatar
unknown committed
2085
    /*
unknown's avatar
unknown committed
2086 2087
      Check if statment should be skipped because of slave filtering
      rules
2088 2089

      Exceptions are:
unknown's avatar
unknown committed
2090 2091
      - UPDATE MULTI: For this statement, we want to check the filtering
        rules later in the code
2092
      - SET: we always execute it (Not that many SET commands exists in
unknown's avatar
unknown committed
2093 2094
        the binary log anyway -- only 4.1 masters write SET statements,
	in 5.0 there are no SET statements in the binary log)
2095 2096
      - 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
2097
    */
unknown's avatar
unknown committed
2098 2099
    if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
	!(lex->sql_command == SQLCOM_SET_OPTION) &&
2100
	!(lex->sql_command == SQLCOM_DROP_TABLE &&
2101
          lex->drop_temporary && lex->drop_if_exists) &&
unknown's avatar
Merge  
unknown committed
2102
        all_tables_not_ok(thd, all_tables))
unknown's avatar
unknown committed
2103 2104
    {
      /* we warn the slave SQL thread */
unknown's avatar
unknown committed
2105
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122
      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);
      }
2123
      DBUG_RETURN(0);
unknown's avatar
unknown committed
2124
    }
2125
  }
2126
  else
2127
  {
2128
#endif /* HAVE_REPLICATION */
2129 2130 2131 2132
    /*
      When option readonly is set deny operations which change non-temporary
      tables. Except for the replication thread and the 'super' users.
    */
2133
    if (deny_updates_if_read_only_option(thd, all_tables))
2134 2135 2136 2137 2138 2139 2140
    {
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
      DBUG_RETURN(-1);
    }
#ifdef HAVE_REPLICATION
  } /* endif unlikely slave */
#endif
2141
  status_var_increment(thd->status_var.com_stat[lex->sql_command]);
2142

unknown's avatar
unknown committed
2143 2144
  DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE);
  
unknown's avatar
unknown committed
2145
  switch (lex->sql_command) {
2146

2147
  case SQLCOM_SHOW_EVENTS:
2148 2149 2150 2151
#ifndef HAVE_EVENT_SCHEDULER
    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "embedded server");
    break;
#endif
2152 2153
  case SQLCOM_SHOW_STATUS_PROC:
  case SQLCOM_SHOW_STATUS_FUNC:
2154 2155
    if (!(res= check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE)))
      res= execute_sqlcom_select(thd, all_tables);
2156 2157 2158 2159 2160
    break;
  case SQLCOM_SHOW_STATUS:
  {
    system_status_var old_status_var= thd->status_var;
    thd->initial_status_var= &old_status_var;
2161 2162
    if (!(res= check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE)))
      res= execute_sqlcom_select(thd, all_tables);
2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187
    /* 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:
2188
  case SQLCOM_SHOW_STORAGE_ENGINES:
2189
  case SQLCOM_SHOW_PROFILE:
unknown's avatar
unknown committed
2190
  case SQLCOM_SELECT:
2191
    thd->status_var.last_query_cost= 0.0;
unknown's avatar
VIEW  
unknown committed
2192
    if (all_tables)
unknown's avatar
unknown committed
2193
    {
2194 2195 2196
      res= check_table_access(thd,
                              lex->exchange ? SELECT_ACL | FILE_ACL :
                              SELECT_ACL,
2197
                              all_tables, UINT_MAX, FALSE);
unknown's avatar
unknown committed
2198 2199
    }
    else
unknown's avatar
VIEW  
unknown committed
2200
      res= check_access(thd,
2201 2202 2203 2204
                        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
2205
    break;
unknown's avatar
unknown committed
2206
  case SQLCOM_PREPARE:
2207
  {
2208
    mysql_sql_stmt_prepare(thd);
unknown's avatar
unknown committed
2209 2210 2211 2212
    break;
  }
  case SQLCOM_EXECUTE:
  {
2213
    mysql_sql_stmt_execute(thd);
unknown's avatar
unknown committed
2214 2215 2216 2217
    break;
  }
  case SQLCOM_DEALLOCATE_PREPARE:
  {
2218
    mysql_sql_stmt_close(thd);
unknown's avatar
unknown committed
2219 2220
    break;
  }
unknown's avatar
unknown committed
2221
  case SQLCOM_DO:
2222
    if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
2223
        open_and_lock_tables(thd, all_tables))
unknown's avatar
unknown committed
2224
      goto error;
unknown's avatar
unknown committed
2225 2226

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

2229
  case SQLCOM_EMPTY_QUERY:
2230
    my_ok(thd);
2231 2232
    break;

unknown's avatar
unknown committed
2233 2234 2235 2236
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

2237
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2238
  case SQLCOM_PURGE:
2239
  {
unknown's avatar
unknown committed
2240
    if (check_global_access(thd, SUPER_ACL))
2241
      goto error;
unknown's avatar
unknown committed
2242
    /* PURGE MASTER LOGS TO 'file' */
2243 2244 2245
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
2246 2247
  case SQLCOM_PURGE_BEFORE:
  {
2248 2249
    Item *it;

2250 2251
    if (check_global_access(thd, SUPER_ACL))
      goto error;
unknown's avatar
unknown committed
2252
    /* PURGE MASTER LOGS BEFORE 'data' */
2253
    it= (Item *)lex->value_list.head();
2254
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) ||
unknown's avatar
unknown committed
2255
        it->check_cols(1))
2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266
    {
      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());
2267 2268
    break;
  }
2269
#endif
unknown's avatar
unknown committed
2270 2271
  case SQLCOM_SHOW_WARNS:
  {
2272 2273
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
2274 2275 2276
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
unknown's avatar
unknown committed
2277 2278 2279 2280
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
2281 2282
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
2283 2284
    break;
  }
unknown's avatar
unknown committed
2285 2286
  case SQLCOM_SHOW_PROFILES:
  {
2287
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
2288
    thd->profiling.discard_current_query();
unknown's avatar
unknown committed
2289
    res= thd->profiling.show_profiles();
2290 2291 2292
    if (res)
      goto error;
#else
2293
    my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILES", "enable-profiling");
2294 2295
    goto error;
#endif
unknown's avatar
unknown committed
2296 2297
    break;
  }
unknown's avatar
unknown committed
2298 2299
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
2300
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2301
      goto error;
2302
    /* This query don't work now. See comment in repl_failsafe.cc */
unknown's avatar
unknown committed
2303
#ifndef WORKING_NEW_MASTER
unknown's avatar
unknown committed
2304 2305
    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
    goto error;
unknown's avatar
unknown committed
2306
#else
unknown's avatar
unknown committed
2307 2308
    res = show_new_master(thd);
    break;
unknown's avatar
unknown committed
2309
#endif
unknown's avatar
unknown committed
2310
  }
2311

unknown's avatar
unknown committed
2312
#ifdef HAVE_REPLICATION
2313 2314
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
2315
    if (check_global_access(thd, REPL_SLAVE_ACL))
2316 2317 2318 2319
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
2320 2321
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
2322
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2323
      goto error;
2324
    res = mysql_show_binlog_events(thd);
unknown's avatar
unknown committed
2325 2326
    break;
  }
2327 2328
#endif

unknown's avatar
unknown committed
2329
  case SQLCOM_BACKUP_TABLE:
2330
  {
unknown's avatar
VIEW  
unknown committed
2331
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2332
    if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
unknown's avatar
unknown committed
2333
	check_global_access(thd, FILE_ACL))
2334
      goto error; /* purecov: inspected */
2335
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2336
    res = mysql_backup_table(thd, first_table);
2337
    select_lex->table_list.first= (uchar*) first_table;
2338
    lex->query_tables=all_tables;
2339 2340
    break;
  }
unknown's avatar
unknown committed
2341
  case SQLCOM_RESTORE_TABLE:
2342
  {
unknown's avatar
VIEW  
unknown committed
2343
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2344
    if (check_table_access(thd, INSERT_ACL, all_tables, UINT_MAX, FALSE) ||
unknown's avatar
unknown committed
2345
	check_global_access(thd, FILE_ACL))
2346
      goto error; /* purecov: inspected */
2347
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2348
    res = mysql_restore_table(thd, first_table);
2349
    select_lex->table_list.first= (uchar*) first_table;
2350
    lex->query_tables=all_tables;
2351 2352
    break;
  }
unknown's avatar
unknown committed
2353 2354
  case SQLCOM_ASSIGN_TO_KEYCACHE:
  {
unknown's avatar
VIEW  
unknown committed
2355
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2356
    if (check_access(thd, INDEX_ACL, first_table->db,
2357 2358
                     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
unknown's avatar
unknown committed
2359
      goto error;
2360
    res= mysql_assign_to_keycache(thd, first_table, &lex->ident);
unknown's avatar
unknown committed
2361 2362
    break;
  }
unknown's avatar
unknown committed
2363 2364
  case SQLCOM_PRELOAD_KEYS:
  {
unknown's avatar
VIEW  
unknown committed
2365
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2366
    if (check_access(thd, INDEX_ACL, first_table->db,
2367 2368
                     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
2369
      goto error;
unknown's avatar
VIEW  
unknown committed
2370
    res = mysql_preload_keys(thd, first_table);
unknown's avatar
unknown committed
2371 2372
    break;
  }
unknown's avatar
unknown committed
2373
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2374
  case SQLCOM_CHANGE_MASTER:
2375
  {
unknown's avatar
unknown committed
2376
    if (check_global_access(thd, SUPER_ACL))
2377
      goto error;
2378
    pthread_mutex_lock(&LOCK_active_mi);
2379
    res = change_master(thd,active_mi);
2380
    pthread_mutex_unlock(&LOCK_active_mi);
2381 2382
    break;
  }
unknown's avatar
unknown committed
2383
  case SQLCOM_SHOW_SLAVE_STAT:
2384
  {
2385 2386
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2387
      goto error;
2388
    pthread_mutex_lock(&LOCK_active_mi);
2389 2390 2391 2392 2393 2394
    if (active_mi != NULL)
    {
      res = show_master_info(thd, active_mi);
    }
    else
    {
2395 2396
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                   WARN_NO_MASTER_INFO, ER(WARN_NO_MASTER_INFO));
2397
      my_ok(thd);
2398
    }
2399
    pthread_mutex_unlock(&LOCK_active_mi);
2400 2401
    break;
  }
unknown's avatar
unknown committed
2402
  case SQLCOM_SHOW_MASTER_STAT:
2403
  {
2404 2405
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2406 2407 2408 2409
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
2410

2411
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
2412
    if (check_global_access(thd, SUPER_ACL))
2413
      goto error;
2414
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2415
      goto error;
2416
    res = load_master_data(thd);
2417
    break;
unknown's avatar
unknown committed
2418
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
2419
  case SQLCOM_SHOW_ENGINE_STATUS:
unknown's avatar
unknown committed
2420
    {
2421
      if (check_global_access(thd, PROCESS_ACL))
unknown's avatar
unknown committed
2422 2423
        goto error;
      res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_STATUS);
unknown's avatar
unknown committed
2424 2425
      break;
    }
unknown's avatar
unknown committed
2426
  case SQLCOM_SHOW_ENGINE_MUTEX:
unknown's avatar
unknown committed
2427
    {
2428
      if (check_global_access(thd, PROCESS_ACL))
unknown's avatar
unknown committed
2429
        goto error;
unknown's avatar
unknown committed
2430
      res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
unknown's avatar
unknown committed
2431 2432
      break;
    }
unknown's avatar
unknown committed
2433
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2434
  case SQLCOM_LOAD_MASTER_TABLE:
2435
  {
unknown's avatar
VIEW  
unknown committed
2436
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2437 2438
    DBUG_ASSERT(first_table->db); /* Must be set in the parser */

unknown's avatar
VIEW  
unknown committed
2439
    if (check_access(thd, CREATE_ACL, first_table->db,
2440 2441
		     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
unknown's avatar
unknown committed
2442
      goto error;				/* purecov: inspected */
2443 2444 2445 2446
    /* Check that the first table has CREATE privilege */
    if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
      goto error;

2447
    pthread_mutex_lock(&LOCK_active_mi);
2448 2449 2450 2451
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
2452
    if (!fetch_master_table(thd, first_table->db, first_table->table_name,
2453
			    active_mi, 0, 0))
2454
    {
2455
      my_ok(thd);
2456
    }
2457
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2458
    break;
2459
  }
unknown's avatar
unknown committed
2460
#endif /* HAVE_REPLICATION */
2461

unknown's avatar
unknown committed
2462
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
2463
  {
2464
    /* If CREATE TABLE of non-temporary table, do implicit commit */
2465 2466 2467 2468 2469 2470 2471 2472
    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
    {
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
unknown's avatar
VIEW  
unknown committed
2473 2474 2475 2476 2477
    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;
2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498
    /*
      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
2499

unknown's avatar
VIEW  
unknown committed
2500
    if ((res= create_table_precheck(thd, select_tables, create_table)))
unknown's avatar
unknown committed
2501
      goto end_with_restore_list;
unknown's avatar
unknown committed
2502

2503 2504 2505
    /* Might have been updated in create_table_precheck */
    create_info.alias= create_table->alias;

2506
#ifdef HAVE_READLINK
2507
    /* Fix names if symlinked tables */
2508
    if (append_file_to_dir(thd, &create_info.data_file_name,
2509
			   create_table->table_name) ||
2510
	append_file_to_dir(thd, &create_info.index_file_name,
2511
			   create_table->table_name))
unknown's avatar
unknown committed
2512
      goto end_with_restore_list;
2513
#endif
2514
    /*
2515
      If we are using SET CHARSET without DEFAULT, add an implicit
2516 2517
      DEFAULT to not confuse old users. (This may change).
    */
2518
    if ((create_info.used_fields &
2519 2520 2521
	 (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
	HA_CREATE_USED_CHARSET)
    {
2522 2523 2524 2525
      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;
2526
    }
2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539
    /*
      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.
    */
2540 2541
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
2542
    {
unknown's avatar
unknown committed
2543 2544
      res= 1;
      goto end_with_restore_list;
2545
    }
2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556
#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
2557
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
2558 2559
    {
      select_result *result;
2560

2561
      select_lex->options|= SELECT_NO_UNLOCK;
2562
      unit->set_limit(select_lex);
2563

2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576
      /*
        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;
      }

2577
      if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
unknown's avatar
unknown committed
2578 2579 2580 2581 2582 2583
      {
        lex->link_first_table_back(create_table, link_to_local);
        create_table->create= TRUE;
      }

      if (!(res= open_and_lock_tables(thd, lex->query_tables)))
2584
      {
2585 2586 2587 2588
        /*
          Is table which we are changing used somewhere in other parts
          of query
        */
2589
        if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
2590
        {
2591
          TABLE_LIST *duplicate;
unknown's avatar
unknown committed
2592
          create_table= lex->unlink_first_table(&link_to_local);
2593
          if ((duplicate= unique_table(thd, create_table, select_tables, 0)))
2594 2595 2596
          {
            update_non_unique_table_error(create_table, "CREATE", duplicate);
            res= 1;
2597
            goto end_with_restore_list;
2598
          }
2599
        }
unknown's avatar
unknown committed
2600
        /* If we create merge table, we have to test tables in merge, too */
2601
        if (create_info.used_fields & HA_CREATE_USED_UNION)
unknown's avatar
unknown committed
2602 2603
        {
          TABLE_LIST *tab;
2604
          for (tab= (TABLE_LIST*) create_info.merge_list.first;
unknown's avatar
unknown committed
2605 2606 2607
               tab;
               tab= tab->next_local)
          {
2608
            TABLE_LIST *duplicate;
2609
            if ((duplicate= unique_table(thd, tab, select_tables, 0)))
unknown's avatar
unknown committed
2610
            {
2611
              update_non_unique_table_error(tab, "CREATE", duplicate);
unknown's avatar
unknown committed
2612
              res= 1;
2613
              goto end_with_restore_list;
unknown's avatar
unknown committed
2614 2615 2616
            }
          }
        }
2617

unknown's avatar
unknown committed
2618
        /*
2619 2620
          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
2621
        */
unknown's avatar
VIEW  
unknown committed
2622
        if ((result= new select_create(create_table,
2623 2624 2625 2626
                                       &create_info,
                                       &alter_info,
                                       select_lex->item_list,
                                       lex->duplicates,
2627
                                       lex->ignore,
2628
                                       select_tables)))
2629 2630 2631 2632 2633
        {
          /*
            CREATE from SELECT give its SELECT_LEX for SELECT,
            and item_list belong to SELECT
          */
2634
          res= handle_select(thd, lex, result, 0);
2635
          delete result;
2636
        }
2637
      }
2638
      else if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
unknown's avatar
unknown committed
2639 2640
        create_table= lex->unlink_first_table(&link_to_local);

2641
    }
unknown's avatar
unknown committed
2642
    else
unknown's avatar
unknown committed
2643
    {
2644
      /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
2645
      if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
2646
        thd->options|= OPTION_KEEP_LOG;
unknown's avatar
unknown committed
2647
      /* regular create */
2648
      if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
unknown's avatar
unknown committed
2649
        res= mysql_create_like_table(thd, create_table, select_tables,
2650
                                     &create_info);
unknown's avatar
unknown committed
2651
      else
2652
      {
unknown's avatar
VIEW  
unknown committed
2653
        res= mysql_create_table(thd, create_table->db,
2654 2655
                                create_table->table_name, &create_info,
                                &alter_info, 0, 0);
2656
      }
unknown's avatar
unknown committed
2657
      if (!res)
2658
	my_ok(thd);
unknown's avatar
unknown committed
2659
    }
2660

unknown's avatar
unknown committed
2661
    /* put tables back for PS rexecuting */
unknown's avatar
unknown committed
2662
end_with_restore_list:
unknown's avatar
VIEW  
unknown committed
2663
    lex->link_first_table_back(create_table, link_to_local);
unknown's avatar
unknown committed
2664
    break;
unknown's avatar
unknown committed
2665
  }
unknown's avatar
unknown committed
2666
  case SQLCOM_CREATE_INDEX:
2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684
    /* 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
2685 2686
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, INDEX_ACL, all_tables))
unknown's avatar
unknown committed
2687
      goto error; /* purecov: inspected */
2688
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2689
      goto error;
2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700
    /*
      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
2701

2702 2703 2704 2705 2706
    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
2707
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2708
  case SQLCOM_SLAVE_START:
2709
  {
2710
    pthread_mutex_lock(&LOCK_active_mi);
2711
    start_slave(thd,active_mi,1 /* net report*/);
2712
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2713
    break;
2714
  }
unknown's avatar
unknown committed
2715
  case SQLCOM_SLAVE_STOP:
2716 2717 2718 2719 2720 2721
  /*
    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,
2722
      so it waits for the client thread because t is locked by it.
2723
    - then the client thread does SLAVE STOP.
2724 2725
      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.
2726 2727 2728
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
2729
  if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock)
2730
  {
2731 2732
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
2733
    goto error;
2734
  }
2735
  {
2736
    pthread_mutex_lock(&LOCK_active_mi);
2737
    stop_slave(thd,active_mi,1/* net report*/);
2738
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2739
    break;
2740
  }
unknown's avatar
unknown committed
2741
#endif /* HAVE_REPLICATION */
2742

unknown's avatar
unknown committed
2743
  case SQLCOM_ALTER_TABLE:
unknown's avatar
VIEW  
unknown committed
2744
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2745
    {
unknown's avatar
unknown committed
2746
      ulong priv=0;
unknown's avatar
unknown committed
2747
      ulong priv_needed= ALTER_ACL;
2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758
      /*
        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;
2759 2760 2761 2762
      /*
        We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
        as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
      */
2763
      if (alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME))
unknown's avatar
unknown committed
2764 2765
        priv_needed|= DROP_ACL;

unknown's avatar
unknown committed
2766 2767
      /* Must be set in the parser */
      DBUG_ASSERT(select_lex->db);
unknown's avatar
unknown committed
2768
      if (check_access(thd, priv_needed, first_table->db,
2769 2770 2771 2772
		       &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
2773
	  check_merge_table_access(thd, first_table->db,
2774
				   (TABLE_LIST *)
2775
				   create_info.merge_list.first))
2776
	goto error;				/* purecov: inspected */
2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788
      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
2789
      }
2790

2791
      /* Don't yet allow changing of symlinks with ALTER TABLE */
2792
      if (create_info.data_file_name)
2793 2794 2795
        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                            WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
                            "DATA DIRECTORY");
2796
      if (create_info.index_file_name)
2797 2798 2799
        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                            WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
                            "INDEX DIRECTORY");
2800
      create_info.data_file_name= create_info.index_file_name= NULL;
unknown's avatar
unknown committed
2801
      /* ALTER TABLE ends previous transaction */
2802
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2803
	goto error;
2804

2805 2806 2807 2808 2809
      if (!thd->locked_tables &&
          !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
      {
        res= 1;
        break;
unknown's avatar
unknown committed
2810
      }
2811

2812
      thd->enable_slow_log= opt_log_slow_admin_statements;
2813
      res= mysql_alter_table(thd, select_lex->db, lex->name.str,
2814 2815 2816
                             &create_info,
                             first_table,
                             &alter_info,
2817 2818
                             select_lex->order_list.elements,
                             (ORDER *) select_lex->order_list.first,
2819
                             lex->ignore);
unknown's avatar
unknown committed
2820 2821
      break;
    }
unknown's avatar
unknown committed
2822
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
2823
  {
unknown's avatar
VIEW  
unknown committed
2824
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2825
    TABLE_LIST *table;
unknown's avatar
VIEW  
unknown committed
2826
    for (table= first_table; table; table= table->next_local->next_local)
unknown's avatar
unknown committed
2827
    {
unknown's avatar
unknown committed
2828
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
2829
		       &table->grant.privilege,0,0, test(table->schema_table)) ||
unknown's avatar
VIEW  
unknown committed
2830
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
2831 2832
		       &table->next_local->grant.privilege, 0, 0,
                       test(table->next_local->schema_table)))
unknown's avatar
unknown committed
2833
	goto error;
2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845
      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
2846
    }
2847

unknown's avatar
unknown committed
2848
    if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
unknown's avatar
unknown committed
2849
      goto error;
unknown's avatar
unknown committed
2850
    break;
unknown's avatar
unknown committed
2851
  }
2852
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2853 2854
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2855 2856
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2857
    goto error;
unknown's avatar
unknown committed
2858 2859
#else
    {
unknown's avatar
unknown committed
2860
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2861 2862 2863 2864
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
2865
#endif
2866
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2867
  case SQLCOM_SHOW_CREATE:
unknown's avatar
VIEW  
unknown committed
2868
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2869
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2870 2871
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2872
    goto error;
unknown's avatar
unknown committed
2873
#else
unknown's avatar
unknown committed
2874
    {
2875 2876 2877
      /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
      if (lex->only_view)
        first_table->skip_temporary= 1;
unknown's avatar
unknown committed
2878
      if (check_show_create_table_access(thd, first_table))
2879
	goto error;
unknown's avatar
unknown committed
2880
      res= mysqld_show_create(thd, first_table);
unknown's avatar
unknown committed
2881 2882
      break;
    }
unknown's avatar
unknown committed
2883
#endif
2884 2885
  case SQLCOM_CHECKSUM:
  {
unknown's avatar
VIEW  
unknown committed
2886
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2887 2888
    if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables,
                           UINT_MAX, FALSE))
2889
      goto error; /* purecov: inspected */
unknown's avatar
VIEW  
unknown committed
2890
    res = mysql_checksum_table(thd, first_table, &lex->check_opt);
2891 2892
    break;
  }
unknown's avatar
unknown committed
2893
  case SQLCOM_REPAIR:
2894
  {
unknown's avatar
VIEW  
unknown committed
2895
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2896 2897
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
                           UINT_MAX, FALSE))
2898
      goto error; /* purecov: inspected */
2899
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2900
    res= mysql_repair_table(thd, first_table, &lex->check_opt);
2901 2902 2903
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
2904 2905 2906
      /*
        Presumably, REPAIR and binlog writing doesn't require synchronization
      */
2907
      write_bin_log(thd, TRUE, thd->query, thd->query_length);
2908
    }
2909
    select_lex->table_list.first= (uchar*) first_table;
2910
    lex->query_tables=all_tables;
2911 2912
    break;
  }
unknown's avatar
unknown committed
2913
  case SQLCOM_CHECK:
2914
  {
unknown's avatar
VIEW  
unknown committed
2915
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2916 2917
    if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables,
                           UINT_MAX, FALSE))
2918
      goto error; /* purecov: inspected */
2919
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2920
    res = mysql_check_table(thd, first_table, &lex->check_opt);
2921
    select_lex->table_list.first= (uchar*) first_table;
2922
    lex->query_tables=all_tables;
2923 2924
    break;
  }
unknown's avatar
unknown committed
2925 2926
  case SQLCOM_ANALYZE:
  {
unknown's avatar
VIEW  
unknown committed
2927
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2928 2929
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
                           UINT_MAX, FALSE))
unknown's avatar
unknown committed
2930
      goto error; /* purecov: inspected */
2931
    thd->enable_slow_log= opt_log_slow_admin_statements;
2932
    res= mysql_analyze_table(thd, first_table, &lex->check_opt);
2933 2934 2935
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
2936 2937 2938
      /*
        Presumably, ANALYZE and binlog writing doesn't require synchronization
      */
2939
      write_bin_log(thd, TRUE, thd->query, thd->query_length);
2940
    }
2941
    select_lex->table_list.first= (uchar*) first_table;
2942
    lex->query_tables=all_tables;
unknown's avatar
unknown committed
2943
    break;
unknown's avatar
unknown committed
2944
  }
2945

unknown's avatar
unknown committed
2946 2947
  case SQLCOM_OPTIMIZE:
  {
unknown's avatar
VIEW  
unknown committed
2948
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2949 2950
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
                           UINT_MAX, FALSE))
unknown's avatar
unknown committed
2951
      goto error; /* purecov: inspected */
2952
    thd->enable_slow_log= opt_log_slow_admin_statements;
2953
    res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
2954
      mysql_recreate_table(thd, first_table) :
unknown's avatar
VIEW  
unknown committed
2955
      mysql_optimize_table(thd, first_table, &lex->check_opt);
2956 2957 2958
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
2959 2960 2961
      /*
        Presumably, OPTIMIZE and binlog writing doesn't require synchronization
      */
2962
      write_bin_log(thd, TRUE, thd->query, thd->query_length);
2963
    }
2964
    select_lex->table_list.first= (uchar*) first_table;
2965
    lex->query_tables=all_tables;
unknown's avatar
unknown committed
2966 2967 2968
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
VIEW  
unknown committed
2969 2970
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (update_precheck(thd, all_tables))
unknown's avatar
unknown committed
2971
      break;
2972 2973
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
unknown's avatar
unknown committed
2974 2975 2976 2977 2978 2979 2980 2981
    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));
2982
    /* mysql_update return 2 if we need to switch to multi-update */
unknown's avatar
unknown committed
2983
    if (up_result != 2)
2984
      break;
unknown's avatar
unknown committed
2985
    /* Fall through */
2986
  case SQLCOM_UPDATE_MULTI:
unknown's avatar
unknown committed
2987 2988 2989
  {
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    /* if we switched from normal update, rights are checked */
unknown's avatar
unknown committed
2990
    if (up_result != 2)
2991
    {
unknown's avatar
unknown committed
2992 2993 2994 2995 2996
      if ((res= multi_update_precheck(thd, all_tables)))
        break;
    }
    else
      res= 0;
unknown's avatar
unknown committed
2997

2998
    res= mysql_multi_update_prepare(thd);
unknown's avatar
unknown committed
2999

3000
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
3001
    /* Check slave filtering rules */
3002
    if (unlikely(thd->slave_thread && !have_table_map_for_update))
unknown's avatar
unknown committed
3003
    {
3004 3005
      if (all_tables_not_ok(thd, all_tables))
      {
3006 3007 3008 3009 3010
        if (res!= 0)
        {
          res= 0;             /* don't care of prev failure  */
          thd->clear_error(); /* filters are of highest prior */
        }
3011 3012 3013 3014
        /* we warn the slave SQL thread */
        my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
        break;
      }
3015 3016
      if (res)
        break;
unknown's avatar
unknown committed
3017
    }
3018 3019
    else
    {
3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032
#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
3033

unknown's avatar
unknown committed
3034 3035 3036 3037 3038 3039
    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
3040
    break;
unknown's avatar
unknown committed
3041
  }
unknown's avatar
unknown committed
3042
  case SQLCOM_REPLACE:
3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072
#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
3073 3074
  case SQLCOM_INSERT:
  {
unknown's avatar
VIEW  
unknown committed
3075
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3076
    if ((res= insert_precheck(thd, all_tables)))
unknown's avatar
unknown committed
3077
      break;
3078 3079 3080 3081 3082 3083 3084 3085

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

unknown's avatar
VIEW  
unknown committed
3086
    res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
unknown's avatar
unknown committed
3087
		      lex->update_list, lex->value_list,
3088
                      lex->duplicates, lex->ignore);
3089 3090 3091 3092 3093 3094 3095

    /*
      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
3096
    if (first_table->view && !first_table->contain_auto_increment)
3097 3098
      thd->first_successful_insert_id_in_cur_stmt=
        thd->first_successful_insert_id_in_prev_stmt;
3099

unknown's avatar
unknown committed
3100
    break;
3101
  }
unknown's avatar
unknown committed
3102 3103 3104
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
unknown's avatar
unknown committed
3105
    select_result *sel_result;
unknown's avatar
VIEW  
unknown committed
3106
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3107
    if ((res= insert_precheck(thd, all_tables)))
3108
      break;
unknown's avatar
unknown committed
3109

3110
    /* Fix lock for first table */
unknown's avatar
VIEW  
unknown committed
3111 3112
    if (first_table->lock_type == TL_WRITE_DELAYED)
      first_table->lock_type= TL_WRITE;
3113

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

3117
    unit->set_limit(select_lex);
3118 3119 3120 3121 3122 3123 3124 3125

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

unknown's avatar
VIEW  
unknown committed
3126
    if (!(res= open_and_lock_tables(thd, all_tables)))
3127
    {
3128
      /* Skip first table, which is the table we are inserting in */
unknown's avatar
unknown committed
3129
      TABLE_LIST *second_table= first_table->next_local;
3130
      select_lex->table_list.first= (uchar*) second_table;
3131 3132
      select_lex->context.table_list= 
        select_lex->context.first_name_resolution_table= second_table;
3133
      res= mysql_insert_select_prepare(thd);
unknown's avatar
unknown committed
3134 3135 3136 3137 3138 3139 3140
      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)))
3141
      {
unknown's avatar
unknown committed
3142
	res= handle_select(thd, lex, sel_result, OPTION_SETUP_TABLES_DONE);
3143 3144 3145 3146 3147 3148 3149 3150 3151
        /*
          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)
        {
3152 3153 3154
          /* INSERT ... SELECT should invalidate only the very first table */
          TABLE_LIST *save_table= first_table->next_local;
          first_table->next_local= 0;
3155
          query_cache_invalidate3(thd, first_table, 1);
3156
          first_table->next_local= save_table;
3157
        }
unknown's avatar
unknown committed
3158
        delete sel_result;
3159
      }
3160
      /* revert changes for SP */
3161
      select_lex->table_list.first= (uchar*) first_table;
3162
    }
unknown's avatar
VIEW  
unknown committed
3163

3164 3165 3166 3167 3168 3169
    /*
      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
3170
    if (first_table->view && !first_table->contain_auto_increment)
3171 3172
      thd->first_successful_insert_id_in_cur_stmt=
        thd->first_successful_insert_id_in_prev_stmt;
3173

unknown's avatar
unknown committed
3174 3175
    break;
  }
3176
  case SQLCOM_TRUNCATE:
3177 3178 3179 3180 3181
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
VIEW  
unknown committed
3182
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3183
    if (check_one_table_access(thd, DROP_ACL, all_tables))
unknown's avatar
unknown committed
3184
      goto error;
3185 3186 3187 3188
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
3189
    if (thd->locked_tables || thd->active_transaction())
3190
    {
unknown's avatar
unknown committed
3191 3192
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3193 3194
      goto error;
    }
unknown's avatar
VIEW  
unknown committed
3195

unknown's avatar
unknown committed
3196
    res= mysql_truncate(thd, first_table, 0);
3197
    break;
unknown's avatar
unknown committed
3198
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
3199
  {
unknown's avatar
VIEW  
unknown committed
3200 3201
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if ((res= delete_precheck(thd, all_tables)))
unknown's avatar
unknown committed
3202
      break;
3203 3204
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
3205 3206 3207 3208 3209 3210 3211 3212

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

unknown's avatar
VIEW  
unknown committed
3213
    res = mysql_delete(thd, all_tables, select_lex->where,
3214
                       &select_lex->order_list,
unknown's avatar
unknown committed
3215 3216
                       unit->select_limit_cnt, select_lex->options,
                       FALSE);
unknown's avatar
unknown committed
3217 3218
    break;
  }
3219
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
3220
  {
unknown's avatar
VIEW  
unknown committed
3221
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3222
    TABLE_LIST *aux_tables=
unknown's avatar
unknown committed
3223
      (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
unknown's avatar
unknown committed
3224
    multi_delete *del_result;
unknown's avatar
unknown committed
3225

3226 3227 3228 3229 3230 3231 3232
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
    {
      res= 1;
      break;
    }

3233
    if ((res= multi_delete_precheck(thd, all_tables)))
3234
      break;
unknown's avatar
unknown committed
3235

unknown's avatar
unknown committed
3236
    /* condition will be TRUE on SP re-excuting */
3237 3238
    if (select_lex->item_list.elements != 0)
      select_lex->item_list.empty();
unknown's avatar
unknown committed
3239
    if (add_item_to_list(thd, new Item_null()))
unknown's avatar
unknown committed
3240
      goto error;
3241

3242
    thd_proc_info(thd, "init");
unknown's avatar
VIEW  
unknown committed
3243 3244 3245 3246
    if ((res= open_and_lock_tables(thd, all_tables)))
      break;

    if ((res= mysql_multi_delete_prepare(thd)))
unknown's avatar
unknown committed
3247
      goto error;
3248

unknown's avatar
unknown committed
3249 3250
    if (!thd->is_fatal_error &&
        (del_result= new multi_delete(aux_tables, lex->table_count)))
unknown's avatar
unknown committed
3251
    {
3252 3253 3254
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
3255
			select_lex->item_list,
unknown's avatar
unknown committed
3256
			select_lex->where,
3257
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
unknown's avatar
unknown committed
3258 3259
			(ORDER *)NULL,
			select_lex->options | thd->options |
3260 3261
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
                        OPTION_SETUP_TABLES_DONE,
unknown's avatar
unknown committed
3262
			del_result, unit, select_lex);
3263 3264
      res|= thd->is_error();
      if (res)
3265
        del_result->abort();
unknown's avatar
unknown committed
3266
      delete del_result;
unknown's avatar
unknown committed
3267 3268
    }
    else
3269
      res= TRUE;                                // Error
unknown's avatar
unknown committed
3270 3271
    break;
  }
unknown's avatar
unknown committed
3272
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
3273
  {
unknown's avatar
VIEW  
unknown committed
3274
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3275 3276
    if (!lex->drop_temporary)
    {
3277
      if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE))
3278 3279
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
unknown's avatar
unknown committed
3280
        goto error;
3281
    }
unknown's avatar
unknown committed
3282
    else
unknown's avatar
unknown committed
3283 3284 3285 3286 3287 3288
    {
      /*
	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
3289 3290
	To not generate such irrelevant "table does not exist errors",
	we silently add IF EXISTS if TEMPORARY was used.
unknown's avatar
unknown committed
3291 3292
      */
      if (thd->slave_thread)
3293
        lex->drop_if_exists= 1;
3294

unknown's avatar
unknown committed
3295
      /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
3296
      thd->options|= OPTION_KEEP_LOG;
unknown's avatar
unknown committed
3297
    }
3298
    /* DDL and binlog write order protected by LOCK_open */
unknown's avatar
VIEW  
unknown committed
3299 3300
    res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
			lex->drop_temporary);
unknown's avatar
unknown committed
3301 3302
  }
  break;
unknown's avatar
unknown committed
3303
  case SQLCOM_SHOW_PROCESSLIST:
3304 3305
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
3306
      break;
unknown's avatar
unknown committed
3307
    mysqld_list_processes(thd,
3308 3309 3310 3311
			  (thd->security_ctx->master_access & PROCESS_ACL ?
                           NullS :
                           thd->security_ctx->priv_user),
                          lex->verbose);
unknown's avatar
unknown committed
3312
    break;
unknown's avatar
unknown committed
3313 3314 3315
  case SQLCOM_SHOW_AUTHORS:
    res= mysqld_show_authors(thd);
    break;
3316 3317 3318
  case SQLCOM_SHOW_CONTRIBUTORS:
    res= mysqld_show_contributors(thd);
    break;
unknown's avatar
unknown committed
3319 3320 3321 3322 3323 3324
  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
3325
  case SQLCOM_SHOW_ENGINE_LOGS:
unknown's avatar
unknown committed
3326
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
3327 3328
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
3329
    goto error;
unknown's avatar
unknown committed
3330 3331
#else
    {
3332
      if (check_access(thd, FILE_ACL, any_db,0,0,0,0))
unknown's avatar
unknown committed
3333
	goto error;
unknown's avatar
unknown committed
3334
      res= ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_LOGS);
unknown's avatar
unknown committed
3335 3336
      break;
    }
unknown's avatar
unknown committed
3337 3338
#endif
  case SQLCOM_CHANGE_DB:
3339 3340 3341 3342
  {
    LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) };

    if (!mysql_change_db(thd, &db_str, FALSE))
3343
      my_ok(thd);
3344

unknown's avatar
unknown committed
3345
    break;
3346
  }
3347

unknown's avatar
unknown committed
3348 3349
  case SQLCOM_LOAD:
  {
unknown's avatar
VIEW  
unknown committed
3350
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3351
    uint privilege= (lex->duplicates == DUP_REPLACE ?
unknown's avatar
unknown committed
3352 3353
		     INSERT_ACL | DELETE_ACL : INSERT_ACL) |
                    (lex->local_file ? 0 : FILE_ACL);
3354

unknown's avatar
unknown committed
3355
    if (lex->local_file)
unknown's avatar
unknown committed
3356
    {
3357
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
3358
          !opt_local_infile)
3359
      {
unknown's avatar
unknown committed
3360
	my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0));
3361 3362
	goto error;
      }
unknown's avatar
unknown committed
3363
    }
unknown's avatar
unknown committed
3364 3365 3366 3367

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

unknown's avatar
VIEW  
unknown committed
3368
    res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
unknown's avatar
unknown committed
3369
                    lex->update_list, lex->value_list, lex->duplicates,
3370
                    lex->ignore, (bool) lex->local_file);
unknown's avatar
unknown committed
3371 3372
    break;
  }
3373

unknown's avatar
unknown committed
3374
  case SQLCOM_SET_OPTION:
3375 3376
  {
    List<set_var_base> *lex_var_list= &lex->var_list;
3377 3378 3379 3380

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

3381
    if ((check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
unknown's avatar
unknown committed
3382 3383
	 open_and_lock_tables(thd, all_tables)))
      goto error;
3384 3385
    if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
    {
unknown's avatar
unknown committed
3386 3387
      my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
      goto error;
3388 3389 3390 3391 3392 3393 3394 3395
    }
    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;
3396
      my_ok(thd);
3397
    }
3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409
    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
3410
    break;
3411
  }
unknown's avatar
unknown committed
3412

unknown's avatar
unknown committed
3413
  case SQLCOM_UNLOCK_TABLES:
3414 3415 3416 3417 3418 3419
    /*
      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
3420
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
3421 3422
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
3423
      end_active_trans(thd);
3424
      thd->options&= ~(OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3425 3426
    }
    if (thd->global_read_lock)
3427
      unlock_global_read_lock(thd);
3428
    my_ok(thd);
unknown's avatar
unknown committed
3429 3430
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
3431
    unlock_locked_tables(thd);
3432
    /* we must end the trasaction first, regardless of anything */
unknown's avatar
unknown committed
3433
    if (end_active_trans(thd))
unknown's avatar
unknown committed
3434
      goto error;
3435 3436
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
                           UINT_MAX, FALSE))
3437
      goto error;
unknown's avatar
unknown committed
3438
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
3439
    thd->options|= OPTION_TABLE_LOCK;
unknown's avatar
VIEW  
unknown committed
3440

3441
    if (!(res= simple_open_n_lock_tables(thd, all_tables)))
unknown's avatar
unknown committed
3442
    {
3443 3444
#ifdef HAVE_QUERY_CACHE
      if (thd->variables.query_cache_wlock_invalidate)
unknown's avatar
VIEW  
unknown committed
3445
	query_cache.invalidate_locked_for_write(first_table);
3446
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
3447 3448
      thd->locked_tables=thd->lock;
      thd->lock=0;
3449
      my_ok(thd);
unknown's avatar
unknown committed
3450
    }
unknown's avatar
unknown committed
3451
    else
3452 3453 3454 3455 3456 3457
    {
      /* 
        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
      */
3458
      ha_autocommit_or_rollback(thd, 1);
3459
      end_active_trans(thd);
3460
      thd->options&= ~(OPTION_TABLE_LOCK);
3461
    }
unknown's avatar
unknown committed
3462 3463 3464
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
3465
  {
3466 3467 3468 3469 3470 3471
    /*
      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);
3472 3473 3474 3475 3476
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
unknown committed
3477
    char *alias;
3478 3479
    if (!(alias=thd->strmake(lex->name.str, lex->name.length)) ||
        check_db_name(&lex->name))
unknown's avatar
unknown committed
3480
    {
3481
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3482 3483
      break;
    }
3484 3485 3486
    /*
      If in a slave thread :
      CREATE DATABASE DB was certainly not preceded by USE DB.
3487
      For that reason, db_ok() in sql/slave.cc did not check the
3488 3489 3490
      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.
    */
3491
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
3492
    if (thd->slave_thread && 
3493 3494
	(!rpl_filter->db_ok(lex->name.str) ||
	 !rpl_filter->db_ok_with_wild_table(lex->name.str)))
unknown's avatar
unknown committed
3495
    {
unknown's avatar
unknown committed
3496
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3497
      break;
unknown's avatar
unknown committed
3498
    }
3499
#endif
3500 3501
    if (check_access(thd,CREATE_ACL,lex->name.str, 0, 1, 0,
                     is_schema_db(lex->name.str)))
3502
      break;
3503
    res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
3504
                              lex->name.str), &create_info, 0);
3505 3506
    break;
  }
unknown's avatar
unknown committed
3507
  case SQLCOM_DROP_DB:
3508
  {
3509 3510 3511 3512 3513
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
3514
    if (check_db_name(&lex->name))
unknown's avatar
unknown committed
3515
    {
3516
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3517 3518
      break;
    }
3519 3520 3521 3522 3523 3524 3525
    /*
      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.
    */
3526
#ifdef HAVE_REPLICATION
3527
    if (thd->slave_thread && 
3528 3529
	(!rpl_filter->db_ok(lex->name.str) ||
	 !rpl_filter->db_ok_with_wild_table(lex->name.str)))
unknown's avatar
unknown committed
3530
    {
unknown's avatar
unknown committed
3531
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3532
      break;
unknown's avatar
unknown committed
3533
    }
3534
#endif
3535 3536
    if (check_access(thd,DROP_ACL,lex->name.str,0,1,0,
                     is_schema_db(lex->name.str)))
3537
      break;
3538 3539
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3540 3541
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3542 3543
      goto error;
    }
3544
    res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0);
3545 3546
    break;
  }
3547
  case SQLCOM_ALTER_DB_UPGRADE:
unknown's avatar
unknown committed
3548
  {
3549
    LEX_STRING *db= & lex->name;
unknown's avatar
unknown committed
3550 3551 3552 3553 3554 3555 3556
    if (end_active_trans(thd))
    {
      res= 1;
      break;
    }
#ifdef HAVE_REPLICATION
    if (thd->slave_thread && 
3557 3558
       (!rpl_filter->db_ok(db->str) ||
        !rpl_filter->db_ok_with_wild_table(db->str)))
unknown's avatar
unknown committed
3559 3560 3561 3562 3563 3564
    {
      res= 1;
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
      break;
    }
#endif
3565
    if (check_db_name(db))
3566
    {
3567
      my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
3568 3569
      break;
    }
3570 3571 3572
    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
3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583
    {
      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;
    }
3584 3585

    res= mysql_upgrade_db(thd, db);
unknown's avatar
unknown committed
3586
    if (!res)
3587
      my_ok(thd);
unknown's avatar
unknown committed
3588 3589
    break;
  }
3590 3591
  case SQLCOM_ALTER_DB:
  {
3592
    LEX_STRING *db= &lex->name;
3593
    HA_CREATE_INFO create_info(lex->create_info);
3594
    if (check_db_name(db))
3595
    {
3596
      my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
3597 3598
      break;
    }
unknown's avatar
unknown committed
3599 3600 3601
    /*
      If in a slave thread :
      ALTER DATABASE DB may not be preceded by USE DB.
3602
      For that reason, maybe db_ok() in sql/slave.cc did not check the
unknown's avatar
unknown committed
3603 3604 3605 3606
      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
3607
    if (thd->slave_thread &&
3608 3609
	(!rpl_filter->db_ok(db->str) ||
	 !rpl_filter->db_ok_with_wild_table(db->str)))
unknown's avatar
unknown committed
3610
    {
unknown's avatar
unknown committed
3611
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
unknown's avatar
unknown committed
3612 3613 3614
      break;
    }
#endif
3615
    if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0, is_schema_db(db->str)))
3616 3617 3618
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3619 3620
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3621 3622
      goto error;
    }
3623
    res= mysql_alter_db(thd, db->str, &create_info);
3624 3625
    break;
  }
unknown's avatar
unknown committed
3626 3627
  case SQLCOM_SHOW_CREATE_DB:
  {
unknown's avatar
unknown committed
3628 3629
    DBUG_EXECUTE_IF("4x_server_emul",
                    my_error(ER_UNKNOWN_ERROR, MYF(0)); goto error;);
3630
    if (check_db_name(&lex->name))
unknown's avatar
unknown committed
3631
    {
3632
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3633 3634
      break;
    }
3635
    res= mysqld_show_create_db(thd, lex->name.str, &lex->create_info);
unknown's avatar
unknown committed
3636 3637
    break;
  }
unknown's avatar
unknown committed
3638 3639
  case SQLCOM_CREATE_EVENT:
  case SQLCOM_ALTER_EVENT:
3640
  #ifdef HAVE_EVENT_SCHEDULER
3641
  do
unknown's avatar
unknown committed
3642
  {
unknown's avatar
unknown committed
3643
    DBUG_ASSERT(lex->event_parse_data);
unknown's avatar
unknown committed
3644 3645 3646 3647 3648 3649
    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;
    }
3650 3651 3652 3653 3654

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

unknown's avatar
unknown committed
3655 3656
    switch (lex->sql_command) {
    case SQLCOM_CREATE_EVENT:
3657 3658 3659 3660
    {
      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
3661
      break;
3662
    }
unknown's avatar
unknown committed
3663
    case SQLCOM_ALTER_EVENT:
3664 3665 3666
      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
3667
      break;
3668 3669
    default:
      DBUG_ASSERT(0);
unknown's avatar
unknown committed
3670
    }
3671
    DBUG_PRINT("info",("DDL error code=%d", res));
unknown's avatar
unknown committed
3672
    if (!res)
3673
      my_ok(thd);
unknown's avatar
unknown committed
3674

3675 3676 3677 3678 3679 3680
  } 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
3681
  }
3682 3683
  /* lex->unit.cleanup() is called outside, no need to call it here */
  break;
unknown's avatar
unknown committed
3684
  case SQLCOM_SHOW_CREATE_EVENT:
3685 3686 3687 3688 3689 3690 3691
    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)))
3692
      my_ok(thd);
3693
    break;
3694 3695 3696 3697
#else
    my_error(ER_NOT_SUPPORTED_YET,MYF(0),"embedded server");
    break;
#endif
unknown's avatar
unknown committed
3698
  case SQLCOM_CREATE_FUNCTION:                  // UDF function
unknown's avatar
unknown committed
3699
  {
3700
    if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
unknown's avatar
unknown committed
3701
      break;
unknown's avatar
unknown committed
3702
#ifdef HAVE_DLOPEN
3703
    if (!(res = mysql_create_function(thd, &lex->udf)))
3704
      my_ok(thd);
unknown's avatar
unknown committed
3705
#else
unknown's avatar
unknown committed
3706
    my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled");
unknown's avatar
unknown committed
3707
    res= TRUE;
unknown's avatar
unknown committed
3708 3709
#endif
    break;
unknown's avatar
unknown committed
3710
  }
unknown's avatar
unknown committed
3711
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3712 3713
  case SQLCOM_CREATE_USER:
  {
3714
    if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) &&
3715
        check_global_access(thd,CREATE_USER_ACL))
3716
      break;
3717 3718
    if (end_active_trans(thd))
      goto error;
3719
    /* Conditionally writes to binlog */
3720
    if (!(res= mysql_create_user(thd, lex->users_list)))
3721
      my_ok(thd);
3722 3723
    break;
  }
3724 3725
  case SQLCOM_DROP_USER:
  {
3726
    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) &&
3727
        check_global_access(thd,CREATE_USER_ACL))
3728
      break;
3729 3730
    if (end_active_trans(thd))
      goto error;
3731
    /* Conditionally writes to binlog */
3732
    if (!(res= mysql_drop_user(thd, lex->users_list)))
3733
      my_ok(thd);
3734 3735 3736 3737
    break;
  }
  case SQLCOM_RENAME_USER:
  {
3738
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
3739
        check_global_access(thd,CREATE_USER_ACL))
3740
      break;
3741 3742
    if (end_active_trans(thd))
      goto error;
3743
    /* Conditionally writes to binlog */
3744
    if (!(res= mysql_rename_user(thd, lex->users_list)))
3745
      my_ok(thd);
3746 3747 3748 3749
    break;
  }
  case SQLCOM_REVOKE_ALL:
  {
3750 3751
    if (end_active_trans(thd))
      goto error;
3752
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
3753
        check_global_access(thd,CREATE_USER_ACL))
3754
      break;
3755
    /* Conditionally writes to binlog */
3756
    if (!(res = mysql_revoke_all(thd, lex->users_list)))
3757
      my_ok(thd);
3758 3759
    break;
  }
3760 3761 3762
  case SQLCOM_REVOKE:
  case SQLCOM_GRANT:
  {
3763 3764 3765
    if (end_active_trans(thd))
      goto error;

3766
    if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
unknown's avatar
unknown committed
3767
		     first_table ?  first_table->db : select_lex->db,
unknown's avatar
VIEW  
unknown committed
3768
		     first_table ? &first_table->grant.privilege : 0,
3769 3770 3771
		     first_table ? 0 : 1, 0,
                     first_table ? (bool) first_table->schema_table :
                     select_lex->db ? is_schema_db(select_lex->db) : 0))
3772 3773
      goto error;

3774
    if (thd->security_ctx->user)              // If not replication
unknown's avatar
unknown committed
3775
    {
3776
      LEX_USER *user, *tmp_user;
3777

unknown's avatar
unknown committed
3778
      List_iterator <LEX_USER> user_list(lex->users_list);
3779
      while ((tmp_user= user_list++))
unknown's avatar
unknown committed
3780
      {
3781 3782
        if (!(user= get_current_user(thd, tmp_user)))
          goto error;
3783 3784 3785 3786 3787 3788 3789 3790
        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);
3791
        if (strcmp(thd->security_ctx->user, user->user.str) ||
3792
            my_strcasecmp(system_charset_info,
3793
                          user->host.str, thd->security_ctx->host_or_ip))
3794 3795
        {
          // TODO: use check_change_password()
3796 3797
          if (is_acl_user(user->host.str, user->user.str) &&
              user->password.str &&
3798
              check_access(thd, UPDATE_ACL,"mysql",0,1,1,0))
3799 3800 3801 3802 3803 3804
          {
            my_message(ER_PASSWORD_NOT_ALLOWED,
                       ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
            goto error;
          }
        }
unknown's avatar
SCRUM  
unknown committed
3805 3806
      }
    }
unknown's avatar
VIEW  
unknown committed
3807
    if (first_table)
3808
    {
3809 3810
      if (lex->type == TYPE_ENUM_PROCEDURE ||
          lex->type == TYPE_ENUM_FUNCTION)
3811 3812 3813 3814
      {
        uint grants= lex->all_privileges 
		   ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
		   : lex->grant;
3815
        if (check_grant_routine(thd, grants | GRANT_ACL, all_tables,
3816
                                lex->type == TYPE_ENUM_PROCEDURE, 0))
3817
	  goto error;
3818
        /* Conditionally writes to binlog */
3819 3820 3821 3822
        res= mysql_routine_grant(thd, all_tables,
                                 lex->type == TYPE_ENUM_PROCEDURE, 
                                 lex->users_list, grants,
                                 lex->sql_command == SQLCOM_REVOKE, 0);
3823 3824 3825
      }
      else
      {
3826 3827
	if (check_grant(thd,(lex->grant | lex->grant_tot_col | GRANT_ACL),
                        all_tables, 0, UINT_MAX, 0))
3828
	  goto error;
3829
        /* Conditionally writes to binlog */
3830 3831 3832 3833
        res= mysql_table_grant(thd, all_tables, lex->users_list,
			       lex->columns, lex->grant,
			       lex->sql_command == SQLCOM_REVOKE);
      }
3834 3835 3836
    }
    else
    {
3837
      if (lex->columns.elements || lex->type)
3838
      {
unknown's avatar
unknown committed
3839 3840
	my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
                   MYF(0));
unknown's avatar
unknown committed
3841
        goto error;
3842 3843
      }
      else
3844
	/* Conditionally writes to binlog */
3845 3846 3847 3848
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
3849
	if (lex->sql_command == SQLCOM_GRANT)
3850
	{
unknown's avatar
unknown committed
3851
	  List_iterator <LEX_USER> str_list(lex->users_list);
3852 3853 3854 3855 3856
	  LEX_USER *user, *tmp_user;
	  while ((tmp_user=str_list++))
          {
            if (!(user= get_current_user(thd, tmp_user)))
              goto error;
3857
	    reset_mqh(user, 0);
3858
          }
3859
	}
3860 3861 3862 3863
      }
    }
    break;
  }
unknown's avatar
SCRUM  
unknown committed
3864
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
unknown's avatar
unknown committed
3865
  case SQLCOM_RESET:
3866 3867 3868
    /*
      RESET commands are never written to the binary log, so we have to
      initialize this variable because RESET shares the same code as FLUSH
3869 3870 3871 3872
    */
    lex->no_write_to_binlog= 1;
  case SQLCOM_FLUSH:
  {
unknown's avatar
unknown committed
3873
    bool write_to_binlog;
unknown's avatar
unknown committed
3874
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
3875
      goto error;
3876

3877 3878 3879 3880
    /*
      reload_acl_and_cache() will tell us if we are allowed to write to the
      binlog or not.
    */
unknown's avatar
unknown committed
3881
    if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
3882 3883 3884 3885 3886
    {
      /*
        We WANT to write and we CAN write.
        ! we write after unlocking the table.
      */
3887 3888 3889
      /*
        Presumably, RESET and binlog writing doesn't require synchronization
      */
3890 3891
      if (!lex->no_write_to_binlog && write_to_binlog)
      {
3892
        write_bin_log(thd, FALSE, thd->query, thd->query_length);
3893
      }
3894
      my_ok(thd);
3895 3896
    } 
    
unknown's avatar
unknown committed
3897
    break;
3898
  }
unknown's avatar
unknown committed
3899
  case SQLCOM_KILL:
3900 3901 3902
  {
    Item *it= (Item *)lex->value_list.head();

unknown's avatar
unknown committed
3903 3904 3905 3906 3907 3908 3909
    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;
    }

3910
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1))
3911 3912 3913 3914 3915
    {
      my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
		 MYF(0));
      goto error;
    }
3916
    sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
unknown's avatar
unknown committed
3917
    break;
3918
  }
unknown's avatar
unknown committed
3919
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
3920
  case SQLCOM_SHOW_GRANTS:
3921 3922 3923 3924
  {
    LEX_USER *grant_user= get_current_user(thd, lex->grant_user);
    if (!grant_user)
      goto error;
3925
    if ((thd->security_ctx->priv_user &&
3926
	 !strcmp(thd->security_ctx->priv_user, grant_user->user.str)) ||
3927
	!check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
unknown's avatar
unknown committed
3928
    {
3929
      res = mysql_show_grants(thd, grant_user);
unknown's avatar
unknown committed
3930 3931
    }
    break;
3932
  }
unknown's avatar
unknown committed
3933
#endif
3934
  case SQLCOM_HA_OPEN:
unknown's avatar
VIEW  
unknown committed
3935
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3936
    if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE))
3937
      goto error;
unknown's avatar
unknown committed
3938
    res= mysql_ha_open(thd, first_table, 0);
3939 3940
    break;
  case SQLCOM_HA_CLOSE:
unknown's avatar
VIEW  
unknown committed
3941 3942
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    res= mysql_ha_close(thd, first_table);
3943 3944
    break;
  case SQLCOM_HA_READ:
unknown's avatar
VIEW  
unknown committed
3945
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3946 3947 3948 3949 3950
    /*
      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.
    */
3951
    unit->set_limit(select_lex);
3952
    res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
unknown's avatar
VIEW  
unknown committed
3953
                       lex->insert_list, lex->ha_rkey_mode, select_lex->where,
3954
                       unit->select_limit_cnt, unit->offset_limit_cnt);
3955 3956
    break;

unknown's avatar
unknown committed
3957
  case SQLCOM_BEGIN:
3958 3959 3960 3961 3962 3963
    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
3964
    if (begin_trans(thd))
unknown's avatar
unknown committed
3965
      goto error;
3966
    my_ok(thd);
unknown's avatar
unknown committed
3967 3968
    break;
  case SQLCOM_COMMIT:
3969
    if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
unknown's avatar
unknown committed
3970
                              lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
unknown's avatar
unknown committed
3971
      goto error;
3972
    my_ok(thd);
unknown's avatar
unknown committed
3973 3974
    break;
  case SQLCOM_ROLLBACK:
3975
    if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
unknown's avatar
unknown committed
3976
                              lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
unknown's avatar
unknown committed
3977
      goto error;
3978
    my_ok(thd);
unknown's avatar
unknown committed
3979
    break;
unknown's avatar
unknown committed
3980
  case SQLCOM_RELEASE_SAVEPOINT:
unknown's avatar
unknown committed
3981
  {
3982 3983
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
unknown's avatar
unknown committed
3984 3985 3986
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
3987
                       (uchar *)sv->name, sv->length) == 0)
unknown's avatar
unknown committed
3988 3989
        break;
    }
3990
    if (sv)
unknown's avatar
unknown committed
3991
    {
3992
      if (ha_release_savepoint(thd, sv))
unknown's avatar
unknown committed
3993
        res= TRUE; // cannot happen
unknown's avatar
unknown committed
3994
      else
3995
        my_ok(thd);
3996
      thd->transaction.savepoints=sv->prev;
unknown's avatar
unknown committed
3997
    }
3998
    else
unknown's avatar
unknown committed
3999
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
4000
    break;
unknown's avatar
unknown committed
4001
  }
unknown's avatar
unknown committed
4002
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
unknown's avatar
unknown committed
4003
  {
4004 4005
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
4006 4007 4008
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
4009
                       (uchar *)sv->name, sv->length) == 0)
4010 4011
        break;
    }
4012
    if (sv)
4013
    {
4014
      if (ha_rollback_to_savepoint(thd, sv))
4015 4016
        res= TRUE; // cannot happen
      else
unknown's avatar
unknown committed
4017
      {
unknown's avatar
unknown committed
4018 4019
        if (((thd->options & OPTION_KEEP_LOG) || 
             thd->transaction.all.modified_non_trans_table) &&
unknown's avatar
unknown committed
4020 4021 4022 4023
            !thd->slave_thread)
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_WARNING_NOT_COMPLETE_ROLLBACK,
                       ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
4024
        my_ok(thd);
unknown's avatar
unknown committed
4025
      }
4026
      thd->transaction.savepoints=sv;
unknown's avatar
unknown committed
4027 4028
    }
    else
4029
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
4030
    break;
4031
  }
4032
  case SQLCOM_SAVEPOINT:
4033 4034
    if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
          thd->in_sub_stmt) || !opt_using_transactions)
4035
      my_ok(thd);
unknown's avatar
unknown committed
4036
    else
4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071
    {
      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;
4072
        my_ok(thd);
4073 4074
      }
    }
unknown's avatar
unknown committed
4075
    break;
4076 4077
  case SQLCOM_CREATE_PROCEDURE:
  case SQLCOM_CREATE_SPFUNCTION:
unknown's avatar
unknown committed
4078
  {
4079
    uint namelen;
unknown's avatar
unknown committed
4080
    char *name;
unknown's avatar
unknown committed
4081
    int sp_result= SP_INTERNAL_ERROR;
4082

4083
    DBUG_ASSERT(lex->sphead != 0);
unknown's avatar
unknown committed
4084
    DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
4085 4086 4087 4088
    /*
      Verify that the database name is allowed, optionally
      lowercase it.
    */
4089
    if (check_db_name(&lex->sphead->m_db))
4090
    {
4091
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str);
4092
      goto create_sp_error;
4093 4094
    }

4095
    /*
4096 4097 4098
      Check that a database directory with this name
      exists. Design note: This won't work on virtual databases
      like information_schema.
4099 4100
    */
    if (check_db_dir_existence(lex->sphead->m_db.str))
4101
    {
4102
      my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
4103
      goto create_sp_error;
4104
    }
4105

4106 4107
    if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
                     is_schema_db(lex->sphead->m_db.str)))
4108
      goto create_sp_error;
4109

4110 4111
    if (end_active_trans(thd))
      goto create_sp_error;
4112 4113

    name= lex->sphead->name(&namelen);
4114
#ifdef HAVE_DLOPEN
unknown's avatar
unknown committed
4115 4116 4117
    if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
    {
      udf_func *udf = find_udf(name, namelen);
4118

unknown's avatar
unknown committed
4119
      if (udf)
4120
      {
4121 4122
        my_error(ER_UDF_EXISTS, MYF(0), name);
        goto create_sp_error;
4123
      }
unknown's avatar
unknown committed
4124 4125 4126
    }
#endif

4127 4128
    if (sp_process_definer(thd))
      goto create_sp_error;
4129

unknown's avatar
unknown committed
4130 4131
    res= (sp_result= lex->sphead->create(thd));
    switch (sp_result) {
4132
    case SP_OK:
unknown's avatar
unknown committed
4133
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4134
      /* only add privileges if really neccessary */
4135
      if (sp_automatic_privileges && !opt_noacl &&
4136
          check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
4137
                               lex->sphead->m_db.str, name,
4138
                               lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
4139
      {
unknown's avatar
unknown committed
4140
        if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
4141
                                lex->sql_command == SQLCOM_CREATE_PROCEDURE))
4142 4143 4144
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_PROC_AUTO_GRANT_FAIL,
                       ER(ER_PROC_AUTO_GRANT_FAIL));
4145
      }
unknown's avatar
unknown committed
4146
#endif
unknown's avatar
unknown committed
4147
    break;
4148 4149 4150 4151 4152 4153 4154 4155 4156
    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;
4157 4158 4159
    case SP_FLD_STORE_FAILED:
      my_error(ER_CANT_CREATE_SROUTINE, MYF(0), name);
      break;
4160 4161 4162 4163 4164 4165 4166 4167 4168 4169
    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
4170
    if (sp_result != SP_OK )
4171
      goto error;
4172
    my_ok(thd);
4173 4174
    break; /* break super switch */
  } /* end case group bracket */
4175 4176 4177 4178
  case SQLCOM_CALL:
    {
      sp_head *sp;

4179 4180 4181 4182
      /*
        This will cache all SP and SF and open and lock all tables
        required for execution.
      */
4183
      if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
4184 4185 4186 4187
	  open_and_lock_tables(thd, all_tables))
       goto error;

      /*
4188 4189
        By this moment all needed SPs should be in cache so no need to look 
        into DB. 
4190
      */
4191 4192
      if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                                &thd->sp_proc_cache, TRUE)))
4193
      {
4194
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
unknown's avatar
unknown committed
4195
                 lex->spname->m_qname.str);
4196
	goto error;
4197 4198 4199
      }
      else
      {
unknown's avatar
unknown committed
4200
	ha_rows select_limit;
unknown's avatar
unknown committed
4201 4202
        /* bits that should be cleared in thd->server_status */
	uint bits_to_be_cleared= 0;
4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214
        /*
          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;
        }
4215

4216
	if (sp->m_flags & sp_head::MULTI_RESULTS)
4217
	{
4218
	  if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
4219
	  {
4220 4221 4222 4223
            /*
              The client does not support multiple result sets being sent
              back
            */
4224
	    my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
4225 4226
	    goto error;
	  }
unknown's avatar
unknown committed
4227 4228 4229 4230 4231 4232 4233
          /*
            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;
4234 4235
	}

4236
	if (check_routine_access(thd, EXECUTE_ACL,
4237
				 sp->m_db.str, sp->m_name.str, TRUE, FALSE))
4238 4239 4240
	{
	  goto error;
	}
unknown's avatar
unknown committed
4241 4242
	select_limit= thd->variables.select_limit;
	thd->variables.select_limit= HA_POS_ERROR;
4243

4244
        /* 
4245
          We never write CALL statements into binlog:
4246 4247 4248 4249 4250
           - 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.
4251
        */
4252
	res= sp->execute_procedure(thd, &lex->value_list);
4253 4254 4255
	/*
          If warnings have been cleared, we have to clear total_warn_count
          too, otherwise the clients get confused.
4256 4257 4258 4259
	 */
	if (thd->warn_list.is_empty())
	  thd->total_warn_count= 0;

unknown's avatar
unknown committed
4260
	thd->variables.select_limit= select_limit;
4261

unknown's avatar
unknown committed
4262
        thd->server_status&= ~bits_to_be_cleared;
4263

unknown's avatar
unknown committed
4264
	if (!res)
4265 4266
          my_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
                              thd->row_count_func));
4267
	else
4268
        {
4269
          DBUG_ASSERT(thd->is_error() || thd->killed);
4270
	  goto error;		// Substatement should already have sent error
4271
        }
4272
      }
4273
      break;
4274 4275
    }
  case SQLCOM_ALTER_PROCEDURE:
4276
  case SQLCOM_ALTER_FUNCTION:
4277
    {
unknown's avatar
unknown committed
4278
      int sp_result;
4279 4280 4281 4282
      sp_head *sp;
      st_sp_chistics chistics;

      memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
unknown's avatar
unknown committed
4283
      if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
4284 4285
        sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                            &thd->sp_proc_cache, FALSE);
4286
      else
4287 4288
        sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                            &thd->sp_func_cache, FALSE);
unknown's avatar
unknown committed
4289
      mysql_reset_errors(thd, 0);
4290
      if (! sp)
4291 4292
      {
	if (lex->spname->m_db.str)
unknown's avatar
unknown committed
4293
	  sp_result= SP_KEY_NOT_FOUND;
4294 4295 4296 4297 4298 4299
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
      }
4300 4301
      else
      {
4302 4303 4304
        if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str, 
				 sp->m_name.str,
                                 lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
4305
	  goto error;
4306 4307 4308

        if (end_active_trans(thd)) 
          goto error;
4309
	memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
4310 4311
        if ((sp->m_type == TYPE_ENUM_FUNCTION) &&
            !trust_function_creators &&  mysql_bin_log.is_open() &&
4312 4313 4314 4315 4316 4317
            !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
4318
          sp_result= SP_INTERNAL_ERROR;
4319 4320 4321
        }
        else
        {
4322 4323 4324 4325 4326 4327
          /*
            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
4328
          /* Conditionally writes to binlog */
unknown's avatar
unknown committed
4329 4330 4331 4332 4333 4334 4335 4336 4337

          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);
4338
        }
4339
      }
unknown's avatar
unknown committed
4340
      switch (sp_result)
4341
      {
unknown's avatar
unknown committed
4342
      case SP_OK:
4343
	my_ok(thd);
unknown's avatar
unknown committed
4344 4345
	break;
      case SP_KEY_NOT_FOUND:
4346 4347
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
4348 4349
	goto error;
      default:
4350 4351
	my_error(ER_SP_CANT_ALTER, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
4352
	goto error;
4353
      }
4354
      break;
4355 4356
    }
  case SQLCOM_DROP_PROCEDURE:
4357
  case SQLCOM_DROP_FUNCTION:
4358
    {
unknown's avatar
unknown committed
4359
      int sp_result;
4360 4361
      int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
                 TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
4362

unknown's avatar
unknown committed
4363
      sp_result= sp_routine_exists_in_table(thd, type, lex->spname);
unknown's avatar
unknown committed
4364
      mysql_reset_errors(thd, 0);
unknown's avatar
unknown committed
4365
      if (sp_result == SP_OK)
4366
      {
4367 4368 4369
        char *db= lex->spname->m_db.str;
	char *name= lex->spname->m_name.str;

4370 4371
	if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
unknown's avatar
merge  
unknown committed
4372
          goto error;
4373 4374 4375

        if (end_active_trans(thd)) 
          goto error;
unknown's avatar
unknown committed
4376
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4377
	if (sp_automatic_privileges && !opt_noacl &&
4378 4379
	    sp_revoke_privileges(thd, db, name, 
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE))
4380 4381 4382 4383 4384
	{
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
		       ER_PROC_AUTO_REVOKE_FAIL,
		       ER(ER_PROC_AUTO_REVOKE_FAIL));
	}
unknown's avatar
unknown committed
4385
#endif
unknown's avatar
unknown committed
4386
        /* Conditionally writes to binlog */
unknown's avatar
unknown committed
4387 4388 4389 4390 4391 4392

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

        sp_result= sp_drop_routine(thd, type, lex->spname);
4393 4394 4395
      }
      else
      {
4396
#ifdef HAVE_DLOPEN
4397 4398 4399 4400 4401 4402
	if (lex->sql_command == SQLCOM_DROP_FUNCTION)
	{
          udf_func *udf = find_udf(lex->spname->m_name.str,
                                   lex->spname->m_name.length);
          if (udf)
          {
4403
	    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
4404
	      goto error;
4405

4406
	    if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
4407
	    {
4408
	      my_ok(thd);
4409
	      break;
4410 4411
	    }
	  }
4412
	}
4413
#endif
4414
	if (lex->spname->m_db.str)
unknown's avatar
unknown committed
4415
	  sp_result= SP_KEY_NOT_FOUND;
4416 4417 4418 4419 4420
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
4421
      }
unknown's avatar
unknown committed
4422 4423
      res= sp_result;
      switch (sp_result) {
4424
      case SP_OK:
4425
	my_ok(thd);
4426 4427
	break;
      case SP_KEY_NOT_FOUND:
4428 4429
	if (lex->drop_if_exists)
	{
4430
	  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
4431
			      ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
4432
			      SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4433
	  res= FALSE;
4434
	  my_ok(thd);
4435 4436
	  break;
	}
4437 4438
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4439 4440
	goto error;
      default:
4441 4442
	my_error(ER_SP_DROP_FAILED, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4443
	goto error;
4444
      }
4445
      break;
4446
    }
unknown's avatar
unknown committed
4447 4448
  case SQLCOM_SHOW_CREATE_PROC:
    {
unknown's avatar
unknown committed
4449 4450
      if (sp_show_create_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname))
      {
4451 4452
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4453 4454 4455 4456 4457 4458
	goto error;
      }
      break;
    }
  case SQLCOM_SHOW_CREATE_FUNC:
    {
unknown's avatar
unknown committed
4459 4460
      if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname))
      {
4461 4462
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4463 4464 4465 4466
	goto error;
      }
      break;
    }
unknown's avatar
unknown committed
4467 4468 4469 4470 4471 4472 4473
#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
4474 4475
        sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                            &thd->sp_proc_cache, FALSE);
unknown's avatar
unknown committed
4476
      else
unknown's avatar
unknown committed
4477 4478
        sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                            &thd->sp_func_cache, FALSE);
4479
      if (!sp || sp->show_routine_code(thd))
4480 4481
      {
        /* We don't distinguish between errors for now */
unknown's avatar
unknown committed
4482 4483 4484 4485 4486 4487 4488
        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
4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501
  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
4502 4503
  case SQLCOM_CREATE_VIEW:
    {
4504 4505 4506 4507
      /*
        Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands
        as specified through the thd->lex->create_view_mode flag.
      */
4508 4509 4510
      if (end_active_trans(thd))
        goto error;

4511
      res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
unknown's avatar
VIEW  
unknown committed
4512 4513 4514 4515
      break;
    }
  case SQLCOM_DROP_VIEW:
    {
4516
      if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE) ||
unknown's avatar
unknown committed
4517 4518
          end_active_trans(thd))
        goto error;
4519 4520
      /* Conditionally writes to binlog. */
      res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
unknown's avatar
VIEW  
unknown committed
4521 4522
      break;
    }
4523 4524
  case SQLCOM_CREATE_TRIGGER:
  {
4525 4526 4527
    if (end_active_trans(thd))
      goto error;

4528
    /* Conditionally writes to binlog. */
4529 4530
    res= mysql_create_or_drop_trigger(thd, all_tables, 1);

4531 4532 4533 4534
    break;
  }
  case SQLCOM_DROP_TRIGGER:
  {
4535 4536 4537
    if (end_active_trans(thd))
      goto error;

4538
    /* Conditionally writes to binlog. */
4539 4540 4541
    res= mysql_create_or_drop_trigger(thd, all_tables, 0);
    break;
  }
4542
  case SQLCOM_XA_START:
4543 4544
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
        thd->lex->xa_opt == XA_RESUME)
4545
    {
4546
      if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
4547 4548 4549 4550
      {
        my_error(ER_XAER_NOTA, MYF(0));
        break;
      }
4551
      thd->transaction.xid_state.xa_state=XA_ACTIVE;
4552
      my_ok(thd);
4553 4554
      break;
    }
unknown's avatar
unknown committed
4555
    if (thd->lex->xa_opt != XA_NONE)
4556 4557 4558 4559
    { // JOIN is not supported yet. TODO
      my_error(ER_XAER_INVAL, MYF(0));
      break;
    }
4560
    if (thd->transaction.xid_state.xa_state != XA_NOTR)
4561
    {
unknown's avatar
unknown committed
4562
      my_error(ER_XAER_RMFAIL, MYF(0),
4563
               xa_state_names[thd->transaction.xid_state.xa_state]);
4564 4565 4566 4567 4568 4569 4570
      break;
    }
    if (thd->active_transaction() || thd->locked_tables)
    {
      my_error(ER_XAER_OUTSIDE, MYF(0));
      break;
    }
4571 4572 4573 4574 4575 4576 4577
    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;
4578
    thd->transaction.xid_state.rm_error= 0;
4579 4580
    thd->transaction.xid_state.xid.set(thd->lex->xid);
    xid_cache_insert(&thd->transaction.xid_state);
unknown's avatar
unknown committed
4581
    thd->transaction.all.modified_non_trans_table= FALSE;
4582
    thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN);
4583
    thd->server_status|= SERVER_STATUS_IN_TRANS;
4584
    my_ok(thd);
4585 4586 4587 4588 4589 4590 4591 4592
    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;
    }
4593
    if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
4594
    {
unknown's avatar
unknown committed
4595
      my_error(ER_XAER_RMFAIL, MYF(0),
4596
               xa_state_names[thd->transaction.xid_state.xa_state]);
4597 4598
      break;
    }
4599
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4600 4601 4602 4603
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
4604 4605
    if (xa_trans_rolled_back(&thd->transaction.xid_state))
      break;
4606
    thd->transaction.xid_state.xa_state=XA_IDLE;
4607
    my_ok(thd);
4608 4609
    break;
  case SQLCOM_XA_PREPARE:
4610
    if (thd->transaction.xid_state.xa_state != XA_IDLE)
4611
    {
unknown's avatar
unknown committed
4612
      my_error(ER_XAER_RMFAIL, MYF(0),
4613
               xa_state_names[thd->transaction.xid_state.xa_state]);
4614 4615
      break;
    }
4616
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4617 4618 4619 4620 4621 4622 4623
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
    if (ha_prepare(thd))
    {
      my_error(ER_XA_RBROLLBACK, MYF(0));
4624 4625
      xid_cache_delete(&thd->transaction.xid_state);
      thd->transaction.xid_state.xa_state=XA_NOTR;
4626 4627
      break;
    }
4628
    thd->transaction.xid_state.xa_state=XA_PREPARED;
4629
    my_ok(thd);
4630 4631
    break;
  case SQLCOM_XA_COMMIT:
4632
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4633
    {
4634 4635
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
4636
        my_error(ER_XAER_NOTA, MYF(0));
4637 4638 4639 4640 4641 4642
      else if (xa_trans_rolled_back(xs))
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
        xid_cache_delete(xs);
        break;
      }
unknown's avatar
unknown committed
4643
      else
4644 4645 4646
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
        xid_cache_delete(xs);
4647
        my_ok(thd);
4648
      }
4649 4650
      break;
    }
4651 4652 4653 4654 4655
    if (xa_trans_rolled_back(&thd->transaction.xid_state))
    {
      xa_trans_rollback(thd);
      break;
    }
4656
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
unknown's avatar
unknown committed
4657
        thd->lex->xa_opt == XA_ONE_PHASE)
4658
    {
unknown's avatar
unknown committed
4659 4660 4661
      int r;
      if ((r= ha_commit(thd)))
        my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
4662
      else
4663
        my_ok(thd);
4664
    }
4665
    else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
unknown's avatar
unknown committed
4666
             thd->lex->xa_opt == XA_NONE)
4667
    {
4668 4669 4670
      if (wait_if_global_read_lock(thd, 0, 0))
      {
        ha_rollback(thd);
4671
        my_error(ER_XAER_RMERR, MYF(0));
4672
      }
4673
      else
4674 4675 4676 4677
      {
        if (ha_commit_one_phase(thd, 1))
          my_error(ER_XAER_RMERR, MYF(0));
        else
4678
          my_ok(thd);
4679 4680
        start_waiting_global_read_lock(thd);
      }
4681 4682 4683
    }
    else
    {
unknown's avatar
unknown committed
4684
      my_error(ER_XAER_RMFAIL, MYF(0),
4685
               xa_state_names[thd->transaction.xid_state.xa_state]);
4686 4687
      break;
    }
unknown's avatar
unknown committed
4688
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
unknown's avatar
unknown committed
4689
    thd->transaction.all.modified_non_trans_table= FALSE;
4690
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
4691 4692
    xid_cache_delete(&thd->transaction.xid_state);
    thd->transaction.xid_state.xa_state=XA_NOTR;
4693 4694
    break;
  case SQLCOM_XA_ROLLBACK:
4695
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4696
    {
4697 4698
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
4699
        my_error(ER_XAER_NOTA, MYF(0));
unknown's avatar
unknown committed
4700
      else
4701
      {
4702
        bool ok= !xa_trans_rolled_back(xs);
4703 4704
        ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
        xid_cache_delete(xs);
4705
        if (ok)
4706
          my_ok(thd);
4707
      }
4708 4709
      break;
    }
4710
    if (thd->transaction.xid_state.xa_state != XA_IDLE &&
4711 4712
        thd->transaction.xid_state.xa_state != XA_PREPARED &&
        thd->transaction.xid_state.xa_state != XA_ROLLBACK_ONLY)
4713
    {
unknown's avatar
unknown committed
4714
      my_error(ER_XAER_RMFAIL, MYF(0),
4715
               xa_state_names[thd->transaction.xid_state.xa_state]);
4716 4717
      break;
    }
4718
    if (xa_trans_rollback(thd))
4719 4720
      my_error(ER_XAER_RMERR, MYF(0));
    else
4721
      my_ok(thd);
4722 4723
    break;
  case SQLCOM_XA_RECOVER:
4724
    res= mysql_xa_recover(thd);
4725
    break;
unknown's avatar
unknown committed
4726 4727 4728 4729
  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)))
4730
      my_ok(thd);
unknown's avatar
unknown committed
4731 4732 4733 4734
    break;
  case SQLCOM_INSTALL_PLUGIN:
    if (! (res= mysql_install_plugin(thd, &thd->lex->comment,
                                     &thd->lex->ident)))
4735
      my_ok(thd);
unknown's avatar
unknown committed
4736 4737 4738
    break;
  case SQLCOM_UNINSTALL_PLUGIN:
    if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment)))
4739
      my_ok(thd);
unknown's avatar
unknown committed
4740 4741 4742 4743 4744 4745 4746 4747 4748 4749
    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
4750 4751 4752 4753 4754
  case SQLCOM_CREATE_SERVER:
  {
    int error;
    LEX *lex= thd->lex;
    DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER"));
unknown's avatar
unknown committed
4755 4756 4757 4758

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4759 4760
    if ((error= create_server(thd, &lex->server_options)))
    {
4761
      DBUG_PRINT("info", ("problem creating server <%s>",
unknown's avatar
unknown committed
4762 4763 4764 4765
                          lex->server_options.server_name));
      my_error(error, MYF(0), lex->server_options.server_name);
      break;
    }
4766
    my_ok(thd, 1);
unknown's avatar
unknown committed
4767 4768 4769 4770 4771 4772 4773
    break;
  }
  case SQLCOM_ALTER_SERVER:
  {
    int error;
    LEX *lex= thd->lex;
    DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER"));
unknown's avatar
unknown committed
4774 4775 4776 4777

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4778 4779
    if ((error= alter_server(thd, &lex->server_options)))
    {
4780
      DBUG_PRINT("info", ("problem altering server <%s>",
unknown's avatar
unknown committed
4781 4782 4783 4784
                          lex->server_options.server_name));
      my_error(error, MYF(0), lex->server_options.server_name);
      break;
    }
4785
    my_ok(thd, 1);
unknown's avatar
unknown committed
4786 4787 4788 4789 4790 4791 4792
    break;
  }
  case SQLCOM_DROP_SERVER:
  {
    int err_code;
    LEX *lex= thd->lex;
    DBUG_PRINT("info", ("case SQLCOM_DROP_SERVER"));
unknown's avatar
unknown committed
4793 4794 4795 4796

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4797 4798
    if ((err_code= drop_server(thd, &lex->server_options)))
    {
unknown's avatar
unknown committed
4799
      if (! lex->drop_if_exists && err_code == ER_FOREIGN_SERVER_DOESNT_EXIST)
unknown's avatar
unknown committed
4800 4801 4802 4803 4804 4805 4806
      {
        DBUG_PRINT("info", ("problem dropping server %s",
                            lex->server_options.server_name));
        my_error(err_code, MYF(0), lex->server_options.server_name);
      }
      else
      {
4807
        my_ok(thd, 0);
unknown's avatar
unknown committed
4808 4809 4810
      }
      break;
    }
4811
    my_ok(thd, 1);
unknown's avatar
unknown committed
4812 4813
    break;
  }
4814
  default:
4815
#ifndef EMBEDDED_LIBRARY
4816
    DBUG_ASSERT(0);                             /* Impossible */
4817
#endif
4818
    my_ok(thd);
unknown's avatar
unknown committed
4819 4820
    break;
  }
4821
  thd_proc_info(thd, "query end");
4822 4823

  /*
unknown's avatar
unknown committed
4824
    Binlog-related cleanup:
4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835
    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);

4836
  /*
4837 4838
    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
4839 4840 4841 4842
    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))
4843
    thd->row_count_func= -1;
4844

4845
  goto finish;
unknown's avatar
unknown committed
4846 4847

error:
4848 4849
  res= TRUE;

4850
finish:
4851 4852 4853 4854 4855 4856 4857 4858
  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);
  }
4859
  DBUG_RETURN(res || thd->is_error());
unknown's avatar
unknown committed
4860 4861 4862
}


4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885
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()))
4886
        return 1;                               /* purecov: inspected */
4887 4888 4889 4890 4891 4892 4893
      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);
4894
        thd->lex->unit.print(&str, QT_ORDINARY);
4895 4896 4897 4898
        str.append('\0');
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
                     ER_YES, str.ptr());
      }
4899 4900 4901 4902
      if (res)
        result->abort();
      else
        result->send_eof();
4903 4904 4905 4906 4907
      delete result;
    }
    else
    {
      if (!result && !(result= new select_send()))
4908
        return 1;                               /* purecov: inspected */
4909 4910 4911 4912 4913 4914 4915 4916 4917 4918
      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
4919
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
4920
/**
4921
  Check grants for commands which work only with one table.
unknown's avatar
unknown committed
4922

4923 4924 4925
  @param thd                    Thread handler
  @param privilege              requested privilege
  @param all_tables             global table list of query
unknown's avatar
unknown committed
4926
  @param no_errors              FALSE/TRUE - report/don't report error to
4927
                            the client (using my_error() call).
unknown's avatar
unknown committed
4928 4929 4930 4931 4932

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

4935
bool check_single_table_access(THD *thd, ulong privilege, 
4936
                               TABLE_LIST *all_tables, bool no_errors)
unknown's avatar
unknown committed
4937
{
4938 4939 4940 4941 4942 4943
  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;

4944 4945 4946 4947 4948 4949 4950 4951
  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,
4952
		   &all_tables->grant.privilege, 0, no_errors,
4953
                   test(all_tables->schema_table)))
4954
    goto deny;
unknown's avatar
unknown committed
4955

unknown's avatar
unknown committed
4956
  /* Show only 1 table for check_grant */
4957
  if (!(all_tables->belong_to_view &&
4958
        (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
4959 4960
      !(all_tables->view &&
        all_tables->effective_algorithm == VIEW_ALGORITHM_TMPTABLE) &&
4961
      check_grant(thd, privilege, all_tables, 0, 1, no_errors))
4962 4963 4964
    goto deny;

  thd->security_ctx= backup_ctx;
4965 4966 4967 4968 4969 4970 4971
  return 0;

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

unknown's avatar
unknown committed
4972
/**
4973 4974 4975
  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
4976 4977 4978 4979 4980 4981 4982 4983
  @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
4984 4985 4986 4987
*/

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

4991
  /* Check rights on tables of subselects and implictly opened tables */
unknown's avatar
unknown committed
4992
  TABLE_LIST *subselects_tables, *view= all_tables->view ? all_tables : 0;
unknown's avatar
VIEW  
unknown committed
4993
  if ((subselects_tables= all_tables->next_global))
unknown's avatar
unknown committed
4994
  {
unknown's avatar
unknown committed
4995 4996 4997 4998 4999 5000
    /*
      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)
    {
5001
      if (check_single_table_access (thd, privilege, subselects_tables, FALSE))
unknown's avatar
unknown committed
5002 5003 5004 5005
        return 1;
      subselects_tables= subselects_tables->next_global;
    }
    if (subselects_tables &&
5006
        (check_table_access(thd, SELECT_ACL, subselects_tables, UINT_MAX, FALSE)))
5007
      return 1;
unknown's avatar
unknown committed
5008 5009
  }
  return 0;
unknown's avatar
unknown committed
5010 5011 5012
}


unknown's avatar
unknown committed
5013 5014
/**
  Get the user (global) and database privileges for all used tables.
unknown's avatar
unknown committed
5015

unknown's avatar
unknown committed
5016 5017 5018 5019
  @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
5020

unknown's avatar
unknown committed
5021
  @note
unknown's avatar
unknown committed
5022 5023 5024 5025 5026
    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
5027
  @retval
unknown's avatar
unknown committed
5028
    0  ok
unknown's avatar
unknown committed
5029 5030 5031 5032
  @retval
    1  If we can't get the privileges and we don't use table/column
    grants.
*/
unknown's avatar
unknown committed
5033
bool
unknown's avatar
unknown committed
5034
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
5035
	     bool dont_check_global_grants, bool no_errors, bool schema_db)
unknown's avatar
unknown committed
5036
{
5037
  Security_context *sctx= thd->security_ctx;
unknown's avatar
unknown committed
5038
  ulong db_access;
5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049
  /*
    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
5050
  ulong dummy;
5051 5052
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("db: %s  want_access: %lu  master_access: %lu",
5053
                      db ? db : "", want_access, sctx->master_access));
unknown's avatar
unknown committed
5054 5055 5056 5057 5058
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

5059
  thd_proc_info(thd, "checking permissions");
5060
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
5061
  {
5062
    DBUG_PRINT("error",("No database"));
5063
    if (!no_errors)
unknown's avatar
unknown committed
5064 5065
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
                 MYF(0));                       /* purecov: tested */
unknown's avatar
unknown committed
5066
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
5067 5068
  }

5069 5070
  if (schema_db)
  {
5071 5072
    if (!(sctx->master_access & FILE_ACL) && (want_access & FILE_ACL) ||
        (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
5073 5074
    {
      if (!no_errors)
5075 5076
      {
        const char *db_name= db ? db : thd->db;
5077
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
5078 5079
                 sctx->priv_user, sctx->priv_host, db_name);
      }
5080 5081 5082 5083 5084 5085 5086 5087 5088
      DBUG_RETURN(TRUE);
    }
    else
    {
      *save_priv= SELECT_ACL;
      DBUG_RETURN(FALSE);
    }
  }

5089
  if ((sctx->master_access & want_access) == want_access)
unknown's avatar
unknown committed
5090
  {
5091 5092 5093 5094 5095
    /*
      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
    */
5096 5097
    db_access= sctx->db_access;
    if (!(sctx->master_access & SELECT_ACL) &&
unknown's avatar
unknown committed
5098
	(db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
5099 5100 5101
      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
5102
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
5103
  }
5104
  if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
5105
      ! db && dont_check_global_grants)
unknown's avatar
unknown committed
5106
  {						// We can never grant this
5107
    DBUG_PRINT("error",("No possible access"));
5108
    if (!no_errors)
5109
      my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
5110 5111
               sctx->priv_user,
               sctx->priv_host,
5112 5113 5114
               (thd->password ?
                ER(ER_YES) :
                ER(ER_NO)));                    /* purecov: tested */
unknown's avatar
unknown committed
5115
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
5116 5117 5118
  }

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

unknown's avatar
unknown committed
5121
  if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
5122 5123
    db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
                       db_is_pattern);
unknown's avatar
unknown committed
5124
  else
5125
    db_access= sctx->db_access;
5126
  DBUG_PRINT("info",("db_access: %lu", db_access));
unknown's avatar
unknown committed
5127
  /* Remove SHOW attribute and access rights we already have */
5128
  want_access &= ~(sctx->master_access | EXTRA_ACL);
5129 5130
  DBUG_PRINT("info",("db_access: %lu  want_access: %lu",
                     db_access, want_access));
5131
  db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
5132

unknown's avatar
unknown committed
5133
  if (db_access == want_access ||
5134
      (!dont_check_global_grants &&
5135
       !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
unknown's avatar
unknown committed
5136
    DBUG_RETURN(FALSE);				/* Ok */
5137 5138

  DBUG_PRINT("error",("Access denied"));
5139
  if (!no_errors)
5140
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
5141
             sctx->priv_user, sctx->priv_host,
5142 5143 5144
             (db ? db : (thd->db ?
                         thd->db :
                         "unknown")));          /* purecov: tested */
unknown's avatar
unknown committed
5145
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
5146 5147 5148
}


5149 5150
static bool check_show_access(THD *thd, TABLE_LIST *table)
{
unknown's avatar
unknown committed
5151
  switch (get_schema_table_idx(table->schema_table)) {
5152 5153
  case SCH_SCHEMATA:
    return (specialflag & SPECIAL_SKIP_SHOW_DB) &&
unknown's avatar
unknown committed
5154
      check_global_access(thd, SHOW_DB_ACL);
5155 5156 5157 5158 5159

  case SCH_TABLE_NAMES:
  case SCH_TABLES:
  case SCH_VIEWS:
  case SCH_TRIGGERS:
unknown's avatar
unknown committed
5160 5161 5162
  case SCH_EVENTS:
  {
    const char *dst_db_name= table->schema_select_lex->db;
5163

unknown's avatar
unknown committed
5164
    DBUG_ASSERT(dst_db_name);
5165

unknown's avatar
unknown committed
5166 5167 5168 5169
    if (check_access(thd, SELECT_ACL, dst_db_name,
                     &thd->col_access, FALSE, FALSE,
                     is_schema_db(dst_db_name)))
      return TRUE;
5170

unknown's avatar
unknown committed
5171 5172 5173 5174 5175 5176 5177
    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;
5178 5179
    }

unknown's avatar
unknown committed
5180 5181 5182
    return FALSE;
  }

5183 5184
  case SCH_COLUMNS:
  case SCH_STATISTICS:
unknown's avatar
unknown committed
5185 5186 5187
  {
    TABLE_LIST *dst_table;
    dst_table= (TABLE_LIST *) table->schema_select_lex->table_list.first;
5188

unknown's avatar
unknown committed
5189
    DBUG_ASSERT(dst_table);
5190

unknown's avatar
unknown committed
5191 5192 5193 5194 5195 5196
    if (check_access(thd, SELECT_ACL | EXTRA_ACL,
                     dst_table->db,
                     &dst_table->grant.privilege,
                     FALSE, FALSE,
                     test(dst_table->schema_table)))
      return FALSE;
5197

5198
    return (check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE));
unknown's avatar
unknown committed
5199 5200
  }
  default:
5201 5202 5203 5204 5205 5206 5207
    break;
  }

  return FALSE;
}


unknown's avatar
unknown committed
5208
/**
5209 5210
  Check the privilege for all used tables.

5211 5212 5213 5214 5215 5216
  @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).
5217

unknown's avatar
unknown committed
5218
  @note
5219 5220 5221 5222 5223 5224
    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).

5225 5226
  @retval  FALSE   OK
  @retval  TRUE    Access denied
unknown's avatar
unknown committed
5227 5228
*/

5229
bool
unknown's avatar
unknown committed
5230
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
5231
		   uint number, bool no_errors)
unknown's avatar
unknown committed
5232
{
5233 5234
  TABLE_LIST *org_tables= tables;
  TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
5235
  uint i= 0;
5236
  Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx;
5237
  /*
unknown's avatar
unknown committed
5238 5239 5240
    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.
5241
  */
5242 5243
  for (; i < number && tables != first_not_own_table;
       tables= tables->next_global, i++)
unknown's avatar
unknown committed
5244
  {
5245 5246 5247 5248 5249
    if (tables->security_ctx)
      sctx= tables->security_ctx;
    else
      sctx= backup_ctx;

5250
    if (tables->schema_table && 
5251
        (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
5252 5253 5254
    {
      if (!no_errors)
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
5255
                 sctx->priv_user, sctx->priv_host,
5256
                 INFORMATION_SCHEMA_NAME.str);
5257 5258
      return TRUE;
    }
5259 5260 5261 5262 5263
    /*
       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
5264 5265 5266 5267 5268 5269 5270 5271 5272

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

      continue;
    }

5273
    if (tables->is_anonymous_derived_table() ||
5274
        (tables->table && (int)tables->table->s->tmp_table))
unknown's avatar
unknown committed
5275
      continue;
5276 5277
    thd->security_ctx= sctx;
    if ((sctx->master_access & want_access) ==
5278
        (want_access & ~EXTRA_ACL) &&
unknown's avatar
unknown committed
5279
	thd->db)
unknown's avatar
unknown committed
5280
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
5281
    else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
unknown's avatar
unknown committed
5282
    {
5283 5284 5285
      if (check_access(thd, want_access, tables->get_db_name(),
                       &tables->grant.privilege, 0, no_errors, 
                       test(tables->schema_table)))
5286
        goto deny;                            // Access denied
unknown's avatar
unknown committed
5287
    }
5288 5289 5290
    else if (check_access(thd, want_access, tables->get_db_name(),
                          &tables->grant.privilege, 0, no_errors, 
                          test(tables->schema_table)))
5291
      goto deny;
unknown's avatar
unknown committed
5292
  }
5293
  thd->security_ctx= backup_ctx;
5294
  return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
5295
		       test(want_access & EXTRA_ACL), number, no_errors);
5296 5297 5298
deny:
  thd->security_ctx= backup_ctx;
  return TRUE;
unknown's avatar
unknown committed
5299 5300
}

5301

5302
bool
5303 5304
check_routine_access(THD *thd, ulong want_access,char *db, char *name,
		     bool is_proc, bool no_errors)
5305 5306 5307 5308 5309
{
  TABLE_LIST tables[1];
  
  bzero((char *)tables, sizeof(TABLE_LIST));
  tables->db= db;
5310
  tables->table_name= tables->alias= name;
5311
  
unknown's avatar
unknown committed
5312 5313 5314 5315 5316 5317 5318
  /*
    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)
5319 5320
    tables->grant.privilege= want_access;
  else if (check_access(thd,want_access,db,&tables->grant.privilege,
unknown's avatar
unknown committed
5321
			0, no_errors, 0))
5322 5323
    return TRUE;
  
5324
    return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
5325 5326
}

5327

unknown's avatar
unknown committed
5328 5329
/**
  Check if the routine has any of the routine privileges.
5330

unknown's avatar
unknown committed
5331 5332 5333
  @param thd	       Thread handler
  @param db           Database name
  @param name         Routine name
5334

unknown's avatar
unknown committed
5335
  @retval
5336
    0            ok
unknown's avatar
unknown committed
5337
  @retval
5338 5339 5340
    1            error
*/

5341 5342
bool check_some_routine_access(THD *thd, const char *db, const char *name,
                               bool is_proc)
5343 5344
{
  ulong save_priv;
5345
  if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
5346
    return FALSE;
5347 5348 5349 5350 5351
  /*
    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) ||
5352 5353
      (save_priv & SHOW_PROC_ACLS))
    return FALSE;
5354
  return check_routine_level_acl(thd, db, name, is_proc);
5355 5356 5357
}


5358 5359 5360
/*
  Check if the given table has any of the asked privileges

unknown's avatar
unknown committed
5361 5362
  @param thd		 Thread handler
  @param want_access	 Bitmap of possible privileges to check for
5363

unknown's avatar
unknown committed
5364
  @retval
5365
    0  ok
unknown's avatar
unknown committed
5366
  @retval
5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380
    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,
5381 5382
                        &table->grant.privilege, 0, 1,
                        test(table->schema_table)) &&
5383
          !check_grant(thd, access, table, 0, 1, 1))
5384 5385 5386 5387 5388 5389 5390
        DBUG_RETURN(0);
    }
  }
  DBUG_PRINT("exit",("no matching access rights"));
  DBUG_RETURN(1);
}

unknown's avatar
unknown committed
5391
#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
5392

5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425

/**
  check for global access and give descriptive error message if it fails.

  @param thd			Thread handler
  @param want_access		Use should have any of these global rights

  @warning
    One gets access right if one has ANY of the rights in want_access.
    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.

  @retval
    0	ok
  @retval
    1	Access denied.  In this case an error is sent to the client
*/

bool check_global_access(THD *thd, ulong want_access)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  char command[128];
  if ((thd->security_ctx->master_access & want_access))
    return 0;
  get_privilege_desc(command, sizeof(command), want_access);
  my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
  return 1;
#else
  return 0;
#endif
}

unknown's avatar
unknown committed
5426 5427 5428 5429
/****************************************************************************
	Check stack size; Send error if there isn't enough stack to continue
****************************************************************************/

5430 5431
#ifndef EMBEDDED_LIBRARY

unknown's avatar
unknown committed
5432 5433 5434 5435 5436 5437
#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
5438 5439 5440 5441
#ifndef DBUG_OFF
long max_stack_used;
#endif

unknown's avatar
unknown committed
5442 5443
/**
  @note
5444 5445 5446 5447
  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
5448
*/
5449
bool check_stack_overrun(THD *thd, long margin,
5450
			 uchar *buf __attribute__((unused)))
unknown's avatar
unknown committed
5451 5452
{
  long stack_used;
5453
  DBUG_ASSERT(thd == current_thd);
unknown's avatar
unknown committed
5454
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
5455
      (long) (my_thread_stack_size - margin))
unknown's avatar
unknown committed
5456
  {
5457 5458 5459 5460
    char ebuff[MYSQL_ERRMSG_SIZE];
    my_snprintf(ebuff, sizeof(ebuff), ER(ER_STACK_OVERRUN_NEED_MORE),
                stack_used, my_thread_stack_size, margin);
    my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR));
5461
    thd->fatal_error();
unknown's avatar
unknown committed
5462 5463
    return 1;
  }
unknown's avatar
unknown committed
5464 5465 5466
#ifndef DBUG_OFF
  max_stack_used= max(max_stack_used, stack_used);
#endif
unknown's avatar
unknown committed
5467 5468
  return 0;
}
5469
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
5470 5471 5472 5473

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

5474
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
unknown's avatar
unknown committed
5475
{
5476
  Yacc_state *state= & current_thd->m_parser_state->m_yacc;
5477
  ulong old_info=0;
5478
  DBUG_ASSERT(state);
unknown's avatar
unknown committed
5479 5480
  if ((uint) *yystacksize >= MY_YACC_MAX)
    return 1;
5481
  if (!state->yacc_yyvs)
unknown's avatar
unknown committed
5482 5483
    old_info= *yystacksize;
  *yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX);
5484
  if (!(state->yacc_yyvs= (uchar*)
5485
        my_realloc(state->yacc_yyvs,
5486 5487 5488
                   *yystacksize*sizeof(**yyvs),
                   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
      !(state->yacc_yyss= (uchar*)
5489
        my_realloc(state->yacc_yyss,
5490 5491
                   *yystacksize*sizeof(**yyss),
                   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
unknown's avatar
unknown committed
5492 5493
    return 1;
  if (old_info)
5494 5495 5496 5497 5498 5499 5500 5501
  {
    /*
      Only copy the old stack on the first call to my_yyoverflow(),
      when replacing a static stack (YYINITDEPTH) by a dynamic stack.
      For subsequent calls, my_realloc already did preserve the old stack.
    */
    memcpy(state->yacc_yyss, *yyss, old_info*sizeof(**yyss));
    memcpy(state->yacc_yyvs, *yyvs, old_info*sizeof(**yyvs));
unknown's avatar
unknown committed
5502
  }
5503 5504
  *yyss= (short*) state->yacc_yyss;
  *yyvs= (YYSTYPE*) state->yacc_yyvs;
unknown's avatar
unknown committed
5505 5506 5507 5508
  return 0;
}


unknown's avatar
unknown committed
5509
/**
5510 5511 5512 5513
 Reset THD part responsible for command processing state.

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

unknown's avatar
unknown committed
5516
  @todo
5517 5518
   Make it a method of THD and align its name with the rest of
   reset/end/start/init methods.
unknown's avatar
unknown committed
5519
  @todo
5520 5521 5522 5523 5524 5525
   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");
5526
  DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
5527
  DBUG_ASSERT(! thd->in_sub_stmt);
5528
  thd->free_list= 0;
5529
  thd->select_number= 1;
5530 5531 5532 5533
  /*
    Those two lines below are theoretically unneeded as
    THD::cleanup_after_query() should take care of this already.
  */
5534
  thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty();
5535 5536 5537
  thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;

  thd->query_start_used= 0;
5538
  thd->is_fatal_error= thd->time_zone_used= 0;
5539 5540 5541 5542 5543
  /*
    Clear the status flag that are expected to be cleared at the
    beginning of each SQL statement.
  */
  thd->server_status&= ~SERVER_STATUS_CLEAR_SET;
5544 5545 5546 5547 5548 5549
  /*
    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
5550 5551
  {
    thd->options&= ~OPTION_KEEP_LOG;
5552
    thd->transaction.all.modified_non_trans_table= FALSE;
unknown's avatar
unknown committed
5553
  }
5554
  DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
unknown's avatar
unknown committed
5555
  thd->thread_specific_used= FALSE;
5556 5557

  if (opt_bin_log)
5558
  {
5559 5560
    reset_dynamic(&thd->user_var_events);
    thd->user_var_events_alloc= thd->mem_root;
5561
  }
5562 5563 5564 5565 5566 5567
  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;

5568 5569 5570 5571
  /*
    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
5572 5573
  thd->reset_current_stmt_binlog_row_based();

5574 5575 5576 5577
  DBUG_PRINT("debug",
             ("current_stmt_binlog_row_based: %d",
              thd->current_stmt_binlog_row_based));

unknown's avatar
unknown committed
5578 5579 5580
  DBUG_VOID_RETURN;
}

5581

5582 5583 5584
void
mysql_init_select(LEX *lex)
{
unknown's avatar
unknown committed
5585
  SELECT_LEX *select_lex= lex->current_select;
unknown's avatar
unknown committed
5586
  select_lex->init_select();
5587
  lex->wild= 0;
5588 5589
  if (select_lex == &lex->select_lex)
  {
5590
    DBUG_ASSERT(lex->result == 0);
5591 5592
    lex->exchange= 0;
  }
5593 5594
}

5595

unknown's avatar
unknown committed
5596
bool
unknown's avatar
unknown committed
5597
mysql_new_select(LEX *lex, bool move_down)
5598
{
unknown's avatar
unknown committed
5599
  SELECT_LEX *select_lex;
5600
  THD *thd= lex->thd;
unknown's avatar
unknown committed
5601 5602
  DBUG_ENTER("mysql_new_select");

5603
  if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
5604
    DBUG_RETURN(1);
5605
  select_lex->select_number= ++thd->select_number;
unknown's avatar
unknown committed
5606
  select_lex->parent_lex= lex; /* Used in init_query. */
unknown's avatar
unknown committed
5607 5608
  select_lex->init_query();
  select_lex->init_select();
unknown's avatar
unknown committed
5609
  lex->nest_level++;
unknown's avatar
unknown committed
5610 5611 5612 5613 5614
  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
5615
  select_lex->nest_level= lex->nest_level;
5616 5617 5618 5619 5620
  /*
    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
5621
  if (thd->stmt_arena->is_stmt_prepare())
5622
    select_lex->uncacheable|= UNCACHEABLE_PREPARE;
unknown's avatar
unknown committed
5623 5624
  if (move_down)
  {
unknown's avatar
unknown committed
5625
    SELECT_LEX_UNIT *unit;
5626
    lex->subqueries= TRUE;
unknown's avatar
unknown committed
5627
    /* first select_lex of subselect or derived table */
5628
    if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
unknown's avatar
unknown committed
5629
      DBUG_RETURN(1);
unknown's avatar
unknown committed
5630

unknown's avatar
unknown committed
5631 5632
    unit->init_query();
    unit->init_select();
5633
    unit->thd= thd;
unknown's avatar
unknown committed
5634
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
5635 5636
    unit->link_next= 0;
    unit->link_prev= 0;
5637
    unit->return_to= lex->current_select;
unknown's avatar
unknown committed
5638
    select_lex->include_down(unit);
5639 5640 5641 5642 5643
    /*
      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
5644 5645
  }
  else
unknown's avatar
unknown committed
5646
  {
unknown's avatar
VIEW  
unknown committed
5647 5648
    if (lex->current_select->order_list.first && !lex->current_select->braces)
    {
unknown's avatar
unknown committed
5649
      my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
unknown's avatar
unknown committed
5650
      DBUG_RETURN(1);
unknown's avatar
VIEW  
unknown committed
5651
    }
5652
    select_lex->include_neighbour(lex->current_select);
5653 5654 5655 5656 5657
    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
5658
  }
unknown's avatar
unknown committed
5659

5660
  select_lex->master_unit()->global_parameters= select_lex;
5661
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
5662
  lex->current_select= select_lex;
5663 5664 5665 5666 5667
  /*
    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
5668
  DBUG_RETURN(0);
5669
}
unknown's avatar
unknown committed
5670

unknown's avatar
unknown committed
5671
/**
5672 5673
  Create a select to return the same output as 'SELECT @@var_name'.

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

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

unknown's avatar
unknown committed
5678
  @param var_name		Variable name
5679 5680 5681 5682
*/

void create_select_for_variable(const char *var_name)
{
5683
  THD *thd;
5684
  LEX *lex;
5685
  LEX_STRING tmp, null_lex_string;
5686 5687
  Item *var;
  char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end;
5688
  DBUG_ENTER("create_select_for_variable");
5689 5690

  thd= current_thd;
unknown's avatar
unknown committed
5691
  lex= thd->lex;
5692 5693 5694 5695
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
5696
  bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
5697 5698 5699 5700
  /*
    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
5701 5702 5703 5704 5705 5706
  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);
  }
5707 5708 5709
  DBUG_VOID_RETURN;
}

5710

unknown's avatar
unknown committed
5711 5712
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
5713
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
5714
  mysql_init_select(lex);
5715 5716
  lex->select_lex.select_limit= 0;
  lex->unit.select_limit_cnt= HA_POS_ERROR;
unknown's avatar
unknown committed
5717
  lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list);
5718
  lex->lock_option= TL_READ_DEFAULT;
unknown's avatar
VIEW  
unknown committed
5719 5720
  lex->query_tables= 0;
  lex->query_tables_last= &lex->query_tables;
unknown's avatar
unknown committed
5721
}
unknown's avatar
unknown committed
5722

5723

5724 5725 5726 5727
/*
  When you modify mysql_parse(), you may need to mofify
  mysql_test_parse_for_slave() in this same file.
*/
unknown's avatar
unknown committed
5728

5729 5730
/**
  Parse a query.
unknown's avatar
unknown committed
5731 5732 5733 5734 5735 5736

  @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.
5737 5738 5739 5740
*/

void mysql_parse(THD *thd, const char *inBuf, uint length,
                 const char ** found_semicolon)
unknown's avatar
unknown committed
5741 5742
{
  DBUG_ENTER("mysql_parse");
5743 5744 5745

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

5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763
  /*
    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);
5764

5765
  if (query_cache_send_result_to_client(thd, (char*) inBuf, length) <= 0)
unknown's avatar
unknown committed
5766
  {
unknown's avatar
unknown committed
5767
    LEX *lex= thd->lex;
5768

5769 5770
    sp_cache_flush_obsolete(&thd->sp_proc_cache);
    sp_cache_flush_obsolete(&thd->sp_func_cache);
5771

5772
    Parser_state parser_state(thd, inBuf, length);
5773

5774
    bool err= parse_sql(thd, & parser_state, NULL);
5775
    *found_semicolon= parser_state.m_lip.found_semicolon;
5776

5777
    if (!err)
unknown's avatar
unknown committed
5778
    {
unknown's avatar
unknown committed
5779
#ifndef NO_EMBEDDED_ACCESS_CHECKS
5780
      if (mqh_used && thd->user_connect &&
5781
	  check_mqh(thd, lex->sql_command))
5782 5783 5784 5785
      {
	thd->net.error = 0;
      }
      else
unknown's avatar
unknown committed
5786
#endif
5787
      {
5788
	if (! thd->is_error())
unknown's avatar
unknown committed
5789
	{
5790 5791 5792 5793 5794 5795 5796 5797 5798 5799
          /*
            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.
          */
5800 5801
          if (*found_semicolon &&
              (thd->query_length= (ulong)(*found_semicolon - thd->query)))
5802 5803
            thd->query_length--;
          /* Actually execute the query */
5804 5805 5806 5807 5808
          if (*found_semicolon)
          {
            lex->safe_to_cache_query= 0;
            thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
          }
5809 5810
          lex->set_trg_event_type_for_tables();
          mysql_execute_command(thd);
unknown's avatar
unknown committed
5811
	}
5812
      }
unknown's avatar
unknown committed
5813 5814
    }
    else
5815
    {
5816
      DBUG_ASSERT(thd->is_error());
5817
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
5818
			 thd->is_fatal_error));
5819 5820

      query_cache_abort(&thd->net);
5821
    }
5822 5823 5824 5825 5826 5827
    if (thd->lex->sphead)
    {
      delete thd->lex->sphead;
      thd->lex->sphead= 0;
    }
    lex->unit.cleanup();
5828
    thd_proc_info(thd, "freeing items");
5829
    thd->end_statement();
5830
    thd->cleanup_after_query();
5831
    DBUG_ASSERT(thd->change_list.is_empty());
unknown's avatar
unknown committed
5832
  }
5833 5834 5835 5836 5837 5838
  else
  {
    /* There are no multi queries in the cache. */
    *found_semicolon= NULL;
  }

unknown's avatar
unknown committed
5839 5840 5841 5842
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
5843
#ifdef HAVE_REPLICATION
5844 5845 5846 5847
/*
  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
5848
  @retval
5849
    0	cannot be ignored
unknown's avatar
unknown committed
5850
  @retval
5851 5852 5853 5854 5855
    1	can be ignored
*/

bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
{
unknown's avatar
unknown committed
5856
  LEX *lex= thd->lex;
5857
  bool error= 0;
unknown's avatar
unknown committed
5858
  DBUG_ENTER("mysql_test_parse_for_slave");
5859

5860
  Parser_state parser_state(thd, inBuf, length);
5861 5862 5863
  lex_start(thd);
  mysql_reset_thd_for_next_command(thd);

5864
  if (!parse_sql(thd, & parser_state, NULL) &&
5865
      all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
unknown's avatar
unknown committed
5866
    error= 1;                  /* Ignore question */
5867
  thd->end_statement();
5868
  thd->cleanup_after_query();
unknown's avatar
unknown committed
5869
  DBUG_RETURN(error);
5870
}
unknown's avatar
unknown committed
5871
#endif
unknown's avatar
unknown committed
5872

5873

unknown's avatar
unknown committed
5874

unknown's avatar
unknown committed
5875 5876 5877 5878 5879 5880
/**
  Store field definition for create.

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

5882
bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
unknown's avatar
unknown committed
5883
		       char *length, char *decimals,
5884
		       uint type_modifier,
5885 5886
		       Item *default_value, Item *on_update_value,
                       LEX_STRING *comment,
5887 5888
		       char *change,
                       List<String> *interval_list, CHARSET_INFO *cs,
unknown's avatar
unknown committed
5889
		       uint uint_geom_type)
unknown's avatar
unknown committed
5890
{
unknown's avatar
unknown committed
5891
  register Create_field *new_field;
unknown's avatar
unknown committed
5892
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
5893 5894
  DBUG_ENTER("add_field_to_list");

5895 5896
  if (check_string_char_length(field_name, "", NAME_CHAR_LEN,
                               system_charset_info, 1))
unknown's avatar
unknown committed
5897
  {
5898
    my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */
unknown's avatar
unknown committed
5899 5900 5901 5902
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
5903
    Key *key;
unknown's avatar
unknown committed
5904
    lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
5905 5906 5907 5908
    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
5909 5910 5911 5912
    lex->col_list.empty();
  }
  if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
  {
5913
    Key *key;
unknown's avatar
unknown committed
5914
    lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
5915 5916 5917 5918
    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
5919 5920 5921
    lex->col_list.empty();
  }

5922
  if (default_value)
unknown's avatar
unknown committed
5923
  {
5924
    /* 
unknown's avatar
unknown committed
5925 5926
      Default value should be literal => basic constants =>
      no need fix_fields()
5927 5928 5929
      
      We allow only one function as part of default value - 
      NOW() as default for TIMESTAMP type.
5930
    */
5931 5932
    if (default_value->type() == Item::FUNC_ITEM && 
        !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
5933
         type == MYSQL_TYPE_TIMESTAMP))
5934
    {
5935
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5936 5937 5938
      DBUG_RETURN(1);
    }
    else if (default_value->type() == Item::NULL_ITEM)
unknown's avatar
unknown committed
5939
    {
5940
      default_value= 0;
5941 5942 5943
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
5944
	my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5945 5946 5947 5948 5949
	DBUG_RETURN(1);
      }
    }
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
5950
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
unknown's avatar
unknown committed
5951 5952 5953
      DBUG_RETURN(1);
    }
  }
5954

5955
  if (on_update_value && type != MYSQL_TYPE_TIMESTAMP)
5956
  {
5957
    my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
5958 5959
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
5960

5961
  if (type == MYSQL_TYPE_TIMESTAMP && length)
5962 5963 5964 5965 5966
  {
    /* 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
5967
    char buf[32];
5968
    my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length);
unknown's avatar
unknown committed
5969
    WARN_DEPRECATED(thd, "5.2", buf, "'TIMESTAMP'");
5970 5971
  }

unknown's avatar
unknown committed
5972
  if (!(new_field= new Create_field()) ||
5973
      new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
5974 5975
                      default_value, on_update_value, comment, change,
                      interval_list, cs, uint_geom_type))
unknown's avatar
unknown committed
5976
    DBUG_RETURN(1);
unknown's avatar
unknown committed
5977

5978
  lex->alter_info.create_list.push_back(new_field);
unknown's avatar
unknown committed
5979 5980 5981 5982
  lex->last_field=new_field;
  DBUG_RETURN(0);
}

5983

unknown's avatar
unknown committed
5984
/** Store position for column in ALTER TABLE .. ADD column. */
unknown's avatar
unknown committed
5985 5986 5987

void store_position_for_column(const char *name)
{
5988
  current_thd->lex->last_field->after=my_const_cast(char*) (name);
unknown's avatar
unknown committed
5989 5990 5991
}

bool
unknown's avatar
unknown committed
5992
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
5993 5994 5995 5996
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
5997
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
5998 5999 6000 6001 6002
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
6003
  thd->lex->proc_list.link_in_list((uchar*) order,(uchar**) &order->next);
unknown's avatar
unknown committed
6004 6005 6006 6007
  return 0;
}


unknown's avatar
unknown committed
6008 6009 6010
/**
  save order by and tables in own lists.
*/
unknown's avatar
unknown committed
6011

unknown's avatar
unknown committed
6012
bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
unknown's avatar
unknown committed
6013 6014 6015
{
  ORDER *order;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
6016
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER))))
unknown's avatar
unknown committed
6017
    DBUG_RETURN(1);
unknown's avatar
unknown committed
6018 6019
  order->item_ptr= item;
  order->item= &order->item_ptr;
unknown's avatar
unknown committed
6020 6021 6022
  order->asc = asc;
  order->free_me=0;
  order->used=0;
6023
  order->counter_used= 0;
6024
  list.link_in_list((uchar*) order,(uchar**) &order->next);
unknown's avatar
unknown committed
6025 6026 6027 6028
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042
/**
  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
6043
      0		Error
unknown's avatar
unknown committed
6044 6045
  @retval
    \#	Pointer to TABLE_LIST element added to the total table list
unknown's avatar
unknown committed
6046 6047
*/

unknown's avatar
unknown committed
6048 6049
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
6050
					     LEX_STRING *alias,
unknown's avatar
unknown committed
6051 6052
					     ulong table_options,
					     thr_lock_type lock_type,
unknown's avatar
unknown committed
6053
					     List<Index_hint> *index_hints_arg,
unknown's avatar
unknown committed
6054
                                             LEX_STRING *option)
unknown's avatar
unknown committed
6055 6056
{
  register TABLE_LIST *ptr;
unknown's avatar
unknown committed
6057
  TABLE_LIST *previous_table_ref; /* The table preceding the current one. */
unknown's avatar
unknown committed
6058
  char *alias_str;
6059
  LEX *lex= thd->lex;
unknown's avatar
unknown committed
6060
  DBUG_ENTER("add_table_to_list");
6061
  LINT_INIT(previous_table_ref);
unknown's avatar
unknown committed
6062 6063 6064 6065

  if (!table)
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? alias->str : table->table.str;
6066 6067
  if (!test(table_options & TL_OPTION_ALIAS) && 
      check_table_name(table->table.str, table->table.length))
unknown's avatar
unknown committed
6068
  {
6069
    my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
unknown's avatar
unknown committed
6070 6071
    DBUG_RETURN(0);
  }
unknown's avatar
unknown committed
6072 6073

  if (table->is_derived_table() == FALSE && table->db.str &&
6074
      check_db_name(&table->db))
unknown's avatar
unknown committed
6075 6076 6077 6078
  {
    my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str);
    DBUG_RETURN(0);
  }
unknown's avatar
unknown committed
6079 6080

  if (!alias)					/* Alias is case sensitive */
6081 6082 6083
  {
    if (table->sel)
    {
unknown's avatar
unknown committed
6084 6085
      my_message(ER_DERIVED_MUST_HAVE_ALIAS,
                 ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
6086 6087
      DBUG_RETURN(0);
    }
6088
    if (!(alias_str= (char*) thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
6089
      DBUG_RETURN(0);
6090
  }
unknown's avatar
unknown committed
6091
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
6092
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
6093
  if (table->db.str)
6094 6095 6096 6097
  {
    ptr->db= table->db.str;
    ptr->db_length= table->db.length;
  }
6098
  else if (lex->copy_db_to(&ptr->db, &ptr->db_length))
unknown's avatar
unknown committed
6099
    DBUG_RETURN(0);
unknown's avatar
unknown committed
6100

6101
  ptr->alias= alias_str;
6102
  if (lower_case_table_names && table->table.length)
6103
    table->table.length= my_casedn_str(files_charset_info, table->table.str);
6104 6105
  ptr->table_name=table->table.str;
  ptr->table_name_length=table->table.length;
6106
  ptr->lock_type=   lock_type;
unknown's avatar
unknown committed
6107 6108
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
6109
  ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
6110
  ptr->derived=	    table->sel;
6111
  if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db,
6112
                                      INFORMATION_SCHEMA_NAME.str))
6113
  {
6114
    ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
6115 6116
    if (!schema_table ||
        (schema_table->hidden && 
unknown's avatar
unknown committed
6117
         ((sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0 || 
6118 6119 6120
          /*
            this check is used for show columns|keys from I_S hidden table
          */
unknown's avatar
unknown committed
6121 6122
          lex->sql_command == SQLCOM_SHOW_FIELDS ||
          lex->sql_command == SQLCOM_SHOW_KEYS)))
6123
    {
unknown's avatar
unknown committed
6124
      my_error(ER_UNKNOWN_TABLE, MYF(0),
6125
               ptr->table_name, INFORMATION_SCHEMA_NAME.str);
6126 6127
      DBUG_RETURN(0);
    }
6128
    ptr->schema_table_name= ptr->table_name;
6129 6130
    ptr->schema_table= schema_table;
  }
6131
  ptr->select_lex=  lex->current_select;
unknown's avatar
unknown committed
6132
  ptr->cacheable_table= 1;
6133
  ptr->index_hints= index_hints_arg;
unknown's avatar
unknown committed
6134
  ptr->option= option ? option->str : 0;
unknown's avatar
unknown committed
6135
  /* check that used name is unique */
6136
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
6137
  {
unknown's avatar
unknown committed
6138 6139 6140 6141
    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
6142
	 tables ;
unknown's avatar
VIEW  
unknown committed
6143
	 tables=tables->next_local)
unknown's avatar
unknown committed
6144
    {
6145 6146
      if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
	  !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
6147
      {
6148
	my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
unknown's avatar
unknown committed
6149 6150
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
6151 6152
    }
  }
unknown's avatar
unknown committed
6153 6154 6155
  /* Store the table reference preceding the current one. */
  if (table_list.elements > 0)
  {
6156 6157 6158
    /*
      table_list.next points to the last inserted TABLE_LIST->next_local'
      element
6159
      We don't use the offsetof() macro here to avoid warnings from gcc
6160
    */
6161 6162 6163
    previous_table_ref= (TABLE_LIST*) ((char*) table_list.next -
                                       ((char*) &(ptr->next_local) -
                                        (char*) ptr));
6164 6165 6166 6167 6168 6169 6170 6171
    /*
      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
6172
  }
6173

unknown's avatar
unknown committed
6174 6175 6176 6177 6178 6179
  /*
    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'.
  */
6180
  table_list.link_in_list((uchar*) ptr, (uchar**) &ptr->next_local);
unknown's avatar
unknown committed
6181
  ptr->next_name_resolution_table= NULL;
6182
  /* Link table in global list (all used tables) */
6183
  lex->add_to_query_tables(ptr);
unknown's avatar
unknown committed
6184 6185 6186
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
6187

unknown's avatar
unknown committed
6188 6189
/**
  Initialize a new table list for a nested join.
6190

6191 6192 6193 6194 6195 6196 6197 6198
    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
6199 6200 6201 6202 6203 6204
  @param thd         current thread

  @retval
    0   if success
  @retval
    1   otherwise
6205 6206 6207 6208 6209 6210 6211
*/

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

6213 6214
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
6215
    DBUG_RETURN(1);
6216
  nested_join= ptr->nested_join=
6217
    ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
6218

6219 6220 6221
  join_list->push_front(ptr);
  ptr->embedding= embedding;
  ptr->join_list= join_list;
6222
  ptr->alias= (char*) "(nested_join)";
6223 6224 6225 6226 6227 6228 6229
  embedding= ptr;
  join_list= &nested_join->join_list;
  join_list->empty();
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
6230 6231
/**
  End a nested join table list.
6232 6233 6234

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

unknown's avatar
unknown committed
6237 6238 6239 6240 6241
  @param thd         current thread

  @return
    - Pointer to TABLE_LIST element added to the total table list, if success
    - 0, otherwise
6242 6243 6244 6245 6246
*/

TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
{
  TABLE_LIST *ptr;
6247
  NESTED_JOIN *nested_join;
6248
  DBUG_ENTER("end_nested_join");
6249

unknown's avatar
unknown committed
6250
  DBUG_ASSERT(embedding);
6251 6252 6253
  ptr= embedding;
  join_list= ptr->join_list;
  embedding= ptr->embedding;
6254
  nested_join= ptr->nested_join;
6255 6256 6257 6258 6259 6260 6261 6262 6263
  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;
  }
6264
  else if (nested_join->join_list.elements == 0)
unknown's avatar
unknown committed
6265 6266
  {
    join_list->pop();
6267
    ptr= 0;                                     // return value
unknown's avatar
unknown committed
6268
  }
6269 6270 6271 6272
  DBUG_RETURN(ptr);
}


unknown's avatar
unknown committed
6273 6274
/**
  Nest last join operation.
6275 6276 6277

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

unknown's avatar
unknown committed
6278
  @param thd         current thread
6279

unknown's avatar
unknown committed
6280
  @retval
6281
    0  Error
unknown's avatar
unknown committed
6282 6283
  @retval
    \#  Pointer to TABLE_LIST element created for the new nested join
6284 6285 6286 6287 6288 6289
*/

TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
{
  TABLE_LIST *ptr;
  NESTED_JOIN *nested_join;
6290
  List<TABLE_LIST> *embedded_list;
6291
  DBUG_ENTER("nest_last_join");
6292

6293 6294
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
6295
    DBUG_RETURN(0);
6296
  nested_join= ptr->nested_join=
6297
    ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
6298

6299 6300
  ptr->embedding= embedding;
  ptr->join_list= join_list;
6301
  ptr->alias= (char*) "(nest_last_join)";
6302
  embedded_list= &nested_join->join_list;
6303
  embedded_list->empty();
6304 6305

  for (uint i=0; i < 2; i++)
6306 6307 6308 6309 6310
  {
    TABLE_LIST *table= join_list->pop();
    table->join_list= embedded_list;
    table->embedding= ptr;
    embedded_list->push_back(table);
unknown's avatar
unknown committed
6311 6312 6313 6314 6315 6316 6317
    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
6318 6319
      if (prev_join_using)
        ptr->join_using_fields= prev_join_using;
unknown's avatar
unknown committed
6320
    }
6321 6322 6323 6324 6325 6326 6327
  }
  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
6328 6329
/**
  Add a table to the current join list.
6330 6331 6332 6333 6334 6335

    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
6336 6337 6338
  @param table       the table to add

  @return
6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351
    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
6352 6353
/**
  Convert a right join into equivalent left join.
6354 6355

    The function takes the current join list t[0],t[1] ... and
6356 6357 6358 6359 6360 6361
    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
6362
  @verbatim
6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373
    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
6374
   @endverbatim
6375

unknown's avatar
unknown committed
6376
  @param thd         current thread
6377

unknown's avatar
unknown committed
6378 6379 6380
  @return
    - Pointer to the table representing the inner table, if success
    - 0, otherwise
6381 6382
*/

6383
TABLE_LIST *st_select_lex::convert_right_join()
6384 6385
{
  TABLE_LIST *tab2= join_list->pop();
6386
  TABLE_LIST *tab1= join_list->pop();
6387 6388 6389 6390 6391 6392 6393 6394 6395
  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
6396 6397
/**
  Set lock for all tables in current select level.
unknown's avatar
unknown committed
6398

unknown's avatar
unknown committed
6399
  @param lock_type			Lock to set for tables
unknown's avatar
unknown committed
6400

unknown's avatar
unknown committed
6401
  @note
unknown's avatar
unknown committed
6402 6403 6404 6405 6406
    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
6407
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
6408 6409 6410 6411 6412 6413
{
  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
6414 6415 6416
  for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first;
       tables;
       tables= tables->next_local)
unknown's avatar
unknown committed
6417 6418 6419 6420 6421 6422 6423
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
6424

unknown's avatar
unknown committed
6425 6426
/**
  Create a fake SELECT_LEX for a unit.
unknown's avatar
unknown committed
6427 6428 6429 6430

    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
6431
    @verbatim
unknown's avatar
unknown committed
6432
    (SELECT ... ORDER BY order_list [LIMIT n]) ORDER BY ... 
unknown's avatar
unknown committed
6433
    @endvarbatim
unknown's avatar
unknown committed
6434
    or of the form
unknown's avatar
unknown committed
6435
    @varbatim
unknown's avatar
unknown committed
6436
    (SELECT ... ORDER BY LIMIT n) ORDER BY ...
unknown's avatar
unknown committed
6437
    @endvarbatim
unknown's avatar
unknown committed
6438
  
unknown's avatar
unknown committed
6439 6440 6441
  @param thd_arg		   thread handle

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

unknown's avatar
unknown committed
6445
  @retval
unknown's avatar
unknown committed
6446
    1     on failure to create the object
unknown's avatar
unknown committed
6447
  @retval
unknown's avatar
unknown committed
6448 6449 6450
    0     on success
*/

unknown's avatar
unknown committed
6451
bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
unknown's avatar
unknown committed
6452 6453 6454 6455
{
  SELECT_LEX *first_sl= first_select();
  DBUG_ENTER("add_fake_select_lex");
  DBUG_ASSERT(!fake_select_lex);
unknown's avatar
unknown committed
6456

unknown's avatar
unknown committed
6457
  if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
6458 6459 6460 6461
      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
6462
  fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */
unknown's avatar
unknown committed
6463 6464
  fake_select_lex->make_empty_select();
  fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
6465 6466
  fake_select_lex->select_limit= 0;

unknown's avatar
unknown committed
6467
  fake_select_lex->context.outer_context=first_sl->context.outer_context;
6468 6469 6470
  /* 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
6471

6472
  if (!is_union())
unknown's avatar
unknown committed
6473 6474 6475 6476 6477 6478 6479 6480 6481
  {
    /* 
      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
6482
    thd_arg->lex->current_select= fake_select_lex;
unknown's avatar
unknown committed
6483
  }
unknown's avatar
unknown committed
6484
  thd_arg->lex->pop_context();
unknown's avatar
unknown committed
6485 6486 6487
  DBUG_RETURN(0);
}

6488

unknown's avatar
unknown committed
6489
/**
6490 6491
  Push a new name resolution context for a JOIN ... ON clause to the
  context stack of a query block.
unknown's avatar
unknown committed
6492 6493

    Create a new name resolution context for a JOIN ... ON clause,
6494 6495 6496
    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
6497

unknown's avatar
unknown committed
6498 6499 6500 6501 6502
  @param thd       pointer to current thread
  @param left_op   left  operand of the JOIN
  @param right_op  rigth operand of the JOIN

  @retval
6503
    FALSE  if all is OK
unknown's avatar
unknown committed
6504
  @retval
6505
    TRUE   if a memory allocation error occured
unknown's avatar
unknown committed
6506 6507
*/

6508 6509 6510
bool
push_new_name_resolution_context(THD *thd,
                                 TABLE_LIST *left_op, TABLE_LIST *right_op)
unknown's avatar
unknown committed
6511 6512
{
  Name_resolution_context *on_context;
6513
  if (!(on_context= new (thd->mem_root) Name_resolution_context))
6514
    return TRUE;
unknown's avatar
unknown committed
6515 6516 6517 6518 6519
  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();
6520
  return thd->lex->push_context(on_context);
unknown's avatar
unknown committed
6521 6522 6523
}


unknown's avatar
unknown committed
6524
/**
unknown's avatar
unknown committed
6525 6526 6527 6528
  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
6529 6530
  @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
6531

unknown's avatar
unknown committed
6532
  @retval
unknown's avatar
unknown committed
6533
    FALSE  if there was some error
unknown's avatar
unknown committed
6534
  @retval
unknown's avatar
unknown committed
6535 6536 6537 6538
    TRUE   if all is OK
*/

void add_join_on(TABLE_LIST *b, Item *expr)
unknown's avatar
unknown committed
6539
{
6540
  if (expr)
6541
  {
6542
    if (!b->on_expr)
unknown's avatar
unknown committed
6543
      b->on_expr= expr;
6544 6545
    else
    {
unknown's avatar
unknown committed
6546 6547 6548 6549 6550 6551
      /*
        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);
6552 6553
    }
    b->on_expr->top_level_item();
6554
  }
unknown's avatar
unknown committed
6555 6556 6557
}


unknown's avatar
unknown committed
6558
/**
unknown's avatar
unknown committed
6559 6560
  Mark that there is a NATURAL JOIN or JOIN ... USING between two
  tables.
6561

unknown's avatar
unknown committed
6562 6563 6564 6565 6566 6567 6568 6569 6570 6571
    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
6572
  @verbatim
6573 6574 6575
    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
6576

unknown's avatar
unknown committed
6577 6578 6579
    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
6580

unknown's avatar
unknown committed
6581 6582 6583
    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
6584 6585 6586 6587 6588
   @endverbatim

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

unknown's avatar
unknown committed
6591 6592
void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
                      SELECT_LEX *lex)
unknown's avatar
unknown committed
6593
{
unknown's avatar
unknown committed
6594
  b->natural_join= a;
unknown's avatar
unknown committed
6595
  lex->prev_join_using= using_fields;
unknown's avatar
unknown committed
6596 6597
}

unknown's avatar
unknown committed
6598

6599
/**
6600 6601
  Reload/resets privileges and the different caches.

6602 6603 6604 6605
  @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.
6606
               
6607 6608 6609 6610 6611 6612 6613 6614
  @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
6615
    @retval !=0  Error; thd->killed is set or thd->is_error() is true
6616 6617
*/

6618 6619
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
                          bool *write_to_binlog)
unknown's avatar
unknown committed
6620 6621 6622
{
  bool result=0;
  select_errors=0;				/* Write if more errors */
6623
  bool tmp_write_to_binlog= 1;
6624

6625
  DBUG_ASSERT(!thd || !thd->in_sub_stmt);
6626

unknown's avatar
SCRUM  
unknown committed
6627
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
6628 6629
  if (options & REFRESH_GRANT)
  {
6630 6631 6632 6633 6634 6635
    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)))
6636 6637
    {
      thd->thread_stack= (char*) &tmp_thd;
6638
      thd->store_globals();
6639
      lex_start(thd);
6640
    }
6641
    
6642 6643
    if (thd)
    {
6644 6645
      bool reload_acl_failed= acl_reload(thd);
      bool reload_grants_failed= grant_reload(thd);
Kristofer Pettersson's avatar
Kristofer Pettersson committed
6646 6647 6648
      bool reload_servers_failed= servers_reload(thd);
      
      if (reload_acl_failed || reload_grants_failed || reload_servers_failed)
6649
      {
6650
        result= 1;
6651 6652 6653 6654 6655 6656
        /*
          When an error is returned, my_message may have not been called and
          the client will hang waiting for a response.
        */
        my_error(ER_UNKNOWN_ERROR, MYF(0), "FLUSH PRIVILEGES failed");
      }
6657
    }
6658

6659 6660 6661 6662 6663 6664 6665
    if (tmp_thd)
    {
      delete tmp_thd;
      /* Remember that we don't have a THD */
      my_pthread_setspecific_ptr(THR_THD,  0);
      thd= 0;
    }
6666
    reset_mqh((LEX_USER *)NULL, TRUE);
unknown's avatar
unknown committed
6667
  }
unknown's avatar
SCRUM  
unknown committed
6668
#endif
unknown's avatar
unknown committed
6669 6670
  if (options & REFRESH_LOG)
  {
6671
    /*
unknown's avatar
unknown committed
6672
      Flush the normal query log, the update log, the binary log,
unknown's avatar
unknown committed
6673 6674
      the slow query log, the relay log (if it exists) and the log
      tables.
6675
    */
unknown's avatar
unknown committed
6676

6677
    /*
unknown's avatar
unknown committed
6678 6679 6680 6681
      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)
6682 6683
    */
    tmp_write_to_binlog= 0;
6684 6685 6686 6687
    if( mysql_bin_log.is_open() )
    {
      mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
    }
unknown's avatar
unknown committed
6688
#ifdef HAVE_REPLICATION
6689
    pthread_mutex_lock(&LOCK_active_mi);
6690
    rotate_relay_log(active_mi);
6691
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
6692
#endif
unknown's avatar
unknown committed
6693 6694 6695 6696 6697

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

    if (ha_flush_logs(NULL))
unknown's avatar
unknown committed
6698
      result=1;
unknown's avatar
unknown committed
6699 6700
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
6701
  }
unknown's avatar
unknown committed
6702
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
6703 6704
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
6705
    query_cache.pack();				// FLUSH QUERY CACHE
6706
    options &= ~REFRESH_QUERY_CACHE;    // Don't flush cache, just free memory
unknown's avatar
unknown committed
6707 6708 6709
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
6710
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
6711
  }
unknown's avatar
unknown committed
6712
#endif /*HAVE_QUERY_CACHE*/
6713 6714 6715 6716 6717
  /*
    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
6718
  {
6719
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
6720
    {
6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731
      /*
        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
6732
        {
6733
          if ((*lock_p)->type >= TL_WRITE_ALLOW_WRITE)
6734 6735 6736 6737
          {
            my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
            return 1;
          }
unknown's avatar
unknown committed
6738
        }
6739
      }
unknown's avatar
unknown committed
6740 6741 6742 6743
      /*
	Writing to the binlog could cause deadlocks, as we don't log
	UNLOCK TABLES
      */
6744
      tmp_write_to_binlog= 0;
6745
      if (lock_global_read_lock(thd))
unknown's avatar
unknown committed
6746
	return 1;                               // Killed
Kristofer Pettersson's avatar
Kristofer Pettersson committed
6747
      if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
6748
                              FALSE : TRUE, TRUE))
6749 6750
          result= 1;
      
unknown's avatar
unknown committed
6751
      if (make_global_read_lock_block_commit(thd)) // Killed
6752 6753 6754 6755 6756
      {
        /* Don't leave things in a half-locked state */
        unlock_global_read_lock(thd);
        return 1;
      }
unknown's avatar
unknown committed
6757
    }
6758
    else
6759
    {
Kristofer Pettersson's avatar
Kristofer Pettersson committed
6760
      if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
6761
                              FALSE : TRUE, FALSE))
6762 6763
        result= 1;
    }
unknown's avatar
unknown committed
6764
    my_dbopt_cleanup();
unknown's avatar
unknown committed
6765 6766 6767
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
unknown's avatar
unknown committed
6768
  if (thd && (options & REFRESH_STATUS))
unknown's avatar
unknown committed
6769
    refresh_status(thd);
unknown's avatar
unknown committed
6770 6771
  if (options & REFRESH_THREADS)
    flush_thread_cache();
unknown's avatar
unknown committed
6772
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
6773
  if (options & REFRESH_MASTER)
6774
  {
6775
    DBUG_ASSERT(thd);
6776
    tmp_write_to_binlog= 0;
6777
    if (reset_master(thd))
unknown's avatar
unknown committed
6778
    {
6779
      result=1;
unknown's avatar
unknown committed
6780
    }
6781
  }
6782
#endif
unknown's avatar
unknown committed
6783
#ifdef OPENSSL
6784 6785
   if (options & REFRESH_DES_KEY_FILE)
   {
6786 6787
     if (des_key_file && load_des_key_file(des_key_file))
         result= 1;
6788 6789
   }
#endif
unknown's avatar
unknown committed
6790
#ifdef HAVE_REPLICATION
6791 6792
 if (options & REFRESH_SLAVE)
 {
6793
   tmp_write_to_binlog= 0;
6794
   pthread_mutex_lock(&LOCK_active_mi);
6795
   if (reset_slave(thd, active_mi))
6796
     result=1;
6797
   pthread_mutex_unlock(&LOCK_active_mi);
6798
 }
6799
#endif
6800
 if (options & REFRESH_USER_RESOURCES)
6801
   reset_mqh((LEX_USER *) NULL, 0);             /* purecov: inspected */
unknown's avatar
unknown committed
6802
 *write_to_binlog= tmp_write_to_binlog;
6803
 return result;
unknown's avatar
unknown committed
6804 6805
}

6806

unknown's avatar
unknown committed
6807 6808
/**
  kill on thread.
6809

unknown's avatar
unknown committed
6810 6811 6812
  @param thd			Thread class
  @param id			Thread id
  @param only_kill_query        Should it kill the query or the connection
6813

unknown's avatar
unknown committed
6814
  @note
6815 6816 6817
    This is written such that we have a short lock on LOCK_thread_count
*/

6818
uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
unknown's avatar
unknown committed
6819 6820 6821
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
6822 6823
  DBUG_ENTER("kill_one_thread");
  DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query));
6824 6825
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
6826 6827
  while ((tmp=it++))
  {
unknown's avatar
unknown committed
6828 6829
    if (tmp->command == COM_DAEMON)
      continue;
unknown's avatar
unknown committed
6830 6831
    if (tmp->thread_id == id)
    {
6832 6833
      pthread_mutex_lock(&tmp->LOCK_delete);	// Lock from delete
      break;
unknown's avatar
unknown committed
6834 6835 6836
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
6837 6838
  if (tmp)
  {
6839 6840
    if ((thd->security_ctx->master_access & SUPER_ACL) ||
	!strcmp(thd->security_ctx->user, tmp->security_ctx->user))
6841
    {
unknown's avatar
SCRUM  
unknown committed
6842
      tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
6843 6844 6845 6846 6847 6848
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
    pthread_mutex_unlock(&tmp->LOCK_delete);
  }
6849 6850 6851 6852
  DBUG_PRINT("exit", ("%d", error));
  DBUG_RETURN(error);
}

6853

6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867
/*
  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)))
6868
    my_ok(thd);
unknown's avatar
unknown committed
6869
  else
unknown's avatar
unknown committed
6870
    my_error(error, MYF(0), id);
unknown's avatar
unknown committed
6871 6872
}

unknown's avatar
unknown committed
6873

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

unknown's avatar
unknown committed
6876 6877
bool append_file_to_dir(THD *thd, const char **filename_ptr,
                        const char *table_name)
6878
{
6879
  char buff[FN_REFLEN],*ptr, *end;
6880 6881 6882 6883 6884 6885 6886
  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))
  {
6887
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
6888 6889 6890 6891
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
6892
  end=convert_dirname(buff, *filename_ptr, NullS);
6893
  if (!(ptr= (char*) thd->alloc((size_t) (end-buff) + strlen(table_name)+1)))
6894 6895
    return 1;					// End of memory
  *filename_ptr=ptr;
6896
  strxmov(ptr,buff,table_name,NullS);
6897 6898
  return 0;
}
6899

6900

unknown's avatar
unknown committed
6901 6902
/**
  Check if the select is a simple select (not an union).
6903

unknown's avatar
unknown committed
6904
  @retval
6905
    0	ok
unknown's avatar
unknown committed
6906
  @retval
6907 6908 6909 6910 6911 6912
    1	error	; In this case the error messege is sent to the client
*/

bool check_simple_select()
{
  THD *thd= current_thd;
6913 6914
  LEX *lex= thd->lex;
  if (lex->current_select != &lex->select_lex)
6915 6916
  {
    char command[80];
6917
    Lex_input_stream *lip= & thd->m_parser_state->m_lip;
6918 6919
    strmake(command, lip->yylval->symbol.str,
	    min(lip->yylval->symbol.length, sizeof(command)-1));
6920
    my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
6921 6922 6923 6924
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
6925

unknown's avatar
unknown committed
6926

unknown's avatar
unknown committed
6927
Comp_creator *comp_eq_creator(bool invert)
unknown's avatar
unknown committed
6928
{
unknown's avatar
unknown committed
6929
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
unknown's avatar
unknown committed
6930 6931
}

unknown's avatar
unknown committed
6932

unknown's avatar
unknown committed
6933
Comp_creator *comp_ge_creator(bool invert)
unknown's avatar
unknown committed
6934
{
unknown's avatar
unknown committed
6935
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
unknown's avatar
unknown committed
6936 6937
}

unknown's avatar
unknown committed
6938

unknown's avatar
unknown committed
6939
Comp_creator *comp_gt_creator(bool invert)
unknown's avatar
unknown committed
6940
{
unknown's avatar
unknown committed
6941
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
unknown's avatar
unknown committed
6942 6943
}

unknown's avatar
unknown committed
6944

unknown's avatar
unknown committed
6945
Comp_creator *comp_le_creator(bool invert)
unknown's avatar
unknown committed
6946
{
unknown's avatar
unknown committed
6947
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
unknown's avatar
unknown committed
6948 6949
}

unknown's avatar
unknown committed
6950

unknown's avatar
unknown committed
6951
Comp_creator *comp_lt_creator(bool invert)
unknown's avatar
unknown committed
6952
{
unknown's avatar
unknown committed
6953
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
unknown's avatar
unknown committed
6954 6955
}

unknown's avatar
unknown committed
6956

unknown's avatar
unknown committed
6957
Comp_creator *comp_ne_creator(bool invert)
unknown's avatar
unknown committed
6958
{
unknown's avatar
unknown committed
6959
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
unknown's avatar
unknown committed
6960
}
unknown's avatar
unknown committed
6961 6962


unknown's avatar
unknown committed
6963 6964
/**
  Construct ALL/ANY/SOME subquery Item.
unknown's avatar
unknown committed
6965

unknown's avatar
unknown committed
6966 6967 6968 6969
  @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
6970

unknown's avatar
unknown committed
6971
  @return
unknown's avatar
unknown committed
6972 6973 6974 6975 6976 6977 6978
    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
6979
  if ((cmp == &comp_eq_creator) && !all)       //  = ANY <=> IN
unknown's avatar
unknown committed
6980
    return new Item_in_subselect(left_expr, select_lex);
unknown's avatar
unknown committed
6981 6982

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

  Item_allany_subselect *it=
6986
    new Item_allany_subselect(left_expr, cmp, select_lex, all);
unknown's avatar
unknown committed
6987
  if (all)
6988
    return it->upper_item= new Item_func_not_all(it);	/* ALL */
unknown's avatar
unknown committed
6989

6990
  return it->upper_item= new Item_func_nop_all(it);      /* ANY/SOME */
unknown's avatar
unknown committed
6991
}
6992 6993


unknown's avatar
unknown committed
6994 6995
/**
  Multi update query pre-check.
6996

unknown's avatar
unknown committed
6997 6998
  @param thd		Thread handler
  @param tables	Global/local table list (have to be the same)
6999

unknown's avatar
unknown committed
7000
  @retval
unknown's avatar
unknown committed
7001
    FALSE OK
unknown's avatar
unknown committed
7002
  @retval
unknown's avatar
unknown committed
7003
    TRUE  Error
7004
*/
unknown's avatar
unknown committed
7005

unknown's avatar
unknown committed
7006
bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
7007 7008 7009 7010 7011
{
  const char *msg= 0;
  TABLE_LIST *table;
  LEX *lex= thd->lex;
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
7012
  DBUG_ENTER("multi_update_precheck");
7013 7014 7015

  if (select_lex->item_list.elements != lex->value_list.elements)
  {
7016
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7017
    DBUG_RETURN(TRUE);
7018 7019 7020 7021 7022
  }
  /*
    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
7023
  for (table= tables; table; table= table->next_local)
7024
  {
7025 7026 7027
    if (table->derived)
      table->grant.privilege= SELECT_ACL;
    else if ((check_access(thd, UPDATE_ACL, table->db,
7028 7029
                           &table->grant.privilege, 0, 1,
                           test(table->schema_table)) ||
7030
              check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
unknown's avatar
unknown committed
7031
             (check_access(thd, SELECT_ACL, table->db,
7032 7033
                           &table->grant.privilege, 0, 0,
                           test(table->schema_table)) ||
7034
              check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
unknown's avatar
unknown committed
7035
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7036

unknown's avatar
VIEW  
unknown committed
7037
    table->table_in_first_from_clause= 1;
7038
  }
unknown's avatar
unknown committed
7039 7040 7041
  /*
    Is there tables of subqueries?
  */
7042
  if (&lex->select_lex != lex->all_selects_list)
7043
  {
7044
    DBUG_PRINT("info",("Checking sub query list"));
unknown's avatar
VIEW  
unknown committed
7045
    for (table= tables; table; table= table->next_global)
7046
    {
7047
      if (!table->table_in_first_from_clause)
7048 7049
      {
	if (check_access(thd, SELECT_ACL, table->db,
7050 7051
			 &table->grant.privilege, 0, 0,
                         test(table->schema_table)) ||
7052
	    check_grant(thd, SELECT_ACL, table, 0, 1, 0))
unknown's avatar
unknown committed
7053
	  DBUG_RETURN(TRUE);
7054 7055 7056 7057 7058 7059
      }
    }
  }

  if (select_lex->order_list.elements)
    msg= "ORDER BY";
7060
  else if (select_lex->select_limit)
7061 7062 7063 7064
    msg= "LIMIT";
  if (msg)
  {
    my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
unknown's avatar
unknown committed
7065
    DBUG_RETURN(TRUE);
7066
  }
unknown's avatar
unknown committed
7067
  DBUG_RETURN(FALSE);
7068 7069
}

unknown's avatar
unknown committed
7070 7071
/**
  Multi delete query pre-check.
7072

unknown's avatar
unknown committed
7073 7074
  @param thd			Thread handler
  @param tables		Global/local table list
7075

unknown's avatar
unknown committed
7076
  @retval
unknown's avatar
unknown committed
7077
    FALSE OK
unknown's avatar
unknown committed
7078
  @retval
unknown's avatar
unknown committed
7079
    TRUE  error
7080
*/
unknown's avatar
unknown committed
7081

7082
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
7083 7084 7085
{
  SELECT_LEX *select_lex= &thd->lex->select_lex;
  TABLE_LIST *aux_tables=
unknown's avatar
unknown committed
7086
    (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
7087
  TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
unknown's avatar
VIEW  
unknown committed
7088
  DBUG_ENTER("multi_delete_precheck");
unknown's avatar
unknown committed
7089

7090 7091
  /* sql_yacc guarantees that tables and aux_tables are not zero */
  DBUG_ASSERT(aux_tables != 0);
7092
  if (check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
7093 7094 7095 7096 7097 7098 7099 7100
    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;
7101
  if (check_table_access(thd, DELETE_ACL, aux_tables, UINT_MAX, FALSE))
7102 7103
  {
    thd->lex->query_tables_own_last= save_query_tables_own_last;
unknown's avatar
unknown committed
7104
    DBUG_RETURN(TRUE);
7105 7106 7107
  }
  thd->lex->query_tables_own_last= save_query_tables_own_last;

7108 7109
  if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
  {
unknown's avatar
unknown committed
7110 7111
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
7112
    DBUG_RETURN(TRUE);
7113
  }
7114 7115 7116 7117
  DBUG_RETURN(FALSE);
}


unknown's avatar
unknown committed
7118
/**
7119 7120 7121
  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
7122
  @param lex   pointer to LEX representing multi-delete
7123

unknown's avatar
unknown committed
7124 7125 7126 7127
  @retval
    FALSE   success
  @retval
    TRUE    error
7128 7129 7130 7131 7132 7133 7134 7135 7136 7137
*/

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
7138
  for (target_tbl= (TABLE_LIST *)lex->auxiliary_table_list.first;
7139
       target_tbl; target_tbl= target_tbl->next_local)
7140
  {
7141
    lex->table_count++;
7142 7143
    /* All tables in aux_tables must be found in FROM PART */
    TABLE_LIST *walk;
unknown's avatar
VIEW  
unknown committed
7144
    for (walk= tables; walk; walk= walk->next_local)
7145
    {
unknown's avatar
unknown committed
7146 7147 7148
      if (!my_strcasecmp(table_alias_charset,
			 target_tbl->alias, walk->alias) &&
	  !strcmp(walk->db, target_tbl->db))
7149 7150 7151 7152
	break;
    }
    if (!walk)
    {
7153
      my_error(ER_UNKNOWN_TABLE, MYF(0),
7154
               target_tbl->table_name, "MULTI DELETE");
unknown's avatar
unknown committed
7155
      DBUG_RETURN(TRUE);
7156
    }
unknown's avatar
unknown committed
7157 7158 7159 7160 7161
    if (!walk->derived)
    {
      target_tbl->table_name= walk->table_name;
      target_tbl->table_name_length= walk->table_name_length;
    }
unknown's avatar
unknown committed
7162
    walk->updating= target_tbl->updating;
unknown's avatar
unknown committed
7163
    walk->lock_type= target_tbl->lock_type;
unknown's avatar
VIEW  
unknown committed
7164
    target_tbl->correspondent_table= walk;	// Remember corresponding table
7165
  }
unknown's avatar
unknown committed
7166
  DBUG_RETURN(FALSE);
7167 7168 7169
}


unknown's avatar
unknown committed
7170 7171
/**
  simple UPDATE query pre-check.
unknown's avatar
unknown committed
7172

unknown's avatar
unknown committed
7173 7174
  @param thd		Thread handler
  @param tables	Global table list
unknown's avatar
unknown committed
7175

unknown's avatar
unknown committed
7176
  @retval
unknown's avatar
unknown committed
7177
    FALSE OK
unknown's avatar
unknown committed
7178
  @retval
unknown's avatar
unknown committed
7179
    TRUE  Error
unknown's avatar
unknown committed
7180
*/
unknown's avatar
unknown committed
7181

unknown's avatar
unknown committed
7182
bool update_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7183 7184 7185 7186
{
  DBUG_ENTER("update_precheck");
  if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
  {
unknown's avatar
unknown committed
7187
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7188
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7189
  }
unknown's avatar
unknown committed
7190
  DBUG_RETURN(check_one_table_access(thd, UPDATE_ACL, tables));
unknown's avatar
unknown committed
7191 7192 7193
}


unknown's avatar
unknown committed
7194 7195
/**
  simple DELETE query pre-check.
unknown's avatar
unknown committed
7196

unknown's avatar
unknown committed
7197 7198
  @param thd		Thread handler
  @param tables	Global table list
unknown's avatar
unknown committed
7199

unknown's avatar
unknown committed
7200
  @retval
unknown's avatar
unknown committed
7201
    FALSE  OK
unknown's avatar
unknown committed
7202
  @retval
unknown's avatar
unknown committed
7203
    TRUE   error
unknown's avatar
unknown committed
7204
*/
unknown's avatar
unknown committed
7205

unknown's avatar
unknown committed
7206
bool delete_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7207 7208 7209
{
  DBUG_ENTER("delete_precheck");
  if (check_one_table_access(thd, DELETE_ACL, tables))
unknown's avatar
unknown committed
7210
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7211
  /* Set privilege for the WHERE clause */
unknown's avatar
unknown committed
7212
  tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
7213
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
7214 7215 7216
}


unknown's avatar
unknown committed
7217 7218
/**
  simple INSERT query pre-check.
unknown's avatar
unknown committed
7219

unknown's avatar
unknown committed
7220 7221
  @param thd		Thread handler
  @param tables	Global table list
unknown's avatar
unknown committed
7222

unknown's avatar
unknown committed
7223
  @retval
unknown's avatar
unknown committed
7224
    FALSE  OK
unknown's avatar
unknown committed
7225
  @retval
unknown's avatar
unknown committed
7226
    TRUE   error
unknown's avatar
unknown committed
7227
*/
unknown's avatar
unknown committed
7228

unknown's avatar
merge  
unknown committed
7229
bool insert_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7230 7231 7232 7233
{
  LEX *lex= thd->lex;
  DBUG_ENTER("insert_precheck");

unknown's avatar
unknown committed
7234 7235 7236 7237
  /*
    Check that we have modify privileges for the first table and
    select privileges for the rest
  */
unknown's avatar
unknown committed
7238 7239 7240
  ulong privilege= (INSERT_ACL |
                    (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
                    (lex->value_list.elements ? UPDATE_ACL : 0));
unknown's avatar
unknown committed
7241 7242

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

unknown's avatar
unknown committed
7245
  if (lex->update_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
7246
  {
unknown's avatar
unknown committed
7247
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7248
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7249
  }
unknown's avatar
unknown committed
7250
  DBUG_RETURN(FALSE);
7251
}
unknown's avatar
unknown committed
7252 7253


unknown's avatar
unknown committed
7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268
/**
    @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)) ||
7269
         check_grant(thd, SELECT_ACL, table, 2, UINT_MAX, 0);
unknown's avatar
unknown committed
7270 7271 7272
}


unknown's avatar
unknown committed
7273 7274
/**
  CREATE TABLE query pre-check.
unknown's avatar
unknown committed
7275

unknown's avatar
unknown committed
7276 7277 7278
  @param thd			Thread handler
  @param tables		Global table list
  @param create_table	        Table which will be created
unknown's avatar
unknown committed
7279

unknown's avatar
unknown committed
7280
  @retval
unknown's avatar
unknown committed
7281
    FALSE   OK
unknown's avatar
unknown committed
7282
  @retval
unknown's avatar
unknown committed
7283
    TRUE   Error
unknown's avatar
unknown committed
7284
*/
unknown's avatar
unknown committed
7285

unknown's avatar
unknown committed
7286 7287
bool create_table_precheck(THD *thd, TABLE_LIST *tables,
                           TABLE_LIST *create_table)
unknown's avatar
unknown committed
7288 7289
{
  LEX *lex= thd->lex;
7290 7291
  SELECT_LEX *select_lex= &lex->select_lex;
  ulong want_priv;
unknown's avatar
merge  
unknown committed
7292
  bool error= TRUE;                                 // Error message is given
unknown's avatar
unknown committed
7293
  DBUG_ENTER("create_table_precheck");
7294

7295 7296 7297 7298 7299
  /*
    Require CREATE [TEMPORARY] privilege on new table; for
    CREATE TABLE ... SELECT, also require INSERT.
  */

7300
  want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
7301 7302 7303
              CREATE_TMP_ACL : CREATE_ACL) |
             (select_lex->item_list.elements ? INSERT_ACL : 0);

unknown's avatar
unknown committed
7304
  if (check_access(thd, want_priv, create_table->db,
7305 7306
		   &create_table->grant.privilege, 0, 0,
                   test(create_table->schema_table)) ||
unknown's avatar
unknown committed
7307 7308 7309
      check_merge_table_access(thd, create_table->db,
			       (TABLE_LIST *)
			       lex->create_info.merge_list.first))
7310
    goto err;
7311
  if (want_priv != CREATE_TMP_ACL &&
7312
      check_grant(thd, want_priv, create_table, 0, 1, 0))
7313 7314 7315 7316 7317 7318
    goto err;

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

7319 7320
#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
    /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
7321
    /*
7322
      Only do the check for PS, because we on execute we have to check that
unknown's avatar
unknown committed
7323 7324
      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).
7325
    */
unknown's avatar
unknown committed
7326
    if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
7327
    {
unknown's avatar
unknown committed
7328 7329 7330 7331
      /*
        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
7332
          find_table_in_global_list(tables, create_table->db,
7333
                                    create_table->table_name))
unknown's avatar
unknown committed
7334
      {
7335
	error= FALSE;
unknown's avatar
unknown committed
7336 7337 7338
        goto err;
      }
    }
7339
#endif
7340
    if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
7341 7342
      goto err;
  }
unknown's avatar
unknown committed
7343 7344 7345 7346 7347
  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
7348
  error= FALSE;
7349 7350 7351

err:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
7352
}
unknown's avatar
unknown committed
7353 7354


unknown's avatar
unknown committed
7355 7356
/**
  negate given expression.
unknown's avatar
unknown committed
7357

unknown's avatar
unknown committed
7358 7359
  @param thd  thread handler
  @param expr expression for negation
unknown's avatar
unknown committed
7360

unknown's avatar
unknown committed
7361
  @return
unknown's avatar
unknown committed
7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386
    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);
}
7387

unknown's avatar
unknown committed
7388 7389 7390
/**
  Set the specified definer to the default value, which is the
  current user in the thread.
7391
 
unknown's avatar
unknown committed
7392 7393
  @param[in]  thd       thread handler
  @param[out] definer   definer
7394 7395
*/
 
7396
void get_default_definer(THD *thd, LEX_USER *definer)
7397 7398 7399 7400 7401 7402 7403 7404 7405 7406
{
  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);
}

7407

unknown's avatar
unknown committed
7408
/**
7409
  Create default definer for the specified THD.
7410

unknown's avatar
unknown committed
7411
  @param[in] thd         thread handler
7412

unknown's avatar
unknown committed
7413 7414
  @return
    - On success, return a valid pointer to the created and initialized
7415
    LEX_USER, which contains definer information.
unknown's avatar
unknown committed
7416
    - On error, return 0.
7417 7418 7419 7420 7421 7422 7423 7424 7425
*/

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

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

7426
  get_default_definer(thd, definer);
7427 7428 7429 7430 7431

  return definer;
}


unknown's avatar
unknown committed
7432
/**
7433
  Create definer with the given user and host names.
7434

unknown's avatar
unknown committed
7435 7436 7437
  @param[in] thd          thread handler
  @param[in] user_name    user name
  @param[in] host_name    host name
7438

unknown's avatar
unknown committed
7439 7440
  @return
    - On success, return a valid pointer to the created and initialized
7441
    LEX_USER, which contains definer information.
unknown's avatar
unknown committed
7442
    - On error, return 0.
7443 7444
*/

7445
LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
7446
{
7447 7448 7449 7450
  LEX_USER *definer;

  /* Create and initialize. */

unknown's avatar
unknown committed
7451
  if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
7452 7453 7454 7455 7456 7457
    return 0;

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

  return definer;
7458
}
7459 7460


unknown's avatar
unknown committed
7461
/**
7462 7463
  Retuns information about user or current user.

unknown's avatar
unknown committed
7464 7465
  @param[in] thd          thread handler
  @param[in] user         user
7466

unknown's avatar
unknown committed
7467 7468
  @return
    - On success, return a valid pointer to initialized
7469
    LEX_USER, which contains user information.
unknown's avatar
unknown committed
7470
    - On error, return 0.
7471 7472 7473 7474 7475
*/

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

7478 7479
  return user;
}
7480 7481


unknown's avatar
unknown committed
7482
/**
7483
  Check that byte length of a string does not exceed some limit.
7484

unknown's avatar
unknown committed
7485 7486 7487
  @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
7488

unknown's avatar
unknown committed
7489
  @retval
7490
    FALSE   the passed string is not longer than max_length
unknown's avatar
unknown committed
7491
  @retval
7492
    TRUE    the passed string is longer than max_length
7493 7494 7495

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

7498 7499
bool check_string_byte_length(LEX_STRING *str, const char *err_msg,
                              uint max_byte_length)
7500
{
7501
  if (str->length <= max_byte_length)
unknown's avatar
unknown committed
7502
    return FALSE;
7503

7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535
  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
7536

7537 7538
  if (!no_error)
    my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_char_length);
7539 7540
  return TRUE;
}
7541 7542


7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554
/*
  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  
*/
7555
C_MODE_START
7556

7557
int test_if_data_home_dir(const char *dir)
7558
{
7559
  char path[FN_REFLEN];
Alexey Botchkov's avatar
Alexey Botchkov committed
7560
  int dir_len;
7561 7562 7563 7564 7565 7566 7567
  DBUG_ENTER("test_if_data_home_dir");

  if (!dir)
    DBUG_RETURN(0);

  (void) fn_format(path, dir, "", "",
                   (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS));
7568 7569
  dir_len= strlen(path);
  if (mysql_unpacked_real_data_home_len<= dir_len)
7570
  {
7571 7572 7573 7574
    if (dir_len > mysql_unpacked_real_data_home_len &&
        path[mysql_unpacked_real_data_home_len] != FN_LIBCHAR)
      DBUG_RETURN(0);

7575 7576
    if (lower_case_file_system)
    {
7577 7578
      if (!my_strnncoll(default_charset_info, (const uchar*) path,
                        mysql_unpacked_real_data_home_len,
7579
                        (const uchar*) mysql_unpacked_real_data_home,
7580
                        mysql_unpacked_real_data_home_len))
7581 7582
        DBUG_RETURN(1);
    }
7583 7584
    else if (!memcmp(path, mysql_unpacked_real_data_home,
                     mysql_unpacked_real_data_home_len))
7585 7586 7587 7588 7589
      DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}

7590 7591
C_MODE_END

7592

7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607
/**
  Check that host name string is valid.

  @param[in] str string to be checked

  @return             Operation status
    @retval  FALSE    host name is ok
    @retval  TRUE     host name string is longer than max_length or
                      has invalid symbols
*/

bool check_host_name(LEX_STRING *str)
{
  const char *name= str->str;
  const char *end= str->str + str->length;
Sergey Glukhov's avatar
Sergey Glukhov committed
7608
  if (check_string_byte_length(str, ER(ER_HOSTNAME), HOSTNAME_LENGTH))
7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623
    return TRUE;

  while (name != end)
  {
    if (*name == '@')
    {
      my_printf_error(ER_UNKNOWN_ERROR, 
                      "Malformed hostname (illegal symbol: '%c')", MYF(0),
                      *name);
      return TRUE;
    }
    name++;
  }
  return FALSE;
}
Sergey Glukhov's avatar
Sergey Glukhov committed
7624 7625


7626 7627 7628 7629 7630 7631 7632 7633
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.
7634
  @param parser_state Parser state.
unknown's avatar
unknown committed
7635
  @param creation_ctx Object creation context.
7636 7637 7638 7639 7640 7641

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

unknown's avatar
unknown committed
7642
bool parse_sql(THD *thd,
7643
               Parser_state *parser_state,
unknown's avatar
unknown committed
7644
               Object_creation_ctx *creation_ctx)
7645
{
7646
  DBUG_ASSERT(thd->m_parser_state == NULL);
7647

unknown's avatar
unknown committed
7648 7649 7650 7651 7652 7653 7654
  /* Backup creation context. */

  Object_creation_ctx *backup_ctx= NULL;

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

7655
  /* Set parser state. */
unknown's avatar
unknown committed
7656

7657
  thd->m_parser_state= parser_state;
7658

unknown's avatar
unknown committed
7659 7660
  /* Parse the query. */

7661 7662
  bool mysql_parse_status= MYSQLparse(thd) != 0;

7663
  /* Check that if MYSQLparse() failed, thd->is_error() is set. */
7664 7665

  DBUG_ASSERT(!mysql_parse_status ||
7666
              mysql_parse_status && thd->is_error());
unknown's avatar
unknown committed
7667

7668
  /* Reset parser state. */
7669

7670
  thd->m_parser_state= NULL;
7671

unknown's avatar
unknown committed
7672 7673 7674 7675 7676 7677 7678
  /* Restore creation context. */

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

  /* That's it. */

7679
  return mysql_parse_status || thd->is_fatal_error;
7680
}
7681 7682 7683 7684

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