sql_parse.cc 235 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
/**
  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)
{
125 126 127 128 129 130 131 132
  /*
    Resource Manager error is meaningless at this point, as we perform
    explicit rollback request by user. We must reset rm_error before
    calling ha_rollback(), so thd->transaction.xid structure gets reset
    by ha_rollback()/THD::transaction::cleanup().
  */
  thd->transaction.xid_state.rm_error= 0;

133 134 135 136 137 138 139 140 141 142 143
  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;

  return status;
}

unknown's avatar
unknown committed
144 145 146 147 148
static void unlock_locked_tables(THD *thd)
{
  if (thd->locked_tables)
  {
    thd->lock=thd->locked_tables;
149
    thd->locked_tables=0;			// Will be automatically closed
unknown's avatar
unknown committed
150 151 152 153
    close_thread_tables(thd);			// Free tables
  }
}

154

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

186

unknown's avatar
unknown committed
187
bool begin_trans(THD *thd)
unknown's avatar
unknown committed
188 189
{
  int error=0;
190
  if (unlikely(thd->in_sub_stmt))
191 192 193 194
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    return 1;
  }
unknown's avatar
unknown committed
195 196 197 198 199 200 201 202 203 204
  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
  {
205
    thd->options|= OPTION_BEGIN;
unknown's avatar
unknown committed
206 207 208 209
    thd->server_status|= SERVER_STATUS_IN_TRANS;
  }
  return error;
}
210

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


223 224 225 226 227 228 229 230 231 232 233 234
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;
}

235

unknown's avatar
unknown committed
236 237 238 239
/**
  Mark all commands that somehow changes a table.

  This is used to check number of updates / hour.
unknown's avatar
unknown committed
240 241 242

  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
243

244
  See COMMAND_FLAG_xxx for different type of commands
unknown's avatar
unknown committed
245 246
     2  - query that returns meaningful ROW_COUNT() -
          a number of modified rows
247 248
*/

249
uint sql_command_flags[SQLCOM_END+1];
250 251 252

void init_update_queries(void)
{
253
  bzero((uchar*) &sql_command_flags, sizeof(sql_command_flags));
254

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

unknown's avatar
unknown committed
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
  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;
290 291 292 293 294 295 296 297 298
  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;
299
  sql_command_flags[SQLCOM_SHOW_PLUGINS]=     CF_STATUS_COMMAND;
300 301 302 303 304
  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;
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
  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;
328
  sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]=  CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
329 330 331
  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;
332 333
  sql_command_flags[SQLCOM_SHOW_PROFILES]= CF_STATUS_COMMAND;
  sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND;
334 335

   sql_command_flags[SQLCOM_SHOW_TABLES]=       (CF_STATUS_COMMAND |
336 337
                                                 CF_SHOW_TABLE_COMMAND |
                                                 CF_REEXECUTION_FRAGILE);
338
  sql_command_flags[SQLCOM_SHOW_TABLE_STATUS]= (CF_STATUS_COMMAND |
339 340
                                                CF_SHOW_TABLE_COMMAND |
                                                CF_REEXECUTION_FRAGILE);
341 342 343 344 345 346 347

  /*
    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.
  */
348
  sql_command_flags[SQLCOM_CALL]= 		CF_HAS_ROW_COUNT | CF_REEXECUTION_FRAGILE;
349
  sql_command_flags[SQLCOM_EXECUTE]= 		CF_HAS_ROW_COUNT;
350 351 352 353 354 355 356 357

  /*
    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;
358 359
}

360

unknown's avatar
unknown committed
361 362
bool is_update_query(enum enum_sql_command command)
{
unknown's avatar
unknown committed
363
  DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
364
  return (sql_command_flags[command] & CF_CHANGES_DATA) != 0;
unknown's avatar
unknown committed
365
}
366

367 368 369 370 371 372 373 374 375 376
/**
  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;
}
377

378 379
void execute_init_command(THD *thd, sys_var_str *init_command_var,
			  rw_lock_t *var_mutex)
unknown's avatar
unknown committed
380 381 382 383
{
  Vio* save_vio;
  ulong save_client_capabilities;

384 385 386 387 388 389
#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

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

#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
  thd->profiling.finish_current_query();
#endif
unknown's avatar
unknown committed
415 416 417
}


418
static void handle_bootstrap_impl(THD *thd)
unknown's avatar
unknown committed
419
{
420 421
  FILE *file=bootstrap_file;
  char *buff;
422
  const char* found_semicolon= NULL;
unknown's avatar
unknown committed
423

424 425
  DBUG_ENTER("handle_bootstrap");

unknown's avatar
unknown committed
426
#ifndef EMBEDDED_LIBRARY
427 428
  pthread_detach_this_thread();
  thd->thread_stack= (char*) &thd;
unknown's avatar
unknown committed
429
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
430

431
  if (thd->variables.max_join_size == HA_POS_ERROR)
unknown's avatar
unknown committed
432 433
    thd->options |= OPTION_BIG_SELECTS;

434
  thd_proc_info(thd, 0);
unknown's avatar
unknown committed
435
  thd->version=refresh_version;
436 437
  thd->security_ctx->priv_user=
    thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
unknown's avatar
unknown committed
438
  thd->security_ctx->priv_host[0]=0;
439 440 441 442 443 444
  /*
    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
445

446
  buff= (char*) thd->net.buff;
447
  thd->init_for_queries();
unknown's avatar
unknown committed
448 449
  while (fgets(buff, thd->net.max_packet, file))
  {
450
    char *query, *res;
451 452 453 454 455 456 457 458 459 460 461
    /* 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))
      {
462 463
        net_end_statement(thd);
        bootstrap_error= 1;
464 465 466
        break;
      }
      buff= (char*) thd->net.buff;
Staale Smedseng's avatar
Staale Smedseng committed
467
      res= fgets(buff + length, thd->net.max_packet - length, file);
468 469 470
      length+= (ulong) strlen(buff + length);
      /* purecov: end */
    }
471
    if (bootstrap_error)
472
      break;                                    /* purecov: inspected */
unknown's avatar
unknown committed
473

unknown's avatar
unknown committed
474
    while (length && (my_isspace(thd->charset(), buff[length-1]) ||
475
                      buff[length-1] == ';'))
unknown's avatar
unknown committed
476 477
      length--;
    buff[length]=0;
unknown's avatar
unknown committed
478 479 480 481 482

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

Gleb Shchepa's avatar
Gleb Shchepa committed
483 484 485
    query= (char *) thd->memdup_w_gap(buff, length + 1,
                                      thd->db_length + 1 +
                                      QUERY_CACHE_FLAGS_SIZE);
486
    thd->set_query(query, length);
487
    DBUG_PRINT("query",("%-.4096s", thd->query()));
488
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
489
    thd->profiling.start_new_query();
490
    thd->profiling.set_query_source(thd->query(), length);
491 492
#endif

493 494 495 496
    /*
      We don't need to obtain LOCK_thread_count here because in bootstrap
      mode we have only one thread.
    */
497
    thd->query_id=next_query_id();
498
    thd->set_time();
499
    mysql_parse(thd, thd->query(), length, & found_semicolon);
unknown's avatar
unknown committed
500
    close_thread_tables(thd);			// Free tables
501

502 503
    bootstrap_error= thd->is_error();
    net_end_statement(thd);
504

505 506 507 508
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
    thd->profiling.finish_current_query();
#endif

509
    if (bootstrap_error)
510 511
      break;

unknown's avatar
unknown committed
512
    free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
513
#ifdef USING_TRANSACTIONS
514
    free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
515
#endif
unknown's avatar
unknown committed
516
  }
517

518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
  DBUG_VOID_RETURN;
}


/**
  Execute commands from bootstrap_file.

  Used when creating the initial grant tables.
*/

pthread_handler_t handle_bootstrap(void *arg)
{
  THD *thd=(THD*) arg;

  /* The following must be called before DBUG_ENTER */
  thd->thread_stack= (char*) &thd;
  if (my_thread_init() || thd->store_globals())
  {
#ifndef EMBEDDED_LIBRARY
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
#endif
    thd->fatal_error();
    goto end;
  }

  handle_bootstrap_impl(thd);

545
end:
546 547 548 549
  net_end(&thd->net);
  thd->cleanup();
  delete thd;

unknown's avatar
unknown committed
550
#ifndef EMBEDDED_LIBRARY
551 552
  (void) pthread_mutex_lock(&LOCK_thread_count);
  thread_count--;
553
  in_bootstrap= FALSE;
554
  (void) pthread_cond_broadcast(&COND_thread_count);
555
  (void) pthread_mutex_unlock(&LOCK_thread_count);
556 557
  my_thread_end();
  pthread_exit(0);
unknown's avatar
unknown committed
558
#endif
559 560

  return 0;
unknown's avatar
unknown committed
561 562 563
}


564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
/**
  @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
581
#ifndef NO_EMBEDDED_ACCESS_CHECKS
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
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,
598
                              table_list, UINT_MAX, FALSE);
599 600 601
  }
  return error;
}
unknown's avatar
unknown committed
602
#endif
603

unknown's avatar
unknown committed
604 605 606 607 608 609 610 611 612 613 614 615 616 617
/* 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;
}

618 619 620 621
/**
   This works because items are allocated with sql_alloc().
   @note The function also handles null pointers (empty list).
*/
622 623
void cleanup_items(Item *item)
{
unknown's avatar
unknown committed
624
  DBUG_ENTER("cleanup_items");  
625 626
  for (; item ; item=item->next)
    item->cleanup();
unknown's avatar
unknown committed
627
  DBUG_VOID_RETURN;
628 629
}

unknown's avatar
unknown committed
630 631
/**
  Handle COM_TABLE_DUMP command.
unknown's avatar
unknown committed
632

unknown's avatar
unknown committed
633 634 635 636
  @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
637

unknown's avatar
unknown committed
638
  @note
unknown's avatar
unknown committed
639 640
    This function is written to handle one specific command only.

unknown's avatar
unknown committed
641
  @retval
unknown's avatar
unknown committed
642
    0               success
unknown's avatar
unknown committed
643
  @retval
unknown's avatar
unknown committed
644 645 646 647
    1               error, the error message is set in THD
*/

static
Ramil Kalimullin's avatar
Ramil Kalimullin committed
648
int mysql_table_dump(THD *thd, LEX_STRING *db, LEX_STRING *table_name)
unknown's avatar
unknown committed
649 650 651 652 653
{
  TABLE* table;
  TABLE_LIST* table_list;
  int error = 0;
  DBUG_ENTER("mysql_table_dump");
654 655 656 657 658
  if (db->length == 0)
  {
    db->str= thd->db;            /* purecov: inspected */
    db->length= thd->db_length;  /* purecov: inspected */
  }
659
  if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
660
    DBUG_RETURN(1); // out of memory
661
  table_list->db= db->str;
Ramil Kalimullin's avatar
Ramil Kalimullin committed
662
  table_list->table_name= table_list->alias= table_name->str;
unknown's avatar
VIEW  
unknown committed
663 664
  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
665

666
  if (check_db_name(db))
667
  {
668 669
    /* purecov: begin inspected */
    my_error(ER_WRONG_DB_NAME ,MYF(0), db->str ? db->str : "NULL");
670
    goto err;
671
    /* purecov: end */
672
  }
Ramil Kalimullin's avatar
Ramil Kalimullin committed
673 674
  if (!table_name->length ||
      check_table_name(table_name->str, table_name->length, TRUE))
675
  {
Ramil Kalimullin's avatar
Ramil Kalimullin committed
676 677 678
    my_error(ER_WRONG_TABLE_NAME, MYF(0),
             table_name->str ? table_name->str : "NULL");
    error= 1;
679 680
    goto err;
  }
681
  if (lower_case_table_names)
Ramil Kalimullin's avatar
Ramil Kalimullin committed
682
    my_casedn_str(files_charset_info, table_name->str);
683

684
  if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT, 0)))
685 686
    DBUG_RETURN(1);

unknown's avatar
unknown committed
687
  if (check_one_table_access(thd, SELECT_ACL, table_list))
unknown's avatar
unknown committed
688 689
    goto err;
  thd->free_list = 0;
Ramil Kalimullin's avatar
Ramil Kalimullin committed
690
  thd->set_query(table_name->str, table_name->length);
unknown's avatar
unknown committed
691
  if ((error = mysqld_dump_create_info(thd, table_list, -1)))
692
  {
693
    my_error(ER_GET_ERRNO, MYF(0), my_errno);
694 695
    goto err;
  }
unknown's avatar
unknown committed
696
  net_flush(&thd->net);
unknown's avatar
unknown committed
697
  if ((error= table->file->dump(thd,-1)))
698
    my_error(ER_GET_ERRNO, MYF(0), error);
unknown's avatar
unknown committed
699

unknown's avatar
unknown committed
700
err:
unknown's avatar
unknown committed
701
  DBUG_RETURN(error);
unknown's avatar
unknown committed
702 703
}

unknown's avatar
unknown committed
704 705
/**
  Ends the current transaction and (maybe) begin the next.
unknown's avatar
unknown committed
706

unknown's avatar
unknown committed
707 708
  @param thd            Current thread
  @param completion     Completion type
unknown's avatar
unknown committed
709

unknown's avatar
unknown committed
710 711
  @retval
    0   OK
unknown's avatar
unknown committed
712 713
*/

714
int end_trans(THD *thd, enum enum_mysql_completiontype completion)
unknown's avatar
unknown committed
715 716 717
{
  bool do_release= 0;
  int res= 0;
718
  DBUG_ENTER("end_trans");
unknown's avatar
unknown committed
719

720
  if (unlikely(thd->in_sub_stmt))
721 722 723 724
  {
    my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
    DBUG_RETURN(1);
  }
725 726 727 728 729 730
  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
731 732 733 734 735 736 737 738
  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;
739
    res= ha_commit(thd);
740
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
unknown's avatar
unknown committed
741
    thd->transaction.all.modified_non_trans_table= FALSE;
unknown's avatar
unknown committed
742 743
    break;
  case COMMIT_RELEASE:
unknown's avatar
unknown committed
744
    do_release= 1; /* fall through */
unknown's avatar
unknown committed
745 746 747 748 749 750
  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
751
    do_release= 1; /* fall through */
unknown's avatar
unknown committed
752 753 754 755
  case ROLLBACK:
  case ROLLBACK_AND_CHAIN:
  {
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
unknown's avatar
unknown committed
756
    if (ha_rollback(thd))
unknown's avatar
unknown committed
757
      res= -1;
758
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
unknown's avatar
unknown committed
759
    thd->transaction.all.modified_non_trans_table= FALSE;
unknown's avatar
unknown committed
760 761 762 763 764 765 766 767 768
    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
769

unknown's avatar
unknown committed
770 771 772
  if (res < 0)
    my_error(thd->killed_errno(), MYF(0));
  else if ((res == 0) && do_release)
unknown's avatar
unknown committed
773 774
    thd->killed= THD::KILL_CONNECTION;

unknown's avatar
unknown committed
775 776
  DBUG_RETURN(res);
}
unknown's avatar
unknown committed
777

778
#ifndef EMBEDDED_LIBRARY
779

unknown's avatar
unknown committed
780
/**
unknown's avatar
unknown committed
781
  Read one command from connection and execute it (query or simple command).
782
  This function is called in loop from thread function.
783 784 785

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

unknown's avatar
unknown committed
786
  @retval
787
    0  success
unknown's avatar
unknown committed
788
  @retval
789 790 791
    1  request of thread shutdown (see dispatch_command() description)
*/

unknown's avatar
unknown committed
792 793
bool do_command(THD *thd)
{
794
  bool return_value;
unknown's avatar
unknown committed
795
  char *packet= 0;
unknown's avatar
unknown committed
796
  ulong packet_length;
unknown's avatar
unknown committed
797
  NET *net= &thd->net;
unknown's avatar
unknown committed
798 799 800
  enum enum_server_command command;
  DBUG_ENTER("do_command");

unknown's avatar
unknown committed
801 802 803 804
  /*
    indicator of uninitialized lex => normal flow of errors handling
    (see my_message_sql)
  */
805
  thd->lex->current_select= 0;
unknown's avatar
unknown committed
806

unknown's avatar
unknown committed
807 808 809 810 811 812
  /*
    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
  */
813
  my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
unknown's avatar
unknown committed
814

815 816 817 818
  /*
    XXX: this code is here only to clear possible errors of init_connect. 
    Consider moving to init_connect() instead.
  */
unknown's avatar
unknown committed
819
  thd->clear_error();				// Clear error message
820
  thd->main_da.reset_diagnostics_area();
unknown's avatar
unknown committed
821 822

  net_new_transaction(net);
823 824 825 826 827 828

  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
829
  {
830 831 832
    DBUG_PRINT("info",("Got error %d reading command from socket %s",
		       net->error,
		       vio_description(net->vio)));
833

834
    /* Check if we can continue without closing the connection */
835

836 837 838 839
    /* The error must be set. */
    DBUG_ASSERT(thd->is_error());
    net_end_statement(thd);

840
    if (net->error != 3)
841
    {
842
      return_value= TRUE;                       // We have to close it.
843 844
      goto out;
    }
845

846
    net->error= 0;
847 848
    return_value= FALSE;
    goto out;
unknown's avatar
unknown committed
849
  }
850 851 852 853 854 855 856 857 858 859 860

  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
861
  {
862 863 864
    /* Initialize with COM_SLEEP packet */
    packet[0]= (uchar) COM_SLEEP;
    packet_length= 1;
unknown's avatar
unknown committed
865
  }
866 867 868 869 870 871 872 873 874 875 876
  /* 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
877 878

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

881
  DBUG_ASSERT(packet_length);
882 883 884 885 886 887 888
  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);
889
}
890
#endif  /* EMBEDDED_LIBRARY */
891

892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922
/**
  @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);

923
  if (!(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA))
924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
    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);
}
959

unknown's avatar
unknown committed
960 961
/**
  Perform one connection-level (COM_XXXX) command.
962

unknown's avatar
unknown committed
963 964 965 966 967 968 969 970
  @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
971 972 973
    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
974 975

  @retval
976
    0   ok
unknown's avatar
unknown committed
977
  @retval
978 979 980
    1   request of thread shutdown, i. e. if command is
        COM_QUIT/COM_SHUTDOWN
*/
981 982 983 984
bool dispatch_command(enum enum_server_command command, THD *thd,
		      char* packet, uint packet_length)
{
  NET *net= &thd->net;
985
  bool error= 0;
986
  DBUG_ENTER("dispatch_command");
987
  DBUG_PRINT("info",("packet: '%*.s'; command: %d", packet_length, packet, command));
988

989
  thd->command=command;
unknown's avatar
unknown committed
990
  /*
991 992
    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
993
  */
994
  thd->enable_slow_log= TRUE;
995
  thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
unknown's avatar
unknown committed
996
  thd->set_time();
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
  if (!thd->is_valid_time())
  {
    /*
     If the time has got past 2038 we need to shut this server down
     We do this by making sure every command is a shutdown and we 
     have enough privileges to shut the server down

     TODO: remove this when we have full 64 bit my_time_t support
    */
    thd->security_ctx->master_access|= SHUTDOWN_ACL;
    command= COM_SHUTDOWN;
  }

unknown's avatar
unknown committed
1010
  VOID(pthread_mutex_lock(&LOCK_thread_count));
unknown's avatar
unknown committed
1011
  thd->query_id= global_query_id;
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021

  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:
1022
    next_query_id();
1023 1024 1025 1026 1027 1028 1029
    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
1030
  thread_running++;
1031
  /* TODO: set thd->lex->sql_command to SQLCOM_END here */
unknown's avatar
unknown committed
1032
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
unknown's avatar
unknown committed
1033

1034 1035 1036 1037 1038
  /**
    Clear the set of flags that are expected to be cleared at the
    beginning of each command.
  */
  thd->server_status&= ~SERVER_STATUS_CLEAR_SET;
1039
  switch (command) {
unknown's avatar
unknown committed
1040
  case COM_INIT_DB:
unknown's avatar
unknown committed
1041 1042
  {
    LEX_STRING tmp;
1043
    status_var_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB]);
unknown's avatar
unknown committed
1044
    thd->convert_string(&tmp, system_charset_info,
1045
			packet, packet_length, thd->charset());
unknown's avatar
unknown committed
1046
    if (!mysql_change_db(thd, &tmp, FALSE))
1047
    {
1048
      general_log_write(thd, command, thd->db, thd->db_length);
1049
      my_ok(thd);
1050
    }
unknown's avatar
unknown committed
1051 1052
    break;
  }
unknown's avatar
unknown committed
1053
#ifdef HAVE_REPLICATION
1054 1055
  case COM_REGISTER_SLAVE:
  {
1056
    if (!register_slave(thd, (uchar*)packet, packet_length))
1057
      my_ok(thd);
1058 1059
    break;
  }
1060
#endif
unknown's avatar
unknown committed
1061
  case COM_TABLE_DUMP:
1062
  {
Ramil Kalimullin's avatar
Ramil Kalimullin committed
1063
    LEX_STRING db, table;
1064
    /* Safe because there is always a trailing \0 at the end of the packet */
1065
    uint db_len= *(uchar*) packet;
1066
    if (db_len + 1 > packet_length || db_len > NAME_LEN)
unknown's avatar
unknown committed
1067
    {
unknown's avatar
unknown committed
1068
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
1069 1070
      break;
    }
1071
    /* Safe because there is always a trailing \0 at the end of the packet */
1072
    uint tbl_len= *(uchar*) (packet + db_len + 1);
1073
    if (db_len + tbl_len + 2 > packet_length || tbl_len > NAME_LEN)
unknown's avatar
unknown committed
1074
    {
unknown's avatar
unknown committed
1075
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
1076 1077
      break;
    }
1078

1079
    status_var_increment(thd->status_var.com_other);
1080
    thd->enable_slow_log= opt_log_slow_admin_statements;
1081
    db.str= (char*) thd->alloc(db_len + tbl_len + 2);
1082
    if (!db.str)
1083 1084 1085 1086
    {
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
      break;
    }
1087
    db.length= db_len;
Ramil Kalimullin's avatar
Ramil Kalimullin committed
1088 1089 1090 1091
    table.length= tbl_len;
    table.str= strmake(db.str, packet + 1, db_len) + 1;
    strmake(table.str, packet + db_len + 2, tbl_len);
    if (mysql_table_dump(thd, &db, &table) == 0)
1092
      thd->main_da.disable_status();
1093 1094
    break;
  }
unknown's avatar
unknown committed
1095 1096
  case COM_CHANGE_USER:
  {
1097
    status_var_increment(thd->status_var.com_other);
1098 1099
    char *user= (char*) packet, *packet_end= packet + packet_length;
    /* Safe because there is always a trailing \0 at the end of the packet */
1100 1101
    char *passwd= strend(user)+1;

unknown's avatar
unknown committed
1102
    thd->change_user();
1103
    thd->clear_error();                         // if errors from rollback
unknown's avatar
unknown committed
1104

1105
    /*
unknown's avatar
unknown committed
1106 1107 1108
      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).
1109 1110 1111

      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
1112
    */
1113
    char db_buff[NAME_LEN+1];                 // buffer to store db in utf8
unknown's avatar
unknown committed
1114
    char *db= passwd;
1115
    char *save_db;
1116 1117 1118 1119 1120 1121 1122 1123 1124
    /*
      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;
    }
1125
    uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
1126
                      (uchar)(*passwd++) : strlen(passwd));
1127 1128
    uint dummy_errors, save_db_length, db_length;
    int res;
1129 1130 1131
    Security_context save_security_ctx= *thd->security_ctx;
    USER_CONN *save_user_connect;

unknown's avatar
unknown committed
1132
    db+= passwd_len + 1;
1133 1134 1135 1136 1137
    /*
      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)
1138
    {
unknown's avatar
unknown committed
1139
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1140 1141
      break;
    }
1142 1143
    db_length= strlen(db);

1144
    char *ptr= db + db_length + 1;
1145 1146
    uint cs_number= 0;

1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
    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);
    }
1157

1158
    /* Convert database name to utf8 */
1159
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
1160
                             system_charset_info, db, db_length,
1161
                             thd->charset(), &dummy_errors)]= 0;
1162
    db= db_buff;
unknown's avatar
unknown committed
1163

1164
    /* Save user and privileges */
1165 1166 1167
    save_db_length= thd->db_length;
    save_db= thd->db;
    save_user_connect= thd->user_connect;
1168 1169

    if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
1170
    {
1171
      thd->security_ctx->user= save_security_ctx.user;
unknown's avatar
unknown committed
1172
      my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
1173 1174
      break;
    }
unknown's avatar
unknown committed
1175

unknown's avatar
unknown committed
1176 1177
    /* Clear variables that are allocated */
    thd->user_connect= 0;
1178
    thd->security_ctx->priv_user= thd->security_ctx->user;
1179
    res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
unknown's avatar
unknown committed
1180

1181 1182
    if (res)
    {
1183 1184
      x_free(thd->security_ctx->user);
      *thd->security_ctx= save_security_ctx;
unknown's avatar
unknown committed
1185
      thd->user_connect= save_user_connect;
1186 1187 1188 1189 1190
      thd->db= save_db;
      thd->db_length= save_db_length;
    }
    else
    {
1191
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1192
      /* we've authenticated new user */
unknown's avatar
unknown committed
1193 1194
      if (save_user_connect)
	decrease_user_connections(save_user_connect);
1195
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
1196 1197
      x_free(save_db);
      x_free(save_security_ctx.user);
1198 1199 1200 1201 1202 1203

      if (cs_number)
      {
        thd_init_client_charset(thd, cs_number);
        thd->update_charset();
      }
1204
    }
unknown's avatar
unknown committed
1205 1206
    break;
  }
1207
  case COM_STMT_EXECUTE:
unknown's avatar
unknown committed
1208
  {
1209
    mysqld_stmt_execute(thd, packet, packet_length);
unknown's avatar
unknown committed
1210 1211
    break;
  }
1212
  case COM_STMT_FETCH:
1213
  {
1214
    mysqld_stmt_fetch(thd, packet, packet_length);
1215 1216
    break;
  }
1217
  case COM_STMT_SEND_LONG_DATA:
unknown's avatar
unknown committed
1218
  {
1219
    mysql_stmt_get_longdata(thd, packet, packet_length);
unknown's avatar
unknown committed
1220 1221
    break;
  }
1222
  case COM_STMT_PREPARE:
unknown's avatar
unknown committed
1223
  {
1224
    mysqld_stmt_prepare(thd, packet, packet_length);
unknown's avatar
unknown committed
1225 1226
    break;
  }
1227
  case COM_STMT_CLOSE:
unknown's avatar
unknown committed
1228
  {
1229
    mysqld_stmt_close(thd, packet);
unknown's avatar
unknown committed
1230 1231
    break;
  }
1232
  case COM_STMT_RESET:
1233
  {
1234
    mysqld_stmt_reset(thd, packet);
1235 1236
    break;
  }
unknown's avatar
unknown committed
1237 1238
  case COM_QUERY:
  {
1239 1240
    if (alloc_query(thd, packet, packet_length))
      break;					// fatal error is set
1241
    char *packet_end= thd->query() + thd->query_length();
unknown's avatar
unknown committed
1242
    /* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */
1243
    const char* end_of_stmt= NULL;
1244

1245 1246
    general_log_write(thd, command, thd->query(), thd->query_length());
    DBUG_PRINT("query",("%-.4096s",thd->query()));
1247
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
1248
    thd->profiling.set_query_source(thd->query(), thd->query_length());
1249
#endif
1250 1251 1252 1253

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

1254
    mysql_parse(thd, thd->query(), thd->query_length(), &end_of_stmt);
1255

1256
    while (!thd->killed && (end_of_stmt != NULL) && ! thd->is_error())
1257
    {
1258
      char *beginning_of_next_stmt= (char*) end_of_stmt;
1259 1260 1261

      net_end_statement(thd);
      query_cache_end_of_result(thd);
1262
      /*
1263 1264
        Multiple queries exits, execute them individually
      */
1265
      close_thread_tables(thd);
1266
      ulong length= (ulong)(packet_end - beginning_of_next_stmt);
1267

1268
      log_slow_statement(thd);
1269

1270
      /* Remove garbage at start of query */
1271
      while (length > 0 && my_isspace(thd->charset(), *beginning_of_next_stmt))
1272
      {
1273
        beginning_of_next_stmt++;
1274 1275
        length--;
      }
1276 1277 1278 1279 1280 1281 1282

#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

Gleb Shchepa's avatar
Gleb Shchepa committed
1283
      thd->set_query(beginning_of_next_stmt, length);
unknown's avatar
unknown committed
1284
      VOID(pthread_mutex_lock(&LOCK_thread_count));
1285 1286 1287 1288
      /*
        Count each statement from the client.
      */
      statistic_increment(thd->status_var.questions, &LOCK_status);
1289
      thd->query_id= next_query_id();
1290
      thd->set_time(); /* Reset the query start time. */
1291
      /* TODO: set thd->lex->sql_command to SQLCOM_END here */
1292
      VOID(pthread_mutex_unlock(&LOCK_thread_count));
1293
      mysql_parse(thd, beginning_of_next_stmt, length, &end_of_stmt);
1294 1295
    }

unknown's avatar
unknown committed
1296 1297 1298 1299 1300
    if (!(specialflag & SPECIAL_NO_PRIOR))
      my_pthread_setprio(pthread_self(),WAIT_PRIOR);
    DBUG_PRINT("info",("query ready"));
    break;
  }
1301
  case COM_FIELD_LIST:				// This isn't actually needed
unknown's avatar
unknown committed
1302
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1303 1304
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
unknown's avatar
unknown committed
1305 1306 1307
    break;
