sp.cc 46.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* Copyright (C) 2002 MySQL AB

   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
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   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.

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


#include "mysql_priv.h"
#include "sp.h"
#include "sp_head.h"
21
#include "sp_cache.h"
22
#include "sql_trigger.h"
23

24 25
static bool
create_string(THD *thd, String *buf,
26
	      int sp_type,
27
	      sp_name *name,
28 29 30 31 32
	      const char *params, ulong paramslen,
	      const char *returns, ulong returnslen,
	      const char *body, ulong bodylen,
	      st_sp_chistics *chistics);

33 34 35 36 37 38
/*
 *
 * DB storage of Stored PROCEDUREs and FUNCTIONs
 *
 */

39 40
enum
{
41
  MYSQL_PROC_FIELD_DB = 0,
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
  MYSQL_PROC_FIELD_NAME,
  MYSQL_PROC_FIELD_TYPE,
  MYSQL_PROC_FIELD_SPECIFIC_NAME,
  MYSQL_PROC_FIELD_LANGUAGE,
  MYSQL_PROC_FIELD_ACCESS,
  MYSQL_PROC_FIELD_DETERMINISTIC,
  MYSQL_PROC_FIELD_SECURITY_TYPE,
  MYSQL_PROC_FIELD_PARAM_LIST,
  MYSQL_PROC_FIELD_RETURNS,
  MYSQL_PROC_FIELD_BODY,
  MYSQL_PROC_FIELD_DEFINER,
  MYSQL_PROC_FIELD_CREATED,
  MYSQL_PROC_FIELD_MODIFIED,
  MYSQL_PROC_FIELD_SQL_MODE,
  MYSQL_PROC_FIELD_COMMENT,
  MYSQL_PROC_FIELD_COUNT
};
59

60 61
bool mysql_proc_table_exists= 1;

62 63 64
/* Tells what SP_DEFAULT_ACCESS should be mapped to */
#define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL

65 66 67 68 69 70 71 72 73 74

/*
  Close mysql.proc, opened with open_proc_table_for_read().

  SYNOPSIS
    close_proc_table()
      thd  Thread context
*/

static void close_proc_table(THD *thd)
75
{
76 77 78
  close_thread_tables(thd);
  thd->pop_open_tables_state();
}
79

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106

/*
  Open the mysql.proc table for read.

  SYNOPSIS
    open_proc_table_for_read()
      thd  Thread context

  NOTES
    Thanks to restrictions which we put on opening and locking of
    this table for writing, we can open and lock it for reading
    even when we already have some other tables open and locked.
    One must call close_proc_table() to close table opened with
    this call.

  RETURN
    0	Error
    #	Pointer to TABLE object of mysql.proc
*/

static TABLE *open_proc_table_for_read(THD *thd)
{
  TABLE_LIST tables;
  TABLE *table;
  bool old_open_tables= thd->open_tables != 0;
  bool refresh;
  DBUG_ENTER("open_proc_table");
107

108
  /*
109 110
    Speed up things if mysql.proc doesn't exists. mysql_proc_table_exists
    is set when we create or read stored procedure or on flush privileges.
111
  */
112 113
  if (!mysql_proc_table_exists)
    DBUG_RETURN(0);
114

115 116 117 118 119 120 121 122
  if (thd->push_open_tables_state())
    DBUG_RETURN(0);

  bzero((char*) &tables, sizeof(tables));
  tables.db= (char*) "mysql";
  tables.table_name= tables.alias= (char*)"proc";
  if (!(table= open_table(thd, &tables, thd->mem_root, &refresh,
                          MYSQL_LOCK_IGNORE_FLUSH)))
123
  {
124 125 126
    thd->pop_open_tables_state();
    mysql_proc_table_exists= 0;
    DBUG_RETURN(0);
127
  }
128

129 130 131 132 133 134 135 136 137 138 139 140 141 142
  DBUG_ASSERT(table->s->system_table);

  table->reginfo.lock_type= TL_READ;
  /*
    If we have other tables opened, we have to ensure we are not blocked
    by a flush tables or global read lock, as this could lead to a deadlock
  */
  if (!(thd->lock= mysql_lock_tables(thd, &table, 1,
                                     old_open_tables ?
                                     (MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |
                                      MYSQL_LOCK_IGNORE_FLUSH) : 0)))
  {
    close_proc_table(thd);
    DBUG_RETURN(0);
143
  }
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
  DBUG_RETURN(table);
}


/*
  Open the mysql.proc table for update.

  SYNOPSIS
    open_proc_table_for_update()
      thd  Thread context

  NOTES
    Table opened with this call should closed using close_thread_tables().

  RETURN
    0	Error
    #	Pointer to TABLE object of mysql.proc
*/

static TABLE *open_proc_table_for_update(THD *thd)
{
  TABLE_LIST tables;
  TABLE *table;
  DBUG_ENTER("open_proc_table");

  bzero((char*) &tables, sizeof(tables));
  tables.db= (char*) "mysql";
  tables.table_name= tables.alias= (char*)"proc";
  tables.lock_type= TL_WRITE;

  table= open_ltable(thd, &tables, TL_WRITE);

  /*
    Under explicit LOCK TABLES or in prelocked mode we should not
    say that mysql.proc table does not exist if we are unable to
    open and lock it for writing since this condition may be
    transient.
  */
  if (!(thd->locked_tables || thd->prelocked_mode) || table)
    mysql_proc_table_exists= test(table);

  DBUG_RETURN(table);
}


/*
  Find row in open mysql.proc table representing stored routine.

  SYNOPSIS
    db_find_routine_aux()
      thd    Thread context
      type   Type of routine to find (function or procedure)
      name   Name of routine
      table  TABLE object for open mysql.proc table.

  RETURN VALUE
    SP_OK           - Routine found
    SP_KEY_NOT_FOUND- No routine with given name
*/

static int
db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table)
{
207
  byte key[MAX_KEY_LENGTH];	// db, name, optional key length type
208 209 210
  DBUG_ENTER("db_find_routine_aux");
  DBUG_PRINT("enter", ("type: %d name: %*s",
		       type, name->m_name.length, name->m_name.str));
211

212 213 214 215 216 217 218
  /*
    Create key to find row. We have to use field->store() to be able to
    handle VARCHAR and CHAR fields.
    Assumption here is that the three first fields in the table are
    'db', 'name' and 'type' and the first key is the primary key over the
    same fields.
  */
219 220
  if (name->m_name.length > table->field[1]->field_length)
    DBUG_RETURN(SP_KEY_NOT_FOUND);
221 222 223 224 225 226 227
  table->field[0]->store(name->m_db.str, name->m_db.length, &my_charset_bin);
  table->field[1]->store(name->m_name.str, name->m_name.length,
                         &my_charset_bin);
  table->field[2]->store((longlong) type);
  key_copy(key, table->record[0], table->key_info,
           table->key_info->key_length);

228
  if (table->file->index_read_idx(table->record[0], 0,
229
				  key, table->key_info->key_length,
230
				  HA_READ_KEY_EXACT))
231
    DBUG_RETURN(SP_KEY_NOT_FOUND);
232

233 234 235
  DBUG_RETURN(SP_OK);
}

unknown's avatar
unknown committed
236

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
/*
  Find routine definition in mysql.proc table and create corresponding
  sp_head object for it.

  SYNOPSIS
    db_find_routine()
      thd   Thread context
      type  Type of routine (TYPE_ENUM_PROCEDURE/...)
      name  Name of routine
      sphp  Out parameter in which pointer to created sp_head
            object is returned (0 in case of error).

  NOTE
    This function may damage current LEX during execution, so it is good
    idea to create temporary LEX and make it active before calling it.

  RETURN VALUE
    0     - Success
    non-0 - Error (may be one of special codes like SP_KEY_NOT_FOUND)
*/

