sp.cc 36.6 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

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

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

38 39
enum
{
40
  MYSQL_PROC_FIELD_DB = 0,
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
  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
};
58

59 60
bool mysql_proc_table_exists= 1;

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

64
/* *opened=true means we opened ourselves */
65
static int
66
db_find_routine_aux(THD *thd, int type, sp_name *name,
67
		    enum thr_lock_type ltype, TABLE **tablep, bool *opened)
68 69
{
  TABLE *table;
70
  byte key[MAX_KEY_LENGTH];	// db, name, optional key length type
unknown's avatar
unknown committed
71
  DBUG_ENTER("db_find_routine_aux");
72 73
  DBUG_PRINT("enter", ("type: %d name: %*s",
		       type, name->m_name.length, name->m_name.str));
74

75 76 77
  *opened= FALSE;
  *tablep= 0;

78
  /*
79 80
    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.
81 82 83 84
  */
  if (!mysql_proc_table_exists && ltype == TL_READ)
    DBUG_RETURN(SP_OPEN_TABLE_FAILED);

85 86 87 88 89
  if (thd->lex->proc_table)
    table= thd->lex->proc_table->table;
  else
  {
    for (table= thd->open_tables ; table ; table= table->next)
90 91
      if (strcmp(table->s->db, "mysql") == 0 &&
          strcmp(table->s->table_name, "proc") == 0)
92 93
        break;
  }
94
  if (!table)
95
  {
96 97 98 99
    TABLE_LIST tables;

    memset(&tables, 0, sizeof(tables));
    tables.db= (char*)"mysql";
100
    tables.table_name= tables.alias= (char*)"proc";
101 102
    if (! (table= open_ltable(thd, &tables, ltype)))
    {
103 104 105 106 107 108 109
      /*
        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 it since this condition may be transient.
      */
      if (!(thd->locked_tables || thd->prelocked_mode))
        mysql_proc_table_exists= 0;
110 111 112
      DBUG_RETURN(SP_OPEN_TABLE_FAILED);
    }
    *opened= TRUE;
113
  }
114
  mysql_proc_table_exists= 1;
115

116 117 118 119 120 121 122
  /*
    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.
  */
123 124 125 126
  if (name->m_name.length > table->field[1]->field_length)
  {
    DBUG_RETURN(SP_KEY_NOT_FOUND);
  }
127 128 129 130 131 132 133
  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);

134
  if (table->file->index_read_idx(table->record[0], 0,
135
				  key, table->key_info->key_length,
136
				  HA_READ_KEY_EXACT))
137 138 139 140
  {
    DBUG_RETURN(SP_KEY_NOT_FOUND);
  }
  *tablep= table;
141

142 143 144
  DBUG_RETURN(SP_OK);
}

unknown's avatar
unknown committed
145