#else
  {
1308
    char *fields, *packet_end= packet + packet_length, *arg_end;
1309
    /* Locked closure of all tables */
unknown's avatar
unknown committed
1310
    TABLE_LIST table_list;
unknown's avatar
unknown committed
1311
    LEX_STRING conv_name;
unknown's avatar
unknown committed
1312

unknown's avatar
unknown committed
1313
    /* used as fields initializator */
1314
    lex_start(thd);
1315

1316
    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]);
unknown's avatar
unknown committed
1317
    bzero((char*) &table_list,sizeof(table_list));
1318
    if (thd->copy_db_to(&table_list.db, &table_list.db_length))
unknown's avatar
unknown committed
1319
      break;
1320 1321 1322 1323
    /*
      We have name + wildcard in packet, separated by endzero
    */
    arg_end= strend(packet);
Ramil Kalimullin's avatar
Ramil Kalimullin committed
1324
    uint arg_length= arg_end - packet;
1325 1326 1327 1328 1329 1330 1331
    
    /* Check given table name length. */
    if (arg_length >= packet_length || arg_length > NAME_LEN)
    {
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
      break;
    }
unknown's avatar
unknown committed
1332
    thd->convert_string(&conv_name, system_charset_info,
1333
			packet, arg_length, thd->charset());
1334
    if (check_table_name(conv_name.str, conv_name.length, FALSE))
1335 1336 1337 1338 1339 1340
    {
      /* this is OK due to convert_string() null-terminating the string */
      my_error(ER_WRONG_TABLE_NAME, MYF(0), conv_name.str);
      break;
    }

1341
    table_list.alias= table_list.table_name= conv_name.str;
1342
    packet= arg_end + 1;
1343

1344
    if (is_schema_db(table_list.db, table_list.db_length))
1345 1346 1347 1348 1349 1350
    {
      ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
      if (schema_table)
        table_list.schema_table= schema_table;
    }

Gleb Shchepa's avatar
Gleb Shchepa committed
1351 1352
    uint query_length= (uint) (packet_end - packet); // Don't count end \0
    if (!(fields= (char *) thd->memdup(packet, query_length + 1)))
unknown's avatar
unknown committed
1353
      break;
1354
    thd->set_query(fields, query_length);
unknown's avatar
unknown committed
1355
    general_log_print(thd, command, "%s %s", table_list.table_name, fields);
1356
    if (lower_case_table_names)
1357
      my_casedn_str(files_charset_info, table_list.table_name);
unknown's avatar
unknown committed
1358

unknown's avatar
unknown committed
1359
    if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
1360
		     0, 0, test(table_list.schema_table)))
unknown's avatar
unknown committed
1361
      break;
1362
    if (check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
unknown's avatar
unknown committed
1363
      break;
1364 1365
    /* init structures for VIEW processing */
    table_list.select_lex= &(thd->lex->select_lex);
1366 1367 1368 1369

    lex_start(thd);
    mysql_reset_thd_for_next_command(thd);

1370
    thd->lex->
1371 1372
      select_lex.table_list.link_in_list(&table_list,
                                         &table_list.next_local);
unknown's avatar
unknown committed
1373
    thd->lex->add_to_query_tables(&table_list);
1374

1375 1376
    /* switch on VIEW optimisation: do not fill temporary tables */
    thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
unknown's avatar
unknown committed
1377
    mysqld_list_fields(thd,&table_list,fields);
1378
    thd->lex->unit.cleanup();
1379
    thd->cleanup_after_query();
unknown's avatar
unknown committed
1380 1381 1382 1383
    break;
  }
#endif
  case COM_QUIT:
1384
    /* We don't calculate statistics for this command */
unknown's avatar
unknown committed
1385
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1386
    net->error=0;				// Don't give 'abort' message
1387
    thd->main_da.disable_status();              // Don't send anything back
unknown's avatar
unknown committed
1388 1389 1390
    error=TRUE;					// End server
    break;

1391
#ifdef REMOVED
unknown's avatar
unknown committed
1392
  case COM_CREATE_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1393
    {
1394
      LEX_STRING db, alias;
1395
      HA_CREATE_INFO create_info;
unknown's avatar
unknown committed
1396

1397
      status_var_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB]);
1398
      if (thd->make_lex_string(&db, packet, packet_length, FALSE) ||
1399
          thd->make_lex_string(&alias, db.str, db.length, FALSE) ||
1400
          check_db_name(&db))
1401
      {
1402
	my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
1403 1404
	break;
      }
1405
      if (check_access(thd, CREATE_ACL, db.str , 0, 1, 0,
1406
                       is_schema_db(db.str, db.length)))
unknown's avatar
unknown committed
1407
	break;
Staale Smedseng's avatar
Staale Smedseng committed
1408
      general_log_print(thd, command, "%.*s", db.length, db.str);
1409
      bzero(&create_info, sizeof(create_info));
1410
      mysql_create_db(thd, (lower_case_table_names == 2 ? alias.str : db.str),
1411
                      &create_info, 0);
unknown's avatar
unknown committed
1412 1413
      break;
    }
unknown's avatar
unknown committed
1414
  case COM_DROP_DB:				// QQ: To be removed
unknown's avatar
unknown committed
1415
    {
1416
      status_var_increment(thd->status_var.com_stat[SQLCOM_DROP_DB]);
1417 1418
      LEX_STRING db;

1419
      if (thd->make_lex_string(&db, packet, packet_length, FALSE) ||
1420
          check_db_name(&db))
1421
      {
1422
	my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
1423 1424
	break;
      }
1425 1426
      if (check_access(thd, DROP_ACL, db.str, 0, 1, 0,
                            is_schema_db(db.str, db.length)))
1427
	break;
unknown's avatar
unknown committed
1428 1429
      if (thd->locked_tables || thd->active_transaction())
      {
unknown's avatar
unknown committed
1430 1431
	my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                   ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
unknown's avatar
unknown committed
1432
	break;
unknown's avatar
unknown committed
1433
      }
Staale Smedseng's avatar
Staale Smedseng committed
1434
      general_log_write(thd, command, "%.*s", db.length, db.str);
1435
      mysql_rm_db(thd, db.str, 0, 0);
unknown's avatar
unknown committed
1436 1437
      break;
    }
1438
#endif
1439
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1440 1441
  case COM_BINLOG_DUMP:
    {
unknown's avatar
unknown committed
1442 1443 1444 1445
      ulong pos;
      ushort flags;
      uint32 slave_server_id;

1446
      status_var_increment(thd->status_var.com_other);
1447
      thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
unknown committed
1448
      if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
1449
	break;
unknown's avatar
unknown committed
1450

1451
      /* TODO: The following has to be changed to an 8 byte integer */
1452 1453
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
unknown's avatar
unknown committed
1454
      thd->server_id=0; /* avoid suicide */
unknown's avatar
unknown committed
1455
      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
unknown's avatar
unknown committed
1456
	kill_zombie_dump_threads(slave_server_id);
1457
      thd->server_id = slave_server_id;
unknown's avatar
unknown committed
1458

unknown's avatar
unknown committed
1459
      general_log_print(thd, command, "Log: '%s'  Pos: %ld", packet+10,
unknown's avatar
unknown committed
1460
                      (long) pos);
1461
      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unknown's avatar
unknown committed
1462
      unregister_slave(thd,1,1);
unknown's avatar
unknown committed
1463
      /*  fake COM_QUIT -- if we get here, the thread needs to terminate */
1464
      error = TRUE;
unknown's avatar
unknown committed
1465 1466
      break;
    }
1467
#endif
unknown's avatar
unknown committed
1468
  case COM_REFRESH:
unknown's avatar
unknown committed
1469 1470
  {
    bool not_used;
1471
    status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
unknown's avatar
unknown committed
1472 1473
    ulong options= (ulong) (uchar) packet[0];
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
1474
      break;
unknown's avatar
unknown committed
1475
    general_log_print(thd, command, NullS);
1476
#ifndef DBUG_OFF
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492
    bool debug_simulate= FALSE;
    DBUG_EXECUTE_IF("simulate_detached_thread_refresh", debug_simulate= TRUE;);
    if (debug_simulate)
    {
      /*
        Simulate a reload without a attached thread session.
        Provides a environment similar to that of when the
        server receives a SIGHUP signal and reloads caches
        and flushes tables.
      */
      bool res;
      my_pthread_setspecific_ptr(THR_THD, NULL);
      res= reload_acl_and_cache(NULL, options | REFRESH_FAST,
                                NULL, &not_used);
      my_pthread_setspecific_ptr(THR_THD, thd);
      if (!res)
Davi Arnaut's avatar
Davi Arnaut committed
1493
        my_ok(thd);
1494 1495
      break;
    }
1496
#endif
Davi Arnaut's avatar
Davi Arnaut committed
1497
    if (!reload_acl_and_cache(thd, options, NULL, &not_used))
1498
      my_ok(thd);
unknown's avatar
unknown committed
1499 1500
    break;
  }
1501
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1502
  case COM_SHUTDOWN:
1503
  {
1504
    status_var_increment(thd->status_var.com_other);
unknown's avatar
unknown committed
1505
    if (check_global_access(thd,SHUTDOWN_ACL))
unknown's avatar
unknown committed
1506
      break; /* purecov: inspected */
1507
    /*
1508
      If the client is < 4.1.3, it is going to send us no argument; then
1509
      packet_length is 0, packet[0] is the end 0 of the packet. Note that
1510 1511
      SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in
      packet[0].
1512
    */
1513 1514 1515 1516 1517
    enum mysql_enum_shutdown_level level;
    if (!thd->is_valid_time())
      level= SHUTDOWN_DEFAULT;
    else
      level= (enum mysql_enum_shutdown_level) (uchar) packet[0];
1518 1519 1520 1521 1522 1523 1524
    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;
    }
1525
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
unknown's avatar
unknown committed
1526
    general_log_print(thd, command, NullS);
1527
    my_eof(thd);
unknown's avatar
unknown committed
1528 1529 1530 1531
    close_thread_tables(thd);			// Free before kill
    kill_mysql();
    error=TRUE;
    break;
1532
  }
1533
#endif
unknown's avatar
unknown committed
1534 1535
  case COM_STATISTICS:
  {
1536 1537 1538
    STATUS_VAR current_global_status_var;
    ulong uptime;
    uint length;
1539
    ulonglong queries_per_second1000;
1540 1541
    char buff[250];
    uint buff_len= sizeof(buff);
1542

1543
    general_log_print(thd, command, NullS);
1544
    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]);
1545
    calc_sum_of_all_status(&current_global_status_var);
1546 1547 1548 1549 1550
    if (!(uptime= (ulong) (thd->start_time - server_start_time)))
      queries_per_second1000= 0;
    else
      queries_per_second1000= thd->query_id * LL(1000) / uptime;

1551 1552 1553
    length= my_snprintf((char*) buff, buff_len - 1,
                        "Uptime: %lu  Threads: %d  Questions: %lu  "
                        "Slow queries: %lu  Opens: %lu  Flush tables: %lu  "
1554
                        "Open tables: %u  Queries per second avg: %u.%u",
1555 1556 1557 1558 1559 1560
                        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(),
1561 1562
                        (uint) (queries_per_second1000 / 1000),
                        (uint) (queries_per_second1000 % 1000));
1563 1564
#ifdef EMBEDDED_LIBRARY
    /* Store the buffer in permanent memory */
1565
    my_ok(thd, 0, 0, buff);
1566
#endif
unknown's avatar
unknown committed
1567
#ifdef SAFEMALLOC
1568
    if (sf_malloc_cur_memory)				// Using SAFEMALLOC
1569 1570 1571 1572 1573 1574 1575
    {
      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
1576 1577
#endif
#ifndef EMBEDDED_LIBRARY
1578
    VOID(my_net_write(net, (uchar*) buff, length));
1579 1580
    VOID(net_flush(net));
    thd->main_da.disable_status();
unknown's avatar
unknown committed
1581
#endif
unknown's avatar
unknown committed
1582 1583 1584
    break;
  }
  case COM_PING:
1585
    status_var_increment(thd->status_var.com_other);
1586
    my_ok(thd);				// Tell client we are alive
unknown's avatar
unknown committed
1587 1588
    break;
  case COM_PROCESS_INFO:
1589
    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]);
1590 1591
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd, PROCESS_ACL))
unknown's avatar
unknown committed
1592
      break;
unknown's avatar
unknown committed
1593
    general_log_print(thd, command, NullS);
unknown's avatar
unknown committed
1594
    mysqld_list_processes(thd,
1595 1596
			  thd->security_ctx->master_access & PROCESS_ACL ? 
			  NullS : thd->security_ctx->priv_user, 0);
unknown's avatar
unknown committed
1597 1598 1599
    break;
  case COM_PROCESS_KILL:
  {
1600
    status_var_increment(thd->status_var.com_stat[SQLCOM_KILL]);
1601
    ulong id=(ulong) uint4korr(packet);
1602
    sql_kill(thd,id,false);
unknown's avatar
unknown committed
1603 1604
    break;
  }
1605 1606
  case COM_SET_OPTION:
  {
1607
    status_var_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION]);
unknown's avatar
unknown committed
1608 1609 1610 1611
    uint opt_command= uint2korr(packet);

    switch (opt_command) {
    case (int) MYSQL_OPTION_MULTI_STATEMENTS_ON:
1612
      thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
1613
      my_eof(thd);
1614
      break;
unknown's avatar
unknown committed
1615
    case (int) MYSQL_OPTION_MULTI_STATEMENTS_OFF:
1616
      thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
1617
      my_eof(thd);
1618 1619
      break;
    default:
unknown's avatar
unknown committed
1620
      my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
1621 1622 1623 1624
      break;
    }
    break;
  }
unknown's avatar
unknown committed
1625
  case COM_DEBUG:
1626
    status_var_increment(thd->status_var.com_other);
unknown's avatar
unknown committed
1627
    if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
1628
      break;					/* purecov: inspected */
1629
    mysql_print_status();
unknown's avatar
unknown committed
1630
    general_log_print(thd, command, NullS);
1631
    my_eof(thd);
unknown's avatar
unknown committed
1632 1633 1634 1635 1636
    break;
  case COM_SLEEP:
  case COM_CONNECT:				// Impossible here
  case COM_TIME:				// Impossible from client
  case COM_DELAYED_INSERT:
1637
  case COM_END:
unknown's avatar
unknown committed
1638
  default:
unknown's avatar
unknown committed
1639
    my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
unknown's avatar
unknown committed
1640 1641
    break;
  }
1642

unknown's avatar
unknown committed
1643
  /* report error issued during command execution */
1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
  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;
  }

1655 1656 1657 1658 1659 1660 1661
  /* 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();

1662 1663
  net_end_statement(thd);
  query_cache_end_of_result(thd);
unknown's avatar
unknown committed
1664

1665 1666 1667 1668
  thd->proc_info= "closing tables";
  /* Free tables */
  close_thread_tables(thd);

1669
  log_slow_statement(thd);
1670

1671
  thd_proc_info(thd, "cleaning up");
1672
  thd->set_query(NULL, 0);
1673
  thd->command=COM_SLEEP;
1674
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
1675 1676
  thread_running--;
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
1677
  thd_proc_info(thd, 0);
1678 1679 1680 1681 1682 1683
  thd->packet.shrink(thd->variables.net_buffer_length);	// Reclaim some memory
  free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
  DBUG_RETURN(error);
}


1684
void log_slow_statement(THD *thd)
1685
{
unknown's avatar
unknown committed
1686
  DBUG_ENTER("log_slow_statement");
1687 1688 1689 1690 1691 1692 1693

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

1696 1697
  /*
    Do not log administrative statements unless the appropriate option is
1698
    set.
1699
  */
1700
  if (thd->enable_slow_log)
unknown's avatar
unknown committed
1701
  {
1702
    ulonglong end_utime_of_query= thd->current_utime();
1703
    thd_proc_info(thd, "logging slow query");
1704

1705 1706 1707 1708
    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)) &&
1709 1710
          opt_log_queries_not_using_indexes &&
           !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) &&
1711
        thd->examined_row_count >= thd->variables.min_examined_row_limit)
1712
    {
1713
      thd_proc_info(thd, "logging slow query");
1714
      thd->status_var.long_query_count++;
1715 1716
      slow_log_print(thd, thd->query(), thd->query_length(), 
                     end_utime_of_query);
1717
    }
unknown's avatar
unknown committed
1718
  }
unknown's avatar
unknown committed
1719
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
1720 1721
}

1722

unknown's avatar
unknown committed
1723
/**
unknown's avatar
unknown committed
1724 1725 1726 1727 1728 1729 1730
  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
1731 1732 1733 1734 1735 1736 1737
  @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
1738 1739 1740 1741
    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
1742
  @retval
unknown's avatar
unknown committed
1743
    0                 success
unknown's avatar
unknown committed
1744
  @retval
unknown's avatar
unknown committed
1745 1746 1747 1748
    1                 out of memory or SHOW commands are not allowed
                      in this version of the server.
*/

1749 1750 1751
int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
                         enum enum_schema_tables schema_table_idx)
{
1752
  SELECT_LEX *schema_select_lex= NULL;
1753
  DBUG_ENTER("prepare_schema_table");
1754

1755
  switch (schema_table_idx) {
1756 1757
  case SCH_SCHEMATA:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
unknown's avatar
unknown committed
1758 1759
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0));   /* purecov: inspected */
1760 1761 1762 1763
    DBUG_RETURN(1);
#else
    break;
#endif
1764

1765 1766 1767
  case SCH_TABLE_NAMES:
  case SCH_TABLES:
  case SCH_VIEWS:
1768
  case SCH_TRIGGERS:
unknown's avatar
unknown committed
1769
  case SCH_EVENTS:
1770
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1771 1772
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1773 1774 1775
    DBUG_RETURN(1);
#else
    {
1776
      LEX_STRING db;
1777
      size_t dummy;
unknown's avatar
unknown committed
1778
      if (lex->select_lex.db == NULL &&
1779
          lex->copy_db_to(&lex->select_lex.db, &dummy))
1780
      {
unknown's avatar
unknown committed
1781
        DBUG_RETURN(1);
1782
      }
1783 1784 1785
      schema_select_lex= new SELECT_LEX();
      db.str= schema_select_lex->db= lex->select_lex.db;
      schema_select_lex->table_list.first= NULL;
1786
      db.length= strlen(db.str);
unknown's avatar
unknown committed
1787

1788
      if (check_db_name(&db))
1789
      {
1790
        my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
1791 1792 1793 1794 1795 1796 1797
        DBUG_RETURN(1);
      }
      break;
    }
#endif
  case SCH_COLUMNS:
  case SCH_STATISTICS:
unknown's avatar
unknown committed
1798
  {
1799
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
1800 1801
    my_message(ER_NOT_ALLOWED_COMMAND,
               ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
1802 1803
    DBUG_RETURN(1);
#else
unknown's avatar
unknown committed
1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814
    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;
  }
1815
#endif
1816 1817 1818 1819 1820
  case SCH_PROFILES:
    /* 
      Mark this current profiling record to be discarded.  We don't
      wish to have SHOW commands show up in profiling.
    */
1821 1822
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
    thd->profiling.discard_current_query();
1823 1824
#endif
    break;
1825 1826 1827
  case SCH_OPEN_TABLES:
  case SCH_VARIABLES:
  case SCH_STATUS:
1828 1829
  case SCH_PROCEDURES:
  case SCH_CHARSETS:
unknown's avatar
unknown committed
1830
  case SCH_ENGINES:
1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847
  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);
  }
1848
  TABLE_LIST *table_list= select_lex->table_list.first;
unknown's avatar
unknown committed
1849
  table_list->schema_select_lex= schema_select_lex;
1850
  table_list->schema_table_reformed= 1;
1851 1852 1853 1854
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
1855 1856 1857
/**
  Read query from packet and store in thd->query.
  Used in COM_QUERY and COM_STMT_PREPARE.
1858 1859

    Sets the following THD variables:
unknown's avatar
unknown committed
1860 1861
  - query
  - query_length
1862

unknown's avatar
unknown committed
1863
  @retval
unknown's avatar
unknown committed
1864
    FALSE ok
unknown's avatar
unknown committed
1865
  @retval
unknown's avatar
unknown committed
1866
    TRUE  error;  In this case thd->fatal_error is set
1867 1868
*/

1869
bool alloc_query(THD *thd, const char *packet, uint packet_length)
1870
{
1871
  char *query;
1872
  /* Remove garbage at start and end of query */
1873
  while (packet_length > 0 && my_isspace(thd->charset(), packet[0]))
1874 1875 1876 1877
  {
    packet++;
    packet_length--;
  }
1878
  const char *pos= packet + packet_length;     // Point at end null
unknown's avatar
unknown committed
1879
  while (packet_length > 0 &&
unknown's avatar
unknown committed
1880
	 (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1])))
1881 1882 1883 1884 1885
  {
    pos--;
    packet_length--;
  }
  /* We must allocate some extra memory for query cache */
1886 1887 1888 1889 1890 1891 1892
  if (! (query= (char*) thd->memdup_w_gap(packet,
                                          packet_length,
                                          1 + thd->db_length +
                                          QUERY_CACHE_FLAGS_SIZE)))
      return TRUE;
  query[packet_length]= '\0';
  thd->set_query(query, packet_length);
1893 1894 1895 1896

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

unknown's avatar
unknown committed
1898
  return FALSE;
1899 1900
}

1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913
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;
1914
  thd->variables.lc_time_names= &my_locale_en_US;
1915 1916 1917
  thd->one_shot_set= 0;
}

1918

1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964
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);

1965
    if (thd->slave_thread && lex->sphead)
1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003
      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
2004 2005
/**
  Execute command saved in thd and lex->sql_command.
2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016

    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
2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028
  @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
2029
    FALSE       OK
unknown's avatar
unknown committed
2030
  @retval
2031 2032
    TRUE        Error
*/
unknown's avatar
unknown committed
2033

2034
int
2035
mysql_execute_command(THD *thd)
unknown's avatar
unknown committed
2036
{
2037
  int res= FALSE;
2038
  bool need_start_waiting= FALSE; // have protection against global read lock
unknown's avatar
unknown committed
2039
  int  up_result= 0;
2040
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
2041
  /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
unknown's avatar
unknown committed
2042
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
2043
  /* first table of first SELECT_LEX */
2044
  TABLE_LIST *first_table= select_lex->table_list.first;
unknown's avatar
VIEW  
unknown committed
2045 2046 2047
  /* list of all tables in query */
  TABLE_LIST *all_tables;
  /* most outer SELECT_LEX_UNIT of query */
2048
  SELECT_LEX_UNIT *unit= &lex->unit;
2049 2050 2051 2052
#ifdef HAVE_REPLICATION
  /* have table map for update for multi-update statement (BUG#37051) */
  bool have_table_map_for_update= FALSE;
#endif
2053
  /* Saved variable value */
unknown's avatar
unknown committed
2054
  DBUG_ENTER("mysql_execute_command");
unknown's avatar
unknown committed
2055 2056 2057
#ifdef WITH_PARTITION_STORAGE_ENGINE
  thd->work_part_info= 0;
#endif
unknown's avatar
unknown committed
2058

unknown's avatar
VIEW  
unknown committed
2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074
  /*
    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();
2075
  /* should be assigned after making first tables same */
unknown's avatar
VIEW  
unknown committed
2076
  all_tables= lex->query_tables;
2077 2078
  /* set context for commands which do not use setup_tables */
  select_lex->
2079
    context.resolve_in_table_list_only(select_lex->
2080
                                       table_list.first);
unknown's avatar
VIEW  
unknown committed
2081

2082 2083 2084 2085 2086
  /*
    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.
2087
    Don't reset warnings when executing a stored routine.
2088
  */
2089
  if ((all_tables || !lex->is_single_level_stmt()) && !thd->spcont)
unknown's avatar
unknown committed
2090
    mysql_reset_errors(thd, 0);
2091

unknown's avatar
SCRUM  
unknown committed
2092
#ifdef HAVE_REPLICATION
2093
  if (unlikely(thd->slave_thread))
2094
  {
2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117
    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;
    }
2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159

    /*
      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;
    }
2160
    
unknown's avatar
unknown committed
2161
    /*
unknown's avatar
unknown committed
2162 2163
      Check if statment should be skipped because of slave filtering
      rules
2164 2165

      Exceptions are:
unknown's avatar
unknown committed
2166 2167
      - UPDATE MULTI: For this statement, we want to check the filtering
        rules later in the code
2168
      - SET: we always execute it (Not that many SET commands exists in
unknown's avatar
unknown committed
2169 2170
        the binary log anyway -- only 4.1 masters write SET statements,
	in 5.0 there are no SET statements in the binary log)
2171 2172
      - 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
2173
    */
unknown's avatar
unknown committed
2174 2175
    if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
	!(lex->sql_command == SQLCOM_SET_OPTION) &&
2176
	!(lex->sql_command == SQLCOM_DROP_TABLE &&
2177
          lex->drop_temporary && lex->drop_if_exists) &&
unknown's avatar
Merge  
unknown committed
2178
        all_tables_not_ok(thd, all_tables))
unknown's avatar
unknown committed
2179 2180
    {
      /* we warn the slave SQL thread */
unknown's avatar
unknown committed
2181
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198
      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);
      }
2199
      DBUG_RETURN(0);
unknown's avatar
unknown committed
2200
    }
2201
  }
2202
  else
2203
  {
2204
#endif /* HAVE_REPLICATION */
2205 2206 2207 2208
    /*
      When option readonly is set deny operations which change non-temporary
      tables. Except for the replication thread and the 'super' users.
    */
2209
    if (deny_updates_if_read_only_option(thd, all_tables))
2210 2211 2212 2213 2214 2215 2216
    {
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
      DBUG_RETURN(-1);
    }
#ifdef HAVE_REPLICATION
  } /* endif unlikely slave */
#endif
2217
  status_var_increment(thd->status_var.com_stat[lex->sql_command]);
2218

unknown's avatar
unknown committed
2219 2220
  DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE);
  
unknown's avatar
unknown committed
2221
  switch (lex->sql_command) {
2222

2223
  case SQLCOM_SHOW_EVENTS:
2224 2225 2226 2227
#ifndef HAVE_EVENT_SCHEDULER
    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "embedded server");
    break;
#endif
2228 2229
  case SQLCOM_SHOW_STATUS_PROC:
  case SQLCOM_SHOW_STATUS_FUNC:
2230 2231
    if (!(res= check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE)))
      res= execute_sqlcom_select(thd, all_tables);
2232 2233 2234 2235 2236
    break;
  case SQLCOM_SHOW_STATUS:
  {
    system_status_var old_status_var= thd->status_var;
    thd->initial_status_var= &old_status_var;
2237 2238
    if (!(res= check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE)))
      res= execute_sqlcom_select(thd, all_tables);
2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263
    /* 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:
2264
  case SQLCOM_SHOW_STORAGE_ENGINES:
2265
  case SQLCOM_SHOW_PROFILE:
unknown's avatar
unknown committed
2266
  case SQLCOM_SELECT:
2267
    thd->status_var.last_query_cost= 0.0;
unknown's avatar
VIEW  
unknown committed
2268
    if (all_tables)
unknown's avatar
unknown committed
2269
    {
2270 2271 2272
      res= check_table_access(thd,
                              lex->exchange ? SELECT_ACL | FILE_ACL :
                              SELECT_ACL,
2273
                              all_tables, UINT_MAX, FALSE);
unknown's avatar
unknown committed
2274 2275
    }
    else
unknown's avatar
VIEW  
unknown committed
2276
      res= check_access(thd,
2277 2278
                        lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
                        any_db, 0, 0, 0, 0);
2279

2280 2281 2282 2283 2284 2285 2286 2287
    if (res)
      break;

    if (!thd->locked_tables && lex->protect_against_global_read_lock &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
      break;

    res= execute_sqlcom_select(thd, all_tables);
unknown's avatar
unknown committed
2288
    break;
unknown's avatar
unknown committed
2289
  case SQLCOM_PREPARE:
2290
  {
2291
    mysql_sql_stmt_prepare(thd);
unknown's avatar
unknown committed
2292 2293 2294 2295
    break;
  }
  case SQLCOM_EXECUTE:
  {
2296
    mysql_sql_stmt_execute(thd);
unknown's avatar
unknown committed
2297 2298 2299 2300
    break;
  }
  case SQLCOM_DEALLOCATE_PREPARE:
  {
2301
    mysql_sql_stmt_close(thd);
unknown's avatar
unknown committed
2302 2303
    break;
  }
unknown's avatar
unknown committed
2304
  case SQLCOM_DO:
2305
    if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
2306
        open_and_lock_tables(thd, all_tables))
unknown's avatar
unknown committed
2307
      goto error;
unknown's avatar
unknown committed
2308 2309

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

2312
  case SQLCOM_EMPTY_QUERY:
2313
    my_ok(thd);
2314 2315
    break;

unknown's avatar
unknown committed
2316 2317 2318 2319
  case SQLCOM_HELP:
    res= mysqld_help(thd,lex->help_arg);
    break;

2320
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2321
  case SQLCOM_PURGE:
2322
  {
unknown's avatar
unknown committed
2323
    if (check_global_access(thd, SUPER_ACL))
2324
      goto error;
unknown's avatar
unknown committed
2325
    /* PURGE MASTER LOGS TO 'file' */
2326 2327 2328
    res = purge_master_logs(thd, lex->to_log);
    break;
  }
2329 2330
  case SQLCOM_PURGE_BEFORE:
  {
2331 2332
    Item *it;

2333 2334
    if (check_global_access(thd, SUPER_ACL))
      goto error;
unknown's avatar
unknown committed
2335
    /* PURGE MASTER LOGS BEFORE 'data' */
2336
    it= (Item *)lex->value_list.head();
2337
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) ||
unknown's avatar
unknown committed
2338
        it->check_cols(1))