258
static int
259
db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
260 261 262
{
  extern int yyparse(void *thd);
  TABLE *table;
263
  const char *params, *returns, *body;
264
  int ret;
265
  const char *definer;
unknown's avatar
unknown committed
266 267
  longlong created;
  longlong modified;
268
  st_sp_chistics chistics;
unknown's avatar
unknown committed
269 270 271
  char *ptr;
  uint length;
  char buff[65];
272
  String str(buff, sizeof(buff), &my_charset_bin);
273
  ulong sql_mode;
unknown's avatar
unknown committed
274
  DBUG_ENTER("db_find_routine");
275 276
  DBUG_PRINT("enter", ("type: %d name: %*s",
		       type, name->m_name.length, name->m_name.str));
277

278 279 280 281 282
  *sphp= 0;                                     // In case of errors
  if (!(table= open_proc_table_for_read(thd)))
    DBUG_RETURN(SP_OPEN_TABLE_FAILED);

  if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK)
283
    goto done;
284

285
  if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
286 287 288 289 290
  {
    ret= SP_GET_FIELD_FAILED;
    goto done;
  }

291
  bzero((char *)&chistics, sizeof(chistics));
unknown's avatar
unknown committed
292
  if ((ptr= get_field(thd->mem_root,
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
		      table->field[MYSQL_PROC_FIELD_ACCESS])) == NULL)
  {
    ret= SP_GET_FIELD_FAILED;
    goto done;
  }
  switch (ptr[0]) {
  case 'N':
    chistics.daccess= SP_NO_SQL;
    break;
  case 'C':
    chistics.daccess= SP_CONTAINS_SQL;
    break;
  case 'R':
    chistics.daccess= SP_READS_SQL_DATA;
    break;
  case 'M':
    chistics.daccess= SP_MODIFIES_SQL_DATA;
    break;
  default:
312
    chistics.daccess= SP_DEFAULT_ACCESS_MAPPING;
313 314
  }

unknown's avatar
unknown committed
315
  if ((ptr= get_field(thd->mem_root,
316
		      table->field[MYSQL_PROC_FIELD_DETERMINISTIC])) == NULL)
317 318 319 320
  {
    ret= SP_GET_FIELD_FAILED;
    goto done;
  }
321
  chistics.detistic= (ptr[0] == 'N' ? FALSE : TRUE);    
unknown's avatar
unknown committed
322

unknown's avatar
unknown committed
323
  if ((ptr= get_field(thd->mem_root,
324
		      table->field[MYSQL_PROC_FIELD_SECURITY_TYPE])) == NULL)
unknown's avatar
unknown committed
325 326 327 328
  {
    ret= SP_GET_FIELD_FAILED;
    goto done;
  }
329
  chistics.suid= (ptr[0] == 'I' ? SP_IS_NOT_SUID : SP_IS_SUID);
unknown's avatar
unknown committed
330

unknown's avatar
unknown committed
331
  if ((params= get_field(thd->mem_root,
332 333 334 335
			 table->field[MYSQL_PROC_FIELD_PARAM_LIST])) == NULL)
  {
    params= "";
  }
unknown's avatar
unknown committed
336

337 338
  if (type == TYPE_ENUM_PROCEDURE)
    returns= "";
unknown's avatar
unknown committed
339
  else if ((returns= get_field(thd->mem_root,
340 341 342 343 344 345
			       table->field[MYSQL_PROC_FIELD_RETURNS])) == NULL)
  {
    ret= SP_GET_FIELD_FAILED;
    goto done;
  }

unknown's avatar
unknown committed
346
  if ((body= get_field(thd->mem_root,
347
		       table->field[MYSQL_PROC_FIELD_BODY])) == NULL)
unknown's avatar
unknown committed
348 349 350 351
  {
    ret= SP_GET_FIELD_FAILED;
    goto done;
  }
352 353

  // Get additional information
unknown's avatar
unknown committed
354
  if ((definer= get_field(thd->mem_root,
355 356 357 358 359 360 361 362
			  table->field[MYSQL_PROC_FIELD_DEFINER])) == NULL)
  {
    ret= SP_GET_FIELD_FAILED;
    goto done;
  }

  modified= table->field[MYSQL_PROC_FIELD_MODIFIED]->val_int();
  created= table->field[MYSQL_PROC_FIELD_CREATED]->val_int();
unknown's avatar
unknown committed
363

unknown's avatar
unknown committed
364
  sql_mode= (ulong) table->field[MYSQL_PROC_FIELD_SQL_MODE]->val_int();
365

366 367
  table->field[MYSQL_PROC_FIELD_COMMENT]->val_str(&str, &str);

unknown's avatar
unknown committed
368
  ptr= 0;
369
  if ((length= str.length()))
370
    ptr= thd->strmake(str.ptr(), length);
371 372
  chistics.comment.str= ptr;
  chistics.comment.length= length;
unknown's avatar
unknown committed
373

374 375
  close_proc_table(thd);
  table= 0;
376

unknown's avatar
unknown committed
377
  {
378
    String defstr;
379
    LEX *oldlex= thd->lex;
380
    char olddb[128];
381
    bool dbchanged;
382
    enum enum_sql_command oldcmd= thd->lex->sql_command;
383 384 385 386 387
    ulong old_sql_mode= thd->variables.sql_mode;
    ha_rows select_limit= thd->variables.select_limit;

    thd->variables.sql_mode= sql_mode;
    thd->variables.select_limit= HA_POS_ERROR;
388

389 390 391 392 393 394 395 396
    defstr.set_charset(system_charset_info);
    if (!create_string(thd, &defstr,
		       type,
		       name,
		       params, strlen(params),
		       returns, strlen(returns),
		       body, strlen(body),
		       &chistics))
unknown's avatar
unknown committed
397 398 399 400 401
    {
      ret= SP_INTERNAL_ERROR;
      goto done;
    }

402 403 404
    dbchanged= FALSE;
    if ((ret= sp_use_new_db(thd, name->m_db.str, olddb, sizeof(olddb),
			    1, &dbchanged)))
405 406
      goto done;

407 408 409 410 411
    {
      /* This is something of a kludge. We need to initialize some fields
       * in thd->lex (the unit and master stuff), and the easiest way to
       * do it is, is to call mysql_init_query(), but this unfortunately
       * resets teh value_list where we keep the CALL parameters. So we
412
       * copy the list and then restore it. (... and found_semicolon too).
413
       */
414 415
      List<Item> tmpvals= thd->lex->value_list;
      char *tmpfsc= thd->lex->found_semicolon;
416

unknown's avatar
unknown committed
417
      lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length());
418 419
      thd->lex->value_list= tmpvals;
      thd->lex->found_semicolon= tmpfsc;
420 421
    }

422 423
    if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL)
    {
424 425 426
      LEX *newlex= thd->lex;
      sp_head *sp= newlex->sphead;

427
      if (dbchanged && (ret= sp_change_db(thd, olddb, 1)))
428
	goto done;
429
      if (sp)
430
      {
431 432
	delete sp;
	newlex->sphead= NULL;
433 434 435 436 437
      }
      ret= SP_PARSE_ERROR;
    }
    else
    {
438
      if (dbchanged && (ret= sp_change_db(thd, olddb, 1)))
439
	goto done;
440
      *sphp= thd->lex->sphead;
441
      (*sphp)->set_info((char *)definer, (uint)strlen(definer),
442
			created, modified, &chistics, sql_mode);
443
      (*sphp)->optimize();
444 445
    }
    thd->lex->sql_command= oldcmd;