146
static int
147
db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
148 149 150
{
  extern int yyparse(void *thd);
  TABLE *table;
151
  const char *params, *returns, *body;
152
  int ret;
153
  bool opened;
154
  const char *definer;
unknown's avatar
unknown committed
155 156
  longlong created;
  longlong modified;
157
  st_sp_chistics chistics;
unknown's avatar
unknown committed
158 159 160
  char *ptr;
  uint length;
  char buff[65];
161
  String str(buff, sizeof(buff), &my_charset_bin);
162
  ulong sql_mode;
unknown's avatar
unknown committed
163
  DBUG_ENTER("db_find_routine");
164 165
  DBUG_PRINT("enter", ("type: %d name: %*s",
		       type, name->m_name.length, name->m_name.str));
166

167
  ret= db_find_routine_aux(thd, type, name, TL_READ, &table, &opened);
168 169
  if (ret != SP_OK)
    goto done;
170

171
  if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
172 173 174 175 176
  {
    ret= SP_GET_FIELD_FAILED;
    goto done;
  }

177
  bzero((char *)&chistics, sizeof(chistics));
unknown's avatar
unknown committed
178
  if ((ptr= get_field(thd->mem_root,
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
		      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:
198
    chistics.daccess= SP_DEFAULT_ACCESS_MAPPING;
199 200
  }

unknown's avatar
unknown committed
201
  if ((ptr= get_field(thd->mem_root,
202
		      table->field[MYSQL_PROC_FIELD_DETERMINISTIC])) == NULL)
203 204 205 206
  {
    ret= SP_GET_FIELD_FAILED;
    goto done;
  }
207
  chistics.detistic= (ptr[0] == 'N' ? FALSE : TRUE);    
unknown's avatar
unknown committed
208

unknown's avatar
unknown committed
209
  if ((ptr= get_field(thd->mem_root,
210
		      table->field[MYSQL_PROC_FIELD_SECURITY_TYPE])) == NULL)
unknown's avatar
unknown committed
211 212 213 214
  {
    ret= SP_GET_FIELD_FAILED;
    goto done;
  }
215
  chistics.suid= (ptr[0] == 'I' ? SP_IS_NOT_SUID : SP_IS_SUID);
unknown's avatar
unknown committed
216

unknown's avatar
unknown committed
217
  if ((params= get_field(thd->mem_root,
218 219 220 221
			 table->field[MYSQL_PROC_FIELD_PARAM_LIST])) == NULL)
  {
    params= "";
  }
unknown's avatar
unknown committed
222

223 224
  if (type == TYPE_ENUM_PROCEDURE)
    returns= "";
unknown's avatar
unknown committed
225
  else if ((returns= get_field(thd->mem_root,
226 227 228 229 230 231
			       table->field[MYSQL_PROC_FIELD_RETURNS])) == NULL)
  {
    ret= SP_GET_FIELD_FAILED;
    goto done;
  }

unknown's avatar
unknown committed
232
  if ((body= get_field(thd->mem_root,
233
		       table->field[MYSQL_PROC_FIELD_BODY])) == NULL)
unknown's avatar
unknown committed
234 235 236 237
  {
    ret= SP_GET_FIELD_FAILED;
    goto done;
  }
238 239

  // Get additional information
unknown's avatar
unknown committed
240
  if ((definer= get_field(thd->mem_root,
241 242 243 244 245 246 247 248
			  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
249

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

252 253
  table->field[MYSQL_PROC_FIELD_COMMENT]->val_str(&str, &str);

unknown's avatar
unknown committed
254
  ptr= 0;
255
  if ((length= str.length()))
256
    ptr= thd->strmake(str.ptr(), length);
257 258
  chistics.comment.str= ptr;
  chistics.comment.length= length;
unknown's avatar
unknown committed
259

260 261
  if (opened)
  {
262
    opened= FALSE;
unknown's avatar
unknown committed
263
    close_thread_tables(thd, 0, 1);
264
  }
265

unknown's avatar
unknown committed
266
  {
267
    String defstr;
268
    LEX *oldlex= thd->lex;
269
    char olddb[128];
270
    bool dbchanged;
271
    enum enum_sql_command oldcmd= thd->lex->sql_command;
272 273 274 275 276
    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;
277

278 279 280 281 282 283 284 285
    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
286 287 288 289 290
    {
      ret= SP_INTERNAL_ERROR;
      goto done;
    }

291 292 293
    dbchanged= FALSE;
    if ((ret= sp_use_new_db(thd, name->m_db.str, olddb, sizeof(olddb),
			    1, &dbchanged)))
294 295
      goto done;

296 297 298 299 300
    {
      /* 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
301
       * copy the list and then restore it. (... and found_semicolon too).
302
       */
303 304
      List<Item> tmpvals= thd->lex->value_list;
      char *tmpfsc= thd->lex->found_semicolon;
305

unknown's avatar
unknown committed
306
      lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length());
307 308
      thd->lex->value_list= tmpvals;
      thd->lex->found_semicolon= tmpfsc;
309 310
    }

311 312
    if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL)
    {
313 314 315
      LEX *newlex= thd->lex;
      sp_head *sp= newlex->sphead;

316
      if (dbchanged && (ret= sp_change_db(thd, olddb, 1)))
317
	goto done;
318
      if (sp)
319
      {
320 321
	delete sp;
	newlex->sphead= NULL;
322 323 324 325 326
      }
      ret= SP_PARSE_ERROR;
    }
    else
    {
327
      if (dbchanged && (ret= sp_change_db(thd, olddb, 1)))
328
	goto done;
329
      *sphp= thd->lex->sphead;
330
      (*sphp)->set_info((char *)definer, (uint)strlen(definer),
331
			created, modified, &chistics, sql_mode);
332
      (*sphp)->optimize();
333 334
    }
    thd->lex->sql_command= oldcmd;
335 336
    thd->variables.sql_mode= old_sql_mode;
    thd->variables.select_limit= select_limit;
unknown's avatar
unknown committed
337
  }
338 339

 done:
340

341
  if (opened)
342
    close_thread_tables(thd);
343
  DBUG_RETURN(ret);
344 345
}

unknown's avatar
unknown committed
346

unknown's avatar
unknown committed
347 348 349
static void
sp_returns_type(THD *thd, String &result, sp_head *sp)
{
unknown's avatar
unknown committed
350
  TABLE table;
unknown's avatar
unknown committed
351
  Field *field;
unknown's avatar
unknown committed
352 353 354 355
  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
356 357 358 359
  field->sql_type(result);
  delete field;
}

360
static int
361
db_create_routine(THD *thd, int type, sp_head *sp)
362
{
363
  int ret;
364 365
  TABLE *table;
  TABLE_LIST tables;
366
  char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
367 368
  char olddb[128];
  bool dbchanged;
unknown's avatar
unknown committed
369 370
  DBUG_ENTER("db_create_routine");
  DBUG_PRINT("enter", ("type: %d name: %*s",type,sp->m_name.length,sp->m_name.str));
371

372 373 374 375 376 377 378 379
  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;
  }

380 381
  memset(&tables, 0, sizeof(tables));
  tables.db= (char*)"mysql";
382
  tables.table_name= tables.alias= (char*)"proc";
383

384
  if (! (table= open_ltable(thd, &tables, TL_WRITE)))
385 386
    ret= SP_OPEN_TABLE_FAILED;
  else
387
  {
388
    restore_record(table, s->default_values); // Get default values for fields
389
    strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS);
390

391
    if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
392 393 394 395
    {
      ret= SP_GET_FIELD_FAILED;
      goto done;
    }
396 397 398 399 400
    if (sp->m_name.length > table->field[MYSQL_PROC_FIELD_NAME]->field_length)
    {
      ret= SP_BAD_IDENTIFIER;
      goto done;
    }
401 402
    table->field[MYSQL_PROC_FIELD_DB]->
      store(sp->m_db.str, sp->m_db.length, system_charset_info);
403 404 405 406 407 408
    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);
409 410 411
    if (sp->m_chistics->daccess != SP_DEFAULT_ACCESS)
      table->field[MYSQL_PROC_FIELD_ACCESS]->
	store((longlong)sp->m_chistics->daccess);
412 413
    table->field[MYSQL_PROC_FIELD_DETERMINISTIC]->
      store((longlong)(sp->m_chistics->detistic ? 1 : 2));
414
    if (sp->m_chistics->suid != SP_IS_DEFAULT_SUID)
415 416 417 418
      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
419 420 421 422
    if (sp->m_type == TYPE_ENUM_FUNCTION)
    {
      String retstr(64);
      sp_returns_type(thd, retstr, sp);
423
      table->field[MYSQL_PROC_FIELD_RETURNS]->
unknown's avatar
unknown committed
424 425
	store(retstr.ptr(), retstr.length(), system_charset_info);
    }
426 427 428
    table->field[MYSQL_PROC_FIELD_BODY]->
      store(sp->m_body.str, sp->m_body.length, system_charset_info);
    table->field[MYSQL_PROC_FIELD_DEFINER]->
429
      store(definer, (uint)strlen(definer), system_charset_info);
430
    ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_CREATED])->set_time();