2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349
    {
      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());
2350 2351
    break;
  }
2352
#endif
unknown's avatar
unknown committed
2353 2354
  case SQLCOM_SHOW_WARNS:
  {
2355 2356
    res= mysqld_show_warnings(thd, (ulong)
			      ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
2357 2358 2359
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
			       (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
			       ));
unknown's avatar
unknown committed
2360 2361 2362 2363
    break;
  }
  case SQLCOM_SHOW_ERRORS:
  {
2364 2365
    res= mysqld_show_warnings(thd, (ulong)
			      (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
unknown's avatar
unknown committed
2366 2367
    break;
  }
unknown's avatar
unknown committed
2368 2369
  case SQLCOM_SHOW_PROFILES:
  {
2370
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
2371
    thd->profiling.discard_current_query();
unknown's avatar
unknown committed
2372
    res= thd->profiling.show_profiles();
2373 2374 2375
    if (res)
      goto error;
#else
2376
    my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILES", "enable-profiling");
2377 2378
    goto error;
#endif
unknown's avatar
unknown committed
2379 2380
    break;
  }
unknown's avatar
unknown committed
2381 2382
  case SQLCOM_SHOW_NEW_MASTER:
  {
unknown's avatar
unknown committed
2383
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2384
      goto error;
2385
    /* This query don't work now. See comment in repl_failsafe.cc */
unknown's avatar
unknown committed
2386
#ifndef WORKING_NEW_MASTER
unknown's avatar
unknown committed
2387 2388
    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
    goto error;
unknown's avatar
unknown committed
2389
#else
unknown's avatar
unknown committed
2390 2391
    res = show_new_master(thd);
    break;
unknown's avatar
unknown committed
2392
#endif
unknown's avatar
unknown committed
2393
  }
2394

unknown's avatar
unknown committed
2395
#ifdef HAVE_REPLICATION
2396 2397
  case SQLCOM_SHOW_SLAVE_HOSTS:
  {
unknown's avatar
unknown committed
2398
    if (check_global_access(thd, REPL_SLAVE_ACL))
2399 2400 2401 2402
      goto error;
    res = show_slave_hosts(thd);
    break;
  }
unknown's avatar
unknown committed
2403 2404
  case SQLCOM_SHOW_BINLOG_EVENTS:
  {
unknown's avatar
unknown committed
2405
    if (check_global_access(thd, REPL_SLAVE_ACL))
unknown's avatar
unknown committed
2406
      goto error;
2407
    res = mysql_show_binlog_events(thd);
unknown's avatar
unknown committed
2408 2409
    break;
  }
2410 2411
#endif

unknown's avatar
unknown committed
2412
  case SQLCOM_BACKUP_TABLE:
2413
  {
unknown's avatar
VIEW  
unknown committed
2414
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2415
    if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
unknown's avatar
unknown committed
2416
	check_global_access(thd, FILE_ACL))
2417
      goto error; /* purecov: inspected */
2418
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2419
    res = mysql_backup_table(thd, first_table);
2420
    select_lex->table_list.first= first_table;
2421
    lex->query_tables=all_tables;
2422 2423
    break;
  }
unknown's avatar
unknown committed
2424
  case SQLCOM_RESTORE_TABLE:
2425
  {
unknown's avatar
VIEW  
unknown committed
2426
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
2427
    if (check_table_access(thd, INSERT_ACL, all_tables, UINT_MAX, FALSE) ||
unknown's avatar
unknown committed
2428
	check_global_access(thd, FILE_ACL))
2429
      goto error; /* purecov: inspected */
2430
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
2431
    res = mysql_restore_table(thd, first_table);
2432
    select_lex->table_list.first= first_table;
2433
    lex->query_tables=all_tables;
2434 2435
    break;
  }
unknown's avatar
unknown committed
2436 2437
  case SQLCOM_ASSIGN_TO_KEYCACHE:
  {
unknown's avatar
VIEW  
unknown committed
2438
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2439
    if (check_access(thd, INDEX_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;
2443
    res= mysql_assign_to_keycache(thd, first_table, &lex->ident);
unknown's avatar
unknown committed
2444 2445
    break;
  }
unknown's avatar
unknown committed
2446 2447
  case SQLCOM_PRELOAD_KEYS:
  {
unknown's avatar
VIEW  
unknown committed
2448
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2449
    if (check_access(thd, INDEX_ACL, first_table->db,
2450 2451
                     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
2452
      goto error;
unknown's avatar
VIEW  
unknown committed
2453
    res = mysql_preload_keys(thd, first_table);
unknown's avatar
unknown committed
2454 2455
    break;
  }
unknown's avatar
unknown committed
2456
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2457
  case SQLCOM_CHANGE_MASTER:
2458
  {
unknown's avatar
unknown committed
2459
    if (check_global_access(thd, SUPER_ACL))
2460
      goto error;
2461
    pthread_mutex_lock(&LOCK_active_mi);
2462
    res = change_master(thd,active_mi);
2463
    pthread_mutex_unlock(&LOCK_active_mi);
2464 2465
    break;
  }
unknown's avatar
unknown committed
2466
  case SQLCOM_SHOW_SLAVE_STAT:
2467
  {
2468 2469
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2470
      goto error;
2471
    pthread_mutex_lock(&LOCK_active_mi);
2472 2473 2474 2475 2476 2477
    if (active_mi != NULL)
    {
      res = show_master_info(thd, active_mi);
    }
    else
    {
2478 2479
      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                   WARN_NO_MASTER_INFO, ER(WARN_NO_MASTER_INFO));
2480
      my_ok(thd);
2481
    }
2482
    pthread_mutex_unlock(&LOCK_active_mi);
2483 2484
    break;
  }
unknown's avatar
unknown committed
2485
  case SQLCOM_SHOW_MASTER_STAT:
2486
  {
2487 2488
    /* Accept one of two privileges */
    if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
2489 2490 2491 2492
      goto error;
    res = show_binlog_info(thd);
    break;
  }
unknown's avatar
unknown committed
2493

2494
  case SQLCOM_LOAD_MASTER_DATA: // sync with master
unknown's avatar
unknown committed
2495
    if (check_global_access(thd, SUPER_ACL))
2496
      goto error;
2497
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2498
      goto error;
2499
    res = load_master_data(thd);
2500
    break;
unknown's avatar
unknown committed
2501
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
2502
  case SQLCOM_SHOW_ENGINE_STATUS:
unknown's avatar
unknown committed
2503
    {
2504
      if (check_global_access(thd, PROCESS_ACL))
unknown's avatar
unknown committed
2505 2506
        goto error;
      res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_STATUS);
unknown's avatar
unknown committed
2507 2508
      break;
    }
unknown's avatar
unknown committed
2509
  case SQLCOM_SHOW_ENGINE_MUTEX:
unknown's avatar
unknown committed
2510
    {
2511
      if (check_global_access(thd, PROCESS_ACL))
unknown's avatar
unknown committed
2512
        goto error;
unknown's avatar
unknown committed
2513
      res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
unknown's avatar
unknown committed
2514 2515
      break;
    }
unknown's avatar
unknown committed
2516
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2517
  case SQLCOM_LOAD_MASTER_TABLE:
2518
  {
unknown's avatar
VIEW  
unknown committed
2519
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2520 2521
    DBUG_ASSERT(first_table->db); /* Must be set in the parser */

unknown's avatar
VIEW  
unknown committed
2522
    if (check_access(thd, CREATE_ACL, first_table->db,
2523 2524
		     &first_table->grant.privilege, 0, 0,
                     test(first_table->schema_table)))
unknown's avatar
unknown committed
2525
      goto error;				/* purecov: inspected */
2526 2527 2528 2529
    /* Check that the first table has CREATE privilege */
    if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
      goto error;

2530
    pthread_mutex_lock(&LOCK_active_mi);
2531 2532 2533 2534
    /*
      fetch_master_table will send the error to the client on failure.
      Give error if the table already exists.
    */
2535
    if (!fetch_master_table(thd, first_table->db, first_table->table_name,
2536
			    active_mi, 0, 0))
2537
    {
2538
      my_ok(thd);
2539
    }
2540
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2541
    break;
2542
  }
unknown's avatar
unknown committed
2543
#endif /* HAVE_REPLICATION */
2544

unknown's avatar
unknown committed
2545
  case SQLCOM_CREATE_TABLE:
unknown's avatar
unknown committed
2546
  {
2547
    /* If CREATE TABLE of non-temporary table, do implicit commit */
2548 2549 2550 2551 2552 2553 2554 2555
    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
    {
      if (end_active_trans(thd))
      {
	res= -1;
	break;
      }
    }
unknown's avatar
VIEW  
unknown committed
2556 2557 2558 2559 2560
    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;
2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581
    /*
      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
2582

unknown's avatar
VIEW  
unknown committed
2583
    if ((res= create_table_precheck(thd, select_tables, create_table)))
unknown's avatar
unknown committed
2584
      goto end_with_restore_list;
unknown's avatar
unknown committed
2585

2586 2587 2588
    /* Might have been updated in create_table_precheck */
    create_info.alias= create_table->alias;

2589
#ifdef HAVE_READLINK
2590
    /* Fix names if symlinked tables */
2591
    if (append_file_to_dir(thd, &create_info.data_file_name,
2592
			   create_table->table_name) ||
2593
	append_file_to_dir(thd, &create_info.index_file_name,
2594
			   create_table->table_name))
unknown's avatar
unknown committed
2595
      goto end_with_restore_list;
2596
#endif
2597
    /*
2598
      If we are using SET CHARSET without DEFAULT, add an implicit
2599 2600
      DEFAULT to not confuse old users. (This may change).
    */
2601
    if ((create_info.used_fields &
2602 2603 2604
	 (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
	HA_CREATE_USED_CHARSET)
    {
2605 2606 2607 2608
      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;
2609
    }
2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622
    /*
      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.
    */
2623 2624
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
2625
    {
unknown's avatar
unknown committed
2626 2627
      res= 1;
      goto end_with_restore_list;
2628
    }
2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639
#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
2640
    if (select_lex->item_list.elements)		// With select
unknown's avatar
unknown committed
2641 2642
    {
      select_result *result;
2643

2644 2645 2646
      /*
        If:
        a) we inside an SP and there was NAME_CONST substitution,
Ramil Kalimullin's avatar
Ramil Kalimullin committed
2647
        b) binlogging is on (STMT mode),
2648 2649 2650 2651 2652 2653
        c) we log the SP as separate statements
        raise a warning, as it may cause problems
        (see 'NAME_CONST issues' in 'Binary Logging of Stored Programs')
       */
      if (thd->query_name_consts && 
          mysql_bin_log.is_open() &&
Ramil Kalimullin's avatar
Ramil Kalimullin committed
2654
          thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680
          !mysql_bin_log.is_query_in_union(thd, thd->query_id))
      {
        List_iterator_fast<Item> it(select_lex->item_list);
        Item *item;
        uint splocal_refs= 0;
        /* Count SP local vars in the top-level SELECT list */
        while ((item= it++))
        {
          if (item->is_splocal())
            splocal_refs++;
        }
        /*
          If it differs from number of NAME_CONST substitution applied,
          we may have a SOME_FUNC(NAME_CONST()) in the SELECT list,
          that may cause a problem with binary log (see BUG#35383),
          raise a warning. 
        */
        if (splocal_refs != thd->query_name_consts)
          push_warning(thd, 
                       MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_UNKNOWN_ERROR,
"Invoked routine ran a statement that may cause problems with "
"binary log, see 'NAME_CONST issues' in 'Binary Logging of Stored Programs' "
"section of the manual.");
      }
      
2681
      select_lex->options|= SELECT_NO_UNLOCK;
2682
      unit->set_limit(select_lex);
2683

2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696
      /*
        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;
      }

2697
      if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
unknown's avatar
unknown committed
2698 2699 2700
      {
        lex->link_first_table_back(create_table, link_to_local);
        create_table->create= TRUE;
2701 2702
        /* Base table and temporary table are not in the same name space. */
        create_table->skip_temporary= 1;
unknown's avatar
unknown committed
2703 2704 2705
      }

      if (!(res= open_and_lock_tables(thd, lex->query_tables)))
2706
      {
2707 2708 2709 2710
        /*
          Is table which we are changing used somewhere in other parts
          of query
        */
2711
        if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
2712
        {
2713
          TABLE_LIST *duplicate;
unknown's avatar
unknown committed
2714
          create_table= lex->unlink_first_table(&link_to_local);
2715
          if ((duplicate= unique_table(thd, create_table, select_tables, 0)))
2716 2717 2718
          {
            update_non_unique_table_error(create_table, "CREATE", duplicate);
            res= 1;
2719
            goto end_with_restore_list;
2720
          }
2721
        }
unknown's avatar
unknown committed
2722
        /* If we create merge table, we have to test tables in merge, too */
2723
        if (create_info.used_fields & HA_CREATE_USED_UNION)
unknown's avatar
unknown committed
2724 2725
        {
          TABLE_LIST *tab;
2726
          for (tab= create_info.merge_list.first;
unknown's avatar
unknown committed
2727 2728 2729
               tab;
               tab= tab->next_local)
          {
2730
            TABLE_LIST *duplicate;
2731
            if ((duplicate= unique_table(thd, tab, select_tables, 0)))
unknown's avatar
unknown committed
2732
            {
2733
              update_non_unique_table_error(tab, "CREATE", duplicate);
unknown's avatar
unknown committed
2734
              res= 1;
2735
              goto end_with_restore_list;
unknown's avatar
unknown committed
2736 2737 2738
            }
          }
        }
2739

2740 2741 2742 2743
        /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
        if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
          thd->options|= OPTION_KEEP_LOG;

unknown's avatar
unknown committed
2744
        /*
2745 2746
          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
2747
        */
unknown's avatar
VIEW  
unknown committed
2748
        if ((result= new select_create(create_table,
2749 2750 2751 2752
                                       &create_info,
                                       &alter_info,
                                       select_lex->item_list,
                                       lex->duplicates,
2753
                                       lex->ignore,
2754
                                       select_tables)))
2755 2756 2757 2758 2759
        {
          /*
            CREATE from SELECT give its SELECT_LEX for SELECT,
            and item_list belong to SELECT
          */
2760
          res= handle_select(thd, lex, result, 0);
2761
          delete result;
2762
        }
2763
      }
2764
      else if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
unknown's avatar
unknown committed
2765 2766
        create_table= lex->unlink_first_table(&link_to_local);

2767
    }
unknown's avatar
unknown committed
2768
    else
unknown's avatar
unknown committed
2769
    {
2770
      /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
2771
      if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
2772
        thd->options|= OPTION_KEEP_LOG;
unknown's avatar
unknown committed
2773
      /* regular create */
2774
      if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
unknown's avatar
unknown committed
2775
        res= mysql_create_like_table(thd, create_table, select_tables,
2776
                                     &create_info);
unknown's avatar
unknown committed
2777
      else
2778
      {
unknown's avatar
VIEW  
unknown committed
2779
        res= mysql_create_table(thd, create_table->db,
2780 2781
                                create_table->table_name, &create_info,
                                &alter_info, 0, 0);
2782
      }
unknown's avatar
unknown committed
2783
      if (!res)
2784
	my_ok(thd);
unknown's avatar
unknown committed
2785
    }
2786

unknown's avatar
unknown committed
2787
    /* put tables back for PS rexecuting */
unknown's avatar
unknown committed
2788
end_with_restore_list:
unknown's avatar
VIEW  
unknown committed
2789
    lex->link_first_table_back(create_table, link_to_local);
unknown's avatar
unknown committed
2790
    break;
unknown's avatar
unknown committed
2791
  }
unknown's avatar
unknown committed
2792
  case SQLCOM_CREATE_INDEX:
2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810
    /* 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
2811 2812
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (check_one_table_access(thd, INDEX_ACL, all_tables))
unknown's avatar
unknown committed
2813
      goto error; /* purecov: inspected */
2814
    if (end_active_trans(thd))
unknown's avatar
unknown committed
2815
      goto error;
2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826
    /*
      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
2827

2828 2829 2830 2831 2832
    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
2833
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
2834
  case SQLCOM_SLAVE_START:
2835
  {
2836
    pthread_mutex_lock(&LOCK_active_mi);
2837
    start_slave(thd,active_mi,1 /* net report*/);
2838
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2839
    break;
2840
  }
unknown's avatar
unknown committed
2841
  case SQLCOM_SLAVE_STOP:
2842 2843 2844 2845 2846 2847
  /*
    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,
2848
      so it waits for the client thread because t is locked by it.
2849
    - then the client thread does SLAVE STOP.
2850 2851
      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.
2852 2853 2854
    To prevent that, refuse SLAVE STOP if the
    client thread has locked tables
  */
2855
  if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock)
2856
  {
2857 2858
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
2859
    goto error;
2860
  }
2861
  {
2862
    pthread_mutex_lock(&LOCK_active_mi);
2863
    stop_slave(thd,active_mi,1/* net report*/);
2864
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
2865
    break;
2866
  }
unknown's avatar
unknown committed
2867
#endif /* HAVE_REPLICATION */
2868

unknown's avatar
unknown committed
2869
  case SQLCOM_ALTER_TABLE:
unknown's avatar
VIEW  
unknown committed
2870
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2871
    {
unknown's avatar
unknown committed
2872
      ulong priv=0;
unknown's avatar
unknown committed
2873
      ulong priv_needed= ALTER_ACL;
2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884
      /*
        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;
2885 2886 2887 2888
      /*
        We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
        as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
      */
2889
      if (alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME))
unknown's avatar
unknown committed
2890 2891
        priv_needed|= DROP_ACL;

unknown's avatar
unknown committed
2892 2893
      /* Must be set in the parser */
      DBUG_ASSERT(select_lex->db);
unknown's avatar
unknown committed
2894
      if (check_access(thd, priv_needed, first_table->db,
2895 2896 2897
		       &first_table->grant.privilege, 0, 0,
                       test(first_table->schema_table)) ||
	  check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0,
2898
                       is_schema_db(select_lex->db))||
unknown's avatar
VIEW  
unknown committed
2899
	  check_merge_table_access(thd, first_table->db,
2900
				   create_info.merge_list.first))
2901
	goto error;				/* purecov: inspected */
2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913
      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
2914
      }
2915

2916
      /* Don't yet allow changing of symlinks with ALTER TABLE */
2917
      if (create_info.data_file_name)
2918 2919 2920
        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                            WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
                            "DATA DIRECTORY");
2921
      if (create_info.index_file_name)
2922 2923 2924
        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                            WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
                            "INDEX DIRECTORY");
2925
      create_info.data_file_name= create_info.index_file_name= NULL;
unknown's avatar
unknown committed
2926
      /* ALTER TABLE ends previous transaction */
2927
      if (end_active_trans(thd))
unknown's avatar
unknown committed
2928
	goto error;
2929

2930 2931 2932 2933 2934
      if (!thd->locked_tables &&
          !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
      {
        res= 1;
        break;
unknown's avatar
unknown committed
2935
      }
2936

2937
      thd->enable_slow_log= opt_log_slow_admin_statements;
2938
      res= mysql_alter_table(thd, select_lex->db, lex->name.str,
2939 2940 2941
                             &create_info,
                             first_table,
                             &alter_info,
2942 2943
                             select_lex->order_list.elements,
                             (ORDER *) select_lex->order_list.first,
2944
                             lex->ignore);
unknown's avatar
unknown committed
2945 2946
      break;
    }
unknown's avatar
unknown committed
2947
  case SQLCOM_RENAME_TABLE:
unknown's avatar
unknown committed
2948
  {
unknown's avatar
VIEW  
unknown committed
2949
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2950
    TABLE_LIST *table;
unknown's avatar
VIEW  
unknown committed
2951
    for (table= first_table; table; table= table->next_local->next_local)
unknown's avatar
unknown committed
2952
    {
unknown's avatar
unknown committed
2953
      if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
2954
		       &table->grant.privilege,0,0, test(table->schema_table)) ||
unknown's avatar
VIEW  
unknown committed
2955
	  check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
2956 2957
		       &table->next_local->grant.privilege, 0, 0,
                       test(table->next_local->schema_table)))
unknown's avatar
unknown committed
2958
	goto error;
2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970
      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
2971
    }
2972

unknown's avatar
unknown committed
2973
    if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
unknown's avatar
unknown committed
2974
      goto error;
unknown's avatar
unknown committed
2975
    break;
unknown's avatar
unknown committed
2976
  }
2977
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
2978 2979
  case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2980 2981
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2982
    goto error;
unknown's avatar
unknown committed
2983 2984
#else
    {
unknown's avatar
unknown committed
2985
      if (check_global_access(thd, SUPER_ACL))
unknown's avatar
unknown committed
2986 2987 2988 2989
	goto error;
      res = show_binlogs(thd);
      break;
    }
unknown's avatar
unknown committed
2990
#endif
2991
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
2992
  case SQLCOM_SHOW_CREATE:
unknown's avatar
VIEW  
unknown committed
2993
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
2994
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
2995 2996
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0)); /* purecov: inspected */
2997
    goto error;
unknown's avatar
unknown committed
2998
#else
unknown's avatar
unknown committed
2999
    {
3000 3001 3002
      /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
      if (lex->only_view)
        first_table->skip_temporary= 1;
unknown's avatar
unknown committed
3003
      if (check_show_create_table_access(thd, first_table))
3004
	goto error;
unknown's avatar
unknown committed
3005
      res= mysqld_show_create(thd, first_table);
unknown's avatar
unknown committed
3006 3007
      break;
    }
unknown's avatar
unknown committed
3008
#endif
3009 3010
  case SQLCOM_CHECKSUM:
  {
unknown's avatar
VIEW  
unknown committed
3011
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3012 3013
    if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables,
                           UINT_MAX, FALSE))
3014
      goto error; /* purecov: inspected */
unknown's avatar
VIEW  
unknown committed
3015
    res = mysql_checksum_table(thd, first_table, &lex->check_opt);
3016 3017
    break;
  }
unknown's avatar
unknown committed
3018
  case SQLCOM_REPAIR:
3019
  {
unknown's avatar
VIEW  
unknown committed
3020
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3021 3022
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
                           UINT_MAX, FALSE))
3023
      goto error; /* purecov: inspected */
3024
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
3025
    res= mysql_repair_table(thd, first_table, &lex->check_opt);
3026 3027 3028
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
3029 3030 3031
      /*
        Presumably, REPAIR and binlog writing doesn't require synchronization
      */
He Zhenxing's avatar
He Zhenxing committed
3032
      res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
3033
    }
3034
    select_lex->table_list.first= first_table;
3035
    lex->query_tables=all_tables;
3036 3037
    break;
  }
unknown's avatar
unknown committed
3038
  case SQLCOM_CHECK:
3039
  {
unknown's avatar
VIEW  
unknown committed
3040
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3041 3042
    if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables,
                           UINT_MAX, FALSE))
3043
      goto error; /* purecov: inspected */
3044
    thd->enable_slow_log= opt_log_slow_admin_statements;
unknown's avatar
VIEW  
unknown committed
3045
    res = mysql_check_table(thd, first_table, &lex->check_opt);
3046
    select_lex->table_list.first= first_table;
3047
    lex->query_tables=all_tables;
3048 3049
    break;
  }
unknown's avatar
unknown committed
3050 3051
  case SQLCOM_ANALYZE:
  {
unknown's avatar
VIEW  
unknown committed
3052
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3053 3054
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
                           UINT_MAX, FALSE))
unknown's avatar
unknown committed
3055
      goto error; /* purecov: inspected */
3056
    thd->enable_slow_log= opt_log_slow_admin_statements;
3057
    res= mysql_analyze_table(thd, first_table, &lex->check_opt);
3058 3059 3060
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
3061 3062 3063
      /*
        Presumably, ANALYZE and binlog writing doesn't require synchronization
      */
He Zhenxing's avatar
He Zhenxing committed
3064
      res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
3065
    }
3066
    select_lex->table_list.first= first_table;
3067
    lex->query_tables=all_tables;
unknown's avatar
unknown committed
3068
    break;
unknown's avatar
unknown committed
3069
  }
3070

unknown's avatar
unknown committed
3071 3072
  case SQLCOM_OPTIMIZE:
  {
unknown's avatar
VIEW  
unknown committed
3073
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3074 3075
    if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
                           UINT_MAX, FALSE))
unknown's avatar
unknown committed
3076
      goto error; /* purecov: inspected */
3077
    thd->enable_slow_log= opt_log_slow_admin_statements;
3078
    res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
3079
      mysql_recreate_table(thd, first_table) :
unknown's avatar
VIEW  
unknown committed
3080
      mysql_optimize_table(thd, first_table, &lex->check_opt);
3081 3082 3083
    /* ! we write after unlocking the table */
    if (!res && !lex->no_write_to_binlog)
    {
3084 3085 3086
      /*
        Presumably, OPTIMIZE and binlog writing doesn't require synchronization
      */
He Zhenxing's avatar
He Zhenxing committed
3087
      res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
3088
    }
3089
    select_lex->table_list.first= first_table;
3090
    lex->query_tables=all_tables;
unknown's avatar
unknown committed
3091 3092 3093
    break;
  }
  case SQLCOM_UPDATE:
unknown's avatar
VIEW  
unknown committed
3094 3095
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if (update_precheck(thd, all_tables))
unknown's avatar
unknown committed
3096
      break;
3097 3098 3099
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
      goto error;
3100 3101
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
unknown's avatar
unknown committed
3102 3103 3104 3105 3106
    res= (up_result= mysql_update(thd, all_tables,
                                  select_lex->item_list,
                                  lex->value_list,
                                  select_lex->where,
                                  select_lex->order_list.elements,
3107
                                  select_lex->order_list.first,
unknown's avatar
unknown committed
3108 3109
                                  unit->select_limit_cnt,
                                  lex->duplicates, lex->ignore));
3110
    /* mysql_update return 2 if we need to switch to multi-update */
unknown's avatar
unknown committed
3111
    if (up_result != 2)
3112
      break;
unknown's avatar
unknown committed
3113
    /* Fall through */
3114
  case SQLCOM_UPDATE_MULTI:
unknown's avatar
unknown committed
3115 3116 3117
  {
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    /* if we switched from normal update, rights are checked */
unknown's avatar
unknown committed
3118
    if (up_result != 2)
3119
    {
unknown's avatar
unknown committed
3120 3121 3122 3123 3124
      if ((res= multi_update_precheck(thd, all_tables)))
        break;
    }
    else
      res= 0;
unknown's avatar
unknown committed
3125

3126 3127 3128 3129 3130 3131 3132 3133 3134
    /*
      Protection might have already been risen if its a fall through
      from the SQLCOM_UPDATE case above.
    */
    if (!thd->locked_tables &&
        lex->sql_command == SQLCOM_UPDATE_MULTI &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
      goto error;

3135
    res= mysql_multi_update_prepare(thd);
unknown's avatar
unknown committed
3136

3137
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
3138
    /* Check slave filtering rules */
3139
    if (unlikely(thd->slave_thread && !have_table_map_for_update))
unknown's avatar
unknown committed
3140
    {
3141 3142
      if (all_tables_not_ok(thd, all_tables))
      {
3143 3144 3145 3146 3147
        if (res!= 0)
        {
          res= 0;             /* don't care of prev failure  */
          thd->clear_error(); /* filters are of highest prior */
        }
3148 3149 3150 3151
        /* we warn the slave SQL thread */
        my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
        break;
      }
3152 3153
      if (res)
        break;
unknown's avatar
unknown committed
3154
    }
3155 3156
    else
    {
3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169
#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
3170

unknown's avatar
unknown committed
3171 3172 3173 3174 3175 3176
    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
3177
    break;
unknown's avatar
unknown committed
3178
  }
unknown's avatar
unknown committed
3179
  case SQLCOM_REPLACE:
3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203
#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);
He Zhenxing's avatar
He Zhenxing committed
3204
        (void) mysql_bin_log.write(&ev);        /* error is ignored */
3205 3206 3207 3208 3209
        mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
      }
      DBUG_PRINT("debug", ("Just after generate_incident()"));
    }
#endif
3210 3211
  case SQLCOM_INSERT:
  {
unknown's avatar
VIEW  
unknown committed
3212
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3213
    if ((res= insert_precheck(thd, all_tables)))
unknown's avatar
unknown committed
3214
      break;
3215 3216 3217 3218 3219 3220 3221 3222

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

unknown's avatar
VIEW  
unknown committed
3223
    res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
unknown's avatar
unknown committed
3224
		      lex->update_list, lex->value_list,
3225
                      lex->duplicates, lex->ignore);
3226 3227 3228 3229 3230 3231 3232

    /*
      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
3233
    if (first_table->view && !first_table->contain_auto_increment)
3234 3235
      thd->first_successful_insert_id_in_cur_stmt=
        thd->first_successful_insert_id_in_prev_stmt;
3236

unknown's avatar
unknown committed
3237
    break;
3238
  }
unknown's avatar
unknown committed
3239 3240 3241
  case SQLCOM_REPLACE_SELECT:
  case SQLCOM_INSERT_SELECT:
  {
unknown's avatar
unknown committed
3242
    select_result *sel_result;
unknown's avatar
VIEW  
unknown committed
3243
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3244
    if ((res= insert_precheck(thd, all_tables)))
3245
      break;
unknown's avatar
unknown committed
3246

3247
    /* Fix lock for first table */
unknown's avatar
VIEW  
unknown committed
3248 3249
    if (first_table->lock_type == TL_WRITE_DELAYED)
      first_table->lock_type= TL_WRITE;
3250

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

3254
    unit->set_limit(select_lex);
3255 3256 3257 3258 3259 3260 3261 3262

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

unknown's avatar
VIEW  
unknown committed
3263
    if (!(res= open_and_lock_tables(thd, all_tables)))