446 447
    thd->variables.sql_mode= old_sql_mode;
    thd->variables.select_limit= select_limit;
unknown's avatar
unknown committed
448
  }
449 450

 done:
451 452
  if (table)
    close_proc_table(thd);
453
  DBUG_RETURN(ret);
454 455
}

unknown's avatar
unknown committed
456

unknown's avatar
unknown committed
457 458 459
static void
sp_returns_type(THD *thd, String &result, sp_head *sp)
{
unknown's avatar
unknown committed
460
  TABLE table;
unknown's avatar
unknown committed
461
  Field *field;
unknown's avatar
unknown committed
462 463 464 465
  bzero(&table, sizeof(table));
  table.in_use= thd;
  table.s = &table.share_not_to_be_used;
  field= sp->make_field(0, 0, &table);
unknown's avatar
unknown committed
466 467 468 469
  field->sql_type(result);
  delete field;
}

470
static int
471
db_create_routine(THD *thd, int type, sp_head *sp)
472
{
473
  int ret;
474
  TABLE *table;
475
  char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
476 477
  char olddb[128];
  bool dbchanged;
unknown's avatar
unknown committed
478 479
  DBUG_ENTER("db_create_routine");
  DBUG_PRINT("enter", ("type: %d name: %*s",type,sp->m_name.length,sp->m_name.str));
480

481 482 483 484 485 486 487 488
  dbchanged= FALSE;
  if ((ret= sp_use_new_db(thd, sp->m_db.str, olddb, sizeof(olddb),
			  0, &dbchanged)))
  {
    ret= SP_NO_DB_ERROR;
    goto done;
  }

489
  if (!(table= open_proc_table_for_update(thd)))
490 491
    ret= SP_OPEN_TABLE_FAILED;
  else
492
  {
493
    restore_record(table, s->default_values); // Get default values for fields
494
    strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS);
495

496
    if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
497 498 499 500
    {
      ret= SP_GET_FIELD_FAILED;
      goto done;
    }
501 502 503 504 505
    if (sp->m_name.length > table->field[MYSQL_PROC_FIELD_NAME]->field_length)
    {
      ret= SP_BAD_IDENTIFIER;
      goto done;
    }
506 507
    table->field[MYSQL_PROC_FIELD_DB]->
      store(sp->m_db.str, sp->m_db.length, system_charset_info);
508 509 510 511 512 513
    table->field[MYSQL_PROC_FIELD_NAME]->
      store(sp->m_name.str, sp->m_name.length, system_charset_info);
    table->field[MYSQL_PROC_FIELD_TYPE]->
      store((longlong)type);
    table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]->
      store(sp->m_name.str, sp->m_name.length, system_charset_info);
514 515 516
    if (sp->m_chistics->daccess != SP_DEFAULT_ACCESS)
      table->field[MYSQL_PROC_FIELD_ACCESS]->
	store((longlong)sp->m_chistics->daccess);
517 518
    table->field[MYSQL_PROC_FIELD_DETERMINISTIC]->
      store((longlong)(sp->m_chistics->detistic ? 1 : 2));
519
    if (sp->m_chistics->suid != SP_IS_DEFAULT_SUID)
520 521 522 523
      table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->
	store((longlong)sp->m_chistics->suid);
    table->field[MYSQL_PROC_FIELD_PARAM_LIST]->
      store(sp->m_params.str, sp->m_params.length, system_charset_info);
unknown's avatar
unknown committed
524 525 526 527
    if (sp->m_type == TYPE_ENUM_FUNCTION)
    {
      String retstr(64);
      sp_returns_type(thd, retstr, sp);
528
      table->field[MYSQL_PROC_FIELD_RETURNS]->
unknown's avatar
unknown committed
529 530
	store(retstr.ptr(), retstr.length(), system_charset_info);
    }
531 532 533
    table->field[MYSQL_PROC_FIELD_BODY]->
      store(sp->m_body.str, sp->m_body.length, system_charset_info);
    table->field[MYSQL_PROC_FIELD_DEFINER]->
534
      store(definer, (uint)strlen(definer), system_charset_info);
535
    ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_CREATED])->set_time();
536
    ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
537 538 539 540 541 542
    table->field[MYSQL_PROC_FIELD_SQL_MODE]->
      store((longlong)thd->variables.sql_mode);
    if (sp->m_chistics->comment.str)
      table->field[MYSQL_PROC_FIELD_COMMENT]->
	store(sp->m_chistics->comment.str, sp->m_chistics->comment.length,
	      system_charset_info);
543

544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
    if (!trust_routine_creators && mysql_bin_log.is_open())
    {
      if (!sp->m_chistics->detistic)
      {
	/*
	  Note that for a _function_ this test is not enough; one could use
	  a non-deterministic read-only function in an update statement.
	*/
	enum enum_sp_data_access access=
	  (sp->m_chistics->daccess == SP_DEFAULT_ACCESS) ?
	  SP_DEFAULT_ACCESS_MAPPING : sp->m_chistics->daccess;
	if (access == SP_CONTAINS_SQL ||
	    access == SP_MODIFIES_SQL_DATA)
	{
	  my_message(ER_BINLOG_UNSAFE_ROUTINE,
		     ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0));
	  ret= SP_INTERNAL_ERROR;
	  goto done;
	}
      }
      if (!(thd->master_access & SUPER_ACL))
      {
	my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER,
		   ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0));
	ret= SP_INTERNAL_ERROR;
	goto done;
      }
    }

unknown's avatar
unknown committed
573
    ret= SP_OK;
574 575
    if (table->file->write_row(table->record[0]))
      ret= SP_WRITE_ROW_FAILED;
576 577 578 579 580 581 582 583
    else if (mysql_bin_log.is_open())
    {
      thd->clear_error();
      /* Such a statement can always go directly to binlog, no trans cache */
      Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
      mysql_bin_log.write(&qinfo);
    }

584 585
  }

586
done:
587
  close_thread_tables(thd);
588 589
  if (dbchanged)
    (void)sp_change_db(thd, olddb, 1);
590 591
  DBUG_RETURN(ret);
}
592

unknown's avatar
unknown committed
593

594
static int
595
db_drop_routine(THD *thd, int type, sp_name *name)
596 597 598
{
  TABLE *table;
  int ret;
unknown's avatar
unknown committed
599
  DBUG_ENTER("db_drop_routine");
600 601
  DBUG_PRINT("enter", ("type: %d name: %*s",
		       type, name->m_name.length, name->m_name.str));
602

603 604 605
  if (!(table= open_proc_table_for_update(thd)))
    DBUG_RETURN(SP_OPEN_TABLE_FAILED);
  if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
606 607 608 609
  {
    if (table->file->delete_row(table->record[0]))
      ret= SP_DELETE_ROW_FAILED;
  }
610
  close_thread_tables(thd);
611 612 613
  DBUG_RETURN(ret);
}

unknown's avatar
unknown committed
614