431
    ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
432 433 434 435 436 437
    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);
438

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
    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
468
    ret= SP_OK;
469 470
    if (table->file->write_row(table->record[0]))
      ret= SP_WRITE_ROW_FAILED;
471 472 473 474 475 476 477 478
    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);
    }

479 480
  }

481
done:
482
  close_thread_tables(thd);
483 484
  if (dbchanged)
    (void)sp_change_db(thd, olddb, 1);
485 486
  DBUG_RETURN(ret);
}
487

unknown's avatar
unknown committed
488

489
static int
490
db_drop_routine(THD *thd, int type, sp_name *name)
491 492 493
{
  TABLE *table;
  int ret;
494
  bool opened;
unknown's avatar
unknown committed
495
  DBUG_ENTER("db_drop_routine");
496 497
  DBUG_PRINT("enter", ("type: %d name: %*s",
		       type, name->m_name.length, name->m_name.str));
498

499
  ret= db_find_routine_aux(thd, type, name, TL_WRITE, &table, &opened);
500 501 502 503 504 505
  if (ret == SP_OK)
  {
    if (table->file->delete_row(table->record[0]))
      ret= SP_DELETE_ROW_FAILED;
  }

506 507
  if (opened)
    close_thread_tables(thd);
508 509 510
  DBUG_RETURN(ret);
}

unknown's avatar
unknown committed
511

unknown's avatar
unknown committed
512
static int
513
db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
unknown's avatar
unknown committed
514 515 516 517
{
  TABLE *table;
  int ret;
  bool opened;
unknown's avatar
unknown committed
518
  DBUG_ENTER("db_update_routine");
519 520
  DBUG_PRINT("enter", ("type: %d name: %*s",
		       type, name->m_name.length, name->m_name.str));
unknown's avatar
unknown committed
521

522
  ret= db_find_routine_aux(thd, type, name, TL_WRITE, &table, &opened);
unknown's avatar
unknown committed
523 524 525
  if (ret == SP_OK)
  {
    store_record(table,record[1]);
unknown's avatar
unknown committed
526
    table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
unknown's avatar
unknown committed
527
    ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
528 529 530 531 532 533
    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);
534 535 536
    if (chistics->comment.str)
      table->field[MYSQL_PROC_FIELD_COMMENT]->store(chistics->comment.str,
						    chistics->comment.length,
unknown's avatar
unknown committed
537 538 539 540 541 542 543 544 545
						    system_charset_info);
    if ((table->file->update_row(table->record[1],table->record[0])))
      ret= SP_WRITE_ROW_FAILED;
  }
  if (opened)
    close_thread_tables(thd);
  DBUG_RETURN(ret);
}