3264
    {
3265
      /* Skip first table, which is the table we are inserting in */
unknown's avatar
unknown committed
3266
      TABLE_LIST *second_table= first_table->next_local;
3267
      select_lex->table_list.first= second_table;
3268 3269
      select_lex->context.table_list= 
        select_lex->context.first_name_resolution_table= second_table;
3270
      res= mysql_insert_select_prepare(thd);
unknown's avatar
unknown committed
3271 3272 3273 3274 3275 3276 3277
      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)))
3278
      {
unknown's avatar
unknown committed
3279
	res= handle_select(thd, lex, sel_result, OPTION_SETUP_TABLES_DONE);
3280 3281 3282 3283 3284 3285
        /*
          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.
        */
3286
        if (!res && first_table->lock_type ==  TL_WRITE_CONCURRENT_INSERT &&
3287 3288
            thd->lock)
        {
3289 3290 3291
          /* INSERT ... SELECT should invalidate only the very first table */
          TABLE_LIST *save_table= first_table->next_local;
          first_table->next_local= 0;
3292
          query_cache_invalidate3(thd, first_table, 1);
3293
          first_table->next_local= save_table;
3294
        }
unknown's avatar
unknown committed
3295
        delete sel_result;
3296
      }
3297
      /* revert changes for SP */
3298
      select_lex->table_list.first= first_table;
3299
    }
unknown's avatar
VIEW  
unknown committed
3300

3301 3302 3303 3304 3305 3306
    /*
      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
3307
    if (first_table->view && !first_table->contain_auto_increment)
3308 3309
      thd->first_successful_insert_id_in_cur_stmt=
        thd->first_successful_insert_id_in_prev_stmt;
3310

unknown's avatar
unknown committed
3311 3312
    break;
  }
3313
  case SQLCOM_TRUNCATE:
3314 3315 3316 3317 3318
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
VIEW  
unknown committed
3319
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3320
    if (check_one_table_access(thd, DROP_ACL, all_tables))
unknown's avatar
unknown committed
3321
      goto error;
3322 3323 3324 3325
    /*
      Don't allow this within a transaction because we want to use
      re-generate table
    */
3326
    if (thd->locked_tables || thd->active_transaction())
3327
    {
unknown's avatar
unknown committed
3328 3329
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3330 3331
      goto error;
    }
3332 3333
    if (!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
      goto error;
unknown's avatar
unknown committed
3334
    res= mysql_truncate(thd, first_table, 0);
3335
    break;
unknown's avatar
unknown committed
3336
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
3337
  {
unknown's avatar
VIEW  
unknown committed
3338 3339
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    if ((res= delete_precheck(thd, all_tables)))
unknown's avatar
unknown committed
3340
      break;
3341 3342
    DBUG_ASSERT(select_lex->offset_limit == 0);
    unit->set_limit(select_lex);
3343 3344 3345 3346 3347 3348 3349 3350

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

unknown's avatar
VIEW  
unknown committed
3351
    res = mysql_delete(thd, all_tables, select_lex->where,
3352
                       &select_lex->order_list,
unknown's avatar
unknown committed
3353 3354
                       unit->select_limit_cnt, select_lex->options,
                       FALSE);
unknown's avatar
unknown committed
3355 3356
    break;
  }
3357
  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
3358
  {
unknown's avatar
VIEW  
unknown committed
3359
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3360
    TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
unknown's avatar
unknown committed
3361
    multi_delete *del_result;
unknown's avatar
unknown committed
3362

3363 3364 3365 3366 3367 3368 3369
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
    {
      res= 1;
      break;
    }

3370
    if ((res= multi_delete_precheck(thd, all_tables)))
3371
      break;
unknown's avatar
unknown committed
3372

unknown's avatar
unknown committed
3373
    /* condition will be TRUE on SP re-excuting */
3374 3375
    if (select_lex->item_list.elements != 0)
      select_lex->item_list.empty();
unknown's avatar
unknown committed
3376
    if (add_item_to_list(thd, new Item_null()))
unknown's avatar
unknown committed
3377
      goto error;
3378

3379
    thd_proc_info(thd, "init");
unknown's avatar
VIEW  
unknown committed
3380 3381 3382 3383
    if ((res= open_and_lock_tables(thd, all_tables)))
      break;

    if ((res= mysql_multi_delete_prepare(thd)))
unknown's avatar
unknown committed
3384
      goto error;
3385

unknown's avatar
unknown committed
3386 3387
    if (!thd->is_fatal_error &&
        (del_result= new multi_delete(aux_tables, lex->table_count)))
unknown's avatar
unknown committed
3388
    {
3389 3390 3391
      res= mysql_select(thd, &select_lex->ref_pointer_array,
			select_lex->get_table_list(),
			select_lex->with_wild,
3392
			select_lex->item_list,
unknown's avatar
unknown committed
3393
			select_lex->where,
3394
			0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
unknown's avatar
unknown committed
3395
			(ORDER *)NULL,
3396
			(select_lex->options | thd->options |
3397
			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
3398
                        OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT,
unknown's avatar
unknown committed
3399
			del_result, unit, select_lex);
3400 3401
      res|= thd->is_error();
      if (res)
3402
        del_result->abort();
unknown's avatar
unknown committed
3403
      delete del_result;
unknown's avatar
unknown committed
3404 3405
    }
    else
3406
      res= TRUE;                                // Error
unknown's avatar
unknown committed
3407 3408
    break;
  }
unknown's avatar
unknown committed
3409
  case SQLCOM_DROP_TABLE:
unknown's avatar
unknown committed
3410
  {
unknown's avatar
VIEW  
unknown committed
3411
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
3412 3413
    if (!lex->drop_temporary)
    {
3414
      if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE))
3415 3416
	goto error;				/* purecov: inspected */
      if (end_active_trans(thd))
unknown's avatar
unknown committed
3417
        goto error;
3418
    }
unknown's avatar
unknown committed
3419
    else
unknown's avatar
unknown committed
3420
    {
unknown's avatar
unknown committed
3421
      /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
3422
      thd->options|= OPTION_KEEP_LOG;
unknown's avatar
unknown committed
3423
    }
3424
    /* DDL and binlog write order protected by LOCK_open */
unknown's avatar
VIEW  
unknown committed
3425 3426
    res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
			lex->drop_temporary);
unknown's avatar
unknown committed
3427 3428
  }
  break;
unknown's avatar
unknown committed
3429
  case SQLCOM_SHOW_PROCESSLIST:
3430 3431
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd,PROCESS_ACL))
unknown's avatar
unknown committed
3432
      break;
unknown's avatar
unknown committed
3433
    mysqld_list_processes(thd,
3434 3435 3436 3437
			  (thd->security_ctx->master_access & PROCESS_ACL ?
                           NullS :
                           thd->security_ctx->priv_user),
                          lex->verbose);
unknown's avatar
unknown committed
3438
    break;
unknown's avatar
unknown committed
3439 3440 3441
  case SQLCOM_SHOW_AUTHORS:
    res= mysqld_show_authors(thd);
    break;
3442 3443 3444
  case SQLCOM_SHOW_CONTRIBUTORS:
    res= mysqld_show_contributors(thd);
    break;
unknown's avatar
unknown committed
3445 3446 3447 3448 3449 3450
  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
3451
  case SQLCOM_SHOW_ENGINE_LOGS:
unknown's avatar
unknown committed
3452
#ifdef DONT_ALLOW_SHOW_COMMANDS
unknown's avatar
unknown committed
3453 3454
    my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
3455
    goto error;
unknown's avatar
unknown committed
3456 3457
#else
    {
3458
      if (check_access(thd, FILE_ACL, any_db,0,0,0,0))
unknown's avatar
unknown committed
3459
	goto error;
unknown's avatar
unknown committed
3460
      res= ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_LOGS);
unknown's avatar
unknown committed
3461 3462
      break;
    }
unknown's avatar
unknown committed
3463 3464
#endif
  case SQLCOM_CHANGE_DB:
3465 3466 3467 3468
  {
    LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) };

    if (!mysql_change_db(thd, &db_str, FALSE))
3469
      my_ok(thd);
3470

unknown's avatar
unknown committed
3471
    break;
3472
  }
3473

unknown's avatar
unknown committed
3474 3475
  case SQLCOM_LOAD:
  {
unknown's avatar
VIEW  
unknown committed
3476
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
unknown's avatar
unknown committed
3477
    uint privilege= (lex->duplicates == DUP_REPLACE ?
unknown's avatar
unknown committed
3478 3479
		     INSERT_ACL | DELETE_ACL : INSERT_ACL) |
                    (lex->local_file ? 0 : FILE_ACL);
3480

unknown's avatar
unknown committed
3481
    if (lex->local_file)
unknown's avatar
unknown committed
3482
    {
3483
      if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
3484
          !opt_local_infile)
3485
      {
unknown's avatar
unknown committed
3486
	my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0));
3487 3488
	goto error;
      }
unknown's avatar
unknown committed
3489
    }
unknown's avatar
unknown committed
3490 3491 3492 3493

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

3494 3495 3496 3497
    if (!thd->locked_tables &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
      goto error;

unknown's avatar
VIEW  
unknown committed
3498
    res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
unknown's avatar
unknown committed
3499
                    lex->update_list, lex->value_list, lex->duplicates,
3500
                    lex->ignore, (bool) lex->local_file);
unknown's avatar
unknown committed
3501 3502
    break;
  }
3503

unknown's avatar
unknown committed
3504
  case SQLCOM_SET_OPTION:
3505 3506
  {
    List<set_var_base> *lex_var_list= &lex->var_list;
3507 3508 3509 3510

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

3511
    if ((check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
unknown's avatar
unknown committed
3512 3513
	 open_and_lock_tables(thd, all_tables)))
      goto error;
3514 3515
    if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
    {
unknown's avatar
unknown committed
3516 3517
      my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
      goto error;
3518 3519 3520 3521 3522 3523 3524 3525
    }
    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;
3526
      my_ok(thd);
3527
    }
3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539
    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
3540
    break;
3541
  }
unknown's avatar
unknown committed
3542

unknown's avatar
unknown committed
3543
  case SQLCOM_UNLOCK_TABLES:
3544 3545 3546 3547 3548 3549
    /*
      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
3550
    unlock_locked_tables(thd);
unknown's avatar
unknown committed
3551 3552
    if (thd->options & OPTION_TABLE_LOCK)
    {
unknown's avatar
unknown committed
3553
      end_active_trans(thd);
3554
      thd->options&= ~(OPTION_TABLE_LOCK);
unknown's avatar
unknown committed
3555 3556
    }
    if (thd->global_read_lock)
3557
      unlock_global_read_lock(thd);
3558
    my_ok(thd);
unknown's avatar
unknown committed
3559 3560
    break;
  case SQLCOM_LOCK_TABLES:
unknown's avatar
unknown committed
3561
    unlock_locked_tables(thd);
3562
    /* we must end the trasaction first, regardless of anything */
unknown's avatar
unknown committed
3563
    if (end_active_trans(thd))
unknown's avatar
unknown committed
3564
      goto error;
3565 3566
    if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
                           UINT_MAX, FALSE))
3567
      goto error;
3568 3569 3570
    if (lex->protect_against_global_read_lock &&
        !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
      goto error;
unknown's avatar
unknown committed
3571
    thd->in_lock_tables=1;
unknown's avatar
unknown committed
3572
    thd->options|= OPTION_TABLE_LOCK;
unknown's avatar
VIEW  
unknown committed
3573

3574
    if (!(res= simple_open_n_lock_tables(thd, all_tables)))
unknown's avatar
unknown committed
3575
    {
3576 3577
#ifdef HAVE_QUERY_CACHE
      if (thd->variables.query_cache_wlock_invalidate)
unknown's avatar
VIEW  
unknown committed
3578
	query_cache.invalidate_locked_for_write(first_table);
3579
#endif /*HAVE_QUERY_CACHE*/
unknown's avatar
unknown committed
3580 3581
      thd->locked_tables=thd->lock;
      thd->lock=0;
3582
      my_ok(thd);
unknown's avatar
unknown committed
3583
    }
unknown's avatar
unknown committed
3584
    else
3585 3586 3587 3588 3589 3590
    {
      /* 
        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
      */
3591
      ha_autocommit_or_rollback(thd, 1);
3592
      end_active_trans(thd);
3593
      thd->options&= ~(OPTION_TABLE_LOCK);
3594
    }
unknown's avatar
unknown committed
3595 3596 3597
    thd->in_lock_tables=0;
    break;
  case SQLCOM_CREATE_DB:
3598
  {
3599 3600 3601 3602 3603 3604
    /*
      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);
3605 3606 3607 3608 3609
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
unknown's avatar
unknown committed
3610
    char *alias;
3611 3612
    if (!(alias=thd->strmake(lex->name.str, lex->name.length)) ||
        check_db_name(&lex->name))
unknown's avatar
unknown committed
3613
    {
3614
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3615 3616
      break;
    }
3617 3618 3619
    /*
      If in a slave thread :
      CREATE DATABASE DB was certainly not preceded by USE DB.
3620
      For that reason, db_ok() in sql/slave.cc did not check the
3621 3622 3623
      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.
    */
3624
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
3625
    if (thd->slave_thread && 
3626 3627
	(!rpl_filter->db_ok(lex->name.str) ||
	 !rpl_filter->db_ok_with_wild_table(lex->name.str)))
unknown's avatar
unknown committed
3628
    {
unknown's avatar
unknown committed
3629
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3630
      break;
unknown's avatar
unknown committed
3631
    }
3632
#endif
3633
    if (check_access(thd,CREATE_ACL,lex->name.str, 0, 1, 0,
3634
                     is_schema_db(lex->name.str, lex->name.length)))
3635
      break;
3636
    res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
3637
                              lex->name.str), &create_info, 0);
3638 3639
    break;
  }
unknown's avatar
unknown committed
3640
  case SQLCOM_DROP_DB:
3641
  {
3642 3643 3644 3645 3646
    if (end_active_trans(thd))
    {
      res= -1;
      break;
    }
3647
    if (check_db_name(&lex->name))
unknown's avatar
unknown committed
3648
    {
3649
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3650 3651
      break;
    }
3652 3653 3654 3655 3656 3657 3658
    /*
      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.
    */
3659
#ifdef HAVE_REPLICATION
3660
    if (thd->slave_thread && 
3661 3662
	(!rpl_filter->db_ok(lex->name.str) ||
	 !rpl_filter->db_ok_with_wild_table(lex->name.str)))
unknown's avatar
unknown committed
3663
    {
unknown's avatar
unknown committed
3664
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
3665
      break;
unknown's avatar
unknown committed
3666
    }
3667
#endif
3668
    if (check_access(thd,DROP_ACL,lex->name.str,0,1,0,
3669
                     is_schema_db(lex->name.str, lex->name.length)))
3670
      break;
3671 3672
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3673 3674
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3675 3676
      goto error;
    }
3677
    res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0);
3678 3679
    break;
  }
3680
  case SQLCOM_ALTER_DB_UPGRADE:
unknown's avatar
unknown committed
3681
  {
3682
    LEX_STRING *db= & lex->name;
unknown's avatar
unknown committed
3683 3684 3685 3686 3687 3688 3689
    if (end_active_trans(thd))
    {
      res= 1;
      break;
    }
#ifdef HAVE_REPLICATION
    if (thd->slave_thread && 
3690 3691
       (!rpl_filter->db_ok(db->str) ||
        !rpl_filter->db_ok_with_wild_table(db->str)))
unknown's avatar
unknown committed
3692 3693 3694 3695 3696 3697
    {
      res= 1;
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
      break;
    }
#endif
3698
    if (check_db_name(db))
3699
    {
3700
      my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
3701 3702
      break;
    }
3703 3704 3705 3706 3707 3708
    if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0,
                     is_schema_db(db->str, db->length)) ||
        check_access(thd, DROP_ACL, db->str, 0, 1, 0,
                     is_schema_db(db->str, db->length)) ||
        check_access(thd, CREATE_ACL, db->str, 0, 1, 0,
                     is_schema_db(db->str, db->length)))
unknown's avatar
unknown committed
3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719
    {
      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;
    }
3720 3721

    res= mysql_upgrade_db(thd, db);
unknown's avatar
unknown committed
3722
    if (!res)
3723
      my_ok(thd);
unknown's avatar
unknown committed
3724 3725
    break;
  }
3726 3727
  case SQLCOM_ALTER_DB:
  {
3728
    LEX_STRING *db= &lex->name;
3729
    HA_CREATE_INFO create_info(lex->create_info);
3730
    if (check_db_name(db))
3731
    {
3732
      my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
3733 3734
      break;
    }
unknown's avatar
unknown committed
3735 3736 3737
    /*
      If in a slave thread :
      ALTER DATABASE DB may not be preceded by USE DB.
3738
      For that reason, maybe db_ok() in sql/slave.cc did not check the
unknown's avatar
unknown committed
3739 3740 3741 3742
      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
3743
    if (thd->slave_thread &&
3744 3745
	(!rpl_filter->db_ok(db->str) ||
	 !rpl_filter->db_ok_with_wild_table(db->str)))
unknown's avatar
unknown committed
3746
    {
unknown's avatar
unknown committed
3747
      my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
unknown's avatar
unknown committed
3748 3749 3750
      break;
    }
#endif
3751 3752
    if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0,
                     is_schema_db(db->str, db->length)))
3753 3754 3755
      break;
    if (thd->locked_tables || thd->active_transaction())
    {
unknown's avatar
unknown committed
3756 3757
      my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
3758 3759
      goto error;
    }
3760
    res= mysql_alter_db(thd, db->str, &create_info);
3761 3762
    break;
  }
unknown's avatar
unknown committed
3763 3764
  case SQLCOM_SHOW_CREATE_DB:
  {
unknown's avatar
unknown committed
3765 3766
    DBUG_EXECUTE_IF("4x_server_emul",
                    my_error(ER_UNKNOWN_ERROR, MYF(0)); goto error;);
3767
    if (check_db_name(&lex->name))
unknown's avatar
unknown committed
3768
    {
3769
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str);
unknown's avatar
unknown committed
3770 3771
      break;
    }
3772
    res= mysqld_show_create_db(thd, lex->name.str, &lex->create_info);
unknown's avatar
unknown committed
3773 3774
    break;
  }
unknown's avatar
unknown committed
3775 3776
  case SQLCOM_CREATE_EVENT:
  case SQLCOM_ALTER_EVENT:
3777
  #ifdef HAVE_EVENT_SCHEDULER
3778
  do
unknown's avatar
unknown committed
3779
  {
unknown's avatar
unknown committed
3780
    DBUG_ASSERT(lex->event_parse_data);
unknown's avatar
unknown committed
3781 3782 3783 3784 3785 3786
    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;
    }
3787 3788 3789 3790 3791

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

unknown's avatar
unknown committed
3792 3793
    switch (lex->sql_command) {
    case SQLCOM_CREATE_EVENT:
3794 3795 3796 3797
    {
      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
3798
      break;
3799
    }
unknown's avatar
unknown committed
3800
    case SQLCOM_ALTER_EVENT:
3801 3802 3803
      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
3804
      break;
3805 3806
    default:
      DBUG_ASSERT(0);
unknown's avatar
unknown committed
3807
    }
3808
    DBUG_PRINT("info",("DDL error code=%d", res));
unknown's avatar
unknown committed
3809
    if (!res)
3810
      my_ok(thd);
unknown's avatar
unknown committed
3811

3812 3813 3814 3815 3816 3817
  } 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
3818
  }
3819 3820
  /* lex->unit.cleanup() is called outside, no need to call it here */
  break;
unknown's avatar
unknown committed
3821
  case SQLCOM_SHOW_CREATE_EVENT:
3822 3823 3824 3825 3826 3827 3828
    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)))
3829
      my_ok(thd);
3830
    break;
3831 3832 3833 3834
#else
    my_error(ER_NOT_SUPPORTED_YET,MYF(0),"embedded server");
    break;
#endif
unknown's avatar
unknown committed
3835
  case SQLCOM_CREATE_FUNCTION:                  // UDF function
unknown's avatar
unknown committed
3836
  {
3837
    if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
unknown's avatar
unknown committed
3838
      break;
unknown's avatar
unknown committed
3839
#ifdef HAVE_DLOPEN
3840
    if (!(res = mysql_create_function(thd, &lex->udf)))
3841
      my_ok(thd);
unknown's avatar
unknown committed
3842
#else
unknown's avatar
unknown committed
3843
    my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled");
unknown's avatar
unknown committed
3844
    res= TRUE;
unknown's avatar
unknown committed
3845 3846
#endif
    break;
unknown's avatar
unknown committed
3847
  }
unknown's avatar
unknown committed
3848
#ifndef NO_EMBEDDED_ACCESS_CHECKS
3849 3850
  case SQLCOM_CREATE_USER:
  {
3851
    if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1, 0) &&
3852
        check_global_access(thd,CREATE_USER_ACL))
3853
      break;
3854 3855
    if (end_active_trans(thd))
      goto error;
3856
    /* Conditionally writes to binlog */
3857
    if (!(res= mysql_create_user(thd, lex->users_list)))
3858
      my_ok(thd);
3859 3860
    break;
  }
3861 3862
  case SQLCOM_DROP_USER:
  {
3863
    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1, 0) &&
3864
        check_global_access(thd,CREATE_USER_ACL))
3865
      break;
3866 3867
    if (end_active_trans(thd))
      goto error;
3868
    /* Conditionally writes to binlog */
3869
    if (!(res= mysql_drop_user(thd, lex->users_list)))
3870
      my_ok(thd);
3871 3872 3873 3874
    break;
  }
  case SQLCOM_RENAME_USER:
  {
3875
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
3876
        check_global_access(thd,CREATE_USER_ACL))
3877
      break;
3878 3879
    if (end_active_trans(thd))
      goto error;
3880
    /* Conditionally writes to binlog */
3881
    if (!(res= mysql_rename_user(thd, lex->users_list)))
3882
      my_ok(thd);
3883 3884 3885 3886
    break;
  }
  case SQLCOM_REVOKE_ALL:
  {
3887 3888
    if (end_active_trans(thd))
      goto error;
3889
    if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
3890
        check_global_access(thd,CREATE_USER_ACL))
3891
      break;
3892
    /* Conditionally writes to binlog */
3893
    if (!(res = mysql_revoke_all(thd, lex->users_list)))
3894
      my_ok(thd);
3895 3896
    break;
  }
3897 3898 3899
  case SQLCOM_REVOKE:
  case SQLCOM_GRANT:
  {
3900 3901 3902
    if (end_active_trans(thd))
      goto error;

3903
    if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
unknown's avatar
unknown committed
3904
		     first_table ?  first_table->db : select_lex->db,
unknown's avatar
VIEW  
unknown committed
3905
		     first_table ? &first_table->grant.privilege : 0,
3906 3907
		     first_table ? 0 : 1, 0,
                     first_table ? (bool) first_table->schema_table :
3908
                     select_lex->db ?
3909
                     is_schema_db(select_lex->db) : 0))
3910 3911
      goto error;

3912
    if (thd->security_ctx->user)              // If not replication
unknown's avatar
unknown committed
3913
    {
3914
      LEX_USER *user, *tmp_user;
3915

unknown's avatar
unknown committed
3916
      List_iterator <LEX_USER> user_list(lex->users_list);
3917
      while ((tmp_user= user_list++))
unknown's avatar
unknown committed
3918
      {
3919 3920
        if (!(user= get_current_user(thd, tmp_user)))
          goto error;
3921 3922 3923 3924 3925 3926 3927 3928
        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);
3929
        if (strcmp(thd->security_ctx->user, user->user.str) ||
3930
            my_strcasecmp(system_charset_info,
3931
                          user->host.str, thd->security_ctx->host_or_ip))
3932 3933
        {
          // TODO: use check_change_password()
3934 3935
          if (is_acl_user(user->host.str, user->user.str) &&
              user->password.str &&
3936
              check_access(thd, UPDATE_ACL,"mysql",0,1,1,0))
3937 3938 3939 3940 3941 3942
          {
            my_message(ER_PASSWORD_NOT_ALLOWED,
                       ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
            goto error;
          }
        }
unknown's avatar
SCRUM  
unknown committed
3943 3944
      }
    }
unknown's avatar
VIEW  
unknown committed
3945
    if (first_table)
3946
    {
3947 3948
      if (lex->type == TYPE_ENUM_PROCEDURE ||
          lex->type == TYPE_ENUM_FUNCTION)
3949 3950 3951 3952
      {
        uint grants= lex->all_privileges 
		   ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
		   : lex->grant;
3953
        if (check_grant_routine(thd, grants | GRANT_ACL, all_tables,
3954
                                lex->type == TYPE_ENUM_PROCEDURE, 0))
3955
	  goto error;
3956
        /* Conditionally writes to binlog */
3957 3958 3959
        res= mysql_routine_grant(thd, all_tables,
                                 lex->type == TYPE_ENUM_PROCEDURE, 
                                 lex->users_list, grants,
3960 3961 3962
                                 lex->sql_command == SQLCOM_REVOKE, TRUE);
        if (!res)
          my_ok(thd);
3963 3964 3965
      }
      else
      {
3966 3967
	if (check_grant(thd,(lex->grant | lex->grant_tot_col | GRANT_ACL),
                        all_tables, 0, UINT_MAX, 0))
3968
	  goto error;
3969
        /* Conditionally writes to binlog */
3970 3971 3972 3973
        res= mysql_table_grant(thd, all_tables, lex->users_list,
			       lex->columns, lex->grant,
			       lex->sql_command == SQLCOM_REVOKE);
      }
3974 3975 3976
    }
    else
    {
3977
      if (lex->columns.elements || lex->type)
3978
      {
unknown's avatar
unknown committed
3979 3980
	my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
                   MYF(0));
unknown's avatar
unknown committed
3981
        goto error;
3982 3983
      }
      else
3984
	/* Conditionally writes to binlog */
3985 3986 3987 3988
	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
			  lex->sql_command == SQLCOM_REVOKE);
      if (!res)
      {
3989
	if (lex->sql_command == SQLCOM_GRANT)
3990
	{
unknown's avatar
unknown committed
3991
	  List_iterator <LEX_USER> str_list(lex->users_list);
3992 3993 3994 3995 3996
	  LEX_USER *user, *tmp_user;
	  while ((tmp_user=str_list++))
          {
            if (!(user= get_current_user(thd, tmp_user)))
              goto error;
3997
	    reset_mqh(user, 0);
3998
          }
3999
	}
4000 4001 4002 4003
      }
    }
    break;
  }
unknown's avatar
SCRUM  
unknown committed
4004
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
unknown's avatar
unknown committed
4005
  case SQLCOM_RESET:
4006 4007 4008
    /*
      RESET commands are never written to the binary log, so we have to
      initialize this variable because RESET shares the same code as FLUSH
4009 4010 4011 4012
    */
    lex->no_write_to_binlog= 1;
  case SQLCOM_FLUSH:
  {
unknown's avatar
unknown committed
4013
    bool write_to_binlog;
unknown's avatar
unknown committed
4014
    if (check_global_access(thd,RELOAD_ACL))
unknown's avatar
unknown committed
4015
      goto error;
4016

4017 4018 4019 4020
    /*
      reload_acl_and_cache() will tell us if we are allowed to write to the
      binlog or not.
    */
unknown's avatar
unknown committed
4021
    if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
4022 4023 4024 4025 4026
    {
      /*
        We WANT to write and we CAN write.
        ! we write after unlocking the table.
      */
4027 4028 4029
      /*
        Presumably, RESET and binlog writing doesn't require synchronization
      */
4030 4031
      if (!lex->no_write_to_binlog && write_to_binlog)
      {
Davi Arnaut's avatar
Davi Arnaut committed
4032
        if ((res= write_bin_log(thd, FALSE, thd->query(), thd->query_length())))
He Zhenxing's avatar
He Zhenxing committed
4033
          break;
4034
      }
4035
      my_ok(thd);
4036 4037
    } 
    
unknown's avatar
unknown committed
4038
    break;
4039
  }
unknown's avatar
unknown committed
4040
  case SQLCOM_KILL:
4041 4042 4043
  {
    Item *it= (Item *)lex->value_list.head();

unknown's avatar
unknown committed
4044 4045 4046 4047 4048 4049 4050
    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;
    }

4051
    if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1))
4052 4053 4054 4055 4056
    {
      my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
		 MYF(0));
      goto error;
    }
4057
    sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
unknown's avatar
unknown committed
4058
    break;
4059
  }
unknown's avatar
unknown committed
4060
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
4061
  case SQLCOM_SHOW_GRANTS:
4062 4063 4064 4065
  {
    LEX_USER *grant_user= get_current_user(thd, lex->grant_user);
    if (!grant_user)
      goto error;
4066
    if ((thd->security_ctx->priv_user &&
4067
	 !strcmp(thd->security_ctx->priv_user, grant_user->user.str)) ||
4068
	!check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
unknown's avatar
unknown committed
4069
    {
4070
      res = mysql_show_grants(thd, grant_user);
unknown's avatar
unknown committed
4071 4072
    }
    break;
4073
  }
unknown's avatar
unknown committed
4074
#endif
4075
  case SQLCOM_HA_OPEN:
unknown's avatar
VIEW  
unknown committed
4076
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
4077
    if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE))
4078
      goto error;
unknown's avatar
unknown committed
4079
    res= mysql_ha_open(thd, first_table, 0);
4080 4081
    break;
  case SQLCOM_HA_CLOSE:
unknown's avatar
VIEW  
unknown committed
4082 4083
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
    res= mysql_ha_close(thd, first_table);
4084 4085
    break;
  case SQLCOM_HA_READ:
unknown's avatar
VIEW  
unknown committed
4086
    DBUG_ASSERT(first_table == all_tables && first_table != 0);