unknown's avatar
unknown committed
615
static int
616
db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
unknown's avatar
unknown committed
617 618 619 620
{
  TABLE *table;
  int ret;
  bool opened;
unknown's avatar
unknown committed
621
  DBUG_ENTER("db_update_routine");
622 623
  DBUG_PRINT("enter", ("type: %d name: %*s",
		       type, name->m_name.length, name->m_name.str));
unknown's avatar
unknown committed
624

625 626 627
  if (!(table= open_proc_table_for_update(thd)))
    DBUG_RETURN(SP_OPEN_TABLE_FAILED);
  if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
unknown's avatar
unknown committed
628 629
  {
    store_record(table,record[1]);
unknown's avatar
unknown committed
630
    table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
unknown's avatar
unknown committed
631
    ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
632 633 634 635 636 637
    if (chistics->suid != SP_IS_DEFAULT_SUID)
      table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->
	store((longlong)chistics->suid);
    if (chistics->daccess != SP_DEFAULT_ACCESS)
      table->field[MYSQL_PROC_FIELD_ACCESS]->
	store((longlong)chistics->daccess);
638 639 640
    if (chistics->comment.str)
      table->field[MYSQL_PROC_FIELD_COMMENT]->store(chistics->comment.str,
						    chistics->comment.length,
unknown's avatar
unknown committed
641 642 643 644
						    system_charset_info);
    if ((table->file->update_row(table->record[1],table->record[0])))
      ret= SP_WRITE_ROW_FAILED;
  }
645
  close_thread_tables(thd);
unknown's avatar
unknown committed
646 647 648
  DBUG_RETURN(ret);
}

unknown's avatar
unknown committed
649

unknown's avatar
unknown committed
650 651 652 653 654 655 656 657 658 659
struct st_used_field
{
  const char *field_name;
  uint field_length;
  enum enum_field_types field_type;
  Field *field;
};

static struct st_used_field init_fields[]=
{
660
  { "Db",       NAME_LEN, MYSQL_TYPE_STRING,    0},
unknown's avatar
unknown committed
661 662
  { "Name",     NAME_LEN, MYSQL_TYPE_STRING,    0},
  { "Type",            9, MYSQL_TYPE_STRING,    0},
663
  { "Definer",        77, MYSQL_TYPE_STRING,    0},
unknown's avatar
unknown committed
664 665
  { "Modified",        0, MYSQL_TYPE_TIMESTAMP, 0},
  { "Created",         0, MYSQL_TYPE_TIMESTAMP, 0},
666
  { "Security_type",   1, MYSQL_TYPE_STRING,    0},
unknown's avatar
unknown committed
667 668 669 670
  { "Comment",  NAME_LEN, MYSQL_TYPE_STRING,    0},
  { 0,                 0, MYSQL_TYPE_STRING,    0}
};

unknown's avatar
unknown committed
671

672 673 674 675
static int
print_field_values(THD *thd, TABLE *table,
		   struct st_used_field *used_fields,
		   int type, const char *wild)
unknown's avatar
unknown committed
676 677 678 679 680
{
  Protocol *protocol= thd->protocol;

  if (table->field[MYSQL_PROC_FIELD_TYPE]->val_int() == type)
  {
681 682
    String db_string;
    String name_string;
unknown's avatar
unknown committed
683
    struct st_used_field *used_field= used_fields;
684

unknown's avatar
unknown committed
685
    if (get_field(thd->mem_root, used_field->field, &db_string))
686 687
      db_string.set_ascii("", 0);
    used_field+= 1;
unknown's avatar
unknown committed
688
    get_field(thd->mem_root, used_field->field, &name_string);
689 690

    if (!wild || !wild[0] || !wild_compare(name_string.ptr(), wild, 0))
unknown's avatar
unknown committed
691 692
    {
      protocol->prepare_for_resend();
693 694
      protocol->store(&db_string);
      protocol->store(&name_string);
unknown's avatar
unknown committed
695 696 697 698 699 700
      for (used_field++;
	   used_field->field_name;
	   used_field++)
      {
	switch (used_field->field_type) {
	case MYSQL_TYPE_TIMESTAMP:
701 702
	  {
	    TIME tmp_time;
703 704

	    bzero((char *)&tmp_time, sizeof(tmp_time));
705 706 707 708
	    ((Field_timestamp *) used_field->field)->get_time(&tmp_time);
	    protocol->store(&tmp_time);
	  }
	  break;
unknown's avatar
unknown committed
709
	default:
710
	  {
711
	    String tmp_string;
712

unknown's avatar
unknown committed
713
	    get_field(thd->mem_root, used_field->field, &tmp_string);
714
	    protocol->store(&tmp_string);
715 716
	  }
	  break;
unknown's avatar
unknown committed
717 718 719
	}
      }
      if (protocol->write())
720
	return SP_INTERNAL_ERROR;
unknown's avatar
unknown committed
721 722
    }
  }
723
  return SP_OK;
unknown's avatar
unknown committed
724 725
}

unknown's avatar
unknown committed
726

727
static int
unknown's avatar
unknown committed
728 729 730 731
db_show_routine_status(THD *thd, int type, const char *wild)
{
  TABLE *table;
  TABLE_LIST tables;
732
  int res;
unknown's avatar
unknown committed
733
  DBUG_ENTER("db_show_routine_status");
unknown's avatar
unknown committed
734 735 736

  memset(&tables, 0, sizeof(tables));
  tables.db= (char*)"mysql";
737
  tables.table_name= tables.alias= (char*)"proc";
unknown's avatar
unknown committed
738 739 740

  if (! (table= open_ltable(thd, &tables, TL_READ)))
  {
741 742
    res= SP_OPEN_TABLE_FAILED;
    goto done;
unknown's avatar
unknown committed
743 744 745 746 747 748
  }
  else
  {
    Item *item;
    List<Item> field_list;
    struct st_used_field *used_field;
749
    TABLE_LIST *leaves= 0;
unknown's avatar
unknown committed
750
    st_used_field used_fields[array_elements(init_fields)];
751

unknown's avatar
unknown committed
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769
    memcpy((char*) used_fields, (char*) init_fields, sizeof(used_fields));
    /* Init header */
    for (used_field= &used_fields[0];
	 used_field->field_name;
	 used_field++)
    {
      switch (used_field->field_type) {
      case MYSQL_TYPE_TIMESTAMP:
	field_list.push_back(item=new Item_datetime(used_field->field_name));
	break;
      default:
	field_list.push_back(item=new Item_empty_string(used_field->field_name,
							used_field->
							field_length));
	break;
      }
    }
    /* Print header */
770 771
    if (thd->protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
                                                Protocol::SEND_EOF))
772 773
    {
      res= SP_INTERNAL_ERROR;
unknown's avatar
unknown committed
774
      goto err_case;
775
    }
unknown's avatar
unknown committed
776

unknown's avatar
VIEW  
unknown committed
777 778 779 780 781
    /*
      Init fields

      tables is not VIEW for sure => we can pass 0 as condition
    */
782 783 784
    thd->lex->select_lex.context.resolve_in_table_list_only(&tables);
    setup_tables(thd, &thd->lex->select_lex.context,
                 &tables, 0, &leaves, FALSE);
unknown's avatar
unknown committed
785 786 787 788
    for (used_field= &used_fields[0];
	 used_field->field_name;
	 used_field++)
    {
789 790
      Item_field *field= new Item_field(&thd->lex->select_lex.context,
                                        "mysql", "proc",
unknown's avatar
unknown committed
791
					used_field->field_name);
792
      if (!field ||
793 794 795
          !(used_field->field= find_field_in_tables(thd, field, &tables,
						    0, REPORT_ALL_ERRORS, 1,
                                                    TRUE)))
796 797
      {
	res= SP_INTERNAL_ERROR;
unknown's avatar
unknown committed
798
	goto err_case1;
799
      }
unknown's avatar
unknown committed
800 801
    }

unknown's avatar
unknown committed
802
    table->file->ha_index_init(0);
803 804
    if ((res= table->file->index_first(table->record[0])))
    {
unknown's avatar
unknown committed
805
      res= (res == HA_ERR_END_OF_FILE) ? 0 : SP_INTERNAL_ERROR;
806 807 808
      goto err_case1;
    }
    if ((res= print_field_values(thd, table, used_fields, type, wild)))
unknown's avatar
unknown committed
809 810 811
      goto err_case1;
    while (!table->file->index_next(table->record[0]))
    {
812
      if ((res= print_field_values(thd, table, used_fields, type, wild)))
unknown's avatar
unknown committed
813 814
	goto err_case1;
    }
815
    res= SP_OK;
unknown's avatar
unknown committed
816
  }