unknown's avatar
unknown committed
546

unknown's avatar
unknown committed
547 548 549 550 551 552 553 554 555 556
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[]=
{
557
  { "Db",       NAME_LEN, MYSQL_TYPE_STRING,    0},
unknown's avatar
unknown committed
558 559
  { "Name",     NAME_LEN, MYSQL_TYPE_STRING,    0},
  { "Type",            9, MYSQL_TYPE_STRING,    0},
560
  { "Definer",        77, MYSQL_TYPE_STRING,    0},
unknown's avatar
unknown committed
561 562
  { "Modified",        0, MYSQL_TYPE_TIMESTAMP, 0},
  { "Created",         0, MYSQL_TYPE_TIMESTAMP, 0},
563
  { "Security_type",   1, MYSQL_TYPE_STRING,    0},
unknown's avatar
unknown committed
564 565 566 567
  { "Comment",  NAME_LEN, MYSQL_TYPE_STRING,    0},
  { 0,                 0, MYSQL_TYPE_STRING,    0}
};

unknown's avatar
unknown committed
568

569 570 571 572
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
573 574 575 576 577
{
  Protocol *protocol= thd->protocol;

  if (table->field[MYSQL_PROC_FIELD_TYPE]->val_int() == type)
  {
578 579
    String db_string;
    String name_string;
unknown's avatar
unknown committed
580
    struct st_used_field *used_field= used_fields;
581

unknown's avatar
unknown committed
582
    if (get_field(thd->mem_root, used_field->field, &db_string))
583 584
      db_string.set_ascii("", 0);
    used_field+= 1;
unknown's avatar
unknown committed
585
    get_field(thd->mem_root, used_field->field, &name_string);
586 587

    if (!wild || !wild[0] || !wild_compare(name_string.ptr(), wild, 0))
unknown's avatar
unknown committed
588 589
    {
      protocol->prepare_for_resend();
590 591
      protocol->store(&db_string);
      protocol->store(&name_string);
unknown's avatar
unknown committed
592 593 594 595 596 597
      for (used_field++;
	   used_field->field_name;
	   used_field++)
      {
	switch (used_field->field_type) {
	case MYSQL_TYPE_TIMESTAMP:
598 599
	  {
	    TIME tmp_time;
600 601

	    bzero((char *)&tmp_time, sizeof(tmp_time));
602 603 604 605
	    ((Field_timestamp *) used_field->field)->get_time(&tmp_time);
	    protocol->store(&tmp_time);
	  }
	  break;
unknown's avatar
unknown committed
606
	default:
607
	  {
608
	    String tmp_string;
609

unknown's avatar
unknown committed
610
	    get_field(thd->mem_root, used_field->field, &tmp_string);
611
	    protocol->store(&tmp_string);
612 613
	  }
	  break;
unknown's avatar
unknown committed
614 615 616
	}
      }
      if (protocol->write())
617
	return SP_INTERNAL_ERROR;
unknown's avatar
unknown committed
618 619
    }
  }
620
  return SP_OK;
unknown's avatar
unknown committed
621 622
}

unknown's avatar
unknown committed
623