4087 4088 4089 4090 4091
    /*
      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.
    */
4092
    unit->set_limit(select_lex);
4093
    res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
unknown's avatar
VIEW  
unknown committed
4094
                       lex->insert_list, lex->ha_rkey_mode, select_lex->where,
4095
                       unit->select_limit_cnt, unit->offset_limit_cnt);
4096 4097
    break;

unknown's avatar
unknown committed
4098
  case SQLCOM_BEGIN:
4099 4100 4101 4102 4103 4104
    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
4105
    if (begin_trans(thd))
unknown's avatar
unknown committed
4106
      goto error;
4107 4108 4109 4110 4111
    if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
    {
      if (ha_start_consistent_snapshot(thd))
        goto error;
    }
4112
    my_ok(thd);
unknown's avatar
unknown committed
4113 4114
    break;
  case SQLCOM_COMMIT:
4115
    if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
unknown's avatar
unknown committed
4116
                              lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
unknown's avatar
unknown committed
4117
      goto error;
4118
    my_ok(thd);
unknown's avatar
unknown committed
4119 4120
    break;
  case SQLCOM_ROLLBACK:
4121
    if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
unknown's avatar
unknown committed
4122
                              lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
unknown's avatar
unknown committed
4123
      goto error;
4124
    my_ok(thd);
unknown's avatar
unknown committed
4125
    break;
unknown's avatar
unknown committed
4126
  case SQLCOM_RELEASE_SAVEPOINT:
unknown's avatar
unknown committed
4127
  {
4128 4129
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
unknown's avatar
unknown committed
4130 4131 4132
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
4133
                       (uchar *)sv->name, sv->length) == 0)
unknown's avatar
unknown committed
4134 4135
        break;
    }
4136
    if (sv)
unknown's avatar
unknown committed
4137
    {
4138
      if (ha_release_savepoint(thd, sv))
unknown's avatar
unknown committed
4139
        res= TRUE; // cannot happen
unknown's avatar
unknown committed
4140
      else
4141
        my_ok(thd);
4142
      thd->transaction.savepoints=sv->prev;
unknown's avatar
unknown committed
4143
    }
4144
    else
unknown's avatar
unknown committed
4145
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
4146
    break;
unknown's avatar
unknown committed
4147
  }
unknown's avatar
unknown committed
4148
  case SQLCOM_ROLLBACK_TO_SAVEPOINT:
unknown's avatar
unknown committed
4149
  {
4150 4151
    SAVEPOINT *sv;
    for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
4152 4153 4154
    {
      if (my_strnncoll(system_charset_info,
                       (uchar *)lex->ident.str, lex->ident.length,
4155
                       (uchar *)sv->name, sv->length) == 0)
4156 4157
        break;
    }
4158
    if (sv)
4159
    {
4160
      if (ha_rollback_to_savepoint(thd, sv))
4161 4162
        res= TRUE; // cannot happen
      else
unknown's avatar
unknown committed
4163
      {
unknown's avatar
unknown committed
4164 4165
        if (((thd->options & OPTION_KEEP_LOG) || 
             thd->transaction.all.modified_non_trans_table) &&
unknown's avatar
unknown committed
4166 4167 4168 4169
            !thd->slave_thread)
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_WARNING_NOT_COMPLETE_ROLLBACK,
                       ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
4170
        my_ok(thd);
unknown's avatar
unknown committed
4171
      }
4172
      thd->transaction.savepoints=sv;
unknown's avatar
unknown committed
4173 4174
    }
    else
4175
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
unknown's avatar
unknown committed
4176
    break;
4177
  }
4178
  case SQLCOM_SAVEPOINT:
4179 4180
    if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
          thd->in_sub_stmt) || !opt_using_transactions)
4181
      my_ok(thd);
unknown's avatar
unknown committed
4182
    else
4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217
    {
      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;
4218
        my_ok(thd);
4219 4220
      }
    }
unknown's avatar
unknown committed
4221
    break;
4222 4223
  case SQLCOM_CREATE_PROCEDURE:
  case SQLCOM_CREATE_SPFUNCTION:
unknown's avatar
unknown committed
4224
  {
4225
    uint namelen;
unknown's avatar
unknown committed
4226
    char *name;
unknown's avatar
unknown committed
4227
    int sp_result= SP_INTERNAL_ERROR;
4228

4229
    DBUG_ASSERT(lex->sphead != 0);
unknown's avatar
unknown committed
4230
    DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
4231 4232 4233 4234
    /*
      Verify that the database name is allowed, optionally
      lowercase it.
    */
4235
    if (check_db_name(&lex->sphead->m_db))
4236
    {
4237
      my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str);
4238
      goto create_sp_error;
4239 4240
    }

4241
    /*
4242 4243 4244
      Check that a database directory with this name
      exists. Design note: This won't work on virtual databases
      like information_schema.
4245 4246
    */
    if (check_db_dir_existence(lex->sphead->m_db.str))
4247
    {
4248
      my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
4249
      goto create_sp_error;
4250
    }
4251

4252
    if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
4253 4254
                     is_schema_db(lex->sphead->m_db.str,
                                  lex->sphead->m_db.length)))
4255
      goto create_sp_error;
4256

4257 4258
    if (end_active_trans(thd))
      goto create_sp_error;
4259 4260

    name= lex->sphead->name(&namelen);
4261
#ifdef HAVE_DLOPEN
unknown's avatar
unknown committed
4262 4263 4264
    if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
    {
      udf_func *udf = find_udf(name, namelen);
4265

unknown's avatar
unknown committed
4266
      if (udf)
4267
      {
4268 4269
        my_error(ER_UDF_EXISTS, MYF(0), name);
        goto create_sp_error;
4270
      }
unknown's avatar
unknown committed
4271 4272 4273
    }
#endif

4274 4275
    if (sp_process_definer(thd))
      goto create_sp_error;
4276

unknown's avatar
unknown committed
4277 4278
    res= (sp_result= lex->sphead->create(thd));
    switch (sp_result) {
4279
    case SP_OK: {
unknown's avatar
unknown committed
4280
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4281
      /* only add privileges if really neccessary */
4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304

      Security_context security_context;
      bool restore_backup_context= false;
      Security_context *backup= NULL;
      LEX_USER *definer= thd->lex->definer;
      /*
        Check if the definer exists on slave, 
        then use definer privilege to insert routine privileges to mysql.procs_priv.

        For current user of SQL thread has GLOBAL_ACL privilege, 
        which doesn't any check routine privileges, 
        so no routine privilege record  will insert into mysql.procs_priv.
      */
      if (thd->slave_thread && is_acl_user(definer->host.str, definer->user.str))
      {
        security_context.change_security_context(thd, 
                                                 &thd->lex->definer->user,
                                                 &thd->lex->definer->host,
                                                 &thd->lex->sphead->m_db,
                                                 &backup);
        restore_backup_context= true;
      }

4305
      if (sp_automatic_privileges && !opt_noacl &&
4306
          check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
4307
                               lex->sphead->m_db.str, name,
4308
                               lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
4309
      {
unknown's avatar
unknown committed
4310
        if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
4311
                                lex->sql_command == SQLCOM_CREATE_PROCEDURE))
4312 4313 4314
          push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_PROC_AUTO_GRANT_FAIL,
                       ER(ER_PROC_AUTO_GRANT_FAIL));
4315
      }
4316 4317 4318 4319 4320 4321 4322 4323 4324 4325

      /*
        Restore current user with GLOBAL_ACL privilege of SQL thread
      */ 
      if (restore_backup_context)
      {
        DBUG_ASSERT(thd->slave_thread == 1);
        thd->security_ctx->restore_security_context(thd, backup);
      }

unknown's avatar
unknown committed
4326
#endif
unknown's avatar
unknown committed
4327
    break;
4328
    }
4329 4330 4331 4332 4333 4334 4335 4336 4337
    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;
4338 4339 4340
    case SP_FLD_STORE_FAILED:
      my_error(ER_CANT_CREATE_SROUTINE, MYF(0), name);
      break;
4341 4342 4343 4344 4345 4346 4347 4348 4349 4350
    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
4351
    if (sp_result != SP_OK )
4352
      goto error;
4353
    my_ok(thd);
4354 4355
    break; /* break super switch */
  } /* end case group bracket */
4356 4357 4358 4359
  case SQLCOM_CALL:
    {
      sp_head *sp;

4360 4361 4362 4363
      /*
        This will cache all SP and SF and open and lock all tables
        required for execution.
      */
4364
      if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) ||
4365 4366 4367 4368
	  open_and_lock_tables(thd, all_tables))
       goto error;

      /*
4369 4370
        By this moment all needed SPs should be in cache so no need to look 
        into DB. 
4371
      */
4372 4373
      if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                                &thd->sp_proc_cache, TRUE)))
4374
      {
4375
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
unknown's avatar
unknown committed
4376
                 lex->spname->m_qname.str);
4377
	goto error;
4378 4379 4380
      }
      else
      {
unknown's avatar
unknown committed
4381
	ha_rows select_limit;
unknown's avatar
unknown committed
4382 4383
        /* bits that should be cleared in thd->server_status */
	uint bits_to_be_cleared= 0;
4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395
        /*
          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;
        }
4396

4397
	if (sp->m_flags & sp_head::MULTI_RESULTS)
4398
	{
4399
	  if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
4400
	  {
4401 4402 4403 4404
            /*
              The client does not support multiple result sets being sent
              back
            */
4405
	    my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
4406 4407
	    goto error;
	  }
unknown's avatar
unknown committed
4408 4409 4410 4411 4412 4413 4414
          /*
            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;
4415 4416
	}

4417
	if (check_routine_access(thd, EXECUTE_ACL,
4418
				 sp->m_db.str, sp->m_name.str, TRUE, FALSE))
4419 4420 4421
	{
	  goto error;
	}
unknown's avatar
unknown committed
4422 4423
	select_limit= thd->variables.select_limit;
	thd->variables.select_limit= HA_POS_ERROR;
4424

4425
        /* 
4426
          We never write CALL statements into binlog:
4427 4428 4429 4430 4431
           - 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.
4432
        */
4433
	res= sp->execute_procedure(thd, &lex->value_list);
4434 4435 4436
	/*
          If warnings have been cleared, we have to clear total_warn_count
          too, otherwise the clients get confused.
4437 4438 4439 4440
	 */
	if (thd->warn_list.is_empty())
	  thd->total_warn_count= 0;

unknown's avatar
unknown committed
4441
	thd->variables.select_limit= select_limit;
4442

unknown's avatar
unknown committed
4443
        thd->server_status&= ~bits_to_be_cleared;
4444

unknown's avatar
unknown committed
4445
	if (!res)
4446 4447
          my_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
                              thd->row_count_func));
4448
	else
4449
        {
4450
          DBUG_ASSERT(thd->is_error() || thd->killed);
4451
	  goto error;		// Substatement should already have sent error
4452
        }
4453
      }
4454
      break;
4455 4456
    }
  case SQLCOM_ALTER_PROCEDURE:
4457
  case SQLCOM_ALTER_FUNCTION:
4458
    {
unknown's avatar
unknown committed
4459
      int sp_result;
4460 4461 4462 4463
      sp_head *sp;
      st_sp_chistics chistics;

      memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
unknown's avatar
unknown committed
4464
      if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
4465 4466
        sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                            &thd->sp_proc_cache, FALSE);
4467
      else
4468 4469
        sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                            &thd->sp_func_cache, FALSE);
unknown's avatar
unknown committed
4470
      mysql_reset_errors(thd, 0);
4471
      if (! sp)
4472 4473
      {
	if (lex->spname->m_db.str)
unknown's avatar
unknown committed
4474
	  sp_result= SP_KEY_NOT_FOUND;
4475 4476 4477 4478 4479 4480
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
      }
4481 4482
      else
      {
4483 4484 4485
        if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str, 
				 sp->m_name.str,
                                 lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
4486
	  goto error;
4487 4488 4489

        if (end_active_trans(thd)) 
          goto error;
4490
	memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
4491 4492
        if ((sp->m_type == TYPE_ENUM_FUNCTION) &&
            !trust_function_creators &&  mysql_bin_log.is_open() &&
4493 4494 4495 4496 4497 4498
            !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
4499
          sp_result= SP_INTERNAL_ERROR;
4500 4501 4502
        }
        else
        {
4503 4504 4505 4506 4507 4508
          /*
            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
4509
          /* Conditionally writes to binlog */
unknown's avatar
unknown committed
4510 4511 4512 4513 4514 4515 4516 4517 4518

          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);
4519
        }
4520
      }
unknown's avatar
unknown committed
4521
      switch (sp_result)
4522
      {
unknown's avatar
unknown committed
4523
      case SP_OK:
4524
	my_ok(thd);
unknown's avatar
unknown committed
4525 4526
	break;
      case SP_KEY_NOT_FOUND:
4527 4528
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
4529 4530
	goto error;
      default:
4531 4532
	my_error(ER_SP_CANT_ALTER, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
unknown's avatar
unknown committed
4533
	goto error;
4534
      }
4535
      break;
4536 4537
    }
  case SQLCOM_DROP_PROCEDURE:
4538
  case SQLCOM_DROP_FUNCTION:
4539
    {
unknown's avatar
unknown committed
4540
      int sp_result;
4541 4542
      int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
                 TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
4543

unknown's avatar
unknown committed
4544
      sp_result= sp_routine_exists_in_table(thd, type, lex->spname);
unknown's avatar
unknown committed
4545
      mysql_reset_errors(thd, 0);
unknown's avatar
unknown committed
4546
      if (sp_result == SP_OK)
4547
      {
4548 4549 4550
        char *db= lex->spname->m_db.str;
	char *name= lex->spname->m_name.str;

4551 4552
	if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
unknown's avatar
merge  
unknown committed
4553
          goto error;
4554 4555 4556

        if (end_active_trans(thd)) 
          goto error;
unknown's avatar
unknown committed
4557
#ifndef NO_EMBEDDED_ACCESS_CHECKS
4558
	if (sp_automatic_privileges && !opt_noacl &&
4559 4560
	    sp_revoke_privileges(thd, db, name, 
                                 lex->sql_command == SQLCOM_DROP_PROCEDURE))
4561 4562 4563 4564 4565
	{
	  push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
		       ER_PROC_AUTO_REVOKE_FAIL,
		       ER(ER_PROC_AUTO_REVOKE_FAIL));
	}
unknown's avatar
unknown committed
4566
#endif
unknown's avatar
unknown committed
4567
        /* Conditionally writes to binlog */
unknown's avatar
unknown committed
4568 4569 4570 4571 4572 4573

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

        sp_result= sp_drop_routine(thd, type, lex->spname);
4574 4575 4576
      }
      else
      {
4577
#ifdef HAVE_DLOPEN
4578 4579 4580 4581 4582 4583
	if (lex->sql_command == SQLCOM_DROP_FUNCTION)
	{
          udf_func *udf = find_udf(lex->spname->m_name.str,
                                   lex->spname->m_name.length);
          if (udf)
          {
4584
	    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
4585
	      goto error;
4586

4587
	    if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
4588
	    {
4589
	      my_ok(thd);
4590
	      break;
4591 4592
	    }
	  }
4593
	}
4594
#endif
4595
	if (lex->spname->m_db.str)
unknown's avatar
unknown committed
4596
	  sp_result= SP_KEY_NOT_FOUND;
4597 4598 4599 4600 4601
	else
	{
	  my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
	  goto error;
	}
4602
      }
unknown's avatar
unknown committed
4603 4604
      res= sp_result;
      switch (sp_result) {
4605
      case SP_OK:
4606
	my_ok(thd);
4607 4608
	break;
      case SP_KEY_NOT_FOUND:
4609 4610
	if (lex->drop_if_exists)
	{
He Zhenxing's avatar
He Zhenxing committed
4611
          res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
4612
	  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
4613
			      ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
4614
			      SP_COM_STRING(lex), lex->spname->m_name.str);
He Zhenxing's avatar
He Zhenxing committed
4615 4616
          if (!res)
            my_ok(thd);
4617 4618
	  break;
	}
4619 4620
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4621 4622
	goto error;
      default:
4623 4624
	my_error(ER_SP_DROP_FAILED, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4625
	goto error;
4626
      }
4627
      break;
4628
    }
unknown's avatar
unknown committed
4629 4630
  case SQLCOM_SHOW_CREATE_PROC:
    {
unknown's avatar
unknown committed
4631 4632
      if (sp_show_create_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname))
      {
4633 4634
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4635 4636 4637 4638 4639 4640
	goto error;
      }
      break;
    }
  case SQLCOM_SHOW_CREATE_FUNC:
    {
unknown's avatar
unknown committed
4641 4642
      if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname))
      {
4643 4644
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
                 SP_COM_STRING(lex), lex->spname->m_name.str);
unknown's avatar
unknown committed
4645 4646 4647 4648
	goto error;
      }
      break;
    }
unknown's avatar
unknown committed
4649 4650 4651 4652 4653 4654 4655
#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
4656 4657
        sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
                            &thd->sp_proc_cache, FALSE);
unknown's avatar
unknown committed
4658
      else
unknown's avatar
unknown committed
4659 4660
        sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                            &thd->sp_func_cache, FALSE);
4661
      if (!sp || sp->show_routine_code(thd))
4662 4663
      {
        /* We don't distinguish between errors for now */
unknown's avatar
unknown committed
4664 4665 4666 4667 4668 4669 4670
        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
4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683
  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
4684 4685
  case SQLCOM_CREATE_VIEW:
    {
4686 4687 4688 4689
      /*
        Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands
        as specified through the thd->lex->create_view_mode flag.
      */
4690 4691 4692
      if (end_active_trans(thd))
        goto error;

4693
      res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
unknown's avatar
VIEW  
unknown committed
4694 4695 4696 4697
      break;
    }
  case SQLCOM_DROP_VIEW:
    {
4698
      if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE) ||
unknown's avatar
unknown committed
4699 4700
          end_active_trans(thd))
        goto error;
4701 4702
      /* Conditionally writes to binlog. */
      res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
unknown's avatar
VIEW  
unknown committed
4703 4704
      break;
    }
4705 4706
  case SQLCOM_CREATE_TRIGGER:
  {
4707 4708 4709
    if (end_active_trans(thd))
      goto error;

4710
    /* Conditionally writes to binlog. */
4711 4712
    res= mysql_create_or_drop_trigger(thd, all_tables, 1);

4713 4714 4715 4716
    break;
  }
  case SQLCOM_DROP_TRIGGER:
  {
4717 4718 4719
    if (end_active_trans(thd))
      goto error;

4720
    /* Conditionally writes to binlog. */
4721 4722 4723
    res= mysql_create_or_drop_trigger(thd, all_tables, 0);
    break;
  }
4724
  case SQLCOM_XA_START:
4725 4726
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
        thd->lex->xa_opt == XA_RESUME)
4727
    {
4728
      if (! thd->transaction.xid_state.xid.eq(thd->lex->xid))
4729 4730 4731 4732
      {
        my_error(ER_XAER_NOTA, MYF(0));
        break;
      }
4733
      thd->transaction.xid_state.xa_state= XA_ACTIVE;
4734
      my_ok(thd);
4735 4736
      break;
    }
unknown's avatar
unknown committed
4737
    if (thd->lex->xa_opt != XA_NONE)
4738 4739 4740 4741
    { // JOIN is not supported yet. TODO
      my_error(ER_XAER_INVAL, MYF(0));
      break;
    }
4742
    if (thd->transaction.xid_state.xa_state != XA_NOTR)
4743
    {
unknown's avatar
unknown committed
4744
      my_error(ER_XAER_RMFAIL, MYF(0),
4745
               xa_state_names[thd->transaction.xid_state.xa_state]);
4746 4747 4748 4749 4750 4751 4752
      break;
    }
    if (thd->active_transaction() || thd->locked_tables)
    {
      my_error(ER_XAER_OUTSIDE, MYF(0));
      break;
    }
4753
    DBUG_ASSERT(thd->transaction.xid_state.xid.is_null());
4754
    thd->transaction.xid_state.xa_state= XA_ACTIVE;
4755
    thd->transaction.xid_state.rm_error= 0;
4756
    thd->transaction.xid_state.xid.set(thd->lex->xid);
4757 4758 4759 4760 4761 4762
    if (xid_cache_insert(&thd->transaction.xid_state))
    {
      thd->transaction.xid_state.xa_state= XA_NOTR;
      thd->transaction.xid_state.xid.null();
      break;
    }
unknown's avatar
unknown committed
4763
    thd->transaction.all.modified_non_trans_table= FALSE;
4764
    thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN);
4765
    thd->server_status|= SERVER_STATUS_IN_TRANS;
4766
    my_ok(thd);
4767 4768 4769 4770 4771 4772 4773 4774
    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;
    }
4775
    if (thd->transaction.xid_state.xa_state != XA_ACTIVE)
4776
    {
unknown's avatar
unknown committed
4777
      my_error(ER_XAER_RMFAIL, MYF(0),
4778
               xa_state_names[thd->transaction.xid_state.xa_state]);
4779 4780
      break;
    }
4781
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4782 4783 4784 4785
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
4786 4787
    if (xa_trans_rolled_back(&thd->transaction.xid_state))
      break;
4788
    thd->transaction.xid_state.xa_state=XA_IDLE;
4789
    my_ok(thd);
4790 4791
    break;
  case SQLCOM_XA_PREPARE:
4792
    if (thd->transaction.xid_state.xa_state != XA_IDLE)
4793
    {
unknown's avatar
unknown committed
4794
      my_error(ER_XAER_RMFAIL, MYF(0),
4795
               xa_state_names[thd->transaction.xid_state.xa_state]);
4796 4797
      break;
    }
4798
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4799 4800 4801 4802 4803 4804 4805
    {
      my_error(ER_XAER_NOTA, MYF(0));
      break;
    }
    if (ha_prepare(thd))
    {
      my_error(ER_XA_RBROLLBACK, MYF(0));
4806 4807
      xid_cache_delete(&thd->transaction.xid_state);
      thd->transaction.xid_state.xa_state=XA_NOTR;
4808 4809
      break;
    }
4810
    thd->transaction.xid_state.xa_state=XA_PREPARED;
4811
    my_ok(thd);
4812 4813
    break;
  case SQLCOM_XA_COMMIT:
4814
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4815
    {
4816 4817 4818 4819 4820 4821 4822 4823 4824 4825
      /*
        xid_state.in_thd is always true beside of xa recovery
        procedure. Note, that there is no race condition here
        between xid_cache_search and xid_cache_delete, since we're always
        deleting our own XID (thd->lex->xid == thd->transaction.xid_state.xid).
        The only case when thd->lex->xid != thd->transaction.xid_state.xid
        and xid_state->in_thd == 0 is in ha_recover() functionality,
        which is called before starting client connections, and thus is
        always single-threaded.
      */
4826 4827
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
4828
        my_error(ER_XAER_NOTA, MYF(0));
4829 4830 4831 4832 4833 4834
      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
4835
      else
4836 4837 4838
      {
        ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
        xid_cache_delete(xs);
4839
        my_ok(thd);
4840
      }
4841 4842
      break;
    }
4843 4844 4845 4846 4847
    if (xa_trans_rolled_back(&thd->transaction.xid_state))
    {
      xa_trans_rollback(thd);
      break;
    }
4848
    if (thd->transaction.xid_state.xa_state == XA_IDLE &&
unknown's avatar
unknown committed
4849
        thd->lex->xa_opt == XA_ONE_PHASE)
4850
    {
unknown's avatar
unknown committed
4851 4852 4853
      int r;
      if ((r= ha_commit(thd)))
        my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
4854
      else
4855
        my_ok(thd);
4856
    }
4857
    else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
unknown's avatar
unknown committed
4858
             thd->lex->xa_opt == XA_NONE)
4859
    {
4860 4861 4862
      if (wait_if_global_read_lock(thd, 0, 0))
      {
        ha_rollback(thd);
4863
        my_error(ER_XAER_RMERR, MYF(0));
4864
      }
4865
      else
4866 4867 4868 4869
      {
        if (ha_commit_one_phase(thd, 1))
          my_error(ER_XAER_RMERR, MYF(0));
        else
4870
          my_ok(thd);
4871 4872
        start_waiting_global_read_lock(thd);
      }
4873 4874 4875
    }
    else
    {
unknown's avatar
unknown committed
4876
      my_error(ER_XAER_RMFAIL, MYF(0),
4877
               xa_state_names[thd->transaction.xid_state.xa_state]);
4878 4879
      break;
    }
unknown's avatar
unknown committed
4880
    thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
unknown's avatar
unknown committed
4881
    thd->transaction.all.modified_non_trans_table= FALSE;
4882
    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
4883 4884
    xid_cache_delete(&thd->transaction.xid_state);
    thd->transaction.xid_state.xa_state=XA_NOTR;
4885 4886
    break;
  case SQLCOM_XA_ROLLBACK:
4887
    if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
4888
    {
4889 4890
      XID_STATE *xs=xid_cache_search(thd->lex->xid);
      if (!xs || xs->in_thd)
4891
        my_error(ER_XAER_NOTA, MYF(0));
unknown's avatar
unknown committed
4892
      else
4893
      {
4894
        bool ok= !xa_trans_rolled_back(xs);
4895 4896
        ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
        xid_cache_delete(xs);
4897
        if (ok)
4898
          my_ok(thd);
4899
      }
4900 4901
      break;
    }
4902
    if (thd->transaction.xid_state.xa_state != XA_IDLE &&
4903 4904
        thd->transaction.xid_state.xa_state != XA_PREPARED &&
        thd->transaction.xid_state.xa_state != XA_ROLLBACK_ONLY)
4905
    {
unknown's avatar
unknown committed
4906
      my_error(ER_XAER_RMFAIL, MYF(0),
4907
               xa_state_names[thd->transaction.xid_state.xa_state]);
4908 4909
      break;
    }
4910
    if (xa_trans_rollback(thd))
4911 4912
      my_error(ER_XAER_RMERR, MYF(0));
    else
4913
      my_ok(thd);
4914 4915
    break;
  case SQLCOM_XA_RECOVER:
4916
    res= mysql_xa_recover(thd);
4917
    break;
unknown's avatar
unknown committed
4918
  case SQLCOM_ALTER_TABLESPACE:
4919 4920
    if (check_access(thd, ALTER_ACL, thd->db, 0, 1, 0,
                     thd->db ? is_schema_db(thd->db, thd->db_length) : 0))
unknown's avatar
unknown committed
4921 4922
      break;
    if (!(res= mysql_alter_tablespace(thd, lex->alter_tablespace_info)))
4923
      my_ok(thd);
unknown's avatar
unknown committed
4924 4925 4926 4927
    break;
  case SQLCOM_INSTALL_PLUGIN:
    if (! (res= mysql_install_plugin(thd, &thd->lex->comment,
                                     &thd->lex->ident)))
4928
      my_ok(thd);
unknown's avatar
unknown committed
4929 4930 4931
    break;
  case SQLCOM_UNINSTALL_PLUGIN:
    if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment)))
4932
      my_ok(thd);
unknown's avatar
unknown committed
4933 4934 4935 4936 4937 4938 4939 4940 4941 4942
    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
4943 4944 4945 4946 4947
  case SQLCOM_CREATE_SERVER:
  {
    int error;
    LEX *lex= thd->lex;
    DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER"));
unknown's avatar
unknown committed
4948 4949 4950 4951

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4952 4953
    if ((error= create_server(thd, &lex->server_options)))
    {
4954
      DBUG_PRINT("info", ("problem creating server <%s>",
unknown's avatar
unknown committed
4955 4956 4957 4958
                          lex->server_options.server_name));
      my_error(error, MYF(0), lex->server_options.server_name);
      break;
    }
4959
    my_ok(thd, 1);
unknown's avatar
unknown committed
4960 4961 4962 4963 4964 4965 4966
    break;
  }
  case SQLCOM_ALTER_SERVER:
  {
    int error;
    LEX *lex= thd->lex;
    DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER"));
unknown's avatar
unknown committed
4967 4968 4969 4970

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4971 4972
    if ((error= alter_server(thd, &lex->server_options)))
    {
4973
      DBUG_PRINT("info", ("problem altering server <%s>",
unknown's avatar
unknown committed
4974 4975 4976 4977
                          lex->server_options.server_name));
      my_error(error, MYF(0), lex->server_options.server_name);
      break;
    }
4978
    my_ok(thd, 1);
unknown's avatar
unknown committed
4979 4980 4981 4982 4983 4984 4985
    break;
  }
  case SQLCOM_DROP_SERVER:
  {
    int err_code;
    LEX *lex= thd->lex;
    DBUG_PRINT("info", ("case SQLCOM_DROP_SERVER"));
unknown's avatar
unknown committed
4986 4987 4988 4989

    if (check_global_access(thd, SUPER_ACL))
      break;

unknown's avatar
unknown committed
4990 4991
    if ((err_code= drop_server(thd, &lex->server_options)))
    {
unknown's avatar
unknown committed
4992
      if (! lex->drop_if_exists && err_code == ER_FOREIGN_SERVER_DOESNT_EXIST)
unknown's avatar
unknown committed
4993 4994 4995 4996 4997 4998 4999
      {
        DBUG_PRINT("info", ("problem dropping server %s",
                            lex->server_options.server_name));
        my_error(err_code, MYF(0), lex->server_options.server_name);
      }
      else
      {
5000
        my_ok(thd, 0);
unknown's avatar
unknown committed
5001 5002 5003
      }
      break;
    }
5004
    my_ok(thd, 1);
unknown's avatar
unknown committed
5005 5006
    break;
  }
5007
  default:
5008
#ifndef EMBEDDED_LIBRARY
5009
    DBUG_ASSERT(0);                             /* Impossible */
5010
#endif
5011
    my_ok(thd);