817

unknown's avatar
unknown committed
818
err_case1:
unknown's avatar
unknown committed
819
  send_eof(thd);
unknown's avatar
unknown committed
820
err_case:
unknown's avatar
unknown committed
821
  table->file->ha_index_end();
unknown's avatar
unknown committed
822
  close_thread_tables(thd);
unknown's avatar
unknown committed
823
done:
824
  DBUG_RETURN(res);
unknown's avatar
unknown committed
825 826
}

827

828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
/* Drop all routines in database 'db' */
int
sp_drop_db_routines(THD *thd, char *db)
{
  TABLE *table;
  byte key[64];			// db
  uint keylen;
  int ret;
  DBUG_ENTER("sp_drop_db_routines");
  DBUG_PRINT("enter", ("db: %s", db));

  // Put the key used to read the row together
  keylen= strlen(db);
  if (keylen > 64)
    keylen= 64;
  memcpy(key, db, keylen);
  memset(key+keylen, (int)' ', 64-keylen); // Pad with space
  keylen= sizeof(key);

847 848 849
  ret= SP_OPEN_TABLE_FAILED;
  if (!(table= open_proc_table_for_update(thd)))
    goto err;
850 851

  ret= SP_OK;
unknown's avatar
unknown committed
852
  table->file->ha_index_init(0);
853 854 855 856 857 858
  if (! table->file->index_read(table->record[0],
				key, keylen, HA_READ_KEY_EXACT))
  {
    int nxtres;
    bool deleted= FALSE;

859 860
    do
    {
861 862 863 864 865
      if (! table->file->delete_row(table->record[0]))
	deleted= TRUE;		/* We deleted something */
      else
      {
	ret= SP_DELETE_ROW_FAILED;
866
	nxtres= 0;
867 868 869 870 871 872 873 874 875
	break;
      }
    } while (! (nxtres= table->file->index_next_same(table->record[0],
						     key, keylen)));
    if (nxtres != HA_ERR_END_OF_FILE)
      ret= SP_KEY_NOT_FOUND;
    if (deleted)
      sp_cache_invalidate();
  }
unknown's avatar
unknown committed
876
  table->file->ha_index_end();
877 878 879

  close_thread_tables(thd);

880
err:
881 882 883 884
  DBUG_RETURN(ret);
}


unknown's avatar
unknown committed
885 886 887
/*****************************************************************************
  PROCEDURE
******************************************************************************/
888

889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
/*
  Obtain object representing stored procedure by its name from
  stored procedures cache and looking into mysql.proc if needed.

  SYNOPSIS
    sp_find_procedure()
      thd        - thread context
      name       - name of procedure
      cache_only - if true perform cache-only lookup
                   (Don't look in mysql.proc).

  TODO
    We should consider merging of sp_find_procedure() and
    sp_find_function() into one sp_find_routine() function
    (the same applies to other similarly paired functions).

  RETURN VALUE
    Non-0 pointer to sp_head object for the procedure, or
    0 - in case of error.
*/

910
sp_head *
911
sp_find_procedure(THD *thd, sp_name *name, bool cache_only)
912 913
{
  sp_head *sp;
unknown's avatar
unknown committed
914
  DBUG_ENTER("sp_find_procedure");
915 916 917
  DBUG_PRINT("enter", ("name: %*s.%*s",
		       name->m_db.length, name->m_db.str,
		       name->m_name.length, name->m_name.str));
918

919
  if (!(sp= sp_cache_lookup(&thd->sp_proc_cache, name)) && !cache_only)
920
  {
921
    if (db_find_routine(thd, TYPE_ENUM_PROCEDURE, name, &sp) == SP_OK)
922
      sp_cache_insert(&thd->sp_proc_cache, sp);
923
  }
924 925 926 927

  DBUG_RETURN(sp);
}

unknown's avatar
unknown committed
928

929 930 931 932 933 934 935 936 937 938 939 940
int
sp_exists_routine(THD *thd, TABLE_LIST *tables, bool any, bool no_error)
{
  TABLE_LIST *table;
  bool result= 0;
  DBUG_ENTER("sp_exists_routine");
  for (table= tables; table; table= table->next_global)
  {
    sp_name *name;
    LEX_STRING lex_db;
    LEX_STRING lex_name;
    lex_db.length= strlen(table->db);
941
    lex_name.length= strlen(table->table_name);
942
    lex_db.str= thd->strmake(table->db, lex_db.length);
943
    lex_name.str= thd->strmake(table->table_name, lex_name.length);
944 945 946 947 948 949 950 951 952 953 954 955 956 957
    name= new sp_name(lex_db, lex_name);
    name->init_qname(thd);
    if (sp_find_procedure(thd, name) != NULL ||
        sp_find_function(thd, name) != NULL)
    {
      if (any)
        DBUG_RETURN(1);
      result= 1;
    }
    else if (!any)
    {
      if (!no_error)
      {
	my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION or PROCEDURE", 
958
		 table->table_name);
959 960 961 962 963 964 965 966 967
	DBUG_RETURN(-1);
      }
      DBUG_RETURN(0);
    }
  }
  DBUG_RETURN(result);
}


968
int
969
sp_create_procedure(THD *thd, sp_head *sp)
970
{
971
  int ret;
972
  DBUG_ENTER("sp_create_procedure");
973
  DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str));
974 975 976

  ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, sp);
  DBUG_RETURN(ret);
977 978
}

unknown's avatar
unknown committed
979

980
int
981
sp_drop_procedure(THD *thd, sp_name *name)
982
{
983
  int ret;
984
  bool found;
985
  DBUG_ENTER("sp_drop_procedure");
986
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
987

988
  found= sp_cache_remove(&thd->sp_proc_cache, name);
989
  ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name);
990 991
  if (!found && !ret)
    sp_cache_invalidate();
992
  DBUG_RETURN(ret);
993
}
994

unknown's avatar
unknown committed
995

unknown's avatar
unknown committed
996
int
997
sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics)
unknown's avatar
unknown committed
998
{
999
  int ret;
1000
  bool found;
unknown's avatar
unknown committed
1001
  DBUG_ENTER("sp_update_procedure");
1002
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
unknown's avatar
unknown committed
1003

1004
  found= sp_cache_remove(&thd->sp_proc_cache, name);
1005
  ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics);
1006 1007
  if (!found && !ret)
    sp_cache_invalidate();
1008
  DBUG_RETURN(ret);
unknown's avatar
unknown committed
1009 1010
}

unknown's avatar
unknown committed
1011

unknown's avatar
unknown committed
1012
int
1013
sp_show_create_procedure(THD *thd, sp_name *name)
unknown's avatar
unknown committed
1014
{
unknown's avatar
unknown committed
1015
  sp_head *sp;
unknown's avatar
unknown committed
1016
  DBUG_ENTER("sp_show_create_procedure");
1017
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
unknown's avatar
unknown committed
1018

unknown's avatar
unknown committed
1019
  if ((sp= sp_find_procedure(thd, name)))
1020 1021 1022 1023 1024
  {
    int ret= sp->show_create_procedure(thd);

    DBUG_RETURN(ret);
  }
unknown's avatar
unknown committed
1025

1026
  DBUG_RETURN(SP_KEY_NOT_FOUND);
unknown's avatar
unknown committed
1027 1028
}

unknown's avatar
unknown committed
1029