624
static int
unknown's avatar
unknown committed
625 626 627 628
db_show_routine_status(THD *thd, int type, const char *wild)
{
  TABLE *table;
  TABLE_LIST tables;
629
  int res;
unknown's avatar
unknown committed
630
  DBUG_ENTER("db_show_routine_status");
unknown's avatar
unknown committed
631 632 633

  memset(&tables, 0, sizeof(tables));
  tables.db= (char*)"mysql";
634
  tables.table_name= tables.alias= (char*)"proc";
unknown's avatar
unknown committed
635 636 637

  if (! (table= open_ltable(thd, &tables, TL_READ)))
  {
638 639
    res= SP_OPEN_TABLE_FAILED;
    goto done;
unknown's avatar
unknown committed
640 641 642 643 644 645
  }
  else
  {
    Item *item;
    List<Item> field_list;
    struct st_used_field *used_field;
646
    TABLE_LIST *leaves= 0;
unknown's avatar
unknown committed
647
    st_used_field used_fields[array_elements(init_fields)];
648

unknown's avatar
unknown committed
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
    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 */
667 668
    if (thd->protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
                                                Protocol::SEND_EOF))
669 670
    {
      res= SP_INTERNAL_ERROR;
unknown's avatar
unknown committed
671
      goto err_case;
672
    }
unknown's avatar
unknown committed
673

unknown's avatar
VIEW  
unknown committed
674 675 676 677 678
    /*
      Init fields

      tables is not VIEW for sure => we can pass 0 as condition
    */
679 680 681
    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
682 683 684 685
    for (used_field= &used_fields[0];
	 used_field->field_name;
	 used_field++)
    {
686 687
      Item_field *field= new Item_field(&thd->lex->select_lex.context,
                                        "mysql", "proc",
unknown's avatar
unknown committed
688
					used_field->field_name);
689
      if (!field ||
690 691 692
          !(used_field->field= find_field_in_tables(thd, field, &tables,
						    0, REPORT_ALL_ERRORS, 1,
                                                    TRUE)))
693 694
      {
	res= SP_INTERNAL_ERROR;
unknown's avatar
unknown committed
695
	goto err_case1;
696
      }
unknown's avatar
unknown committed
697 698
    }

unknown's avatar
unknown committed
699
    table->file->ha_index_init(0);
700 701
    if ((res= table->file->index_first(table->record[0])))
    {
unknown's avatar
unknown committed
702
      res= (res == HA_ERR_END_OF_FILE) ? 0 : SP_INTERNAL_ERROR;
703 704 705
      goto err_case1;
    }
    if ((res= print_field_values(thd, table, used_fields, type, wild)))
unknown's avatar
unknown committed
706 707 708
      goto err_case1;
    while (!table->file->index_next(table->record[0]))
    {
709
      if ((res= print_field_values(thd, table, used_fields, type, wild)))
unknown's avatar
unknown committed
710 711
	goto err_case1;
    }
712
    res= SP_OK;
unknown's avatar
unknown committed
713
  }
714

unknown's avatar
unknown committed
715
err_case1:
unknown's avatar
unknown committed
716
  send_eof(thd);
unknown's avatar
unknown committed
717
err_case:
unknown's avatar
unknown committed
718
  table->file->ha_index_end();
unknown's avatar
unknown committed
719
  close_thread_tables(thd);
unknown's avatar
unknown committed
720
done:
721
  DBUG_RETURN(res);
unknown's avatar
unknown committed
722 723
}

724

725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
/* 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);

  for (table= thd->open_tables ; table ; table= table->next)
745 746
    if (strcmp(table->s->db, "mysql") == 0 &&
	strcmp(table->s->table_name, "proc") == 0)
747 748 749 750 751 752 753
      break;
  if (! table)
  {
    TABLE_LIST tables;

    memset(&tables, 0, sizeof(tables));
    tables.db= (char*)"mysql";
754
    tables.table_name= tables.alias= (char*)"proc";
755 756 757 758 759
    if (! (table= open_ltable(thd, &tables, TL_WRITE)))
      DBUG_RETURN(SP_OPEN_TABLE_FAILED);
  }

  ret= SP_OK;
unknown's avatar
unknown committed
760
  table->file->ha_index_init(0);
761 762 763 764 765 766 767 768 769 770 771 772
  if (! table->file->index_read(table->record[0],
				key, keylen, HA_READ_KEY_EXACT))
  {
    int nxtres;
    bool deleted= FALSE;

    do {
      if (! table->file->delete_row(table->record[0]))
	deleted= TRUE;		/* We deleted something */
      else
      {
	ret= SP_DELETE_ROW_FAILED;
773
	nxtres= 0;
774 775 776 777 778 779 780 781 782
	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
783
  table->file->ha_index_end();
784 785 786 787 788 789 790

  close_thread_tables(thd);

  DBUG_RETURN(ret);
}


unknown's avatar
unknown committed
791 792 793
/*****************************************************************************
  PROCEDURE
******************************************************************************/
794

795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
/*
  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.
*/

816
sp_head *
817
sp_find_procedure(THD *thd, sp_name *name, bool cache_only)
818 819
{
  sp_head *sp;
unknown's avatar
unknown committed
820
  DBUG_ENTER("sp_find_procedure");
821 822 823
  DBUG_PRINT("enter", ("name: %*s.%*s",
		       name->m_db.length, name->m_db.str,
		       name->m_name.length, name->m_name.str));
824

825
  if (!(sp= sp_cache_lookup(&thd->sp_proc_cache, name)) && !cache_only)
826
  {
827
    if (db_find_routine(thd, TYPE_ENUM_PROCEDURE, name, &sp) == SP_OK)
828
      sp_cache_insert(&thd->sp_proc_cache, sp);
829
  }
830 831 832 833

  DBUG_RETURN(sp);
}

unknown's avatar
unknown committed
834

835 836 837 838 839 840 841 842 843 844 845 846
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);
847
    lex_name.length= strlen(table->table_name);
848
    lex_db.str= thd->strmake(table->db, lex_db.length);
849
    lex_name.str= thd->strmake(table->table_name, lex_name.length);
850 851 852 853 854 855 856 857 858 859 860 861 862 863
    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", 
864
		 table->table_name);