unknown's avatar
unknown committed
5012 5013
    break;
  }
5014
  thd_proc_info(thd, "query end");
5015 5016

  /*
unknown's avatar
unknown committed
5017
    Binlog-related cleanup:
5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028
    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);

5029
  /*
5030 5031
    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
5032 5033 5034 5035
    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))
5036
    thd->row_count_func= -1;
5037

5038
  goto finish;
unknown's avatar
unknown committed
5039 5040

error:
5041 5042
  res= TRUE;

5043
finish:
5044 5045 5046 5047 5048 5049 5050 5051
  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);
  }
5052
  DBUG_RETURN(res || thd->is_error());
unknown's avatar
unknown committed
5053 5054 5055
}


5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078
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()))
5079
        return 1;                               /* purecov: inspected */
5080 5081 5082 5083 5084 5085 5086
      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);
5087
        thd->lex->unit.print(&str, QT_ORDINARY);
5088 5089 5090 5091
        str.append('\0');
        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
                     ER_YES, str.ptr());
      }
5092 5093 5094 5095
      if (res)
        result->abort();
      else
        result->send_eof();
5096 5097 5098 5099 5100
      delete result;
    }
    else
    {
      if (!result && !(result= new select_send()))
5101
        return 1;                               /* purecov: inspected */
5102 5103 5104 5105 5106 5107 5108 5109 5110 5111
      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
5112
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
5113
/**
5114
  Check grants for commands which work only with one table.
unknown's avatar
unknown committed
5115

5116 5117 5118
  @param thd                    Thread handler
  @param privilege              requested privilege
  @param all_tables             global table list of query
unknown's avatar
unknown committed
5119
  @param no_errors              FALSE/TRUE - report/don't report error to
5120
                            the client (using my_error() call).
unknown's avatar
unknown committed
5121 5122 5123 5124 5125

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

5128
bool check_single_table_access(THD *thd, ulong privilege, 
5129
                               TABLE_LIST *all_tables, bool no_errors)
unknown's avatar
unknown committed
5130
{
5131 5132 5133 5134 5135 5136
  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;

5137 5138 5139 5140 5141 5142 5143 5144
  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,
5145
		   &all_tables->grant.privilege, 0, no_errors,
5146
                   test(all_tables->schema_table)))
5147
    goto deny;
unknown's avatar
unknown committed
5148

unknown's avatar
unknown committed
5149
  /* Show only 1 table for check_grant */
5150
  if (!(all_tables->belong_to_view &&
5151
        (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
5152
      check_grant(thd, privilege, all_tables, 0, 1, no_errors))
5153 5154 5155
    goto deny;

  thd->security_ctx= backup_ctx;
5156 5157 5158 5159 5160 5161 5162
  return 0;

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

unknown's avatar
unknown committed
5163
/**
5164 5165 5166
  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
5167 5168 5169 5170 5171 5172 5173 5174
  @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
5175 5176 5177 5178
*/

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

5182
  /* Check rights on tables of subselects and implictly opened tables */
unknown's avatar
unknown committed
5183
  TABLE_LIST *subselects_tables, *view= all_tables->view ? all_tables : 0;
unknown's avatar
VIEW  
unknown committed
5184
  if ((subselects_tables= all_tables->next_global))
unknown's avatar
unknown committed
5185
  {
unknown's avatar
unknown committed
5186 5187 5188 5189 5190 5191
    /*
      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)
    {
5192
      if (check_single_table_access (thd, privilege, subselects_tables, FALSE))
unknown's avatar
unknown committed
5193 5194 5195 5196
        return 1;
      subselects_tables= subselects_tables->next_global;
    }
    if (subselects_tables &&
5197
        (check_table_access(thd, SELECT_ACL, subselects_tables, UINT_MAX, FALSE)))
5198
      return 1;
unknown's avatar
unknown committed
5199 5200
  }
  return 0;
unknown's avatar
unknown committed
5201 5202 5203
}


unknown's avatar
unknown committed
5204 5205
/**
  Get the user (global) and database privileges for all used tables.
unknown's avatar
unknown committed
5206

unknown's avatar
unknown committed
5207 5208 5209 5210
  @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
5211

unknown's avatar
unknown committed
5212
  @note
unknown's avatar
unknown committed
5213 5214 5215 5216 5217
    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
5218
  @retval
unknown's avatar
unknown committed
5219
    0  ok
unknown's avatar
unknown committed
5220 5221 5222 5223
  @retval
    1  If we can't get the privileges and we don't use table/column
    grants.
*/
unknown's avatar
unknown committed
5224
bool
unknown's avatar
unknown committed
5225
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
5226
	     bool dont_check_global_grants, bool no_errors, bool schema_db)
unknown's avatar
unknown committed
5227
{
5228
  Security_context *sctx= thd->security_ctx;
unknown's avatar
unknown committed
5229
  ulong db_access;
5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240
  /*
    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
5241
  ulong dummy;
5242 5243
  DBUG_ENTER("check_access");
  DBUG_PRINT("enter",("db: %s  want_access: %lu  master_access: %lu",
5244
                      db ? db : "", want_access, sctx->master_access));
unknown's avatar
unknown committed
5245 5246 5247 5248 5249
  if (save_priv)
    *save_priv=0;
  else
    save_priv= &dummy;

5250
  thd_proc_info(thd, "checking permissions");
5251
  if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
unknown's avatar
unknown committed
5252
  {
5253
    DBUG_PRINT("error",("No database"));
5254
    if (!no_errors)
unknown's avatar
unknown committed
5255 5256
      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
                 MYF(0));                       /* purecov: tested */
unknown's avatar
unknown committed
5257
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
5258 5259
  }

5260 5261
  if (schema_db)
  {
5262
    if ((!(sctx->master_access & FILE_ACL) && (want_access & FILE_ACL)) ||
5263
        (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
5264 5265
    {
      if (!no_errors)
5266 5267
      {
        const char *db_name= db ? db : thd->db;
5268
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
5269 5270
                 sctx->priv_user, sctx->priv_host, db_name);
      }
5271 5272 5273 5274 5275 5276 5277 5278 5279
      DBUG_RETURN(TRUE);
    }
    else
    {
      *save_priv= SELECT_ACL;
      DBUG_RETURN(FALSE);
    }
  }

5280
  if ((sctx->master_access & want_access) == want_access)
unknown's avatar
unknown committed
5281
  {
5282 5283 5284 5285 5286
    /*
      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
    */
5287 5288
    db_access= sctx->db_access;
    if (!(sctx->master_access & SELECT_ACL) &&
unknown's avatar
unknown committed
5289
	(db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
5290 5291 5292
      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
5293
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
5294
  }
5295
  if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
5296
      (! db && dont_check_global_grants))
unknown's avatar
unknown committed
5297
  {						// We can never grant this
5298
    DBUG_PRINT("error",("No possible access"));
5299
    if (!no_errors)
5300
      my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
5301 5302
               sctx->priv_user,
               sctx->priv_host,
5303 5304 5305
               (thd->password ?
                ER(ER_YES) :
                ER(ER_NO)));                    /* purecov: tested */
unknown's avatar
unknown committed
5306
    DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
5307 5308 5309
  }

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

unknown's avatar
unknown committed
5312
  if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
5313 5314
    db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
                       db_is_pattern);
unknown's avatar
unknown committed
5315
  else
5316
    db_access= sctx->db_access;
5317
  DBUG_PRINT("info",("db_access: %lu", db_access));
unknown's avatar
unknown committed
5318
  /* Remove SHOW attribute and access rights we already have */
5319
  want_access &= ~(sctx->master_access | EXTRA_ACL);
5320 5321
  DBUG_PRINT("info",("db_access: %lu  want_access: %lu",
                     db_access, want_access));
5322
  db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
5323

unknown's avatar
unknown committed
5324
  if (db_access == want_access ||
5325
      (!dont_check_global_grants &&
5326
       !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
unknown's avatar
unknown committed
5327
    DBUG_RETURN(FALSE);				/* Ok */
5328 5329

  DBUG_PRINT("error",("Access denied"));
5330
  if (!no_errors)
5331
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
5332
             sctx->priv_user, sctx->priv_host,
5333 5334 5335
             (db ? db : (thd->db ?
                         thd->db :
                         "unknown")));          /* purecov: tested */
unknown's avatar
unknown committed
5336
  DBUG_RETURN(TRUE);				/* purecov: tested */
unknown's avatar
unknown committed
5337 5338 5339
}


5340 5341
static bool check_show_access(THD *thd, TABLE_LIST *table)
{
unknown's avatar
unknown committed
5342
  switch (get_schema_table_idx(table->schema_table)) {
5343 5344
  case SCH_SCHEMATA:
    return (specialflag & SPECIAL_SKIP_SHOW_DB) &&
unknown's avatar
unknown committed
5345
      check_global_access(thd, SHOW_DB_ACL);
5346 5347 5348 5349 5350

  case SCH_TABLE_NAMES:
  case SCH_TABLES:
  case SCH_VIEWS:
  case SCH_TRIGGERS:
unknown's avatar
unknown committed
5351 5352 5353
  case SCH_EVENTS:
  {
    const char *dst_db_name= table->schema_select_lex->db;
5354

unknown's avatar
unknown committed
5355
    DBUG_ASSERT(dst_db_name);
5356

unknown's avatar
unknown committed
5357 5358
    if (check_access(thd, SELECT_ACL, dst_db_name,
                     &thd->col_access, FALSE, FALSE,
5359
                     is_schema_db(dst_db_name)))
unknown's avatar
unknown committed
5360
      return TRUE;
5361

unknown's avatar
unknown committed
5362 5363 5364 5365 5366 5367 5368
    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;
5369 5370
    }

unknown's avatar
unknown committed
5371 5372 5373
    return FALSE;
  }

5374 5375
  case SCH_COLUMNS:
  case SCH_STATISTICS:
unknown's avatar
unknown committed
5376 5377
  {
    TABLE_LIST *dst_table;
5378
    dst_table= table->schema_select_lex->table_list.first;
5379

unknown's avatar
unknown committed
5380
    DBUG_ASSERT(dst_table);
5381

unknown's avatar
unknown committed
5382 5383 5384 5385 5386 5387
    if (check_access(thd, SELECT_ACL | EXTRA_ACL,
                     dst_table->db,
                     &dst_table->grant.privilege,
                     FALSE, FALSE,
                     test(dst_table->schema_table)))
      return FALSE;
5388

5389
    return (check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE));
unknown's avatar
unknown committed
5390 5391
  }
  default:
5392 5393 5394 5395 5396 5397 5398
    break;
  }

  return FALSE;
}


unknown's avatar
unknown committed
5399
/**
5400 5401
  Check the privilege for all used tables.

5402 5403 5404 5405 5406 5407
  @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).
5408

unknown's avatar
unknown committed
5409
  @note
5410 5411 5412 5413 5414 5415
    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).

5416 5417
  @retval  FALSE   OK
  @retval  TRUE    Access denied
unknown's avatar
unknown committed
5418 5419
*/

5420
bool
unknown's avatar
unknown committed
5421
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
5422
		   uint number, bool no_errors)
unknown's avatar
unknown committed
5423
{
5424 5425
  TABLE_LIST *org_tables= tables;
  TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
5426
  uint i= 0;
5427
  Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx;
5428
  /*
unknown's avatar
unknown committed
5429 5430 5431
    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.
5432
  */
5433 5434
  for (; i < number && tables != first_not_own_table;
       tables= tables->next_global, i++)
unknown's avatar
unknown committed
5435
  {
5436 5437 5438 5439 5440
    if (tables->security_ctx)
      sctx= tables->security_ctx;
    else
      sctx= backup_ctx;

5441
    if (tables->schema_table && 
5442
        (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
5443 5444 5445
    {
      if (!no_errors)
        my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
5446
                 sctx->priv_user, sctx->priv_host,
5447
                 INFORMATION_SCHEMA_NAME.str);
5448 5449
      return TRUE;
    }
5450 5451 5452 5453 5454
    /*
       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
5455 5456 5457 5458 5459 5460 5461 5462 5463

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

      continue;
    }

5464
    if (tables->is_anonymous_derived_table() ||
5465
        (tables->table && (int)tables->table->s->tmp_table))
unknown's avatar
unknown committed
5466
      continue;
5467 5468
    thd->security_ctx= sctx;
    if ((sctx->master_access & want_access) ==
5469
        (want_access & ~EXTRA_ACL) &&
unknown's avatar
unknown committed
5470
	thd->db)
unknown's avatar
unknown committed
5471
      tables->grant.privilege= want_access;
unknown's avatar
unknown committed
5472
    else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
unknown's avatar
unknown committed
5473
    {
5474 5475 5476
      if (check_access(thd, want_access, tables->get_db_name(),
                       &tables->grant.privilege, 0, no_errors, 
                       test(tables->schema_table)))
5477
        goto deny;                            // Access denied
unknown's avatar
unknown committed
5478
    }
5479 5480 5481
    else if (check_access(thd, want_access, tables->get_db_name(),
                          &tables->grant.privilege, 0, no_errors, 
                          test(tables->schema_table)))
5482
      goto deny;
unknown's avatar
unknown committed
5483
  }
5484
  thd->security_ctx= backup_ctx;
5485
  return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
5486
		       test(want_access & EXTRA_ACL), number, no_errors);
5487 5488 5489
deny:
  thd->security_ctx= backup_ctx;
  return TRUE;
unknown's avatar
unknown committed
5490 5491
}

5492

5493
bool
5494 5495
check_routine_access(THD *thd, ulong want_access,char *db, char *name,
		     bool is_proc, bool no_errors)
5496 5497 5498 5499 5500
{
  TABLE_LIST tables[1];
  
  bzero((char *)tables, sizeof(TABLE_LIST));
  tables->db= db;
5501
  tables->table_name= tables->alias= name;
5502
  
unknown's avatar
unknown committed
5503 5504 5505 5506 5507 5508 5509
  /*
    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)
5510 5511
    tables->grant.privilege= want_access;
  else if (check_access(thd,want_access,db,&tables->grant.privilege,
unknown's avatar
unknown committed
5512
			0, no_errors, 0))
5513 5514
    return TRUE;
  
5515
    return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
5516 5517
}

5518

unknown's avatar
unknown committed
5519 5520
/**
  Check if the routine has any of the routine privileges.
5521

unknown's avatar
unknown committed
5522 5523 5524
  @param thd	       Thread handler
  @param db           Database name
  @param name         Routine name
5525

unknown's avatar
unknown committed
5526
  @retval
5527
    0            ok
unknown's avatar
unknown committed
5528
  @retval
5529 5530 5531
    1            error
*/

5532 5533
bool check_some_routine_access(THD *thd, const char *db, const char *name,
                               bool is_proc)
5534 5535
{
  ulong save_priv;
5536
  if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
5537
    return FALSE;
5538 5539 5540 5541 5542
  /*
    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) ||
5543 5544
      (save_priv & SHOW_PROC_ACLS))
    return FALSE;
5545
  return check_routine_level_acl(thd, db, name, is_proc);
5546 5547 5548
}


5549 5550 5551
/*
  Check if the given table has any of the asked privileges

unknown's avatar
unknown committed
5552 5553
  @param thd		 Thread handler
  @param want_access	 Bitmap of possible privileges to check for
5554

unknown's avatar
unknown committed
5555
  @retval
5556
    0  ok
unknown's avatar
unknown committed
5557
  @retval
5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571
    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,
5572 5573
                        &table->grant.privilege, 0, 1,
                        test(table->schema_table)) &&
Staale Smedseng's avatar
Staale Smedseng committed
5574
           !check_grant(thd, access, table, 0, 1, 1))
5575 5576 5577 5578 5579 5580 5581
        DBUG_RETURN(0);
    }
  }
  DBUG_PRINT("exit",("no matching access rights"));
  DBUG_RETURN(1);
}

unknown's avatar
unknown committed
5582
#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
5583

5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616

/**
  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
5617 5618 5619 5620
/****************************************************************************
	Check stack size; Send error if there isn't enough stack to continue
****************************************************************************/

5621 5622
#ifndef EMBEDDED_LIBRARY

unknown's avatar
unknown committed
5623 5624 5625 5626 5627 5628
#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
5629 5630 5631 5632
#ifndef DBUG_OFF
long max_stack_used;
#endif

unknown's avatar
unknown committed
5633 5634
/**
  @note
5635 5636 5637 5638
  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
5639
*/
5640
bool check_stack_overrun(THD *thd, long margin,
5641
			 uchar *buf __attribute__((unused)))
unknown's avatar
unknown committed
5642 5643
{
  long stack_used;
5644
  DBUG_ASSERT(thd == current_thd);
unknown's avatar
unknown committed
5645
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
5646
      (long) (my_thread_stack_size - margin))
unknown's avatar
unknown committed
5647
  {
5648 5649 5650 5651
    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));
5652
    thd->fatal_error();
unknown's avatar
unknown committed
5653 5654
    return 1;
  }
unknown's avatar
unknown committed
5655 5656 5657
#ifndef DBUG_OFF
  max_stack_used= max(max_stack_used, stack_used);
#endif
unknown's avatar
unknown committed
5658 5659
  return 0;
}
5660
#endif /* EMBEDDED_LIBRARY */
unknown's avatar
unknown committed
5661 5662 5663 5664

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

5665
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
unknown's avatar
unknown committed
5666
{
5667
  Yacc_state *state= & current_thd->m_parser_state->m_yacc;
5668
  ulong old_info=0;
5669
  DBUG_ASSERT(state);
unknown's avatar
unknown committed
5670 5671
  if ((uint) *yystacksize >= MY_YACC_MAX)
    return 1;
5672
  if (!state->yacc_yyvs)
unknown's avatar
unknown committed
5673 5674
    old_info= *yystacksize;
  *yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX);
5675
  if (!(state->yacc_yyvs= (uchar*)
5676
        my_realloc(state->yacc_yyvs,
5677 5678 5679
                   *yystacksize*sizeof(**yyvs),
                   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
      !(state->yacc_yyss= (uchar*)
5680
        my_realloc(state->yacc_yyss,
5681 5682
                   *yystacksize*sizeof(**yyss),
                   MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
unknown's avatar
unknown committed
5683 5684
    return 1;
  if (old_info)
5685 5686 5687 5688 5689 5690 5691 5692
  {
    /*
      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
5693
  }
5694 5695
  *yyss= (short*) state->yacc_yyss;
  *yyvs= (YYSTYPE*) state->yacc_yyvs;
unknown's avatar
unknown committed
5696 5697 5698 5699
  return 0;
}


unknown's avatar
unknown committed
5700
/**
5701 5702 5703 5704
 Reset THD part responsible for command processing state.

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

unknown's avatar
unknown committed
5707
  @todo
5708 5709
   Make it a method of THD and align its name with the rest of
   reset/end/start/init methods.
unknown's avatar
unknown committed
5710
  @todo
5711 5712 5713 5714 5715 5716
   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");
5717
  DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
5718
  DBUG_ASSERT(! thd->in_sub_stmt);
5719
  thd->free_list= 0;
5720
  thd->select_number= 1;
5721 5722 5723 5724
  /*
    Those two lines below are theoretically unneeded as
    THD::cleanup_after_query() should take care of this already.
  */
5725
  thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty();
5726 5727 5728
  thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;

  thd->query_start_used= 0;
5729
  thd->is_fatal_error= thd->time_zone_used= 0;
5730 5731 5732 5733 5734
  /*
    Clear the status flag that are expected to be cleared at the
    beginning of each SQL statement.
  */
  thd->server_status&= ~SERVER_STATUS_CLEAR_SET;
5735 5736 5737 5738 5739 5740
  /*
    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
5741 5742
  {
    thd->options&= ~OPTION_KEEP_LOG;
5743
    thd->transaction.all.modified_non_trans_table= FALSE;
unknown's avatar
unknown committed
5744
  }
5745
  DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
unknown's avatar
unknown committed
5746
  thd->thread_specific_used= FALSE;
5747 5748

  if (opt_bin_log)
5749
  {
5750 5751
    reset_dynamic(&thd->user_var_events);
    thd->user_var_events_alloc= thd->mem_root;
5752
  }
5753 5754 5755 5756 5757 5758
  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;

5759 5760 5761 5762
  /*
    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
5763 5764
  thd->reset_current_stmt_binlog_row_based();

5765 5766 5767 5768
  DBUG_PRINT("debug",
             ("current_stmt_binlog_row_based: %d",
              thd->current_stmt_binlog_row_based));

unknown's avatar
unknown committed
5769 5770 5771
  DBUG_VOID_RETURN;
}

5772

5773 5774 5775 5776 5777 5778 5779 5780
/**
  Resets the lex->current_select object.
  @note It is assumed that lex->current_select != NULL

  This function is a wrapper around select_lex->init_select() with an added
  check for the special situation when using INTO OUTFILE and LOAD DATA.
*/

5781 5782 5783
void
mysql_init_select(LEX *lex)
{
unknown's avatar
unknown committed
5784
  SELECT_LEX *select_lex= lex->current_select;
unknown's avatar
unknown committed
5785
  select_lex->init_select();
5786
  lex->wild= 0;
5787 5788
  if (select_lex == &lex->select_lex)
  {
5789
    DBUG_ASSERT(lex->result == 0);
5790 5791
    lex->exchange= 0;
  }
5792 5793
}

5794

5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806
/**
  Used to allocate a new SELECT_LEX object on the current thd mem_root and
  link it into the relevant lists.

  This function is always followed by mysql_init_select.

  @see mysql_init_select

  @retval TRUE An error occurred
  @retval FALSE The new SELECT_LEX was successfully allocated.
*/

unknown's avatar
unknown committed
5807
bool
unknown's avatar
unknown committed
5808
mysql_new_select(LEX *lex, bool move_down)
5809
{
unknown's avatar
unknown committed
5810
  SELECT_LEX *select_lex;
5811
  THD *thd= lex->thd;
unknown's avatar
unknown committed
5812 5813
  DBUG_ENTER("mysql_new_select");

5814
  if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
5815
    DBUG_RETURN(1);
5816
  select_lex->select_number= ++thd->select_number;
unknown's avatar
unknown committed
5817
  select_lex->parent_lex= lex; /* Used in init_query. */
unknown's avatar
unknown committed
5818 5819
  select_lex->init_query();
  select_lex->init_select();
unknown's avatar
unknown committed
5820
  lex->nest_level++;
unknown's avatar
unknown committed
5821 5822 5823 5824 5825
  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
5826
  select_lex->nest_level= lex->nest_level;
5827 5828 5829
  /*
    Don't evaluate this subquery during statement prepare even if
    it's a constant one. The flag is switched off in the end of
5830
    mysqld_stmt_prepare.
5831
  */
unknown's avatar
unknown committed
5832
  if (thd->stmt_arena->is_stmt_prepare())
5833
    select_lex->uncacheable|= UNCACHEABLE_PREPARE;
unknown's avatar
unknown committed
5834 5835
  if (move_down)
  {
unknown's avatar
unknown committed
5836
    SELECT_LEX_UNIT *unit;
5837
    lex->subqueries= TRUE;
unknown's avatar
unknown committed
5838
    /* first select_lex of subselect or derived table */
5839
    if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
unknown's avatar
unknown committed
5840
      DBUG_RETURN(1);
unknown's avatar
unknown committed
5841

unknown's avatar
unknown committed
5842 5843
    unit->init_query();
    unit->init_select();
5844
    unit->thd= thd;
unknown's avatar
unknown committed
5845
    unit->include_down(lex->current_select);
unknown's avatar
unknown committed
5846 5847
    unit->link_next= 0;
    unit->link_prev= 0;
5848
    unit->return_to= lex->current_select;
unknown's avatar
unknown committed
5849
    select_lex->include_down(unit);
5850 5851 5852 5853 5854
    /*
      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
5855 5856
  }
  else
unknown's avatar
unknown committed
5857
  {
unknown's avatar
VIEW  
unknown committed
5858 5859
    if (lex->current_select->order_list.first && !lex->current_select->braces)
    {
unknown's avatar
unknown committed
5860
      my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
unknown's avatar
unknown committed
5861
      DBUG_RETURN(1);
unknown's avatar
VIEW  
unknown committed
5862
    }
5863
    select_lex->include_neighbour(lex->current_select);
5864 5865 5866 5867 5868
    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
5869
  }
unknown's avatar
unknown committed
5870

5871
  select_lex->master_unit()->global_parameters= select_lex;
5872
  select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
5873
  lex->current_select= select_lex;
5874 5875 5876 5877 5878
  /*
    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
5879
  DBUG_RETURN(0);
5880
}
unknown's avatar
unknown committed
5881

unknown's avatar
unknown committed
5882
/**
5883 5884
  Create a select to return the same output as 'SELECT @@var_name'.

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

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

unknown's avatar
unknown committed
5889
  @param var_name		Variable name
5890 5891 5892 5893
*/

void create_select_for_variable(const char *var_name)
{
5894
  THD *thd;
5895
  LEX *lex;
5896
  LEX_STRING tmp, null_lex_string;
5897 5898
  Item *var;
  char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end;
5899
  DBUG_ENTER("create_select_for_variable");
5900 5901

  thd= current_thd;
unknown's avatar
unknown committed
5902
  lex= thd->lex;
5903 5904 5905 5906
  mysql_init_select(lex);
  lex->sql_command= SQLCOM_SELECT;
  tmp.str= (char*) var_name;
  tmp.length=strlen(var_name);
5907
  bzero((char*) &null_lex_string.str, sizeof(null_lex_string));
5908 5909 5910 5911
  /*
    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
5912 5913 5914 5915 5916 5917
  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);
  }
5918 5919 5920
  DBUG_VOID_RETURN;
}

5921

unknown's avatar
unknown committed
5922 5923
void mysql_init_multi_delete(LEX *lex)
{
unknown's avatar
unknown committed
5924
  lex->sql_command=  SQLCOM_DELETE_MULTI;
unknown's avatar
unknown committed
5925
  mysql_init_select(lex);
5926 5927
  lex->select_lex.select_limit= 0;
  lex->unit.select_limit_cnt= HA_POS_ERROR;
unknown's avatar
unknown committed
5928
  lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list);
5929
  lex->lock_option= TL_READ_DEFAULT;
unknown's avatar
VIEW  
unknown committed
5930 5931
  lex->query_tables= 0;
  lex->query_tables_last= &lex->query_tables;
unknown's avatar
unknown committed
5932
}
unknown's avatar
unknown committed
5933

5934

5935 5936 5937 5938
/*
  When you modify mysql_parse(), you may need to mofify
  mysql_test_parse_for_slave() in this same file.
*/
unknown's avatar
unknown committed
5939

5940 5941
/**
  Parse a query.
unknown's avatar
unknown committed
5942 5943 5944 5945 5946 5947

  @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.
5948 5949 5950 5951
*/

void mysql_parse(THD *thd, const char *inBuf, uint length,
                 const char ** found_semicolon)
unknown's avatar
unknown committed
5952 5953
{
  DBUG_ENTER("mysql_parse");
5954 5955 5956

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

5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974
  /*
    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);
5975

5976
  if (query_cache_send_result_to_client(thd, (char*) inBuf, length) <= 0)
unknown's avatar
unknown committed
5977
  {
unknown's avatar
unknown committed
5978
    LEX *lex= thd->lex;
5979

5980 5981
    sp_cache_flush_obsolete(&thd->sp_proc_cache);
    sp_cache_flush_obsolete(&thd->sp_func_cache);
5982

5983 5984 5985 5986 5987 5988 5989 5990 5991
    Parser_state parser_state;
    bool err;
    if (!(err= parser_state.init(thd, inBuf, length)))
    {
      err= parse_sql(thd, & parser_state, NULL);
      *found_semicolon= parser_state.m_lip.found_semicolon;
    }
    else
      *found_semicolon= NULL;
5992

5993
    if (!err)
unknown's avatar
unknown committed
5994
    {
unknown's avatar
unknown committed
5995
#ifndef NO_EMBEDDED_ACCESS_CHECKS
5996
      if (mqh_used && thd->user_connect &&
5997
	  check_mqh(thd, lex->sql_command))
5998 5999 6000 6001
      {
	thd->net.error = 0;
      }
      else
unknown's avatar
unknown committed
6002
#endif
6003
      {
6004
	if (! thd->is_error())
unknown's avatar
unknown committed
6005
	{
6006 6007 6008 6009 6010 6011 6012 6013 6014 6015
          /*
            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.
          */
6016 6017 6018 6019
          if (*found_semicolon && (ulong) (*found_semicolon - thd->query()))
            thd->set_query_inner(thd->query(),
                                 (uint32) (*found_semicolon -
                                           thd->query() - 1));
6020
          /* Actually execute the query */
6021 6022 6023 6024 6025
          if (*found_semicolon)
          {
            lex->safe_to_cache_query= 0;
            thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
          }
6026 6027
          lex->set_trg_event_type_for_tables();
          mysql_execute_command(thd);
unknown's avatar
unknown committed
6028
	}
6029
      }
unknown's avatar
unknown committed
6030 6031
    }
    else
6032
    {
6033
      DBUG_ASSERT(thd->is_error());
6034
      DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
6035
			 thd->is_fatal_error));
6036 6037

      query_cache_abort(&thd->net);
6038
    }
6039 6040 6041 6042 6043 6044
    if (thd->lex->sphead)
    {
      delete thd->lex->sphead;
      thd->lex->sphead= 0;
    }
    lex->unit.cleanup();
6045
    thd_proc_info(thd, "freeing items");
6046
    thd->end_statement();
6047
    thd->cleanup_after_query();
6048
    DBUG_ASSERT(thd->change_list.is_empty());
unknown's avatar
unknown committed
6049
  }
6050 6051 6052 6053 6054 6055
  else
  {
    /* There are no multi queries in the cache. */
    *found_semicolon= NULL;
  }

unknown's avatar
unknown committed
6056 6057 6058 6059
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
6060
#ifdef HAVE_REPLICATION
6061 6062 6063 6064
/*
  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
6065
  @retval
6066
    0	cannot be ignored
unknown's avatar
unknown committed
6067
  @retval
6068 6069 6070 6071 6072
    1	can be ignored
*/

bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
{
unknown's avatar
unknown committed
6073
  LEX *lex= thd->lex;
6074
  bool error= 0;
unknown's avatar
unknown committed
6075
  DBUG_ENTER("mysql_test_parse_for_slave");
6076

6077 6078 6079 6080 6081
  Parser_state parser_state;
  if (!(error= parser_state.init(thd, inBuf, length)))
  {
    lex_start(thd);
    mysql_reset_thd_for_next_command(thd);
6082

6083
    if (!parse_sql(thd, & parser_state, NULL) &&
6084
        all_tables_not_ok(thd, lex->select_lex.table_list.first))
6085 6086 6087
      error= 1;                  /* Ignore question */
    thd->end_statement();
  }
6088
  thd->cleanup_after_query();
unknown's avatar
unknown committed
6089
  DBUG_RETURN(error);
6090
}
unknown's avatar
unknown committed
6091
#endif
unknown's avatar
unknown committed
6092

6093

unknown's avatar
unknown committed
6094

unknown's avatar
unknown committed
6095 6096 6097 6098 6099 6100
/**
  Store field definition for create.

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

6102
bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
unknown's avatar
unknown committed
6103
		       char *length, char *decimals,
6104
		       uint type_modifier,
6105 6106
		       Item *default_value, Item *on_update_value,
                       LEX_STRING *comment,
6107 6108
		       char *change,
                       List<String> *interval_list, CHARSET_INFO *cs,
unknown's avatar
unknown committed
6109
		       uint uint_geom_type)
unknown's avatar
unknown committed
6110
{
unknown's avatar
unknown committed
6111
  register Create_field *new_field;
unknown's avatar
unknown committed
6112
  LEX  *lex= thd->lex;
unknown's avatar
unknown committed
6113 6114
  DBUG_ENTER("add_field_to_list");

6115 6116
  if (check_string_char_length(field_name, "", NAME_CHAR_LEN,
                               system_charset_info, 1))
unknown's avatar
unknown committed
6117
  {
6118
    my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */
unknown's avatar
unknown committed
6119 6120 6121 6122
    DBUG_RETURN(1);				/* purecov: inspected */
  }
  if (type_modifier & PRI_KEY_FLAG)
  {
6123
    Key *key;
unknown's avatar
unknown committed
6124
    lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
6125 6126 6127 6128
    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
6129 6130 6131 6132
    lex->col_list.empty();
  }
  if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
  {
6133
    Key *key;
unknown's avatar
unknown committed
6134
    lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
6135 6136 6137 6138
    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
6139 6140 6141
    lex->col_list.empty();
  }

6142
  if (default_value)
unknown's avatar
unknown committed
6143
  {
6144
    /* 
unknown's avatar
unknown committed
6145 6146
      Default value should be literal => basic constants =>
      no need fix_fields()
6147 6148 6149
      
      We allow only one function as part of default value - 
      NOW() as default for TIMESTAMP type.
6150
    */
6151 6152
    if (default_value->type() == Item::FUNC_ITEM && 
        !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
6153
         type == MYSQL_TYPE_TIMESTAMP))
6154
    {
6155
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
6156 6157 6158
      DBUG_RETURN(1);
    }
    else if (default_value->type() == Item::NULL_ITEM)
unknown's avatar
unknown committed
6159
    {
6160
      default_value= 0;
6161 6162 6163
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
	  NOT_NULL_FLAG)
      {
6164
	my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
6165 6166 6167 6168 6169
	DBUG_RETURN(1);
      }
    }
    else if (type_modifier & AUTO_INCREMENT_FLAG)
    {
6170
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
unknown's avatar
unknown committed
6171 6172 6173
      DBUG_RETURN(1);
    }
  }
6174

6175
  if (on_update_value && type != MYSQL_TYPE_TIMESTAMP)
6176
  {
6177
    my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
6178 6179
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
6180

6181
  if (type == MYSQL_TYPE_TIMESTAMP && length)
6182 6183 6184 6185 6186
  {
    /* 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
6187
    char buf[32];
6188
    my_snprintf(buf, sizeof(buf), "TIMESTAMP(%s)", length);
6189
    WARN_DEPRECATED(thd, "6.0", buf, "'TIMESTAMP'");
6190 6191
  }

unknown's avatar
unknown committed
6192
  if (!(new_field= new Create_field()) ||
6193
      new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
6194 6195
                      default_value, on_update_value, comment, change,
                      interval_list, cs, uint_geom_type))
unknown's avatar
unknown committed
6196
    DBUG_RETURN(1);
unknown's avatar
unknown committed
6197

6198
  lex->alter_info.create_list.push_back(new_field);
unknown's avatar
unknown committed
6199 6200 6201 6202
  lex->last_field=new_field;
  DBUG_RETURN(0);
}

6203

unknown's avatar
unknown committed
6204
/** Store position for column in ALTER TABLE .. ADD column. */
unknown's avatar
unknown committed
6205 6206 6207

void store_position_for_column(const char *name)
{
6208
  current_thd->lex->last_field->after=my_const_cast(char*) (name);
unknown's avatar
unknown committed
6209 6210 6211
}

bool
unknown's avatar
unknown committed
6212
add_proc_to_list(THD* thd, Item *item)
unknown's avatar
unknown committed
6213 6214 6215 6216
{
  ORDER *order;
  Item	**item_ptr;

unknown's avatar
unknown committed
6217
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
unknown's avatar
unknown committed
6218 6219 6220 6221 6222
    return 1;
  item_ptr = (Item**) (order+1);
  *item_ptr= item;
  order->item=item_ptr;
  order->free_me=0;
6223
  thd->lex->proc_list.link_in_list(order, &order->next);
unknown's avatar
unknown committed
6224 6225 6226 6227
  return 0;
}


unknown's avatar
unknown committed
6228 6229 6230
/**
  save order by and tables in own lists.
*/
unknown's avatar
unknown committed
6231

6232
bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *item,bool asc)
unknown's avatar
unknown committed
6233 6234 6235
{
  ORDER *order;
  DBUG_ENTER("add_to_list");
unknown's avatar
unknown committed
6236
  if (!(order = (ORDER *) thd->alloc(sizeof(ORDER))))
unknown's avatar
unknown committed
6237
    DBUG_RETURN(1);
unknown's avatar
unknown committed
6238 6239
  order->item_ptr= item;
  order->item= &order->item_ptr;
unknown's avatar
unknown committed
6240 6241 6242
  order->asc = asc;
  order->free_me=0;
  order->used=0;
6243
  order->counter_used= 0;
6244
  list.link_in_list(order, &order->next);
unknown's avatar
unknown committed
6245 6246 6247 6248
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262
/**
  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
6263
      0		Error
unknown's avatar
unknown committed
6264 6265
  @retval
    \#	Pointer to TABLE_LIST element added to the total table list
unknown's avatar
unknown committed
6266 6267
*/

unknown's avatar
unknown committed
6268 6269
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
6270
					     LEX_STRING *alias,
unknown's avatar
unknown committed
6271 6272
					     ulong table_options,
					     thr_lock_type lock_type,
unknown's avatar
unknown committed
6273
					     List<Index_hint> *index_hints_arg,
unknown's avatar
unknown committed
6274
                                             LEX_STRING *option)
unknown's avatar
unknown committed
6275 6276
{
  register TABLE_LIST *ptr;
unknown's avatar
unknown committed
6277
  TABLE_LIST *previous_table_ref; /* The table preceding the current one. */
unknown's avatar
unknown committed
6278
  char *alias_str;
6279
  LEX *lex= thd->lex;
unknown's avatar
unknown committed
6280
  DBUG_ENTER("add_table_to_list");
6281
  LINT_INIT(previous_table_ref);
unknown's avatar
unknown committed
6282 6283 6284 6285

  if (!table)
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? alias->str : table->table.str;
6286
  if (!test(table_options & TL_OPTION_ALIAS) && 
6287
      check_table_name(table->table.str, table->table.length, FALSE))
unknown's avatar
unknown committed
6288
  {
6289
    my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
unknown's avatar
unknown committed
6290 6291
    DBUG_RETURN(0);
  }
unknown's avatar
unknown committed
6292 6293

  if (table->is_derived_table() == FALSE && table->db.str &&
6294
      check_db_name(&table->db))
unknown's avatar
unknown committed
6295 6296 6297 6298
  {
    my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str);
    DBUG_RETURN(0);
  }
unknown's avatar
unknown committed
6299 6300

  if (!alias)					/* Alias is case sensitive */
6301 6302 6303
  {
    if (table->sel)
    {
unknown's avatar
unknown committed
6304 6305
      my_message(ER_DERIVED_MUST_HAVE_ALIAS,
                 ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
6306 6307
      DBUG_RETURN(0);
    }
6308
    if (!(alias_str= (char*) thd->memdup(alias_str,table->table.length+1)))
unknown's avatar
unknown committed
6309
      DBUG_RETURN(0);
6310
  }
unknown's avatar
unknown committed
6311
  if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
unknown's avatar
unknown committed
6312
    DBUG_RETURN(0);				/* purecov: inspected */
unknown's avatar
unknown committed
6313
  if (table->db.str)
6314 6315 6316 6317
  {
    ptr->db= table->db.str;
    ptr->db_length= table->db.length;
  }
6318
  else if (lex->copy_db_to(&ptr->db, &ptr->db_length))
unknown's avatar
unknown committed
6319
    DBUG_RETURN(0);
unknown's avatar
unknown committed
6320

6321
  ptr->alias= alias_str;
6322
  if (lower_case_table_names && table->table.length)
6323
    table->table.length= my_casedn_str(files_charset_info, table->table.str);
6324 6325
  ptr->table_name=table->table.str;
  ptr->table_name_length=table->table.length;
6326
  ptr->lock_type=   lock_type;
unknown's avatar
unknown committed
6327
  ptr->updating=    test(table_options & TL_OPTION_UPDATING);
6328
  /* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */
unknown's avatar
unknown committed
6329
  ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
unknown's avatar
unknown committed
6330
  ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
6331
  ptr->derived=	    table->sel;
6332
  if (!ptr->derived && is_schema_db(ptr->db, ptr->db_length))
6333
  {
6334
    ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
6335 6336
    if (!schema_table ||
        (schema_table->hidden && 
unknown's avatar
unknown committed
6337
         ((sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0 || 
6338 6339 6340
          /*
            this check is used for show columns|keys from I_S hidden table
          */
unknown's avatar
unknown committed
6341 6342
          lex->sql_command == SQLCOM_SHOW_FIELDS ||
          lex->sql_command == SQLCOM_SHOW_KEYS)))
6343
    {
unknown's avatar
unknown committed
6344
      my_error(ER_UNKNOWN_TABLE, MYF(0),
6345
               ptr->table_name, INFORMATION_SCHEMA_NAME.str);
6346 6347
      DBUG_RETURN(0);
    }
6348
    ptr->schema_table_name= ptr->table_name;
6349 6350
    ptr->schema_table= schema_table;
  }
6351
  ptr->select_lex=  lex->current_select;
unknown's avatar
unknown committed
6352
  ptr->cacheable_table= 1;
6353
  ptr->index_hints= index_hints_arg;
unknown's avatar
unknown committed
6354
  ptr->option= option ? option->str : 0;
unknown's avatar
unknown committed
6355
  /* check that used name is unique */
6356
  if (lock_type != TL_IGNORE)
unknown's avatar
unknown committed
6357
  {
6358
    TABLE_LIST *first_table= table_list.first;
unknown's avatar
unknown committed
6359 6360 6361
    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
6362
	 tables ;
unknown's avatar
VIEW  
unknown committed
6363
	 tables=tables->next_local)
unknown's avatar
unknown committed
6364
    {
6365 6366
      if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
	  !strcmp(ptr->db, tables->db))
unknown's avatar
unknown committed
6367
      {
6368
	my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
unknown's avatar
unknown committed
6369 6370
	DBUG_RETURN(0);				/* purecov: tested */
      }
unknown's avatar
unknown committed
6371 6372
    }
  }
unknown's avatar
unknown committed
6373 6374 6375
  /* Store the table reference preceding the current one. */
  if (table_list.elements > 0)
  {
6376 6377 6378
    /*
      table_list.next points to the last inserted TABLE_LIST->next_local'
      element
6379
      We don't use the offsetof() macro here to avoid warnings from gcc
6380
    */
6381 6382 6383
    previous_table_ref= (TABLE_LIST*) ((char*) table_list.next -
                                       ((char*) &(ptr->next_local) -
                                        (char*) ptr));
6384 6385 6386 6387 6388 6389 6390 6391
    /*
      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
6392
  }
6393

unknown's avatar
unknown committed
6394 6395 6396 6397 6398 6399
  /*
    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'.
  */
6400
  table_list.link_in_list(ptr, &ptr->next_local);
unknown's avatar
unknown committed
6401
  ptr->next_name_resolution_table= NULL;
6402
  /* Link table in global list (all used tables) */
6403
  lex->add_to_query_tables(ptr);
unknown's avatar
unknown committed
6404 6405 6406
  DBUG_RETURN(ptr);
}

unknown's avatar
unknown committed
6407

unknown's avatar
unknown committed
6408 6409
/**
  Initialize a new table list for a nested join.
6410

6411 6412 6413 6414 6415 6416 6417 6418
    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
6419 6420 6421 6422 6423 6424
  @param thd         current thread

  @retval
    0   if success
  @retval
    1   otherwise
6425 6426 6427 6428 6429 6430 6431
*/

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

6433 6434
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
6435
    DBUG_RETURN(1);
6436
  nested_join= ptr->nested_join=
6437
    ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
6438

6439 6440 6441
  join_list->push_front(ptr);
  ptr->embedding= embedding;
  ptr->join_list= join_list;
6442
  ptr->alias= (char*) "(nested_join)";
6443 6444 6445 6446 6447 6448 6449
  embedding= ptr;
  join_list= &nested_join->join_list;
  join_list->empty();
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
6450 6451
/**
  End a nested join table list.
6452 6453 6454

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

unknown's avatar
unknown committed
6457 6458 6459 6460 6461
  @param thd         current thread

  @return
    - Pointer to TABLE_LIST element added to the total table list, if success
    - 0, otherwise
6462 6463 6464 6465 6466
*/

TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
{
  TABLE_LIST *ptr;
6467
  NESTED_JOIN *nested_join;
6468
  DBUG_ENTER("end_nested_join");
6469

unknown's avatar
unknown committed
6470
  DBUG_ASSERT(embedding);
6471 6472 6473
  ptr= embedding;
  join_list= ptr->join_list;
  embedding= ptr->embedding;
6474
  nested_join= ptr->nested_join;
6475 6476 6477 6478 6479 6480 6481 6482 6483
  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;
  }
6484
  else if (nested_join->join_list.elements == 0)
unknown's avatar
unknown committed
6485 6486
  {
    join_list->pop();
6487
    ptr= 0;                                     // return value
unknown's avatar
unknown committed
6488
  }
6489 6490 6491 6492
  DBUG_RETURN(ptr);
}


unknown's avatar
unknown committed
6493 6494
/**
  Nest last join operation.
6495 6496 6497

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

unknown's avatar
unknown committed
6498
  @param thd         current thread
6499

unknown's avatar
unknown committed
6500
  @retval
6501
    0  Error
unknown's avatar
unknown committed
6502 6503
  @retval
    \#  Pointer to TABLE_LIST element created for the new nested join
6504 6505 6506 6507 6508 6509
*/

TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
{
  TABLE_LIST *ptr;
  NESTED_JOIN *nested_join;
6510
  List<TABLE_LIST> *embedded_list;
6511
  DBUG_ENTER("nest_last_join");
6512

6513 6514
  if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+
                                       sizeof(NESTED_JOIN))))