unknown's avatar
unknown committed
1030
int
1031
sp_show_status_procedure(THD *thd, const char *wild)
unknown's avatar
unknown committed
1032
{
1033
  int ret;
1034
  DBUG_ENTER("sp_show_status_procedure");
1035 1036 1037

  ret= db_show_routine_status(thd, TYPE_ENUM_PROCEDURE, wild);
  DBUG_RETURN(ret);
unknown's avatar
unknown committed
1038
}
1039

unknown's avatar
unknown committed
1040 1041 1042 1043

/*****************************************************************************
  FUNCTION
******************************************************************************/
1044

1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
/*
  Obtain object representing stored function by its name from
  stored functions cache and looking into mysql.proc if needed.

  SYNOPSIS
    sp_find_function()
      thd        - thread context
      name       - name of function
      cache_only - if true perform cache-only lookup
                   (Don't look in mysql.proc).

  NOTE
    See TODO section for sp_find_procedure().

  RETURN VALUE
    Non-0 pointer to sp_head object for the function, or
    0 - in case of error.
*/

1064
sp_head *
1065
sp_find_function(THD *thd, sp_name *name, bool cache_only)
1066 1067
{
  sp_head *sp;
unknown's avatar
unknown committed
1068
  DBUG_ENTER("sp_find_function");
1069
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
1070

1071 1072
  if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)) &&
      !cache_only)
1073
  {
1074
    if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) == SP_OK)
unknown's avatar
unknown committed
1075
      sp_cache_insert(&thd->sp_func_cache, sp);
1076
  }
1077 1078 1079
  DBUG_RETURN(sp);
}

unknown's avatar
unknown committed
1080

1081
int
1082
sp_create_function(THD *thd, sp_head *sp)
1083
{
1084
  int ret;
1085
  DBUG_ENTER("sp_create_function");
1086
  DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str));
1087

1088 1089
  ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, sp);
  DBUG_RETURN(ret);
1090 1091
}

unknown's avatar
unknown committed
1092

1093
int
1094
sp_drop_function(THD *thd, sp_name *name)
1095
{
1096
  int ret;
1097
  bool found;
1098
  DBUG_ENTER("sp_drop_function");
1099
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
1100

1101
  found= sp_cache_remove(&thd->sp_func_cache, name);
1102
  ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name);
1103 1104
  if (!found && !ret)
    sp_cache_invalidate();
1105
  DBUG_RETURN(ret);
1106
}
1107

unknown's avatar
unknown committed
1108

unknown's avatar
unknown committed
1109
int
1110
sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics)
unknown's avatar
unknown committed
1111
{
1112
  int ret;
1113
  bool found;
unknown's avatar
unknown committed
1114
  DBUG_ENTER("sp_update_procedure");
1115
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
unknown's avatar
unknown committed
1116

1117
  found= sp_cache_remove(&thd->sp_func_cache, name);
1118
  ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics);
1119 1120
  if (!found && !ret)
    sp_cache_invalidate();
1121
  DBUG_RETURN(ret);
unknown's avatar
unknown committed
1122 1123
}

unknown's avatar
unknown committed
1124

unknown's avatar
unknown committed
1125
int
1126
sp_show_create_function(THD *thd, sp_name *name)
unknown's avatar
unknown committed
1127
{
unknown's avatar
unknown committed
1128
  sp_head *sp;
unknown's avatar
unknown committed
1129
  DBUG_ENTER("sp_show_create_function");
1130
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
unknown's avatar
unknown committed
1131

unknown's avatar
unknown committed
1132
  if ((sp= sp_find_function(thd, name)))
1133 1134 1135 1136 1137
  {
    int ret= sp->show_create_function(thd);

    DBUG_RETURN(ret);
  }
1138
  DBUG_RETURN(SP_KEY_NOT_FOUND);
unknown's avatar
unknown committed
1139 1140
}

unknown's avatar
unknown committed
1141

unknown's avatar
unknown committed
1142
int
1143
sp_show_status_function(THD *thd, const char *wild)
unknown's avatar
unknown committed
1144
{
1145
  int ret;
1146
  DBUG_ENTER("sp_show_status_function");
1147 1148
  ret= db_show_routine_status(thd, TYPE_ENUM_FUNCTION, wild);
  DBUG_RETURN(ret);
unknown's avatar
unknown committed
1149 1150
}

unknown's avatar
unknown committed
1151

1152 1153 1154 1155 1156 1157 1158
/*
  Structure that represents element in the set of stored routines
  used by statement or routine.
*/
struct Sroutine_hash_entry;

struct Sroutine_hash_entry
1159
{
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174
  /* Set key consisting of one-byte routine type and quoted routine name. */
  LEX_STRING key;
  /*
    Next element in list linking all routines in set. See also comments
    for LEX::sroutine/sroutine_list and sp_head::m_sroutines.
  */
  Sroutine_hash_entry *next;
};


extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first)
{
  Sroutine_hash_entry *rn= (Sroutine_hash_entry *)ptr;
  *plen= rn->key.length;
  return (byte *)rn->key.str;
1175 1176
}

unknown's avatar
unknown committed
1177

1178
/*
1179 1180 1181 1182
  Check if
   - current statement (the one in thd->lex) needs table prelocking
   - first routine in thd->lex->sroutines_list needs to execute its body in
     prelocked mode.
1183 1184

  SYNOPSIS
1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
    sp_get_prelocking_info()
      thd                  Current thread, thd->lex is the statement to be
                           checked.
      need_prelocking      OUT TRUE  - prelocked mode should be activated
                                       before executing the statement
                               FALSE - Don't activate prelocking 
      first_no_prelocking  OUT TRUE  - Tables used by first routine in
                                       thd->lex->sroutines_list should be
                                       prelocked.
                               FALSE - Otherwise.
1195 1196 1197 1198 1199 1200
  NOTES 
    This function assumes that for any "CALL proc(...)" statement routines_list 
    will have 'proc' as first element (it may have several, consider e.g.
    "proc(sp_func(...)))". This property is currently guaranted by the parser.
*/

1201 1202
void sp_get_prelocking_info(THD *thd, bool *need_prelocking, 
                            bool *first_no_prelocking)
1203 1204
{
  Sroutine_hash_entry *routine;
1205
  routine= (Sroutine_hash_entry*)thd->lex->sroutines_list.first;
1206

1207 1208
  DBUG_ASSERT(routine);
  bool first_is_procedure= (routine->key.str[0] == TYPE_ENUM_PROCEDURE);
1209

1210 1211
  *first_no_prelocking= first_is_procedure;
  *need_prelocking= !first_is_procedure || test(routine->next);
1212 1213 1214
}


1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
/*
  Auxilary function that adds new element to the set of stored routines
  used by statement.

  SYNOPSIS
    add_used_routine()
      lex     - LEX representing statement
      arena   - arena in which memory for new element will be allocated
      key     - key for the hash representing set

  NOTES
    Will also add element to end of 'LEX::sroutines_list' list.

    In case when statement uses stored routines but does not need
    prelocking (i.e. it does not use any tables) we will access the
    elements of LEX::sroutines set on prepared statement re-execution.
    Because of this we have to allocate memory for both hash element
    and copy of its key in persistent arena.

  TODO
    When we will got rid of these accesses on re-executions we will be
    able to allocate memory for hash elements in non-persitent arena
    and directly use key values from sp_head::m_sroutines sets instead
    of making their copies.

  RETURN VALUE
    TRUE  - new element was added.
    FALSE - element was not added (because it is already present in the set).
*/

1245
static bool add_used_routine(LEX *lex, Query_arena *arena,
1246
                             const LEX_STRING *key)