865 866 867 868 869 870 871 872 873
	DBUG_RETURN(-1);
      }
      DBUG_RETURN(0);
    }
  }
  DBUG_RETURN(result);
}


874
int
875
sp_create_procedure(THD *thd, sp_head *sp)
876
{
877
  int ret;
878
  DBUG_ENTER("sp_create_procedure");
879
  DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str));
880 881 882

  ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, sp);
  DBUG_RETURN(ret);
883 884
}

unknown's avatar
unknown committed
885

886
int
887
sp_drop_procedure(THD *thd, sp_name *name)
888
{
889
  int ret;
890
  bool found;
891
  DBUG_ENTER("sp_drop_procedure");
892
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
893

894
  found= sp_cache_remove(&thd->sp_proc_cache, name);
895
  ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name);
896 897
  if (!found && !ret)
    sp_cache_invalidate();
898
  DBUG_RETURN(ret);
899
}
900

unknown's avatar
unknown committed
901

unknown's avatar
unknown committed
902
int
903
sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics)
unknown's avatar
unknown committed
904
{
905
  int ret;
906
  bool found;
unknown's avatar
unknown committed
907
  DBUG_ENTER("sp_update_procedure");
908
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
unknown's avatar
unknown committed
909

910
  found= sp_cache_remove(&thd->sp_proc_cache, name);
911
  ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics);
912 913
  if (!found && !ret)
    sp_cache_invalidate();
914
  DBUG_RETURN(ret);
unknown's avatar
unknown committed
915 916
}

unknown's avatar
unknown committed
917

unknown's avatar
unknown committed
918
int
919
sp_show_create_procedure(THD *thd, sp_name *name)
unknown's avatar
unknown committed
920
{
unknown's avatar
unknown committed
921
  sp_head *sp;
unknown's avatar
unknown committed
922
  DBUG_ENTER("sp_show_create_procedure");
923
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
unknown's avatar
unknown committed
924

unknown's avatar
unknown committed
925
  if ((sp= sp_find_procedure(thd, name)))
926 927 928 929 930
  {
    int ret= sp->show_create_procedure(thd);

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

932
  DBUG_RETURN(SP_KEY_NOT_FOUND);
unknown's avatar
unknown committed
933 934
}

unknown's avatar
unknown committed
935

unknown's avatar
unknown committed
936
int
937
sp_show_status_procedure(THD *thd, const char *wild)
unknown's avatar
unknown committed
938
{
939
  int ret;
940
  DBUG_ENTER("sp_show_status_procedure");
941 942 943

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

unknown's avatar
unknown committed
946 947 948 949

/*****************************************************************************
  FUNCTION
******************************************************************************/
950

951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
/*
  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.
*/

970
sp_head *
971
sp_find_function(THD *thd, sp_name *name, bool cache_only)
972 973
{
  sp_head *sp;
unknown's avatar
unknown committed
974
  DBUG_ENTER("sp_find_function");
975
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
976

977 978
  if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)) &&
      !cache_only)
979
  {
980
    if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) != SP_OK)
981
      sp= NULL;
unknown's avatar
unknown committed
982 983
    else
      sp_cache_insert(&thd->sp_func_cache, sp);
984
  }
985 986 987
  DBUG_RETURN(sp);
}

unknown's avatar
unknown committed
988

989
int
990
sp_create_function(THD *thd, sp_head *sp)
991
{
992
  int ret;
993
  DBUG_ENTER("sp_create_function");
994
  DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str));
995

996 997
  ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, sp);
  DBUG_RETURN(ret);
998 999
}

unknown's avatar
unknown committed
1000

1001
int
1002
sp_drop_function(THD *thd, sp_name *name)
1003
{
1004
  int ret;
1005
  bool found;
1006
  DBUG_ENTER("sp_drop_function");
1007
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
1008

1009
  found= sp_cache_remove(&thd->sp_func_cache, name);
1010
  ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name);
1011 1012
  if (!found && !ret)
    sp_cache_invalidate();
1013
  DBUG_RETURN(ret);
1014
}
1015

unknown's avatar
unknown committed
1016

unknown's avatar
unknown committed
1017
int
1018
sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics)
unknown's avatar
unknown committed
1019
{
1020
  int ret;
1021
  bool found;
unknown's avatar
unknown committed
1022
  DBUG_ENTER("sp_update_procedure");
1023
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
unknown's avatar
unknown committed
1024

1025
  found= sp_cache_remove(&thd->sp_func_cache, name);
1026
  ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics);
1027 1028
  if (!found && !ret)
    sp_cache_invalidate();
1029
  DBUG_RETURN(ret);
unknown's avatar
unknown committed
1030 1031
}

unknown's avatar
unknown committed
1032