6515
    DBUG_RETURN(0);
6516
  nested_join= ptr->nested_join=
6517
    ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
6518

6519 6520
  ptr->embedding= embedding;
  ptr->join_list= join_list;
6521
  ptr->alias= (char*) "(nest_last_join)";
6522
  embedded_list= &nested_join->join_list;
6523
  embedded_list->empty();
6524 6525

  for (uint i=0; i < 2; i++)
6526 6527 6528 6529 6530
  {
    TABLE_LIST *table= join_list->pop();
    table->join_list= embedded_list;
    table->embedding= ptr;
    embedded_list->push_back(table);
unknown's avatar
unknown committed
6531 6532 6533 6534 6535 6536 6537
    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
6538 6539
      if (prev_join_using)
        ptr->join_using_fields= prev_join_using;
unknown's avatar
unknown committed
6540
    }
6541 6542 6543 6544 6545 6546 6547
  }
  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
6548 6549
/**
  Add a table to the current join list.
6550 6551 6552 6553 6554 6555

    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
6556 6557 6558
  @param table       the table to add

  @return
6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571
    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
6572 6573
/**
  Convert a right join into equivalent left join.
6574 6575

    The function takes the current join list t[0],t[1] ... and
6576 6577 6578 6579 6580 6581
    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
6582
  @verbatim
6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593
    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
6594
   @endverbatim
6595

unknown's avatar
unknown committed
6596
  @param thd         current thread
6597

unknown's avatar
unknown committed
6598 6599 6600
  @return
    - Pointer to the table representing the inner table, if success
    - 0, otherwise
6601 6602
*/

6603
TABLE_LIST *st_select_lex::convert_right_join()
6604 6605
{
  TABLE_LIST *tab2= join_list->pop();
6606
  TABLE_LIST *tab1= join_list->pop();
6607 6608 6609 6610 6611 6612 6613 6614 6615
  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
6616 6617
/**
  Set lock for all tables in current select level.
unknown's avatar
unknown committed
6618

unknown's avatar
unknown committed
6619
  @param lock_type			Lock to set for tables
unknown's avatar
unknown committed
6620

unknown's avatar
unknown committed
6621
  @note
unknown's avatar
unknown committed
6622 6623 6624 6625 6626
    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
6627
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
unknown's avatar
unknown committed
6628 6629 6630 6631 6632
{
  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));
6633
  for (TABLE_LIST *tables= table_list.first;
unknown's avatar
VIEW  
unknown committed
6634 6635
       tables;
       tables= tables->next_local)
unknown's avatar
unknown committed
6636 6637 6638 6639 6640 6641 6642
  {
    tables->lock_type= lock_type;
    tables->updating=  for_update;
  }
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
6643

unknown's avatar
unknown committed
6644 6645
/**
  Create a fake SELECT_LEX for a unit.
unknown's avatar
unknown committed
6646 6647 6648 6649

    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
6650
    @verbatim
unknown's avatar
unknown committed
6651
    (SELECT ... ORDER BY order_list [LIMIT n]) ORDER BY ... 
unknown's avatar
unknown committed
6652
    @endvarbatim
unknown's avatar
unknown committed
6653
    or of the form
unknown's avatar
unknown committed
6654
    @varbatim
unknown's avatar
unknown committed
6655
    (SELECT ... ORDER BY LIMIT n) ORDER BY ...
unknown's avatar
unknown committed
6656
    @endvarbatim
unknown's avatar
unknown committed
6657
  
unknown's avatar
unknown committed
6658 6659 6660
  @param thd_arg		   thread handle

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

unknown's avatar
unknown committed
6664
  @retval
unknown's avatar
unknown committed
6665
    1     on failure to create the object
unknown's avatar
unknown committed
6666
  @retval
unknown's avatar
unknown committed
6667 6668 6669
    0     on success
*/

unknown's avatar
unknown committed
6670
bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
unknown's avatar
unknown committed
6671 6672 6673 6674
{
  SELECT_LEX *first_sl= first_select();
  DBUG_ENTER("add_fake_select_lex");
  DBUG_ASSERT(!fake_select_lex);
unknown's avatar
unknown committed
6675

unknown's avatar
unknown committed
6676
  if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX()))
unknown's avatar
unknown committed
6677 6678 6679 6680
      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
6681
  fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */
unknown's avatar
unknown committed
6682 6683
  fake_select_lex->make_empty_select();
  fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
6684 6685
  fake_select_lex->select_limit= 0;

unknown's avatar
unknown committed
6686
  fake_select_lex->context.outer_context=first_sl->context.outer_context;
6687 6688 6689
  /* 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
6690

6691
  if (!is_union())
unknown's avatar
unknown committed
6692 6693 6694 6695 6696 6697 6698 6699 6700
  {
    /* 
      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
6701
    thd_arg->lex->current_select= fake_select_lex;
unknown's avatar
unknown committed
6702
  }
unknown's avatar
unknown committed
6703
  thd_arg->lex->pop_context();
unknown's avatar
unknown committed
6704 6705 6706
  DBUG_RETURN(0);
}

6707

unknown's avatar
unknown committed
6708
/**
6709 6710
  Push a new name resolution context for a JOIN ... ON clause to the
  context stack of a query block.
unknown's avatar
unknown committed
6711 6712

    Create a new name resolution context for a JOIN ... ON clause,
6713 6714 6715
    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
6716

unknown's avatar
unknown committed
6717 6718 6719 6720 6721
  @param thd       pointer to current thread
  @param left_op   left  operand of the JOIN
  @param right_op  rigth operand of the JOIN

  @retval
6722
    FALSE  if all is OK
unknown's avatar
unknown committed
6723
  @retval
6724
    TRUE   if a memory allocation error occured
unknown's avatar
unknown committed
6725 6726
*/

6727 6728 6729
bool
push_new_name_resolution_context(THD *thd,
                                 TABLE_LIST *left_op, TABLE_LIST *right_op)
unknown's avatar
unknown committed
6730 6731
{
  Name_resolution_context *on_context;
6732
  if (!(on_context= new (thd->mem_root) Name_resolution_context))
6733
    return TRUE;
unknown's avatar
unknown committed
6734 6735 6736 6737 6738
  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();
6739
  return thd->lex->push_context(on_context);
unknown's avatar
unknown committed
6740 6741 6742
}


unknown's avatar
unknown committed
6743
/**
unknown's avatar
unknown committed
6744 6745 6746 6747
  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
6748 6749
  @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
6750

unknown's avatar
unknown committed
6751
  @retval
unknown's avatar
unknown committed
6752
    FALSE  if there was some error
unknown's avatar
unknown committed
6753
  @retval
unknown's avatar
unknown committed
6754 6755 6756 6757
    TRUE   if all is OK
*/

void add_join_on(TABLE_LIST *b, Item *expr)
unknown's avatar
unknown committed
6758
{
6759
  if (expr)
6760
  {
6761
    if (!b->on_expr)
unknown's avatar
unknown committed
6762
      b->on_expr= expr;
6763 6764
    else
    {
unknown's avatar
unknown committed
6765 6766 6767 6768 6769 6770
      /*
        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);
6771 6772
    }
    b->on_expr->top_level_item();
6773
  }
unknown's avatar
unknown committed
6774 6775 6776
}


unknown's avatar
unknown committed
6777
/**
unknown's avatar
unknown committed
6778 6779
  Mark that there is a NATURAL JOIN or JOIN ... USING between two
  tables.
6780

unknown's avatar
unknown committed
6781 6782 6783 6784 6785 6786 6787 6788 6789 6790
    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
6791
  @verbatim
6792 6793 6794
    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
6795

unknown's avatar
unknown committed
6796 6797 6798
    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
6799

unknown's avatar
unknown committed
6800 6801 6802
    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
6803 6804 6805 6806 6807
   @endverbatim

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

unknown's avatar
unknown committed
6810 6811
void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
                      SELECT_LEX *lex)
unknown's avatar
unknown committed
6812
{
unknown's avatar
unknown committed
6813
  b->natural_join= a;
unknown's avatar
unknown committed
6814
  lex->prev_join_using= using_fields;
unknown's avatar
unknown committed
6815 6816
}

unknown's avatar
unknown committed
6817

6818
/**
6819 6820
  Reload/resets privileges and the different caches.

6821 6822 6823 6824
  @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.
6825
               
6826 6827 6828 6829 6830 6831 6832 6833
  @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
6834
    @retval !=0  Error; thd->killed is set or thd->is_error() is true
6835 6836
*/

6837 6838
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
                          bool *write_to_binlog)
unknown's avatar
unknown committed
6839 6840 6841
{
  bool result=0;
  select_errors=0;				/* Write if more errors */
6842
  bool tmp_write_to_binlog= 1;
6843

6844
  DBUG_ASSERT(!thd || !thd->in_sub_stmt);
6845

unknown's avatar
SCRUM  
unknown committed
6846
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
6847 6848
  if (options & REFRESH_GRANT)
  {
6849 6850 6851 6852 6853 6854
    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)))
6855 6856
    {
      thd->thread_stack= (char*) &tmp_thd;
6857
      thd->store_globals();
6858
      lex_start(thd);
6859
    }
6860

6861 6862
    if (thd)
    {
6863 6864
      bool reload_acl_failed= acl_reload(thd);
      bool reload_grants_failed= grant_reload(thd);
Kristofer Pettersson's avatar
Kristofer Pettersson committed
6865
      bool reload_servers_failed= servers_reload(thd);
6866

Kristofer Pettersson's avatar
Kristofer Pettersson committed
6867
      if (reload_acl_failed || reload_grants_failed || reload_servers_failed)
6868
      {
6869
        result= 1;
6870 6871 6872 6873 6874 6875
        /*
          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");
      }
6876
    }
6877

6878 6879 6880 6881 6882 6883 6884
    if (tmp_thd)
    {
      delete tmp_thd;
      /* Remember that we don't have a THD */
      my_pthread_setspecific_ptr(THR_THD,  0);
      thd= 0;
    }
6885
    reset_mqh((LEX_USER *)NULL, TRUE);
unknown's avatar
unknown committed
6886
  }
unknown's avatar
SCRUM  
unknown committed
6887
#endif
unknown's avatar
unknown committed
6888 6889
  if (options & REFRESH_LOG)
  {
6890
    /*
unknown's avatar
unknown committed
6891
      Flush the normal query log, the update log, the binary log,
unknown's avatar
unknown committed
6892 6893
      the slow query log, the relay log (if it exists) and the log
      tables.
6894
    */
unknown's avatar
unknown committed
6895

6896
    /*
unknown's avatar
unknown committed
6897 6898 6899 6900
      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)
6901 6902
    */
    tmp_write_to_binlog= 0;
6903 6904 6905 6906
    if( mysql_bin_log.is_open() )
    {
      mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
    }
unknown's avatar
unknown committed
6907
#ifdef HAVE_REPLICATION
6908
    pthread_mutex_lock(&LOCK_active_mi);
6909
    rotate_relay_log(active_mi);
6910
    pthread_mutex_unlock(&LOCK_active_mi);
unknown's avatar
unknown committed
6911
#endif
unknown's avatar
unknown committed
6912 6913 6914 6915 6916

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

    if (ha_flush_logs(NULL))
unknown's avatar
unknown committed
6917
      result=1;
unknown's avatar
unknown committed
6918 6919
    if (flush_error_log())
      result=1;
unknown's avatar
unknown committed
6920
  }
unknown's avatar
unknown committed
6921
#ifdef HAVE_QUERY_CACHE
unknown's avatar
unknown committed
6922 6923
  if (options & REFRESH_QUERY_CACHE_FREE)
  {
unknown's avatar
unknown committed
6924
    query_cache.pack();				// FLUSH QUERY CACHE
6925
    options &= ~REFRESH_QUERY_CACHE;    // Don't flush cache, just free memory
unknown's avatar
unknown committed
6926 6927 6928
  }
  if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
  {
unknown's avatar
unknown committed
6929
    query_cache.flush();			// RESET QUERY CACHE
unknown's avatar
unknown committed
6930
  }
unknown's avatar
unknown committed
6931
#endif /*HAVE_QUERY_CACHE*/
6932 6933 6934 6935 6936
  /*
    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
6937
  {
6938
    if ((options & REFRESH_READ_LOCK) && thd)
unknown's avatar
unknown committed
6939
    {
6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950
      /*
        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
6951
        {
6952
          if ((*lock_p)->type >= TL_WRITE_ALLOW_WRITE)
6953 6954 6955 6956
          {
            my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
            return 1;
          }
unknown's avatar
unknown committed
6957
        }
6958
      }
unknown's avatar
unknown committed
6959 6960 6961 6962
      /*
	Writing to the binlog could cause deadlocks, as we don't log
	UNLOCK TABLES
      */
6963
      tmp_write_to_binlog= 0;
6964
      if (lock_global_read_lock(thd))
unknown's avatar
unknown committed
6965
	return 1;                               // Killed
Kristofer Pettersson's avatar
Kristofer Pettersson committed
6966
      if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
6967
                              FALSE : TRUE, TRUE))
6968 6969
          result= 1;
      
unknown's avatar
unknown committed
6970
      if (make_global_read_lock_block_commit(thd)) // Killed
6971 6972 6973 6974 6975
      {
        /* Don't leave things in a half-locked state */
        unlock_global_read_lock(thd);
        return 1;
      }
unknown's avatar
unknown committed
6976
    }
6977
    else
6978
    {
Kristofer Pettersson's avatar
Kristofer Pettersson committed
6979
      if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
6980
                              FALSE : TRUE, FALSE))
6981 6982
        result= 1;
    }
unknown's avatar
unknown committed
6983
    my_dbopt_cleanup();
unknown's avatar
unknown committed
6984 6985 6986
  }
  if (options & REFRESH_HOSTS)
    hostname_cache_refresh();
unknown's avatar
unknown committed
6987
  if (thd && (options & REFRESH_STATUS))
unknown's avatar
unknown committed
6988
    refresh_status(thd);