1247
{
1248
  if (!hash_search(&lex->sroutines, (byte *)key->str, key->length))
1249
  {
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260
    Sroutine_hash_entry *rn=
      (Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry) +
                                          key->length);
    if (!rn)              // OOM. Error will be reported using fatal_error().
      return FALSE;
    rn->key.length= key->length;
    rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry);
    memcpy(rn->key.str, key->str, key->length);
    my_hash_insert(&lex->sroutines, (byte *)rn);
    lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next);
    return TRUE;
1261
  }
1262
  return FALSE;
1263 1264
}

unknown's avatar
unknown committed
1265

1266
/*
1267
  Add routine to the set of stored routines used by statement.
1268 1269

  SYNOPSIS
1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
    sp_add_used_routine()
      lex     - LEX representing statement
      arena   - arena in which memory for new element of the set
                will be allocated
      rt      - routine name
      rt_type - routine type (one of TYPE_ENUM_PROCEDURE/...)

  NOTES
    Will also add element to end of 'LEX::sroutines_list' list.

    To be friendly towards prepared statements one should pass
    persistent arena as second argument.
*/

1284
void sp_add_used_routine(LEX *lex, Query_arena *arena,
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
                         sp_name *rt, char rt_type)
{
  rt->set_routine_type(rt_type);
  (void)add_used_routine(lex, arena, &rt->m_sroutines_key);
}


/*
  Merge contents of two hashes representing sets of routines used
  by statements or by other routines.

  SYNOPSIS
    sp_update_sp_used_routines()
1298 1299 1300
      dst - hash to which elements should be added
      src - hash from which elements merged

1301 1302 1303 1304 1305 1306 1307
  NOTE
    This procedure won't create new Sroutine_hash_entry objects,
    instead it will simply add elements from source to destination
    hash. Thus time of life of elements in destination hash becomes
    dependant on time of life of elements from source hash. It also
    won't touch lists linking elements in source and destination
    hashes.
1308 1309
*/

1310
void sp_update_sp_used_routines(HASH *dst, HASH *src)
1311
{
1312
  for (uint i=0 ; i < src->records ; i++)
1313
  {
1314 1315 1316
    Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i);
    if (!hash_search(dst, (byte *)rt->key.str, rt->key.length))
      my_hash_insert(dst, (byte *)rt);
1317 1318 1319
  }
}

unknown's avatar
unknown committed
1320

1321
/*
1322 1323
  Add contents of hash representing set of routines to the set of
  routines used by statement.
1324 1325

  SYNOPSIS
1326
    sp_update_stmt_used_routines()
1327
      thd - thread context
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351
      lex - LEX representing statement
      src - hash representing set from which routines will be added

  NOTE
    It will also add elements to end of 'LEX::sroutines_list' list.
*/

static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src)
{
  for (uint i=0 ; i < src->records ; i++)
  {
    Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i);
    (void)add_used_routine(lex, thd->current_arena, &rt->key);
  }
}


/*
  Cache sub-set of routines used by statement, add tables used by these
  routines to statement table list. Do the same for all routines used
  by these routines.

  SYNOPSIS
    sp_cache_routines_and_add_tables_aux()
1352 1353 1354 1355 1356 1357 1358
      thd              - thread context
      lex              - LEX representing statement
      start            - first routine from the list of routines to be cached
                         (this list defines mentioned sub-set).
      first_no_prelock - If true, don't add tables or cache routines used by
                         the body of the first routine (i.e. *start)
                         will be executed in non-prelocked mode.
1359 1360 1361 1362
  NOTE
    If some function is missing this won't be reported here.
    Instead this fact will be discovered during query execution.

1363 1364 1365
  RETURN VALUE
    TRUE  - some tables were added
    FALSE - no tables were added.
1366 1367
*/

1368 1369
static bool
sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
1370 1371
                                     Sroutine_hash_entry *start, 
                                     bool first_no_prelock)
1372
{
1373
  bool result= FALSE;
1374
  bool first= TRUE;
1375
  DBUG_ENTER("sp_cache_routines_and_add_tables_aux");
1376

1377
  for (Sroutine_hash_entry *rt= start; rt; rt= rt->next)
1378
  {
1379 1380 1381
    sp_name name(rt->key.str, rt->key.length);
    int type= rt->key.str[0];
    sp_head *sp;
1382

1383 1384 1385
    if (!(sp= sp_cache_lookup((type == TYPE_ENUM_FUNCTION ?
                              &thd->sp_func_cache : &thd->sp_proc_cache),
                              &name)))
1386
    {
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398
      LEX *oldlex= thd->lex;
      LEX *newlex= new st_lex;
      thd->lex= newlex;
      newlex->current_select= NULL;
      name.m_name.str= strchr(name.m_qname.str, '.');
      name.m_db.length= name.m_name.str - name.m_qname.str;
      name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str,
                                  name.m_db.length);
      name.m_name.str+= 1;
      name.m_name.length= name.m_qname.length - name.m_db.length - 1;

      if (db_find_routine(thd, type, &name, &sp) == SP_OK)
1399
      {
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409
        if (type == TYPE_ENUM_FUNCTION)
          sp_cache_insert(&thd->sp_func_cache, sp);
        else
          sp_cache_insert(&thd->sp_proc_cache, sp);
      }
      delete newlex;
      thd->lex= oldlex;
    }
    if (sp)
    {
1410 1411 1412 1413 1414
      if (!(first && first_no_prelock))
      {
        sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines);
        result|= sp->add_used_tables_to_table_list(thd, &lex->query_tables_last);
      }
1415
    }
1416
    first= FALSE;
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
  }
  DBUG_RETURN(result);
}


/*
  Cache all routines from the set of used by statement, add tables used
  by those routines to statement table list. Do the same for all routines
  used by those routines.

  SYNOPSIS
    sp_cache_routines_and_add_tables()
1429 1430 1431 1432 1433
      thd              - thread context
      lex              - LEX representing statement
      first_no_prelock - If true, don't add tables or cache routines used by
                         the body of the first routine (i.e. *start)
                         
1434 1435 1436 1437 1438 1439
  RETURN VALUE
    TRUE  - some tables were added
    FALSE - no tables were added.
*/

bool
1440
sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock)
1441 1442
{
  return sp_cache_routines_and_add_tables_aux(thd, lex,
1443 1444
           (Sroutine_hash_entry *)lex->sroutines_list.first,
           first_no_prelock);
1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465
}


/*
  Add all routines used by view to the set of routines used by statement.
  Add tables used by those routines to statement table list. Do the same
  for all routines used by these routines.

  SYNOPSIS
    sp_cache_routines_and_add_tables_for_view()
      thd     - thread context
      lex     - LEX representing statement
      aux_lex - LEX representing view
*/

void
sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex)
{
  Sroutine_hash_entry **last_cached_routine_ptr=
                          (Sroutine_hash_entry **)lex->sroutines_list.next;
  sp_update_stmt_used_routines(thd, lex, &aux_lex->sroutines);
1466 1467
  (void)sp_cache_routines_and_add_tables_aux(thd, lex, 
                                             *last_cached_routine_ptr, FALSE);
1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490
}


/*
  Add triggers for table to the set of routines used by statement.
  Add tables used by them to statement table list. Do the same for
  all implicitly used routines.

  SYNOPSIS
    sp_cache_routines_and_add_tables_for_triggers()
      thd      - thread context
      lex      - LEX respresenting statement
      triggers - triggers of the table
*/