unknown's avatar
unknown committed
1033
int
1034
sp_show_create_function(THD *thd, sp_name *name)
unknown's avatar
unknown committed
1035
{
unknown's avatar
unknown committed
1036
  sp_head *sp;
unknown's avatar
unknown committed
1037
  DBUG_ENTER("sp_show_create_function");
1038
  DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
unknown's avatar
unknown committed
1039

unknown's avatar
unknown committed
1040
  if ((sp= sp_find_function(thd, name)))
1041 1042 1043 1044 1045
  {
    int ret= sp->show_create_function(thd);

    DBUG_RETURN(ret);
  }
1046
  DBUG_RETURN(SP_KEY_NOT_FOUND);
unknown's avatar
unknown committed
1047 1048
}

unknown's avatar
unknown committed
1049

unknown's avatar
unknown committed
1050
int
1051
sp_show_status_function(THD *thd, const char *wild)
unknown's avatar
unknown committed
1052
{
1053
  int ret;
1054
  DBUG_ENTER("sp_show_status_function");
1055 1056
  ret= db_show_routine_status(thd, TYPE_ENUM_FUNCTION, wild);
  DBUG_RETURN(ret);
unknown's avatar
unknown committed
1057 1058
}

unknown's avatar
unknown committed
1059

1060
bool
1061
sp_function_exists(THD *thd, sp_name *name)
1062 1063
{
  TABLE *table;
1064
  bool ret= FALSE;
1065
  bool opened= FALSE;
unknown's avatar
unknown committed
1066
  DBUG_ENTER("sp_function_exists");
1067

1068
  if (sp_cache_lookup(&thd->sp_func_cache, name) ||
1069
      db_find_routine_aux(thd, TYPE_ENUM_FUNCTION,
1070
			  name, TL_READ,
1071
			  &table, &opened) == SP_OK)
1072
    ret= TRUE;
1073
  if (opened)
unknown's avatar
unknown committed
1074
    close_thread_tables(thd, 0, 1);
1075
  thd->clear_error();
unknown's avatar
unknown committed
1076
  DBUG_RETURN(ret);
1077 1078 1079
}


1080
byte *
1081
sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first)
1082 1083 1084 1085 1086 1087
{
  LEX_STRING *lsp= (LEX_STRING *)ptr;
  *plen= lsp->length;
  return (byte *)lsp->str;
}

unknown's avatar
unknown committed
1088

1089
void
1090
sp_add_to_hash(HASH *h, sp_name *fun)
1091
{
1092
  if (! hash_search(h, (byte *)fun->m_qname.str, fun->m_qname.length))
1093
  {
1094
    LEX_STRING *ls= (LEX_STRING *)sql_alloc(sizeof(LEX_STRING));
1095 1096
    ls->str= sql_strmake(fun->m_qname.str, fun->m_qname.length);
    ls->length= fun->m_qname.length;
unknown's avatar
unknown committed
1097

1098
    my_hash_insert(h, (byte *)ls);
1099 1100 1101
  }
}

unknown's avatar
unknown committed
1102

1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
/*
  Merge contents of two hashes containing LEX_STRING's

  SYNOPSIS
    sp_merge_hash()
      dst - hash to which elements should be added
      src - hash from which elements merged

  RETURN VALUE
    TRUE  - if we have added some new elements to destination hash.
    FALSE - there were no new elements in src.
*/

bool
1117
sp_merge_hash(HASH *dst, HASH *src)
1118
{
1119
  bool res= FALSE;
1120
  for (uint i=0 ; i < src->records ; i++)
1121
  {
1122
    LEX_STRING *ls= (LEX_STRING *)hash_element(src, i);
1123

1124
    if (! hash_search(dst, (byte *)ls->str, ls->length))
1125
    {
1126
      my_hash_insert(dst, (byte *)ls);
1127 1128
      res= TRUE;
    }
1129
  }
1130
  return res;
1131 1132
}

unknown's avatar
unknown committed
1133

1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
/*
  Cache all routines implicitly or explicitly used by query
  (or whatever object is represented by LEX).

  SYNOPSIS
    sp_cache_routines()
      thd - thread context
      lex - LEX representing query

  NOTE
    If some function is missing this won't be reported here.
    Instead this fact will be discovered during query execution.

  TODO
    Currently if after passing through routine hashes we discover
    that we have added something to them, we do one more pass to
    process all routines which were missed on previous pass because
    of these additions. We can avoid this if along with hashes
    we use lists holding routine names and iterate other these
    lists instead of hashes (since addition to the end of list
    does not reorder elements in it).
*/

