Commit cb5d6dbf authored by unknown's avatar unknown
Browse files

Merge bk-internal.mysql.com:/home/bk/mysql-5.0-runtime

into  mysql.com:/home/dlenev/mysql-5.0-bg12472


sql/mysql_priv.h:
  Auto merged
sql/sql_base.cc:
  Auto merged
sql/sql_insert.cc:
  Auto merged
sql/sql_table.cc:
  Auto merged
mysql-test/r/sp.result:
  Manual merge.
mysql-test/t/sp.test:
  Manual merge.
parents 59ff5274 4f15a043
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -4904,4 +4904,29 @@ schema_name
select routine_name,routine_schema from information_schema.routines where
routine_schema like 'bug18344%'|
routine_name	routine_schema
drop function if exists bug12472|
create function bug12472() returns int return (select count(*) from t1)|
create table t3 as select bug12472() as i|
show create table t3|
Table	Create Table
t3	CREATE TABLE `t3` (
  `i` int(11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t3|
i
0
drop table t3|
create view v1 as select bug12472() as j|
create table t3 as select * from v1|
show create table t3|
Table	Create Table
t3	CREATE TABLE `t3` (
  `j` bigint(11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t3|
j
0
drop table t3|
drop view v1|
drop function bug12472|
drop table t1,t2;
+23 −0
Original line number Diff line number Diff line
@@ -5773,6 +5773,29 @@ select routine_name,routine_schema from information_schema.routines where
  routine_schema like 'bug18344%'|


#
# BUG#12472/BUG#15137 'CREATE TABLE ... SELECT ... which explicitly or
# implicitly uses stored function gives "Table not locked" error'.
#
--disable_warnings
drop function if exists bug12472|
--enable_warnings
create function bug12472() returns int return (select count(*) from t1)|
# Check case when function is used directly
create table t3 as select bug12472() as i|
show create table t3|
select * from t3|
drop table t3|
# Check case when function is used indirectly through view
create view v1 as select bug12472() as j|
create table t3 as select * from v1|
show create table t3|
select * from t3|
drop table t3|
drop view v1|
drop function bug12472|


#
# BUG#NNNN: New bug synopsis
#
+2 −7
Original line number Diff line number Diff line
@@ -718,12 +718,6 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
                        List<create_field> &fields, List<Key> &keys,
                        bool tmp_table, uint select_field_count);

TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
			       TABLE_LIST *create_table,
			       List<create_field> *extra_fields,
			       List<Key> *keys,
			       List<Item> *items,
                               MYSQL_LOCK **lock);
bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
                       HA_CREATE_INFO *create_info,
                       TABLE_LIST *table_list,
@@ -1315,10 +1309,11 @@ extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd;

MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count,
                              uint flags, bool *need_reopen);
/* mysql_lock_tables() flags bits */
/* mysql_lock_tables() and open_table() flags bits */
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK      0x0001
#define MYSQL_LOCK_IGNORE_FLUSH                 0x0002
#define MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN        0x0004
#define MYSQL_OPEN_IGNORE_LOCKED_TABLES         0x0008

void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
+4 −1
Original line number Diff line number Diff line
@@ -1160,6 +1160,8 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
                          MYSQL_LOCK_IGNORE_FLUSH - Open table even if
                          someone has done a flush or namelock on it.
                          No version number checking is done.
                          MYSQL_OPEN_IGNORE_LOCKED_TABLES - Open table
                          ignoring set of locked tables and prelocked mode.

  IMPLEMENTATION
    Uses a cache of open tables to find a table not in use.
@@ -1219,7 +1221,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
    }
  }

  if (thd->locked_tables || thd->prelocked_mode)
  if (!(flags & MYSQL_OPEN_IGNORE_LOCKED_TABLES) &&
      (thd->locked_tables || thd->prelocked_mode))
  {						// Using table locks
    TABLE *best_table= 0;
    int best_distance= INT_MIN;
+147 −0
Original line number Diff line number Diff line
@@ -2437,6 +2437,153 @@ bool select_insert::send_eof()
  CREATE TABLE (SELECT) ...
***************************************************************************/

/*
  Create table from lists of fields and items (or open existing table
  with same name).

  SYNOPSIS
    create_table_from_items()
      thd          in     Thread object
      create_info  in     Create information (like MAX_ROWS, ENGINE or
                          temporary table flag)
      create_table in     Pointer to TABLE_LIST object providing database
                          and name for table to be created or to be open
      extra_fields in/out Initial list of fields for table to be created
      keys         in     List of keys for table to be created
      items        in     List of items which should be used to produce rest
                          of fields for the table (corresponding fields will
                          be added to the end of 'extra_fields' list)
      lock         out    Pointer to the MYSQL_LOCK object for table created
                          (open) will be returned in this parameter. Since
                          this table is not included in THD::lock caller is
                          responsible for explicitly unlocking this table.

  NOTES
    If 'create_info->options' bitmask has HA_LEX_CREATE_IF_NOT_EXISTS
    flag and table with name provided already exists then this function will
    simply open existing table.
    Also note that create, open and lock sequence in this function is not
    atomic and thus contains gap for deadlock and can cause other troubles.
    Since this function contains some logic specific to CREATE TABLE ... SELECT
    it should be changed before it can be used in other contexts.

  RETURN VALUES
    non-zero  Pointer to TABLE object for table created or opened
    0         Error
*/

static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
                                      TABLE_LIST *create_table,
                                      List<create_field> *extra_fields,
                                      List<Key> *keys, List<Item> *items,
                                      MYSQL_LOCK **lock)
{
  TABLE tmp_table;		// Used during 'create_field()'
  TABLE *table= 0;
  uint select_field_count= items->elements;
  /* Add selected items to field list */
  List_iterator_fast<Item> it(*items);
  Item *item;
  Field *tmp_field;
  bool not_used;
  DBUG_ENTER("create_table_from_items");

  tmp_table.alias= 0;
  tmp_table.timestamp_field= 0;
  tmp_table.s= &tmp_table.share_not_to_be_used;
  tmp_table.s->db_create_options=0;
  tmp_table.s->blob_ptr_size= portable_sizeof_char_ptr;
  tmp_table.s->db_low_byte_first= test(create_info->db_type == DB_TYPE_MYISAM ||
                                       create_info->db_type == DB_TYPE_HEAP);
  tmp_table.null_row=tmp_table.maybe_null=0;

  while ((item=it++))
  {
    create_field *cr_field;
    Field *field;
    if (item->type() == Item::FUNC_ITEM)
      field=item->tmp_table_field(&tmp_table);
    else
      field=create_tmp_field(thd, &tmp_table, item, item->type(),
                             (Item ***) 0, &tmp_field, 0, 0, 0, 0, 0);
    if (!field ||
	!(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ?
					   ((Item_field *)item)->field :
					   (Field*) 0))))
      DBUG_RETURN(0);
    if (item->maybe_null)
      cr_field->flags &= ~NOT_NULL_FLAG;
    extra_fields->push_back(cr_field);
  }
  /*
    create and lock table

    We don't log the statement, it will be logged later.

    If this is a HEAP table, the automatic DELETE FROM which is written to the
    binlog when a HEAP table is opened for the first time since startup, must
    not be written: 1) it would be wrong (imagine we're in CREATE SELECT: we
    don't want to delete from it) 2) it would be written before the CREATE
    TABLE, which is a wrong order. So we keep binary logging disabled when we
    open_table().
    NOTE: By locking table which we just have created (or for which we just have
    have found that it already exists) separately from other tables used by the
    statement we create potential window for deadlock.
    TODO: create and open should be done atomic !
  */
  {
    tmp_disable_binlog(thd);
    if (!mysql_create_table(thd, create_table->db, create_table->table_name,
                            create_info, *extra_fields, *keys, 0,
                            select_field_count))
    {
      /*
        If we are here in prelocked mode we either create temporary table
        or prelocked mode is caused by the SELECT part of this statement.
      */
      DBUG_ASSERT(!thd->prelocked_mode ||
                  create_info->options & HA_LEX_CREATE_TMP_TABLE ||
                  thd->lex->requires_prelocking());

      /*
        NOTE: We don't want to ignore set of locked tables here if we are
              under explicit LOCK TABLES since it will open gap for deadlock
              too wide (and also is not backward compatible).
      */
      if (! (table= open_table(thd, create_table, thd->mem_root, (bool*) 0,
                               (MYSQL_LOCK_IGNORE_FLUSH |
                                ((thd->prelocked_mode == PRELOCKED) ?
                                 MYSQL_OPEN_IGNORE_LOCKED_TABLES:0)))))
        quick_rm_table(create_info->db_type, create_table->db,
                       table_case_name(create_info, create_table->table_name));
    }
    reenable_binlog(thd);
    if (!table)                                   // open failed
      DBUG_RETURN(0);
  }

  /*
    FIXME: What happens if trigger manages to be created while we are
           obtaining this lock ? May be it is sensible just to disable
           trigger execution in this case ? Or will MYSQL_LOCK_IGNORE_FLUSH
           save us from that ?
  */
  table->reginfo.lock_type=TL_WRITE;
  if (! ((*lock)= mysql_lock_tables(thd, &table, 1,
                                    MYSQL_LOCK_IGNORE_FLUSH, &not_used)))
  {
    VOID(pthread_mutex_lock(&LOCK_open));
    hash_delete(&open_cache,(byte*) table);
    VOID(pthread_mutex_unlock(&LOCK_open));
    quick_rm_table(create_info->db_type, create_table->db,
		   table_case_name(create_info, create_table->table_name));
    DBUG_RETURN(0);
  }
  table->file->extra(HA_EXTRA_WRITE_CACHE);
  DBUG_RETURN(table);
}


int
select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
Loading