void
sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
                                              Table_triggers_list *triggers)
{
  if (add_used_routine(lex, thd->current_arena, &triggers->sroutines_key))
  {
    Sroutine_hash_entry **last_cached_routine_ptr=
                            (Sroutine_hash_entry **)lex->sroutines_list.next;
1491 1492
    for (int i= 0; i < (int)TRG_EVENT_MAX; i++)
      for (int j= 0; j < (int)TRG_ACTION_MAX; j++)
1493
        if (triggers->bodies[i][j])
1494
        {
1495 1496 1497 1498
          (void)triggers->bodies[i][j]->add_used_tables_to_table_list(thd,
                                          &lex->query_tables_last);
          sp_update_stmt_used_routines(thd, lex,
                                       &triggers->bodies[i][j]->m_sroutines);
1499
        }
1500 1501

    (void)sp_cache_routines_and_add_tables_aux(thd, lex,
1502 1503
                                               *last_cached_routine_ptr, 
                                               FALSE);
1504
  }
1505
}
1506

1507

1508 1509 1510 1511 1512 1513
/*
 * Generates the CREATE... string from the table information.
 * Returns TRUE on success, FALSE on (alloc) failure.
 */
static bool
create_string(THD *thd, String *buf,
1514
	      int type,
1515
	      sp_name *name,
1516 1517 1518 1519 1520
	      const char *params, ulong paramslen,
	      const char *returns, ulong returnslen,
	      const char *body, ulong bodylen,
	      st_sp_chistics *chistics)
{
1521 1522 1523 1524
  /* Make some room to begin with */
  if (buf->alloc(100 + name->m_qname.length + paramslen + returnslen + bodylen +
		 chistics->comment.length))
    return FALSE;
unknown's avatar
unknown committed
1525

1526
  buf->append("CREATE ", 7);
1527
  if (type == TYPE_ENUM_FUNCTION)
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542
    buf->append("FUNCTION ", 9);
  else
    buf->append("PROCEDURE ", 10);
  append_identifier(thd, buf, name->m_db.str, name->m_db.length);
  buf->append('.');
  append_identifier(thd, buf, name->m_name.str, name->m_name.length);
  buf->append('(');
  buf->append(params, paramslen);
  buf->append(')');
  if (type == TYPE_ENUM_FUNCTION)
  {
    buf->append(" RETURNS ", 9);
    buf->append(returns, returnslen);
  }
  buf->append('\n');
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552
  switch (chistics->daccess) {
  case SP_NO_SQL:
    buf->append("    NO SQL\n");
    break;
  case SP_READS_SQL_DATA:
    buf->append("    READS SQL DATA\n");
    break;
  case SP_MODIFIES_SQL_DATA:
    buf->append("    MODIFIES SQL DATA\n");
    break;
unknown's avatar
unknown committed
1553 1554 1555 1556
  case SP_DEFAULT_ACCESS:
  case SP_CONTAINS_SQL:
    /* Do nothing */
    break;
1557
  }
1558
  if (chistics->detistic)
1559 1560
    buf->append("    DETERMINISTIC\n", 18);
  if (chistics->suid == SP_IS_NOT_SUID)
1561
    buf->append("    SQL SECURITY INVOKER\n", 25);
1562
  if (chistics->comment.length)
unknown's avatar
unknown committed
1563
  {
1564 1565 1566
    buf->append("    COMMENT ");
    append_unescaped(buf, chistics->comment.str, chistics->comment.length);
    buf->append('\n');
unknown's avatar
unknown committed
1567
  }
1568 1569
  buf->append(body, bodylen);
  return TRUE;
1570
}
1571 1572 1573 1574 1575 1576 1577 1578


//
// Utilities...
//

int
sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddblen,
1579
	      bool no_access_check, bool *dbchangedp)
1580 1581 1582 1583 1584
{
  bool changeit;
  DBUG_ENTER("sp_use_new_db");
  DBUG_PRINT("enter", ("newdb: %s", newdb));

1585 1586
  if (! newdb)
    newdb= (char *)"";
1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606
  if (thd->db && thd->db[0])
  {
    if (my_strcasecmp(system_charset_info, thd->db, newdb) == 0)
      changeit= 0;
    else
    {
      changeit= 1;
      strnmov(olddb, thd->db, olddblen);
    }
  }
  else
  {				// thd->db empty
    if (newdb[0])
      changeit= 1;
    else
      changeit= 0;
    olddb[0] = '\0';
  }
  if (!changeit)
  {
1607
    *dbchangedp= FALSE;
1608 1609 1610 1611 1612 1613
    DBUG_RETURN(0);
  }
  else
  {
    int ret= sp_change_db(thd, newdb, no_access_check);

1614 1615
    if (! ret)
      *dbchangedp= TRUE;
1616 1617 1618 1619
    DBUG_RETURN(ret);
  }
}

1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
/*
  Change database.

  SYNOPSIS
    sp_change_db()
    thd		    Thread handler
    name	    Database name
    empty_is_ok     True= it's ok with "" as name
    no_access_check True= don't do access check

  DESCRIPTION
    This is the same as mysql_change_db(), but with some extra
    arguments for Stored Procedure usage; doing implicit "use" 
    when executing an SP in a different database.
    We also use different error routines, since this might be
    invoked from a function when executing a query or statement.
    Note: We would have prefered to reuse mysql_change_db(), but
      the error handling in particular made that too awkward, so
      we (reluctantly) have a "copy" here.

  RETURN VALUES
    0	ok
    1	error
*/

1645
int
1646
sp_change_db(THD *thd, char *name, bool no_access_check)
1647
{
1648 1649 1650 1651
  int length, db_length;
  char *dbname=my_strdup((char*) name,MYF(MY_WME));
  char	path[FN_REFLEN];
  HA_CREATE_INFO create;
1652
  DBUG_ENTER("sp_change_db");
1653
  DBUG_PRINT("enter", ("db: %s, no_access_check: %d", name, no_access_check));
1654

1655 1656 1657 1658 1659
  db_length= (!dbname ? 0 : strip_sp(dbname));
  if (dbname && db_length)
  {
    if ((db_length > NAME_LEN) || check_db_name(dbname))
    {
1660
      my_error(ER_WRONG_DB_NAME, MYF(0), dbname);
1661 1662 1663 1664
      x_free(dbname);
      DBUG_RETURN(1);
    }
  }
1665

1666 1667 1668 1669 1670
  if (dbname && db_length)
  {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
    if (! no_access_check)
    {
1671 1672
      ulong db_access;

1673 1674 1675 1676 1677 1678 1679 1680
      if (test_all_bits(thd->master_access,DB_ACLS))
	db_access=DB_ACLS;
      else
	db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
		    thd->master_access);  
      if (!(db_access & DB_ACLS) &&
	  (!grant_option || check_grant_db(thd,dbname)))
      {
1681 1682 1683 1684
	my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
                 thd->priv_user,
                 thd->priv_host,
                 dbname);
1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699
	mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
			thd->priv_user,
			thd->priv_host,
			dbname);
	my_free(dbname,MYF(0));
	DBUG_RETURN(1);
      }
    }
#endif
    (void) sprintf(path,"%s/%s",mysql_data_home,dbname);
    length=unpack_dirname(path,path);		// Convert if not unix
    if (length && path[length-1] == FN_LIBCHAR)
      path[length-1]=0;				// remove ending '\'
    if (access(path,F_OK))
    {
1700
      my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719
      my_free(dbname,MYF(0));
      DBUG_RETURN(1);
    }
  }

  x_free(thd->db);
  thd->db=dbname;				// THD::~THD will free this
  thd->db_length=db_length;

  if (dbname && db_length)
  {
    strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
    load_db_opt(thd, path, &create);
    thd->db_charset= create.default_table_charset ?
      create.default_table_charset :
      thd->variables.collation_server;
    thd->variables.collation_database= thd->db_charset;
  }
  DBUG_RETURN(0);
1720
}