void
sp_cache_routines(THD *thd, LEX *lex)
1159
{
1160 1161 1162
  bool routines_added= TRUE;

  DBUG_ENTER("sp_cache_routines");
1163

1164
  while (routines_added)
1165
  {
1166
    routines_added= FALSE;
1167

1168
    for (int type= TYPE_ENUM_FUNCTION; type < TYPE_ENUM_TRIGGER; type++)
1169
    {
1170 1171 1172
      HASH *h= (type == TYPE_ENUM_FUNCTION ? &lex->spfuns : &lex->spprocs);

      for (uint i=0 ; i < h->records ; i++)
1173
      {
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
        LEX_STRING *ls= (LEX_STRING *)hash_element(h, i);
        sp_name name(*ls);
        sp_head *sp;

        name.m_qname= *ls;
        if (!(sp= sp_cache_lookup((type == TYPE_ENUM_FUNCTION ?
                                   &thd->sp_func_cache : &thd->sp_proc_cache),
                                  &name)))
        {
          LEX *oldlex= thd->lex;
          LEX *newlex= new st_lex;

          thd->lex= newlex;
          /* Pass hint pointer to mysql.proc table */
          newlex->proc_table= oldlex->proc_table;
          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)
          {
            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)
        {
          routines_added|= sp_merge_hash(&lex->spfuns, &sp->m_spfuns);
          routines_added|= sp_merge_hash(&lex->spprocs, &sp->m_spprocs);
        }
1213
      }
1214 1215
    }
  }
1216
  DBUG_VOID_RETURN;
1217
}
1218

1219 1220 1221 1222 1223 1224
/*
 * Generates the CREATE... string from the table information.
 * Returns TRUE on success, FALSE on (alloc) failure.
 */
static bool
create_string(THD *thd, String *buf,
1225
	      int type,
1226
	      sp_name *name,
1227 1228 1229 1230 1231
	      const char *params, ulong paramslen,
	      const char *returns, ulong returnslen,
	      const char *body, ulong bodylen,
	      st_sp_chistics *chistics)
{
1232 1233 1234 1235
  /* 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
1236

1237
  buf->append("CREATE ", 7);
1238
  if (type == TYPE_ENUM_FUNCTION)
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
    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');
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
  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
1264 1265 1266 1267
  case SP_DEFAULT_ACCESS:
  case SP_CONTAINS_SQL:
    /* Do nothing */
    break;
1268
  }
1269
  if (chistics->detistic)
1270 1271
    buf->append("    DETERMINISTIC\n", 18);
  if (chistics->suid == SP_IS_NOT_SUID)
1272
    buf->append("    SQL SECURITY INVOKER\n", 25);
1273
  if (chistics->comment.length)
unknown's avatar
unknown committed
1274
  {
1275 1276 1277
    buf->append("    COMMENT ");
    append_unescaped(buf, chistics->comment.str, chistics->comment.length);
    buf->append('\n');
unknown's avatar
unknown committed
1278
  }
1279 1280
  buf->append(body, bodylen);
  return TRUE;
1281
}
1282 1283 1284 1285 1286 1287 1288 1289


//
// Utilities...
//

int
sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddblen,
1290
	      bool no_access_check, bool *dbchangedp)
1291 1292 1293 1294 1295
{
  bool changeit;
  DBUG_ENTER("sp_use_new_db");
  DBUG_PRINT("enter", ("newdb: %s", newdb));

1296 1297
  if (! newdb)
    newdb= (char *)"";
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317
  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)
  {
1318
    *dbchangedp= FALSE;
1319 1320 1321 1322 1323 1324
    DBUG_RETURN(0);
  }
  else
  {
    int ret= sp_change_db(thd, newdb, no_access_check);

1325 1326
    if (! ret)
      *dbchangedp= TRUE;
1327 1328 1329 1330
    DBUG_RETURN(ret);
  }
}

1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355
/*
  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
*/

1356
int
1357
sp_change_db(THD *thd, char *name, bool no_access_check)
1358
{
1359 1360 1361 1362
  int length, db_length;
  char *dbname=my_strdup((char*) name,MYF(MY_WME));
  char	path[FN_REFLEN];
  HA_CREATE_INFO create;
1363
  DBUG_ENTER("sp_change_db");
1364
  DBUG_PRINT("enter", ("db: %s, no_access_check: %d", name, no_access_check));
1365

1366 1367 1368 1369 1370
  db_length= (!dbname ? 0 : strip_sp(dbname));
  if (dbname && db_length)
  {
    if ((db_length > NAME_LEN) || check_db_name(dbname))
    {
1371
      my_error(ER_WRONG_DB_NAME, MYF(0), dbname);
1372 1373 1374 1375
      x_free(dbname);
      DBUG_RETURN(1);
    }
  }
1376

1377 1378 1379 1380 1381
  if (dbname && db_length)
  {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
    if (! no_access_check)
    {
1382 1383
      ulong db_access;

1384 1385 1386 1387 1388 1389 1390 1391
      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)))
      {
1392 1393 1394 1395
	my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
                 thd->priv_user,
                 thd->priv_host,
                 dbname);
1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410
	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))
    {
1411
      my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430
      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);
1431
}