unknown's avatar
unknown committed
6989 6990
  if (options & REFRESH_THREADS)
    flush_thread_cache();
unknown's avatar
unknown committed
6991
#ifdef HAVE_REPLICATION
unknown's avatar
unknown committed
6992
  if (options & REFRESH_MASTER)
6993
  {
6994
    DBUG_ASSERT(thd);
6995
    tmp_write_to_binlog= 0;
6996
    if (reset_master(thd))
unknown's avatar
unknown committed
6997
    {
6998
      result=1;
unknown's avatar
unknown committed
6999
    }
7000
  }
7001
#endif
unknown's avatar
unknown committed
7002
#ifdef OPENSSL
7003 7004
   if (options & REFRESH_DES_KEY_FILE)
   {
7005 7006
     if (des_key_file && load_des_key_file(des_key_file))
         result= 1;
7007 7008
   }
#endif
unknown's avatar
unknown committed
7009
#ifdef HAVE_REPLICATION
7010 7011
 if (options & REFRESH_SLAVE)
 {
7012
   tmp_write_to_binlog= 0;
7013
   pthread_mutex_lock(&LOCK_active_mi);
7014
   if (reset_slave(thd, active_mi))
7015
     result=1;
7016
   pthread_mutex_unlock(&LOCK_active_mi);
7017
 }
7018
#endif
7019
 if (options & REFRESH_USER_RESOURCES)
7020
   reset_mqh((LEX_USER *) NULL, 0);             /* purecov: inspected */
unknown's avatar
unknown committed
7021
 *write_to_binlog= tmp_write_to_binlog;
7022 7023 7024
 /*
   If the query was killed then this function must fail.
 */
7025
 return result || (thd ? thd->killed : 0);
unknown's avatar
unknown committed
7026 7027
}

7028

unknown's avatar
unknown committed
7029 7030
/**
  kill on thread.
7031

unknown's avatar
unknown committed
7032 7033 7034
  @param thd			Thread class
  @param id			Thread id
  @param only_kill_query        Should it kill the query or the connection
7035

unknown's avatar
unknown committed
7036
  @note
7037 7038 7039
    This is written such that we have a short lock on LOCK_thread_count
*/

7040
uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
unknown's avatar
unknown committed
7041 7042 7043
{
  THD *tmp;
  uint error=ER_NO_SUCH_THREAD;
7044 7045
  DBUG_ENTER("kill_one_thread");
  DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query));
7046 7047
  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
  I_List_iterator<THD> it(threads);
unknown's avatar
unknown committed
7048 7049
  while ((tmp=it++))
  {
unknown's avatar
unknown committed
7050 7051
    if (tmp->command == COM_DAEMON)
      continue;
unknown's avatar
unknown committed
7052 7053
    if (tmp->thread_id == id)
    {
7054
      pthread_mutex_lock(&tmp->LOCK_thd_data);	// Lock from delete
7055
      break;
unknown's avatar
unknown committed
7056 7057 7058
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
7059 7060
  if (tmp)
  {
7061 7062 7063 7064 7065

    /*
      If we're SUPER, we can KILL anything, including system-threads.
      No further checks.

7066 7067 7068
      KILLer: thd->security_ctx->user could in theory be NULL while
      we're still in "unauthenticated" state. This is a theoretical
      case (the code suggests this could happen, so we play it safe).
7069

7070
      KILLee: tmp->security_ctx->user will be NULL for system threads.
7071
      We need to check so Jane Random User doesn't crash the server
7072 7073
      when trying to kill a) system threads or b) unauthenticated users'
      threads (Bug#43748).
7074

7075
      If user of both killer and killee are non-NULL, proceed with
7076 7077 7078
      slayage if both are string-equal.
    */

7079
    if ((thd->security_ctx->master_access & SUPER_ACL) ||
7080
        thd->security_ctx->user_matches(tmp->security_ctx))
7081
    {
unknown's avatar
SCRUM  
unknown committed
7082
      tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
7083 7084 7085 7086
      error=0;
    }
    else
      error=ER_KILL_DENIED_ERROR;
7087
    pthread_mutex_unlock(&tmp->LOCK_thd_data);
7088
  }
7089 7090 7091 7092
  DBUG_PRINT("exit", ("%d", error));
  DBUG_RETURN(error);
}

7093

7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107
/*
  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)))
7108
    my_ok(thd);
unknown's avatar
unknown committed
7109
  else
unknown's avatar
unknown committed
7110
    my_error(error, MYF(0), id);
unknown's avatar
unknown committed
7111 7112
}

unknown's avatar
unknown committed
7113

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

unknown's avatar
unknown committed
7116 7117
bool append_file_to_dir(THD *thd, const char **filename_ptr,
                        const char *table_name)
7118
{
7119
  char buff[FN_REFLEN],*ptr, *end;
7120 7121 7122 7123 7124 7125 7126
  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))
  {
7127
    my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
7128 7129 7130 7131
    return 1;
  }
  /* Fix is using unix filename format on dos */
  strmov(buff,*filename_ptr);
7132
  end=convert_dirname(buff, *filename_ptr, NullS);
7133
  if (!(ptr= (char*) thd->alloc((size_t) (end-buff) + strlen(table_name)+1)))
7134 7135
    return 1;					// End of memory
  *filename_ptr=ptr;
7136
  strxmov(ptr,buff,table_name,NullS);
7137 7138
  return 0;
}
7139

7140

unknown's avatar
unknown committed
7141 7142
/**
  Check if the select is a simple select (not an union).
7143

unknown's avatar
unknown committed
7144
  @retval
7145
    0	ok
unknown's avatar
unknown committed
7146
  @retval
7147 7148 7149 7150 7151 7152
    1	error	; In this case the error messege is sent to the client
*/

bool check_simple_select()
{
  THD *thd= current_thd;
7153 7154
  LEX *lex= thd->lex;
  if (lex->current_select != &lex->select_lex)
7155 7156
  {
    char command[80];
7157
    Lex_input_stream *lip= & thd->m_parser_state->m_lip;
7158 7159
    strmake(command, lip->yylval->symbol.str,
	    min(lip->yylval->symbol.length, sizeof(command)-1));
7160
    my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
7161 7162 7163 7164
    return 1;
  }
  return 0;
}
unknown's avatar
unknown committed
7165

unknown's avatar
unknown committed
7166

unknown's avatar
unknown committed
7167
Comp_creator *comp_eq_creator(bool invert)
unknown's avatar
unknown committed
7168
{
unknown's avatar
unknown committed
7169
  return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator;
unknown's avatar
unknown committed
7170 7171
}

unknown's avatar
unknown committed
7172

unknown's avatar
unknown committed
7173
Comp_creator *comp_ge_creator(bool invert)
unknown's avatar
unknown committed
7174
{
unknown's avatar
unknown committed
7175
  return invert?(Comp_creator *)&lt_creator:(Comp_creator *)&ge_creator;
unknown's avatar
unknown committed
7176 7177
}

unknown's avatar
unknown committed
7178

unknown's avatar
unknown committed
7179
Comp_creator *comp_gt_creator(bool invert)
unknown's avatar
unknown committed
7180
{
unknown's avatar
unknown committed
7181
  return invert?(Comp_creator *)&le_creator:(Comp_creator *)&gt_creator;
unknown's avatar
unknown committed
7182 7183
}

unknown's avatar
unknown committed
7184

unknown's avatar
unknown committed
7185
Comp_creator *comp_le_creator(bool invert)
unknown's avatar
unknown committed
7186
{
unknown's avatar
unknown committed
7187
  return invert?(Comp_creator *)&gt_creator:(Comp_creator *)&le_creator;
unknown's avatar
unknown committed
7188 7189
}

unknown's avatar
unknown committed
7190

unknown's avatar
unknown committed
7191
Comp_creator *comp_lt_creator(bool invert)
unknown's avatar
unknown committed
7192
{
unknown's avatar
unknown committed
7193
  return invert?(Comp_creator *)&ge_creator:(Comp_creator *)&lt_creator;
unknown's avatar
unknown committed
7194 7195
}

unknown's avatar
unknown committed
7196

unknown's avatar
unknown committed
7197
Comp_creator *comp_ne_creator(bool invert)
unknown's avatar
unknown committed
7198
{
unknown's avatar
unknown committed
7199
  return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator;
unknown's avatar
unknown committed
7200
}
unknown's avatar
unknown committed
7201 7202


unknown's avatar
unknown committed
7203 7204
/**
  Construct ALL/ANY/SOME subquery Item.
unknown's avatar
unknown committed
7205

unknown's avatar
unknown committed
7206 7207 7208 7209
  @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
7210

unknown's avatar
unknown committed
7211
  @return
unknown's avatar
unknown committed
7212 7213 7214 7215 7216 7217 7218
    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
7219
  if ((cmp == &comp_eq_creator) && !all)       //  = ANY <=> IN
unknown's avatar
unknown committed
7220
    return new Item_in_subselect(left_expr, select_lex);
unknown's avatar
unknown committed
7221 7222

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

  Item_allany_subselect *it=
7226
    new Item_allany_subselect(left_expr, cmp, select_lex, all);
unknown's avatar
unknown committed
7227
  if (all)
7228
    return it->upper_item= new Item_func_not_all(it);	/* ALL */
unknown's avatar
unknown committed
7229

7230
  return it->upper_item= new Item_func_nop_all(it);      /* ANY/SOME */
unknown's avatar
unknown committed
7231
}
7232 7233


unknown's avatar
unknown committed
7234 7235
/**
  Multi update query pre-check.
7236

unknown's avatar
unknown committed
7237 7238
  @param thd		Thread handler
  @param tables	Global/local table list (have to be the same)
7239

unknown's avatar
unknown committed
7240
  @retval
unknown's avatar
unknown committed
7241
    FALSE OK
unknown's avatar
unknown committed
7242
  @retval
unknown's avatar
unknown committed
7243
    TRUE  Error
7244
*/
unknown's avatar
unknown committed
7245

unknown's avatar
unknown committed
7246
bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
7247 7248 7249 7250 7251
{
  const char *msg= 0;
  TABLE_LIST *table;
  LEX *lex= thd->lex;
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
7252
  DBUG_ENTER("multi_update_precheck");
7253 7254 7255

  if (select_lex->item_list.elements != lex->value_list.elements)
  {
7256
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7257
    DBUG_RETURN(TRUE);
7258 7259 7260 7261 7262
  }
  /*
    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
7263
  for (table= tables; table; table= table->next_local)
7264
  {
7265 7266 7267
    if (table->derived)
      table->grant.privilege= SELECT_ACL;
    else if ((check_access(thd, UPDATE_ACL, table->db,
7268 7269
                           &table->grant.privilege, 0, 1,
                           test(table->schema_table)) ||
7270
              check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
unknown's avatar
unknown committed
7271
             (check_access(thd, SELECT_ACL, table->db,
7272 7273
                           &table->grant.privilege, 0, 0,
                           test(table->schema_table)) ||
7274
              check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
unknown's avatar
unknown committed
7275
      DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7276

unknown's avatar
VIEW  
unknown committed
7277
    table->table_in_first_from_clause= 1;
7278
  }
unknown's avatar
unknown committed
7279 7280 7281
  /*
    Is there tables of subqueries?
  */
7282
  if (&lex->select_lex != lex->all_selects_list)
7283
  {
7284
    DBUG_PRINT("info",("Checking sub query list"));
unknown's avatar
VIEW  
unknown committed
7285
    for (table= tables; table; table= table->next_global)
7286
    {
7287
      if (!table->table_in_first_from_clause)
7288 7289
      {
	if (check_access(thd, SELECT_ACL, table->db,
7290 7291
			 &table->grant.privilege, 0, 0,
                         test(table->schema_table)) ||
7292
	    check_grant(thd, SELECT_ACL, table, 0, 1, 0))
unknown's avatar
unknown committed
7293
	  DBUG_RETURN(TRUE);
7294 7295 7296 7297 7298 7299
      }
    }
  }

  if (select_lex->order_list.elements)
    msg= "ORDER BY";
7300
  else if (select_lex->select_limit)
7301 7302 7303 7304
    msg= "LIMIT";
  if (msg)
  {
    my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
unknown's avatar
unknown committed
7305
    DBUG_RETURN(TRUE);
7306
  }
unknown's avatar
unknown committed
7307
  DBUG_RETURN(FALSE);
7308 7309
}

unknown's avatar
unknown committed
7310 7311
/**
  Multi delete query pre-check.
7312

unknown's avatar
unknown committed
7313 7314
  @param thd			Thread handler
  @param tables		Global/local table list
7315

unknown's avatar
unknown committed
7316
  @retval
unknown's avatar
unknown committed
7317
    FALSE OK
unknown's avatar
unknown committed
7318
  @retval
unknown's avatar
unknown committed
7319
    TRUE  error
7320
*/
unknown's avatar
unknown committed
7321

7322
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
7323 7324
{
  SELECT_LEX *select_lex= &thd->lex->select_lex;
7325
  TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
7326
  TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
unknown's avatar
VIEW  
unknown committed
7327
  DBUG_ENTER("multi_delete_precheck");
unknown's avatar
unknown committed
7328

7329 7330
  /* sql_yacc guarantees that tables and aux_tables are not zero */
  DBUG_ASSERT(aux_tables != 0);
7331
  if (check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
7332 7333 7334 7335 7336 7337 7338 7339
    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;
7340
  if (check_table_access(thd, DELETE_ACL, aux_tables, UINT_MAX, FALSE))
7341 7342
  {
    thd->lex->query_tables_own_last= save_query_tables_own_last;
unknown's avatar
unknown committed
7343
    DBUG_RETURN(TRUE);
7344 7345 7346
  }
  thd->lex->query_tables_own_last= save_query_tables_own_last;

7347 7348
  if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
  {
unknown's avatar
unknown committed
7349 7350
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
7351
    DBUG_RETURN(TRUE);
7352
  }
7353 7354 7355 7356
  DBUG_RETURN(FALSE);
}


unknown's avatar
unknown committed
7357
/**
7358 7359 7360
  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
7361
  @param lex   pointer to LEX representing multi-delete
7362

unknown's avatar
unknown committed
7363 7364 7365 7366
  @retval
    FALSE   success
  @retval
    TRUE    error
7367 7368 7369 7370
*/

bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
{
7371
  TABLE_LIST *tables= lex->select_lex.table_list.first;
7372 7373 7374 7375 7376
  TABLE_LIST *target_tbl;
  DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables");

  lex->table_count= 0;

7377
  for (target_tbl= lex->auxiliary_table_list.first;
7378
       target_tbl; target_tbl= target_tbl->next_local)
7379
  {
7380
    lex->table_count++;
7381 7382
    /* All tables in aux_tables must be found in FROM PART */
    TABLE_LIST *walk;
unknown's avatar
VIEW  
unknown committed
7383
    for (walk= tables; walk; walk= walk->next_local)
7384
    {
unknown's avatar
unknown committed
7385 7386 7387
      if (!my_strcasecmp(table_alias_charset,
			 target_tbl->alias, walk->alias) &&
	  !strcmp(walk->db, target_tbl->db))
7388 7389 7390 7391
	break;
    }
    if (!walk)
    {
7392
      my_error(ER_UNKNOWN_TABLE, MYF(0),
7393
               target_tbl->table_name, "MULTI DELETE");
unknown's avatar
unknown committed
7394
      DBUG_RETURN(TRUE);
7395
    }
unknown's avatar
unknown committed
7396 7397 7398 7399 7400
    if (!walk->derived)
    {
      target_tbl->table_name= walk->table_name;
      target_tbl->table_name_length= walk->table_name_length;
    }
unknown's avatar
unknown committed
7401
    walk->updating= target_tbl->updating;
unknown's avatar
unknown committed
7402
    walk->lock_type= target_tbl->lock_type;
unknown's avatar
VIEW  
unknown committed
7403
    target_tbl->correspondent_table= walk;	// Remember corresponding table
7404
  }
unknown's avatar
unknown committed
7405
  DBUG_RETURN(FALSE);
7406 7407 7408
}


unknown's avatar
unknown committed
7409 7410
/**
  simple UPDATE query pre-check.
unknown's avatar
unknown committed
7411

unknown's avatar
unknown committed
7412 7413
  @param thd		Thread handler
  @param tables	Global table list
unknown's avatar
unknown committed
7414

unknown's avatar
unknown committed
7415
  @retval
unknown's avatar
unknown committed
7416
    FALSE OK
unknown's avatar
unknown committed
7417
  @retval
unknown's avatar
unknown committed
7418
    TRUE  Error
unknown's avatar
unknown committed
7419
*/
unknown's avatar
unknown committed
7420

unknown's avatar
unknown committed
7421
bool update_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7422 7423 7424 7425
{
  DBUG_ENTER("update_precheck");
  if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
  {
unknown's avatar
unknown committed
7426
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7427
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7428
  }
unknown's avatar
unknown committed
7429
  DBUG_RETURN(check_one_table_access(thd, UPDATE_ACL, tables));
unknown's avatar
unknown committed
7430 7431 7432
}


unknown's avatar
unknown committed
7433 7434
/**
  simple DELETE query pre-check.
unknown's avatar
unknown committed
7435

unknown's avatar
unknown committed
7436 7437
  @param thd		Thread handler
  @param tables	Global table list
unknown's avatar
unknown committed
7438

unknown's avatar
unknown committed
7439
  @retval
unknown's avatar
unknown committed
7440
    FALSE  OK
unknown's avatar
unknown committed
7441
  @retval
unknown's avatar
unknown committed
7442
    TRUE   error
unknown's avatar
unknown committed
7443
*/
unknown's avatar
unknown committed
7444

unknown's avatar
unknown committed
7445
bool delete_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7446 7447 7448
{
  DBUG_ENTER("delete_precheck");
  if (check_one_table_access(thd, DELETE_ACL, tables))
unknown's avatar
unknown committed
7449
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7450
  /* Set privilege for the WHERE clause */
unknown's avatar
unknown committed
7451
  tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
unknown's avatar
unknown committed
7452
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
7453 7454 7455
}


unknown's avatar
unknown committed
7456 7457
/**
  simple INSERT query pre-check.
unknown's avatar
unknown committed
7458

unknown's avatar
unknown committed
7459 7460
  @param thd		Thread handler
  @param tables	Global table list
unknown's avatar
unknown committed
7461

unknown's avatar
unknown committed
7462
  @retval
unknown's avatar
unknown committed
7463
    FALSE  OK
unknown's avatar
unknown committed
7464
  @retval
unknown's avatar
unknown committed
7465
    TRUE   error
unknown's avatar
unknown committed
7466
*/
unknown's avatar
unknown committed
7467

unknown's avatar
merge  
unknown committed
7468
bool insert_precheck(THD *thd, TABLE_LIST *tables)
unknown's avatar
unknown committed
7469 7470 7471 7472
{
  LEX *lex= thd->lex;
  DBUG_ENTER("insert_precheck");

unknown's avatar
unknown committed
7473 7474 7475 7476
  /*
    Check that we have modify privileges for the first table and
    select privileges for the rest
  */
unknown's avatar
unknown committed
7477 7478 7479
  ulong privilege= (INSERT_ACL |
                    (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
                    (lex->value_list.elements ? UPDATE_ACL : 0));
unknown's avatar
unknown committed
7480 7481

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

unknown's avatar
unknown committed
7484
  if (lex->update_list.elements != lex->value_list.elements)
unknown's avatar
unknown committed
7485
  {
unknown's avatar
unknown committed
7486
    my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
unknown's avatar
unknown committed
7487
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
7488
  }
unknown's avatar
unknown committed
7489
  DBUG_RETURN(FALSE);
7490
}
unknown's avatar
unknown committed
7491 7492


unknown's avatar
unknown committed
7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507
/**
    @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)) ||
7508
         check_grant(thd, SELECT_ACL, table, 2, UINT_MAX, 0);
unknown's avatar
unknown committed
7509 7510 7511
}


unknown's avatar
unknown committed
7512 7513
/**
  CREATE TABLE query pre-check.
unknown's avatar
unknown committed
7514

unknown's avatar
unknown committed
7515 7516 7517
  @param thd			Thread handler
  @param tables		Global table list
  @param create_table	        Table which will be created
unknown's avatar
unknown committed
7518

unknown's avatar
unknown committed
7519
  @retval
unknown's avatar
unknown committed
7520
    FALSE   OK
unknown's avatar
unknown committed
7521
  @retval
unknown's avatar
unknown committed
7522
    TRUE   Error
unknown's avatar
unknown committed
7523
*/
unknown's avatar
unknown committed
7524

unknown's avatar
unknown committed
7525 7526
bool create_table_precheck(THD *thd, TABLE_LIST *tables,
                           TABLE_LIST *create_table)
unknown's avatar
unknown committed
7527 7528
{
  LEX *lex= thd->lex;
7529 7530
  SELECT_LEX *select_lex= &lex->select_lex;
  ulong want_priv;
unknown's avatar
merge  
unknown committed
7531
  bool error= TRUE;                                 // Error message is given
unknown's avatar
unknown committed
7532
  DBUG_ENTER("create_table_precheck");
7533

7534 7535 7536 7537 7538
  /*
    Require CREATE [TEMPORARY] privilege on new table; for
    CREATE TABLE ... SELECT, also require INSERT.
  */

7539
  want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
7540 7541 7542
              CREATE_TMP_ACL : CREATE_ACL) |
             (select_lex->item_list.elements ? INSERT_ACL : 0);

unknown's avatar
unknown committed
7543
  if (check_access(thd, want_priv, create_table->db,
7544 7545
		   &create_table->grant.privilege, 0, 0,
                   test(create_table->schema_table)) ||
unknown's avatar
unknown committed
7546
      check_merge_table_access(thd, create_table->db,
7547
                               lex->create_info.merge_list.first))
7548
    goto err;
7549
  if (want_priv != CREATE_TMP_ACL &&
7550
      check_grant(thd, want_priv, create_table, 0, 1, 0))
7551 7552 7553 7554 7555 7556
    goto err;

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

7557 7558
#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
    /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
7559
    /*
7560
      Only do the check for PS, because we on execute we have to check that
unknown's avatar
unknown committed
7561 7562
      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).
7563
    */
unknown's avatar
unknown committed
7564
    if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
7565
    {
unknown's avatar
unknown committed
7566 7567 7568 7569
      /*
        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
7570
          find_table_in_global_list(tables, create_table->db,
7571
                                    create_table->table_name))
unknown's avatar
unknown committed
7572
      {
7573
	error= FALSE;
unknown's avatar
unknown committed
7574 7575 7576
        goto err;
      }
    }
7577
#endif
7578
    if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
7579 7580
      goto err;
  }
unknown's avatar
unknown committed
7581 7582 7583 7584 7585
  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
7586
  error= FALSE;
7587 7588 7589

err:
  DBUG_RETURN(error);
unknown's avatar
unknown committed
7590
}
unknown's avatar
unknown committed
7591 7592


unknown's avatar
unknown committed
7593 7594
/**
  negate given expression.
unknown's avatar
unknown committed
7595

unknown's avatar
unknown committed
7596 7597
  @param thd  thread handler
  @param expr expression for negation
unknown's avatar
unknown committed
7598

unknown's avatar
unknown committed
7599
  @return
unknown's avatar
unknown committed
7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624
    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);
}
7625

unknown's avatar
unknown committed
7626 7627 7628
/**
  Set the specified definer to the default value, which is the
  current user in the thread.
7629
 
unknown's avatar
unknown committed
7630 7631
  @param[in]  thd       thread handler
  @param[out] definer   definer
7632 7633
*/
 
7634
void get_default_definer(THD *thd, LEX_USER *definer)
7635 7636 7637 7638 7639 7640 7641 7642
{
  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);
7643 7644 7645

  definer->password.str= NULL;
  definer->password.length= 0;
7646 7647
}

7648

unknown's avatar
unknown committed
7649
/**
7650
  Create default definer for the specified THD.
7651

unknown's avatar
unknown committed
7652
  @param[in] thd         thread handler
7653

unknown's avatar
unknown committed
7654 7655
  @return
    - On success, return a valid pointer to the created and initialized
7656
    LEX_USER, which contains definer information.
unknown's avatar
unknown committed
7657
    - On error, return 0.
7658 7659 7660 7661 7662 7663 7664 7665 7666
*/

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

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

7667
  get_default_definer(thd, definer);
7668 7669 7670 7671 7672

  return definer;
}


unknown's avatar
unknown committed
7673
/**
7674
  Create definer with the given user and host names.
7675

unknown's avatar
unknown committed
7676 7677 7678
  @param[in] thd          thread handler
  @param[in] user_name    user name
  @param[in] host_name    host name
7679

unknown's avatar
unknown committed
7680 7681
  @return
    - On success, return a valid pointer to the created and initialized
7682
    LEX_USER, which contains definer information.
unknown's avatar
unknown committed
7683
    - On error, return 0.
7684 7685
*/

7686
LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
7687
{
7688 7689 7690 7691
  LEX_USER *definer;

  /* Create and initialize. */

unknown's avatar
unknown committed
7692
  if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
7693 7694 7695 7696
    return 0;

  definer->user= *user_name;
  definer->host= *host_name;
7697 7698
  definer->password.str= NULL;
  definer->password.length= 0;
7699 7700

  return definer;
7701
}
7702 7703


unknown's avatar
unknown committed
7704
/**
7705 7706
  Retuns information about user or current user.

unknown's avatar
unknown committed
7707 7708
  @param[in] thd          thread handler
  @param[in] user         user
7709

unknown's avatar
unknown committed
7710 7711
  @return
    - On success, return a valid pointer to initialized
7712
    LEX_USER, which contains user information.
unknown's avatar
unknown committed
7713
    - On error, return 0.
7714 7715 7716 7717 7718
*/

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

7721 7722
  return user;
}
7723 7724


unknown's avatar
unknown committed
7725
/**
7726
  Check that byte length of a string does not exceed some limit.
7727

unknown's avatar
unknown committed
7728 7729 7730
  @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
7731

unknown's avatar
unknown committed
7732
  @retval
7733
    FALSE   the passed string is not longer than max_length
unknown's avatar
unknown committed
7734
  @retval
7735
    TRUE    the passed string is longer than max_length
7736 7737 7738

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

7741 7742
bool check_string_byte_length(LEX_STRING *str, const char *err_msg,
                              uint max_byte_length)
7743
{
7744
  if (str->length <= max_byte_length)
unknown's avatar
unknown committed
7745
    return FALSE;
7746

7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778
  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
7779

7780 7781
  if (!no_error)
    my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_char_length);
7782 7783
  return TRUE;
}
7784 7785


7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797
/*
  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  
*/
7798
C_MODE_START
7799

7800
int test_if_data_home_dir(const char *dir)
7801
{
7802
  char path[FN_REFLEN];
Alexey Botchkov's avatar
Alexey Botchkov committed
7803
  int dir_len;
7804 7805 7806 7807 7808 7809 7810
  DBUG_ENTER("test_if_data_home_dir");

  if (!dir)
    DBUG_RETURN(0);

  (void) fn_format(path, dir, "", "",
                   (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS));
7811 7812
  dir_len= strlen(path);
  if (mysql_unpacked_real_data_home_len<= dir_len)
7813
  {
7814 7815 7816 7817
    if (dir_len > mysql_unpacked_real_data_home_len &&
        path[mysql_unpacked_real_data_home_len] != FN_LIBCHAR)
      DBUG_RETURN(0);

7818 7819
    if (lower_case_file_system)
    {
7820 7821
      if (!my_strnncoll(default_charset_info, (const uchar*) path,
                        mysql_unpacked_real_data_home_len,
7822
                        (const uchar*) mysql_unpacked_real_data_home,
7823
                        mysql_unpacked_real_data_home_len))
7824 7825
        DBUG_RETURN(1);
    }
7826 7827
    else if (!memcmp(path, mysql_unpacked_real_data_home,
                     mysql_unpacked_real_data_home_len))
7828 7829 7830 7831 7832
      DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}

7833 7834
C_MODE_END

7835

7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850
/**
  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
7851
  if (check_string_byte_length(str, ER(ER_HOSTNAME), HOSTNAME_LENGTH))
7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866
    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
7867 7868


7869 7870 7871 7872 7873 7874 7875 7876
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.
7877
  @param parser_state Parser state.
unknown's avatar
unknown committed
7878
  @param creation_ctx Object creation context.
7879 7880 7881 7882 7883 7884

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

unknown's avatar
unknown committed
7885
bool parse_sql(THD *thd,
7886
               Parser_state *parser_state,
unknown's avatar
unknown committed
7887
               Object_creation_ctx *creation_ctx)
7888
{
7889
  DBUG_ASSERT(thd->m_parser_state == NULL);
7890

unknown's avatar
unknown committed
7891 7892 7893 7894 7895 7896 7897
  /* Backup creation context. */

  Object_creation_ctx *backup_ctx= NULL;

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

7898
  /* Set parser state. */
unknown's avatar
unknown committed
7899

7900
  thd->m_parser_state= parser_state;
7901

unknown's avatar
unknown committed
7902 7903
  /* Parse the query. */

7904 7905
  bool mysql_parse_status= MYSQLparse(thd) != 0;

7906
  /* Check that if MYSQLparse() failed, thd->is_error() is set. */
7907 7908

  DBUG_ASSERT(!mysql_parse_status ||
Staale Smedseng's avatar
Staale Smedseng committed
7909
              (mysql_parse_status && thd->is_error()));
unknown's avatar
unknown committed
7910

7911
  /* Reset parser state. */
7912

7913
  thd->m_parser_state= NULL;
7914

unknown's avatar
unknown committed
7915 7916 7917 7918 7919 7920 7921
  /* Restore creation context. */

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

  /* That's it. */

7922
  return mysql_parse_status || thd->is_fatal_error;
7923
}
7924 7925 7926 7927

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